hctree

Check-in Differences
Login

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

Difference From 184a0cd2e855c517 To 8a6196ab29052071

2024-03-19
13:55
On second thought, change SQLITE_TESTCTRL_ROWID_IN_VIEW into a start-time option SQLITE_CONFIG_NO_ROWID_IN_VIEW. check-in: b8e045c9e1 user: drh tags: rowid-in-view
13:31
When compiled with SQLITE_ALLOW_ROWID_IN_VIEW, rowid-in-view is on by default but can now be turned off using SQLITE_TESTCTRL_ROWID_IN_VIEW. Without the compile-time option, rowid-in-view is always off. check-in: 8a6196ab29 user: drh tags: rowid-in-view
02:30
First steps toward getting -DSQLITE_ALLOW_ROWID_IN_VIEW to work again. That compile-time option is untested, undocumented, and unsupported. But it was mentioned in the release notes for version 3.36.0, so I think that means we need to support it forever. check-in: 7c46ff6402 user: drh tags: rowid-in-view
2023-11-20
15:58
Back out an incorrect change to the sqlite3ExprCompareSkip() function from long ago. check-in: 89658abbcd user: drh tags: branch-3.44
13:59
Arrange to not compile unused console I/O function. check-in: 184a0cd2e8 user: larrybr tags: branch-3.44
13:12
Convert an assert in OP_VCheck into a branch that aborts the opcode, as this can happen on some very obscure conditions, as discovered by dbsqlfuzz. check-in: 0d5f68717c user: drh tags: branch-3.44

Changes to Makefile.in.
414
415
416
417
418
419
420


421
422
423
424
425
426
427
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429







+
+







  $(TOP)/src/test_wsd.c       \
  $(TOP)/ext/fts3/fts3_term.c \
  $(TOP)/ext/fts3/fts3_test.c  \
  $(TOP)/ext/session/test_session.c \
  $(TOP)/ext/recover/sqlite3recover.c \
  $(TOP)/ext/recover/dbdata.c \
  $(TOP)/ext/recover/test_recover.c \
  $(TOP)/ext/intck/test_intck.c  \
  $(TOP)/ext/intck/sqlite3intck.c \
  $(TOP)/ext/rbu/test_rbu.c

# Statically linked extensions
#
TESTSRC += \
  $(TOP)/ext/expert/sqlite3expert.c \
  $(TOP)/ext/expert/test_expert.c \
443
444
445
446
447
448
449

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







+







  $(TOP)/ext/misc/ieee754.c \
  $(TOP)/ext/misc/mmapwarm.c \
  $(TOP)/ext/misc/nextchar.c \
  $(TOP)/ext/misc/normalize.c \
  $(TOP)/ext/misc/percentile.c \
  $(TOP)/ext/misc/prefixes.c \
  $(TOP)/ext/misc/qpvtab.c \
  $(TOP)/ext/misc/randomjson.c \
  $(TOP)/ext/misc/regexp.c \
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \
596
597
598
599
600
601
602

603
604
605
606
607
608
609
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613







+







SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_STRICT_SUBTYPE=1
FUZZERSHELL_OPT =
FUZZCHECK_OPT += -I$(TOP)/test
FUZZCHECK_OPT += -I$(TOP)/ext/recover
FUZZCHECK_OPT += \
  -DSQLITE_OSS_FUZZ \
  -DSQLITE_ENABLE_BYTECODE_VTAB \
  -DSQLITE_ENABLE_DBPAGE_VTAB \
626
627
628
629
630
631
632
633



634
635
636
637
638
639
640

641
642
643
644
645
646
647
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







-
+
+
+







+







  -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
  -DSQLITE_ENABLE_STAT4 \
  -DSQLITE_ENABLE_STMT_SCANSTATUS \
  -DSQLITE_MAX_MEMORY=50000000 \
  -DSQLITE_MAX_MMAP_SIZE=0 \
  -DSQLITE_OMIT_LOAD_EXTENSION \
  -DSQLITE_PRINTF_PRECISION_LIMIT=1000 \
  -DSQLITE_PRIVATE=""
  -DSQLITE_PRIVATE="" \
  -DSQLITE_STRICT_SUBTYPE=1 \
  -DSQLITE_STATIC_RANDOMJSON

FUZZCHECK_SRC += $(TOP)/test/fuzzcheck.c
FUZZCHECK_SRC += $(TOP)/test/ossfuzz.c
FUZZCHECK_SRC += $(TOP)/test/fuzzinvariants.c
FUZZCHECK_SRC += $(TOP)/ext/recover/dbdata.c
FUZZCHECK_SRC += $(TOP)/ext/recover/sqlite3recover.c
FUZZCHECK_SRC += $(TOP)/test/vt02.c
FUZZCHECK_SRC += $(TOP)/ext/misc/randomjson.c
DBFUZZ_OPT =
ST_OPT = -DSQLITE_OS_KV_OPTIONAL


# In wasi-sdk builds, disable the CLI shell build in the "all" target.
SQLITE3_SHELL_TARGET_  = sqlite3$(TEXE)
SQLITE3_SHELL_TARGET_1 =
705
706
707
708
709
710
711















712
713
714
715
716
717
718
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







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







	$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)

fuzzcheck-asan$(TEXE):	$(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
	$(LTLINK) -o $@ -fsanitize=address $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)

fuzzcheck-ubsan$(TEXE):	$(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
	$(LTLINK) -o $@ -fsanitize=undefined $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)

# Usage:    FUZZDB=filename make run-fuzzcheck
#
# Where filename is a fuzzcheck database, this target builds and runs
# fuzzcheck, fuzzcheck-asan, and fuzzcheck-ubsan on that database.
#
# FUZZDB can be a glob pattern of two or more databases. Example:
#
#     FUZZDB=test/fuzzdata*.db make run-fuzzcheck
#
run-fuzzcheck:	fuzzcheck$(TEXE) fuzzcheck-asan$(TEXE) fuzzcheck-ubsan$(TEXE)
	@if test "$(FUZZDB)" = ""; then echo 'ERROR: No FUZZDB specified. Rerun with FUZZDB=filename'; exit 1; fi
	./fuzzcheck$(TEXE) --spinner $(FUZZDB)
	./fuzzcheck-asan$(TEXE) --spinner $(FUZZDB)
	./fuzzcheck-ubsan$(TEXE) --spinner $(FUZZDB)

ossshell$(TEXE):	$(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
             $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)

sessionfuzz$(TEXE):	$(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
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
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







-
+










-
+







	rm tsrc/sqlite.h.in tsrc/parse.y
	$(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
	mv vdbe.new tsrc/vdbe.c
	cp fts5.c fts5.h tsrc
	touch .target_source

sqlite3.c:	.target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84
	$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS)
	$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)
	cp tsrc/sqlite3ext.h .
	cp $(TOP)/ext/session/sqlite3session.h .

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

sqlite3r.c: sqlite3.c sqlite3r.h has_tclsh84
	cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
	cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
	cp $(TOP)/ext/recover/dbdata.c tsrc/
	$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_LINE_MACROS)
	$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)

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

tclsqlite3.c:	sqlite3.c
	echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
	cat sqlite3.c >>tclsqlite3.c
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
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







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

-
+







	cat $(TOP)/VERSION | $(TCLSH_CMD) $(TOP)/tool/replace.tcl exact . , >>$@
	echo '#endif' >>sqlite3rc.h

keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash$(BEXE) >keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
# Source and header files that shell.c depends on
SHELL_DEP = \
    $(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/completion.c \
        $(TOP)/ext/consio/console_io.c \
        $(TOP)/ext/consio/console_io.h \
        $(TOP)/ext/misc/decimal.c \
        $(TOP)/ext/misc/basexx.c \
        $(TOP)/ext/misc/base64.c \
        $(TOP)/ext/misc/base85.c \
	$(TOP)/ext/misc/fileio.c \
        $(TOP)/ext/misc/ieee754.c \
        $(TOP)/ext/misc/regexp.c \
        $(TOP)/ext/misc/series.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/sqlar.c \
        $(TOP)/ext/misc/uint.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
	$(TOP)/ext/misc/memtrace.c \
	$(TOP)/ext/misc/pcachetrace.c \
	$(TOP)/ext/recover/dbdata.c \
	$(TOP)/ext/recover/sqlite3recover.c \
	$(TOP)/ext/recover/sqlite3recover.h \
        $(TOP)/src/test_windirent.c
    $(TOP)/ext/consio/console_io.c \
    $(TOP)/ext/consio/console_io.h \
    $(TOP)/ext/expert/sqlite3expert.c \
    $(TOP)/ext/expert/sqlite3expert.h \
    $(TOP)/ext/intck/sqlite3intck.c \
    $(TOP)/ext/intck/sqlite3intck.h \
    $(TOP)/ext/misc/appendvfs.c \
    $(TOP)/ext/misc/base64.c \
    $(TOP)/ext/misc/base85.c \
    $(TOP)/ext/misc/completion.c \
    $(TOP)/ext/misc/decimal.c \
    $(TOP)/ext/misc/fileio.c \
    $(TOP)/ext/misc/ieee754.c \
    $(TOP)/ext/misc/memtrace.c \
    $(TOP)/ext/misc/pcachetrace.c \
    $(TOP)/ext/misc/regexp.c \
    $(TOP)/ext/misc/series.c \
    $(TOP)/ext/misc/shathree.c \
    $(TOP)/ext/misc/sqlar.c \
    $(TOP)/ext/misc/uint.c \
    $(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_SRC) $(TOP)/tool/mkshellc.tcl has_tclsh84
shell.c:	$(SHELL_DEP) $(TOP)/tool/mkshellc.tcl has_tclsh84
	$(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c




# Rules to build the extension objects.
#
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
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







+
+










-
+

-
+







TESTFIXTURE_FLAGS += -DBUILD_sqlite
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
TESTFIXTURE_FLAGS += -DSQLITE_STATIC_RANDOMJSON
TESTFIXTURE_FLAGS += -DSQLITE_STRICT_SUBTYPE=1

TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))

testfixture$(TEXE):	has_tclsh85 $(TESTFIXTURE_SRC)
	$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
		-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)

coretestprogs:	$(TESTPROGS)
coretestprogs:	testfixture$(BEXE) sqlite3$(BEXE)

testprogs:	coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE)
testprogs:	$(TESTPROGS) srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE)

# A very detailed test running most or all test cases
fulltest:	alltest fuzztest

# Run most or all tcl test cases
alltest:	$(TESTPROGS)
	./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
Changes to Makefile.msc.
13
14
15
16
17
18
19







20
21
22
23
24
25
26
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







+
+
+
+
+
+
+







# <<mark>>
# Set this non-0 to create and use the SQLite amalgamation file.
#
!IFNDEF USE_AMALGAMATION
USE_AMALGAMATION = 1
!ENDIF
# <</mark>>

# Optionally set EXTRA_SRC to a list of C files to append to
# the generated sqlite3.c.
#
!IFNDEF EXTRA_SRC
EXTRA_SRC =
!ENDIF

# Set this non-0 to enable full warnings (-W4, etc) when compiling.
#
!IFNDEF USE_FULLWARN
USE_FULLWARN = 1
!ENDIF

1580
1581
1582
1583
1584
1585
1586

1587
1588
1589
1590
1591
1592
1593
1594
1595
1596


1597
1598
1599
1600
1601
1602
1603
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613







+










+
+







  $(TOP)\ext\misc\ieee754.c \
  $(TOP)\ext\misc\mmapwarm.c \
  $(TOP)\ext\misc\nextchar.c \
  $(TOP)\ext\misc\normalize.c \
  $(TOP)\ext\misc\percentile.c \
  $(TOP)\ext\misc\prefixes.c \
  $(TOP)\ext\misc\qpvtab.c \
  $(TOP)\ext\misc\randomjson.c \
  $(TOP)\ext\misc\regexp.c \
  $(TOP)\ext\misc\remember.c \
  $(TOP)\ext\misc\series.c \
  $(TOP)\ext\misc\spellfix.c \
  $(TOP)\ext\misc\totype.c \
  $(TOP)\ext\misc\unionvtab.c \
  $(TOP)\ext\misc\wholenumber.c \
  $(TOP)\ext\rtree\test_rtreedoc.c \
  $(TOP)\ext\recover\sqlite3recover.c \
  $(TOP)\ext\recover\test_recover.c \
  $(TOP)\ext\intck\test_intck.c  \
  $(TOP)\ext\intck\sqlite3intck.c \
  $(TOP)\ext\recover\dbdata.c 

# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0
TESTEXT = $(TESTEXT) $(TOP)\ext\misc\zipfile.c
!ENDIF
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697
1698
1699
1700
1701
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712







+







!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
!ENDIF

# <<mark>>
# Extra compiler options for various test tools.
#
MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_FTS5
FUZZERSHELL_COMPILE_OPTS =
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
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







+
+
















+







FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_STAT4
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MMAP_SIZE=0
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRIVATE=""
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_STRICT_SUBTYPE=1
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_STATIC_RANDOMJSON

FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS5
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzcheck.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\ossfuzz.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c

OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
KV_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
ST_COMPILE_OPTS = -DSQLITE_THREADSAFE=0

# Standard options to testfixture.
1819
1820
1821
1822
1823
1824
1825
1826
1827


1828
1829
1830
1831
1832
1833
1834
1833
1834
1835
1836
1837
1838
1839


1840
1841
1842
1843
1844
1845
1846
1847
1848







-
-
+
+







# <</block2>>

$(SQLITE3EXE):	shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
	$(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) shell.c $(SHELL_CORE_SRC) \
		/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)

# <<mark>>
sqldiff.exe:	$(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
sqldiff.exe:	$(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.h $(TOP)\ext\consio\console_io.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -I$(TOP)\ext\consio $(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)

dbhash.exe:	$(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

scrub.exe:	$(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

1904
1905
1906
1907
1908
1909
1910
1911

1912
1913
1914
1915
1916
1917
1918
1918
1919
1920
1921
1922
1923
1924

1925
1926
1927
1928
1929
1930
1931
1932







-
+







	copy /B tsrc\fts5.h +,,
	del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL
	$(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
	move vdbe.new tsrc\vdbe.c
	echo > .target_source

sqlite3.c:	.target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-verify.exe
	$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
	$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) $(EXTRA_SRC)

sqlite3-all.c:	sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
	$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
# <</mark>>

# Rule to build the amalgamation
#
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284





























2285
2286
2287
2288
2289
2290


2291
2292
2293

2294
2295
2296
2297
2298
2299
2300
2268
2269
2270
2271
2272
2273
2274
























2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307


2308
2309
2310
2311

2312
2313
2314
2315
2316
2317
2318
2319







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




-
-
+
+


-
+







mkkeywordhash.exe:	$(TOP)\tool\mkkeywordhash.c
	$(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) \
		$(TOP)\tool\mkkeywordhash.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS)

keywordhash.h:	$(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
	.\mkkeywordhash.exe > keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)\src\shell.c.in \
	$(TOP)\ext\consio\console_io.c \
	$(TOP)\ext\consio\console_io.h \
	$(TOP)\ext\misc\appendvfs.c \
	$(TOP)\ext\misc\completion.c \
	$(TOP)\ext\misc\base64.c \
	$(TOP)\ext\misc\base85.c \
	$(TOP)\ext\misc\decimal.c \
	$(TOP)\ext\misc\fileio.c \
	$(TOP)\ext\misc\ieee754.c \
	$(TOP)\ext\misc\regexp.c \
	$(TOP)\ext\misc\series.c \
	$(TOP)\ext\misc\shathree.c \
	$(TOP)\ext\misc\uint.c \
	$(TOP)\ext\expert\sqlite3expert.c \
	$(TOP)\ext\expert\sqlite3expert.h \
	$(TOP)\ext\misc\memtrace.c \
	$(TOP)\ext\misc\pcachetrace.c \
	$(TOP)\ext\recover\dbdata.c \
	$(TOP)\ext\recover\sqlite3recover.c \
	$(TOP)\ext\recover\sqlite3recover.h \
	$(TOP)\src\test_windirent.c
# Source and header files that shell.c depends on
SHELL_DEP = \
    $(TOP)\src\shell.c.in \
    $(TOP)\ext\consio\console_io.c \
    $(TOP)\ext\consio\console_io.h \
    $(TOP)\ext\expert\sqlite3expert.c \
    $(TOP)\ext\expert\sqlite3expert.h \
    $(TOP)\ext\intck\sqlite3intck.c \
    $(TOP)\ext\intck\sqlite3intck.h \
    $(TOP)\ext\misc\appendvfs.c \
    $(TOP)\ext\misc\base64.c \
    $(TOP)\ext\misc\base85.c \
    $(TOP)\ext\misc\completion.c \
    $(TOP)\ext\misc\decimal.c \
    $(TOP)\ext\misc\fileio.c \
    $(TOP)\ext\misc\ieee754.c \
    $(TOP)\ext\misc\memtrace.c \
    $(TOP)\ext\misc\pcachetrace.c \
    $(TOP)\ext\misc\regexp.c \
    $(TOP)\ext\misc\series.c \
    $(TOP)\ext\misc\shathree.c \
    $(TOP)\ext\misc\sqlar.c \
    $(TOP)\ext\misc\uint.c \
    $(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

# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0
SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\sqlar.c
SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\zipfile.c
SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\sqlar.c
SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\zipfile.c
!ENDIF

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

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

# Rules to build the extension objects.
#
2429
2430
2431
2432
2433
2434
2435


2436
2437
2438
2439
2440
2441
2442
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463







+
+







TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STATIC_RANDOMJSON
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STRICT_SUBTYPE=1

TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
!IF $(USE_AMALGAMATION)==0
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
!ELSE
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1)
2471
2472
2473
2474
2475
2476
2477
2478

2479
2480

2481
2482
2483
2484
2485
2486
2487
2492
2493
2494
2495
2496
2497
2498

2499
2500

2501
2502
2503
2504
2505
2506
2507
2508







-
+

-
+







extensiontest:	testfixture.exe testloadext.dll
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)

tool-zip:	testfixture.exe sqlite3.exe sqldiff.exe sqlite3_analyzer.exe $(TOP)\tool\mktoolzip.tcl
	.\testfixture.exe $(TOP)\tool\mktoolzip.tcl

coretestprogs:	$(TESTPROGS)
coretestprogs:	testfixture.exe sqlite3.exe

testprogs:	coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe
testprogs:	$(TESTPROGS) srcck1.exe fuzzcheck.exe sessionfuzz.exe

fulltest:	alltest fuzztest

alltest:	$(TESTPROGS)
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)

2528
2529
2530
2531
2532
2533
2534
2535

2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546

2547
2548
2549
2550
2551
2552
2553
2549
2550
2551
2552
2553
2554
2555

2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566

2567
2568
2569
2570
2571
2572
2573
2574







-
+










-
+







devtest:	testfixture.exe fuzztest testrunner

mdevtest:
	$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest

# Testing for a release
#
releasetest: testfixture.exe fuzztest
releasetest: testfixture.exe
	testfixture.exe $(TOP)\test\testrunner.tcl release


smoketest:	$(TESTPROGS)
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)

shelltest: $(TESTPROGS)
	.\testfixture.exe $(TOP)\test\permutations.test shell

sqlite3_analyzer.c:	$(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
sqlite3_analyzer.c:	$(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\consio\console_io.h $(TOP)\ext\consio\console_io.c $(SQLITE_TCL_DEP)
	$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@

sqlite3_analyzer.exe:	sqlite3_analyzer.c $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
		/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)

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
Changes to README.md.
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169







-
+







the "tclsqlite.c" file which implements the
[Tcl bindings](https://sqlite.org/tclsqlite.html) for SQLite.
(Historical note:  SQLite began as a Tcl
extension and only later escaped to the wild as an independent library.)

Test scripts and programs are found in the **test/** subdirectory.
Additional test code is found in other source repositories.
See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for
See [How SQLite Is Tested](https://www.sqlite.org/testing.html) for
additional information.

The **ext/** subdirectory contains code for extensions.  The
Full-text search engine is in **ext/fts3**.  The R-Tree engine is in
**ext/rtree**.  The **ext/misc** subdirectory contains a number of
smaller, single-file extensions, such as a REGEXP operator.

179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
179
180
181
182
183
184
185

186
187
188
189
190
191
192
193







-
+







of the automatically-generated files, simply run "make target&#95;source".
The "target&#95;source" make target will create a subdirectory "tsrc/" and
fill it with all the source files needed to build SQLite, both
manually-edited files and automatically-generated files.

The SQLite interface is defined by the **sqlite3.h** header file, which is
generated from src/sqlite.h.in, ./manifest.uuid, and ./VERSION.  The
[Tcl script](http://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion.
[Tcl script](https://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion.
The manifest.uuid file contains the SHA3 hash of the particular check-in
and is used to generate the SQLITE\_SOURCE\_ID macro.  The VERSION file
contains the current SQLite version number.  The sqlite3.h header is really
just a copy of src/sqlite.h.in with the source-id and version number inserted
at just the right spots. Note that comment text in the sqlite3.h file is
used to generate much of the SQLite API documentation.  The Tcl scripts
used to generate that documentation are in a separate source repository.
246
247
248
249
250
251
252
253

254
255
256
257


258
259
260


261
262
263
264
265
266
267
246
247
248
249
250
251
252

253
254
255


256
257
258


259
260
261
262
263
264
265
266
267







-
+


-
-
+
+

-
-
+
+







all of the source code is contained within a single translation unit so
that the compiler can do extra cross-procedure optimization, but no
individual source file exceeds 32K lines in length.

## How It All Fits Together

SQLite is modular in design.
See the [architectural description](http://www.sqlite.org/arch.html)
See the [architectural description](https://www.sqlite.org/arch.html)
for details. Other documents that are useful in
(helping to understand how SQLite works include the
[file format](http://www.sqlite.org/fileformat2.html) description,
the [virtual machine](http://www.sqlite.org/opcode.html) that runs
[file format](https://www.sqlite.org/fileformat2.html) description,
the [virtual machine](https://www.sqlite.org/opcode.html) that runs
prepared statements, the description of
[how transactions work](http://www.sqlite.org/atomiccommit.html), and
the [overview of the query planner](http://www.sqlite.org/optoverview.html).
[how transactions work](https://www.sqlite.org/atomiccommit.html), and
the [overview of the query planner](https://www.sqlite.org/optoverview.html).

Years of effort have gone into optimizing SQLite, both
for small size and high performance.  And optimizations tend to result in
complex code.  So there is a lot of complexity in the current SQLite
implementation.  It will not be the easiest library in the world to hack.

Key files:
349
350
351
352
353
354
355
356

357
358
359


349
350
351
352
353
354
355

356
357


358
359







-
+

-
-
+
+

Using the makefile to verify source integrity is good for detecting
accidental changes to the source tree, but malicious changes could be
hidden by also modifying the makefiles.

## Contacts

The main SQLite website is [http:/sqlite.org/](http://sqlite.org/)
The main SQLite website is [https://sqlite.org/](https://sqlite.org/)
with geographically distributed backups at
[http://www2.sqlite.org/](http://www2.sqlite.org) and
[http://www3.sqlite.org/](http://www3.sqlite.org).
[https://www2.sqlite.org/](https://www2.sqlite.org) and
[https://www3.sqlite.org/](https://www3.sqlite.org).
Changes to VERSION.
1


1
-
+
3.44.1
3.46.0
Added art/icon-243x273.gif.

cannot compute difference between binary files

Added art/icon-80x90.gif.

cannot compute difference between binary files

Changes to autoconf/Makefile.msc.
13
14
15
16
17
18
19







20
21
22
23
24
25
26
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







+
+
+
+
+
+
+







###############################################################################

# The toplevel directory of the source tree.  This is the directory
# that contains this "Makefile.msc".
#
TOP = .


# Optionally set EXTRA_SRC to a list of C files to append to
# the generated sqlite3.c.
#
!IFNDEF EXTRA_SRC
EXTRA_SRC =
!ENDIF

# Set this non-0 to enable full warnings (-W4, etc) when compiling.
#
!IFNDEF USE_FULLWARN
USE_FULLWARN = 1
!ENDIF

986
987
988
989
990
991
992

993
994
995
996
997
998
999
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007







+







!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
!ENDIF


# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
core:	dll shell
Changes to autoconf/tea/configure.ac.
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29







-
+







# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
# so that we create the export library with the dll.
#-----------------------------------------------------------------------

AC_INIT([sqlite],[3.44.1])
AC_INIT([sqlite],[3.46.0])

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

Changes to configure.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.44.1.
# Generated by GNU Autoconf 2.69 for sqlite 3.46.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
722
723
724
725
726
727
728
729
730


731
732
733
734
735
736
737
722
723
724
725
726
727
728


729
730
731
732
733
734
735
736
737







-
-
+
+







subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.44.1'
PACKAGE_STRING='sqlite 3.44.1'
PACKAGE_VERSION='3.46.0'
PACKAGE_STRING='sqlite 3.46.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
1468
1469
1470
1471
1472
1473
1474
1475

1476
1477
1478
1479
1480
1481
1482
1468
1469
1470
1471
1472
1473
1474

1475
1476
1477
1478
1479
1480
1481
1482







-
+







#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures sqlite 3.44.1 to adapt to many kinds of systems.
\`configure' configures sqlite 3.46.0 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.
1533
1534
1535
1536
1537
1538
1539
1540

1541
1542
1543
1544
1545
1546
1547
1533
1534
1535
1536
1537
1538
1539

1540
1541
1542
1543
1544
1545
1546
1547







-
+







  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of sqlite 3.44.1:";;
     short | recursive ) echo "Configuration of sqlite 3.46.0:";;
   esac
  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
1664
1665
1666
1667
1668
1669
1670
1671

1672
1673
1674
1675
1676
1677
1678
1664
1665
1666
1667
1668
1669
1670

1671
1672
1673
1674
1675
1676
1677
1678







-
+







    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
sqlite configure 3.44.1
sqlite configure 3.46.0
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
2083
2084
2085
2086
2087
2088
2089
2090

2091
2092
2093
2094
2095
2096
2097
2083
2084
2085
2086
2087
2088
2089

2090
2091
2092
2093
2094
2095
2096
2097







-
+







  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by sqlite $as_me 3.44.1, which was
It was created by sqlite $as_me 3.46.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
12477
12478
12479
12480
12481
12482
12483
12484

12485
12486
12487
12488
12489
12490
12491
12477
12478
12479
12480
12481
12482
12483

12484
12485
12486
12487
12488
12489
12490
12491







-
+







test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.44.1, which was
This file was extended by sqlite $as_me 3.46.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@
12543
12544
12545
12546
12547
12548
12549
12550

12551
12552
12553
12554
12555
12556
12557
12543
12544
12545
12546
12547
12548
12549

12550
12551
12552
12553
12554
12555
12556
12557







-
+








Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.44.1
sqlite config.status 3.46.0
configured by $0, generated by GNU Autoconf 2.69,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

Changes to configure.ac.
70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84







-
+







#        target platform.  "" for Unix and ".exe" for windows.
#
# This configure.in file is easy to reuse on other projects.  Just
# change the argument to AC_INIT.  And disable any features that
# you don't need (for example BLT) by erasing or commenting out
# the corresponding code.
#
AC_INIT([sqlite],[m4_esyscmd(cat VERSION | tr -d '\n')])
AC_INIT([sqlite],m4_esyscmd(cat VERSION | tr -d '\n'))

dnl Make sure the local VERSION file matches this configure script
sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'`
if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then
AC_MSG_ERROR([configure script is out of date:
 configure \$PACKAGE_VERSION = $PACKAGE_VERSION
 top level VERSION file     = $sqlite_version_sanity_check
Changes to doc/compile-for-windows.md.
1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Notes On Compiling SQLite On Windows 11

Here are step-by-step instructions on how to build SQLite from
canonical source on a new Windows 11 PC, as of 2023-08-16:
canonical source on a new Windows 11 PC, as of 2023-11-01:

  1.  Install Microsoft Visual Studio. The free "community edition" 
      will work fine.  Do a standard install for C++ development.
      SQLite only needs the
      "cl" compiler and the "nmake" build tool.

  2.  Under the "Start" menu, find "All Apps" then go to "Visual Studio 20XX"
80
81
82
83
84
85
86












87
88
89
90
91
92
93
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







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







  3.  Ensure that `c:\tcl32\bin` comes before `c:\tcl\bin` on
      your PATH environment variable.  You can achieve this using
      a command like:
      <ul>
      <li>  `set PATH=c:\tcl32\bin;%PATH%`
      </ul>

## Building a DLL

The command the developers use for building the deliverable DLL on the 
[download page](https://sqlite.org/download.html) is as follows:

> ~~~~
nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
~~~~

That command generates both the sqlite3.dll and sqlite3.def files.  The same
command works for both 32-bit and 64-bit builds.

## Statically Linking The TCL Library

Some utility programs associated with SQLite need to be linked
with TCL in order to function.  The [sqlite3_analyzer.exe program](https://sqlite.org/sqlanalyze.html)
is an example.  You can build as described above, and then
enter:

Added doc/jsonb.md.


































































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# The JSONB Format

This document describes SQLite's JSONB binary encoding of
JSON.

## 1.0 What Is JSONB?

Beginning with version 3.45.0 (circa 2024-01-01), SQLite supports an
alternative binary encoding of JSON which we call "JSONB".  JSONB is
a binary format that stored as a BLOB.

The advantage of JSONB over ordinary text RFC 8259 JSON is that JSONB
is both slightly smaller (by between 5% and 10% in most cases) and
can be processed in less than half the number of CPU cycles.  The built-in
[JSON SQL functions] of SQLite can accept either ordinary text JSON
or the binary JSONB encoding for any of their JSON inputs.

The "JSONB" name is inspired by [PostgreSQL](https://postgresql.org), but the
on-disk format for SQLite's JSONB is not the same as PostgreSQL's.
The two formats have the same name, but they have wildly different internal
representations and are not in any way binary compatible.

The central idea behind this JSONB specification is that each element
begins with a header that includes the size and type of that element.
The header takes the place of punctuation such as double-quotes,
curly-brackes, square-brackets, commas, and colons.  Since the size
and type of each element is contained in its header, the element can
be read faster since it is no longer necessary to carefully scan forward
looking for the closing delimiter.  The payload of JSONB is the same
as for corresponding text JSON.  The same payload bytes occur in the
same order.  The only real difference between JSONB and ordinary text
JSON is that JSONB includes a binary header on
each element and omits delimiter and separator punctuation.

### 1.1 Internal Use Only

The details of the JSONB are not intended to be visible to application
developers.  Application developers should look at JSONB as an opaque BLOB
used internally by SQLite.  Nevertheless, we want the format to be backwards
compatible across all future versions of SQLite.  To that end, the format
is documented by this file in the source tree.  But this file should be
used only by SQLite core developers, not by developers of applications
that only use SQLite.

## 2.0 The Purpose Of This Document

JSONB is not intended as an external format to be used by
applications.  JSONB is designed for internal use by SQLite only.
Programmers do not need to understand the JSONB format in order to
use it effectively.
Applications should access JSONB only through the [JSON SQL functions],
not by looking at individual bytes of the BLOB.

However, JSONB is intended to be portable and backwards compatible
for all future versions of SQLite.  In other words, you should not have
to export and reimport your SQLite database files when you upgrade to
a newer SQLite version.  For that reason, the JSONB format needs to
be well-defined.

This document is therefore similar in purpose to the
[SQLite database file format] document that describes the on-disk
format of an SQLite database file.  Applications are not expected
to directly read and write the bits and bytes of SQLite database files.
The SQLite database file format is carefully documented so that it
can be stable and enduring.  In the same way, the JSONB representation
of JSON is documented here so that it too can be stable and enduring,
not so that applications can read or writes individual bytes.

## 3.0 Encoding

JSONB is a direct translation of the underlying text JSON. The difference
is that JSONB uses a binary encoding that is faster to parse compared to
the detailed syntax of text JSON.

Each JSON element is encoded as a header and a payload.  The header
determines type of element (string, numeric, boolean, null, object, or
array) and the size of the payload.  The header can be between 1 and
9 bytes in size.  The payload can be any size from zero bytes up to the
maximum allowed BLOB size.

### 3.1 Payload Size

The upper four bits of the first byte of the header determine size of the
header and possibly also the size of the payload.
If the upper four bits have a value between 0 and 11, then the header is
exactly one byte in size and the payload size is determined by those
upper four bits.  If the upper four bits have a value between 12 and 15,
that means that the total header size is 2, 3, 5, or 9 bytes and the
payload size is unsigned big-endian integer that is contained in the
subsequent bytes.  The size integer is the one byte that following the
initial header byte if the upper four bits
are 12, two bytes if the upper bits are 13, four bytes if the upper bits
are 14, and eight bytes if the upper bits are 15.  The current design
of SQLite does not support BLOB values larger than 2GiB, so the eight-byte
variant of the payload size integer will never be used by the current code.
The eight-byte payload size integer is included in the specification
to allow for future expansion.

The header for an element does *not* need to be in its simplest
form.  For example, consider the JSON numeric value "`1`".
That element can be encode in five different ways:

  *  `0x13 0x31`
  *  `0xc3 0x01 0x31`
  *  `0xd3 0x00 0x01 0x31`
  *  `0xe3 0x00 0x00 0x00 0x01 0x31`
  *  `0xf3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x31`

The shortest encoding is preferred, of course, and usually happens with
primitive elements such as numbers.  However the total size of an array
or object might not be known exactly when the header of the element is
first generated.  It is convenient to reserve space for the largest
possible header and then go back and fill in the correct payload size
at the end.  This technique can result in array or object headers that
are larger than absolutely necessary.

### 3.2 Element Type

The least-significant four bits of the first byte of the header (the first
byte masked against 0x0f) determine element type.  The following codes are
used:

<ol>
<li type="0"><p><b>NULL</b> &rarr;
The element is a JSON "null".  The payload size for a true JSON NULL must
must be zero.  Future versions of SQLite might extend the JSONB format
with elements that have a zero element type but a non-zero size.  In that
way, legacy versions of SQLite will interpret the element as a NULL 
for backwards compatibility while newer versions will interpret the
element in some other way.

<li value="1"><p><b>TRUE</b> &rarr;
The element is a JSON "true".  The payload size must be zero for a actual
"true" value.  Elements with type 1 and a non-zero payload size are
reserved for future expansion.  Legacy implementations that see an element
type of 1 with a non-zero payload size should continue to interpret that
element as "true" for compatibility.

<li value="2"><p><b>FALSE</b> &rarr;
The element is a JSON "false".  The payload size must be zero for a actual
"false" value.  Elements with type 2 and a non-zero payload size are
reserved for future expansion.  Legacy implementations that see an element
type of 2 with a non-zero payload size should continue to interpret that
element as "false" for compatibility.

<li value="3"><p><b>INT</b> &rarr;
The element is a JSON integer value in the canonical
RFC 8259 format, without extensions.  The payload is the ASCII
text representation of that numeric value.

<li value="4"><p><b>INT5</b> &rarr;
The element is a JSON integer value that is not in the
canonical format.   The payload is the ASCII
text representation of that numeric value.  Because the payload is in a
non-standard format, it will need to be translated when the JSONB is
converted into RFC 8259 text JSON.

<li value="5"><p><b>FLOAT</b> &rarr;
The element is a JSON floating-point value in the canonical
RFC 8259 format, without extensions.  The payload is the ASCII
text representation of that numeric value.

<li value="6"><p><b>FLOAT5</b> &rarr;
The element is a JSON floating-point value that is not in the
canonical format.   The payload is the ASCII
text representation of that numeric value.  Because the payload is in a
non-standard format, it will need to be translated when the JSONB is
converted into RFC 8259 text JSON.

<li value="7"><p><b>TEXT</b> &rarr;
The element is a JSON string value that does not contain
any escapes nor any characters that need to be escaped for either SQL or
JSON.  The payload is the UTF8 text representation of the string value.
The payload does <i>not</i> include string delimiters.

<li value="8"><p><b>TEXTJ</b> &rarr;
The element is a JSON string value that contains
RFC 8259 character escapes (such as "<tt>\n</tt>" or "<tt>\u0020</tt>").
Those escapes will need to be translated into actual UTF8 if this element
is [json_extract|extracted] into SQL.
The payload is the UTF8 text representation of the escaped string value.
The payload does <i>not</i> include string delimiters.

<li value="9"><p><b>TEXT5</b> &rarr;
The element is a JSON string value that contains
character escapes, including some character escapes that part of JSON5
and which are not found in the canonical RFC 8259 spec.
Those escapes will need to be translated into standard JSON prior to
rendering the JSON as text, or into their actual UTF8 characters if this
element is [json_extract|extracted] into SQL.
The payload is the UTF8 text representation of the escaped string value.
The payload does <i>not</i> include string delimiters.

<li value="10"><p><b>TEXTRAW</b> &rarr;
The element is a JSON string value that contains
UTF8 characters that need to be escaped if this string is rendered into
standard JSON text.
The payload does <i>not</i> include string delimiters.

<li value="11"><p><b>ARRAY</b> &rarr;
The element is a JSON array.  The payload contains
JSONB elements that comprise values contained within the array.

<li value="12"><p><b>OBJECT</b> &rarr;
The element is a JSON object.  The payload contains
pairs of JSONB elements that comprise entries for the JSON object.
The first element in each pair must be a string (types 7 through 10).
The second element of each pair may be any types, including nested
arrays or objects.

<li value="13"><p><b>RESERVED-13</b> &rarr;
Reserved for future expansion.  Legacy implements that encounter this
element type should raise an error.

<li value="14"><p><b>RESERVED-14</b> &rarr;
Reserved for future expansion.  Legacy implements that encounter this
element type should raise an error.

<li value="15"><p><b>RESERVED-15</b> &rarr;
Reserved for future expansion.  Legacy implements that encounter this
element type should raise an error.
</ol>

Element types outside the range of 0 to 12 are reserved for future
expansion.  The current implement raises an error if see an element type
other than those listed above.  However, future versions of SQLite might
use of the three remaining element types to implement indexing or similar
optimizations, to speed up lookup against large JSON arrays and/or objects.

### 3.3 Design Rationale For Element Types

A key goal of JSONB is that it should be quick to translate
to and from text JSON and/or be constructed from SQL values.
When converting from text into JSONB, we do not want the
converter subroutine to burn CPU cycles converting elements
values into some standard format which might never be used.
Format conversion is "lazy" - it is deferred until actually
needed.  This has implications for the JSONB format design:

  1.   Numeric values are stored as text, not a numbers.  The values are
       a direct copy of the text JSON values from which they are derived.

  2.   There are multiple element types depending on the details of value
       formats.  For example, INT is used for pure RFC-8259 integer
       literals and INT5 exists for JSON5 extensions such as hexadecimal
       notation.  FLOAT is used for pure RFC-8259 floating point literals
       and FLOAT5 is used for JSON5 extensions.  There are four different
       representations of strings, depending on where the string came from
       and how special characters within the string are escaped.

A second goal of JSONB is that it should be capable of serving as the
"parse tree" for JSON when a JSON value is being processed by the
various [JSON SQL functions] built into SQLite.  Before JSONB was
developed, operations such [json_replace()] and [json_patch()]
and similar worked in three stages:


  1.  Translate the text JSON into a internal format that is
      easier to scan and edit.
  2.  Perform the requested operation on the JSON.
  3.  Translate the internal format back into text.

JSONB seeks to serve as the internal format directly - bypassing
the first and third stages of that process.  Since most of the CPU
cycles are spent on the first and third stages, that suggests that
JSONB processing will be much faster than text JSON processing.

So when processing JSONB, only the second stage of the three-stage
process is required.  But when processing text JSON, it is still necessary
to do stages one and three.  If JSONB is to be used as the internal
binary representation, this is yet another reason to store numeric
values as text.  Storing numbers as text minimizes the amount of
conversion work needed for stages one and three.  This is also why
there are four different representations of text in JSONB.  Different
text representations are used for text coming from different sources
(RFC-8259 JSON, JSON5, or SQL string values) and conversions only
happen if and when they are actually needed.

### 3.4 Valid JSONB BLOBs

A valid JSONB BLOB consists of a single JSON element.  The element must
exactly fill the BLOB.  This one element is often a JSON object or array
and those usually contain additional elements as its payload, but the
element can be a primite value such a string, number, boolean, or null.

When the built-in JSON functions are attempting to determine if a BLOB
argument is a JSONB or just a random BLOB, they look at the header of
the outer element to see that it is well-formed and that the element
completely fills the BLOB.  If these conditions are met, then the BLOB
is accepted as a JSONB value.
Changes to doc/lemon.html.
679
680
681
682
683
684
685

686
687
688
689
690
691
692
693
694
695

696
697
698
699
700
701
702
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704







+










+







<li><tt><a href='#default_destructor'>%default_destructor</a></tt>
<li><tt><a href='#default_type'>%default_type</a></tt>
<li><tt><a href='#destructor'>%destructor</a></tt>
<li><tt><a href='#pifdef'>%else</a></tt>
<li><tt><a href='#pifdef'>%endif</a></tt>
<li><tt><a href='#extraarg'>%extra_argument</a></tt>
<li><tt><a href='#pfallback'>%fallback</a></tt>
<li><tt><a href='#reallc'>%free</a></tt>
<li><tt><a href='#pifdef'>%if</a></tt>
<li><tt><a href='#pifdef'>%ifdef</a></tt>
<li><tt><a href='#pifdef'>%ifndef</a></tt>
<li><tt><a href='#pinclude'>%include</a></tt>
<li><tt><a href='#pleft'>%left</a></tt>
<li><tt><a href='#pname'>%name</a></tt>
<li><tt><a href='#pnonassoc'>%nonassoc</a></tt>
<li><tt><a href='#parse_accept'>%parse_accept</a></tt>
<li><tt><a href='#parse_failure'>%parse_failure</a></tt>
<li><tt><a href='#pright'>%right</a></tt>
<li><tt><a href='#reallc'>%realloc</a></tt>
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
<li><tt><a href='#stack_size'>%stack_size</a></tt>
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
<li><tt><a href='#token'>%token</a></tt>
<li><tt><a href='#token_class'>%token_class</a></tt>
<li><tt><a href='#token_destructor'>%token_destructor</a></tt>
1196
1197
1198
1199
1200
1201
1202















1203
1204
1205
1206
1207
1208
1209
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







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







period.  This directive specifies that the identified token should
match any input token.</p>

<p>When the generated parser has the choice of matching an input against
the wildcard token and some other token, the other token is always used.
The wildcard token is only matched if there are no alternatives.</p>

<a id='reallc'></a>
<h4>4.4.26 The <tt>%realloc</tt> and <tt>%free</tt> directives</h4>

<p>The <tt>%realloc</tt> and <tt>%free</tt> directives defines function
that allocate and free heap memory.  The signatures of these functions
should be the same as the realloc() and free() functions from the standard
C library.

<p>If both of these functions are defined
then these functions are used to allocate and free
memory for supplemental parser stack space, if the initial
parse stack space is exceeded.  The initial parser stack size
is specified by either <tt>%stack_size</tt> or the
-DYYSTACKDEPTH compile-time flag.

<a id='errors'></a>
<h2>5.0 Error Processing</h2>

<p>After extensive experimentation over several years, it has been
discovered that the error recovery strategy used by yacc is about
as good as it gets.  And so that is what Lemon uses.</p>

1219
1220
1221
1222
1223
1224
1225

1226
1227
1228
1229
1230
1231
1232
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250







+







<p>If the parser pops its stack until the stack is empty, and it still
is unable to shift the error symbol, then the
<tt><a href='#parse_failure'>%parse_failure</a></tt> routine
is invoked and the parser resets itself to its start state, ready
to begin parsing a new file.  This is what will happen at the very
first syntax error, of course, if there are no instances of the
"error" non-terminal in your grammar.</p>


<a id='history'></a>
<h2>6.0 History of Lemon</h2>

<p>Lemon was originally written by Richard Hipp sometime in the late
1980s on a Sun4 Workstation using K&amp;R C.  
There was a companion LL(1) parser generator program named "Lime".
Changes to doc/testrunner.md.
1
2
3
4



















5
6
7
8
9
10
11
12
13





14
15
16
17





18
19
20
21
22
23
24
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




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







-
-
+
+
+
+
+


-
-
+
+
+
+
+









# The testrunner.tcl Script

<ul type=none>
  <li> 1. <a href=#overview>Overview</a>
  <li> 2. <a href=#binary_tests>Binary Tests</a>
<ul type=none>
  <li> 2.1. <a href=#organization_tests>Organization of Tcl Tests</a>
  <li> 2.2. <a href=#run_tests>Commands to Run Tests</a>
  <li> 2.3. <a href=#binary_test_failures>Investigating Binary Test Failures</a>
</ul>
  <li> 3. <a href=#source_code_tests>Source Tests</a>
<ul type=none>
  <li> 3.1. <a href=#commands_to_run_tests>Commands to Run SQLite Tests</a>
  <li> 3.2. <a href=#zipvfs_tests>Running ZipVFS Tests</a>
  <li> 3.3. <a href=#source_code_test_failures>Investigating Source Code Test Failures</a>
</ul>
  <li> 4. <a href=#testrunner_options>Extra testrunner.tcl Options</a>
  <li> 5. <a href=#cpu_cores>Controlling CPU Core Utilization</a>
</ul>

<a name=overview></a>
# 1. Overview

testrunner.tcl is a Tcl script used to run multiple SQLite tests using 
multiple jobs. It supports the following types of tests:

  *  Tcl test scripts.

  *  Tests run with [make] commands. Specifically, at time of writing, 
     [make fuzztest], [make mptest], [make sourcetest] and [make threadtest].
  *  Tests run with `make` commands.  Examples:
      -  `make mdevtest`
      -  `make releasetest`
      -  `make sdevtest`
      -  `make testrunner`

testrunner.tcl pipes the output of all tests and builds run into log file
**testrunner.log**, created in the cwd directory. Searching this file for
"failed" is a good way to find the output of a failed test.
**testrunner.log**, created in the current working directory. Search this
file to find details of errors.  Suggested search commands:

   *  `grep "^!" testrunner.log`
   *  `grep failed testrunner.log`

testrunner.tcl also populates SQLite database **testrunner.db**. This database
contains details of all tests run, running and to be run. A useful query
might be:

```
  SELECT * FROM script WHERE state='failed'
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
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







-
+



+



-
+

-
+











+








```
  watch ./testfixture $(TESTDIR)/testrunner.tcl status
```

in another terminal is a good way to keep an eye on a long running test.

Sometimes testrunner.tcl uses the [testfixture] binary that it is run with
Sometimes testrunner.tcl uses the `testfixture` binary that it is run with
to run tests (see "Binary Tests" below). Sometimes it builds testfixture and
other binaries in specific configurations to test (see "Source Tests").

<a name=binary_tests></a>
# 2. Binary Tests

The commands described in this section all run various combinations of the Tcl
test scripts using the [testfixture] binary used to run the testrunner.tcl
test scripts using the `testfixture` binary used to run the testrunner.tcl
script (i.e. they do not invoke the compiler to build new binaries, or the
[make] command to run tests that are not Tcl scripts). The procedure to run
`make` command to run tests that are not Tcl scripts). The procedure to run
these tests is therefore:

  1. Build the "testfixture" (or "testfixture.exe" for windows) binary using
     whatever method seems convenient.

  2. Test the binary built in step 1 by running testrunner.tcl with it, 
     perhaps with various options.

The following sub-sections describe the various options that can be
passed to testrunner.tcl to test binary testfixture builds.

<a name=organization_tests></a>
## 2.1. Organization of Tcl Tests

Tcl tests are stored in files that match the pattern *\*.test*. They are
found in both the $TOP/test/ directory, and in the various sub-directories
of the $TOP/ext/ directory of the source tree. Not all *\*.test* files
contain Tcl tests - a handful are Tcl scripts designed to invoke other
*\*.test* files.
87
88
89
90
91
92
93

94
95
96
97
98
99
100
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128







+







  *  Runtime configuration to apply before running each test script 
     (e.g. enabling auto-vacuum, or disable lookaside).

Running **all** tests is to run all tests in the full test set, plus a dozen
or so permutations. The specific permutations that are run as part of "all"
are defined in file *testrunner_data.tcl*.

<a name=run_tests></a>
## 2.2. Commands to Run Tests

To run the "veryquick" test set, use either of the following:

```
  ./testfixture $TESTDIR/testrunner.tcl
  ./testfixture $TESTDIR/testrunner.tcl veryquick
109
110
111
112
113
114
115






116
117
118
119
120
121
122
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156







+
+
+
+
+
+







To run the subset of the "full" test suite for which the test file name matches
a specified pattern (e.g. all tests that start with "fts5"), either of:

```
  ./testfixture $TESTDIR/testrunner.tcl fts5%
  ./testfixture $TESTDIR/testrunner.tcl 'fts5*'
```

Strictly speaking, for a test to be run the pattern must match the script
filename, not including the directory, using the rules of Tcl's 
\[string match\] command. Except that before the matching is done, any "%"
characters specified as part of the pattern are transformed to "\*".


To run "all" tests (full + permutations):

```
  ./testfixture $TESTDIR/testrunner.tcl all
```

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







+


















+
-
+


-
+








```
  ./testfixture $TESTDIR/testrunner.tcl $PERMUTATION $PATH_TO_SCRIPT
```

TODO: An example instead of "$PERMUTATION" and $PATH\_TO\_SCRIPT?

<a name=source_code_tests></a>
# 3. Source Code Tests

The commands described in this section invoke the C compiler to build 
binaries from the source tree, then use those binaries to run Tcl and
other tests. The advantages of this are that:

  *  it is possible to test multiple build configurations with a single
     command, and 

  *  it ensures that tests are always run using binaries created with the
     same set of compiler options.

The testrunner.tcl commands described in this section may be run using
either a *testfixture* (or testfixture.exe) build, or with any other Tcl
shell that supports SQLite 3.31.1 or newer via "package require sqlite3".

TODO: ./configure + Makefile.msc build systems.

<a name=commands_to_run_tests></a>
## Commands to Run SQLite Tests
## 3.1. Commands to Run SQLite Tests

The **mdevtest** command is equivalent to running the veryquick tests and
the [make fuzztest] target once for each of two --enable-all builds - one 
the `make fuzztest` target once for each of two --enable-all builds - one 
with debugging enabled and one without:

```
  tclsh $TESTDIR/testrunner.tcl mdevtest
```

In other words, it is equivalent to running:
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
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







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















+
-
+







on Linux, Windows or OSX. Refer to *testrunner\_data.tcl* for the details
of the specific tests run.

```
  tclsh $TESTDIR/testrunner.tcl release
```

As with <a href=#source code tests>source code tests</a>, one or more patterns
may be appended to any of the above commands (mdevtest, sdevtest or release).
In that case only Tcl tests (no fuzz or other tests) that match the specified
pattern are run. For example, to run the just the Tcl rtree tests in all 
builds and configurations supported by "release":

```
  tclsh $TESTDIR/testrunner.tcl release rtree%
```

<a name=zipvfs_tests></a>
## Running ZipVFS Tests
## 3.2. Running ZipVFS Tests

testrunner.tcl can build a zipvfs-enabled testfixture and use it to run
tests from the Zipvfs project with the following command:

```
  tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS
```

This can be combined with any of "mdevtest", "sdevtest" or "release" to
test both SQLite and Zipvfs with a single command:

```
  tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
```

<a name=source_code_test_failures></a>
## Investigating Source Code Test Failures
## 3.3. Investigating Source Code Test Failures

Investigating a test failure that occurs during source code testing is a
two step process:

  1. Recreating the build configuration in which the test failed, and

  2. Re-running the actual test.
236
237
238
239
240
241
242
243

244
245
246


247


248




























249

250
251
252
253
254
255
256
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







-
+



+
+

+
+

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







  tclsh $TESTDIR/testrunner.tcl script Device-One > make.sh 

  # Create a script that recreates build configuration "Have-Not" on Windows:
  tclsh $TESTDIR/testrunner.tcl script Have-Not > make.bat 
```

The generated bash or \*.bat file script accepts a single argument - a makefile
target to build. This may be used either to run a [make] command test directly,
target to build. This may be used either to run a `make` command test directly,
or else to build a testfixture (or testfixture.exe) binary with which to
run a Tcl test script, as <a href=#binary_test_failures>described above</a>.

<a name=testrunner_options></a>
# 4. Extra testrunner.tcl Options

The testrunner.tcl script options in this section may be used with both source
code and binary tests.

The **--buildonly** option instructs testrunner.tcl just to build the binaries
required by a test, not to run any actual tests. For example:

```
  # Build binaries required by release test.
  tclsh $TESTDIR/testrunner.tcl --buildonly release"
```

The **--dryrun** option prevents testrunner.tcl from building any binaries
or running any tests. Instead, it just writes the shell commands that it
would normally execute into the testrunner.log file. Example:

```
  # Log the shell commmands that make up the mdevtest test.
  tclsh $TESTDIR/testrunner.tcl --dryrun mdevtest"
```

The **--explain** option is similar to --dryrun in that it prevents testrunner.tcl
from building any binaries or running any tests.  The difference is that --explain
prints on standard output a human-readable summary of all the builds and tests that
would have been run.

```
  # Show what builds and tests would have been run
  tclsh $TESTDIR/testrunner.tcl --explain mdevtest
```

<a name=cpu_cores></a>
# 4. Controlling CPU Core Utilization
# 5. Controlling CPU Core Utilization

When running either binary or source code tests, testrunner.tcl reports the
number of jobs it intends to use to stdout. e.g.

```
  $ ./testfixture $TESTDIR/testrunner.tcl
  splitting work across 16 jobs
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
350
351
352
353
354
355
356















-
-
-
-
-
-
-
-
The number of jobs may also be changed while an instance of testrunner.tcl is
running by exucuting the following command from the directory containing the
testrunner.log and testrunner.db files:

```
  $ ./testfixture $TESTDIR/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
```








Changes to ext/consio/console_io.c.
20
21
22
23
24
25
26
27
28




29



30
31
32
33
34
35
36
20
21
22
23
24
25
26


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41







-
-
+
+
+
+

+
+
+








#ifndef SHELL_NO_SYSINC
# include <stdarg.h>
# include <string.h>
# include <stdlib.h>
# include <limits.h>
# include <assert.h>
# include "console_io.h"
# include "sqlite3.h"
# include "sqlite3.h"
#endif
#ifndef HAVE_CONSOLE_IO_H
# include "console_io.h"
#endif
#if defined(_MSC_VER)
# pragma warning(disable : 4204)
#endif

#ifndef SQLITE_CIO_NO_TRANSLATE
# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
#  ifndef SHELL_NO_SYSINC
#   include <io.h>
#   include <fcntl.h>
#   undef WIN32_LEAN_AND_MEAN
120
121
122
123
124
125
126




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







+
+
+
+







  return rv;
# else
  ppst->pf = pf;
  ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
  return ppst->reachesConsole;
# endif
}

# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#  define ENABLE_VIRTUAL_TERMINAL_PROCESSING  (0x4)
# endif

# if CIO_WIN_WC_XLATE
/* Define console modes for use with the Windows Console API. */
#  define SHELL_CONI_MODE \
  (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
  | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
#  define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
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
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







-
-
+
+












-
+







}
# endif

/* Get stream info, either for designated output or error stream when
** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
** In either case, ppst references a caller-owned PerStreamTags
** struct which may be filled in if none of the known writable
** streams is being held by consoleInfo. The ppf parameter is an
** output when chix!=0 and an input when chix==0.
** streams is being held by consoleInfo. The ppf parameter is a
** byref output when chix!=0 and a byref input when chix==0.
 */
static PerStreamTags *
getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
                  /* in/out */ FILE **ppf){
  PerStreamTags *ppstTry;
  FILE *pfEmit;
  if( chix > 0 ){
    ppstTry = &consoleInfo.pstDesignated[chix];
    if( !isValidStreamInfo(ppstTry) ){
      ppstTry = &consoleInfo.pstSetup[chix];
      pfEmit = ppst->pf;
    }else pfEmit = ppstTry->pf;
    if( !isValidStreamInfo(ppst) ){
    if( !isValidStreamInfo(ppstTry) ){
      pfEmit = (chix > 1)? stderr : stdout;
      ppstTry = ppst;
      streamOfConsole(pfEmit, ppstTry);
    }
    *ppf = pfEmit;
  }else{
    ppstTry = isKnownWritable(*ppf);
545
546
547
548
549
550
551
552
553

554
555
556
557

558
559
560
561
562
563
564
565
566
567

568
569

570
571

572
573

574
575
576
577
578
579
580
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







-
-
+



-
+









-
+

-
+

-
+

-
+







    }
  }
  return z;
}
#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/

#ifndef SQLITE_CIO_NO_TRANSLATE

#ifdef CONSIO_SPUTB
# ifdef CONSIO_SPUTB
SQLITE_INTERNAL_LINKAGE int
fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
  assert(pfO!=0);
# if CIO_WIN_WC_XLATE
#  if CIO_WIN_WC_XLATE
  PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
  PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
  if( pstReachesConsole(ppst) ){
    int rv;
    maybeSetupAsConsole(ppst, 1);
    rv = conZstrEmit(ppst, cBuf, nAccept);
    if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
    return rv;
  }else {
# endif
#  endif
    return (int)fwrite(cBuf, 1, nAccept, pfO);
# if CIO_WIN_WC_XLATE
#  if CIO_WIN_WC_XLATE
  }
# endif
#  endif
}
#endif /* defined(CONSIO_SPUTB) */
# endif

SQLITE_INTERNAL_LINKAGE int
oPutbUtf8(const char *cBuf, int nAccept){
  FILE *pfOut;
  PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
# if CIO_WIN_WC_XLATE
  PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
672
673
674
675
676
677
678



679

680
680
681
682
683
684
685
686
687
688
689

690
691







+
+
+
-
+

    return fgets(cBuf, ncMax, pfIn);
# if CIO_WIN_WC_XLATE
  }
# endif
}
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */

#if defined(_MSC_VER)
# pragma warning(default : 4204)
#endif
#undef CIO_WIN_WC_XLATE

#undef SHELL_INVALID_FILE_PTR
Changes to ext/consio/console_io.h.
18
19
20
21
22
23
24





25
26

27
28
29
30
31
32
33
18
19
20
21
22
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
38







+
+
+
+
+

-
+







** Platform dependencies are "hidden" here by various stratagems so
** that, provided certain conditions are met, the programs using this
** source or object code compiled from it need no explicit conditional
** compilation in their source for their console and stream I/O.
**
** The symbols and functionality exposed here are not a public API.
** This code may change in tandem with other project code as needed.
**
** When this .h file and its companion .c are directly incorporated into
** a source conglomeration (such as shell.c), the preprocessor symbol
** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
** translation for Windows is effected for the build.
*/

#define HAVE_CONSOLE_IO_H 1
#ifndef SQLITE_INTERNAL_LINKAGE
# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
# include <stdio.h>
#else
# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
#endif

157
158
159
160
161
162
163
164
165

166
167
168
169
170
171
172
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177







-

+







** accepted char or character sequence is limited by nAccept.
**
** Returns the number of accepted char values.
*/
#ifdef CONSIO_SPUTB
SQLITE_INTERNAL_LINKAGE int
fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
#endif
/* Like fPutbUtf8 except stream is always the designated output. */
#endif
SQLITE_INTERNAL_LINKAGE int
oPutbUtf8(const char *cBuf, int nAccept);
/* Like fPutbUtf8 except stream is always the designated error. */
#ifdef CONSIO_EPUTB
SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept);
#endif
Changes to ext/expert/expert1.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2009 Nov 11
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool. Specifically,
# the ".recommend" command.
#
#

# Test plan:
Changes to ext/expert/sqlite3expert.c.
1944
1945
1946
1947
1948
1949
1950
1951

1952
1953
1954
1955
1956
1957
1958
1944
1945
1946
1947
1948
1949
1950

1951
1952
1953
1954
1955
1956
1957
1958







-
+







#endif

  /* Copy the entire schema of database [db] into [dbm]. */
  if( rc==SQLITE_OK ){
    sqlite3_stmt *pSql = 0;
    rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, 
        "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
        " AND sql NOT LIKE 'CREATE VIRTUAL %%'"
        " AND sql NOT LIKE 'CREATE VIRTUAL %%' ORDER BY rowid"
    );
    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
      const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
      if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
    }
    idxFinalize(&rc, pSql);
  }
Changes to ext/fts3/fts3.c.
4002
4003
4004
4005
4006
4007
4008
4009

4010
4011
4012
4013
4014
4015
4016
4017
4018
4019


4020
4021
4022
4023
4024

4025
4026
4027
4028

4029
4030
4031
4032

4033
4034
4035
4036
4037
4038






4039
4040
4041


4042
4043
4044
4045
4046
4047
4048
4002
4003
4004
4005
4006
4007
4008

4009
4010
4011
4012
4013
4014
4015
4016



4017
4018
4019


4020

4021




4022




4023



4024
4025

4026
4027
4028
4029
4030
4031
4032


4033
4034
4035
4036
4037
4038
4039
4040
4041







-
+







-
-
-
+
+

-
-

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


-
+
+
+
+
+
+

-
-
+
+







  return 0;
}

/*
** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
** table.
*/
static int fts3Integrity(
static int fts3IntegrityMethod(
  sqlite3_vtab *pVtab,      /* The virtual table to be checked */
  const char *zSchema,      /* Name of schema in which pVtab lives */
  const char *zTabname,     /* Name of the pVTab table */
  int isQuick,              /* True if this is a quick_check */
  char **pzErr              /* Write error message here */
){
  Fts3Table *p = (Fts3Table*)pVtab;
  char *zSql;
  int rc;
  char *zErr = 0;
  int rc = SQLITE_OK;
  int bOk = 0;

  assert( pzErr!=0 );
  assert( *pzErr==0 );
  UNUSED_PARAMETER(isQuick);
  zSql = sqlite3_mprintf(
  rc = sqlite3Fts3IntegrityCheck(p, &bOk);
            "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
            zSchema, zTabname, zTabname);
  if( zSql==0 ){
    return SQLITE_NOMEM;
  assert( rc!=SQLITE_CORRUPT_VTAB );
  }
  rc = sqlite3_exec(p->db, zSql, 0, 0, &zErr);
  sqlite3_free(zSql);
  if( (rc&0xff)==SQLITE_CORRUPT ){
  if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
    *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
                p->bFts4 ? 4 : 3, zSchema, zTabname);
  }else if( rc!=SQLITE_OK ){
    *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
                             " FTS%d table %s.%s: %s",
                p->bFts4 ? 4 : 3, zSchema, zTabname, zErr);
                p->bFts4 ? 4 : 3, zSchema, zTabname, sqlite3_errstr(rc));
    if( *pzErr ) rc = SQLITE_OK;
  }else if( rc==SQLITE_OK && bOk==0 ){
    *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
                p->bFts4 ? 4 : 3, zSchema, zTabname);
    if( *pzErr==0 ) rc = SQLITE_NOMEM;
  }
  sqlite3_free(zErr);
  return SQLITE_OK;
  sqlite3Fts3SegmentsClose(p);
  return rc;
}



static const sqlite3_module fts3Module = {
  /* iVersion      */ 4,
  /* xCreate       */ fts3CreateMethod,
4064
4065
4066
4067
4068
4069
4070
4071

4072
4073
4074
4075
4076
4077
4078
4057
4058
4059
4060
4061
4062
4063

4064
4065
4066
4067
4068
4069
4070
4071







-
+







  /* xRollback     */ fts3RollbackMethod,
  /* xFindFunction */ fts3FindFunctionMethod,
  /* xRename */       fts3RenameMethod,
  /* xSavepoint    */ fts3SavepointMethod,
  /* xRelease      */ fts3ReleaseMethod,
  /* xRollbackTo   */ fts3RollbackToMethod,
  /* xShadowName   */ fts3ShadowName,
  /* xIntegrity    */ fts3Integrity,
  /* xIntegrity    */ fts3IntegrityMethod,
};

/*
** This function is registered as the module destructor (called when an
** FTS3 enabled database connection is closed). It frees the memory
** allocated for the tokenizer hash table.
*/
Changes to ext/fts3/fts3Int.h.
648
649
650
651
652
653
654


655
656
657
648
649
650
651
652
653
654
655
656
657
658
659







+
+



#ifndef SQLITE_DISABLE_FTS3_UNICODE
int sqlite3FtsUnicodeFold(int, int);
int sqlite3FtsUnicodeIsalnum(int);
int sqlite3FtsUnicodeIsdiacritic(int);
#endif

int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);

int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);

#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
Changes to ext/fts3/fts3_write.c.
5290
5291
5292
5293
5294
5295
5296
5297

5298
5299
5300
5301
5302
5303
5304
5290
5291
5292
5293
5294
5295
5296

5297
5298
5299
5300
5301
5302
5303
5304







-
+







** content table. If no error occurs and the contents do match, set *pbOk
** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk
** to false before returning.
**
** If an error occurs (e.g. an OOM or IO error), return an SQLite error 
** code. The final value of *pbOk is undefined in this case.
*/
static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){
  int rc = SQLITE_OK;             /* Return code */
  u64 cksum1 = 0;                 /* Checksum based on FTS index contents */
  u64 cksum2 = 0;                 /* Checksum based on %_content contents */
  sqlite3_stmt *pAllLangid = 0;   /* Statement to return all language-ids */

  /* This block calculates the checksum according to the FTS index. */
  rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
5368
5369
5370
5371
5372
5373
5374


5375




5376
5377
5378
5379
5380
5381
5382
5368
5369
5370
5371
5372
5373
5374
5375
5376

5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387







+
+
-
+
+
+
+







        }
      }
    }

    sqlite3_finalize(pStmt);
  }

  if( rc==SQLITE_CORRUPT_VTAB ){
    rc = SQLITE_OK;
  *pbOk = (cksum1==cksum2);
    *pbOk = 0;
  }else{
    *pbOk = (rc==SQLITE_OK && cksum1==cksum2);
  }
  return rc;
}

/*
** Run the integrity-check. If no error occurs and the current contents of
** the FTS index are correct, return SQLITE_OK. Or, if the contents of the
** FTS index are incorrect, return SQLITE_CORRUPT_VTAB.
5408
5409
5410
5411
5412
5413
5414
5415

5416
5417
5418
5419
5420
5421
5422
5413
5414
5415
5416
5417
5418
5419

5420
5421
5422
5423
5424
5425
5426
5427







-
+







** passed.
*/
static int fts3DoIntegrityCheck(
  Fts3Table *p                    /* FTS3 table handle */
){
  int rc;
  int bOk = 0;
  rc = fts3IntegrityCheck(p, &bOk);
  rc = sqlite3Fts3IntegrityCheck(p, &bOk);
  if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB;
  return rc;
}

/*
** Handle a 'special' INSERT of the form:
**
Changes to ext/fts5/extract_api_docs.tcl.
219
220
221
222
223
224
225

226
227
228

229

230
231
232
233
234
235
236
219
220
221
222
223
224
225
226
227
228

229
230
231
232
233
234
235
236
237
238







+


-
+

+







    fts5_extension {
      output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"]
    }

    Fts5ExtensionApi {
      set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
      set map [list]
      set lKey [list]
      foreach {k v} [get_struct_members $data] {
        if {[string match x* $k]==0} continue
        lappend map $k "<a href=#$k>$k</a>"
        lappend lKey $k
      }
      foreach k [lsort -decr $lKey] { lappend map $k "<a href=#$k>$k</a>" }
      output [string map $map $struct]
    }

    api {
      get_api_docs $data
    }

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







+
+
+
-
-
+
+









+
+
-
-
+
+















-
+
+

-
+

-
-
+
+







**   an OOM condition or IO error), an appropriate SQLite error code is 
**   returned.
**
**   This function may be quite inefficient if used with an FTS5 table
**   created with the "columnsize=0" option.
**
** xColumnText:
**   If parameter iCol is less than zero, or greater than or equal to the
**   number of columns in the table, SQLITE_RANGE is returned. 
**
**   This function attempts to retrieve the text of column iCol of the
**   current document. If successful, (*pz) is set to point to a buffer
**   Otherwise, this function attempts to retrieve the text of column iCol of
**   the current document. If successful, (*pz) is set to point to a buffer
**   containing the text in utf-8 encoding, (*pn) is set to the size in bytes
**   (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
**   if an error occurs, an SQLite error code is returned and the final values
**   of (*pz) and (*pn) are undefined.
**
** xPhraseCount:
**   Returns the number of phrases in the current query expression.
**
** xPhraseSize:
**   If parameter iCol is less than zero, or greater than or equal to the
**   number of phrases in the current query, as returned by xPhraseCount, 
**   Returns the number of tokens in phrase iPhrase of the query. Phrases
**   are numbered starting from zero.
**   0 is returned. Otherwise, this function returns the number of tokens in
**   phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
**   Set *pnInst to the total number of occurrences of all phrases within
**   the query within the current row. Return SQLITE_OK if successful, or
**   an error code (i.e. SQLITE_NOMEM) if an error occurs.
**
**   This API can be quite slow if used with an FTS5 table created with the
**   "detail=none" or "detail=column" option. If the FTS5 table is created 
**   with either "detail=none" or "detail=column" and "content=" option 
**   (i.e. if it is a contentless table), then this API always returns 0.
**
** xInst:
**   Query for the details of phrase match iIdx within the current row.
**   Phrase matches are numbered starting from zero, so the iIdx argument
**   should be greater than or equal to zero and smaller than the value
**   output by xInstCount().
**   output by xInstCount(). If iIdx is less than zero or greater than
**   or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
**   Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
**   to the column in which it occurs and *piOff the token offset of the
**   first token of the phrase. Returns SQLITE_OK if successful, or an error
**   code (i.e. SQLITE_NOMEM) if an error occurs.
**   first token of the phrase. SQLITE_OK is returned if successful, or an
**   error code (i.e. SQLITE_NOMEM) if an error occurs.
**
**   This API can be quite slow if used with an FTS5 table created with the
**   "detail=none" or "detail=column" option. 
**
** xRowid:
**   Returns the rowid of the current row.
**
142
143
144
145
146
147
148




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







+
+
+
+







**   current query is executed. Any column filter that applies to
**   phrase iPhrase of the current query is included in $p. For each 
**   row visited, the callback function passed as the fourth argument 
**   is invoked. The context and API objects passed to the callback 
**   function may be used to access the properties of each matched row.
**   Invoking Api.xUserData() returns a copy of the pointer passed as 
**   the third argument to pUserData.
**
**   If parameter iPhrase is less than zero, or greater than or equal to
**   the number of phrases in the query, as returned by xPhraseCount(),
**   this function returns SQLITE_RANGE.
**
**   If the callback function returns any value other than SQLITE_OK, the
**   query is abandoned and the xQueryPhrase function returns immediately.
**   If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
**   Otherwise, the error code is propagated upwards.
**
**   If the query runs to completion without incident, SQLITE_OK is returned.
257
258
259
260
261
262
263

































264
265
266

267
268
269
270
271
272
273
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







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


-
+







**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
**   (or xInst/xInstCount). The chief advantage of this API is that it is
**   significantly more efficient than those alternatives when used with
**   "detail=column" tables.  
**
** xPhraseNextColumn()
**   See xPhraseFirstColumn above.
**
** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
**   This is used to access token iToken of phrase iPhrase of the current
**   query. Before returning, output parameter *ppToken is set to point
**   to a buffer containing the requested token, and *pnToken to the
**   size of this buffer in bytes.
**
**   If iPhrase or iToken are less than zero, or if iPhrase is greater than
**   or equal to the number of phrases in the query as reported by 
**   xPhraseCount(), or if iToken is equal to or greater than the number of
**   tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
     are both zeroed.
**
**   The output text is not a copy of the query text that specified the
**   token. It is the output of the tokenizer module. For tokendata=1
**   tables, this includes any embedded 0x00 and trailing data.
**
** 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.
**
**   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 can be quite slow if used with an FTS5 table created with the
**   "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
  int iVersion;                   /* Currently always set to 2 */
  int iVersion;                   /* Currently always set to 3 */

  void *(*xUserData)(Fts5Context*);

  int (*xColumnCount)(Fts5Context*);
  int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
  int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);

294
295
296
297
298
299
300







301
302
303
304
305
306
307
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357







+
+
+
+
+
+
+







  void *(*xGetAuxdata)(Fts5Context*, int bClear);

  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
  void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);

  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);

  /* Below this point are iVersion>=3 only */
  int (*xQueryToken)(Fts5Context*, 
      int iPhrase, int iToken, 
      const char **ppToken, int *pnToken
  );
  int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};

/* 
** CUSTOM AUXILIARY FUNCTIONS
*************************************************************************/

/*************************************************************************
Changes to ext/fts5/fts5Int.h.
192
193
194
195
196
197
198

199
200
201
202
203
204
205
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206







+







  int nPrefix;                    /* Number of prefix indexes */
  int *aPrefix;                   /* Sizes in bytes of nPrefix prefix indexes */
  int eContent;                   /* An FTS5_CONTENT value */
  int bContentlessDelete;         /* "contentless_delete=" option (dflt==0) */
  char *zContent;                 /* content table */ 
  char *zContentRowid;            /* "content_rowid=" option value */ 
  int bColumnsize;                /* "columnsize=" option value (dflt==1) */
  int bTokendata;                 /* "tokendata=" option value (dflt==0) */
  int eDetail;                    /* FTS5_DETAIL_XXX value */
  char *zContentExprlist;
  Fts5Tokenizer *pTok;
  fts5_tokenizer *pTokApi;
  int bLock;                      /* True when table is preparing statement */
  int ePattern;                   /* FTS_PATTERN_XXX constant */

380
381
382
383
384
385
386
387
388
389
390




391
392
393
394
395
396
397





398
399
400
401
402
403
404
381
382
383
384
385
386
387




388
389
390
391
392
393
394
395



396
397
398
399
400
401
402
403
404
405
406
407







-
-
-
-
+
+
+
+




-
-
-
+
+
+
+
+







};

#define sqlite3Fts5IterEof(x) ((x)->bEof)

/*
** Values used as part of the flags argument passed to IndexQuery().
*/
#define FTS5INDEX_QUERY_PREFIX     0x0001   /* Prefix query */
#define FTS5INDEX_QUERY_DESC       0x0002   /* Docs in descending rowid order */
#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004   /* Do not use prefix index */
#define FTS5INDEX_QUERY_SCAN       0x0008   /* Scan query (fts5vocab) */
#define FTS5INDEX_QUERY_PREFIX      0x0001  /* Prefix query */
#define FTS5INDEX_QUERY_DESC        0x0002  /* Docs in descending rowid order */
#define FTS5INDEX_QUERY_TEST_NOIDX  0x0004  /* Do not use prefix index */
#define FTS5INDEX_QUERY_SCAN        0x0008  /* Scan query (fts5vocab) */

/* The following are used internally by the fts5_index.c module. They are
** defined here only to make it easier to avoid clashes with the flags
** above. */
#define FTS5INDEX_QUERY_SKIPEMPTY  0x0010
#define FTS5INDEX_QUERY_NOOUTPUT   0x0020
#define FTS5INDEX_QUERY_SKIPHASH   0x0040
#define FTS5INDEX_QUERY_SKIPEMPTY   0x0010
#define FTS5INDEX_QUERY_NOOUTPUT    0x0020
#define FTS5INDEX_QUERY_SKIPHASH    0x0040
#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080
#define FTS5INDEX_QUERY_SCANONETERM 0x0100

/*
** Create/destroy an Fts5Index object.
*/
int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**);
int sqlite3Fts5IndexClose(Fts5Index *p);

459
460
461
462
463
464
465




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







+
+
+
+







*/
const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*);
int sqlite3Fts5IterNextScan(Fts5IndexIter*);
void *sqlite3Fts5StructureRef(Fts5Index*);
void sqlite3Fts5StructureRelease(void*);
int sqlite3Fts5StructureTest(Fts5Index*, void*);

/*
** Used by xInstToken():
*/
int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);

/*
** 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.
535
536
537
538
539
540
541







542
543
544
545
546
547
548
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562







+
+
+
+
+
+
+







int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
int sqlite3Fts5IndexReset(Fts5Index *p);

int sqlite3Fts5IndexLoadConfig(Fts5Index *p);

int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);

void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*);

/* Used to populate hash tables for xInstToken in detail=none/column mode. */
int sqlite3Fts5IndexIterWriteTokendata(
    Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff
);

/*
** End of interface to code in fts5_index.c.
**************************************************************************/

/**************************************************************************
** Interface to code in fts5_varint.c. 
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







+







  Fts5Hash*,                      /* Hash table to query */
  const char *pTerm, int nTerm    /* Query prefix */
);
void sqlite3Fts5HashScanNext(Fts5Hash*);
int sqlite3Fts5HashScanEof(Fts5Hash*);
void sqlite3Fts5HashScanEntry(Fts5Hash *,
  const char **pzTerm,            /* OUT: term (nul-terminated) */
  int *pnTerm,                    /* OUT: Size of term in bytes */
  const u8 **ppDoclist,           /* OUT: pointer to doclist */
  int *pnDoclist                  /* OUT: size of doclist in bytes */
);



/*
766
767
768
769
770
771
772




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







+
+
+
+







    Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
);
void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);

int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);

int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);

int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*);
int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*);
void sqlite3Fts5ExprClearTokens(Fts5Expr*);

/*******************************************
** The fts5_expr.c API above this point is used by the other hand-written
** C code in this module. The interfaces below this point are called by
** the parser code in fts5parse.y.  */

void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...);
Changes to ext/fts5/fts5_aux.c.
207
208
209
210
211
212
213








214
215
216
217
218
219
220
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228







+
+
+
+
+
+
+
+








    if( rc==SQLITE_OK ){
      rc = fts5CInstIterNext(&p->iter);
    }
  }

  if( iPos==p->iRangeEnd ){
    if( p->bOpen ){
      if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
        fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
        p->iOff = iEndOff;
      }
      fts5HighlightAppend(&rc, p, p->zClose, -1);
      p->bOpen = 0;
    }
    fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
    p->iOff = iEndOff;
  }

  return rc;
}

240
241
242
243
244
245
246
247
248




249
250
251
252
253
254
255
248
249
250
251
252
253
254


255
256
257
258
259
260
261
262
263
264
265







-
-
+
+
+
+








  iCol = sqlite3_value_int(apVal[0]);
  memset(&ctx, 0, sizeof(HighlightContext));
  ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
  ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
  ctx.iRangeEnd = -1;
  rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);

  if( ctx.zIn ){
  if( rc==SQLITE_RANGE ){
    sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
    rc = SQLITE_OK;
  }else if( ctx.zIn ){
    if( rc==SQLITE_OK ){
      rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
    }

    if( rc==SQLITE_OK ){
      rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
    }
Changes to ext/fts5/fts5_buffer.c.
64
65
66
67
68
69
70

71
72
73
74
75
76
77
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78







+







  int *pRc,
  Fts5Buffer *pBuf, 
  u32 nData, 
  const u8 *pData
){
  if( nData ){
    if( fts5BufferGrow(pRc, pBuf, nData) ) return;
    assert( pBuf->p!=0 );
    memcpy(&pBuf->p[pBuf->n], pData, nData);
    pBuf->n += nData;
  }
}

/*
** Append the nul-terminated string zStr to the buffer pBuf. This function
165
166
167
168
169
170
171

172
173
174
175
176
177
178

179
180
181
182
183
184
185
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188







+







+








int sqlite3Fts5PoslistNext64(
  const u8 *a, int n,             /* Buffer containing poslist */
  int *pi,                        /* IN/OUT: Offset within a[] */
  i64 *piOff                      /* IN/OUT: Current offset */
){
  int i = *pi;
  assert( a!=0 || i==0 );
  if( i>=n ){
    /* EOF */
    *piOff = -1;
    return 1;  
  }else{
    i64 iOff = *piOff;
    u32 iVal;
    assert( a!=0 );
    fts5FastGetVarint32(a, i, iVal);
    if( iVal<=1 ){
      if( iVal==0 ){
        *pi = i;
        return 0;
      }
      fts5FastGetVarint32(a, i, iVal);
Changes to ext/fts5/fts5_config.c.
393
394
395
396
397
398
399










400
401
402
403
404
405
406
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416







+
+
+
+
+
+
+
+
+
+







    };

    if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){
      *pzErr = sqlite3_mprintf("malformed detail=... directive");
    }
    return rc;
  }

  if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){
    if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
      *pzErr = sqlite3_mprintf("malformed tokendata=... directive");
      rc = SQLITE_ERROR;
    }else{
      pConfig->bTokendata = (zArg[0]=='1');
    }
    return rc;
  }

  *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
  return SQLITE_ERROR;
}

/*
** Allocate an instance of the default tokenizer ("simple") at 
Changes to ext/fts5/fts5_expr.c.
96
97
98
99
100
101
102
103



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

103
104
105
106
107
108
109
110
111
112







-
+
+
+







/*
** An instance of the following structure represents a single search term
** or term prefix.
*/
struct Fts5ExprTerm {
  u8 bPrefix;                     /* True for a prefix term */
  u8 bFirst;                      /* True if token must be first in column */
  char *zTerm;                    /* nul-terminated term */
  char *pTerm;                    /* Term data */
  int nQueryTerm;                 /* Effective size of term in bytes */
  int nFullTerm;                  /* Size of term in bytes incl. tokendata */
  Fts5IndexIter *pIter;           /* Iterator for this term */
  Fts5ExprTerm *pSynonym;         /* Pointer to first in list of synonyms */
};

/*
** A phrase. One or more terms that must appear in a contiguous sequence
** within a document for it to match.
963
964
965
966
967
968
969
970

971
972
973
974
975
976
977
965
966
967
968
969
970
971

972
973
974
975
976
977
978
979







-
+







        for(p=pTerm; p; p=p->pSynonym){
          int rc;
          if( p->pIter ){
            sqlite3Fts5IterClose(p->pIter);
            p->pIter = 0;
          }
          rc = sqlite3Fts5IndexQuery(
              pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
              pExpr->pIndex, p->pTerm, p->nQueryTerm,
              (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
              (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
              pNear->pColset,
              &p->pIter
          );
          assert( (rc==SQLITE_OK)==(p->pIter!=0) );
          if( rc!=SQLITE_OK ) return rc;
1600
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1602
1603
1604
1605
1606
1607
1608

1609
1610
1611
1612
1613
1614
1615
1616







-
+







static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
  if( pPhrase ){
    int i;
    for(i=0; i<pPhrase->nTerm; i++){
      Fts5ExprTerm *pSyn;
      Fts5ExprTerm *pNext;
      Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
      sqlite3_free(pTerm->zTerm);
      sqlite3_free(pTerm->pTerm);
      sqlite3Fts5IterClose(pTerm->pIter);
      for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
        pNext = pSyn->pSynonym;
        sqlite3Fts5IterClose(pSyn->pIter);
        fts5BufferFree((Fts5Buffer*)&pSyn[1]);
        sqlite3_free(pSyn);
      }
1698
1699
1700
1701
1702
1703
1704

1705
1706
1707
1708
1709
1710
1711
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714







+







  }
  return pRet;
}

typedef struct TokenCtx TokenCtx;
struct TokenCtx {
  Fts5ExprPhrase *pPhrase;
  Fts5Config *pConfig;
  int rc;
};

/*
** Callback for tokenizing terms used by ParseTerm().
*/
static int fts5ParseTokenize(
1731
1732
1733
1734
1735
1736
1737
1738
1739






1740
1741
1742
1743
1744
1745
1746
1734
1735
1736
1737
1738
1739
1740


1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753







-
-
+
+
+
+
+
+







    Fts5ExprTerm *pSyn;
    sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
    pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte);
    if( pSyn==0 ){
      rc = SQLITE_NOMEM;
    }else{
      memset(pSyn, 0, (size_t)nByte);
      pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
      memcpy(pSyn->zTerm, pToken, nToken);
      pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
      pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
      if( pCtx->pConfig->bTokendata ){
        pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
      }
      memcpy(pSyn->pTerm, pToken, nToken);
      pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
      pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
    }
  }else{
    Fts5ExprTerm *pTerm;
    if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){
      Fts5ExprPhrase *pNew;
1757
1758
1759
1760
1761
1762
1763
1764





1765
1766
1767
1768
1769
1770
1771
1764
1765
1766
1767
1768
1769
1770

1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782







-
+
+
+
+
+







        pNew->nTerm = nNew - SZALLOC;
      }
    }

    if( rc==SQLITE_OK ){
      pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
      memset(pTerm, 0, sizeof(Fts5ExprTerm));
      pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
      pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
      pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
      if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){ 
        pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
      }
    }
  }

  pCtx->rc = rc;
  return rc;
}

1824
1825
1826
1827
1828
1829
1830

1831
1832
1833
1834
1835
1836
1837
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849







+







  Fts5Config *pConfig = pParse->pConfig;
  TokenCtx sCtx;                  /* Context object passed to callback */
  int rc;                         /* Tokenize return code */
  char *z = 0;

  memset(&sCtx, 0, sizeof(TokenCtx));
  sCtx.pPhrase = pAppend;
  sCtx.pConfig = pConfig;

  rc = fts5ParseStringFromToken(pToken, &z);
  if( rc==SQLITE_OK ){
    int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0);
    int n;
    sqlite3Fts5Dequote(z);
    n = (int)strlen(z);
1871
1872
1873
1874
1875
1876
1877
1878

1879
1880
1881
1882
1883







1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896

1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909

1910
1911
1912
1913
1914
1915







1916
1917

1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929












1930
1931
1932
1933
1934
1935
1936
1883
1884
1885
1886
1887
1888
1889

1890
1891




1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910

1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925






1926
1927
1928
1929
1930
1931
1932


1933












1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952







-
+

-
-
-
-
+
+
+
+
+
+
+












-
+













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







*/
int sqlite3Fts5ExprClonePhrase(
  Fts5Expr *pExpr, 
  int iPhrase, 
  Fts5Expr **ppNew
){
  int rc = SQLITE_OK;             /* Return code */
  Fts5ExprPhrase *pOrig;          /* The phrase extracted from pExpr */
  Fts5ExprPhrase *pOrig = 0;      /* The phrase extracted from pExpr */
  Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
  TokenCtx sCtx = {0,0};          /* Context object for fts5ParseTokenize */

  pOrig = pExpr->apExprPhrase[iPhrase];
  pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
  TokenCtx sCtx = {0,0,0};        /* Context object for fts5ParseTokenize */
  if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
    rc = SQLITE_RANGE;
  }else{
    pOrig = pExpr->apExprPhrase[iPhrase];
    pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
  }
  if( rc==SQLITE_OK ){
    pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 
        sizeof(Fts5ExprPhrase*));
  }
  if( rc==SQLITE_OK ){
    pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, 
        sizeof(Fts5ExprNode));
  }
  if( rc==SQLITE_OK ){
    pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, 
        sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
  }
  if( rc==SQLITE_OK ){
  if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
    Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
    if( pColsetOrig ){
      sqlite3_int64 nByte;
      Fts5Colset *pColset;
      nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
      pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
      if( pColset ){ 
        memcpy(pColset, pColsetOrig, (size_t)nByte);
      }
      pNew->pRoot->pNear->pColset = pColset;
    }
  }

  if( rc==SQLITE_OK ){
  if( pOrig->nTerm ){
    int i;                          /* Used to iterate through phrase terms */
    for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
      int tflags = 0;
      Fts5ExprTerm *p;
      for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
    if( pOrig->nTerm ){
      int i;                          /* Used to iterate through phrase terms */
      sCtx.pConfig = pExpr->pConfig;
      for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
        int tflags = 0;
        Fts5ExprTerm *p;
        for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
        const char *zTerm = p->zTerm;
        rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
          rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
            0, 0);
        tflags = FTS5_TOKEN_COLOCATED;
      }
      if( rc==SQLITE_OK ){
        sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
        sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
      }
    }
  }else{
    /* This happens when parsing a token or quoted phrase that contains
    ** no token characters at all. (e.g ... MATCH '""'). */
    sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
          tflags = FTS5_TOKEN_COLOCATED;
        }
        if( rc==SQLITE_OK ){
          sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
          sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
        }
      }
    }else{
      /* This happens when parsing a token or quoted phrase that contains
      ** no token characters at all. (e.g ... MATCH '""'). */
      sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
    }
  }

  if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
    /* All the allocations succeeded. Put the expression object together. */
    pNew->pIndex = pExpr->pIndex;
    pNew->pConfig = pExpr->pConfig;
    pNew->nPhrase = 1;
2292
2293
2294
2295
2296
2297
2298


2299
2300
2301

2302
2303


2304
2305
2306
2307
2308
2309
2310
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318

2319


2320
2321
2322
2323
2324
2325
2326
2327
2328







+
+


-
+
-
-
+
+







      Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
          &pParse->rc, sizeof(Fts5ExprPhrase)
      );
      if( pPhrase ){
        if( parseGrowPhraseArray(pParse) ){
          fts5ExprPhraseFree(pPhrase);
        }else{
          Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
          Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
          pParse->apPhrase[pParse->nPhrase++] = pPhrase;
          pPhrase->nTerm = 1;
          pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
          pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm);
              &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
          );
          pTo->nQueryTerm = p->nQueryTerm;
          pTo->nFullTerm = p->nFullTerm;
          pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 
              0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
          );
        }
      }
    }
  
2481
2482
2483
2484
2485
2486
2487
2488

2489
2490
2491
2492
2493
2494
2495


2496
2497

2498
2499
2500
2501
2502
2503
2504
2499
2500
2501
2502
2503
2504
2505

2506
2507
2508
2509
2510
2511
2512

2513
2514
2515

2516
2517
2518
2519
2520
2521
2522
2523







-
+






-
+
+

-
+







static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
  sqlite3_int64 nByte = 0;
  Fts5ExprTerm *p;
  char *zQuoted;

  /* Determine the maximum amount of space required. */
  for(p=pTerm; p; p=p->pSynonym){
    nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
    nByte += pTerm->nQueryTerm * 2 + 3 + 2;
  }
  zQuoted = sqlite3_malloc64(nByte);

  if( zQuoted ){
    int i = 0;
    for(p=pTerm; p; p=p->pSynonym){
      char *zIn = p->zTerm;
      char *zIn = p->pTerm;
      char *zEnd = &zIn[p->nQueryTerm];
      zQuoted[i++] = '"';
      while( *zIn ){
      while( zIn<zEnd ){
        if( *zIn=='"' ) zQuoted[i++] = '"';
        zQuoted[i++] = *zIn++;
      }
      zQuoted[i++] = '"';
      if( p->pSynonym ) zQuoted[i++] = '|';
    }
    if( pTerm->bPrefix ){
2568
2569
2570
2571
2572
2573
2574
2575
2576




2577
2578
2579
2580
2581
2582
2583
2587
2588
2589
2590
2591
2592
2593


2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604







-
-
+
+
+
+







    if( zRet==0 ) return 0;

    for(i=0; i<pNear->nPhrase; i++){
      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];

      zRet = fts5PrintfAppend(zRet, " {");
      for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
        char *zTerm = pPhrase->aTerm[iTerm].zTerm;
        zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
        Fts5ExprTerm *p = &pPhrase->aTerm[iTerm];
        zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ", 
            p->nQueryTerm, p->pTerm
        );
        if( pPhrase->aTerm[iTerm].bPrefix ){
          zRet = fts5PrintfAppend(zRet, "*");
        }
      }

      if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
      if( zRet==0 ) return 0;
2969
2970
2971
2972
2973
2974
2975











2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987


2988
2989
2990
2991




2992
2993
2994

2995
2996

2997
2998
2999


3000
3001
3002
3003







3004
3005
3006
3007
3008
3009
3010
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024

3025
3026
3027
3028
3029
3030

3031
3032

3033



3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053







+
+
+
+
+
+
+
+
+
+
+












+
+



-
+
+
+
+


-
+

-
+
-
-
-
+
+




+
+
+
+
+
+
+







static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
  int i;
  for(i=0; i<pColset->nCol; i++){
    if( pColset->aiCol[i]==iCol ) return 1;
  }
  return 0;
}

/*
** pToken is a buffer nToken bytes in size that may or may not contain
** an embedded 0x00 byte. If it does, return the number of bytes in
** the buffer before the 0x00. If it does not, return nToken.
*/
static int fts5QueryTerm(const char *pToken, int nToken){
  int ii;
  for(ii=0; ii<nToken && pToken[ii]; ii++){}
  return ii;
}

static int fts5ExprPopulatePoslistsCb(
  void *pCtx,                /* Copy of 2nd argument to xTokenize() */
  int tflags,                /* Mask of FTS5_TOKEN_* flags */
  const char *pToken,        /* Pointer to buffer containing token */
  int nToken,                /* Size of token in bytes */
  int iUnused1,              /* Byte offset of token within input text */
  int iUnused2               /* Byte offset of end of token within input text */
){
  Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
  Fts5Expr *pExpr = p->pExpr;
  int i;
  int nQuery = nToken;
  i64 iRowid = pExpr->pRoot->iRowid;

  UNUSED_PARAM2(iUnused1, iUnused2);

  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
  if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE;
  if( pExpr->pConfig->bTokendata ){
    nQuery = fts5QueryTerm(pToken, nQuery);
  }
  if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
  for(i=0; i<pExpr->nPhrase; i++){
    Fts5ExprTerm *pTerm;
    Fts5ExprTerm *pT;
    if( p->aPopulator[i].bOk==0 ) continue;
    for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
    for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
      int nTerm = (int)strlen(pTerm->zTerm);
      if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
       && memcmp(pTerm->zTerm, pToken, nTerm)==0
      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 ){
          int iCol = p->iOff>>32;
          int iTokOff = p->iOff & 0x7FFFFFFF;
          rc = sqlite3Fts5IndexIterWriteTokendata(
              pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
          );
        }
        if( rc ) return rc;
        break;
      }
    }
  }
  return SQLITE_OK;
}
3131
3132
3133
3134
3135
3136
3137













































































3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
  }else{
    *ppCollist = 0;
    *pnCollist = 0;
  }

  return rc;
}

/*
** Does the work of the fts5_api.xQueryToken() API method.
*/
int sqlite3Fts5ExprQueryToken(
  Fts5Expr *pExpr, 
  int iPhrase, 
  int iToken, 
  const char **ppOut, 
  int *pnOut
){
  Fts5ExprPhrase *pPhrase = 0;

  if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
    return SQLITE_RANGE;
  }
  pPhrase = pExpr->apExprPhrase[iPhrase];
  if( iToken<0 || iToken>=pPhrase->nTerm ){
    return SQLITE_RANGE;
  }

  *ppOut = pPhrase->aTerm[iToken].pTerm;
  *pnOut = pPhrase->aTerm[iToken].nFullTerm;
  return SQLITE_OK;
}

/*
** Does the work of the fts5_api.xInstToken() API method.
*/
int sqlite3Fts5ExprInstToken(
  Fts5Expr *pExpr, 
  i64 iRowid,
  int iPhrase, 
  int iCol, 
  int iOff, 
  int iToken, 
  const char **ppOut, 
  int *pnOut
){
  Fts5ExprPhrase *pPhrase = 0;
  Fts5ExprTerm *pTerm = 0;
  int rc = SQLITE_OK;

  if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
    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;
    }
  }
  return rc;
}

/*
** Clear the token mappings for all Fts5IndexIter objects mannaged by 
** the expression passed as the only argument.
*/
void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
  int ii;
  for(ii=0; ii<pExpr->nPhrase; ii++){
    Fts5ExprTerm *pT;
    for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
      sqlite3Fts5IndexIterClearTokendata(pT->pIter);
    }
  }
}
Changes to ext/fts5/fts5_hash.c.
32
33
34
35
36
37
38
39
40
41
42









43
44
45
46
47
48
49
32
33
34
35
36
37
38




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54







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







  int nSlot;                      /* Size of aSlot[] array */
  Fts5HashEntry *pScan;           /* Current ordered scan item */
  Fts5HashEntry **aSlot;          /* Array of hash slots */
};

/*
** Each entry in the hash table is represented by an object of the 
** following type. Each object, its key (a nul-terminated string) and 
** its current data are stored in a single memory allocation. The 
** key immediately follows the object in memory. The position list
** data immediately follows the key data in memory.
** following type. Each object, its key, and its current data are stored 
** in a single memory allocation. The key immediately follows the object 
** in memory. The position list data immediately follows the key data 
** in memory.
**
** The key is Fts5HashEntry.nKey bytes in size. It consists of a single
** byte identifying the index (either the main term index or a prefix-index),
** followed by the term data. For example: "0token". There is no 
** nul-terminator - in this case nKey=6.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
**
**   * Rowid, as a varint
**   * Position list, without 0x00 terminator.
**   * Size of previous position list and rowid, as a 4 byte
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185
175
176
177
178
179
180
181

182

183
184
185
186
187
188
189







-
+
-







  memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));

  for(i=0; i<pHash->nSlot; i++){
    while( apOld[i] ){
      unsigned int iHash;
      Fts5HashEntry *p = apOld[i];
      apOld[i] = p->pHashNext;
      iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
      iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey);
                          (int)strlen(fts5EntryKey(p)));
      p->pHashNext = apNew[iHash];
      apNew[iHash] = p;
    }
  }

  sqlite3_free(apOld);
  pHash->nSlot = nNew;
255
256
257
258
259
260
261
262

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

266
267
268
269
270
271
272
273







-
+







  bNew = (pHash->eDetail==FTS5_DETAIL_FULL);

  /* Attempt to locate an existing hash entry */
  iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
  for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
    char *zKey = fts5EntryKey(p);
    if( zKey[0]==bByte 
     && p->nKey==nToken
     && p->nKey==nToken+1
     && memcmp(&zKey[1], pToken, nToken)==0 
    ){
      break;
    }
  }

  /* If an existing hash entry cannot be found, create a new one. */
285
286
287
288
289
290
291
292

293
294

295
296
297
298
299
300
301
289
290
291
292
293
294
295

296
297

298
299
300
301
302
303
304
305







-
+

-
+







    if( !p ) return SQLITE_NOMEM;
    memset(p, 0, sizeof(Fts5HashEntry));
    p->nAlloc = (int)nByte;
    zKey = fts5EntryKey(p);
    zKey[0] = bByte;
    memcpy(&zKey[1], pToken, nToken);
    assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
    p->nKey = nToken;
    p->nKey = nToken+1;
    zKey[nToken+1] = '\0';
    p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
    p->nData = nToken+1 + sizeof(Fts5HashEntry);
    p->pHashNext = pHash->aSlot[iHash];
    pHash->aSlot[iHash] = p;
    pHash->nEntry++;

    /* Add the first rowid field to the hash-entry */
    p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
    p->iRowid = iRowid;
404
405
406
407
408
409
410
411
412
413

414
415
416








417
418
419
420
421
422
423
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







-


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







    if( p1==0 ){
      *ppOut = p2;
      p2 = 0;
    }else if( p2==0 ){
      *ppOut = p1;
      p1 = 0;
    }else{
      int i = 0;
      char *zKey1 = fts5EntryKey(p1);
      char *zKey2 = fts5EntryKey(p2);
      int nMin = MIN(p1->nKey, p2->nKey);
      while( zKey1[i]==zKey2[i] ) i++;

      if( ((u8)zKey1[i])>((u8)zKey2[i]) ){

      int cmp = memcmp(zKey1, zKey2, nMin);
      if( cmp==0 ){
        cmp = p1->nKey - p2->nKey;
      }
      assert( cmp!=0 );

      if( cmp>0 ){
        /* p2 is smaller */
        *ppOut = p2;
        ppOut = &p2->pScanNext;
        p2 = p2->pScanNext;
      }else{
        /* p1 is smaller */
        *ppOut = p1;
451
452
453
454
455
456
457
458

459
460
461
462
463
464
465
460
461
462
463
464
465
466

467
468
469
470
471
472
473
474







-
+







  if( !ap ) return SQLITE_NOMEM;
  memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);

  for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
    Fts5HashEntry *pIter;
    for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
      if( pTerm==0 
       || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
       || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
      ){
        Fts5HashEntry *pEntry = pIter;
        pEntry->pScanNext = 0;
        for(i=0; ap[i]; i++){
          pEntry = fts5HashEntryMerge(pEntry, ap[i]);
          ap[i] = 0;
        }
490
491
492
493
494
495
496
497
498

499
500
501
502

503
504
505
506
507
508
509
499
500
501
502
503
504
505


506
507
508
509

510
511
512
513
514
515
516
517







-
-
+



-
+







){
  unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
  char *zKey = 0;
  Fts5HashEntry *p;

  for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
    zKey = fts5EntryKey(p);
    assert( p->nKey+1==(int)strlen(zKey) );
    if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
    if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break;
  }

  if( p ){
    int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
    int nHashPre = sizeof(Fts5HashEntry) + nTerm;
    int nList = p->nData - nHashPre;
    u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10));
    if( pRet ){
      Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre];
      memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList);
      nList += fts5HashAddPoslistSize(pHash, p, pFaux);
      *pnDoclist = nList;
556
557
558
559
560
561
562

563
564
565
566
567
568
569

570
571

572
573


574
575

576
577
578
579
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







+






-
+


+
-
-
+
+


+




int sqlite3Fts5HashScanEof(Fts5Hash *p){
  return (p->pScan==0);
}

void sqlite3Fts5HashScanEntry(
  Fts5Hash *pHash,
  const char **pzTerm,            /* OUT: term (nul-terminated) */
  int *pnTerm,                    /* OUT: Size of term in bytes */
  const u8 **ppDoclist,           /* OUT: pointer to doclist */
  int *pnDoclist                  /* OUT: size of doclist in bytes */
){
  Fts5HashEntry *p;
  if( (p = pHash->pScan) ){
    char *zKey = fts5EntryKey(p);
    int nTerm = (int)strlen(zKey);
    int nTerm = p->nKey;
    fts5HashAddPoslistSize(pHash, p, 0);
    *pzTerm = zKey;
    *pnTerm = nTerm;
    *ppDoclist = (const u8*)&zKey[nTerm+1];
    *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
    *ppDoclist = (const u8*)&zKey[nTerm];
    *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm);
  }else{
    *pzTerm = 0;
    *pnTerm = 0;
    *ppDoclist = 0;
    *pnDoclist = 0;
  }
}
Changes to ext/fts5/fts5_index.c.
319
320
321
322
323
324
325



326
327
328
329
330
331
332
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335







+
+
+







typedef struct Fts5PageWriter Fts5PageWriter;
typedef struct Fts5SegIter Fts5SegIter;
typedef struct Fts5DoclistIter Fts5DoclistIter;
typedef struct Fts5SegWriter Fts5SegWriter;
typedef struct Fts5Structure Fts5Structure;
typedef struct Fts5StructureLevel Fts5StructureLevel;
typedef struct Fts5StructureSegment Fts5StructureSegment;
typedef struct Fts5TokenDataIter Fts5TokenDataIter;
typedef struct Fts5TokenDataMap Fts5TokenDataMap;
typedef struct Fts5TombstoneArray Fts5TombstoneArray;

struct Fts5Data {
  u8 *p;                          /* Pointer to buffer containing record */
  int nn;                         /* Size of record in bytes */
  int szLeaf;                     /* Size of leaf without page-index */
};

353
354
355
356
357
358
359

360
361
362
363
364
365
366
367

368
369
370
371
372
373
374
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379







+








+







  i64 iWriteRowid;                /* Rowid for current doc being written */
  int bDelete;                    /* Current write is a delete */
  int nContentlessDelete;         /* Number of contentless delete ops */
  int nPendingRow;                /* Number of INSERT in hash table */

  /* Error state. */
  int rc;                         /* Current error code */
  int flushRc;

  /* State used by the fts5DataXXX() functions. */
  sqlite3_blob *pReader;          /* RO incr-blob open on %_data table */
  sqlite3_stmt *pWriter;          /* "INSERT ... %_data VALUES(?,?)" */
  sqlite3_stmt *pDeleter;         /* "DELETE FROM %_data ... id>=? AND id<=?" */
  sqlite3_stmt *pIdxWriter;       /* "INSERT ... %_idx VALUES(?,?,?,?)" */
  sqlite3_stmt *pIdxDeleter;      /* "DELETE FROM %_idx WHERE segid=?" */
  sqlite3_stmt *pIdxSelect;
  sqlite3_stmt *pIdxNextSelect;
  int nRead;                      /* Total number of blocks read */

  sqlite3_stmt *pDeleteFromIdx;

  sqlite3_stmt *pDataVersion;
  i64 iStructVersion;             /* data_version when pStruct read */
  Fts5Structure *pStruct;         /* Current db structure (or NULL) */
514
515
516
517
518
519
520
521

522
523
524
525
526
527
528
529
519
520
521
522
523
524
525

526

527
528
529
530
531
532
533







-
+
-







struct Fts5SegIter {
  Fts5StructureSegment *pSeg;     /* Segment to iterate through */
  int flags;                      /* Mask of configuration flags */
  int iLeafPgno;                  /* Current leaf page number */
  Fts5Data *pLeaf;                /* Current leaf data */
  Fts5Data *pNextLeaf;            /* Leaf page (iLeafPgno+1) */
  i64 iLeafOffset;                /* Byte offset within current leaf */
  Fts5Data **apTombstone;         /* Array of tombstone pages */
  Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */
  int nTombstone;

  /* Next method */
  void (*xNext)(Fts5Index*, Fts5SegIter*, int*);

  /* The page and offset from which the current term was read. The offset 
  ** is the offset of the first rowid in the current doclist.  */
  int iTermLeafPgno;
541
542
543
544
545
546
547









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







+
+
+
+
+
+
+
+
+








  /* Variables populated based on current entry. */
  Fts5Buffer term;                /* Current term */
  i64 iRowid;                     /* Current rowid */
  int nPos;                       /* Number of bytes in current position list */
  u8 bDel;                        /* True if the delete flag is set */
};

/*
** Array of tombstone pages. Reference counted.
*/
struct Fts5TombstoneArray {
  int nRef;                       /* Number of pointers to this object */
  int nTombstone;
  Fts5Data *apTombstone[1];       /* Array of tombstone pages */
};

/*
** Argument is a pointer to an Fts5Data structure that contains a 
** leaf page.
*/
#define ASSERT_SZLEAF_OK(x) assert( \
    (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
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
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







+
+
+
+
+
+



+
















-







**
** aFirst[1] contains the index in aSeg[] of the iterator that points to
** the smallest key overall. aFirst[0] is unused. 
**
** poslist:
**   Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
**   There is no way to tell if this is populated or not.
**
** pColset:
**   If not NULL, points to an object containing a set of column indices.
**   Only matches that occur in one of these columns will be returned.
**   The Fts5Iter does not own the Fts5Colset object, and so it is not
**   freed when the iterator is closed - it is owned by the upper layer.
*/
struct Fts5Iter {
  Fts5IndexIter base;             /* Base class containing output vars */
  Fts5TokenDataIter *pTokenDataIter;

  Fts5Index *pIndex;              /* Index that owns this iterator */
  Fts5Buffer poslist;             /* Buffer containing current poslist */
  Fts5Colset *pColset;            /* Restrict matches to these columns */

  /* Invoked to set output variables. */
  void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*);

  int nSeg;                       /* Size of aSeg[] array */
  int bRev;                       /* True to iterate in reverse order */
  u8 bSkipEmpty;                  /* True to skip deleted entries */

  i64 iSwitchRowid;               /* Firstest rowid of other than aFirst[1] */
  Fts5CResult *aFirst;            /* Current merge state (see above) */
  Fts5SegIter aSeg[1];            /* Array of segment iterators */
};


/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
**
** pData:
**   Record containing the doclist-index data.
1524
1525
1526
1527
1528
1529
1530
1531

1532
1533

1534
1535
1536
1537
1538
1539
1540
1543
1544
1545
1546
1547
1548
1549

1550
1551

1552
1553
1554
1555
1556
1557
1558
1559







-
+

-
+







  }else{
    int iOff;
    for(iOff=pLvl->iOff; iOff<pData->nn; iOff++){
      if( pData->p[iOff] ) break; 
    }

    if( iOff<pData->nn ){
      i64 iVal;
      u64 iVal;
      pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
      iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
      iOff += fts5GetVarint(&pData->p[iOff], &iVal);
      pLvl->iRowid += iVal;
      pLvl->iOff = iOff;
    }else{
      pLvl->bEof = 1;
    }
  }

1905
1906
1907
1908
1909
1910
1911
1912
1913
1914



1915
1916
1917
1918
1919
1920
1921




1922
1923



1924
1925
1926
1927
1928
1929
1930
1924
1925
1926
1927
1928
1929
1930



1931
1932
1933
1934
1935
1936
1937



1938
1939
1940
1941


1942
1943
1944
1945
1946
1947
1948
1949
1950
1951







-
-
-
+
+
+




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







    pIter->xNext = fts5SegIterNext_None;
  }else{
    pIter->xNext = fts5SegIterNext;
  }
}

/*
** Allocate a tombstone hash page array (pIter->apTombstone) for the 
** iterator passed as the second argument. If an OOM error occurs, leave
** an error in the Fts5Index object.
** Allocate a tombstone hash page array object (pIter->pTombArray) for 
** the iterator passed as the second argument. If an OOM error occurs, 
** leave an error in the Fts5Index object.
*/
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
  const int nTomb = pIter->pSeg->nPgTombstone;
  if( nTomb>0 ){
    Fts5Data **apTomb = 0;
    apTomb = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data)*nTomb);
    if( apTomb ){
    int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
    Fts5TombstoneArray *pNew;
    pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
    if( pNew ){
      pIter->apTombstone = apTomb;
      pIter->nTombstone = nTomb;
      pNew->nTombstone = nTomb;
      pNew->nRef = 1;
      pIter->pTombArray = pNew;
    }
  }
}

/*
** Initialize the iterator object pIter to iterate through the entries in
** segment pSeg. The iterator is left pointing to the first entry when 
2173
2174
2175
2176
2177
2178
2179

2180
2181
2182

2183
2184
2185
2186
2187
2188

2189
2190
2191
2192
2193
2194
2195
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203

2204
2205
2206
2207
2208
2209

2210
2211
2212
2213
2214
2215
2216
2217







+


-
+





-
+







        iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep);
      }
      pIter->iLeafOffset = iOff;
      fts5SegIterLoadTerm(p, pIter, nKeep);
    }else{
      const u8 *pList = 0;
      const char *zTerm = 0;
      int nTerm = 0;
      int nList;
      sqlite3Fts5HashScanNext(p->pHash);
      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
      if( pList==0 ) goto next_none_eof;
      pIter->pLeaf->p = (u8*)pList;
      pIter->pLeaf->nn = nList;
      pIter->pLeaf->szLeaf = nList;
      pIter->iEndofDoclist = nList;
      sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
      sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm);
      pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    }

    if( pbNewTerm ) *pbNewTerm = 1;
  }else{
    goto next_none_eof;
  }
2247
2248
2249
2250
2251
2252
2253

2254
2255
2256
2257
2258

2259
2260
2261
2262
2263
2264
2265
2266
2267
2268

2269
2270
2271
2272
2273
2274
2275
2276
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280

2281
2282
2283
2284
2285
2286
2287
2288
2289
2290

2291

2292
2293
2294
2295
2296
2297
2298







+




-
+









-
+
-







      assert_nc( iDelta>0 );
    }
    pIter->iLeafOffset = iOff;

  }else if( pIter->pSeg==0 ){
    const u8 *pList = 0;
    const char *zTerm = 0;
    int nTerm = 0;
    int nList = 0;
    assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
    if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
      sqlite3Fts5HashScanNext(p->pHash);
      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
    }
    if( pList==0 ){
      fts5DataRelease(pIter->pLeaf);
      pIter->pLeaf = 0;
    }else{
      pIter->pLeaf->p = (u8*)pList;
      pIter->pLeaf->nn = nList;
      pIter->pLeaf->szLeaf = nList;
      pIter->iEndofDoclist = nList+1;
      sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
      sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm);
          (u8*)zTerm);
      pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
      *pbNewTerm = 1;
    }
  }else{
    iOff = 0;
    /* Next entry is not on the current page */
    while( iOff==0 ){
2648
2649
2650
2651
2652
2653
2654
2655

2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670

2671


2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687









































































2688
2689
2690
2691
2692
2693
2694
2670
2671
2672
2673
2674
2675
2676

2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693

2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791







-
+















+
-
+
+
















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







  pIter->iLeafPgno = iPg - 1;
  fts5SegIterNextPage(p, pIter);

  if( pIter->pLeaf ){
    fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
  }

  if( p->rc==SQLITE_OK && bGe==0 ){
  if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){
    pIter->flags |= FTS5_SEGITER_ONETERM;
    if( pIter->pLeaf ){
      if( flags & FTS5INDEX_QUERY_DESC ){
        pIter->flags |= FTS5_SEGITER_REVERSE;
      }
      if( bDlidx ){
        fts5SegIterLoadDlidx(p, pIter);
      }
      if( flags & FTS5INDEX_QUERY_DESC ){
        fts5SegIterReverse(p, pIter);
      }
    }
  }

  fts5SegIterSetNext(p, pIter);
  if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){
  fts5SegIterAllocTombstone(p, pIter);
    fts5SegIterAllocTombstone(p, pIter);
  }

  /* Either:
  **
  **   1) an error has occurred, or
  **   2) the iterator points to EOF, or
  **   3) the iterator points to an entry with term (pTerm/nTerm), or
  **   4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
  **      to an entry with a term greater than or equal to (pTerm/nTerm).
  */
  assert_nc( p->rc!=SQLITE_OK                                       /* 1 */
   || pIter->pLeaf==0                                               /* 2 */
   || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0          /* 3 */
   || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0)  /* 4 */
  );
}


/*
** SQL used by fts5SegIterNextInit() to find the page to open.
*/
static sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){
  if( p->pIdxNextSelect==0 ){
    Fts5Config *pConfig = p->pConfig;
    fts5IndexPrepareStmt(p, &p->pIdxNextSelect, sqlite3_mprintf(
          "SELECT pgno FROM '%q'.'%q_idx' WHERE "
          "segid=? AND term>? ORDER BY term ASC LIMIT 1",
          pConfig->zDb, pConfig->zName
    ));
    
  }
  return p->pIdxNextSelect;
}

/*
** This is similar to fts5SegIterSeekInit(), except that it initializes
** the segment iterator to point to the first term following the page
** with pToken/nToken on it.
*/
static void fts5SegIterNextInit(
  Fts5Index *p, 
  const char *pTerm, int nTerm,
  Fts5StructureSegment *pSeg,     /* Description of segment */
  Fts5SegIter *pIter              /* Object to populate */
){
  int iPg = -1;                   /* Page of segment to open */
  int bDlidx = 0;
  sqlite3_stmt *pSel = 0;         /* SELECT to find iPg */

  pSel = fts5IdxNextStmt(p);
  if( pSel ){
    assert( p->rc==SQLITE_OK );
    sqlite3_bind_int(pSel, 1, pSeg->iSegid);
    sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC);

    if( sqlite3_step(pSel)==SQLITE_ROW ){
      i64 val = sqlite3_column_int64(pSel, 0);
      iPg = (int)(val>>1);
      bDlidx = (val & 0x0001);
    }
    p->rc = sqlite3_reset(pSel);
    sqlite3_bind_null(pSel, 2);
    if( p->rc ) return;
  }

  memset(pIter, 0, sizeof(*pIter));
  pIter->pSeg = pSeg;
  pIter->flags |= FTS5_SEGITER_ONETERM;
  if( iPg>=0 ){
    pIter->iLeafPgno = iPg - 1;
    fts5SegIterNextPage(p, pIter);
    fts5SegIterSetNext(p, pIter);
  }
  if( pIter->pLeaf ){
    const u8 *a = pIter->pLeaf->p;
    int iTermOff = 0;

    pIter->iPgidxOff = pIter->pLeaf->szLeaf;
    pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff);
    pIter->iLeafOffset = iTermOff;
    fts5SegIterLoadTerm(p, pIter, 0);
    fts5SegIterLoadNPos(p, pIter);
    if( bDlidx ) fts5SegIterLoadDlidx(p, pIter);

    assert( p->rc!=SQLITE_OK || 
        fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0
    );
  }
}

/*
** Initialize the object pIter to point to term pTerm/nTerm within the
** in-memory hash table. If there is no such term in the hash-table, the 
** iterator is set to EOF.
**
** If an error occurs, Fts5Index.rc is set to an appropriate error code. If 
** an error has already occurred when this function is called, it is a no-op.
2707
2708
2709
2710
2711
2712
2713
2714

2715
2716
2717
2718
2719
2720
2721
2722
2804
2805
2806
2807
2808
2809
2810

2811

2812
2813
2814
2815
2816
2817
2818







-
+
-







  assert( p->pHash );
  assert( p->rc==SQLITE_OK );

  if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
    const u8 *pList = 0;

    p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
    sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
    sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList);
    n = (z ? (int)strlen((const char*)z) : 0);
    if( pList ){
      pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
      if( pLeaf ){
        pLeaf->p = (u8*)pList;
      }
    }

2766
2767
2768
2769
2770
2771
2772

















2773
2774
2775
2776
2777
2778
2779
2780
2781

2782
2783
2784
2785
2786
2787
2788
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893

2894
2895
2896
2897
2898
2899
2900
2901







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








-
+







    int ii;
    for(ii=0; ii<n; ii++){
      fts5DataRelease(ap[ii]);
    }
    sqlite3_free(ap);
  }
}

/*
** Decrement the ref-count of the object passed as the only argument. If it
** reaches 0, free it and its contents. 
*/
static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){
  if( p ){
    p->nRef--;
    if( p->nRef<=0 ){
      int ii;
      for(ii=0; ii<p->nTombstone; ii++){
        fts5DataRelease(p->apTombstone[ii]);
      }
      sqlite3_free(p);
    }
  }
}

/*
** Zero the iterator passed as the only argument.
*/
static void fts5SegIterClear(Fts5SegIter *pIter){
  fts5BufferFree(&pIter->term);
  fts5DataRelease(pIter->pLeaf);
  fts5DataRelease(pIter->pNextLeaf);
  fts5IndexFreeArray(pIter->apTombstone, pIter->nTombstone);
  fts5TombstoneArrayDelete(pIter->pTombArray);
  fts5DlidxIterFree(pIter->pDlidx);
  sqlite3_free(pIter->aRowidOffset);
  memset(pIter, 0, sizeof(Fts5SegIter));
}

#ifdef SQLITE_DEBUG

3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3132
3133
3134
3135
3136
3137
3138

3139
3140
3141
3142
3143
3144
3145







-







    if( pIter->pLeaf==0 ) break;
    if( bRev==0 && pIter->iRowid>=iMatch ) break;
    if( bRev!=0 && pIter->iRowid<=iMatch ) break;
    bMove = 1;
  }while( p->rc==SQLITE_OK );
}


/*
** Free the iterator object passed as the second argument.
*/
static void fts5MultiIterFree(Fts5Iter *pIter){
  if( pIter ){
    int i;
    for(i=0; i<pIter->nSeg; i++){
3164
3165
3166
3167
3168
3169
3170

3171
3172

3173
3174

3175
3176
3177
3178
3179
3180


3181
3182
3183

3184
3185
3186
3187
3188


3189
3190
3191
3192
3193
3194
3195
3276
3277
3278
3279
3280
3281
3282
3283
3284

3285
3286

3287
3288
3289
3290
3291


3292
3293
3294
3295

3296
3297
3298
3299


3300
3301
3302
3303
3304
3305
3306
3307
3308







+

-
+

-
+




-
-
+
+


-
+



-
-
+
+







** Return true if the iterator passed as the only argument points
** to an segment entry for which there is a tombstone. Return false
** if there is no tombstone or if the iterator is already at EOF.
*/
static int fts5MultiIterIsDeleted(Fts5Iter *pIter){
  int iFirst = pIter->aFirst[1].iFirst;
  Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
  Fts5TombstoneArray *pArray = pSeg->pTombArray;

  if( pSeg->pLeaf && pSeg->nTombstone ){
  if( pSeg->pLeaf && pArray ){
    /* Figure out which page the rowid might be present on. */
    int iPg = ((u64)pSeg->iRowid) % pSeg->nTombstone;
    int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone;
    assert( iPg>=0 );

    /* If tombstone hash page iPg has not yet been loaded from the 
    ** database, load it now. */
    if( pSeg->apTombstone[iPg]==0 ){
      pSeg->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
    if( pArray->apTombstone[iPg]==0 ){
      pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
          FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg)
      );
      if( pSeg->apTombstone[iPg]==0 ) return 0;
      if( pArray->apTombstone[iPg]==0 ) return 0;
    }

    return fts5IndexTombstoneQuery(
        pSeg->apTombstone[iPg],
        pSeg->nTombstone,
        pArray->apTombstone[iPg],
        pArray->nTombstone,
        pSeg->iRowid
    );
  }

  return 0;
}

3720
3721
3722
3723
3724
3725
3726


























3727
3728
3729
3730
3731
3732
3733
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872







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







      }else{
        pIter->xSetOutputs = fts5IterSetOutputs_Col;
      }
    }
  }
}

/*
** All the component segment-iterators of pIter have been set up. This
** functions finishes setup for iterator pIter itself.
*/
static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){
  int iIter;
  for(iIter=pIter->nSeg-1; iIter>0; iIter--){
    int iEq;
    if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){
      Fts5SegIter *pSeg = &pIter->aSeg[iEq];
      if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
      fts5MultiIterAdvanced(p, pIter, iEq, iIter);
    }
  }
  fts5MultiIterSetEof(pIter);
  fts5AssertMultiIterSetup(p, pIter);

  if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter))
   || fts5MultiIterIsDeleted(pIter)
  ){
    fts5MultiIterNext(p, pIter, 0, 0);
  }else if( pIter->base.bEof==0 ){
    Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
    pIter->xSetOutputs(pIter, pSeg);
  }
}

/*
** Allocate a new Fts5Iter object.
**
** The new object will be used to iterate through data in structure pStruct.
** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel
** is zero or greater, data from the first nSegment segments on level iLevel
3801
3802
3803
3804
3805
3806
3807
3808

3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821

3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3940
3941
3942
3943
3944
3945
3946

3947
3948
3949
3950
3951









3952











3953
3954
3955
3956
3957
3958
3959







-
+




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







      for(iSeg=nSeg-1; iSeg>=0; iSeg--){
        fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
      }
    }
    assert( iIter==nSeg );
  }

  /* If the above was successful, each component iterators now points 
  /* If the above was successful, each component iterator now points 
  ** to the first entry in its segment. In this case initialize the 
  ** aFirst[] array. Or, if an error has occurred, free the iterator
  ** object and set the output variable to NULL.  */
  if( p->rc==SQLITE_OK ){
    for(iIter=pNew->nSeg-1; iIter>0; iIter--){
      int iEq;
      if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
        Fts5SegIter *pSeg = &pNew->aSeg[iEq];
        if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
        fts5MultiIterAdvanced(p, pNew, iEq, iIter);
      }
    }
    fts5MultiIterSetEof(pNew);
    fts5MultiIterFinishSetup(p, pNew);
    fts5AssertMultiIterSetup(p, pNew);

    if( (pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew))
     || fts5MultiIterIsDeleted(pNew)
    ){
      fts5MultiIterNext(p, pNew, 0, 0);
    }else if( pNew->base.bEof==0 ){
      Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
      pNew->xSetOutputs(pNew, pSeg);
    }

  }else{
    fts5MultiIterFree(pNew);
    *ppOut = 0;
  }

fts5MultiIterNew_post_check:
  assert( (*ppOut)!=0 || p->rc!=SQLITE_OK );
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3970
3971
3972
3973
3974
3975
3976

3977
3978
3979
3980
3981
3982
3983







-







  int bDesc,                      /* True for descending rowid order */
  Fts5Iter **ppOut                /* New object */
){
  Fts5Iter *pNew;
  pNew = fts5MultiIterAlloc(p, 2);
  if( pNew ){
    Fts5SegIter *pIter = &pNew->aSeg[1];

    pIter->flags = FTS5_SEGITER_ONETERM;
    if( pData->szLeaf>0 ){
      pIter->pLeaf = pData;
      pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid);
      pIter->iEndofDoclist = pData->nn;
      pNew->aFirst[1].iFirst = 1;
      if( bDesc ){
3998
3999
4000
4001
4002
4003
4004

4005
4006
4007
4008
4009
4010
4011
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131







+







*/
static void fts5IndexDiscardData(Fts5Index *p){
  assert( p->pHash || p->nPendingData==0 );
  if( p->pHash ){
    sqlite3Fts5HashClear(p->pHash);
    p->nPendingData = 0;
    p->nPendingRow = 0;
    p->flushRc = SQLITE_OK;
  }
  p->nContentlessDelete = 0;
}

/*
** Return the size of the prefix, in bytes, that buffer 
** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
4213
4214
4215
4216
4217
4218
4219
4220

4221
4222
4223
4224
4225
4226
4227
4333
4334
4335
4336
4337
4338
4339

4340
4341
4342
4343
4344
4345
4346
4347







-
+







      pDlidx->bPrevValid = 0;
      pDlidx->pgno++;
    }else{
      bDone = 1;
    }

    if( pDlidx->bPrevValid ){
      iVal = iRowid - pDlidx->iPrev;
      iVal = (u64)iRowid - (u64)pDlidx->iPrev;
    }else{
      i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
      assert( pDlidx->buf.n==0 );
      sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone);
      sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno);
      iVal = iRowid;
    }
5133
5134
5135
5136
5137
5138
5139




5140
5141


5142
5143
5144
5145
5146
5147








5148
5149
5150
5151

5152
5153
5154
5155
5156
5157
5158
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263


5264
5265






5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276

5277
5278
5279
5280
5281
5282
5283
5284







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



-
+







      assert_nc( iSOP==pSeg->iLeafOffset );
      iNextOff = pSeg->iLeafOffset + pSeg->nPos;
    }
  }

  iOff = iStart;

  /* If the position-list for the entry being removed flows over past
  ** the end of this page, delete the portion of the position-list on the
  ** next page and beyond.
  **
  /* Set variable bLastInDoclist to true if this entry happens to be
  ** the last rowid in the doclist for its term.  */
  ** Set variable bLastInDoclist to true if this entry happens 
  ** to be the last rowid in the doclist for its term.  */
  if( pSeg->bDel==0 ){
    if( iNextOff>=iPgIdx ){
      int pgno = pSeg->iLeafPgno+1;
      fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
      iNextOff = iPgIdx;
    }else{
  if( iNextOff>=iPgIdx ){
    int pgno = pSeg->iLeafPgno+1;
    fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
    iNextOff = iPgIdx;
  }

  if( pSeg->bDel==0 ){
    if( iNextOff!=iPgIdx ){
      /* Loop through the page-footer. If iNextOff (offset of the
      ** entry following the one we are removing) is equal to the 
      ** offset of a key on this page, then the entry is the last 
      ** in its doclist.  */
      ** in its doclist. */
      int iKeyOff = 0;
      for(iIdx=0; iIdx<nIdx; /* no-op */){
        u32 iVal = 0;
        iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
        iKeyOff += iVal;
        if( iKeyOff==iNextOff ){
          bLastInDoclist = 1;
5330
5331
5332
5333
5334
5335
5336

5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466

5467
5468
5469
5470
5471
5472
5473







+



-







** mode. It edits the segments within the database described by argument
** pStruct to remove the entries for term zTerm, rowid iRowid.
*/
static void fts5FlushSecureDelete(
  Fts5Index *p,
  Fts5Structure *pStruct,
  const char *zTerm,
  int nTerm,
  i64 iRowid
){
  const int f = FTS5INDEX_QUERY_SKIPHASH;
  int nTerm = (int)strlen(zTerm);
  Fts5Iter *pIter = 0;            /* Used to find term instance */

  fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
  if( fts5MultiIterEof(p, pIter)==0 ){
    i64 iThis = fts5MultiIterRowid(pIter);
    if( iThis<iRowid ){
      fts5MultiIterNextFrom(p, pIter, iRowid);
5407
5408
5409
5410
5411
5412
5413
5414

5415
5416
5417
5418
5419
5420
5421
5422
5533
5534
5535
5536
5537
5538
5539

5540

5541
5542
5543
5544
5545
5546
5547







-
+
-







      while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
        const char *zTerm;        /* Buffer containing term */
        int nTerm;                /* Size of zTerm in bytes */
        const u8 *pDoclist;       /* Pointer to doclist for this term */
        int nDoclist;             /* Size of doclist in bytes */
  
        /* Get the term and doclist for this entry. */
        sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
        sqlite3Fts5HashScanEntry(pHash, &zTerm, &nTerm, &pDoclist, &nDoclist);
        nTerm = (int)strlen(zTerm);
        if( bSecureDelete==0 ){
          fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
          if( p->rc!=SQLITE_OK ) break;
          assert( writer.bFirstRowidInPage==0 );
        }
  
        if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
5438
5439
5440
5441
5442
5443
5444
5445

5446
5447
5448
5449
5450
5451
5452
5453
5454
5455

5456
5457
5458
5459
5460
5461
5462
5563
5564
5565
5566
5567
5568
5569

5570
5571
5572
5573
5574
5575
5576
5577
5578
5579

5580
5581
5582
5583
5584
5585
5586
5587







-
+









-
+







  
            /* If in secure delete mode, and if this entry in the poslist is
            ** in fact a delete, then edit the existing segments directly
            ** using fts5FlushSecureDelete().  */
            if( bSecureDelete ){
              if( eDetail==FTS5_DETAIL_NONE ){
                if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
                  fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
                  fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
                  iOff++;
                  if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
                    iOff++;
                    nDoclist = 0;
                  }else{
                    continue;
                  }
                }
              }else if( (pDoclist[iOff] & 0x01) ){
                fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
                fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
                if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
                  iOff++;
                  continue;
                }
              }
            }
  
5574
5575
5576
5577
5578
5579
5580




5581
5582
5583
5584
5585
5586
5587
5588


5589
5590
5591
5592
5593
5594
5595
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726







+
+
+
+








+
+







}

/*
** Flush any data stored in the in-memory hash tables to the database.
*/
static void fts5IndexFlush(Fts5Index *p){
  /* Unless it is empty, flush the hash table to disk */
  if( p->flushRc ){
    p->rc = p->flushRc;
    return;
  }
  if( p->nPendingData || p->nContentlessDelete ){
    assert( p->pHash );
    fts5FlushOneHash(p);
    if( p->rc==SQLITE_OK ){
      sqlite3Fts5HashClear(p->pHash);
      p->nPendingData = 0;
      p->nPendingRow = 0;
      p->nContentlessDelete = 0;
    }else if( p->nPendingData || p->nContentlessDelete ){
      p->flushRc = p->rc;
    }
  }
}

static Fts5Structure *fts5IndexOptimizeStruct(
  Fts5Index *p, 
  Fts5Structure *pStruct
6068
6069
6070
6071
6072
6073
6074
6075

6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095

6096
6097

6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108






6109
6110
6111
6112
6113
6114
6115
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







-
+




















+

-
+











+
+
+
+
+
+







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 */
  Fts5Iter **ppIter               /* OUT: New iterator */
){
  Fts5Structure *pStruct;
  Fts5Buffer *aBuf;
  int nBuf = 32;
  int nMerge = 1;

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

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

  if( aBuf && pStruct ){
  if( p->rc==SQLITE_OK ){
    const int flags = FTS5INDEX_QUERY_SCAN 
                    | 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);
      fts5IterSetOutputCb(&p->rc, p1);
      for(;
6125
6126
6127
6128
6129
6130
6131

6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
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







+















-







      }
      fts5MultiIterFree(p1);
    }

    pToken[0] = FTS5_MAIN_PREFIX + iIdx;
    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 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 ){
6179
6180
6181
6182
6183
6184
6185
6186

6187
6188
6189
6190
6191
6192
6193
6317
6318
6319
6320
6321
6322
6323

6324
6325
6326
6327
6328
6329
6330
6331







-
+







      }
      for(iFree=i; iFree<i+nMerge; iFree++){
        fts5BufferFree(&aBuf[iFree]);
      }
    }
    fts5MultiIterFree(p1);

    pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
    pData = fts5IdxMalloc(p, sizeof(*pData)+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);
      fts5MultiIterNew2(p, pData, bDesc, ppIter);
    }
    fts5BufferFree(&doclist);
6322
6323
6324
6325
6326
6327
6328

6329
6330
6331
6332
6333
6334
6335
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474







+







    assert( p->pReader==0 );
    fts5StructureInvalidate(p);
    sqlite3_finalize(p->pWriter);
    sqlite3_finalize(p->pDeleter);
    sqlite3_finalize(p->pIdxWriter);
    sqlite3_finalize(p->pIdxDeleter);
    sqlite3_finalize(p->pIdxSelect);
    sqlite3_finalize(p->pIdxNextSelect);
    sqlite3_finalize(p->pDataVersion);
    sqlite3_finalize(p->pDeleteFromIdx);
    sqlite3Fts5HashFree(p->pHash);
    sqlite3_free(p->zDataTbl);
    sqlite3_free(p);
  }
  return rc;
6416
6417
6418
6419
6420
6421
6422



































































































































































































































































































































































































































































6423
6424
6425
6426
6427
6428
6429
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
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
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
6879
6880
6881
6882
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893
6894
6895
6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019







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







          nByte
      );
    }
  }

  return rc;
}

/*
** pToken points to a buffer of size nToken bytes containing a search 
** term, including the index number at the start, used on a tokendata=1
** table. This function returns true if the term in buffer pBuf matches 
** token pToken/nToken.
*/
static int fts5IsTokendataPrefix(
  Fts5Buffer *pBuf,
  const u8 *pToken,
  int nToken
){
  return (
      pBuf->n>=nToken 
   && 0==memcmp(pBuf->p, pToken, nToken)
   && (pBuf->n==nToken || pBuf->p[nToken]==0x00)
  );
}

/*
** 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 */
  Fts5Iter *pAppend               /* Append this iterator */
){
  Fts5TokenDataIter *pRet = pIn;

  if( p->rc==SQLITE_OK ){
    if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
      int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
      int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
      Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);

      if( pNew==0 ){
        p->rc = SQLITE_NOMEM;
      }else{
        if( pIn==0 ) memset(pNew, 0, nByte);
        pRet = pNew;
        pNew->nIterAlloc = nAlloc;
      }
    }
  }
  if( p->rc ){
    sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
  }else{
    pRet->apIter[pRet->nIter++] = pAppend;
  }
  assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );

  return pRet;
}

/*
** 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){
  int ii;
  int nHit = 0;
  i64 iRowid = SMALLEST_INT64;
  int iMin = 0;

  Fts5TokenDataIter *pT = pIter->pTokenDataIter;

  pIter->base.nData = 0;
  pIter->base.pData = 0;

  for(ii=0; ii<pT->nIter; ii++){
    Fts5Iter *p = pT->apIter[ii];
    if( p->base.bEof==0 ){
      if( nHit==0 || p->base.iRowid<iRowid ){
        iRowid = p->base.iRowid;
        nHit = 1;
        pIter->base.pData = p->base.pData;
        pIter->base.nData = p->base.nData;
        iMin = ii;
      }else if( p->base.iRowid==iRowid ){
        nHit++;
      }
    }
  }

  if( nHit==0 ){
    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);
    }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. */
      if( pT->aPoslistReader==0 ){
        pT->aPoslistReader = (Fts5PoslistReader*)sqlite3Fts5MallocZero(
            &pIter->pIndex->rc,
            pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int))
        );
        if( pT->aPoslistReader==0 ) return;
        pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter];
      }

      /* Populate an iterator for each poslist that will be merged */
      for(ii=0; ii<pT->nIter; ii++){
        Fts5Iter *p = pT->apIter[ii];
        if( iRowid==p->base.iRowid ){
          pT->aPoslistToIter[nReader] = ii;
          sqlite3Fts5PoslistReaderInit(
              p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++]
          );
          nByte += p->base.nData;
        }
      }

      /* Ensure the output buffer is large enough */
      if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){
        return;
      }

      /* Ensure the token-mapping is large enough */
      if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
        int nNew = (pT->nMapAlloc + nByte) * 2;
        Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc(
            pT->aMap, nNew*sizeof(Fts5TokenDataMap)
        );
        if( aNew==0 ){
          pIter->pIndex->rc = SQLITE_NOMEM;
          return;
        }
        pT->aMap = aNew;
        pT->nMapAlloc = nNew;
      }

      pIter->poslist.n = 0;

      while( 1 ){
        i64 iMinPos = LARGEST_INT64;

        /* Find smallest position */
        iMin = 0;
        for(ii=0; ii<nReader; ii++){
          Fts5PoslistReader *pReader = &pT->aPoslistReader[ii];
          if( pReader->bEof==0 ){
            if( pReader->iPos<iMinPos ){
              iMinPos = pReader->iPos;
              iMin = ii;
            }
          }
        }

        /* If all readers were at EOF, break out of the loop. */
        if( iMinPos==LARGEST_INT64 ) break;

        sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos);
        sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]);

        if( eDetail==FTS5_DETAIL_FULL ){
          pT->aMap[pT->nMap].iPos = iMinPos;
          pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin];
          pT->aMap[pT->nMap].iRowid = iRowid;
          pT->nMap++;
        }
      }

      pIter->base.pData = pIter->poslist.p;
      pIter->base.nData = pIter->poslist.n;
    }
  }
}

/*
** The iterator passed as the only argument must be a tokendata=1 iterator
** (pIter->pTokenDataIter!=0). This function advances the iterator. If
** argument bFrom is false, then the iterator is advanced to the next
** entry. Or, if bFrom is true, it is advanced to the first entry with
** a rowid of iFrom or greater.
*/
static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
  int ii;
  Fts5TokenDataIter *pT = pIter->pTokenDataIter;
  Fts5Index *pIndex = pIter->pIndex;

  for(ii=0; ii<pT->nIter; ii++){
    Fts5Iter *p = pT->apIter[ii];
    if( p->base.bEof==0 
     && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
    ){
      fts5MultiIterNext(pIndex, p, bFrom, iFrom);
      while( bFrom && p->base.bEof==0 
          && p->base.iRowid<iFrom 
          && pIndex->rc==SQLITE_OK 
      ){
        fts5MultiIterNext(pIndex, p, 0, 0);
      }
    }
  }

  if( pIndex->rc==SQLITE_OK ){
    fts5IterSetOutputsTokendata(pIter);
  }
}

/*
** If the segment-iterator passed as the first argument is at EOF, then
** set pIter->term to a copy of buffer pTerm.
*/
static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){
  if( pIter && pIter->aSeg[0].pLeaf==0 ){
    fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p);
  }
}

/*
** This function sets up an iterator to use for a non-prefix query on a 
** tokendata=1 table. 
*/
static Fts5Iter *fts5SetupTokendataIter(
  Fts5Index *p,                   /* FTS index to query */
  const u8 *pToken,               /* Buffer containing query term */
  int nToken,                     /* Size of buffer pToken in bytes */
  Fts5Colset *pColset             /* Colset to filter on */
){
  Fts5Iter *pRet = 0;
  Fts5TokenDataIter *pSet = 0;
  Fts5Structure *pStruct = 0;
  const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN;

  Fts5Buffer bSeek = {0, 0, 0};
  Fts5Buffer *pSmall = 0;             

  fts5IndexFlush(p);
  pStruct = fts5StructureRead(p);

  while( p->rc==SQLITE_OK ){
    Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0;
    Fts5Iter *pNew = 0;
    Fts5SegIter *pNewIter = 0;
    Fts5SegIter *pPrevIter = 0;

    int iLvl, iSeg, ii;

    pNew = fts5MultiIterAlloc(p, pStruct->nSegment);
    if( pSmall ){
      fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
      fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
    }else{
      fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
    }
    if( p->rc ){
      sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
      break;
    }

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

        if( pPrevIter ){
          if( fts5BufferCompare(pSmall, &pPrevIter->term) ){
            memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter));
            memset(pPrevIter, 0, sizeof(Fts5SegIter));
            bDone = 1;
          }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){
            fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter);
            bDone = 1;
          }
        }

        if( bDone==0 ){
          fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter);
        }

        if( pPrevIter ){
          if( pPrevIter->pTombArray ){
            pNewIter->pTombArray = pPrevIter->pTombArray;
            pNewIter->pTombArray->nRef++;
          }
        }else{
          fts5SegIterAllocTombstone(p, pNewIter);
        }

        pNewIter++;
        if( pPrevIter ) pPrevIter++;
        if( p->rc ) break;
      }
    }
    fts5TokendataSetTermIfEof(pPrev, pSmall);

    pNew->bSkipEmpty = 1;
    pNew->pColset = pColset;
    fts5IterSetOutputCb(&p->rc, pNew);

    /* Loop through all segments in the new iterator. Find the smallest 
    ** term that any segment-iterator points to. Iterator pNew will be
    ** used for this term. Also, set any iterator that points to a term that
    ** does not match pToken/nToken to point to EOF */
    pSmall = 0;
    for(ii=0; ii<pNew->nSeg; ii++){
      Fts5SegIter *pII = &pNew->aSeg[ii];
      if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){
        fts5SegIterSetEOF(pII);
      }
      if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){
        pSmall = &pII->term;
      }
    }

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

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

  if( p->rc==SQLITE_OK && pSet ){
    int ii;
    for(ii=0; ii<pSet->nIter; ii++){
      Fts5Iter *pIter = pSet->apIter[ii];
      int iSeg;
      for(iSeg=0; iSeg<pIter->nSeg; iSeg++){
        pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM;
      }
      fts5MultiIterFinishSetup(p, pIter);
    }
  }
    
  if( p->rc==SQLITE_OK ){
    pRet = fts5MultiIterAlloc(p, 0);
  }
  if( pRet ){
    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 */
6438
6439
6440
6441
6442
6443
6444

6445




6446
6447
6448
6449
6450
6451
6452
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047







+

+
+
+
+








  /* If the QUERY_SCAN flag is set, all other flags must be clear. */
  assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN );

  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);

    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
    ** satisfied by scanning multiple terms in the main index.
    **
    ** If the QUERY_TEST_NOIDX flag was specified, then this must be a
6465
6466
6467
6468
6469
6470
6471



6472

6473
6474
6475
6476
6477
6478
6479
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069

7070
7071
7072
7073
7074
7075
7076
7077







+
+
+
-
+







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

    if( bTokendata && iIdx==0 ){
      buf.p[0] = '0';
      pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
    if( iIdx<=pConfig->nPrefix ){
    }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
        );
6512
6513
6514
6515
6516
6517
6518



6519


6520
6521
6522
6523
6524
6525
6526
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119

7120
7121
7122
7123
7124
7125
7126
7127
7128







+
+
+
-
+
+







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

/*
** Move to the next matching term/rowid. Used by the fts5vocab module.
*/
int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
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
7147
7148
7149
7150
7151
7152
7153
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
7208
7209
7210
7211
7212
7213
7214
7215
7216
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
7276
7277
7278
7279
7280







+
+
+
-
+
+















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






+







/*
** 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->pTokenDataIter ){
    fts5TokendataIterNext(pIter, 1, iMatch);
  }else{
  fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
    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);
}

/*
** 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).
*/
int sqlite3Fts5IterToken(
  Fts5IndexIter *pIndexIter, 
  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;

  int i1 = 0;
  int i2 = pT->nMap;
  int iTest = 0;

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

    if( aMap[iTest].iRowid<iRowid ){
      i1 = iTest+1;
    }else if( aMap[iTest].iRowid>iRowid ){
      i2 = iTest;
    }else{
      if( aMap[iTest].iPos<iPos ){
        if( aMap[iTest].iPos<0 ){
          break;
        }
        i1 = iTest+1;
      }else if( aMap[iTest].iPos>iPos ){
        i2 = iTest;
      }else{
        break;
      }
    }
  }

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

  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 ){
    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;

  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);
  }
  return fts5IndexReturn(p);
}

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

/*
** Read and decode the "averages" record from the database. 
7074
7075
7076
7077
7078
7079
7080
7081



7082
7083
7084
7085
7086
7087
7088
7774
7775
7776
7777
7778
7779
7780

7781
7782
7783
7784
7785
7786
7787
7788
7789
7790







-
+
+
+







  int n,                          /* Size of index key in bytes */
  int flags,                      /* Flags for Fts5IndexQuery */
  u64 *pCksum                     /* IN/OUT: Checksum value */
){
  int eDetail = p->pConfig->eDetail;
  u64 cksum = *pCksum;
  Fts5IndexIter *pIter = 0;
  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
  int rc = sqlite3Fts5IndexQuery(
      p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter
  );

  while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){
    i64 rowid = pIter->iRowid;

    if( eDetail==FTS5_DETAIL_NONE ){
      cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
    }else{
7241
7242
7243
7244
7245
7246
7247
7248

7249
7250
7251
7252
7253
7254
7255
7256
7257

7258
7259
7260
7261
7262
7263
7264
7943
7944
7945
7946
7947
7948
7949

7950
7951
7952
7953
7954
7955
7956
7957
7958

7959
7960
7961
7962
7963
7964
7965
7966







-
+








-
+







      if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT;
    }
    fts5DataRelease(pLeaf);
  }
}

static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
  int iTermOff = 0;
  i64 iTermOff = 0;
  int ii;

  Fts5Buffer buf1 = {0,0,0};
  Fts5Buffer buf2 = {0,0,0};

  ii = pLeaf->szLeaf;
  while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
    int res;
    int iOff;
    i64 iOff;
    int nIncr;

    ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
    iTermOff += nIncr;
    iOff = iTermOff;

    if( iOff>=pLeaf->szLeaf ){
7771
7772
7773
7774
7775
7776
7777


















7778
7779
7780
7781
7782
7783
7784
8473
8474
8475
8476
8477
8478
8479
8480
8481
8482
8483
8484
8485
8486
8487
8488
8489
8490
8491
8492
8493
8494
8495
8496
8497
8498
8499
8500
8501
8502
8503
8504







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







      }
    }

    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
  }
}
#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */

#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){
  int ii;
  fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1);
  if( *pRc==SQLITE_OK ){
    for(ii=0; ii<pTerm->n; ii++){
      if( pTerm->p[ii]==0x00 ){
        pBuf->p[pBuf->n++] = '\\';
        pBuf->p[pBuf->n++] = '0';
      }else{
        pBuf->p[pBuf->n++] = pTerm->p[ii];
      }
    }
    pBuf->p[pBuf->n] = 0x00;
  }
}
#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */

#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_decode().
*/
static void fts5DecodeFunction(
  sqlite3_context *pCtx,          /* Function call context */
7879
7880
7881
7882
7883
7884
7885
7886
7887


7888
7889
7890
7891
7892
7893
7894
7895
8599
8600
8601
8602
8603
8604
8605


8606
8607

8608
8609
8610
8611
8612
8613
8614







-
-
+
+
-







    while( iOff<szLeaf && rc==SQLITE_OK ){
      int nAppend;

      /* Read the term data for the next term*/
      iOff += fts5GetVarint32(&a[iOff], nAppend);
      term.n = nKeep;
      fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
      sqlite3Fts5BufferAppendPrintf(
          &rc, &s, " term=%.*s", term.n, (const char*)term.p
      sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
      fts5BufferAppendTerm(&rc, &s, &term);
      );
      iOff += nAppend;

      /* Figure out where the doclist for this term ends */
      if( iPgidxOff<n ){
        int nIncr;
        iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr);
        iTermOff += nIncr;
7989
7990
7991
7992
7993
7994
7995
7996
7997


7998
7999
8000
8001
8002
8003
8004
8005
8708
8709
8710
8711
8712
8713
8714


8715
8716

8717
8718
8719
8720
8721
8722
8723







-
-
+
+
-







      if( iOff+nByte>n ){
        rc = FTS5_CORRUPT;
        break;
      }
      fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
      iOff += nByte;

      sqlite3Fts5BufferAppendPrintf(
          &rc, &s, " term=%.*s", term.n, (const char*)term.p
      sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
      fts5BufferAppendTerm(&rc, &s, &term);
      );
      iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
    }

    fts5BufferFree(&term);
  }
  
 decode_out:
Changes to ext/fts5/fts5_main.c.
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128







-
+








struct Fts5FullTable {
  Fts5Table p;                    /* Public class members from fts5Int.h */
  Fts5Storage *pStorage;          /* Document store */
  Fts5Global *pGlobal;            /* Global (connection wide) data */
  Fts5Cursor *pSortCsr;           /* Sort data from this cursor */
  int iSavepoint;                 /* Successful xSavepoint()+1 */
  int bInSavepoint;
  
#ifdef SQLITE_DEBUG
  struct Fts5TransactionState ts;
#endif
};

struct Fts5MatchPhrase {
  Fts5Buffer *pPoslist;           /* Pointer to current poslist */
652
653
654
655
656
657
658
659




660
661
662
663
664

665
666
667
668
669
670
671
652
653
654
655
656
657
658

659
660
661
662
663
664
665
666

667
668
669
670
671
672
673
674







-
+
+
+
+




-
+







          bSeenGt = 1;
        }
      }
    }
  }
  idxStr[iIdxStr] = '\0';

  /* Set idxFlags flags for the ORDER BY clause */
  /* Set idxFlags flags for the ORDER BY clause
  **
  ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
  */
  if( pInfo->nOrderBy==1 ){
    int iSort = pInfo->aOrderBy[0].iColumn;
    if( iSort==(pConfig->nCol+1) && bSeenMatch ){
      idxFlags |= FTS5_BI_ORDER_RANK;
    }else if( iSort==-1 ){
    }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
      idxFlags |= FTS5_BI_ORDER_ROWID;
    }
    if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
      pInfo->orderByConsumed = 1;
      if( pInfo->aOrderBy[0].desc ){
        idxFlags |= FTS5_BI_ORDER_DESC;
      }
908
909
910
911
912
913
914










915
916
917
918
919
920
921
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934







+
+
+
+
+
+
+
+
+
+







  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
  int rc;

  assert( (pCsr->ePlan<3)==
          (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) 
  );
  assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );

  /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
  ** clear any token mappings accumulated at the fts5_index.c level. In
  ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
  ** we need to retain the mappings for the entire query.  */
  if( pCsr->ePlan==FTS5_PLAN_MATCH 
   && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata 
  ){
    sqlite3Fts5ExprClearTokens(pCsr->pExpr);
  }

  if( pCsr->ePlan<3 ){
    int bSkip = 0;
    if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
    rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
    CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
    fts5CsrNewrow(pCsr);
1569
1570
1571
1572
1573
1574
1575


1576


1577
1578
1579
1580
1581
1582
1583
1582
1583
1584
1585
1586
1587
1588
1589
1590

1591
1592
1593
1594
1595
1596
1597
1598
1599







+
+
-
+
+







#ifdef SQLITE_DEBUG
  }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
    pConfig->bPrefixIndex = sqlite3_value_int(pVal);
#endif
  }else if( 0==sqlite3_stricmp("flush", zCmd) ){
    rc = sqlite3Fts5FlushToDisk(&pTab->p);
  }else{
    rc = sqlite3Fts5FlushToDisk(&pTab->p);
    if( rc==SQLITE_OK ){
    rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
      rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
    }
    if( rc==SQLITE_OK ){
      rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
    }
    if( rc==SQLITE_OK ){
      if( bError ){
        rc = SQLITE_ERROR;
      }else{
1894
1895
1896
1897
1898
1899
1900



1901

1902
1903
1904
1905
1906
1907
1908
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919

1920
1921
1922
1923
1924
1925
1926
1927







+
+
+
-
+







  Fts5Context *pCtx, 
  int iCol, 
  const char **pz, 
  int *pn
){
  int rc = SQLITE_OK;
  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
  if( iCol<0 || iCol>=pTab->pConfig->nCol ){
    rc = SQLITE_RANGE;
  if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) 
  }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) 
   || pCsr->ePlan==FTS5_PLAN_SPECIAL 
  ){
    *pz = 0;
    *pn = 0;
  }else{
    rc = fts5SeekCursor(pCsr, 0);
    if( rc==SQLITE_OK ){
1919
1920
1921
1922
1923
1924
1925


1926

1927
1928
1929
1930
1931
1932
1933
1934
1938
1939
1940
1941
1942
1943
1944
1945
1946

1947

1948
1949
1950
1951
1952
1953
1954







+
+
-
+
-







  const u8 **pa,
  int *pn
){
  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
  int rc = SQLITE_OK;
  int bLive = (pCsr->pSorter==0);

  if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
    rc = SQLITE_RANGE;
  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
  }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){

    if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
      Fts5PoslistPopulator *aPopulator;
      int i;
      aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
      if( aPopulator==0 ) rc = SQLITE_NOMEM;
      for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
        int n; const char *z;
1944
1945
1946
1947
1948
1949
1950

1951
1952
1953
1954
1955
1956
1957
1958













1959
1960
1961
1962
1963
1964
1965
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







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







      if( pCsr->pSorter ){
        sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
      }
    }
    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
  }

  if( rc==SQLITE_OK ){
  if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
    Fts5Sorter *pSorter = pCsr->pSorter;
    int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
    *pn = pSorter->aIdx[iPhrase] - i1;
    *pa = &pSorter->aPoslist[i1];
  }else{
    *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
  }
    if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
      Fts5Sorter *pSorter = pCsr->pSorter;
      int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
      *pn = pSorter->aIdx[iPhrase] - i1;
      *pa = &pSorter->aPoslist[i1];
    }else{
      *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
    }
  }else{
    *pa = 0;
    *pn = 0;
  }


  return rc;
}

/*
** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
** correctly for the current view. Return SQLITE_OK if successful, or an
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2085
2086
2087
2088
2089
2090
2091






2092
2093
2094
2095
2096
2097
2098







-
-
-
-
-
-







  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
  int rc = SQLITE_OK;
  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 
   || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) 
  ){
    if( iIdx<0 || iIdx>=pCsr->nInstCount ){
      rc = SQLITE_RANGE;
#if 0
    }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
      *piPhrase = pCsr->aInst[iIdx*3];
      *piCol = pCsr->aInst[iIdx*3 + 2];
      *piOff = -1;
#endif
    }else{
      *piPhrase = pCsr->aInst[iIdx*3];
      *piCol = pCsr->aInst[iIdx*3 + 1];
      *piOff = pCsr->aInst[iIdx*3 + 2];
    }
  }
  return rc;
2319
2320
2321
2322
2323
2324
2325











































2326
2327
2328
2329
2330
2331
2332

2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351


2352
2353
2354
2355
2356
2357
2358
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394

2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423







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






-
+



















+
+







      }
    }
  }

  return rc;
}

/*
** xQueryToken() API implemenetation.
*/
static int fts5ApiQueryToken(
  Fts5Context* pCtx, 
  int iPhrase, 
  int iToken, 
  const char **ppOut, 
  int *pnOut
){
  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
  return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
}

/*
** xInstToken() API implemenetation.
*/
static int fts5ApiInstToken(
  Fts5Context *pCtx,
  int iIdx, 
  int iToken,
  const char **ppOut, int *pnOut
){
  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
  int rc = SQLITE_OK;
  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 
   || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) 
  ){
    if( iIdx<0 || iIdx>=pCsr->nInstCount ){
      rc = SQLITE_RANGE;
    }else{
      int iPhrase = pCsr->aInst[iIdx*3];
      int iCol = pCsr->aInst[iIdx*3 + 1];
      int iOff = pCsr->aInst[iIdx*3 + 2];
      i64 iRowid = fts5CursorRowid(pCsr);
      rc = sqlite3Fts5ExprInstToken(
          pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
      );
    }
  }
  return rc;
}


static int fts5ApiQueryPhrase(Fts5Context*, int, void*, 
    int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);

static const Fts5ExtensionApi sFts5Api = {
  2,                            /* iVersion */
  3,                            /* iVersion */
  fts5ApiUserData,
  fts5ApiColumnCount,
  fts5ApiRowCount,
  fts5ApiColumnTotalSize,
  fts5ApiTokenize,
  fts5ApiPhraseCount,
  fts5ApiPhraseSize,
  fts5ApiInstCount,
  fts5ApiInst,
  fts5ApiRowid,
  fts5ApiColumnText,
  fts5ApiColumnSize,
  fts5ApiQueryPhrase,
  fts5ApiSetAuxdata,
  fts5ApiGetAuxdata,
  fts5ApiPhraseFirst,
  fts5ApiPhraseNext,
  fts5ApiPhraseFirstColumn,
  fts5ApiPhraseNextColumn,
  fts5ApiQueryToken,
  fts5ApiInstToken
};

/*
** Implementation of API function xQueryPhrase().
*/
static int fts5ApiQueryPhrase(
  Fts5Context *pCtx, 
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637

2638
2639

2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654



2655
2656
2657
2658
2659
2660
2661
2662
2663
2676
2677
2678
2679
2680
2681
2682

2683

2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699

2700
2701

2702















2703
2704
2705


2706
2707
2708
2709
2710
2711
2712







-

-
















-
+

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







*/
static int fts5RenameMethod(
  sqlite3_vtab *pVtab,            /* Virtual table handle */
  const char *zName               /* New name of table */
){
  int rc;
  Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
  pTab->bInSavepoint = 1;
  rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
  pTab->bInSavepoint = 0;
  return rc;
}

int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
  fts5TripCursors((Fts5FullTable*)pTab);
  return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
}

/*
** The xSavepoint() method.
**
** Flush the contents of the pending-terms table to disk.
*/
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
  Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
  int rc = SQLITE_OK;
  char *zSql = 0;

  fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);

  rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
  if( pTab->bInSavepoint==0 ){
    zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
        pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName
    );
    if( zSql ){
      pTab->bInSavepoint = 1;
      rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0);
      pTab->bInSavepoint = 0;
      sqlite3_free(zSql);
    }else{
      rc = SQLITE_NOMEM;
    }
    if( rc==SQLITE_OK ){
      pTab->iSavepoint = iSavepoint+1;
    }
  if( rc==SQLITE_OK ){
    pTab->iSavepoint = iSavepoint+1;
  }
  }

  return rc;
}

/*
** The xRelease() method.
**
** This is a no-op.
2681
2682
2683
2684
2685
2686
2687
2688
2689

2690
2691
2692
2693
2694
2695
2696
2730
2731
2732
2733
2734
2735
2736

2737
2738
2739
2740
2741
2742
2743
2744
2745







-

+







** Discard the contents of the pending terms table.
*/
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
  Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
  int rc = SQLITE_OK;
  fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
  fts5TripCursors(pTab);
  pTab->p.pConfig->pgsz = 0;
  if( (iSavepoint+1)<=pTab->iSavepoint ){
    pTab->p.pConfig->pgsz = 0;
    rc = sqlite3Fts5StorageRollback(pTab->pStorage);
  }
  return rc;
}

/*
** Register a new auxiliary function with global context pGlobal.
2910
2911
2912
2913
2914
2915
2916
2917

2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928

2929
2930
2931

2932
2933
2934
2935
2936
2937
2938
2939

2940
2941
2942
2943

2944

2945
2946


2947
2948
2949
2950
2951
2952
2953
2959
2960
2961
2962
2963
2964
2965

2966
2967
2968
2969
2970
2971
2972
2973



2974
2975
2976
2977

2978





2979
2980
2981
2982
2983
2984
2985

2986
2987
2988


2989
2990
2991
2992
2993
2994
2995
2996
2997







-
+







-
-
-

+


-
+
-
-
-
-
-



+



-
+

+
-
-
+
+







}

/*
** Run an integrity check on the FTS5 data structures.  Return a string
** if anything is found amiss.  Return a NULL pointer if everything is
** OK.
*/
static int fts5Integrity(
static int fts5IntegrityMethod(
  sqlite3_vtab *pVtab,    /* the FTS5 virtual table to check */
  const char *zSchema,    /* Name of schema in which this table lives */
  const char *zTabname,   /* Name of the table itself */
  int isQuick,            /* True if this is a quick-check */
  char **pzErr            /* Write error message here */
){
  Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
  Fts5Config *pConfig = pTab->p.pConfig;
  char *zSql;
  char *zErr = 0;
  int rc;

  assert( pzErr!=0 && *pzErr==0 );
  UNUSED_PARAM(isQuick);
  zSql = sqlite3_mprintf(
  rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
            "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
            zSchema, zTabname, pConfig->zName);
  if( zSql==0 ) return SQLITE_NOMEM;
  rc = sqlite3_exec(pConfig->db, zSql, 0, 0, &zErr);
  sqlite3_free(zSql);
  if( (rc&0xff)==SQLITE_CORRUPT ){
    *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
                zSchema, zTabname);
     rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
  }else if( rc!=SQLITE_OK ){
    *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
                             " FTS5 table %s.%s: %s",
                zSchema, zTabname, zErr);
                zSchema, zTabname, sqlite3_errstr(rc));
  }
  sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
  sqlite3_free(zErr);
  return SQLITE_OK;

  return rc;
}

static int fts5Init(sqlite3 *db){
  static const sqlite3_module fts5Mod = {
    /* iVersion      */ 4,
    /* xCreate       */ fts5CreateMethod,
    /* xConnect      */ fts5ConnectMethod,
2968
2969
2970
2971
2972
2973
2974
2975

2976
2977
2978
2979
2980
2981
2982
3012
3013
3014
3015
3016
3017
3018

3019
3020
3021
3022
3023
3024
3025
3026







-
+







    /* xRollback     */ fts5RollbackMethod,
    /* xFindFunction */ fts5FindFunctionMethod,
    /* xRename       */ fts5RenameMethod,
    /* xSavepoint    */ fts5SavepointMethod,
    /* xRelease      */ fts5ReleaseMethod,
    /* xRollbackTo   */ fts5RollbackToMethod,
    /* xShadowName   */ fts5ShadowName,
    /* xIntegrity    */ fts5Integrity
    /* xIntegrity    */ fts5IntegrityMethod
  };

  int rc;
  Fts5Global *pGlobal = 0;

  pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
  if( pGlobal==0 ){
Changes to ext/fts5/fts5_storage.c.
669
670
671
672
673
674
675
676

677
678
679
680
681
682
683
669
670
671
672
673
674
675

676
677
678
679
680
681
682
683







-
+







  ctx.pStorage = p;
  rc = sqlite3Fts5StorageDeleteAll(p);
  if( rc==SQLITE_OK ){
    rc = fts5StorageLoadTotals(p, 1);
  }

  if( rc==SQLITE_OK ){
    rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
    rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
  }

  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
    i64 iRowid = sqlite3_column_int64(pScan, 0);

    sqlite3Fts5BufferZero(&buf);
    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
Changes to ext/fts5/fts5_tcl.c.
240
241
242
243
244
245
246



247
248
249
250
251
252
253
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256







+
+
+







    { "xQueryPhrase",      2, "PHRASE SCRIPT" },      /* 11 */
    { "xSetAuxdata",       1, "VALUE" },              /* 12 */
    { "xGetAuxdata",       1, "CLEAR" },              /* 13 */
    { "xSetAuxdataInt",    1, "INTEGER" },            /* 14 */
    { "xGetAuxdataInt",    1, "CLEAR" },              /* 15 */
    { "xPhraseForeach",    4, "IPHRASE COLVAR OFFVAR SCRIPT" }, /* 16 */
    { "xPhraseColumnForeach", 3, "IPHRASE COLVAR SCRIPT" }, /* 17 */

    { "xQueryToken",       2, "IPHRASE ITERM" },      /* 18 */
    { "xInstToken",        2, "IDX ITERM" },          /* 19 */
    { 0, 0, 0}
  };

  int rc;
  int iSub = 0;
  F5tApi *p = (F5tApi*)clientData;

492
493
494
495
496
497
498
































499
500
501
502
503
504
505
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







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







        rc = Tcl_EvalObjEx(interp, pScript, 0);
        if( rc==TCL_CONTINUE ) rc = TCL_OK;
        if( rc!=TCL_OK ){
          if( rc==TCL_BREAK ) rc = TCL_OK;
          break;
        }
      }

      break;
    }

    CASE(18, "xQueryToken") {
      const char *pTerm = 0;
      int nTerm = 0;
      int iPhrase = 0;
      int iTerm = 0;

      if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR;
      if( Tcl_GetIntFromObj(interp, objv[3], &iTerm) ) return TCL_ERROR;
      rc = p->pApi->xQueryToken(p->pFts, iPhrase, iTerm, &pTerm, &nTerm);
      if( rc==SQLITE_OK ){
        Tcl_SetObjResult(interp, Tcl_NewStringObj(pTerm, nTerm));
      }

      break;
    }

    CASE(19, "xInstToken") {
      const char *pTerm = 0;
      int nTerm = 0;
      int iIdx = 0;
      int iTerm = 0;

      if( Tcl_GetIntFromObj(interp, objv[2], &iIdx) ) return TCL_ERROR;
      if( Tcl_GetIntFromObj(interp, objv[3], &iTerm) ) return TCL_ERROR;
      rc = p->pApi->xInstToken(p->pFts, iIdx, iTerm, &pTerm, &nTerm);
      if( rc==SQLITE_OK ){
        Tcl_SetObjResult(interp, Tcl_NewStringObj(pTerm, nTerm));
      }

      break;
    }

    default: 
      assert( 0 );
      break;
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
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







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

















-
+
+







  rc = sqlite3Fts5TestRegisterTok(db, pApi);
  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
    return TCL_ERROR;
  }
  return TCL_OK;
}

typedef struct OriginTextCtx OriginTextCtx;
struct OriginTextCtx {
  sqlite3 *db;
  fts5_api *pApi;
};

typedef struct OriginTextTokenizer OriginTextTokenizer;
struct OriginTextTokenizer {
  Fts5Tokenizer *pTok;            /* Underlying tokenizer object */
  fts5_tokenizer tokapi;          /* API implementation for pTok */
};

/*
** Delete the OriginTextCtx object indicated by the only argument.
*/
static void f5tOrigintextTokenizerDelete(void *pCtx){
  OriginTextCtx *p = (OriginTextCtx*)pCtx;
  ckfree((char*)p);
}

static int f5tOrigintextCreate(
  void *pCtx, 
  const char **azArg, 
  int nArg, 
  Fts5Tokenizer **ppOut
){
  OriginTextCtx *p = (OriginTextCtx*)pCtx;
  OriginTextTokenizer *pTok = 0;
  void *pTokCtx = 0;
  int rc = SQLITE_OK;

  pTok = (OriginTextTokenizer*)sqlite3_malloc(sizeof(OriginTextTokenizer));
  if( pTok==0 ){
    rc = SQLITE_NOMEM;
  }else if( nArg<1 ){
    rc = SQLITE_ERROR;
  }else{
    /* Locate the underlying tokenizer */
    rc = p->pApi->xFindTokenizer(p->pApi, azArg[0], &pTokCtx, &pTok->tokapi);
  }

  /* Create the new tokenizer instance */
  if( rc==SQLITE_OK ){
    rc = pTok->tokapi.xCreate(pTokCtx, &azArg[1], nArg-1, &pTok->pTok);
  }

  if( rc!=SQLITE_OK ){
    sqlite3_free(pTok);
    pTok = 0;
  }
  *ppOut = (Fts5Tokenizer*)pTok;
  return rc;
}

static void f5tOrigintextDelete(Fts5Tokenizer *pTokenizer){
  OriginTextTokenizer *p = (OriginTextTokenizer*)pTokenizer;
  if( p->pTok ){
    p->tokapi.xDelete(p->pTok);
  }
  sqlite3_free(p);
}

typedef struct OriginTextCb OriginTextCb;
struct OriginTextCb {
  void *pCtx;
  const char *pText; 
  int nText;
  int (*xToken)(void *, int, const char *, int, int, int);

  char *aBuf;                     /* Buffer to use */
  int nBuf;                       /* Allocated size of aBuf[] */
};

static int xOriginToken(
  void *pCtx,                     /* Copy of 2nd argument to xTokenize() */
  int tflags,                     /* Mask of FTS5_TOKEN_* flags */
  const char *pToken,             /* Pointer to buffer containing token */
  int nToken,                     /* Size of token in bytes */
  int iStart,                     /* Byte offset of token within input text */
  int iEnd                        /* Byte offset of end of token within input */
){
  OriginTextCb *p = (OriginTextCb*)pCtx;
  int ret = 0;

  if( nToken==(iEnd-iStart) && 0==memcmp(pToken, &p->pText[iStart], nToken) ){
    /* Token exactly matches document text. Pass it through as is. */
    ret = p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd);
  }else{
    int nReq = nToken + 1 + (iEnd-iStart);
    if( nReq>p->nBuf ){
      sqlite3_free(p->aBuf);
      p->aBuf = sqlite3_malloc(nReq*2);
      if( p->aBuf==0 ) return SQLITE_NOMEM;
      p->nBuf = nReq*2;
    }

    memcpy(p->aBuf, pToken, nToken);
    p->aBuf[nToken] = '\0';
    memcpy(&p->aBuf[nToken+1], &p->pText[iStart], iEnd-iStart);
    ret = p->xToken(p->pCtx, tflags, p->aBuf, nReq, iStart, iEnd);
  }

  return ret;
}


static int f5tOrigintextTokenize(
  Fts5Tokenizer *pTokenizer, 
  void *pCtx,
  int flags,                      /* Mask of FTS5_TOKENIZE_* flags */
  const char *pText, int nText, 
  int (*xToken)(void *, int, const char *, int, int, int)
){
  OriginTextTokenizer *p = (OriginTextTokenizer*)pTokenizer;
  OriginTextCb cb;
  int ret;

  memset(&cb, 0, sizeof(cb));
  cb.pCtx = pCtx;
  cb.pText = pText;
  cb.nText = nText;
  cb.xToken = xToken;

  ret = p->tokapi.xTokenize(p->pTok,(void*)&cb,flags,pText,nText,xOriginToken);
  sqlite3_free(cb.aBuf);
  return ret;
}

/*
**      sqlite3_fts5_register_origintext DB
**
** Description...
*/
static int SQLITE_TCLAPI f5tRegisterOriginText(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db = 0;
  fts5_api *pApi = 0;
  int rc;
  fts5_tokenizer tok = {0, 0, 0};
  OriginTextCtx *pCtx = 0;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB");
    return TCL_ERROR;
  }
  if( f5tDbAndApi(interp, objv[1], &db, &pApi) ) return TCL_ERROR;

  pCtx = (OriginTextCtx*)ckalloc(sizeof(OriginTextCtx));
  pCtx->db = db;
  pCtx->pApi = pApi;

  tok.xCreate = f5tOrigintextCreate;
  tok.xDelete = f5tOrigintextDelete;
  tok.xTokenize = f5tOrigintextTokenize;
  rc = pApi->xCreateTokenizer(
      pApi, "origintext", (void*)pCtx, &tok, f5tOrigintextTokenizerDelete
  );

  Tcl_ResetResult(interp);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*
** Entry point.
*/
int Fts5tcl_Init(Tcl_Interp *interp){
  static struct Cmd {
    char *zName;
    Tcl_ObjCmdProc *xProc;
    int bTokenizeCtx;
  } aCmd[] = {
    { "sqlite3_fts5_create_tokenizer",   f5tCreateTokenizer, 1 },
    { "sqlite3_fts5_token",              f5tTokenizerReturn, 1 },
    { "sqlite3_fts5_tokenize",           f5tTokenize, 0 },
    { "sqlite3_fts5_create_function",    f5tCreateFunction, 0 },
    { "sqlite3_fts5_may_be_corrupt",     f5tMayBeCorrupt, 0 },
    { "sqlite3_fts5_token_hash",         f5tTokenHash, 0 },
    { "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 },
    { "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 }
    { "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 },
    { "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 }
  };
  int i;
  F5tTokenizerContext *pContext;

  pContext = (F5tTokenizerContext*)ckalloc(sizeof(F5tTokenizerContext));
  memset(pContext, 0, sizeof(*pContext));

Changes to ext/fts5/fts5_tokenize.c.
224
225
226
227
228
229
230






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







+
+
+
+
+
+







    *zOut++ = 0x80 + (unsigned char)((c>>12) & 0x3F);  \
    *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F);   \
    *zOut++ = 0x80 + (unsigned char)(c & 0x3F);        \
  }                                                    \
}

#endif /* ifndef SQLITE_AMALGAMATION */

#define FTS5_SKIP_UTF8(zIn) {                               \
  if( ((unsigned char)(*(zIn++)))>=0xc0 ){                              \
    while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; }             \
  }                                                    \
}

typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
  unsigned char aTokenChar[128];  /* ASCII range token characters */
  char *aFold;                    /* Buffer to fold text into */
  int nFold;                      /* Size of aFold[] in bytes */
  int eRemoveDiacritic;           /* True if remove_diacritics=1 is set */
1260
1261
1262
1263
1264
1265
1266

1267
1268
1269
1270
1271
1272
1273
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280







+








/**************************************************************************
** Start of trigram implementation.
*/
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
  int bFold;                      /* True to fold to lower-case */
  int iFoldParam;                 /* Parameter to pass to Fts5UnicodeFold() */
};

/*
** Free a trigram tokenizer.
*/
static void fts5TriDelete(Fts5Tokenizer *p){
  sqlite3_free(p);
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
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







+








+
+
+
+
+
+




+
+
+
+
+







  TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
  UNUSED_PARAM(pUnused);
  if( pNew==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int i;
    pNew->bFold = 1;
    pNew->iFoldParam = 0;
    for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
      const char *zArg = azArg[i+1];
      if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
        if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
          rc = SQLITE_ERROR;
        }else{
          pNew->bFold = (zArg[0]=='0');
        }
      }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
        if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
          rc = SQLITE_ERROR;
        }else{
          pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
        }
      }else{
        rc = SQLITE_ERROR;
      }
    }

    if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
      rc = SQLITE_ERROR;
    }

    if( rc!=SQLITE_OK ){
      fts5TriDelete((Fts5Tokenizer*)pNew);
      pNew = 0;
    }
  }
  *ppOut = (Fts5Tokenizer*)pNew;
  return rc;
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
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







+
+



+


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

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







  int unusedFlags,
  const char *pText, int nText,
  int (*xToken)(void*, int, const char*, int, int, int)
){
  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;
  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;
      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 */
    char *zOut = aBuf;
    int iStart = zIn - (const unsigned char*)pText;
    const char *z1;

    const unsigned char *zNext; 

    READ_UTF8(zIn, zEof, iCode);
    if( iCode==0 ) break;
    /* Read characters from the input up until the first non-diacritic */
    do {
      iNext = zIn - (const unsigned char*)pText;
      READ_UTF8(zIn, zEof, iCode);
      if( iCode==0 ) break;
    zNext = zIn;
    if( zIn<zEof ){
      if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
      WRITE_UTF8(zOut, iCode);
      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;
    }else{
      break;
    }
    if( zIn<zEof ){
      if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
      WRITE_UTF8(zOut, iCode);
      READ_UTF8(zIn, zEof, iCode);

    /* Remove the first character from buffer aBuf[]. Append the character
    ** with codepoint iCode.  */
    z1 = aBuf;
    FTS5_SKIP_UTF8(z1);
    memmove(aBuf, z1, zOut - z1);
      if( iCode==0 ) break;
      if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
      WRITE_UTF8(zOut, iCode);
    zOut -= (z1 - aBuf);
    WRITE_UTF8(zOut, iCode);
    }else{
      break;
    }
    rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);

    /* Update the aStart[] array */
    aStart[0] = aStart[1];
    if( rc!=SQLITE_OK ) break;
    zIn = zNext;
    aStart[1] = aStart[2];
    aStart[2] = iNext;
  }

  return rc;
}

/*
** Argument xCreate is a pointer to a constructor function for a tokenizer.
1376
1377
1378
1379
1380
1381
1382

1383


1384
1385
1386
1387
1388
1389
1390
1417
1418
1419
1420
1421
1422
1423
1424

1425
1426
1427
1428
1429
1430
1431
1432
1433







+
-
+
+







*/
int sqlite3Fts5TokenizerPattern(
    int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
    Fts5Tokenizer *pTok
){
  if( xCreate==fts5TriCreate ){
    TrigramTokenizer *p = (TrigramTokenizer*)pTok;
    if( p->iFoldParam==0 ){
    return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
      return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
    }
  }
  return FTS5_PATTERN_NONE;
}

/*
** Register all built-in tokenizers with FTS5.
*/
Changes to ext/fts5/fts5_vocab.c.
625
626
627
628
629
630
631
632

633
634
635
636
637
638
639
625
626
627
628
629
630
631

632
633
634
635
636
637
638
639







-
+







  if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
  if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
  if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];

  if( pEq ){
    zTerm = (const char *)sqlite3_value_text(pEq);
    nTerm = sqlite3_value_bytes(pEq);
    f = 0;
    f = FTS5INDEX_QUERY_NOTOKENDATA;
  }else{
    if( pGe ){
      zTerm = (const char *)sqlite3_value_text(pGe);
      nTerm = sqlite3_value_bytes(pGe);
    }
    if( pLe ){
      const char *zCopy = (const char *)sqlite3_value_text(pLe);
Changes to ext/fts5/test/fts5_common.tcl.
56
57
58
59
60
61
62






63
64
65
66
67
68
69
70




71
72
73
74
75
76
77
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







+
+
+
+
+
+








+
+
+
+








  for {set i 0} {$i < [$cmd xPhraseCount]} {incr i} {
    $cmd xPhraseColumnForeach $i c { lappend res $i.$c }
  }

  set res
}

proc fts5_collist {cmd iPhrase} {
  set res [list]
  $cmd xPhraseColumnForeach $iPhrase c { lappend res $c }
  set res
}

proc fts5_test_columnsize {cmd} {
  set res [list]
  for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
    lappend res [$cmd xColumnSize $i]
  }
  set res
}

proc fts5_columntext {cmd iCol} {
  $cmd xColumnText $iCol
}

proc fts5_test_columntext {cmd} {
  set res [list]
  for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
    lappend res [$cmd xColumnText $i]
  }
  set res
120
121
122
123
124
125
126







127
128
129
130
131
132
133
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150







+
+
+
+
+
+
+







    set cnt [list]
    for {set j 0} {$j < [$cmd xColumnCount]} {incr j} { lappend cnt 0 }
    $cmd xQueryPhrase $i [list test_queryphrase_cb cnt]
    lappend res $cnt
  }
  set res
}

proc fts5_queryphrase {cmd iPhrase} {
  set cnt [list]
  for {set j 0} {$j < [$cmd xColumnCount]} {incr j} { lappend cnt 0 }
  $cmd xQueryPhrase $iPhrase [list test_queryphrase_cb cnt]
  set cnt
}

proc fts5_test_phrasecount {cmd} {
  $cmd xPhraseCount
}

proc fts5_test_all {cmd} {
  set res [list]
150
151
152
153
154
155
156



157
158
159
160
161
162
163
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183







+
+
+







    fts5_test_collist
    fts5_test_tokenize
    fts5_test_rowcount
    fts5_test_all

    fts5_test_queryphrase
    fts5_test_phrasecount
    fts5_columntext
    fts5_queryphrase
    fts5_collist
  } {
    sqlite3_fts5_create_function $db $f $f
  }
}

proc fts5_segcount {tbl} {
  set N 0
434
435
436
437
438
439
440














441
442
443
444
445
446
447
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







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







    error "not in foreach_detail_mode {...} block"
  }
}
proc detail_is_none {} { detail_check ; expr {$::detail == "none"} }
proc detail_is_col {}  { detail_check ; expr {$::detail == "col" } }
proc detail_is_full {} { detail_check ; expr {$::detail == "full"} }

proc foreach_tokenizer_mode {prefix script} {
  set saved $::testprefix
  foreach {d mapping} {
    ""              {}
    "-origintext"   {, tokenize="origintext unicode61", tokendata=1}
  } {
    set s [string map [list %TOKENIZER% $mapping] $script]
    set ::testprefix "$prefix$d"
    reset_db
    sqlite3_fts5_register_origintext db
    uplevel $s
  }
  set ::testprefix $saved
}

#-------------------------------------------------------------------------
# Convert a poslist of the type returned by fts5_test_poslist() to a 
# collist as returned by fts5_test_collist().
#
proc fts5_poslist2collist {poslist} {
  set res [list]
Changes to ext/fts5/test/fts5aa.test.
18
19
20
21
22
23
24

25
26
27
28
29
30
31
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32







+







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

foreach_detail_mode $::testprefix {
foreach_tokenizer_mode $::testprefix {

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
  SELECT name, sql FROM sqlite_master;
} {
  t1 {CREATE VIRTUAL TABLE t1 USING fts5(a, b, c)}
  t1_data {CREATE TABLE 't1_data'(id INTEGER PRIMARY KEY, block BLOB)}
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55







-
+







  SELECT name, sql FROM sqlite_master;
} {}

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

do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
}
do_execsql_test 2.1 {
  INSERT INTO t1 VALUES('a b c', 'd e f');
}

do_test 2.2 {
  execsql { SELECT fts5_decode(id, block) FROM t1_data WHERE id==10 }
69
70
71
72
73
74
75

76
77

78
79
80
81
82
83
84
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86







+

-
+







  PRAGMA integrity_check(t1);
} {ok ok}


#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
}
foreach {i x y} {
   1  {g f d b f} {h h e i a}
   2  {f i g j e} {i j c f f}
   3  {e e i f a} {e h f d f}
   4  {h j f j i} {h a c f j}
   5  {d b j c g} {f e i b e}
93
94
95
96
97
98
99

100
101

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

104
105
106
107
108
109
110
111







+

-
+







  do_execsql_test 3.$i.3 { PRAGMA integrity_check(t1) } ok
  if {[set_test_counter errors]} break
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 4.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
foreach {i x y} {
   1  {g f d b f} {h h e i a}
   2  {f i g j e} {i j c f f}
   3  {e e i f a} {e h f d f}
   4  {h j f j i} {h a c f j}
117
118
119
120
121
122
123

124
125

126
127
128
129
130
131
132
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136







+

-
+







  do_execsql_test 4.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
  if {[set_test_counter errors]} break
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 5.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
foreach {i x y} {
   1  {dd abc abc abc abcde} {aaa dd ddd ddd aab}
   2  {dd aab d aaa b} {abcde c aaa aaa aaa}
   3  {abcde dd b b dd} {abc abc d abc ddddd}
   4  {aaa abcde dddd dddd abcde} {abc b b abcde abc}
141
142
143
144
145
146
147

148
149

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

154
155
156
157
158
159
160
161







+

-
+







  do_execsql_test 5.$i.2 { PRAGMA integrity_check(t1) } ok
  if {[set_test_counter errors]} break
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 6.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}

do_execsql_test 6.1 {
  INSERT  INTO t1(rowid, x, y) VALUES(22, 'a b c', 'c b a');
  REPLACE INTO t1(rowid, x, y) VALUES(22, 'd e f', 'f e d');
}
177
178
179
180
181
182
183

184
185
186
187
188
189
190
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196







+







  22 {l l l} {l l l}
  23 {x y z} {x y z}
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
expr srand(0)
do_execsql_test 7.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y,z);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}

proc doc {} {
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
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







+














+







  } {}
  if {[set_test_counter errors]} break
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 8.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x, prefix="1,2,3");
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}

do_execsql_test 8.1 {
  INSERT INTO t1 VALUES('the quick brown fox');
  INSERT INTO t1(t1) VALUES('integrity-check');
}


#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db

expr srand(0)

do_execsql_test 9.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y,z, prefix="1,2,3");
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
276
277
278
279
280
281
282

283
284

285
286
287
288
289
290
291
284
285
286
287
288
289
290
291
292

293
294
295
296
297
298
299
300







+

-
+







  if {[set_test_counter errors]} break
}


#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 10.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
}
set d10 {
   1  {g f d b f} {h h e i a}
   2  {f i g j e} {i j c f f}
   3  {e e i f a} {e h f d f}
   4  {h j f j i} {h a c f j}
   5  {d b j c g} {f e i b e}
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
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







-
+


-
+


-
+





-
+














+

-
+








do_execsql_test 10.4.1 { DELETE FROM t1 }
do_execsql_test 10.4.2 { INSERT INTO t1(t1) VALUES('integrity-check') }

#-------------------------------------------------------------------------
#
do_catchsql_test 11.1 {
  CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL% %TOKENIZER%);
} {1 {reserved fts5 column name: rank}}
do_catchsql_test 11.2 {
  CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL%);
  CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL% %TOKENIZER%);
} {1 {reserved fts5 table name: rank}}
do_catchsql_test 11.3 {
  CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL% %TOKENIZER%);
} {1 {reserved fts5 column name: rowid}}

#-------------------------------------------------------------------------
#
do_execsql_test 12.1 {
  CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
} {}

do_catchsql_test 12.2 {
  SELECT t2 FROM t2 WHERE t2 MATCH '*stuff'
} {1 {unknown special query: stuff}}

do_test 12.3 {
  set res [db eval { SELECT t2 FROM t2 WHERE t2 MATCH '* reads ' }]
  string is integer $res
} {1}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 13.1 {
  CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1(rowid, x) VALUES(1, 'o n e'), (2, 't w o');
} {}

do_execsql_test 13.2 {
  SELECT rowid FROM t1 WHERE t1 MATCH 'o';
} {1 2}

361
362
363
364
365
366
367

368
369

370
371
372
373
374
375
376
371
372
373
374
375
376
377
378
379

380
381
382
383
384
385
386
387







+

-
+







do_execsql_test 13.6 {
  SELECT rowid FROM t1 WHERE t1 MATCH '""';
} {}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 14.1 {
  CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  WITH d(x,y) AS (
    SELECT NULL, 'xyz xyz xyz xyz xyz xyz'
    UNION ALL 
    SELECT NULL, 'xyz xyz xyz xyz xyz xyz' FROM d
  )
  INSERT INTO t1 SELECT * FROM d LIMIT 200;
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
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







+

-
+















+

-
+








+

-
+







  SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}}
# {1 {SQL logic error}}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 17.1 {
  CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO b2 VALUES('a');
  INSERT INTO b2 VALUES('b');
  INSERT INTO b2 VALUES('c');
}

do_test 17.2 {
  set res [list]
  db eval { SELECT * FROM b2 ORDER BY rowid ASC } {
    lappend res [execsql { SELECT * FROM b2 ORDER BY rowid ASC }]
  }
  set res
} {{a b c} {a b c} {a b c}}

if {[string match n* %DETAIL%]==0} {
  reset_db
  sqlite3_fts5_register_origintext db
  do_execsql_test 17.3 {
    CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL%);
    CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
    INSERT INTO c2 VALUES('x x x', 'x x x');
    SELECT rowid FROM c2 WHERE c2 MATCH 'y:x';
  } {1}
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 17.1 {
  CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL%);
  CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO uio VALUES(NULL);
  INSERT INTO uio SELECT NULL FROM uio;
  INSERT INTO uio SELECT NULL FROM uio;
  INSERT INTO uio SELECT NULL FROM uio;
  INSERT INTO uio SELECT NULL FROM uio;
  INSERT INTO uio SELECT NULL FROM uio;
  INSERT INTO uio SELECT NULL FROM uio;
520
521
522
523
524
525
526
527
528


529
530
531
532
533
534
535
536
537
538
539
540
541
542

543
544

545
546
547
548
549
550
551
552
553

554
555

556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573

574
575
576
577
578
579
580
581
582
583
584

585
586
587
588
589
590
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
534
535
536
537
538
539
540


541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558

559
560
561
562
563
564
565
566
567
568
569
570

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

589
590
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
661
662
663
664







-
-
+
+














+

-
+









+

-
+

















-
+










-
+














-
+











-
+









+
+
+









-
+










+




do_execsql_test 17.9 {
  SELECT min(rowid), max(rowid), count(*) FROM uio WHERE rowid < 10;
} {-9223372036854775808 9 10}

#--------------------------------------------------------------------
#
do_execsql_test 18.1 {
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL% %TOKENIZER%);
  CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1 VALUES('abc*', NULL);
  INSERT INTO t2 VALUES(1, 'abcdefg');
}
do_execsql_test 18.2 {
  SELECT t1.rowid, t2.rowid FROM t1, t2 WHERE t2 MATCH t1.a AND t1.rowid = t2.c
} {1 1}
do_execsql_test 18.3 {
  SELECT t1.rowid, t2.rowid FROM t2, t1 WHERE t2 MATCH t1.a AND t1.rowid = t2.c
} {1 1}

#--------------------------------------------------------------------
# fts5 table in the temp schema.
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 19.0 {
  CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t1 VALUES('x y z');
  INSERT INTO t1 VALUES('w x 1');
  SELECT rowid FROM t1 WHERE t1 MATCH 'x';
} {1 2}

#--------------------------------------------------------------------
# Test that 6 and 7 byte varints can be read.
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 20.0 {
  CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL% %TOKENIZER%);
}
set ::ids [list \
  0 [expr 1<<36] [expr 2<<36] [expr 1<<43] [expr 2<<43]
]
do_test 20.1 {
  foreach id $::ids {
    execsql { INSERT INTO tmp(rowid, x) VALUES($id, 'x y z') }
  }
  execsql { SELECT rowid FROM tmp WHERE tmp MATCH 'y' }
} $::ids

#--------------------------------------------------------------------
# Test that a DROP TABLE may be executed within a transaction that
# writes to an FTS5 table.
#
do_execsql_test 21.0 {
  CREATE TEMP TABLE t8(a, b);
  CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL% %TOKENIZER%);
}

do_execsql_test 21.1 {
  BEGIN;
    INSERT INTO ft VALUES('a b c');
    DROP TABLE t8;
  COMMIT;
}

do_execsql_test 22.0 {
  CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t9(rowid, x) VALUES(2, 'bbb');
  BEGIN;
    INSERT INTO t9(rowid, x) VALUES(1, 'aaa');
    DELETE FROM t9 WHERE rowid = 2;
    INSERT INTO t9(rowid, x) VALUES(3, 'bbb');
  COMMIT;
}

do_execsql_test 22.1 {
  SELECT rowid FROM t9('a*')
} {1}

#-------------------------------------------------------------------------
do_execsql_test 23.0 {
  CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
  CREATE TABLE t11(x);
}
do_execsql_test 23.1 {
  SELECT * FROM t11, t10 WHERE t11.x = t10.x AND t10.rowid IS NULL;
}
do_execsql_test 23.2 {
  SELECT * FROM t11, t10 WHERE t10.rowid IS NULL;
}

#-------------------------------------------------------------------------
do_execsql_test 24.0 {
  CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
  INSERT INTO t12 VALUES('aaaa');
}
do_execsql_test 24.1 {
  BEGIN;
    DELETE FROM t12 WHERE rowid=1;
    SELECT * FROM t12('aaaa');
    INSERT INTO t12 VALUES('aaaa');
  END;
}
execsql_pp {
  SELECT rowid, hex(block) FROM t12_data
}
do_execsql_test 24.2 {
  INSERT INTO t12(t12) VALUES('integrity-check');
}
do_execsql_test 24.3 {
    SELECT * FROM t12('aaaa');
} {aaaa}

#-------------------------------------------------------------------------
do_execsql_test 25.0 {
  CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL%);
  CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
}
do_execsql_test 25.1 {
  BEGIN;
  INSERT INTO t13 VALUES('AAAA');
SELECT * FROM t13('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB*');

  END;
}


}
}

expand_all_sql db
finish_test
Changes to ext/fts5/test/fts5aux.test.
329
330
331
332
333
334
335











































336
337
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







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


  INSERT INTO x1 VALUES('one two one three one');
  INSERT INTO x1 VALUES('one two three');
}

do_execsql_test 11.2 {
  SELECT fts5_hitcount(x1) FROM x1('one') LIMIT 1;
} {5}

#-------------------------------------------------------------------------
# Test that xColumnText returns SQLITE_RANGE when it should.
#
reset_db
fts5_aux_test_functions db
do_execsql_test 12.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
  INSERT INTO t1 VALUES('one', 'two', 'three');
  INSERT INTO t1 VALUES('one', 'one', 'one');
  INSERT INTO t1 VALUES('two', 'two', 'two');
  INSERT INTO t1 VALUES('three', 'three', 'three');
}

do_catchsql_test 12.1.1 {
  SELECT fts5_columntext(t1, -1) FROM t1('two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.1.2 {
  SELECT fts5_columntext(t1, 3) FROM t1('two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.1.2 {
  SELECT fts5_columntext(t1, 1) FROM t1('one AND two');
} {0 two}

do_catchsql_test 12.2.1 {
  SELECT fts5_queryphrase(t1, -1) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.2.2 {
  SELECT fts5_queryphrase(t1, 2) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.2.3 {
  SELECT fts5_queryphrase(t1, 1) FROM t1('one AND two');
} {0 {{1 2 1}}}

do_catchsql_test 12.3.1 {
  SELECT fts5_collist(t1, -1) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.3.2 {
  SELECT fts5_collist(t1, 2) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.3.3 {
  SELECT fts5_collist(t1, 1) FROM t1('one AND two');
} {0 1}

finish_test
Changes to ext/fts5/test/fts5content.test.
288
289
290
291
292
293
294



































295
296
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







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


} {1 {recursively defined fts5 content table}}
do_catchsql_test 7.2.4 { 
  SELECT count(*) FROM t1;
} {1 {recursively defined fts5 content table}}
do_catchsql_test 7.2.5 { 
  SELECT * FROM t1('abc') ORDER BY rank;
} {1 {recursively defined fts5 content table}}

#---------------------------------------------------------------------------
# Check that if the content table is a view, and that view contains an
# error, a reasonable error message is returned if the user tries to
# read from the view via the fts5 table.
#
reset_db
do_execsql_test 8.1 {
  CREATE VIEW a1 AS 
    SELECT 1 AS r, text_value(1) AS t
      UNION ALL
    SELECT 2 AS r, text_value(2) AS t;

  CREATE VIRTUAL TABLE t1 USING fts5(t, content='a1', content_rowid='r');
}

foreach {tn sql} {
  1 "SELECT * FROM t1"
  2 "INSERT INTO t1(t1) VALUES('rebuild')"
  3 "SELECT * FROM t1 WHERE rowid=1"
} {
  do_catchsql_test 8.2.$tn $sql {1 {no such function: text_value}}
}

proc text_value {i} {
  if {$i==1} { return "one" }
  if {$i==2} { return "two" }
  return "many"
}
db func text_value text_value

do_execsql_test 8.3.1 { SELECT * FROM t1 } {one two}
do_execsql_test 8.3.2 { INSERT INTO t1(t1) VALUES('rebuild') }
do_execsql_test 8.3.3 { SELECT * FROM t1 WHERE rowid=1 } {one}
do_execsql_test 8.3.4 { SELECT rowid FROM t1('two') } {2}

finish_test
Changes to ext/fts5/test/fts5corrupt5.test.
876
877
878
879
880
881
882


























































































































































































































































































































































































































































































































































































883
884
885
886
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
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







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




do_execsql_test 5.1 {
  INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
}
do_catchsql_test 5.4 {
  UPDATE t1 SET content=randomblob(500);
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
reset_db
do_test 6.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
.open --hexdb
| size 32768 pagesize 4096 filename crash-42fa37b694d45a.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07   .....@  ........
|     96: 00 00 00 00 0d 00 00 00 07 0d d2 00 0f c4 0f 6d   ...............m
|    112: 0f 02 0e ab 0e 4e 0d f6 0d d2 00 00 00 00 00 00   .....N..........
|   3536: 00 00 22 07 06 17 11 11 01 31 74 61 62 6c 65 74   .........1tablet
|   3552: 32 74 32 07 43 52 45 41 54 45 20 54 41 42 4c 45   2t2.CREATE TABLE
|   3568: 20 74 32 28 78 29 56 06 06 17 1f 1f 01 7d 74 61    t2(x)V.......ta
|   3584: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63   blet1_configt1_c
|   3600: 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 41 42   onfig.CREATE TAB
|   3616: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b   LE 't1_config'(k
|   3632: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29    PRIMARY KEY, v)
|   3648: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 05    WITHOUT ROWID[.
|   3664: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64   ..!!...tablet1_d
|   3680: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65   ocsizet1_docsize
|   3696: 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74   .CREATE TABLE 't
|   3712: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e   1_docsize'(id IN
|   3728: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45   TEGER PRIMARY KE
|   3744: 59 2c 20 73 7a 20 42 4c 4f 42 29 55 04 06 17 21   Y, sz BLOB)U...!
|   3760: 21 01 77 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65   !.wtablet1_conte
|   3776: 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 04 43 52 45   ntt1_content.CRE
|   3792: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f   ATE TABLE 't1_co
|   3808: 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 45   ntent'(id INTEGE
|   3824: 52 20 50 52 49 4d 41 52 49 20 4b 45 59 2c 20 63   R PRIMARI KEY, c
|   3840: 30 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65   0)i.......-table
|   3856: 74 31 5f 69 64 78 74 31 5f 69 64 78 03 43 52 45   t1_idxt1_idx.CRE
|   3872: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64   ATE TABLE 't1_id
|   3888: 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20   x'(segid, term, 
|   3904: 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45   pgno, PRIMARY KE
|   3920: 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20   Y(segid, term)) 
|   3936: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07   WITHOUT ROWIDU..
|   3952: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61   ......tablet1_da
|   3968: 74 61 74 31 5f 64 61 74 61 02 43 52 45 41 54 45   tat1_data.CREATE
|   3984: 20 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27    TABLE 't1_data'
|   4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d   (id INTEGER PRIM
|   4016: 41 52 b9 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42   AR. KEY, block B
|   4032: 4c 4f 42 29 3a 01 06 17 11 11 08 63 74 61 62 6c   LOB):......ctabl
|   4048: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54   et1t1CREATE VIRT
|   4064: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49   UAL TABLE t1 USI
|   4080: 4e 47 20 66 74 73 35 28 63 6f 6e 74 65 6e 74 29   NG fts5(content)
| page 2 offset 4096
|      0: 0d 00 00 00 03 0f bd 00 0f e8 0f ef 0f bd f0 00   ................
|     16: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
|   4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 24 84 80   .............$..
|   4032: 80 80 80 01 03 00 4e 00 10 00 1e 06 30 61 62 61   ......N.....0aba
|   4048: 63 6c 01 02 02 04 02 66 74 02 5f 02 04 04 6e 64   cl.....ft._...nd
|   4064: 6f 6e 02 02 02 04 0a 07 05 01 03 00 10 03 03 0f   on..............
|   4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 11   ...$............
| page 3 offset 8192
|      0: 0a 00 00 00 01 0f 00 01 00 00 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02   ................
| page 4 offset 12288
|      0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00   ................
|   4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00   .....abandon....
|   4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b   .abaft.....aback
| page 5 offset 16384
|      0: 0d 00 00 00 03 0f ee 00 0f fa 0f 00 00 00 00 00   ................
|   4064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 03   ................
|   4080: 03 00 0e 01 04 02 03 00 0e 01 04 01 03 00 0e 01   ................
| page 6 offset 20480
|      0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04   ........version.
| page 7 offset 24576
|      0: 0d 00 00 10 03 0f d6 00 0f 00 00 00 00 00 00 00   ................
|   4048: 00 00 00 00 00 00 09 03 02 1b 72 65 62 75 69 6c   ..........rebuil
|   4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63   d...+integrity-c
|   4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 00 00 00   heck....optim...
| page 8 offset 28672
|      0: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
| end crash-42fa37b694d45a.db
}]} {}

do_execsql_test 6.1 {
  INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
}
do_catchsql_test 6.2 {
  UPDATE t1 SET content=randomblob(500) WHERE t1;
} {1 {constraint failed}}

#-------------------------------------------------------------------------
reset_db
do_test 7.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
.open --hexdb
| size 40960 pagesize 4096 filename crash-d8b4a99207c10b.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 0a   .....@  ........
|     32: 00 00 00 00 00 00 00 00 00 00 00 0d 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 0d 0b 62 00 0f 97 0f 40   ..........b....@
|    112: 0e d5 0e 75 0e 18 0d c0 0d 66 0d 0f 0c a4 0c 44   ...u.....f.....D
|    128: 0b ec 0b a7 0b 62 00 00 00 00 00 00 00 00 00 00   .....b..........
|   2912: 00 00 43 0d 06 17 11 11 08 75 74 61 62 6c 65 74   ..C......utablet
|   2928: 34 74 34 43 52 45 41 54 45 20 56 49 52 54 55 41   4t4CREATE VIRTUA
|   2944: 4c 20 54 41 42 4c 45 20 74 34 20 55 53 49 4e 47   L TABLE t4 USING
|   2960: 20 66 74 73 35 76 6f 63 61 62 28 27 74 32 27 2c    fts5vocab('t2',
|   2976: 20 27 72 6f 77 27 29 43 0c 06 17 11 11 08 75 74    'row')C......ut
|   2992: 61 62 6c 65 74 33 74 33 43 52 45 41 54 45 20 56   ablet3t3CREATE V
|   3008: 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 33 20   IRTUAL TABLE t3 
|   3024: 55 53 49 4e 47 20 66 74 73 35 76 6f 63 61 62 28   USING fts5vocab(
|   3040: 27 74 31 27 2c 20 27 72 6f 77 27 29 56 0b 06 17   't1', 'row')V...
|   3056: 1f 1f 01 7d 74 61 62 6c 65 74 32 5f 63 6f 6e 66   ....tablet2_conf
|   3072: 69 67 74 32 5f 63 6f 6e 66 69 67 0a 43 52 45 41   igt2_config.CREA
|   3088: 54 45 20 54 41 42 4c 45 20 27 74 32 5f 63 6f 6e   TE TABLE 't2_con
|   3104: 66 69 67 27 28 6b 20 50 52 49 4d 41 52 59 20 4b   fig'(k PRIMARY K
|   3120: 45 59 2c 20 76 29 20 57 49 54 48 4f 55 54 20 52   EY, v) WITHOUT R
|   3136: 4f 57 49 44 5e 0a 07 17 21 21 01 81 07 74 61 62   OWID^...!!...tab
|   3152: 6c 65 74 32 5f 63 6f 6e 74 65 6e 74 74 32 5f 63   let2_contentt2_c
|   3168: 6f 6e 74 65 6e 74 09 43 52 45 41 54 45 20 54 41   ontent.CREATE TA
|   3184: 42 4c 45 20 27 74 32 5f 63 6f 6e 74 65 6e 74 27   BLE 't2_content'
|   3200: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d   (id INTEGER PRIM
|   3216: 41 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31 2c   ARY KEY, c0, c1,
|   3232: 20 63 32 29 69 09 07 17 19 19 01 81 2d 74 61 62    c2)i.......-tab
|   3248: 6c 65 74 32 5f 69 64 78 74 32 5f 69 64 78 08 43   let2_idxt2_idx.C
|   3264: 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 32 5f   REATE TABLE 't2_
|   3280: 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d   idx'(segid, term
|   3296: 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20   , pgno, PRIMARY 
|   3312: 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29   KEY(segid, term)
|   3328: 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55   ) WITHOUT ROWIDU
|   3344: 08 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 32 5f   ........tablet2_
|   3360: 64 61 74 61 74 32 5f 64 61 74 61 07 43 52 45 41   datat2_data.CREA
|   3376: 54 45 20 54 41 42 4c 45 20 27 74 32 5f 64 61 74   TE TABLE 't2_dat
|   3392: 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52   a'(id INTEGER PR
|   3408: 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b   IMARY KEY, block
|   3424: 20 42 4c 4f 42 29 58 07 07 17 11 11 08 81 1d 74    BLOB)X........t
|   3440: 61 62 6c 65 74 32 74 32 43 52 45 41 54 45 20 56   ablet2t2CREATE V
|   3456: 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 32 20   IRTUAL TABLE t2 
|   3472: 55 53 49 4e 47 20 66 74 73 35 28 27 61 27 2c 5b   USING fts5('a',[
|   3488: 62 5d 2c 22 63 22 2c 64 65 74 61 69 6c 3d 6e 6f   b],.c.,detail=no
|   3504: 6e 65 2c 63 6f 6c 75 6d 6e 73 69 7a 65 3d 30 29   ne,columnsize=0)
|   3520: 56 06 06 17 1f 1f 01 7d 74 61 62 6c 65 74 31 5f   V.......tablet1_
|   3536: 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 69 67 06   configt1_config.
|   3552: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31   CREATE TABLE 't1
|   3568: 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 49 4d 41   _config'(k PRIMA
|   3584: 52 59 20 4b 45 59 2c 20 76 29 20 57 49 54 48 4f   RY KEY, v) WITHO
|   3600: 55 54 20 52 4f 57 49 44 5b 05 07 17 21 21 01 81   UT ROWID[...!!..
|   3616: 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 69 7a 65   .tablet1_docsize
|   3632: 74 31 5f 64 6f 63 73 69 7a 65 05 43 52 45 41 54   t1_docsize.CREAT
|   3648: 45 20 54 41 42 4c 45 20 27 74 31 5f 64 6f 63 73   E TABLE 't1_docs
|   3664: 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 52 20   ize'(id INTEGER 
|   3680: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20   PRIMARY KEY, sz 
|   3696: 42 4c 4f 42 29 5e 04 07 17 21 21 01 81 07 74 61   BLOB)^...!!...ta
|   3712: 62 6c 65 74 31 5f 63 6f 6e 74 65 6e 74 74 31 5f   blet1_contentt1_
|   3728: 63 6f 6e 74 65 6e 74 04 43 52 45 41 54 45 20 54   content.CREATE T
|   3744: 41 42 4c 45 20 27 74 31 5f 63 6f 6e 74 65 6e 74   ABLE 't1_content
|   3760: 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49   '(id INTEGER PRI
|   3776: 4d 41 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31   MARY KEY, c0, c1
|   3792: 2c 20 63 32 29 69 03 07 17 19 19 01 81 2d 74 61   , c2)i.......-ta
|   3808: 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 64 78 03   blet1_idxt1_idx.
|   3824: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31   CREATE TABLE 't1
|   3840: 5f 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72   _idx'(segid, ter
|   3856: 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59   m, pgno, PRIMARY
|   3872: 20 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d    KEY(segid, term
|   3888: 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44   )) WITHOUT ROWID
|   3904: 55 02 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 31   U........tablet1
|   3920: 5f 64 61 74 61 74 31 5f 64 61 74 61 02 43 52 45   _datat1_data.CRE
|   3936: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 61   ATE TABLE 't1_da
|   3952: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50   ta'(id INTEGER P
|   3968: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63   RIMARY KEY, bloc
|   3984: 6b 20 42 4c 4f 42 29 67 01 07 17 11 11 08 81 3b   k BLOB)g.......;
|   4000: 74 61 62 6c 65 74 31 74 31 43 52 45 41 54 45 20   tablet1t1CREATE 
|   4016: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31   VIRTUAL TABLE t1
|   4032: 20 55 53 49 4e 47 20 66 74 73 35 28 61 2c 62 20    USING fts5(a,b 
|   4048: 75 6e 69 6e 64 65 78 65 64 2c 63 2c 74 6f 6b 65   unindexed,c,toke
|   4064: 6e 69 7a 65 3d 22 70 6f 72 74 65 72 20 61 73 63   nize=.porter asc
|   4080: 69 69 22 2c 74 6f 6b 65 6e 64 61 74 61 3d 31 29   ii.,tokendata=1)
| page 2 offset 4096
|      0: 0d 0f 68 00 05 0f 13 00 0f e6 0f 13 0f a8 0f 7c   ..h............|
|     16: 0f 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00   .*..............
|   3856: 00 00 00 15 0a 03 00 30 00 00 00 00 01 03 03 00   .......0........
|   3872: 03 01 01 01 02 01 01 03 01 01 37 8c 80 80 80 80   ..........7.....
|   3888: 01 03 00 74 00 00 00 2e 02 30 61 03 02 02 01 01   ...t.....0a.....
|   3904: 62 03 02 03 01 01 63 03 02 04 01 01 67 03 06 01   b.....c.....g...
|   3920: 02 02 01 01 68 03 06 01 02 03 01 01 69 03 06 01   ....h.......i...
|   3936: 02 04 04 06 06 06 08 08 0f ef 00 14 2a 00 00 00   ............*...
|   3952: 00 01 02 02 00 02 01 01 01 02 01 01 25 88 80 80   ............%...
|   3968: 80 80 01 03 00 50 00 00 00 1f 02 30 67 02 08 02   .....P.....0g...
|   3984: 01 02 02 01 01 68 02 08 03 01 02 03 01 01 69 02   .....h........i.
|   4000: 08 04 01 02 04 04 09 09 37 84 80 80 80 7f f1 03   ........7.......
|   4016: 00 74 00 00 00 2e 02 30 61 01 02 02 01 01 62 01   .t.....0a.....b.
|   4032: 02 03 01 01 63 01 02 04 01 01 67 01 06 01 02 02   ....c.....g.....
|   4048: 01 01 68 01 06 01 02 03 01 01 69 01 06 01 02 04   ..h.......i.....
|   4064: 04 06 06 06 08 08 07 01 03 00 14 03 09 00 09 00   ................
|   4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01   ...$............
| page 3 offset 8192
|      0: 0a 00 00 00 03 0f ec 00 0f fa 0f f3 0f ec 00 00   ................
|   4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c   ................
|   4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02   ................
| page 4 offset 12288
|      0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00   ................
|   4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03   ................
|   4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67   .....a b cg h ig
|   4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69    h i.......g h i
|   4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17   a b cg h i......
|   4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69   .a b cd e fg h i
| page 5 offset 16384
|      0: 0d 00 00 00 03 0f e8 00 0f f8 0f f0 0f e8 00 00   ................
|   4064: 00 00 00 00 00 00 00 00 06 03 03 00 12 03 00 03   ................
|   4080: 06 02 03 00 12 03 00 03 06 01 03 00 12 03 00 03   ................
| page 6 offset 20480
|      0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04   ........version.
| page 7 offset 24576
|      0: 0d 00 00 00 03 0f 9e 00 0f e6 0f ef 0f 9e 00 00   ................
|   3984: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 84   ..............A.
|   4000: 80 80 80 80 01 04 00 81 06 00 00 00 34 02 30 61   ............4.0a
|   4016: 01 01 01 01 01 62 01 01 01 01 01 63 01 01 01 01   .....b.....c....
|   4032: 01 64 01 01 01 65 01 01 01 66 01 01 01 67 01 01   .d...e...f...g..
|   4048: 01 01 01 68 01 01 01 01 01 69 01 01 01 04 06 06   ...h.....i......
|   4064: 06 04 04 04 06 06 07 01 03 00 14 03 09 09 09 0f   ................
|   4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01   ...$............
| page 8 offset 28672
|      0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02   ................
| page 9 offset 32768
|      0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00   ................
|   4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03   ................
|   4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67   .....a b cg h ig
|   4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69    h i.......g h i
|   4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17   a b cg h i......
|   4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69   .a b cd e fg h i
| page 10 offset 36864
|      0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04   ........version.
| end crash-d8b4a99207c10b.db
}]} {}

do_catchsql_test 7.1 {
  SELECT snippet(t1, -1, '.', '..', '[', ']'), 
         highlight(t1, 2, '[', ']') 
           FROM t1('g + h') 
           WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank;
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
reset_db
do_test 8.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
.open --hexdb
| size 20480 pagesize 4096 filename crash-d57c01958e48ab.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05   .....@  ........
|     32: 00 00 00 00 00 00 00 00 00 00 00 05 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 05 0e 10 00 0f 97 0f 40   ...............@
|    112: 0e d5 0e 68 0e 10 01 00 00 00 00 00 00 00 00 00   ...h............
|   3600: 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 74 31 5f   V.......tablet1_
|   3616: 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 69 67 05   configt1_config.
|   3632: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31   CREATE TABLE 't1
|   3648: 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 49 4d 41   _config'(k PRIMA
|   3664: 52 59 20 4b 45 59 2c 20 76 29 20 57 49 54 48 4f   RY KEY, v) WITHO
|   3680: 55 54 20 52 4f 57 49 44 6b 04 07 17 21 21 01 81   UT ROWIDk...!!..
|   3696: 21 74 61 62 6c 65 74 31 5f 64 6f 63 73 69 7a 65   !tablet1_docsize
|   3712: 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 45 41 54   t1_docsize.CREAT
|   3728: 45 20 54 41 42 4c 45 20 27 74 31 5f 64 6f 63 73   E TABLE 't1_docs
|   3744: 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 52 20   ize'(id INTEGER 
|   3760: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20   PRIMARY KEY, sz 
|   3776: 42 4c 4f 42 2c 20 6f 72 69 67 69 6e 20 49 4e 54   BLOB, origin INT
|   3792: 45 47 45 52 29 69 03 07 17 19 19 01 81 2d 74 61   EGER)i.......-ta
|   3808: 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 64 78 03   blet1_idxt1_idx.
|   3824: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31   CREATE TABLE 't1
|   3840: 5f 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72   _idx'(segid, ter
|   3856: 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59   m, pgno, PRIMARY
|   3872: 20 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d    KEY(segid, term
|   3888: 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44   )) WITHOUT ROWID
|   3904: 55 02 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 31   U........tablet1
|   3920: 5f 64 61 74 61 74 31 5f 64 61 74 61 02 43 52 45   _datat1_data.CRE
|   3936: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 61   ATE TABLE 't1_da
|   3952: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50   ta'(id INTEGER P
|   3968: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63   RIMARY KEY, bloc
|   3984: 6b 20 42 4c 4f 42 29 67 01 07 17 11 11 08 81 3b   k BLOB)g.......;
|   4000: 74 61 62 6c 65 74 31 74 31 43 52 45 41 54 45 20   tablet1t1CREATE 
|   4016: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31   VIRTUAL TABLE t1
|   4032: 20 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62    USING fts5(a, b
|   4048: 2c 20 63 6f 6e 74 65 6e 74 3d 27 27 2c 20 63 6f   , content='', co
|   4064: 6e 74 65 6e 74 6c 65 73 73 5f 64 65 6c 65 74 65   ntentless_delete
|   4080: 3d 31 2c 20 74 6f 6b 65 6e 64 61 74 61 3d 31 29   =1, tokendata=1)
| page 2 offset 4096
|      0: 0d 0f eb 00 03 0e 17 00 0f e2 0e 17 0e 31 00 00   .............1..
|     16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
|   3600: 00 00 00 00 00 00 00 18 0a 03 00 36 00 00 00 00   ...........6....
|   3616: ff 00 00 01 01 01 01 00 01 01 01 01 01 01 00 00   ................
|   3632: 07 83 29 84 80 80 80 80 01 04 00 86 56 00 00 01   ..).........V...
|   3648: 96 04 30 61 61 61 01 02 02 01 04 02 04 01 08 02   ..0aaa..........
|   3664: 04 04 04 01 10 02 04 04 04 04 04 04 04 01 20 02   .............. .
|   3680: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 01   ................
|   3696: 40 02 04 04 04 04 04 04 04 04 04 04 04 04 04 04   @...............
|   3712: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04   ................
|   3728: 04 01 81 00 02 04 04 04 04 04 04 04 04 04 04 04   ................
|   3744: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04   ................
|   3760: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04   ................
|   3776: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04   ................
|   3792: 04 04 04 04 02 02 62 63 01 06 01 01 02 01 03 62   ......bc.......b
|   3808: 62 62 02 02 03 01 04 03 06 01 08 03 06 06 06 01   bb..............
|   3824: 10 03 06 06 06 06 06 06 06 01 20 03 06 06 06 06   .......... .....
|   3840: 06 06 06 06 06 06 06 06 06 06 06 01 40 03 06 06   ............@...
|   3856: 06 06 06 06 06 06 06 06 06 06 06 06 06 06 06 06   ................
|   3872: 06 06 06 06 06 06 06 06 06 06 16 06 06 02 02 63   ...............c
|   3888: 64 02 06 01 01 02 01 03 63 63 63 03 02 05 01 04   d.......ccc.....
|   3904: 05 0a 01 08 05 0a 0a 0a 01 10 05 0a 0a 0a 0a 0a   ................
|   3920: 0a 0a 01 20 05 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a   ... ............
|   3936: 0a 0a 0a 0a 02 02 64 65 03 06 01 01 02 01 03 64   ......de.......d
|   3952: 64 64 04 02 09 01 04 09 12 01 08 09 12 12 12 01   dd..............
|   3968: 10 09 12 12 12 12 12 12 12 02 02 65 66 04 06 01   ...........ef...
|   3984: 01 02 01 03 65 65 65 05 02 11 01 04 11 22 01 08   ....eee.........
|   4000: 11 22 22 22 02 02 66 67 05 06 01 01 02 01 03 66   ......fg.......f
|   4016: 56 66 06 02 21 01 04 21 42 02 02 67 68 06 06 01   Vf..!..!B..gh...
|   4032: 01 02 cb 03 67 67 67 07 02 41 02 02 68 69 07 06   ....ggg..A..hi..
|   4048: 01 01 02 04 81 13 09 50 09 2e 09 1c 09 12 09 0c   .......P........
|   4064: 09 08 07 01 03 00 14 07 81 77 07 00 00 00 15 22   .........w......
|   4080: 00 00 00 00 ff 00 00 01 00 00 00 00 00 00 05 0c   ................
| page 3 offset 8192
|      0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02   ................
| page 4 offset 12288
|      0: 0d 00 00 00 07 0f c8 00 0f f8 0f f0 0f e8 0f e0   ................
|     16: 0f d8 0f d0 0f c8 00 00 00 00 00 00 00 00 00 00   ................
|   4032: 00 00 00 00 00 00 00 00 06 07 04 00 10 09 7f 01   ................
|   4048: 06 06 04 00 10 09 3f 01 06 05 04 00 10 09 1f 01   ......?.........
|   4064: 06 04 04 00 10 09 0f 01 06 03 04 00 10 09 07 01   ................
|   4080: 06 02 04 00 10 09 03 01 06 01 04 00 10 09 01 01   ................
| page 5 offset 16384
|      0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04   ........version.
| end crash-d57c01958e48ab.db
}]} {}

do_catchsql_test 8.1 {
  SELECT rowid FROM t1('a* NOT ý‘') ;
} {0 {1 2 3 4 5 6 7}}

#-------------------------------------------------------------------------
reset_db
do_test 9.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
.open --hexdb
| size 32768 pagesize 4096 filename crash-c76a16c24c8ba6.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08   .....@  ........
|     32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04   ................
|     96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36   ...............6
|    112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00   ...k............
|   3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74   .........1tablet
|   3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45   2t2.CREATE TABLE
|   3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61    t2(x)V.......ta
|   3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63   blet1_configt1_c
|   3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42   onfig.CREATE TAB
|   3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b   LE 't1_config'(k
|   3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29    PRIMARY KEY, v)
|   3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06    WITHOUT ROWID[.
|   3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64   ..!!...tablet1_d
|   3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65   ocsizet1_docsize
|   3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74   .CREATE TABLE 't
|   3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e   1_docsize'(id IN
|   3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45   TEGER PRIMARY KE
|   3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21   Y, sz BLOB)^...!
|   3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74   !...tablet1_cont
|   3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52   entt1_content.CR
|   3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63   EATE TABLE 't1_c
|   3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47   ontent'(id INTEG
|   3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20   ER PRIMARY KEY, 
|   3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19   c0, c1, c2)i....
|   3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74   ...-tablet1_idxt
|   3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42   1_idx.CREATE TAB
|   3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69   LE 't1_idx'(segi
|   3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50   d, term, pgno, P
|   3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64   RIMARY KEY(segid
|   3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54   , term)) WITHOUT
|   3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74    ROWIDU........t
|   3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61   ablet1_datat1_da
|   3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20   ta.CREATE TABLE 
|   3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54   't1_data'(id INT
|   3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59   EGER PRIMARY KEY
|   3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06   , block BLOB)8..
|   3984: 17 11 11 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 35   LE t1 USING fts5
|   4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00   (a,b,c).........
| page 3 offset 8192
|      0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00   ................
|   3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18   .....J..........
|   3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06   ...+.00.........
|   3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30   ...........20160
|   3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01   609...........4.
|   3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02   ..........5.....
|   3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04   ......0000000...
|   3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06   ........binary..
|   3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01   ................
|   3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02   ................
|   3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02   ................
|   3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70   ............comp
|   3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64   iler...........d
|   3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04   bstat...........
|   3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65   ebug...........e
|   3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02   nable...........
|   3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02   ................
|   3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01   ................
|   3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02   ................
|   3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02   ......xtension..
|   3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03   .........fts4...
|   3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01   ........5.......
|   3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03   ....gcc.........
|   3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02   ..eopoly........
|   3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02   ...json1........
|   3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03   ...load.........
|   3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05   ..max...........
|   3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04   emory...........
|   3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e   sys5...........n
|   3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03   ocase...........
|   3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06   ................
|   3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01   ................
|   3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02   ................
|   3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02   ...omit.........
|   3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03   ..rtree.........
|   3760: 04 02 69 6d 01 06 01 02 02 03 06 01 02 02 03 06   ..im............
|   3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01   ................
|   3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02   ................
|   3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02   ................
|   3824: 01 0a 74 68 72 65 61 64 73 61 66 65 03 57 34 56   ..threadsafe.W4V
|   3840: 94 64 91 46 85 84 04 76 74 61 62 07 02 04 01 02   .d.F...vtab.....
|   3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01   ......x.........
|   3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 10 02   ................
|   3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01   ................
|   3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06   ................
|   3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01   ................
|   3936: 01 02 01 06 01 01 10 01 06 01 01 02 01 06 01 01   ................
|   3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02   ................
|   3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01   ................
|   3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06   ................
|   4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01   ................
|   4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01   ................
|   4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c   ................
|   4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f   .D...G..........
|   4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f   D..@.......$Z$$.
|   4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01   ...$............
| page 4 offset 12288
|      0: 0a 00 00 00 01 0f fa 00 00 00 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02   ................
| page 5 offset 16384
|      0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74   ....$..........t
|     16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5   .a.N./..........
|     32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5   ...t.[.@.$......
|     48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb   .......h.O.5....
|     64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a   .......x.W.>.$..
|   3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f   ...........$..%.
|   3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49   .THREADSAFE=0XBI
|   3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41   NARY.#..%..THREA
|   3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22   DSAFE=0XNOCASE..
|   3136: 05 00 25 0f 17 54 48 52 45 41 44 53 31 46 45 3d   ..%..THREADS1FE=
|   3152: 30 58 52 64 52 49 4d 1f 21 05 00 33 0f 19 4f 4d   0XRdRIM.!..3..OM
|   3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f   IT LOAD EXTENSIO
|   3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f   NXBINARY. ..3..O
|   3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49   MIT LOAD EXTENSI
|   3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17   ONXNOCASE....3..
|   3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53   OMIT LOAD EXTENS
|   3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19   IONXRTRIM....3..
|   3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30   MAX MEMORY=50000
|   3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f   000XBINARY....3.
|   3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30   .MAX MEMORY=5000
|   3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33   0000XNOCASE....3
|   3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30   ..MAX MEMORY=500
|   3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25   00000XRTRIM....%
|   3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42   ..ENABLE RTREEXB
|   3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42   INARY....%..ENAB
|   3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17   LE RTREEXNOCASE.
|   3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52   ...%..ENABLE RTR
|   3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45   EEXRTRIM....)..E
|   3440: 4e 41 42 4b 45 20 4d 45 4d 53 59 53 35 58 42 49   NABKE MEMSYS5XBI
|   3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c   NARY....)..ENABL
|   3472: 42 60 2d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45   B`-EMSYS5XNOCASE
|   3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45   ....)..ENABLE ME
|   3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25   MSYS5XRTRIM....%
|   3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42   ..ENABLE JSON1XB
|   3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42   INARY....%..ENAB
|   3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17   LE JSON1XNOCASE.
|   3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f   ...%..ENABLE JSO
|   3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45   N1XRTRIM....)..E
|   3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49   NABLE GEOPOLYXBI
|   3616: 4e 41 52 59 1a 11 05 00 39 0f 19 45 4e 41 42 4c   NARY....9..ENABL
|   3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45   E GEOPOLYXNOCASE
|   3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45   ....)..ENABLE GE
|   3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23   OPOLYXRTRIM....#
|   3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49   ..ENABLE FTS5XBI
|   3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c   NARY....#..ENABL
|   3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05   E FTS5XNOCASE...
|   3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58   .#..ENABLE FTS5X
|   3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42   RTRIM....#..ENAB
|   3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b   LE FTS4XBINARY..
|   3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34   ..#..ENABLE FTS4
|   3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e   XNOCASE....#..EN
|   3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e   ABLE FTS4XRTRIM.
|   3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53   ...1..ENABLE DBS
|   3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e   TAT VTABXBINARY.
|   3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53   ...1..ENABLE DBS
|   3872: 54 41 54 20 56 54 24 15 48 4e 4f 43 41 53 45 1d   TAT VT$.HNOCASE.
|   3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53   ...1..ENABLE DBS
|   3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06   TAT VTABXRTRIM..
|   3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52   .....DEBUGXBINAR
|   3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f   Y.......DEBUGXNO
|   3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47   CASE.......DEBUG
|   3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d   XRTRIM'...C..COM
|   3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20   PILER=gcc-5.4.0 
|   4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27   20160609XBINARY'
|   4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3c 67   ...C..COMPILER<g
|   4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30   cc-5.4.0 2016060
|   4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43   9XNOCASE&...C..C
|   4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e   OMPILER=gcc-5.4.
|   4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d   0 20160609XRTRIM
| page 6 offset 20480
|      0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0   ....$...........
|     16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0   ................
|     32: 1f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60   .........x.p.h.`
|     48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 0f 28 0f 20   .X.P.H.@.8.0.(. 
|     64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 0e e0   ................
|   3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01   .$.......#......
|   3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01   .........!......
|   3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01   . ..............
|   3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01   ................
|   3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01   ................
|   3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01   ................
|   3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01   ................
|   3920: 06 15 f3 00 12 02 01 01 06 15 03 00 12 02 01 01   ................
|   3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01   ................
|   3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01   ................
|   3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01   ................
|   3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01   ................
|   4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01   ................
|   4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01   ................
|   4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01   ................
|   4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01   ................
|   4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01   ................
|   4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01   ................
| page 7 offset 24576
|      0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04   ........version.
| page 8 offset 28672
|      0: 0d 00 00 00 03 0f d6 00 0f f4 0f e9 0f d6 00 00   ................
|   4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72   .........+integr
|   4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62   ity-check....reb
|   4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 00 00 00 00   uild....opti....
| end crash-c76a16c24c8ba6.db
}]} {}

#.testctrl prng_seed 1 db
#.testctrl internal_functions
#.testctrl json_selfcheck on
#

do_execsql_test 9.1 { 
  UPDATE t1 SET b=quote(zeroblob(current_date)) WHERE t1 MATCH 't*';
  SAVEPOINT a;
  UPDATE t1 SET b=quote(zeroblob(current_date)) WHERE t1 MATCH 't*';
  INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
}
do_catchsql_test 9.2 {
  DELETE FROM t1;
} {1 {database disk image is malformed}}

sqlite3_fts5_may_be_corrupt 0
finish_test

Changes to ext/fts5/test/fts5fault8.test.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
53
54
55
56
57
58
59

60
61
62
63
64
65
66







-







    } -test {
      faultsim_test_result {0 {1 3}} {1 SQLITE_NOMEM}
    }
  }

} ;# foreach_detail_mode...


do_execsql_test 4.0 {
  CREATE VIRTUAL TABLE x2 USING fts5(a);
  INSERT INTO x2(x2, rank) VALUES('crisismerge', 2);
  INSERT INTO x2(x2, rank) VALUES('pgsz', 32);
  INSERT INTO x2 VALUES('a b c d');
  INSERT INTO x2 VALUES('e f g h');
  INSERT INTO x2 VALUES('i j k l');
75
76
77
78
79
80
81













82
83
84
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96







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



do_faultsim_test 4 -faults oom-* -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { INSERT INTO x2(x2) VALUES('optimize') }
} -test {
  faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}

set TMPDBERROR {1 {unable to open a temporary database file for storing temporary tables}}

do_faultsim_test 5 -faults oom-t* -prep {
  faultsim_restore_and_reopen
  execsql { PRAGMA temp_store = memory }
} -body {
  execsql { PRAGMA integrity_check }
} -test {
  if {[string match {*error code=7*} $testresult]==0} {
    faultsim_test_result {0 ok} {1 SQLITE_NOMEM} $::TMPDBERROR
  }
}


finish_test
Added ext/fts5/test/fts5faultH.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2010 June 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultG

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

set ::testprefix fts5faultH

sqlite3_fts5_register_origintext db

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(
      x, tokenize="origintext unicode61", tokendata=1
  );

  BEGIN;
    INSERT INTO t1 VALUES('oNe tWo thRee');
    INSERT INTO t1 VALUES('One Two Three');
    INSERT INTO t1 VALUES('onE twO threE');
  COMMIT;
  BEGIN;
    INSERT INTO t1 VALUES('one two three');
    INSERT INTO t1 VALUES('one two three');
    INSERT INTO t1 VALUES('one two three');
  COMMIT;
}

do_faultsim_test 1 -faults oom* -prep { 
} -body {
  execsql {
    SELECT rowid FROM t1('three');
  }
} -test {
  faultsim_integrity_check
  faultsim_test_result {0 {1 2 3 4 5 6}}
}


reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(
      x, tokenize="origintext unicode61", tokendata=1
  );
  INSERT INTO t1(t1, rank) VALUES('pgsz', 64);

  BEGIN;
    INSERT INTO t1(rowid, x) VALUES(10, 'aaa bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(12, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(13, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(14, 'bbb BBB bbb');
    INSERT INTO t1(rowid, x) VALUES(15, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(16, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(17, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(18, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(19, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(20, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(21, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(22, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(23, 'bbb bbb bbb');
    INSERT INTO t1(rowid, x) VALUES(24, 'aaa bbb BBB');
  COMMIT;
}

do_faultsim_test 2 -faults oom* -prep { 
} -body {
  execsql {
    SELECT rowid FROM t1('BBB AND AAA');
  }
} -test {
  faultsim_integrity_check
  faultsim_test_result {0 {10 24}}
}

reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(
      x, tokenize="origintext unicode61", tokendata=1
  );
  INSERT INTO t1(t1, rank) VALUES('pgsz', 64);

  INSERT INTO t1(rowid, x) VALUES(9, 'bbb Bbb BBB');
  BEGIN;
    INSERT INTO t1(rowid, x) VALUES(10, 'aaa bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(11, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(12, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(13, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(14, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(15, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(16, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(17, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(18, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(19, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(20, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(21, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(22, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(23, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(24, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(25, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(26, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(27, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(28, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(29, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(30, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(31, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(32, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(33, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(34, 'bbb Bbb BBB');
    INSERT INTO t1(rowid, x) VALUES(35, 'aaa bbb BBB');
  COMMIT;
}

do_faultsim_test 3.1 -faults oom* -prep { 
} -body {
  execsql {
    SELECT rowid FROM t1('BBB AND AAA');
  }
} -test {
  faultsim_integrity_check
  faultsim_test_result {0 {10 35}}
}
do_faultsim_test 3.2 -faults oom* -prep { 
} -body {
  execsql {
    SELECT count(*) FROM t1('BBB');
  }
} -test {
  faultsim_integrity_check
  faultsim_test_result {0 27}
}


finish_test
Changes to ext/fts5/test/fts5integrity.test.
350
351
352
353
354
355
356


























357
358
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







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


do_execsql_test 11.3 {
  PRAGMA integrity_check(t2);
} {ok}
do_execsql_test 11.4 {
  DROP TABLE t1;
  PRAGMA integrity_check(t2);
} {ok}

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

do_execsql_test 12.1 {
  CREATE VIRTUAL TABLE x1 USING fts5(a, b);
  INSERT INTO x1 VALUES('one', 'two');
  INSERT INTO x1 VALUES('three', 'four');
  INSERT INTO x1 VALUES('five', 'six');
}

do_execsql_test 12.2 {
  PRAGMA integrity_check
} {ok}

db close
sqlite3 db test.db -readonly 1

explain_i {
  PRAGMA integrity_check
  }
do_execsql_test 12.3 {
  PRAGMA integrity_check
} {ok}



finish_test
Changes to ext/fts5/test/fts5misc.test.
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
87
88
89
90
91
92
93

94
95
96
97
98
99
100







-







do_execsql_test 2.2.1 {
  CREATE TABLE t0(c0);
  CREATE VIRTUAL TABLE vt0 USING fts5(c0);
  BEGIN TRANSACTION;
  INSERT INTO vt0(c0) VALUES ('xyz');
}

breakpoint
do_execsql_test 2.2.2 {
  ALTER TABLE t0 RENAME TO t1;
}
do_execsql_test 2.2.3 {
  INSERT INTO vt0(vt0) VALUES('integrity-check');
}
do_execsql_test 2.2.4 {
496
497
498
499
500
501
502






503






























504
505
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







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


do_execsql_test 17.5 {
  SELECT c0 FROM t0 WHERE c0 GLOB '*f*';
} {assertionfaultproblem}
do_execsql_test 17.5 {
  SELECT c0 FROM t0 WHERE c0 GLOB '*faul*';
} {assertionfaultproblem}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 18.0 {
  BEGIN;
    CREATE VIRTUAL TABLE t1 USING fts5(text);
    ALTER TABLE t1 RENAME TO t2;

}

do_execsql_test 18.1 {
    DROP TABLE t2;
}

do_execsql_test 18.2 {
  COMMIT;
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 19.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(text);
  CREATE TABLE t2(text);
  BEGIN;
    INSERT INTO t1 VALUES('one');
    INSERT INTO t1 VALUES('two');
    INSERT INTO t1 VALUES('three');
    INSERT INTO t1 VALUES('one');
    INSERT INTO t1 VALUES('two');
    INSERT INTO t1 VALUES('three');
    SAVEPOINT one;
      INSERT INTO t2 VALUES('one');
      INSERT INTO t2 VALUES('two');
      INSERT INTO t2 VALUES('three');
    ROLLBACK TO one;
  COMMIT;
}

finish_test

Added ext/fts5/test/fts5origintext.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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 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 fts5origintext

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

foreach_detail_mode $testprefix {

sqlite3_fts5_register_origintext db
do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", detail=%DETAIL%
  );
  CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
}

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

do_execsql_test 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 {
  select b(term) from vocab;
} {
  hello.Hello
  world
}

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

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

# Return a random integer between 0 and n-1.
#
proc random {n} {
  expr {abs(int(rand()*$n))}
}

proc select_one {list} {
  set n [llength $list]
  lindex $list [random $n]
}

proc term {} {
  set first_letter {
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
  }

  set term [select_one $first_letter]
  append term [random 100]
}

proc document {} {
  set nTerm [expr [random 5] + 5]
  set doc ""
  for {set ii 0} {$ii < $nTerm} {incr ii} {
    lappend doc [term]
  }
  set doc
}
db func document document

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

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

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

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

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

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

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

sqlite3_fts5_register_origintext db
do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", detail=%DETAIL%
  );
  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 3.2 {
  CREATE VIRTUAL TABLE ft2 USING fts5(x, 
      tokenize="origintext unicode61", 
      tokendata=1,
      detail=%DETAIL%
  );
  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 3.3.4 { SELECT rowid FROM ft2('hello*') } {1 2 3 10}

#-------------------------------------------------------------------------
#
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 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
  );
  INSERT INTO ft VALUES('one two three four');
}

do_execsql_test 4.1 {
  SELECT rowid, querytoken(ft, 0, 0) FROM ft('TwO')
} {1 two.TwO}
do_execsql_test 4.2 {
  SELECT rowid, querytoken(ft, 0, 0) FROM ft('one TWO ThreE')
} {1 one}
do_execsql_test 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 {
    SELECT rowid, querytoken(ft, 0, 2) FROM ft('"one TWO ThreE"')
  } {1 three.ThreE}
  do_catchsql_test 4.5 {
    SELECT rowid, querytoken(ft, 0, 3) FROM ft('"one TWO ThreE"')
  } {1 SQLITE_RANGE}
  do_catchsql_test 4.6 {
    SELECT rowid, querytoken(ft, 1, 0) FROM ft('"one TWO ThreE"')
  } {1 SQLITE_RANGE}
  do_catchsql_test 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 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
  );
  INSERT INTO ft VALUES('one ONE One oNe oNE one');
}

do_execsql_test 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 {
  SELECT insttoken(ft, 1, 0) FROM ft('one');
} {
  one.ONE
}

do_execsql_test 5.3 {
  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 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, y, tokenize='origintext unicode61', detail=%DETAIL%
  );

  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 {
  SELECT rowid, tokens(ft) FROM ft('One');
} {1 one.One 2 one.One}

do_execsql_test 6.2 {
  SELECT rowid, tokens(ft) FROM ft('on*');
} {1 {{}} 2 {{} {}}}

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

}

finish_test

Added ext/fts5/test/fts5origintext2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 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 fts5origintext2

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

sqlite3_fts5_register_origintext db
do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", tokendata=1
  );
}

do_execsql_test 1.1 {
  BEGIN;
  INSERT INTO ft VALUES('Hello');
  INSERT INTO ft VALUES('hello');
  INSERT INTO ft VALUES('HELLO');
  INSERT INTO ft VALUES('today');
  INSERT INTO ft VALUES('today');
  INSERT INTO ft VALUES('today');
  INSERT INTO ft VALUES('World');
  INSERT INTO ft VALUES('world');
  INSERT INTO ft VALUES('WORLD');
  COMMIT;
}

do_execsql_test 1.2 { SELECT rowid FROM ft('hello'); } {1 2 3}
do_execsql_test 1.3 { SELECT rowid FROM ft('today'); } {4 5 6}
do_execsql_test 1.4 { SELECT rowid FROM ft('world'); } {7 8 9}

do_execsql_test 1.5 {
  SELECT count(*) FROM ft_data
} 3

do_execsql_test 1.6 {
  DELETE FROM ft;
  INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
  BEGIN;
    WITH s(i) AS (
      SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
    )
    INSERT INTO ft SELECT 'Hello Hello Hello Hello Hello Hello Hello' FROM s;
    INSERT INTO ft VALUES ('hELLO hELLO hELLO');
    INSERT INTO ft VALUES('today today today today today today today');
    INSERT INTO ft VALUES('today today today today today today today');
    INSERT INTO ft VALUES('today today today today today today today');
    INSERT INTO ft VALUES('today today today today today today today');
    INSERT INTO ft VALUES('today today today today today today today');
    INSERT INTO ft VALUES('today today today today today today today');
    INSERT INTO ft VALUES('World World World World World World World');
    INSERT INTO ft VALUES('world world world world world world world');
    INSERT INTO ft VALUES('WORLD WORLD WORLD WORLD WORLD WORLD WORLD');
    INSERT INTO ft VALUES('World World World World World World World');
    INSERT INTO ft VALUES('world world world world world world world');
    INSERT INTO ft VALUES('WORLD WORLD WORLD WORLD WORLD WORLD WORLD');
  COMMIT;
}

do_execsql_test 1.7 {
  SELECT count(*) FROM ft_data;
} 23

do_execsql_test 1.8 { SELECT rowid FROM ft('hello') WHERE rowid>100; } {101}

do_execsql_test 1.9 {
  DELETE FROM ft;
  INSERT INTO ft(ft) VALUES('optimize');
  SELECT count(*) FROM ft_data;
} {2}
do_execsql_test 1.10 {
  BEGIN;
    INSERT INTO ft VALUES('Hello');
    INSERT INTO ft VALUES('hello');
    INSERT INTO ft VALUES('HELLO');
    INSERT INTO ft VALUES('today');
    INSERT INTO ft VALUES('today');
    INSERT INTO ft VALUES('today');
    INSERT INTO ft VALUES('World');
    INSERT INTO ft VALUES('world');
    INSERT INTO ft VALUES('WORLD');
}

do_execsql_test 1.11 { SELECT rowid FROM ft('hello'); } {1 2 3}
do_execsql_test 1.12 { SELECT rowid FROM ft('today'); } {4 5 6}
do_execsql_test 1.13 { SELECT rowid FROM ft('world'); } {7 8 9}
do_execsql_test 1.14 { SELECT rowid FROM ft('hello') ORDER BY rank; } {1 2 3}

#------------------------------------------------------------------------
reset_db
sqlite3_fts5_register_origintext 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

do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE x1 USING fts5(
    v, tokenize="origintext unicode61", tokendata=1, detail=none
  );

  INSERT INTO x1 VALUES('xxx Xxx XXX yyy YYY yyy');
  INSERT INTO x1 VALUES('xxx yyy xxx yyy yyy yyy');
}

do_execsql_test 2.1 {
  SELECT tokens(x1) FROM x1('xxx');
} {
  {xxx xxx.Xxx xxx.XXX} {xxx xxx}
}

do_execsql_test 2.2 {
  UPDATE x1_content SET c0 = 'xxx xxX xxx yyy yyy yyy' WHERE id=1;
}

do_execsql_test 2.3 {
  SELECT tokens(x1) FROM x1('xxx');
} {
  {xxx {} xxx} {xxx xxx}
}

finish_test

Added ext/fts5/test/fts5origintext3.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 November 22
#
# 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 fts5origintext3

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

foreach_detail_mode $testprefix {
  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 {
    CREATE VIRTUAL TABLE ft USING fts5(
        x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
    );
  }
  
  do_execsql_test 1.1 {
    INSERT INTO ft VALUES('Hello world HELLO WORLD hello');
  }
  
  do_execsql_test 1.2 {
    SELECT fts5_test_poslist(ft) FROM ft('hello');
  } {{0.0.0 0.0.2 0.0.4}}

  do_execsql_test 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.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 {
    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 {
    SELECT insttoken(ft2, 0, 0), rowid FROM ft2('three') ORDER BY rank;
  } {three.THREE 3 three 1 three 2}

  do_execsql_test 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}

}

finish_test

Added ext/fts5/test/fts5origintext4.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 November 22
#
# 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 fts5origintext4

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

# The tests below verify that a doclist-index is used to limit the number
# of pages loaded into the cache. It does this by querying sqlite3_db_status()
# for the amount of memory used by the pager cache.
#
# memsubsys1 effectively limits the page-cache to 24 pages. Which masks
# the effect tested by the tests in this file. And "mmap" prevents the 
# cache from being used, also preventing these tests from working.
#
if {[permutation]=="memsubsys1" || [permutation]=="mmap"} {
  finish_test
  return
}

sqlite3_fts5_register_origintext db
do_execsql_test 1.0 {
  PRAGMA page_size = 4096;
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", tokendata=1
  );
}

do_execsql_test 1.1 {
  BEGIN;
    INSERT INTO ft SELECT 'the first thing';

    WITH s(i) AS (
      SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<90000
    )
    INSERT INTO ft SELECT 'The second thing' FROM s;

    INSERT INTO ft SELECT 'the first thing';
  COMMIT;
  INSERT INTO ft(ft) VALUES('optimize');
}

foreach {tn sql expr} {
  1 { SELECT rowid FROM ft('the') }       {$mem > 250000}
  2 { SELECT rowid FROM ft('first') }     {$mem <  50000}
  3 { SELECT rowid FROM ft('the first') } {$mem <  50000}
} {
  db close
  sqlite3 db test.db
  sqlite3_fts5_register_origintext db

  execsql $sql
  do_test 1.2.$tn {
    set mem [lindex [sqlite3_db_status db CACHE_USED 0] 1]
    expr $expr
  } 1
}

proc b {x} { string map [list "\0" "."] $x }
db func b b
# execsql_pp { SELECT segid, b(term), pgno from ft_idx }

finish_test

Added ext/fts5/test/fts5origintext5.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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 Dec 04
#
# 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 for tables that use both tokendata=1 and contentless_delete=1.
#

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

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

# Return a random integer between 0 and n-1.
#
proc random {n} { expr {abs(int(rand()*$n))} }

# Select an element of the list passed as the only argument at random and
# return it. 
#
proc select_one {list} {
  set n [llength $list]
  lindex $list [random $n]
}

# Given a term that consists entirely of alphabet characters, return all
# permutations of the term using upper and lower case characters. e.g.
#
#    "abc" -> {CBA cBA CbA cbA CBa cBa Cba cba}
#
proc casify {term {lRet {{}}}} {
  if {$term==""} { return $lRet }
  set t [string range $term 1 end]
  set f1 [string toupper [string range $term 0 0]]
  set f2 [string tolower [string range $term 0 0]]
  set ret [list]
  foreach x $lRet {
    lappend ret "$x$f1"
    lappend ret "$x$f2"
  }
  return [casify $t $ret]
}

proc vocab {} {
  list abc def ghi jkl mno pqr stu vwx yza
}

# Return a random 3 letter term.
#
proc term {} {
  if {[info exists ::expanded_vocab]==0} {
    foreach v [vocab] { lappend ::expanded_vocab {*}[casify $v] }
  }

  select_one $::expanded_vocab
}

# Return a document - between 3 and 10 terms.
#
proc document {} {
  set nTerm [expr [random 3] + 7]
  set doc ""
  for {set ii 0} {$ii < $nTerm} {incr ii} {
    lappend doc [term]
  }
  set doc
}
db func document document

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

expr srand(6)

set NDOC  200
set NLOOP 50

sqlite3_fts5_register_origintext 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

proc rankfunc {cmd} { 
  $cmd xRowid
}
sqlite3_fts5_create_function db rankfunc rankfunc

proc ctrl_tokens {term args} {
  set ret [list]
  set term [string tolower $term]
  foreach doc $args {
    foreach a $doc {
      if {[string tolower $a]==$term} {
        if {$a==$term} {
          lappend ret $a
        } else {
          lappend ret [string tolower $a].$a
        }
      }
    }
  }
  set ret
}
db func ctrl_tokens ctrl_tokens

proc do_all_vocab_test {tn} {
  foreach ::v [concat [vocab] nnn] {
    set answer [execsql {
      SELECT id, ctrl_tokens($::v, x) FROM ctrl WHERE x LIKE '%' || $::v || '%'
    }]
    do_execsql_test $tn.$::v.1 {
      SELECT rowid, tokens(ft) FROM ft($::v)
    } $answer
    do_execsql_test $tn.$::v.2 {
      SELECT rowid, tokens(ft) FROM ft($::v) ORDER BY rank
    } $answer
  }
}

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", content=, contentless_delete=1,
      tokendata=1
  );

  CREATE TABLE ctrl(id INTEGER PRIMARY KEY, x TEXT);
  INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
  INSERT INTO ft(ft, rank) VALUES('rank', 'rankfunc()');
}
do_test 1.1 {
  for {set ii 0} {$ii < $NDOC} {incr ii} {
    set doc [document]
    execsql {
      INSERT INTO ft(rowid, x) VALUES($ii, $doc);
      INSERT INTO ctrl(id, x) VALUES($ii, $doc);
    }
  }
} {}

#execsql_pp { SELECT * FROM ctrl }
#execsql_pp { SELECT * FROM ft }
#fts5_aux_test_functions db
#execsql_pp { SELECT rowid, tokens(ft), fts5_test_poslist(ft) FROM ft('ghi'); }

do_all_vocab_test 1.2

for {set ii 0} {$ii < $NLOOP} {incr ii} {
  set lRowid [execsql { SELECT id FROM ctrl WHERE random() % 2 }]
  foreach r $lRowid {
    execsql { DELETE FROM ft WHERE rowid = $r }
    execsql { DELETE FROM ctrl WHERE rowid = $r }

    set doc [document]
    execsql { INSERT INTO ft(rowid, x) VALUES($r, $doc) }
    execsql { INSERT INTO ctrl(id, x) VALUES($r, $doc) }
  }
  do_all_vocab_test 1.3.$ii
}

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

do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE ft2 USING fts5(
      x, y, tokenize="origintext unicode61", content=, contentless_delete=1,
      tokendata=1
  );

  CREATE TABLE ctrl2(id INTEGER PRIMARY KEY, x TEXT, y TEXT);
  INSERT INTO ft2(ft2, rank) VALUES('pgsz', 64);
  INSERT INTO ft2(ft2, rank) VALUES('rank', 'rankfunc()');
}
do_test 2.1 {
  for {set ii 0} {$ii < $NDOC} {incr ii} {
    set doc1 [document]
    set doc2 [document]
    execsql {
      INSERT INTO ft2(rowid, x, y) VALUES($ii, $doc, $doc2);
      INSERT INTO ctrl2(id, x, y) VALUES($ii, $doc, $doc2);
    }
  }
} {}

proc do_all_vocab_test2 {tn} {
  foreach ::v [vocab] {
    set answer [execsql {
      SELECT id, ctrl_tokens($::v, x, y) FROM ctrl2
      WHERE x LIKE '%' || $::v || '%' OR y LIKE '%' || $::v || '%';
    }]
    do_execsql_test $tn.$::v.1 {
      SELECT rowid, tokens(ft2) FROM ft2($::v)
    } $answer
    do_execsql_test $tn.$::v.2 {
      SELECT rowid, tokens(ft2) FROM ft2($::v) ORDER BY rank
    } $answer
  }
}

do_all_vocab_test2 2.2

for {set ii 0} {$ii < $NLOOP} {incr ii} {
  set lRowid [execsql { SELECT id FROM ctrl2 WHERE random() % 2 }]
  foreach r $lRowid {
    execsql { DELETE FROM ft2 WHERE rowid = $r }
    execsql { DELETE FROM ctrl2 WHERE rowid = $r }

    set doc1 [document]
    set doc2 [document]
    execsql { INSERT INTO ft2(rowid, x, y) VALUES($r, $doc, $doc1) }
    execsql { INSERT INTO ctrl2(id, x, y) VALUES($r, $doc, $doc2) }
  }
  do_all_vocab_test 2.3.$ii
}

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

unset -nocomplain ::expanded_vocab
proc vocab {} {
  list abcde fghij klmno
}

proc do_all_vocab_test3 {tn} {
  foreach ::v [concat [vocab] nnn] {
    set answer [execsql {
      SELECT rowid, ctrl_tokens($::v, w) FROM ctrl3 WHERE w LIKE '%' || $::v || '%'
    }]
    do_execsql_test $tn.$::v.1 {
      SELECT rowid, tokens(ft3) FROM ft3($::v)
    } $answer
    do_execsql_test $tn.$::v.2 {
      SELECT rowid, tokens(ft3) FROM ft3($::v) ORDER BY rank
    } $answer
  }
}

do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE ft3 USING fts5(
      w, tokenize="origintext unicode61", content=, contentless_delete=1,
      tokendata=1
  );
  INSERT INTO ft3(ft3, rank) VALUES('rank', 'rankfunc()');
  CREATE TABLE ctrl3(w);
}

do_execsql_test 3.1 {
  WITH s(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<2
  )
  INSERT INTO ctrl3 SELECT document() FROM s;
  INSERT INTO ft3(rowid, w) SELECT rowid, w FROM ctrl3;
}

do_all_vocab_test3 3.2


finish_test

Changes to ext/fts5/test/fts5secure3.test.
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
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







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








#execsql_pp { SELECT id, quote(block), fts5_decode(id, block) FROM t1_data; }

#-------------------------------------------------------------------------
# Tests with large/small rowid values.
#

foreach {tn cfg} {
  1 ""
  2 "INSERT INTO fff(fff, rank) VALUES('secure-delete', 1)"
} {
reset_db

expr srand(0)

set vocab {
  Popper Poppins Popsicle Porfirio Porrima Porsche
  Porter Portia Portland Portsmouth Portugal Portuguese
  Poseidon Post PostgreSQL Potemkin Potomac Potsdam
  Pottawatomie Potter Potts Pound Poussin Powell
  PowerPC PowerPoint Powers Powhatan Poznan Prada
  Prado Praetorian Prague Praia Prakrit Pratchett
  Pratt Pravda Praxiteles Preakness Precambrian Preminger
  Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
}
proc newdoc {} {
  for {set i 0} {$i<8} {incr i} {
    lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
  }
  set ret
}
db func newdoc newdoc

do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE fff USING fts5(y);
  INSERT INTO fff(fff, rank) VALUES('pgsz', 64);

  WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
  INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;

  WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
  INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;

  WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
  INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;

  reset_db
  
  expr srand(0)
  
  set vocab {
    Popper Poppins Popsicle Porfirio Porrima Porsche
    Porter Portia Portland Portsmouth Portugal Portuguese
    Poseidon Post PostgreSQL Potemkin Potomac Potsdam
    Pottawatomie Potter Potts Pound Poussin Powell
    PowerPC PowerPoint Powers Powhatan Poznan Prada
    Prado Praetorian Prague Praia Prakrit Pratchett
    Pratt Pravda Praxiteles Preakness Precambrian Preminger
    Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
  }
  proc newdoc {} {
    for {set i 0} {$i<8} {incr i} {
      lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
    }
    set ret
  }
  db func newdoc newdoc
  
  do_execsql_test 3.$tn.0 {
    CREATE VIRTUAL TABLE fff USING fts5(y);
    INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
  
    WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
    INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
  
    WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
    INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
  
    WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
    INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
  }
  INSERT INTO fff(fff, rank) VALUES('secure-delete', 1);
}

proc lshuffle {in} {
  set out [list]
  while {[llength $in]>0} {
    set idx [expr int(abs(rand()) * [llength $in])]
    lappend out [lindex $in $idx]
    set in [lreplace $in $idx $idx]
  }
  set out
}

#dump fff

set iTest 1
foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
  #if {$iTest==1} { dump fff }
  #if {$iTest==1} { breakpoint }
  do_execsql_test 3.1.$iTest.$ii {
    DELETE FROM fff WHERE rowid=$ii;
  }
  #if {$iTest==1} { dump fff }
  if {($iTest % 20)==0} {
    do_execsql_test 3.1.$iTest.$ii.ic {
      INSERT INTO fff(fff) VALUES('integrity-check');
    }
  }
  #if {$iTest==1} { break }
  incr iTest

  execsql $cfg
  
  proc lshuffle {in} {
    set out [list]
    while {[llength $in]>0} {
      set idx [expr int(abs(rand()) * [llength $in])]
      lappend out [lindex $in $idx]
      set in [lreplace $in $idx $idx]
    }
    set out
  }
  
  #dump fff
  
  set iTest 1
  foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
    #if {$iTest==1} { dump fff }
    #if {$iTest==1} { breakpoint }
    do_execsql_test 3.$tn.1.$iTest.$ii {
      DELETE FROM fff WHERE rowid=$ii;
    }
    #if {$iTest==1} { dump fff }
    if {($iTest % 20)==0} {
      do_execsql_test 3.$tn.1.$iTest.$ii.ic {
        INSERT INTO fff(fff) VALUES('integrity-check');
      }
    }
    #if {$iTest==1} { break }
    incr iTest
  }
}

#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC }
#breakpoint
#execsql_pp { 
#  SELECT rowid FROM fff('post') ORDER BY rowid DESC 
#}
Added ext/fts5/test/fts5secure8.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 Nov 23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
#

source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5secure8

proc sql_repeat {txt n} {
  string repeat $txt $n
}
db func repeat sql_repeat

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE ft USING fts5(x);

  INSERT INTO ft(ft, rank) VALUES('pgsz', 64);

  INSERT INTO ft(rowid, x) VALUES(100, 'hello world');
  INSERT INTO ft(rowid, x) VALUES(200, 'one day');

  BEGIN;
    INSERT INTO ft(rowid, x) VALUES(45, 'one two three');
    UPDATE ft SET x = repeat('hello world ', 500) WHERE rowid=100;
  COMMIT
}

do_execsql_test 1.1 {
  INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
  DELETE FROM ft WHERE rowid=100;
}

do_execsql_test 1.2 {
  PRAGMA integrity_check;
} {ok}





finish_test


Changes to ext/fts5/test/fts5simple2.test.
339
340
341
342
343
344
345

346


347
348
349
350
351
352
353
339
340
341
342
343
344
345
346

347
348
349
350
351
352
353
354
355







+
-
+
+







  CREATE VIRTUAL TABLE t2 USING fts5(x, y);
  BEGIN;
    INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
    INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
    INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
  COMMIT;
}
do_execsql_test 17.1 { 
do_execsql_test 17.1 { SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20 }
  SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20 
}
do_execsql_test 17.2 {
  BEGIN;
    INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
    SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20 ;
}
do_execsql_test 17.3 {
  COMMIT
Changes to ext/fts5/test/fts5synonym2.test.
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52







-
+







    }
  }

  list [sort_poslist $PL] $CL
}
sqlite3_fts5_create_function db fts5_test_bothlist fts5_test_bothlist

proc fts5_rowid {cmd} { expr [$cmd xColumnText -1] }
proc fts5_rowid {cmd} { expr [$cmd xRowid] }
sqlite3_fts5_create_function db fts5_rowid fts5_rowid

do_execsql_test 1.$tok.0.1 "
  CREATE VIRTUAL TABLE ss USING fts5(a, b, 
       tokenize='tclnum $tok', detail=%DETAIL%);
  INSERT INTO ss(ss, rank) VALUES('rank', 'fts5_rowid()');
"
Added ext/fts5/test/fts5tokenizer2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 Nov 03
#
# 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 focusing on the built-in fts5 tokenizers. 
#

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

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

sqlite3_fts5_create_tokenizer db tst get_tst_tokenizer
proc get_tst_tokenizer {args} {
  return "tst_tokenizer"
}
proc tst_tokenizer {flags txt} {
  set token ""
  set lTok [list]

  foreach c [split $txt {}] {
    if {$token==""} {
      append token $c
    } else {
      set t1 [string is upper $token]
      set t2 [string is upper $c]

      if {$t1!=$t2} {
        lappend lTok $token
        set token ""
      }
      append token $c
    }
  }
  if {$token!=""} { lappend lTok $token }

  set iOff 0
  foreach t $lTok {
    set n [string length $t]
    sqlite3_fts5_token $t $iOff [expr $iOff+$n]
    incr iOff $n
  }
}

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(t, tokenize=tst);
}

do_execsql_test 1.1 {
  INSERT INTO t1 VALUES('AAdontBBmess');
}

do_execsql_test 1.2 {
  SELECT snippet(t1, 0, '>', '<', '...', 4) FROM t1('BB');
} {AAdont>BB<mess}

do_execsql_test 1.3 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('BB');
} {AAdont>BB<mess}

do_execsql_test 1.4 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('AA');
} {>AA<dontBBmess}

do_execsql_test 1.5 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('dont');
} {AA>dont<BBmess}

do_execsql_test 1.6 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('mess');
} {AAdontBB>mess<}

do_execsql_test 1.7 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
} {AAdont>BBmess<}


finish_test
Added ext/fts5/test/fts5trigram2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 October 24
#
# 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 for the fts5 "trigram" tokenizer.
#

source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5trigram2

do_execsql_test 1.0 "
  CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize='trigram remove_diacritics 1');
  INSERT INTO t1 VALUES('abc\u0303defghijklm');
  INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
"

do_execsql_test 1.1 {
  SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
} [list \
  "(abc\u0303)defghijklm"                          \
  "(a\u0303b\u0303c\u0303)defghijklm"              \
]

do_execsql_test 1.2 {
  SELECT highlight(t1, 0, '(', ')') FROM t1('bcde');
} [list \
  "a(bc\u0303de)fghijklm"                          \
  "a\u0303(b\u0303c\u0303de)fghijklm"              \
]

do_execsql_test 1.3 {
  SELECT highlight(t1, 0, '(', ')') FROM t1('cdef');
} [list \
  "ab(c\u0303def)ghijklm"                          \
  "a\u0303b\u0303(c\u0303def)ghijklm"              \
]

do_execsql_test 1.4 {
  SELECT highlight(t1, 0, '(', ')') FROM t1('def');
} [list \
  "abc\u0303(def)ghijklm"                          \
  "a\u0303b\u0303c\u0303(def)ghijklm"              \
]


#-------------------------------------------------------------------------
do_catchsql_test 2.0 {
  CREATE VIRTUAL TABLE t2 USING fts5(
      z, tokenize='trigram case_sensitive 1 remove_diacritics 1'
  );
} {1 {error in tokenizer constructor}}

do_execsql_test 2.1 {
  CREATE VIRTUAL TABLE t2 USING fts5(
      z, tokenize='trigram case_sensitive 0 remove_diacritics 1'
  );
}
do_execsql_test 2.2 "
  INSERT INTO t2 VALUES('\u00E3bcdef');
  INSERT INTO t2 VALUES('b\u00E3cdef');
  INSERT INTO t2 VALUES('bc\u00E3def');
  INSERT INTO t2 VALUES('bcd\u00E3ef');
"

do_execsql_test 2.3 {
  SELECT highlight(t2, 0, '(', ')') FROM t2('abc');
} "(\u00E3bc)def"
do_execsql_test 2.4 {
  SELECT highlight(t2, 0, '(', ')') FROM t2('bac');
} "(b\u00E3c)def"
do_execsql_test 2.5 {
  SELECT highlight(t2, 0, '(', ')') FROM t2('bca');
} "(bc\u00E3)def"
do_execsql_test 2.6 "
  SELECT highlight(t2, 0, '(', ')') FROM t2('\u00E3bc');
" "(\u00E3bc)def"

#-------------------------------------------------------------------------
do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE t3 USING fts5(
      z, tokenize='trigram remove_diacritics 1'
  );
} {}
do_execsql_test 3.1 "
  INSERT INTO t3 VALUES ('\u0303abc\u0303');
"
do_execsql_test 3.2 {
  SELECT highlight(t3, 0, '(', ')') FROM t3('abc');
} "\u0303(abc\u0303)"

#-------------------------------------------------------------------------
do_execsql_test 4.0 {
  CREATE VIRTUAL TABLE t4 USING fts5(z, tokenize=trigram);
} {}

breakpoint
do_execsql_test 4.1 {
  INSERT INTO t4 VALUES('ABCD');
} {}

finish_test
Changes to ext/fts5/test/fts5vocab2.test.
276
277
278
279
280
281
282
























283
284
285
286
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







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




} {1 {query aborted}}

do_catchsql_test 5.2 {
  DELETE FROM t1 WHERE rowid>100;
  INSERT INTO t1 SELECT randomblob(3000) FROM v1
} {1 {query aborted}}

#-------------------------------------------------------------------------
reset_db
sqlite3_fts5_may_be_corrupt 1

do_execsql_test 6.0 {
  BEGIN TRANSACTION;
    CREATE VIRTUAL TABLE t1 USING fts5(a,b unindexed,c,tokenize="porter ascii",tokendata=1);
    REPLACE INTO t1_data VALUES(1,X'03090009');
    REPLACE INTO t1_data VALUES(10,X'000000000103030003010101020101030101');
    REPLACE INTO t1_data VALUES(137438953473,X'0000002e023061010202010162010203010163010204010167010601020201016801060102030101690106010204040606060808');
    REPLACE INTO t1_data VALUES(274877906945,X'0000001f013067020802010202010168020803010203010169020804010204040909');
    REPLACE INTO t1_data VALUES(412316860417,X'0000002e023061030202010162030203010163030204010167030601020201016803060102030101690306010204040606060808');
  COMMIT;
}

do_execsql_test 6.1 {
  CREATE VIRTUAL TABLE t3 USING fts5vocab('t1', 'row');
}

do_catchsql_test 6.2 {
  SELECT * FROM t3;
} {1 {database disk image is malformed}}

sqlite3_fts5_may_be_corrupt 0

finish_test


Added ext/intck/intck1.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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2008 Feb 19
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the incremental integrity check
# (intck) extension.
#

source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intck1
return_if_no_intck

foreach {tn sql} {
  1 "CREATE TABLE t1(a PRIMARY KEY, b)"
  2 "CREATE TABLE t2(a PRIMARY KEY, b) WITHOUT   ROWID  "
  3 "CREATE TABLE t3(a PRIMARY KEY, b) WITHOUT   rowID;"
  4 "CREATE TABLE t4(a PRIMARY KEY, ROWID)"
  5 {CREATE TABLE t5(a PRIMARY KEY, ROWID) WITHOUT ROWID
    }
} {
  do_test 1.1.$tn {
    db eval $sql
    set {} {}
  } {}
}

set space " \n\v\t\r\f"

do_execsql_test 1.2 {
  SELECT name, (rtrim(sql, $space) LIKE '%rowid') 
  FROM sqlite_schema WHERE type='table'
  ORDER BY 1
} {
  t1 0
  t2 1
  t3 1
  t4 0
  t5 1
}

do_execsql_test 1.3 {
  CREATE TABLE x1(a COLLATE nocase, b INTEGER, c BLOB);
  INSERT INTO x1 VALUES('lEtTeRs', 1234, 1234);
}
do_execsql_test 1.3.1 {
  WITH wrapper(c1, c2, c3) AS (
    SELECT a, b, c FROM x1
  )
  SELECT * FROM wrapper WHERE c1='letters';
} {lEtTeRs 1234 1234}
do_execsql_test 1.3.2 {
  WITH wrapper(c1, c2, c3) AS (
    SELECT a, b, c FROM x1
  )
  SELECT * FROM wrapper WHERE c2='1234';
} {lEtTeRs 1234 1234}
do_execsql_test 1.3.2 {
  WITH wrapper(c1, c2, c3) AS (
    SELECT a, b, c FROM x1
  )
  SELECT * FROM wrapper WHERE c3='1234';
} {}

do_execsql_test 1.4 {
  CREATE TABLE z1(a, b);
  CREATE INDEX z1ab ON z1(a+b COLLATE nocase);
}
do_execsql_test 1.4.1 {
  SELECT * FROM z1 INDEXED BY z1ab 
}

do_catchsql_test 1.5.1 {
  CREATE INDEX z1b ON z1(b ASC NULLS LAST);
} {1 {unsupported use of NULLS LAST}}
do_catchsql_test 1.5.2 {
  CREATE INDEX z1b ON z1(b DESC NULLS LAST);
} {1 {unsupported use of NULLS LAST}}
do_catchsql_test 1.5.3 {
  CREATE INDEX z1b ON z1(b ASC NULLS FIRST);
} {1 {unsupported use of NULLS FIRST}}
do_catchsql_test 1.5.4 {
  CREATE INDEX z1b ON z1(b DESC NULLS FIRST);
} {1 {unsupported use of NULLS FIRST}}


reset_db
do_execsql_test 1.6.1 {
  CREATE TABLE t1(i INTEGER PRIMARY KEY, b, c);
  CREATE INDEX i1 ON t1(b);
  ANALYZE;
  INSERT INTO sqlite_stat1 VALUES('t1', 'i1', '10000 10000');
  ANALYZE sqlite_schema;
} {}
do_eqp_test 1.6.2 {
  SELECT 1 FROM t1 INDEXED BY i1 WHERE (b, i) IS (?, ?);
} {SEARCH}



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

do_test 2.0 {
  set ic [sqlite3_intck db main]
  $ic close
} {}

do_execsql_test 2.1 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(3, 4);

  CREATE INDEX i1 ON t1(a COLLATE nocase);
  CREATE INDEX i2 ON t1(b, a);
  CREATE INDEX i3 ON t1(b + a COLLATE nocase) WHERE a!=1;
}

do_intck_test 2.2 {
}

# Delete a row from each of the i1 and i2 indexes using the imposter
# table interface.
#
do_test 2.3 {
  db eval {SELECT name, rootpage FROM sqlite_schema} {
    set R($name) $rootpage
  }
  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(i1)
  db eval { CREATE TABLE imp1(a PRIMARY KEY, rowid) WITHOUT ROWID; }
  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(i2)
  db eval { CREATE TABLE imp2(b, a, rowid, PRIMARY KEY(b, a)) WITHOUT ROWID; }
  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0

  db eval {
    DELETE FROM imp1 WHERE rowid=1;
    DELETE FROM imp2 WHERE rowid=2;
  }

  db close
  sqlite3 db test.db
} {}

do_intck_test 2.4 {
  {entry (1,1) missing from index i1} 
  {entry (4,3,2) missing from index i2}
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
  CREATE TABLE x1(a, b, c, PRIMARY KEY(c, b)) WITHOUT ROWID;
  CREATE INDEX x1a ON x1(a COLLATE nocase);

  INSERT INTO x1 VALUES(1, 2, 'three');
  INSERT INTO x1 VALUES(4, 5, 'six');
  INSERT INTO x1 VALUES(7, 8, 'nine');
}

do_intck_test 3.1 { }

do_test 3.2 {
  db eval {SELECT name, rootpage FROM sqlite_schema} {
    set R($name) $rootpage
  }
  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(x1a)
  db eval { CREATE TABLE imp1(c, b, a, PRIMARY KEY(c, b)) WITHOUT ROWID }
  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0

  db eval {
    DELETE FROM imp1 WHERE a=5;
  }
  execsql_pp {
  }

  db close
  sqlite3 db test.db
} {}

do_intck_test 3.3 { 
  {entry (4,'six',5) missing from index x1a}
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
  CREATE TABLE www(x, y, z);
  CREATE INDEX w1 ON www( (x+1), z );
  INSERT INTO www VALUES(1, 1, 1), (2, 2, 2);
}

do_intck_test 4.1 { }

#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a, b);             
  CREATE INDEX i1 ON t1(a COLLATE NOCASE);
  INSERT INTO t1 VALUES(1, 1);
  INSERT INTO t1 VALUES(2, 2);
}

do_test 5.1 {
  set ic [sqlite3_intck db nosuchdb]
  $ic step
} {SQLITE_ERROR}

do_test 5.2 {
  $ic close
  set ic [sqlite3_intck db {}]
  while {[$ic step]=="SQLITE_OK"} {}
  set res [$ic error]
  $ic close
  set res
} {SQLITE_OK {}}

do_test 5.3 { test_do_intck db "main" } {}

do_test 5.4 {
  set ret {}
  set ic [sqlite3_intck db main]
  db eval [$ic test_sql t1] {
    if {$error_message!=""} { lappend ret $error_message }
  }
  $ic close
  set ret
} {}

do_test 5.5 {
  set ret {}
  set ic [sqlite3_intck db main]
  db eval [$ic test_sql {}] {
    if {$error_message!=""} { lappend ret $error_message }
  }
  $ic close
  set ret
} {}

db cache flush

do_test 5.6 {
  set ret {}
  set ic [sqlite3_intck db main]
  $ic step
  db eval [$ic test_sql {}] {
    if {$error_message!=""} { lappend ret $error_message }
  }
  $ic close
  set ret
} {}

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

do_execsql_test 6.0 {
  CREATE TABLE t1(x, y, PRIMARY KEY(x)) WITHOUT ROWID;
  CREATE INDEX i1 ON t1(y, x);
  INSERT INTO t1 VALUES(X'0000', X'1111');
}

do_intck_test 6.1 {}

do_execsql_test 6.2.1 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_schema SET sql = 'CREATE INDEX i1' WHERE name='i1';
} {}
do_intck_test 6.2.2 {}

do_execsql_test 6.3.1 {
  UPDATE sqlite_schema SET sql = 'CREATE INDEX i1(y' WHERE name='i1';
} {}
do_intck_test 6.3.2 {}

do_execsql_test 6.4.1 {
  UPDATE sqlite_schema 
  SET sql = 'CREATE INDEX i1(y) hello world' 
  WHERE name='i1';
} {}
do_intck_test 6.4.2 {}

do_execsql_test 6.5.1 {
  UPDATE sqlite_schema 
  SET sql = 'CREATE INDEX i1(y, x) WHERE 1     ' 
  WHERE name='i1';
} {}
do_intck_test 6.5.2 {}

do_execsql_test 6.6.1 {
  UPDATE sqlite_schema 
  SET sql = 'CREATE INDEX i1(  ,  ) WHERE 1     ' 
  WHERE name='i1';
} {}

do_test 6.7.2 {
  set ic [sqlite3_intck db main]
  $ic step
} {SQLITE_ERROR}
do_test 6.5.3 {
  $ic error
} {SQLITE_ERROR {near "AS": syntax error}}
$ic close

do_execsql_test 6.6.1 {
  UPDATE sqlite_schema 
  SET sql = 'CREATE INDEX i1([y'
  WHERE name='i1';
} {}
do_intck_test 6.6.2 {}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 7.0 {
  CREATE TABLE x1("1", "22", "3333", four);
  CREATE INDEX i1 ON x1(  "1"  , "22", NULL);
  INSERT INTO x1 VALUES(1, 22, 3333, NULL);
  INSERT INTO x1 VALUES(1, 22, 3333, NULL);
}
do_execsql_test 7.1 " CREATE INDEX i2 ON x1(  \"1\"\r\n\t ) "
do_execsql_test 7.2 { CREATE INDEX i3 ON x1( "22" || 'abc''def' || `1` ) }
do_execsql_test 7.3 { CREATE INDEX i4 ON x1( [22] + [1] ) }
do_execsql_test 7.4 { CREATE INDEX i5 ON x1( four||'hello' ) }

do_intck_test 7.5 {}


finish_test
Added ext/intck/intck2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 Feb 19
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the incremental integrity check
# (intck) extension.
#

source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intck2
return_if_no_intck


do_execsql_test 1.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
  INSERT INTO t1 VALUES(1, 'one');
  INSERT INTO t1 VALUES(2, 'two');
  INSERT INTO t1 VALUES(3, 'three');
  CREATE INDEX i1 ON t1(b);
}

proc imposter_edit {obj create sql} {
  sqlite3 xdb test.db
  set pgno [xdb one {SELECT rootpage FROM sqlite_schema WHERE name=$obj}]

  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 1 $pgno
  xdb eval $create
  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 0 0
  xdb eval $sql
  xdb close
}

imposter_edit i1 {
  CREATE TABLE imp(b, a, PRIMARY KEY(b)) WITHOUT ROWID;
} {
  DELETE FROM imp WHERE b='two';
  INSERT INTO imp(b, a) VALUES('four', 4);
}

do_intck_test 1.1 {
  {surplus entry ('four',4) in index i1}
  {entry ('two',2) missing from index i1}
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
  CREATE TABLE x1(a, b, "c d");
  CREATE INDEX x1a ON x1(a COLLATE nocase DESC , b ASC);
  CREATE INDEX x1b ON x1( a || b || ' "''" ' COLLATE binary ASC );
  CREATE INDEX x1c ON x1( format('%s', a)ASC, format('%d', "c d" ) );
  INSERT INTO x1 VALUES('one', 2, 3);
  INSERT INTO x1 VALUES('One', 4, 5);
  INSERT INTO x1 VALUES('ONE', 6, 7);
  INSERT INTO x1 VALUES(NULL, NULL, NULL);
}

do_intck_test 2.1 {}

imposter_edit x1 {
  CREATE TABLE imp(a, b, c);
} {
  DELETE FROM imp WHERE c=7;
}
do_intck_test 2.2 {
  {surplus entry ('ONE',6,3) in index x1a}
  {surplus entry ('ONE6 "''" ',3) in index x1b}
  {surplus entry ('ONE','7',3) in index x1c}
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
  CREATE TABLE x1(a, b, c);
  CREATE INDEX x1all ON x1(a DESC, b ASC, c DESC);
  INSERT INTO x1 VALUES(2, 1, 2);
  INSERT INTO x1 VALUES(2, 1, 1);
  INSERT INTO x1 VALUES(2, 2, 2);
  INSERT INTO x1 VALUES(2, 2, 1);
  INSERT INTO x1 VALUES(1, 1, 2);
  INSERT INTO x1 VALUES(1, 1, 1);
  INSERT INTO x1 VALUES(1, 2, 2);
  INSERT INTO x1 VALUES(1, 2, 1);
}

do_intck_test 3.1 {
}

imposter_edit x1 {
  CREATE TABLE imp(a, b, c);
} {
  DELETE FROM imp WHERE 1;
}

db close
sqlite3 db test.db

do_intck_test 3.2 {
  {surplus entry (2,1,2,1) in index x1all} 
  {surplus entry (2,1,1,2) in index x1all}
  {surplus entry (2,2,2,3) in index x1all} 
  {surplus entry (2,2,1,4) in index x1all}
  {surplus entry (1,1,2,5) in index x1all} 
  {surplus entry (1,1,1,6) in index x1all} 
  {surplus entry (1,2,2,7) in index x1all}
  {surplus entry (1,2,1,8) in index x1all}
}

do_execsql_test 3.3 {
  DELETE FROM x1;
  INSERT INTO x1 VALUES(NULL, NULL, NULL);
  INSERT INTO x1 VALUES(NULL, NULL, NULL);
  INSERT INTO x1 VALUES(NULL, NULL, NULL);
  INSERT INTO x1 VALUES(NULL, NULL, NULL);
}

do_intck_test 3.4 {
}

imposter_edit x1 {
  CREATE TABLE imp(a, b, c);
} {
  DELETE FROM imp WHERE 1;
  INSERT INTO imp(rowid) VALUES(-123);
  INSERT INTO imp(rowid) VALUES(456);
}

db close
sqlite3 db test.db

do_intck_test 3.5 {
  {entry (NULL,NULL,NULL,-123) missing from index x1all}
  {entry (NULL,NULL,NULL,456) missing from index x1all}
  {surplus entry (NULL,NULL,NULL,1) in index x1all}
  {surplus entry (NULL,NULL,NULL,2) in index x1all}
  {surplus entry (NULL,NULL,NULL,3) in index x1all}
  {surplus entry (NULL,NULL,NULL,4) in index x1all}
}

reset_db

do_execsql_test 3.6 {
  CREATE TABLE w1(a PRIMARY KEY, b, c);
  INSERT INTO w1 VALUES(1.0, NULL, NULL);
  INSERT INTO w1 VALUES(33.0, NULL, NULL);
  INSERT INTO w1 VALUES(100.0, NULL, NULL);
  CREATE INDEX w1bc ON w1(b, c);
}

do_intck_test 3.7 {
}

imposter_edit w1 {
  CREATE TABLE imp(a, b, c);
} {
  DELETE FROM imp WHERE a=33;
  INSERT INTO imp(a) VALUES(1234.5);
  INSERT INTO imp(a) VALUES(-1234.5);
}

do_intck_test 3.8 {
  {surplus entry (33.0,2) in index sqlite_autoindex_w1_1}
  {entry (1234.5,4) missing from index sqlite_autoindex_w1_1} 
  {entry (NULL,NULL,4) missing from index w1bc} 
  {entry (-1234.5,5) missing from index sqlite_autoindex_w1_1} 
  {entry (NULL,NULL,5) missing from index w1bc} 
  {surplus entry (NULL,NULL,2) in index w1bc}
}

finish_test
Added ext/intck/intck_common.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 Feb 18
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl

ifcapable !vtab||!pragma {
  proc return_if_no_intck {} {
    finish_test
    return -code return
  }
  return
} else {
  proc return_if_no_intck {} {}
}

proc do_intck {db {bSuspend 0}} {
  set ic [sqlite3_intck $db main]

  set ret [list]
  while {"SQLITE_OK"==[$ic step]} {
    set msg [$ic message]
    if {$msg!=""} {
      lappend ret $msg
    }
    if {$bSuspend} { 
      $ic unlock 
      #puts "SQL: [$ic test_sql {}]"
      #execsql_pp "EXPLAIN query plan [$ic test_sql {}]"
      #explain_i [$ic test_sql {}]
    }
  }

  set err [$ic error]
  if {[lindex $err 0]!="SQLITE_OK"} {
    error $err
  }
  $ic close

  return $ret
}

proc intck_sql {db tbl} {
  set ic [sqlite3_intck $db main]
  set sql [$ic test_sql $tbl]
  $ic close
  return $sql
}

proc do_intck_test {tn expect} {
  uplevel [list do_test $tn.a [list do_intck db] [list {*}$expect]]
  uplevel [list do_test $tn.b [list do_intck db 1] [list {*}$expect]]
}


Added ext/intck/intckbusy.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 February 24
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intckbusy
return_if_no_intck



do_execsql_test 1.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
  INSERT INTO t1 VALUES(1, 2, 3);
  INSERT INTO t1 VALUES(2, 'two', 'three');
  INSERT INTO t1 VALUES(3, NULL, NULL);
  CREATE INDEX i1 ON t1(b, c);
}

sqlite3 db2 test.db

do_execsql_test -db db2 1.1 {
  BEGIN EXCLUSIVE;
    INSERT INTO t1 VALUES(4, 5, 6);
}

do_test 1.2 {
  set ic [sqlite3_intck db main]
  $ic step
} {SQLITE_BUSY}
do_test 1.3 {
  $ic unlock
} {SQLITE_BUSY}
do_test 1.4 {
  $ic error
} {SQLITE_BUSY {database is locked}}
do_test 1.4 {
  $ic close
} {}

finish_test

Added ext/intck/intckcorrupt.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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 Feb 21
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the intck extensions response
# to corruption at the b-tree level.
#

source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intckcorrupt
return_if_no_intck

#-------------------------------------------------------------------------
reset_db
do_test 1.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 356352 pagesize 4096 filename crash-acaae0347204ae.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 d0 00 00 00   .....@  ........
|     32: 40 00 ea 00 00 00 00 00 00 40 00 00 00 40 00 00   @........@...@..
|     96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f   ...............O
|    112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00   ................
|   3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17   ............^...
|   3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72   .....tablet1_par
|   3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45   entt1_parent.CRE
|   3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61   ATE TABLE .t1_pa
|   3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54   rent.(nodeno INT
|   3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59   EGER PRIMARY KEY
|   3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17   ,parentnode)Q...
|   3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65   ....tablet1_node
|   3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54   t1_node.CREATE T
|   3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e   ABLE .t1_node.(n
|   3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52   odeno INTEGER PR
|   3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c   IMARY KEY,data).
|   3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f   ........tablet1_
|   3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52   rowidt1_rowid.CR
|   3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72   EATE TABLE .t1_r
|   3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45   owid.(rowid INTE
|   3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c   GER PRIMARY KEY,
|   4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07   nodeno,a0,a1)Q..
|   4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43   ......tablet1t1C
|   4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41   REATE VIRTUAL TA
|   4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72   BLE t1 USING rtr
|   4064: 65 65 28 69 64 2c 78 30 20 50 52 49 4d 41 52 59   ee(id,x0 PRIMARY
|   4080: 20 4b 45 59 2c 70 61 72 65 6e 74 6e 6f 64 65 29    KEY,parentnode)
| page 2 offset 4096
|      0: 51 03 06 17 1b 1b 01 7b 74 61 62 6c 65 74 31 5f   Q.......tablet1_
|     16: 6e 6f 64 65 74 31 5f 6e 6f 64 65 03 43 52 45 41   nodet1_node.CREA
|     32: 54 45 20 54 41 42 4c 45 20 22 74 31 5f 6e 6f 64   TE TABLE .t1_nod
|     48: 65 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 45 47 45   e.(nodeno INTEGE
|     64: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61   R PRIMARY KEY,da
|     80: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c   ta).........tabl
|     96: 65 74 31 5f 72 6f 77 69 64 74 31 5f 72 6f 77 69   et1_rowidt1_rowi
|    112: 64 02 43 52 45 41 54 45 20 54 41 42 4c 45 00 00   d.CREATE TABLE..
|    128: 01 0a 02 00 00 00 01 0e 0d 00 00 00 00 24 0e 0d   .............$..
|    144: 0c 1a 06 85 50 46 60 27 70 08 00 00 00 00 00 00   ....PF`'p.......
|   3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f   ..............to
|   3840: 79 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74   y half.....#.bot
|   3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72   tom half.....!.r
|   3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00   ight half.......
|   3888: 6c 65 66 74 20 43 15 f6 e6 f6 46 50 34 35 24 54   left C....FP45$T
|   3904: 15 44 52 05 44 14 24 c4 52 02 27 43 15 f6 e6 f6   .DR.D.$.R.'C....
|   3920: 46 52 22 8e 6f 64 65 6e 6f 20 49 4e 54 45 47 45   FR..odeno INTEGE
|   3936: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61   R PRIMARY KEY,da
|   3952: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c   ta).........tabl
|   3968: 65 74 31 5f 72 6f 74 74 6f 6d 20 65 64 67 65 0f   et1_rottom edge.
|   3984: 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 65   ....!.right edge
|   4000: 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 65   .......left edge
|   4016: 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 05   .......center...
|   4032: 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 20   ..1.upper-right 
|   4048: 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f 77   corner.....1.low
|   4064: 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 16   er-right corner.
|   4080: 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 74   ..../.upper-left
| page 3 offset 8192
|      0: 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 01 8c 6f    corner...../..o
|     16: 77 65 72 2d 6c 53 51 4c 69 74 65 20 66 6f 72 6d   wer-lSQLite form
|     32: 61 74 20 33 00 10 00 01 01 00 40 20 20 00 00 00   at 3......@  ...
|     48: 00 00 00 00 2f 00 00 0d eb 13 00 00 00 03 00 00   ..../...........
|     64: 00 04 00 00 00 00 00 00 00 06 00 00 00 01 00 00   ................
|     80: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00   ................
| page 6 offset 20480
|    128: 00 00 00 00 00 00 00 00 97 3d 04 ae 7c 01 00 00   .........=..|...
|    624: 00 00 00 00 00 00 21 97 3d 04 ae 7c 01 00 00 00   ......!.=..|....
|   1120: 00 00 00 00 00 20 97 3d 04 ae 7c 01 00 00 00 00   ..... .=..|.....
|   1616: 00 00 00 00 1f 97 3d 04 ae 7c 01 00 00 00 00 00   ......=..|......
|   2112: 00 00 00 1e 97 3d 04 ae 7c 01 00 00 00 00 00 00   .....=..|.......
|   2608: 00 00 1d 97 d3 d0 4a e7 c0 00 00 00 00 00 00 00   ......J.........
|   3088: 00 00 00 00 00 00 00 00 00 00 00 00 01 f3 00 00   ................
|   3600: 23 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 00 00   #.=..|..........
|   4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26   ...............&
| page 8 offset 28672
|      0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00   ......0..0......
|   1072: 97 4d 1e 14 00 ae 7c 00 00 00 00 00 00 00 00 00   .M....|.........
|   1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00   ................
|   4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03   ................
| page 10 offset 36864
|      0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00   ......0..0......
|   1072: 9a ee c1 80 fd 78 1f ce 1b ae eb b4 00 00 00 00   .....x..........
|   1088: 13 20 ff 20 00 70 00 00 00 60 50 00 00 00 11 e0   . . .p...`P.....
|   1104: 00 00 00 70 00 00 00 60 50 05 35 14 c6 97 46 52   ...p...`P.5...FR
|   1120: 06 66 f7 26 d6 17 42 03 30 01 00 00 10 10 04 02   .f.&..B.0.......
|   1136: 02 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00   .........@......
|   1152: 00 00 00 00 00 40 00 00 00 40 00 00 00 00 00 00   .....@...@......
|   4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05   ................
| page 12 offset 45056
|      0: 0d 00 00 00 01 04 30 00 04 30 e1 b4 30 97 4d 46   ......0..0..0.MF
|     16: 14 00 ae 7c 00 00 00 00 00 00 00 03 00 00 43 00   ...|..........C.
| page 47 offset 188416
|   2512: 00 00 00 00 00 00 00 00 be 00 00 00 00 00 00 00   ................
| page 87 offset 352256
|   2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00   ................
| end crash-acaae0347204ae.db
}]} {}

do_intck_test 1.1 {
  {corruption found while reading database schema}
}

#-------------------------------------------------------------------------
reset_db
do_test 2.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 28672 pagesize 4096 filename crash-3afa1ca9e9c1bd.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07   .....@  ........
|     32: 00 00 00 00 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 0e 88 00 0f b8 0f 6d   ...............m
|    112: 0f 3a 0f 0b 0e d5 0e 88 01 00 00 00 00 00 00 00   .:..............
|   3712: 00 00 00 00 00 00 00 00 4b 06 06 17 25 25 01 5b   ........K...%%.[
|   3728: 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 74 61 74   tablesqlite_stat
|   3744: 31 73 71 6c 69 74 65 5f 73 74 61 74 31 07 43 52   1sqlite_stat1.CR
|   3760: 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c 69 74   EATE TABLE sqlit
|   3776: 65 5f 73 74 61 74 31 28 74 62 6c 2c 69 64 78 2c   e_stat1(tbl,idx,
|   3792: 73 74 61 74 29 34 05 06 17 13 11 01 53 69 6e 64   stat)4......Sind
|   3808: 65 78 63 31 63 63 31 06 43 52 45 41 54 45 20 55   exc1cc1.CREATE U
|   3824: 4e 49 51 55 45 20 49 4e 44 45 58 20 63 31 63 20   NIQUE INDEX c1c 
|   3840: 4f 4e 20 63 31 28 63 2c 20 62 29 2d 04 06 17 13   ON c1(c, b)-....
|   3856: 11 01 45 69 6e 64 65 78 63 31 64 63 31 05 43 52   ..Eindexc1dc1.CR
|   3872: 45 41 54 45 20 49 4e 44 45 58 20 63 31 64 20 4f   EATE INDEX c1d O
|   3888: 4e 20 63 31 28 64 2c 20 62 29 31 03 06 17 13 11   N c1(d, b)1.....
|   3904: 01 4d 69 6e 64 65 78 62 31 63 62 31 05 43 52 45   .Mindexb1cb1.CRE
|   3920: 41 54 45 20 55 4e 49 51 55 45 20 49 4e 44 45 58   ATE UNIQUE INDEX
|   3936: 20 62 31 63 20 4f 4e 20 62 31 28 63 29 49 02 06    b1c ON b1(c)I..
|   3952: 17 11 11 0f 7f 74 61 62 6c 65 63 31 63 31 03 43   .....tablec1c1.C
|   3968: 52 45 41 54 45 20 54 41 42 4c 45 20 63 31 28 61   REATE TABLE c1(a
|   3984: 20 49 4e 54 20 50 52 49 4d 41 52 59 20 4b 45 59    INT PRIMARY KEY
|   4000: 2c 20 62 2c 20 63 2c 20 64 29 20 57 49 54 48 4f   , b, c, d) WITHO
|   4016: 55 54 20 52 4f 57 49 44 46 01 06 17 11 11 01 79   UT ROWIDF......y
|   4032: 74 61 62 6c 65 62 31 62 31 02 43 52 45 41 54 45   tableb1b1.CREATE
|   4048: 20 54 41 42 4c 45 20 62 31 28 61 20 49 4e 54 20    TABLE b1(a INT 
|   4064: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 2c 20   PRIMARY KEY, b, 
|   4080: 63 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44   c) WITHOUT ROWID
| page 2 offset 4096
|      0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f e2   ................
|     16: 0f da 00 00 00 01 00 00 00 00 00 00 00 00 00 00   ................
|   4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 06   ................
|   4048: 67 07 07 04 01 0f 01 06 66 06 07 04 01 0f 01 05   g.......f.......
|   4064: 65 05 07 04 01 0f 01 04 64 04 07 04 01 0f 01 03   e.......d.......
|   4080: 63 03 07 04 01 0f 01 02 62 0f 05 04 09 0f 09 61   c.......b......a
| page 3 offset 8192
|      0: 0a 00 00 00 07 0f bd 00 0f f9 0f ef 0f e5 0f db   ................
|     16: 0f d1 0f c7 0f bd 00 00 00 00 01 00 00 00 00 00   ................
|   4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 09 05 01   ................
|   4032: 0f 01 01 07 61 07 07 09 05 01 0f 01 01 06 61 06   ....a.........a.
|   4048: 06 09 05 01 0f 01 01 05 61 05 05 09 05 01 0f 01   ........a.......
|   4064: 01 04 61 04 04 09 05 01 0f 01 01 03 61 03 03 09   ..a.........a...
|   4080: 05 01 0f 01 01 02 61 0f 02 06 05 09 0f 09 09 61   ......a........a
| page 4 offset 12288
|      0: 0a 00 00 00 07 0f d8 00 0f fc 0f f0 0f ea 0f e4   ................
|     16: 0f de 0f d8 0f f6 00 00 00 00 00 00 00 00 00 00   ................
|   4048: 00 00 00 00 00 00 00 00 05 03 01 01 07 07 05 03   ................
|   4064: 01 01 06 06 05 03 01 01 05 05 05 03 01 01 04 04   ................
|   4080: 05 03 01 01 03 03 05 03 01 01 0f 02 03 03 09 09   ................
| page 5 offset 16384
|      0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f 00   ................
|   4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07   ................
|   4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05   a.......a.......
|   4064: 61 05 07 04 01 1f 01 04 61 04 07 04 01 0f 01 03   a.......a.......
|   4080: 61 03 07 04 01 0f 01 02 61 02 05 04 09 0f 09 61   a.......a......a
| page 6 offset 20480
|      0: 0a 00 00 00 07 0f ca 00 0f fa 0f ea 0f e2 00 00   ................
|   4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07   ................
|   4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05   a.......a.......
|   4064: 61 05 07 04 01 0f 01 04 61 04 07 04 01 0f 01 03   a.......a.......
|   4080: 61 03 07 04 01 0f 01 0f 61 02 05 04 09 0f 09 61   a.......a......a
| page 7 offset 24576
|      0: 0d 00 00 00 05 0f 1c 00 0f f0 0f e0 0f d3 0f c5   ................
|     16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
|   4016: 00 00 00 00 00 00 00 00 0b 05 04 11 11 13 62 31   ..............b1
|   4032: 62 31 37 20 31 0c 04 04 11 13 13 62 31 62 31 63   b17 1......b1b1c
|   4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31   7 1......c1c17 1
|   4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31   ......c1c1d7 1 1
|   4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00   ......c1c1c7 1..
| end crash-3afa1ca9e9c1bd.db
}]} {}

do_intck_test 2.1 {
  {corruption found while reading database schema}
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
  PRAGMA page_size = 1024;
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
  INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 3);
}

do_test 3.1 {
  set pgno [db one {SELECT rootpage FROM sqlite_schema WHERE name='t1'}]
  db close
  hexio_write test.db [expr ($pgno-1)*1024] 0000
} {2}

sqlite3 db test.db
do_intck_test 3.2 {
  {corruption found while scanning database object i1}
  {corruption found while scanning database object t1}
}

finish_test


Added ext/intck/intckfault.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 February 24
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intckfault
return_if_no_intck

do_execsql_test 1.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
  INSERT INTO t1 VALUES(1, 2, 3);
  INSERT INTO t1 VALUES(2, 'two', 'three');
  INSERT INTO t1 VALUES(3, NULL, NULL);
  CREATE INDEX i1 ON t1(b, c);
}

do_faultsim_test 1 -faults oom-t* -prep {
} -body {
  set ::ic [sqlite3_intck db main]
  set nStep 0
  while {"SQLITE_OK"==[$::ic step]} {
    incr nStep
    if {$nStep==3} { $::ic unlock }
  }
  set res [$::ic error]
  $::ic close
  set res
} -test {
  catch { $::ic close }
  faultsim_test_result {0 {SQLITE_OK {}}} {0 {SQLITE_NOMEM {}}} {0 {SQLITE_NOMEM {out of memory}}}
}

finish_test

Added ext/intck/sqlite3intck.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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2024-02-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.
**
*************************************************************************
*/

#include "sqlite3intck.h"
#include <string.h>
#include <assert.h>

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

/*
** nKeyVal:
**   The number of values that make up the 'key' for the current pCheck
**   statement.
**
** rc:
**   Error code returned by most recent sqlite3_intck_step() or 
**   sqlite3_intck_unlock() call. This is set to SQLITE_DONE when
**   the integrity-check operation is finished.
**
** zErr:
**   If the object has entered the error state, this is the error message.
**   Is freed using sqlite3_free() when the object is deleted.
**
** zTestSql:
**   The value returned by the most recent call to sqlite3_intck_testsql().
**   Each call to testsql() frees the previous zTestSql value (using
**   sqlite3_free()) and replaces it with the new value it will return.
*/
struct sqlite3_intck {
  sqlite3 *db;
  const char *zDb;                /* Copy of zDb parameter to _open() */
  char *zObj;                     /* Current object. Or NULL. */

  sqlite3_stmt *pCheck;           /* Current check statement */
  char *zKey;
  int nKeyVal;

  char *zMessage;
  int bCorruptSchema;

  int rc;                         /* Error code */
  char *zErr;                     /* Error message */
  char *zTestSql;                 /* Returned by sqlite3_intck_test_sql() */
};


/*
** Some error has occurred while using database p->db. Save the error message
** and error code currently held by the database handle in p->rc and p->zErr.
*/
static void intckSaveErrmsg(sqlite3_intck *p){
  p->rc = sqlite3_errcode(p->db);
  sqlite3_free(p->zErr);
  p->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
}

/*
** If the handle passed as the first argument is already in the error state,
** then this function is a no-op (returns NULL immediately). Otherwise, if an
** error occurs within this function, it leaves an error in said handle.
**
** Otherwise, this function attempts to prepare SQL statement zSql and
** return the resulting statement handle to the user.
*/
static sqlite3_stmt *intckPrepare(sqlite3_intck *p, const char *zSql){
  sqlite3_stmt *pRet = 0;
  if( p->rc==SQLITE_OK ){
    p->rc = sqlite3_prepare_v2(p->db, zSql, -1, &pRet, 0);
    if( p->rc!=SQLITE_OK ){
      intckSaveErrmsg(p);
      assert( pRet==0 );
    }
  }
  return pRet;
}

/*
** If the handle passed as the first argument is already in the error state,
** then this function is a no-op (returns NULL immediately). Otherwise, if an
** error occurs within this function, it leaves an error in said handle.
**
** Otherwise, this function treats argument zFmt as a printf() style format
** string. It formats it according to the trailing arguments and then 
** attempts to prepare the results and return the resulting prepared
** statement.
*/
static sqlite3_stmt *intckPrepareFmt(sqlite3_intck *p, const char *zFmt, ...){
  sqlite3_stmt *pRet = 0;
  va_list ap;
  char *zSql = 0;
  va_start(ap, zFmt);
  zSql = sqlite3_vmprintf(zFmt, ap);
  if( p->rc==SQLITE_OK && zSql==0 ){
    p->rc = SQLITE_NOMEM;
  }
  pRet = intckPrepare(p, zSql);
  sqlite3_free(zSql);
  va_end(ap);
  return pRet;
}

/*
** Finalize SQL statement pStmt. If an error occurs and the handle passed
** as the first argument does not already contain an error, store the
** error in the handle.
*/
static void intckFinalize(sqlite3_intck *p, sqlite3_stmt *pStmt){
  int rc = sqlite3_finalize(pStmt);
  if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
    intckSaveErrmsg(p);
  }
}

/*
** If there is already an error in handle p, return it. Otherwise, call
** sqlite3_step() on the statement handle and return that value.
*/
static int intckStep(sqlite3_intck *p, sqlite3_stmt *pStmt){
  if( p->rc ) return p->rc;
  return sqlite3_step(pStmt);
}

/*
** Execute SQL statement zSql. There is no way to obtain any results 
** returned by the statement. This function uses the sqlite3_intck error
** code convention.
*/
static void intckExec(sqlite3_intck *p, const char *zSql){
  sqlite3_stmt *pStmt = 0;
  pStmt = intckPrepare(p, zSql);
  intckStep(p, pStmt);
  intckFinalize(p, pStmt);
}

/*
** A wrapper around sqlite3_mprintf() that uses the sqlite3_intck error
** code convention.
*/
static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){
  va_list ap;
  char *zRet = 0;
  va_start(ap, zFmt);
  zRet = sqlite3_vmprintf(zFmt, ap);
  if( p->rc==SQLITE_OK ){
    if( zRet==0 ){
      p->rc = SQLITE_NOMEM;
    }
  }else{
    sqlite3_free(zRet);
    zRet = 0;
  }
  return zRet;
}

/*
** This is used by sqlite3_intck_unlock() to save the vector key value 
** required to restart the current pCheck query as a nul-terminated string 
** in p->zKey.
*/
static void intckSaveKey(sqlite3_intck *p){
  int ii;
  char *zSql = 0;
  sqlite3_stmt *pStmt = 0;
  sqlite3_stmt *pXinfo = 0;
  const char *zDir = 0;

  assert( p->pCheck );
  assert( p->zKey==0 );

  pXinfo = intckPrepareFmt(p, 
      "SELECT group_concat(desc, '') FROM %Q.sqlite_schema s, "
      "pragma_index_xinfo(%Q, %Q) "
      "WHERE s.type='index' AND s.name=%Q",
      p->zDb, p->zObj, p->zDb, p->zObj
  );
  if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXinfo) ){
    zDir = (const char*)sqlite3_column_text(pXinfo, 0);
  }

  if( zDir==0 ){
    /* Object is a table, not an index. This is the easy case,as there are 
    ** no DESC columns or NULL values in a primary key.  */
    const char *zSep = "SELECT '(' || ";
    for(ii=0; ii<p->nKeyVal; ii++){
      zSql = intckMprintf(p, "%z%squote(?)", zSql, zSep);
      zSep = " || ', ' || ";
    }
    zSql = intckMprintf(p, "%z || ')'", zSql);
  }else{

    /* Object is an index. */
    assert( p->nKeyVal>1 );
    for(ii=p->nKeyVal; ii>0; ii--){
      int bLastIsDesc = zDir[ii-1]=='1';
      int bLastIsNull = sqlite3_column_type(p->pCheck, ii)==SQLITE_NULL;
      const char *zLast = sqlite3_column_name(p->pCheck, ii);
      char *zLhs = 0;
      char *zRhs = 0;
      char *zWhere = 0;

      if( bLastIsNull ){
        if( bLastIsDesc ) continue;
        zWhere = intckMprintf(p, "'%s IS NOT NULL'", zLast);
      }else{
        const char *zOp = bLastIsDesc ? "<" : ">";
        zWhere = intckMprintf(p, "'%s %s ' || quote(?%d)", zLast, zOp, ii);
      }

      if( ii>1 ){
        const char *zLhsSep = "";
        const char *zRhsSep = "";
        int jj;
        for(jj=0; jj<ii-1; jj++){
          const char *zAlias = (const char*)sqlite3_column_name(p->pCheck,jj+1);
          zLhs = intckMprintf(p, "%z%s%s", zLhs, zLhsSep, zAlias);
          zRhs = intckMprintf(p, "%z%squote(?%d)", zRhs, zRhsSep, jj+1);
          zLhsSep = ",";
          zRhsSep = " || ',' || ";
        }

        zWhere = intckMprintf(p, 
            "'(%z) IS (' || %z || ') AND ' || %z",
            zLhs, zRhs, zWhere);
      }
      zWhere = intckMprintf(p, "'WHERE ' || %z", zWhere);

      zSql = intckMprintf(p, "%z%s(quote( %z ) )",
          zSql,
          (zSql==0 ? "VALUES" : ",\n      "),
          zWhere
      );
    }
    zSql = intckMprintf(p, 
        "WITH wc(q) AS (\n%z\n)"
        "SELECT 'VALUES' || group_concat('(' || q || ')', ',\n      ') FROM wc"
        , zSql
    );
  }

  pStmt = intckPrepare(p, zSql);
  if( p->rc==SQLITE_OK ){
    for(ii=0; ii<p->nKeyVal; ii++){
      sqlite3_bind_value(pStmt, ii+1, sqlite3_column_value(p->pCheck, ii+1));
    }
    if( SQLITE_ROW==sqlite3_step(pStmt) ){
      p->zKey = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
    }
    intckFinalize(p, pStmt);
  }

  sqlite3_free(zSql);
  intckFinalize(p, pXinfo);
}

/*
** Find the next database object (table or index) to check. If successful,
** set sqlite3_intck.zObj to point to a nul-terminated buffer containing
** the object's name before returning.
*/
static void intckFindObject(sqlite3_intck *p){
  sqlite3_stmt *pStmt = 0;
  char *zPrev = p->zObj;
  p->zObj = 0;

  assert( p->rc==SQLITE_OK );
  assert( p->pCheck==0 );

  pStmt = intckPrepareFmt(p, 
    "WITH tables(table_name) AS (" 
    "  SELECT name"
    "  FROM %Q.sqlite_schema WHERE (type='table' OR type='index') AND rootpage"
    "  UNION ALL "
    "  SELECT 'sqlite_schema'"
    ")"
    "SELECT table_name FROM tables "
    "WHERE ?1 IS NULL OR table_name%s?1 "
    "ORDER BY 1"
    , p->zDb, (p->zKey ? ">=" : ">")
  );

  if( p->rc==SQLITE_OK ){
    sqlite3_bind_text(pStmt, 1, zPrev, -1, SQLITE_TRANSIENT);
    if( sqlite3_step(pStmt)==SQLITE_ROW ){
      p->zObj = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
    }
  }
  intckFinalize(p, pStmt);

  /* If this is a new object, ensure the previous key value is cleared. */
  if( sqlite3_stricmp(p->zObj, zPrev) ){
    sqlite3_free(p->zKey);
    p->zKey = 0;
  }

  sqlite3_free(zPrev);
}

/*
** Return the size in bytes of the first token in nul-terminated buffer z.
** For the purposes of this call, a token is either:
**
**   *  a quoted SQL string,
*    *  a contiguous series of ascii alphabet characters, or
*    *  any other single byte.
*/
static int intckGetToken(const char *z){
  char c = z[0];
  int iRet = 1;
  if( c=='\'' || c=='"' || c=='`' ){
    while( 1 ){
      if( z[iRet]==c ){
        iRet++;
        if( z[iRet]!=c ) break;
      }
      iRet++;
    }
  }
  else if( c=='[' ){
    while( z[iRet++]!=']' && z[iRet] );
  }
  else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){
    while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){
      iRet++;
    }
  }

  return iRet;
}

/*
** Return true if argument c is an ascii whitespace character.
*/
static int intckIsSpace(char c){
  return (c==' ' || c=='\t' || c=='\n' || c=='\r');
}

/*
** Argument z points to the text of a CREATE INDEX statement. This function
** identifies the part of the text that contains either the index WHERE 
** clause (if iCol<0) or the iCol'th column of the index.
**
** If (iCol<0), the identified fragment does not include the "WHERE" keyword,
** only the expression that follows it. If (iCol>=0) then the identified
** fragment does not include any trailing sort-order keywords - "ASC" or 
** "DESC".
**
** If the CREATE INDEX statement does not contain the requested field or
** clause, NULL is returned and (*pnByte) is set to 0. Otherwise, a pointer to
** the identified fragment is returned and output parameter (*pnByte) set
** to its size in bytes.
*/
static const char *intckParseCreateIndex(const char *z, int iCol, int *pnByte){
  int iOff = 0;
  int iThisCol = 0;
  int iStart = 0;
  int nOpen = 0;

  const char *zRet = 0;
  int nRet = 0;

  int iEndOfCol = 0;

  /* Skip forward until the first "(" token */
  while( z[iOff]!='(' ){
    iOff += intckGetToken(&z[iOff]);
    if( z[iOff]=='\0' ) return 0;
  }
  assert( z[iOff]=='(' );

  nOpen = 1;
  iOff++;
  iStart = iOff;
  while( z[iOff] ){
    const char *zToken = &z[iOff];
    int nToken = 0;

    /* Check if this is the end of the current column - either a "," or ")"
    ** when nOpen==1.  */
    if( nOpen==1 ){
      if( z[iOff]==',' || z[iOff]==')' ){
        if( iCol==iThisCol ){
          int iEnd = iEndOfCol ? iEndOfCol : iOff;
          nRet = (iEnd - iStart);
          zRet = &z[iStart];
          break;
        }
        iStart = iOff+1;
        while( intckIsSpace(z[iStart]) ) iStart++;
        iThisCol++;
      }
      if( z[iOff]==')' ) break;
    }
    if( z[iOff]=='(' ) nOpen++;
    if( z[iOff]==')' ) nOpen--;
    nToken = intckGetToken(zToken);

    if( (nToken==3 && 0==sqlite3_strnicmp(zToken, "ASC", nToken))
     || (nToken==4 && 0==sqlite3_strnicmp(zToken, "DESC", nToken))
    ){
      iEndOfCol = iOff;
    }else if( 0==intckIsSpace(zToken[0]) ){
      iEndOfCol = 0;
    }

    iOff += nToken;
  }

  /* iStart is now the byte offset of 1 byte passed the final ')' in the
  ** CREATE INDEX statement. Try to find a WHERE clause to return.  */
  while( zRet==0 && z[iOff] ){
    int n = intckGetToken(&z[iOff]);
    if( n==5 && 0==sqlite3_strnicmp(&z[iOff], "where", 5) ){
      zRet = &z[iOff+5];
      nRet = (int)strlen(zRet);
    }
    iOff += n;
  }

  /* Trim any whitespace from the start and end of the returned string. */
  if( zRet ){
    while( intckIsSpace(zRet[0]) ){
      nRet--;
      zRet++;
    }
    while( nRet>0 && intckIsSpace(zRet[nRet-1]) ) nRet--;
  }

  *pnByte = nRet;
  return zRet;
}

/*
** User-defined SQL function wrapper for intckParseCreateIndex():
**
**     SELECT parse_create_index(<sql>, <icol>);
*/
static void intckParseCreateIndexFunc(
  sqlite3_context *pCtx, 
  int nVal, 
  sqlite3_value **apVal
){
  const char *zSql = (const char*)sqlite3_value_text(apVal[0]);
  int idx = sqlite3_value_int(apVal[1]);
  const char *zRes = 0;
  int nRes = 0;

  assert( nVal==2 );
  if( zSql ){
    zRes = intckParseCreateIndex(zSql, idx, &nRes);
  }
  sqlite3_result_text(pCtx, zRes, nRes, SQLITE_TRANSIENT);
}

/*
** Return true if sqlite3_intck.db has automatic indexes enabled, false
** otherwise.
*/
static int intckGetAutoIndex(sqlite3_intck *p){
  int bRet = 0;
  sqlite3_stmt *pStmt = 0;
  pStmt = intckPrepare(p, "PRAGMA automatic_index");
  if( SQLITE_ROW==intckStep(p, pStmt) ){
    bRet = sqlite3_column_int(pStmt, 0);
  }
  intckFinalize(p, pStmt);
  return bRet;
}

/*
** Return true if zObj is an index, or false otherwise.
*/
static int intckIsIndex(sqlite3_intck *p, const char *zObj){
  int bRet = 0;
  sqlite3_stmt *pStmt = 0;
  pStmt = intckPrepareFmt(p, 
      "SELECT 1 FROM %Q.sqlite_schema WHERE name=%Q AND type='index'",
      p->zDb, zObj
  );
  if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    bRet = 1;
  }
  intckFinalize(p, pStmt);
  return bRet;
}

/*
** Return a pointer to a nul-terminated buffer containing the SQL statement
** used to check database object zObj (a table or index) for corruption.
** If parameter zPrev is not NULL, then it must be a string containing the
** vector key required to restart the check where it left off last time.
** If pnKeyVal is not NULL, then (*pnKeyVal) is set to the number of
** columns in the vector key value for the specified object.
**
** This function uses the sqlite3_intck error code convention.
*/
static char *intckCheckObjectSql(
  sqlite3_intck *p,               /* Integrity check object */
  const char *zObj,               /* Object (table or index) to scan */
  const char *zPrev,              /* Restart key vector, if any */
  int *pnKeyVal                   /* OUT: Number of key-values for this scan */
){
  char *zRet = 0;
  sqlite3_stmt *pStmt = 0;
  int bAutoIndex = 0;
  int bIsIndex = 0;

  const char *zCommon = 
      /* Relation without_rowid also contains just one row. Column "b" is
      ** set to true if the table being examined is a WITHOUT ROWID table,
      ** or false otherwise.  */
      ", without_rowid(b) AS ("
      "  SELECT EXISTS ("
      "    SELECT 1 FROM tabname, pragma_index_list(tab, db) AS l"
      "      WHERE origin='pk' "
      "      AND NOT EXISTS (SELECT 1 FROM sqlite_schema WHERE name=l.name)"
      "  )"
      ")"
      ""
      /* Table idx_cols contains 1 row for each column in each index on the
      ** table being checked. Columns are:
      **
      **   idx_name: Name of the index.
      **   idx_ispk: True if this index is the PK of a WITHOUT ROWID table.
      **   col_name: Name of indexed column, or NULL for index on expression.
      **   col_expr: Indexed expression, including COLLATE clause.
      **   col_alias: Alias used for column in 'intck_wrapper' table.
      */
      ", idx_cols(idx_name, idx_ispk, col_name, col_expr, col_alias) AS ("
      "  SELECT l.name, (l.origin=='pk' AND w.b), i.name, COALESCE(("
      "    SELECT parse_create_index(sql, i.seqno) FROM "
      "    sqlite_schema WHERE name = l.name"
      "  ), format('\"%w\"', i.name) || ' COLLATE ' || quote(i.coll)),"
      "  'c' || row_number() OVER ()"
      "  FROM "
      "      tabname t,"
      "      without_rowid w,"
      "      pragma_index_list(t.tab, t.db) l,"
      "      pragma_index_xinfo(l.name) i"
      "      WHERE i.key"
      "  UNION ALL"
      "  SELECT '', 1, '_rowid_', '_rowid_', 'r1' FROM without_rowid WHERE b=0"
      ")"
      ""
      ""
      /*
      ** For a PK declared as "PRIMARY KEY(a, b) ... WITHOUT ROWID", where
      ** the intck_wrapper aliases of "a" and "b" are "c1" and "c2":
      **
      **   o_pk:   "o.c1, o.c2"
      **   i_pk:   "i.'a', i.'b'"
      **   ...
      **   n_pk:   2
      */ 
      ", tabpk(db, tab, idx, o_pk, i_pk, q_pk, eq_pk, ps_pk, pk_pk, n_pk) AS ("
      "    WITH pkfields(f, a) AS ("
      "      SELECT i.col_name, i.col_alias FROM idx_cols i WHERE i.idx_ispk"
      "    )"
      "    SELECT t.db, t.tab, t.idx, "
      "           group_concat(a, ', '), "
      "           group_concat('i.'||quote(f), ', '), "
      "           group_concat('quote(o.'||a||')', ' || '','' || '),  "
      "           format('(%s)==(%s)',"
      "               group_concat('o.'||a, ', '), "
      "               group_concat(format('\"%w\"', f), ', ')"
      "           ),"
      "           group_concat('%s', ','),"
      "           group_concat('quote('||a||')', ', '),  "
      "           count(*)"
      "    FROM tabname t, pkfields"
      ")"
      ""
      ", idx(name, match_expr, partial, partial_alias, idx_ps, idx_idx) AS ("
      "  SELECT idx_name,"
      "    format('(%s,%s) IS (%s,%s)', "
      "           group_concat(i.col_expr, ', '), i_pk,"
      "           group_concat('o.'||i.col_alias, ', '), o_pk"
      "    ), "
      "    parse_create_index("
      "        (SELECT sql FROM sqlite_schema WHERE name=idx_name), -1"
      "    ),"
      "    'cond' || row_number() OVER ()"
      "    , group_concat('%s', ',')"
      "    , group_concat('quote('||i.col_alias||')', ', ')"
      "  FROM tabpk t, "
      "       without_rowid w,"
      "       idx_cols i"
      "  WHERE i.idx_ispk==0 "
      "  GROUP BY idx_name"
      ")"
      ""
      ", wrapper_with(s) AS ("
      "  SELECT 'intck_wrapper AS (\n  SELECT\n    ' || ("
      "      WITH f(a, b) AS ("
      "        SELECT col_expr, col_alias FROM idx_cols"
      "          UNION ALL "
      "        SELECT partial, partial_alias FROM idx WHERE partial IS NOT NULL"
      "      )"
      "      SELECT group_concat(format('%s AS %s', a, b), ',\n    ') FROM f"
      "    )"
      "    || format('\n  FROM %Q.%Q ', t.db, t.tab)"
           /* If the object being checked is a table, append "NOT INDEXED".
           ** Otherwise, append "INDEXED BY <index>", and then, if the index 
           ** is a partial index " WHERE <condition>".  */
      "    || CASE WHEN t.idx IS NULL THEN "
      "        'NOT INDEXED'"
      "       ELSE"
      "        format('INDEXED BY %Q%s', t.idx, ' WHERE '||i.partial)"
      "       END"
      "    || '\n)'"
      "    FROM tabname t LEFT JOIN idx i ON (i.name=t.idx)"
      ")"
      ""
  ;

  bAutoIndex = intckGetAutoIndex(p);
  if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 0");

  bIsIndex = intckIsIndex(p, zObj);
  if( bIsIndex ){
    pStmt = intckPrepareFmt(p,
      /* Table idxname contains a single row. The first column, "db", contains
      ** the name of the db containing the table (e.g. "main") and the second,
      ** "tab", the name of the table itself.  */
      "WITH tabname(db, tab, idx) AS ("
      "  SELECT %Q, (SELECT tbl_name FROM %Q.sqlite_schema WHERE name=%Q), %Q "
      ")"
      ""
      ", whereclause(w_c) AS (%s)"
      ""
      "%s" /* zCommon */
      ""
      ", case_statement(c) AS ("
      "  SELECT "
      "    'CASE WHEN (' || group_concat(col_alias, ', ') || ', 1) IS (\n' "
      "    || '      SELECT ' || group_concat(col_expr, ', ') || ', 1 FROM '"
      "    || format('%%Q.%%Q NOT INDEXED WHERE %%s\n', t.db, t.tab, p.eq_pk)"
      "    || '    )\n  THEN NULL\n    '"
      "    || 'ELSE format(''surplus entry ('"
      "    ||   group_concat('%%s', ',') || ',' || p.ps_pk"
      "    || ') in index ' || t.idx || ''', ' "
      "    ||   group_concat('quote('||i.col_alias||')', ', ') || ', ' || p.pk_pk"
      "    || ')'"
      "    || '\n  END AS error_message'"
      "  FROM tabname t, tabpk p, idx_cols i WHERE i.idx_name=t.idx"
      ")"
      ""
      ", thiskey(k, n) AS ("
      "    SELECT group_concat(i.col_alias, ', ') || ', ' || p.o_pk, "
      "           count(*) + p.n_pk "
      "    FROM tabpk p, idx_cols i WHERE i.idx_name=p.idx"
      ")"
      ""
      ", main_select(m, n) AS ("
      "  SELECT format("
      "      'WITH %%s\n' ||"
      "      ', idx_checker AS (\n' ||"
      "      '  SELECT %%s,\n' ||"
      "      '  %%s\n' || "
      "      '  FROM intck_wrapper AS o\n' ||"
      "      ')\n',"
      "      ww.s, c, t.k"
      "  ), t.n"
      "  FROM case_statement, wrapper_with ww, thiskey t"
      ")"

      "SELECT m || "
      "    group_concat('SELECT * FROM idx_checker ' || w_c, ' UNION ALL '), n"
      " FROM "
      "main_select, whereclause "
      , p->zDb, p->zDb, zObj, zObj
      , zPrev ? zPrev : "VALUES('')", zCommon
      );
  }else{
    pStmt = intckPrepareFmt(p,
      /* Table tabname contains a single row. The first column, "db", contains
      ** the name of the db containing the table (e.g. "main") and the second,
      ** "tab", the name of the table itself.  */
      "WITH tabname(db, tab, idx, prev) AS (SELECT %Q, %Q, NULL, %Q)"
      ""
      "%s" /* zCommon */

      /* expr(e) contains one row for each index on table zObj. Value e
      ** is set to an expression that evaluates to NULL if the required
      ** entry is present in the index, or an error message otherwise.  */
      ", expr(e, p) AS ("
      "  SELECT format('CASE WHEN EXISTS \n"
      "    (SELECT 1 FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n"
      "    THEN NULL\n"
      "    ELSE format(''entry (%%s,%%s) missing from index %%s'', %%s, %%s)\n"
      "  END\n'"
      "    , t.db, t.tab, i.name, i.match_expr, ' AND (' || partial || ')',"
      "      i.idx_ps, t.ps_pk, i.name, i.idx_idx, t.pk_pk),"
      "    CASE WHEN partial IS NULL THEN NULL ELSE i.partial_alias END"
      "  FROM tabpk t, idx i"
      ")"

      ", numbered(ii, cond, e) AS ("
      "  SELECT 0, 'n.ii=0', 'NULL'"
      "    UNION ALL "
      "  SELECT row_number() OVER (),"
      "      '(n.ii='||row_number() OVER ()||COALESCE(' AND '||p||')', ')'), e"
      "  FROM expr"
      ")"

      ", counter_with(w) AS ("
      "    SELECT 'WITH intck_counter(ii) AS (\n  ' || "
      "       group_concat('SELECT '||ii, ' UNION ALL\n  ') "
      "    || '\n)' FROM numbered"
      ")"
      ""
      ", case_statement(c) AS ("
      "    SELECT 'CASE ' || "
      "    group_concat(format('\n  WHEN %%s THEN (%%s)', cond, e), '') ||"
      "    '\nEND AS error_message'"
      "    FROM numbered"
      ")"
      ""

      /* This table contains a single row consisting of a single value -
      ** the text of an SQL expression that may be used by the main SQL
      ** statement to output an SQL literal that can be used to resume
      ** the scan if it is suspended. e.g. for a rowid table, an expression
      ** like:
      **
      **     format('(%d,%d)', _rowid_, n.ii)
      */
      ", thiskey(k, n) AS ("
      "    SELECT o_pk || ', ii', n_pk+1 FROM tabpk"
      ")"
      ""
      ", whereclause(w_c) AS ("
      "    SELECT CASE WHEN prev!='' THEN "
      "    '\nWHERE (' || o_pk ||', n.ii) > ' || prev"
      "    ELSE ''"
      "    END"
      "    FROM tabpk, tabname"
      ")"
      ""
      ", main_select(m, n) AS ("
      "  SELECT format("
      "      '%%s, %%s\nSELECT %%s,\n%%s\nFROM intck_wrapper AS o"
               ", intck_counter AS n%%s\nORDER BY %%s', "
      "      w, ww.s, c, thiskey.k, whereclause.w_c, t.o_pk"
      "  ), thiskey.n"
      "  FROM case_statement, tabpk t, counter_with, "
      "       wrapper_with ww, thiskey, whereclause"
      ")"

      "SELECT m, n FROM main_select",
      p->zDb, zObj, zPrev, zCommon
    );
  }

  while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    zRet = intckMprintf(p, "%s", (const char*)sqlite3_column_text(pStmt, 0));
    if( pnKeyVal ){
      *pnKeyVal = sqlite3_column_int(pStmt, 1);
    }
  }
  intckFinalize(p, pStmt);

  if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1");
  return zRet;
}

/*
** Open a new integrity-check object.
*/
int sqlite3_intck_open(
  sqlite3 *db,                    /* Database handle to operate on */
  const char *zDbArg,             /* "main", "temp" etc. */
  sqlite3_intck **ppOut           /* OUT: New integrity-check handle */
){
  sqlite3_intck *pNew = 0;
  int rc = SQLITE_OK;
  const char *zDb = zDbArg ? zDbArg : "main";
  int nDb = (int)strlen(zDb);

  pNew = (sqlite3_intck*)sqlite3_malloc(sizeof(*pNew) + nDb + 1);
  if( pNew==0 ){
    rc = SQLITE_NOMEM;
  }else{
    memset(pNew, 0, sizeof(*pNew));
    pNew->db = db;
    pNew->zDb = (const char*)&pNew[1];
    memcpy(&pNew[1], zDb, nDb+1);
    rc = sqlite3_create_function(db, "parse_create_index", 
        2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0
    );
    if( rc!=SQLITE_OK ){
      sqlite3_intck_close(pNew);
      pNew = 0;
    }
  }

  *ppOut = pNew;
  return rc;
}

/*
** Free the integrity-check object.
*/
void sqlite3_intck_close(sqlite3_intck *p){
  if( p ){
    sqlite3_finalize(p->pCheck);
    sqlite3_create_function(
        p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0
    );
    sqlite3_free(p->zObj);
    sqlite3_free(p->zKey);
    sqlite3_free(p->zTestSql);
    sqlite3_free(p->zErr);
    sqlite3_free(p->zMessage);
    sqlite3_free(p);
  }
}

/*
** Step the integrity-check object.
*/
int sqlite3_intck_step(sqlite3_intck *p){
  if( p->rc==SQLITE_OK ){

    if( p->zMessage ){
      sqlite3_free(p->zMessage);
      p->zMessage = 0;
    }

    if( p->bCorruptSchema ){
      p->rc = SQLITE_DONE;
    }else
    if( p->pCheck==0 ){
      intckFindObject(p);
      if( p->rc==SQLITE_OK ){
        if( p->zObj ){
          char *zSql = 0;
          zSql = intckCheckObjectSql(p, p->zObj, p->zKey, &p->nKeyVal);
          p->pCheck = intckPrepare(p, zSql);
          sqlite3_free(zSql);
          sqlite3_free(p->zKey);
          p->zKey = 0;
        }else{
          p->rc = SQLITE_DONE;
        }
      }else if( p->rc==SQLITE_CORRUPT ){
        p->rc = SQLITE_OK;
        p->zMessage = intckMprintf(p, "%s",
            "corruption found while reading database schema"
        );
        p->bCorruptSchema = 1;
      }
    }

    if( p->pCheck ){
      assert( p->rc==SQLITE_OK );
      if( sqlite3_step(p->pCheck)==SQLITE_ROW ){
        /* Normal case, do nothing. */
      }else{
        intckFinalize(p, p->pCheck);
        p->pCheck = 0;
        p->nKeyVal = 0;
        if( p->rc==SQLITE_CORRUPT ){
          p->rc = SQLITE_OK;
          p->zMessage = intckMprintf(p, 
              "corruption found while scanning database object %s", p->zObj
          );
        }
      }
    }
  }

  return p->rc;
}

/*
** Return a message describing the corruption encountered by the most recent
** call to sqlite3_intck_step(), or NULL if no corruption was encountered.
*/
const char *sqlite3_intck_message(sqlite3_intck *p){
  assert( p->pCheck==0 || p->zMessage==0 );
  if( p->zMessage ){
    return p->zMessage;
  }
  if( p->pCheck ){
    return (const char*)sqlite3_column_text(p->pCheck, 0);
  }
  return 0;
}

/*
** Return the error code and message.
*/
int sqlite3_intck_error(sqlite3_intck *p, const char **pzErr){
  if( pzErr ) *pzErr = p->zErr;
  return (p->rc==SQLITE_DONE ? SQLITE_OK : p->rc);
}

/*
** Close any read transaction the integrity-check object is holding open
** on the database.
*/
int sqlite3_intck_unlock(sqlite3_intck *p){
  if( p->rc==SQLITE_OK && p->pCheck ){
    assert( p->zKey==0 && p->nKeyVal>0 );
    intckSaveKey(p);
    intckFinalize(p, p->pCheck);
    p->pCheck = 0;
  }
  return p->rc;
}

/*
** Return the SQL statement used to check object zObj. Or, if zObj is 
** NULL, the current SQL statement.
*/
const char *sqlite3_intck_test_sql(sqlite3_intck *p, const char *zObj){
  sqlite3_free(p->zTestSql);
  if( zObj ){
    p->zTestSql = intckCheckObjectSql(p, zObj, 0, 0);
  }else{
    if( p->zObj ){
      p->zTestSql = intckCheckObjectSql(p, p->zObj, p->zKey, 0);
    }else{
      sqlite3_free(p->zTestSql);
      p->zTestSql = 0;
    }
  }
  return p->zTestSql;
}
Added ext/intck/sqlite3intck.h.











































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2024-02-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.
**
*************************************************************************
*/

/*
** Incremental Integrity-Check Extension
** -------------------------------------
**
** This module contains code to check whether or not an SQLite database
** is well-formed or corrupt. This is the same task as performed by SQLite's
** built-in "PRAGMA integrity_check" command. This module differs from
** "PRAGMA integrity_check" in that:
**
**   +  It is less thorough - this module does not detect certain types
**      of corruption that are detected by the PRAGMA command. However,
**      it does detect all kinds of corruption that are likely to cause
**      errors in SQLite applications.
**
**   +  It is slower. Sometimes up to three times slower.
**
**   +  It allows integrity-check operations to be split into multiple
**      transactions, so that the database does not need to be read-locked
**      for the duration of the integrity-check.
**
** One way to use the API to run integrity-check on the "main" database
** of handle db is:
**
**   int rc = SQLITE_OK;
**   sqlite3_intck *p = 0;
**
**   sqlite3_intck_open(db, "main", &p);
**   while( SQLITE_OK==sqlite3_intck_step(p) ){
**     const char *zMsg = sqlite3_intck_message(p);
**     if( zMsg ) printf("corruption: %s\n", zMsg);
**   }
**   rc = sqlite3_intck_error(p, &zErr);
**   if( rc!=SQLITE_OK ){
**     printf("error occured (rc=%d), (errmsg=%s)\n", rc, zErr);
**   }
**   sqlite3_intck_close(p);
**
** Usually, the sqlite3_intck object opens a read transaction within the
** first call to sqlite3_intck_step() and holds it open until the 
** integrity-check is complete. However, if sqlite3_intck_unlock() is
** called, the read transaction is ended and a new read transaction opened
** by the subsequent call to sqlite3_intck_step().
*/

#ifndef _SQLITE_INTCK_H
#define _SQLITE_INTCK_H

#include "sqlite3.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
** An ongoing incremental integrity-check operation is represented by an
** opaque pointer of the following type.
*/
typedef struct sqlite3_intck sqlite3_intck;

/*
** Open a new incremental integrity-check object. If successful, populate
** output variable (*ppOut) with the new object handle and return SQLITE_OK.
** Or, if an error occurs, set (*ppOut) to NULL and return an SQLite error
** code (e.g. SQLITE_NOMEM).
**
** The integrity-check will be conducted on database zDb (which must be "main",
** "temp", or the name of an attached database) of database handle db. Once
** this function has been called successfully, the caller should not use 
** database handle db until the integrity-check object has been destroyed
** using sqlite3_intck_close().
*/
int sqlite3_intck_open(
  sqlite3 *db,                    /* Database handle */
  const char *zDb,                /* Database name ("main", "temp" etc.) */
  sqlite3_intck **ppOut           /* OUT: New sqlite3_intck handle */
);

/*
** Close and release all resources associated with a handle opened by an
** earlier call to sqlite3_intck_open(). The results of using an
** integrity-check handle after it has been passed to this function are
** undefined.
*/
void sqlite3_intck_close(sqlite3_intck *pCk);

/*
** Do the next step of the integrity-check operation specified by the handle
** passed as the only argument. This function returns SQLITE_DONE if the 
** integrity-check operation is finished, or an SQLite error code if
** an error occurs, or SQLITE_OK if no error occurs but the integrity-check
** is not finished. It is not considered an error if database corruption
** is encountered.
**
** Following a successful call to sqlite3_intck_step() (one that returns
** SQLITE_OK), sqlite3_intck_message() returns a non-NULL value if 
** corruption was detected in the db.
**
** If an error occurs and a value other than SQLITE_OK or SQLITE_DONE is
** returned, then the integrity-check handle is placed in an error state.
** In this state all subsequent calls to sqlite3_intck_step() or 
** sqlite3_intck_unlock() will immediately return the same error. The 
** sqlite3_intck_error() method may be used to obtain an English language 
** error message in this case.
*/
int sqlite3_intck_step(sqlite3_intck *pCk);

/*
** If the previous call to sqlite3_intck_step() encountered corruption 
** within the database, then this function returns a pointer to a buffer
** containing a nul-terminated string describing the corruption in 
** English. If the previous call to sqlite3_intck_step() did not encounter
** corruption, or if there was no previous call, this function returns 
** NULL.
*/
const char *sqlite3_intck_message(sqlite3_intck *pCk);

/*
** Close any read-transaction opened by an earlier call to 
** sqlite3_intck_step(). Any subsequent call to sqlite3_intck_step() will
** open a new transaction. Return SQLITE_OK if successful, or an SQLite error
** code otherwise.
**
** If an error occurs, then the integrity-check handle is placed in an error
** state. In this state all subsequent calls to sqlite3_intck_step() or 
** sqlite3_intck_unlock() will immediately return the same error. The 
** sqlite3_intck_error() method may be used to obtain an English language 
** error message in this case.
*/
int sqlite3_intck_unlock(sqlite3_intck *pCk);

/*
** If an error has occurred in an earlier call to sqlite3_intck_step()
** or sqlite3_intck_unlock(), then this method returns the associated 
** SQLite error code. Additionally, if pzErr is not NULL, then (*pzErr)
** may be set to point to a nul-terminated string containing an English
** language error message. Or, if no error message is available, to
** NULL.
**
** If no error has occurred within sqlite3_intck_step() or
** sqlite_intck_unlock() calls on the handle passed as the first argument, 
** then SQLITE_OK is returned and (*pzErr) set to NULL.
*/
int sqlite3_intck_error(sqlite3_intck *pCk, const char **pzErr);

/*
** This API is used for testing only. It returns the full-text of an SQL
** statement used to test object zObj, which may be a table or index.
** The returned buffer is valid until the next call to either this function
** or sqlite3_intck_close() on the same sqlite3_intck handle.
*/
const char *sqlite3_intck_test_sql(sqlite3_intck *pCk, const char *zObj);


#ifdef __cplusplus
}  /* end of the 'extern "C"' block */
#endif

#endif /* ifndef _SQLITE_INTCK_H */
Added ext/intck/test_intck.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2010 August 28
**
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"
#include "sqlite3intck.h"

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#include <string.h>
#include <assert.h>

/* In test1.c */
int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
const char *sqlite3ErrName(int);

typedef struct TestIntck TestIntck;
struct TestIntck {
  sqlite3_intck *intck;
};

static int testIntckCmd(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  struct Subcmd {
    const char *zName;
    int nArg;
    const char *zExpect;
  } aCmd[] = {
    {"close", 0, ""},        /* 0 */
    {"step", 0, ""},         /* 1 */
    {"message", 0, ""},      /* 2 */
    {"error", 0, ""},        /* 3 */
    {"unlock", 0, ""},      /* 4 */
    {"test_sql", 1, ""},     /* 5 */
    {0 , 0}
  };
  int rc = TCL_OK;
  int iIdx = -1;
  TestIntck *p = (TestIntck*)clientData;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
    return TCL_ERROR;
  }

  rc = Tcl_GetIndexFromObjStruct(
      interp, objv[1], aCmd, sizeof(aCmd[0]), "SUB-COMMAND", 0, &iIdx
  );
  if( rc ) return rc;

  if( objc!=2+aCmd[iIdx].nArg ){
    Tcl_WrongNumArgs(interp, 2, objv, aCmd[iIdx].zExpect);
    return TCL_ERROR;
  }

  switch( iIdx ){
    case 0: assert( 0==strcmp("close", aCmd[iIdx].zName) ); {
      Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
      break;
    }

    case 1: assert( 0==strcmp("step", aCmd[iIdx].zName) ); {
      rc = sqlite3_intck_step(p->intck);
      Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
      break;
    }

    case 2: assert( 0==strcmp("message", aCmd[iIdx].zName) ); {
      const char *z = sqlite3_intck_message(p->intck);
      Tcl_SetObjResult(interp, Tcl_NewStringObj(z ? z : "", -1));
      break;
    }

    case 3: assert( 0==strcmp("error", aCmd[iIdx].zName) ); {
      const char *zErr = 0;
      rc = sqlite3_intck_error(p->intck, 0);
      Tcl_Obj *pRes = Tcl_NewObj();
      Tcl_ListObjAppendElement(
          interp, pRes, Tcl_NewStringObj(sqlite3ErrName(rc), -1)
      );
      sqlite3_intck_error(p->intck, &zErr);
      Tcl_ListObjAppendElement(
          interp, pRes, Tcl_NewStringObj(zErr ? zErr : 0, -1)
      );
      Tcl_SetObjResult(interp, pRes);
      break;
    }

    case 4: assert( 0==strcmp("unlock", aCmd[iIdx].zName) ); {
      rc = sqlite3_intck_unlock(p->intck);
      Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
      break;
    }

    case 5: assert( 0==strcmp("test_sql", aCmd[iIdx].zName) ); {
      const char *zObj = Tcl_GetString(objv[2]);
      const char *zSql = sqlite3_intck_test_sql(p->intck, zObj[0] ? zObj : 0);
      Tcl_SetObjResult(interp, Tcl_NewStringObj(zSql, -1));
      break;
    }
  }

  return TCL_OK;
}

/*
** Destructor for commands created by test_sqlite3_intck().
*/
static void testIntckFree(void *clientData){
  TestIntck *p = (TestIntck*)clientData;
  sqlite3_intck_close(p->intck);
  ckfree(p);
}

/*
** tclcmd: sqlite3_intck DB DBNAME
*/
static int test_sqlite3_intck(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  char zName[64];
  int iName = 0;
  Tcl_CmdInfo info;
  TestIntck *p = 0;
  sqlite3 *db = 0;
  const char *zDb = 0;
  int rc = SQLITE_OK;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
    return TCL_ERROR;
  }

  p = (TestIntck*)ckalloc(sizeof(TestIntck));
  memset(p, 0, sizeof(TestIntck));

  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zDb = Tcl_GetString(objv[2]);
  if( zDb[0]=='\0' ) zDb = 0;

  rc = sqlite3_intck_open(db, zDb, &p->intck);
  if( rc!=SQLITE_OK ){
    ckfree(p);
    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errstr(rc), -1));
    return TCL_ERROR;
  }

  do {
    sprintf(zName, "intck%d", iName++);
  }while( Tcl_GetCommandInfo(interp, zName, &info)!=0 );
  Tcl_CreateObjCommand(interp, zName, testIntckCmd, (void*)p, testIntckFree);
  Tcl_SetObjResult(interp, Tcl_NewStringObj(zName, -1));

  return TCL_OK;
}

/*
** tclcmd: test_do_intck DB DBNAME
*/
static int test_do_intck(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db = 0;
  const char *zDb = 0;
  int rc = SQLITE_OK;
  sqlite3_intck *pCk = 0;
  Tcl_Obj *pRet = 0;
  const char *zErr = 0;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zDb = Tcl_GetString(objv[2]);

  pRet = Tcl_NewObj();
  Tcl_IncrRefCount(pRet);

  rc = sqlite3_intck_open(db, zDb, &pCk);
  if( rc==SQLITE_OK ){
    while( sqlite3_intck_step(pCk)==SQLITE_OK ){
      const char *zMsg = sqlite3_intck_message(pCk);
      if( zMsg ){
        Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zMsg, -1));
      }
    }
    rc = sqlite3_intck_error(pCk, &zErr);
  }
  if( rc!=SQLITE_OK ){
    if( zErr ){
      Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
    }else{
      Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
    }
  }else{
    Tcl_SetObjResult(interp, pRet);
  }
  Tcl_DecrRefCount(pRet);
  sqlite3_intck_close(pCk);
  sqlite3_intck_close(0);
  return rc ? TCL_ERROR : TCL_OK;
}

int Sqlitetestintck_Init(Tcl_Interp *interp){
  Tcl_CreateObjCommand(interp, "sqlite3_intck", test_sqlite3_intck, 0, 0);
  Tcl_CreateObjCommand(interp, "test_do_intck", test_do_intck, 0, 0);
  return TCL_OK;
}
Changes to ext/jni/GNUmakefile.
31
32
33
34
35
36
37


38
39
40
41
42
43
44
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46







+
+







dir.tests   := $(dir.src)/tests
mkdir       ?= mkdir -p
$(dir.bld.c):
	$(mkdir) $@

javac.flags ?= -Xlint:unchecked -Xlint:deprecation
java.flags ?=
javac.flags += -encoding utf8
# -------------^^^^^^^^^^^^^^ required for Windows builds
jnicheck ?= 1
ifeq (1,$(jnicheck))
  java.flags += -Xcheck:jni
endif

classpath := $(dir.src)
CLEAN_FILES := $(package.jar)
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
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







+












-
+


















+










+







.NOTPARALLEL: $(bin.version-info)
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
	$(MAKE) -C $(dir.top) version-info

# Be explicit about which Java files to compile so that we can work on
# in-progress files without requiring them to be in a compilable statae.
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
  Experimental.java \
  NotNull.java \
  Nullable.java \
) $(patsubst %,$(dir.src.capi)/%,\
  AbstractCollationCallback.java \
  AggregateFunction.java \
  AuthorizerCallback.java \
  AutoExtensionCallback.java \
  BusyHandlerCallback.java \
  CollationCallback.java \
  CollationNeededCallback.java \
  CommitHookCallback.java \
  ConfigLogCallback.java \
  ConfigSqllogCallback.java \
  ConfigSqlLogCallback.java \
  NativePointerHolder.java \
  OutputPointer.java \
  PrepareMultiCallback.java \
  PreupdateHookCallback.java \
  ProgressHandlerCallback.java \
  ResultCode.java \
  RollbackHookCallback.java \
  ScalarFunction.java \
  SQLFunction.java \
  CallbackProxy.java \
  CApi.java \
  TableColumnMetadata.java \
  TraceV2Callback.java \
  UpdateHookCallback.java \
  ValueHolder.java \
  WindowFunction.java \
  XDestroyCallback.java \
  sqlite3.java \
  sqlite3_blob.java \
  sqlite3_context.java \
  sqlite3_stmt.java \
  sqlite3_value.java \
) $(patsubst %,$(dir.src.jni)/wrapper1/%,\
  AggregateFunction.java \
  ScalarFunction.java \
  SqlFunction.java \
  Sqlite.java \
  SqliteException.java \
  ValueHolder.java \
  WindowFunction.java \
)

JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\
  capi/Tester1.java \
  wrapper1/Tester2.java \
)
ifeq (1,$(enable.fts5))
155
156
157
158
159
160
161

162
163
164
165
166
167

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

173
174
175
176
177
178
179
180







+





-
+







ifeq (1,$(enable.tester))
  JAVA_FILES += $(JAVA_FILES.tester)
endif

CLASS_FILES :=
define CLASSFILE_DEPS
all: $(1).class
$(1).class: $(1).java
CLASS_FILES += $(1).class
endef
$(foreach B,$(basename \
  $(JAVA_FILES.main) $(JAVA_FILES.unittest) $(JAVA_FILES.tester)),\
  $(eval $(call CLASSFILE_DEPS,$(B))))
$(CLASS_FILES): $(JAVA_FILES) $(MAKEFILE)
$(CLASS_FILES): $(MAKEFILE)
	$(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES)

#.PHONY: classfiles

########################################################################
# Set up sqlite3.c and sqlite3.h...
#
222
223
224
225
226
227
228
229


230
231
232
233
234
235
236
228
229
230
231
232
233
234

235
236
237
238
239
240
241
242
243







-
+
+







  -DSQLITE_ENABLE_STMTVTAB \
  -DSQLITE_ENABLE_DBPAGE_VTAB \
  -DSQLITE_ENABLE_DBSTAT_VTAB \
  -DSQLITE_ENABLE_BYTECODE_VTAB \
  -DSQLITE_ENABLE_OFFSET_SQL_FUNC \
  -DSQLITE_ENABLE_PREUPDATE_HOOK \
  -DSQLITE_ENABLE_NORMALIZE \
  -DSQLITE_ENABLE_SQLLOG
  -DSQLITE_ENABLE_SQLLOG \
  -DSQLITE_ENABLE_COLUMN_METADATA
endif

ifeq (1,$(opt.debug))
  SQLITE_OPT += -DSQLITE_DEBUG -g -DDEBUG -UNDEBUG
else
  SQLITE_OPT += -Os
endif
312
313
314
315
316
317
318
319

320
321
322
323
324
325
326
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333







-
+







                  $(java.flags) -cp $(classpath)
test.deps := $(CLASS_FILES) $(package.dll)
test-one: $(test.deps)
	$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags)
	$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
test-sqllog: $(test.deps)
	@echo "Testing with -sqllog..."
	$(bin.java) $(test.flags.jvm) -sqllog
	$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags) -sqllog
test-mt: $(test.deps)
	@echo "Testing in multi-threaded mode:";
	$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
    -t 7 -r 50 -shuffle $(Tester1.flags)
	$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 \
    -t 7 -r 50 -shuffle $(Tester2.flags)

Changes to ext/jni/README.md.
12
13
14
15
16
17
18
19

20
21

22
23
24
25
26
27
28
12
13
14
15
16
17
18

19


20
21
22
23
24
25
26
27







-
+
-
-
+








  <https://sqlite.org/forum>


> **FOREWARNING:** this subproject is very much in development and
  subject to any number of changes. Please do not rely on any
  information about its API until this disclaimer is removed.  The JNI
  bindings released with version 3.43 are a "tech preview" and 3.44
  bindings released with version 3.43 are a "tech preview." Once
  will be "final," at which point strong backward compatibility
  guarantees will apply.
  finalized, strong backward compatibility guarantees will apply.

Project goals/requirements:

- A [1-to-1(-ish) mapping of the C API](#1to1ish) to Java via JNI,
  insofar as cross-language semantics allow for. A closely-related
  goal is that [the C documentation](https://sqlite.org/c3ref/intro.html)
  should be usable as-is, insofar as possible, for the JNI binding.
38
39
40
41
42
43
44



45
46
47
48
49


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


50
51

52
53
54
55
56
57
58







+
+
+



-
-
+
+
-







  insofar as they neither interfere with each other nor become
  a maintenance burden for the sqlite developers.

Non-goals:

- Creation of high-level OO wrapper APIs. Clients are free to create
  them off of the C-style API.

- Virtual tables are unlikely to be supported due to the amount of
  glue code needed to fit them into Java.

- Support for mixed-mode operation, where client code accesses SQLite
  both via the Java-side API and the C API via their own native
  code. In such cases, proxy functionalities (primarily callback
  handler wrappers of all sorts) may fail because the C-side use of
  code. Such cases would be a minefield of potential mis-interactions
  between this project's JNI bindings and mixed-mode client code.
  the SQLite APIs will bypass those proxies.


Hello World
-----------------------------------------------------------------------

```java
import org.sqlite.jni.*;
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
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







-
+





-

-


















+
+
+









-
-
-
-
-
+
+
+
+
+
+


-
+








Where it makes sense to do so for usability, Java-side overloads are
provided which accept or return data in alternative forms or provide
sensible default argument values. In all such cases they are thin
proxies around the corresponding C APIs and do not introduce new
semantics.

In some very few cases, Java-specific capabilities have been added in
In a few cases, Java-specific capabilities have been added in
new APIs, all of which have "_java" somewhere in their names.
Examples include:

- `sqlite3_result_java_object()`
- `sqlite3_column_java_object()`
- `sqlite3_column_java_casted()`
- `sqlite3_value_java_object()`
- `sqlite3_value_java_casted()`

which, as one might surmise, collectively enable the passing of
arbitrary Java objects from user-defined SQL functions through to the
caller.


Golden Rule: Garbage Collection Cannot Free SQLite Resources
------------------------------------------------------------------------

It is important that all databases and prepared statement handles get
cleaned up by client code. A database cannot be closed if it has open
statement handles. `sqlite3_close()` fails if the db cannot be closed
whereas `sqlite3_close_v2()` recognizes that case and marks the db as
a "zombie," pending finalization when the library detects that all
pending statements have been closed. Be aware that Java garbage
collection _cannot_ close a database or finalize a prepared statement.
Those things require explicit API calls.

Classes for which it is sensible support Java's `AutoCloseable`
interface so can be used with try-with-resources constructs.


Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
------------------------------------------------------------------------

All routines in this API, barring explicitly documented exceptions,
retain C-like semantics. For example, they are not permitted to throw
or propagate exceptions and must return error information (if any) via
result codes or `null`. The only cases where the C-style APIs may
throw is through client-side misuse, e.g. passing in a null where it
shouldn't be used. The APIs clearly mark function parameters which
should not be null, but does not actively defend itself against such
misuse. Some C-style APIs explicitly accept `null` as a no-op for
usability's sake, and some of the JNI APIs deliberately return an
error code, instead of segfaulting, when passed a `null`.
may cause a `NullPointerException`. The APIs clearly mark function
parameters which should not be null, but does not generally actively
defend itself against such misuse. Some C-style APIs explicitly accept
`null` as a no-op for usability's sake, and some of the JNI APIs
deliberately return an error code, instead of segfaulting, when passed
a `null`.

Client-defined callbacks _must never throw exceptions_ unless _very
explicitly documented_ as being throw-safe. Exceptions are generally
explitly documented_ as being throw-safe. Exceptions are generally
reserved for higher-level bindings which are constructed to
specifically deal with them and ensure that they do not leak C-level
resources. In some cases, callback handlers are permitted to throw, in
which cases they get translated to C-level result codes and/or
messages. If a callback which is not permitted to throw throws, its
exception may trigger debug output but will otherwise be suppressed.

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







-
+

-
+

-
+


-
+












> Design question: does the encoding argument serve any purpose in
  Java? That's as-yet undetermined. If not, it will be removed.

`SQLFunction` is not used directly, but is instead instantiated via
one of its three subclasses:

- `SQLFunction.Scalar` implements simple scalar functions using but a
- `ScalarFunction` implements simple scalar functions using but a
  single callback.
- `SQLFunction.Aggregate` implements aggregate functions using two
- `AggregateFunction` implements aggregate functions using two
  callbacks.
- `SQLFunction.Window` implements window functions using four
- `WindowFunction` implements window functions using four
  callbacks.

Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/Tester1.java) for
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/Tester1.java) for
`SQLFunction` for how it's used.

Reminder: see the disclaimer at the top of this document regarding the
in-flux nature of this API.

### And so on...

Various APIs which accept callbacks, e.g. `sqlite3_trace_v2()` and
`sqlite3_update_hook()`, use interfaces similar to those shown above.
Despite the changes in signature, the JNI layer makes every effort to
provide the same semantics as the C API documentation suggests.
Changes to ext/jni/src/c/sqlite3-jni.c.
11
12
13
14
15
16
17

18

19
20
21
22
23
24



25
26
27
28
29
30
31
11
12
13
14
15
16
17
18

19
20
21
22



23
24
25
26
27
28
29
30
31
32







+
-
+



-
-
-
+
+
+







*************************************************************************
** This file implements the JNI bindings declared in
** org.sqlite.jni.capi.CApi (from which sqlite3-jni.h is generated).
*/

/*
** If you found this comment by searching the code for
** CallStaticObjectMethod because it appears in console output then
** CallStaticObjectMethod then you're the victim of an OpenJDK bug:
** you're probably the victim of an OpenJDK bug:
**
** https://bugs.openjdk.org/browse/JDK-8130659
**
** It's known to happen with OpenJDK v8 but not with v19.
**
** This code does not use JNI's CallStaticObjectMethod().
** It's known to happen with OpenJDK v8 but not with v19. It was
** triggered by this code long before it made any use of
** CallStaticObjectMethod().
*/

/*
** Define any SQLITE_... config defaults we want if they aren't
** overridden by the builder. Please keep these alphabetized.
*/

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







-
-
-
-
-
-















+
+
+
+
+
+







/* SQLITE_J... */
#ifdef SQLITE_JNI_FATAL_OOM
#if !SQLITE_JNI_FATAL_OOM
#undef SQLITE_JNI_FATAL_OOM
#endif
#endif

/**********************************************************************/
/* SQLITE_M... */
#ifndef SQLITE_MAX_ALLOCATION_SIZE
# define SQLITE_MAX_ALLOCATION_SIZE 0x1fffffff
#endif

/**********************************************************************/
/* SQLITE_O... */
#ifndef SQLITE_OMIT_DEPRECATED
# define SQLITE_OMIT_DEPRECATED 1
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION 1
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
# define SQLITE_OMIT_SHARED_CACHE 1
#endif
#ifdef SQLITE_OMIT_UTF16
/* UTF16 is required for java */
# undef SQLITE_OMIT_UTF16 1
#endif

/**********************************************************************/
/* SQLITE_S... */
#ifndef SQLITE_STRICT_SUBTYPE
# define SQLITE_STRICT_SUBTYPE 1
#endif

/**********************************************************************/
/* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 2
#endif
#ifndef SQLITE_THREADSAFE
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
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







+
+
















-
-
+
+







** S3JniCast_L2P and P2L cast jlong (64-bit) to/from pointers. This is
** required for casting warning-free on 32-bit builds, where we
** otherwise get complaints that we're casting between different-sized
** int types.
**
** This use of intptr_t is the _only_ reason we require <stdint.h>
** which, in turn, requires building with -std=c99 (or later).
**
** See also: the notes for LongPtrGet_T.
*/
#define S3JniCast_L2P(JLongAsPtr) (void*)((intptr_t)(JLongAsPtr))
#define S3JniCast_P2L(PTR) (jlong)((intptr_t)(PTR))

/*
** Shortcuts for the first 2 parameters to all JNI bindings.
**
** The type of the jSelf arg differs, but no docs seem to mention
** this: for static methods it's of type jclass and for non-static
** it's jobject. jobject actually works for all funcs, in the sense
** that it compiles and runs so long as we don't use jSelf (which is
** only rarely needed in this code), but to be pedantically correct we
** need the proper type in the signature.
**
** https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#jni_interface_functions_and_pointers
*/
#define JniArgsEnvObj JNIEnv * const env, jobject jSelf
#define JniArgsEnvClass JNIEnv * const env, jclass jKlazz
#define JniArgsEnvObj JNIEnv * env, jobject jSelf
#define JniArgsEnvClass JNIEnv * env, jclass jKlazz
/*
** Helpers to account for -Xcheck:jni warnings about not having
** checked for exceptions.
*/
#define S3JniIfThrew if( (*env)->ExceptionCheck(env) )
#define S3JniExceptionClear (*env)->ExceptionClear(env)
#define S3JniExceptionReport (*env)->ExceptionDescribe(env)
653
654
655
656
657
658
659















660
661
662
663
664
665
666
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684







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







  struct {
    jclass cLong             /* global ref to java.lang.Long */;
    jclass cString           /* global ref to java.lang.String */;
    jobject oCharsetUtf8     /* global ref to StandardCharset.UTF_8 */;
    jmethodID ctorLong1      /* the Long(long) constructor */;
    jmethodID ctorStringBA   /* the String(byte[],Charset) constructor */;
    jmethodID stringGetBytes /* the String.getBytes(Charset) method */;

    /*
      ByteBuffer may or may not be supported via JNI on any given
      platform:

      https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#nio_support

      We only store a ref to byteBuffer.klazz if JNI support for
      ByteBuffer is available (which we determine during static init).
    */
    struct {
      jclass klazz       /* global ref to java.nio.ByteBuffer */;
      jmethodID midAlloc /* ByteBuffer.allocateDirect() */;
      jmethodID midLimit /* ByteBuffer.limit() */;
    } byteBuffer;
  } g;
  /*
  ** The list of Java-side auto-extensions
  ** (org.sqlite.jni.capi.AutoExtensionCallback objects).
  */
  struct {
    S3JniAutoExtension *aExt /* The auto-extension list. It is
859
860
861
862
863
864
865




















































866
867
868
869
870
871
872
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942







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







  s3jni__jbyteArray_bytes2(env, (jByteArray), (ptrToSz))
#define s3jni_jbyteArray_bytes(jByteArray) s3jni__jbyteArray_bytes2(env, (jByteArray), 0)
#define s3jni_jbyteArray_release(jByteArray,jBytes) \
  if( jBytes ) (*env)->ReleaseByteArrayElements(env, jByteArray, jBytes, JNI_ABORT)
#define s3jni_jbyteArray_commit(jByteArray,jBytes) \
  if( jBytes ) (*env)->ReleaseByteArrayElements(env, jByteArray, jBytes, JNI_COMMIT)

/*
** If jbb is-a java.nio.Buffer object and the JNI environment supports
** it, *pBuf is set to the buffer's memory and *pN is set to its
** limit() (as opposed to its capacity()). If jbb is NULL, not a
** Buffer, or the JNI environment does not support that operation,
** *pBuf is set to 0 and *pN is set to 0.
**
** Note that the length of the buffer can be larger than SQLITE_LIMIT
** but this function does not know what byte range of the buffer is
** required so cannot check for that violation. The caller is required
** to ensure that any to-be-bind()ed range fits within SQLITE_LIMIT.
**
** Sidebar: it is unfortunate that we cannot get ByteBuffer.limit()
** via a JNI method like we can for ByteBuffer.capacity(). We instead
** have to call back into Java to get the limit(). Depending on how
** the ByteBuffer is used, the limit and capacity might be the same,
** but when reusing a buffer, the limit may well change whereas the
** capacity is fixed. The problem with, e.g., read()ing blob data to a
** ByteBuffer's memory based on its capacity is that Java-level code
** is restricted to accessing the range specified in
** ByteBuffer.limit().  If we were to honor only the capacity, we
** could end up writing to, or reading from, parts of a ByteBuffer
** which client code itself cannot access without explicitly modifying
** the limit. The penalty we pay for this correctness is that we must
** call into Java to get the limit() of every ByteBuffer we work with.
**
** An alternative to having to call into ByteBuffer.limit() from here
** would be to add private native impls of all ByteBuffer-using
** methods, each of which adds a jint parameter which _must_ be set to
** theBuffer.limit() by public Java APIs which use those private impls
** to do the real work.
*/
static void s3jni__get_nio_buffer(JNIEnv * const env, jobject jbb, void **pBuf, jint * pN ){
  *pBuf = 0;
  *pN = 0;
  if( jbb ){
    *pBuf = (*env)->GetDirectBufferAddress(env, jbb);
    if( *pBuf ){
      /*
      ** Maintenance reminder: do not use
      ** (*env)->GetDirectBufferCapacity(env,jbb), even though it
      ** would be much faster, for reasons explained in this
      ** function's comments.
      */
      *pN = (*env)->CallIntMethod(env, jbb, SJG.g.byteBuffer.midLimit);
      S3JniExceptionIsFatal("Error calling ByteBuffer.limit() method.");
    }
  }
}
#define s3jni_get_nio_buffer(JOBJ,vpOut,jpOut) \
  s3jni__get_nio_buffer(env,(JOBJ),(vpOut),(jpOut))

/*
** Returns the current JNIEnv object. Fails fatally if it cannot find
** the object.
*/
static JNIEnv * s3jni_env(void){
  JNIEnv * env = 0;
  if( (*SJG.jvm)->GetEnv(SJG.jvm, (void **)&env,
1056
1057
1058
1059
1060
1061
1062









































1063
1064
1065
1066
1067
1068
1069
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







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







static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p, int nP){
  jstring const rv = p
    ? (*env)->NewString(env, (const jchar *)p, (jsize)(nP/2))
    : NULL;
  s3jni_oom_check( p ? !!rv : 1 );
  return rv;
}

/*
** Creates a new ByteBuffer instance with a capacity of n. assert()s
** that SJG.g.byteBuffer.klazz is not 0 and n>0.
*/
static jobject s3jni__new_ByteBuffer(JNIEnv * const env, int n){
  jobject rv = 0;
  assert( SJG.g.byteBuffer.klazz );
  assert( SJG.g.byteBuffer.midAlloc );
  assert( n > 0 );
  rv = (*env)->CallStaticObjectMethod(env, SJG.g.byteBuffer.klazz,
                                      SJG.g.byteBuffer.midAlloc, (jint)n);
  S3JniIfThrew {
    S3JniExceptionReport;
    S3JniExceptionClear;
  }
  s3jni_oom_check( rv );
  return rv;
}

/*
** If n>0 and sqlite3_jni_supports_nio() is true then this creates a
** new ByteBuffer object and copies n bytes from p to it. Returns NULL
** if n is 0, sqlite3_jni_supports_nio() is false, or on allocation
** error (unless fatal alloc failures are enabled).
*/
static jobject s3jni__blob_to_ByteBuffer(JNIEnv * const env,
                                         const void * p, int n){
  jobject rv = NULL;
  assert( n >= 0 );
  if( 0==n || !SJG.g.byteBuffer.klazz ){
    return NULL;
  }
  rv = s3jni__new_ByteBuffer(env, n);
  if( rv ){
    void * tgt = (*env)->GetDirectBufferAddress(env, rv);
    memcpy(tgt, p, (size_t)n);
  }
  return rv;
}


/*
** Requires jx to be a Throwable. Calls its toString() method and
** returns its value converted to a UTF-8 string. The caller owns the
** returned string and must eventually sqlite3_free() it.  Returns 0
** if there is a problem fetching the info or on OOM.
**
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481







1482
1483

1484
1485
1486
1487
1488
1489
1490









1491
1492
1493
1494
1495
1496
1497






1498
1499
1500
1501
1502
1503
1504
1579
1580
1581
1582
1583
1584
1585







1586
1587
1588
1589
1590
1591
1592
1593

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






1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624







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

-
+







+
+
+
+
+
+
+
+
+

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







**
**   sqlite3 * s = PtrGet_sqlite3_stmt(...)
**
** will work, despite the incorrect macro name, so long as the
** argument is a Java sqlite3 object, as this operation only has void
** pointers to work with.
*/
#define PtrGet_T(T,OBJ) (T*)NativePointerHolder_get(OBJ, S3JniNph(T))
#define PtrGet_sqlite3(OBJ) PtrGet_T(sqlite3, OBJ)
#define PtrGet_sqlite3_backup(OBJ) PtrGet_T(sqlite3_backup, OBJ)
#define PtrGet_sqlite3_blob(OBJ) PtrGet_T(sqlite3_blob, OBJ)
#define PtrGet_sqlite3_context(OBJ) PtrGet_T(sqlite3_context, OBJ)
#define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
#define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
#define PtrGet_T(T,JOBJ) (T*)NativePointerHolder_get((JOBJ), S3JniNph(T))
#define PtrGet_sqlite3(JOBJ) PtrGet_T(sqlite3, (JOBJ))
#define PtrGet_sqlite3_backup(JOBJ) PtrGet_T(sqlite3_backup, (JOBJ))
#define PtrGet_sqlite3_blob(JOBJ) PtrGet_T(sqlite3_blob, (JOBJ))
#define PtrGet_sqlite3_context(JOBJ) PtrGet_T(sqlite3_context, (JOBJ))
#define PtrGet_sqlite3_stmt(JOBJ) PtrGet_T(sqlite3_stmt, (JOBJ))
#define PtrGet_sqlite3_value(JOBJ) PtrGet_T(sqlite3_value, (JOBJ))
/*
** S3JniLongPtr_T(X,Y) expects X to be an unqualified sqlite3 struct
** LongPtrGet_T(X,Y) expects X to be an unqualified sqlite3 struct
** type name and Y to be a native pointer to such an object in the
** form of a jlong value. The jlong is simply cast to (X*). This
** approach is, as of 2023-09-27, supplanting the former approach. We
** now do the native pointer extraction in the Java side, rather than
** the C side, because it's reportedly significantly faster. The
** intptr_t part here is necessary for compatibility with (at least)
** ARM32.
**
** 2023-11-09: testing has not revealed any measurable performance
** difference between the approach of passing type T to C compared to
** passing pointer-to-T to C, and adding support for the latter
** everywhere requires sigificantly more code. As of this writing, the
** older/simpler approach is being applied except for (A) where the
** newer approach has already been applied and (B) hot-spot APIs where
** a difference of microseconds (i.e. below our testing measurement
** threshold) might add up.
*/
#define S3JniLongPtr_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr))
#define S3JniLongPtr_sqlite3(JLongAsPtr) S3JniLongPtr_T(sqlite3,JLongAsPtr)
#define S3JniLongPtr_sqlite3_backup(JLongAsPtr) S3JniLongPtr_T(sqlite3_backup,JLongAsPtr)
#define S3JniLongPtr_sqlite3_blob(JLongAsPtr) S3JniLongPtr_T(sqlite3_blob,JLongAsPtr)
#define S3JniLongPtr_sqlite3_stmt(JLongAsPtr) S3JniLongPtr_T(sqlite3_stmt,JLongAsPtr)
#define S3JniLongPtr_sqlite3_value(JLongAsPtr) S3JniLongPtr_T(sqlite3_value,JLongAsPtr)
#define LongPtrGet_T(T,JLongAsPtr) (T*)((intptr_t)((JLongAsPtr)))
#define LongPtrGet_sqlite3(JLongAsPtr) LongPtrGet_T(sqlite3,(JLongAsPtr))
#define LongPtrGet_sqlite3_backup(JLongAsPtr) LongPtrGet_T(sqlite3_backup,(JLongAsPtr))
#define LongPtrGet_sqlite3_blob(JLongAsPtr) LongPtrGet_T(sqlite3_blob,(JLongAsPtr))
#define LongPtrGet_sqlite3_stmt(JLongAsPtr) LongPtrGet_T(sqlite3_stmt,(JLongAsPtr))
#define LongPtrGet_sqlite3_value(JLongAsPtr) LongPtrGet_T(sqlite3_value,(JLongAsPtr))
/*
** Extracts the new S3JniDb instance from the free-list, or allocates
** one if needed, associates it with pDb, and returns.  Returns NULL
** on OOM. The returned object MUST, on success of the calling
** operation, subsequently be associated with jDb via
** NativePointerHolder_set() or freed using S3JniDb_set_aside().
*/
1549
1550
1551
1552
1553
1554
1555
1556

1557
1558
1559
1560
1561
1562
1563
1669
1670
1671
1672
1673
1674
1675

1676
1677
1678
1679
1680
1681
1682
1683







-
+







/*
** Evaluates to the S3JniDb object for the given sqlite3 object, or
** NULL if pDb is NULL or was not initialized via the JNI interfaces.
*/
#define S3JniDb_from_c(sqlite3Ptr) \
  ((sqlite3Ptr) ? S3JniDb_from_clientdata(sqlite3Ptr) : 0)
#define S3JniDb_from_jlong(sqlite3PtrAsLong) \
  S3JniDb_from_c(S3JniLongPtr_T(sqlite3,sqlite3PtrAsLong))
  S3JniDb_from_c(LongPtrGet_T(sqlite3,sqlite3PtrAsLong))

/*
** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out
** AX.
*/
#define S3JniAutoExtension_clear(AX) S3JniHook_unref(AX);

1666
1667
1668
1669
1670
1671
1672
1673
1674



1675
1676
1677
1678
1679
1680
1681
1786
1787
1788
1789
1790
1791
1792


1793
1794
1795
1796
1797
1798
1799
1800
1801
1802







-
-
+
+
+







    case SQLITE_UTF16LE: case SQLITE_UTF16BE:
      return 1;
    default:
      return 0;
  }
}

/* For use with sqlite3_result/value_pointer() */
static const char * const ResultJavaValuePtrStr = "org.sqlite.jni.capi.ResultJavaVal";
/* For use with sqlite3_result_pointer(), sqlite3_value_pointer(),
   sqlite3_bind_java_object(), and sqlite3_column_java_object(). */
static const char * const s3jni__value_jref_key = "org.sqlite.jni.capi.ResultJavaVal";

/*
** If v is not NULL, it must be a jobject global reference. Its
** reference is relinquished.
*/
static void S3Jni_jobject_finalizer(void *v){
  if( v ){
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
1997
1998
1999
2000
2001
2002
2003

2004
2005
2006
2007




2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039


2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050







-
+
+


-
-
-
-
+
+
+
+
+
+







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







  S3JniUnrefLocal(jcx);
  S3JniUnrefLocal(ja);
  return SQLITE_NOMEM;
}

/*
** Requires that jCx and jArgv are sqlite3_context
** resp. array-of-sqlite3_value values initialized by udf_args(). This
** resp. array-of-sqlite3_value values initialized by udf_args(). The
** latter will be 0-and-NULL for UDF types with no arguments. This
** function zeroes out the nativePointer member of jCx and each entry
** in jArgv. This is a safety-net precaution to avoid undefined
** behavior if a Java-side UDF holds a reference to one of its
** arguments. This MUST be called from any function which successfully
** calls udf_args(), after calling the corresponding UDF and checking
** its exception status. It MUST NOT be called in any other case.
** behavior if a Java-side UDF holds a reference to its context or one
** of its arguments. This MUST be called from any function which
** successfully calls udf_args(), after calling the corresponding UDF
** and checking its exception status, or which Java-wraps a
** sqlite3_context for use with a UDF(ish) call. It MUST NOT be called
** in any other case.
*/
static void udf_unargs(JNIEnv *env, jobject jCx, int argc, jobjectArray jArgv){
  int i = 0;
  assert(jCx);
  NativePointerHolder_set(S3JniNph(sqlite3_context), jCx, 0);
  for( ; i < argc; ++i ){
    jobject jsv = (*env)->GetObjectArrayElement(env, jArgv, i);
    /*
    ** There is a potential Java-triggerable case of Undefined
    ** Behavior here, but it would require intentional misuse of the
    ** API:
    **
    ** If a Java UDF grabs an sqlite3_value from its argv and then
    ** assigns that element to null, it becomes unreachable to us so
    ** we cannot clear out its pointer. That Java-side object's
    ** getNativePointer() will then refer to a stale value, so passing
    ** it into (e.g.) sqlite3_value_SOMETHING() would invoke UB.
    **
    ** High-level wrappers can avoid that possibility if they do not
    ** expose sqlite3_value directly to clients (as is the case in
    ** org.sqlite.jni.wrapper1.SqlFunction).
    **
    ** One potential (but expensive) workaround for this would be to
    ** privately store a duplicate argv array in each sqlite3_context
    ** wrapper object, and clear the native pointers from that copy.
    */
    assert(jsv);
    NativePointerHolder_set(S3JniNph(sqlite3_value), jsv, 0);
    assert(jsv && "Someone illegally modified a UDF argument array.");
    if( jsv ){
      NativePointerHolder_set(S3JniNph(sqlite3_value), jsv, 0);
    }
  }
}


/*
** Must be called immediately after a Java-side UDF callback throws.
** If translateToErr is true then it sets the exception's message in
1980
1981
1982
1983
1984
1985
1986

1987
1988
1989
1990
1991
1992
1993
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139







+








  if( jcx ){
    (*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx);
    S3JniIfThrew{
      rc = udf_report_exception(env, isFinal, cx, s->zFuncName,
                                zFuncType);
    }
    udf_unargs(env, jcx, 0, 0);
    S3JniUnrefLocal(jcx);
  }else{
    if( isFinal ) sqlite3_result_error_nomem(cx);
    rc = SQLITE_NOMEM;
  }
  return rc;
}
2053
2054
2055
2056
2057
2058
2059
2060

2061
2062
2063
2064
2065

2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076

2077
2078
2079
2080
2081
2082

2083
2084
2085
2086
2087

2088
2089
2090
2091
2092

2093
2094
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
2199
2200
2201
2202
2203
2204
2205

2206
2207
2208
2209
2210

2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221

2222
2223
2224
2225
2226
2227

2228
2229
2230
2231
2232

2233
2234
2235
2236
2237

2238
2239
2240
2241
2242
2243

2244
2245
2246
2247
2248
2249

2250
2251
2252
2253
2254
2255

2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280







-
+




-
+










-
+





-
+




-
+




-
+





-
+





-
+





-
+












+



+







    jstring const rv = (*env)->NewStringUTF( env, CName() );   \
    s3jni_oom_check(rv);                                       \
    return rv;                                                 \
  }
/** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*)). */
#define WRAP_INT_STMT(JniNameSuffix,CName)                    \
  JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt){ \
    return (jint)CName(S3JniLongPtr_sqlite3_stmt(jpStmt));    \
    return (jint)CName(LongPtrGet_sqlite3_stmt(jpStmt));    \
  }
/** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*,int)). */
#define WRAP_INT_STMT_INT(JniNameSuffix,CName)                         \
  JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt, jint n){ \
    return (jint)CName(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)n);            \
    return (jint)CName(LongPtrGet_sqlite3_stmt(jpStmt), (int)n);            \
  }
/** Create a trivial JNI wrapper for (boolean CName(sqlite3_stmt*)). */
#define WRAP_BOOL_STMT(JniNameSuffix,CName)                           \
  JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jobject jStmt){     \
    return CName(PtrGet_sqlite3_stmt(jStmt)) ? JNI_TRUE : JNI_FALSE; \
  }
/** Create a trivial JNI wrapper for (jstring CName(sqlite3_stmt*,int)). */
#define WRAP_STR_STMT_INT(JniNameSuffix,CName)                             \
  JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt, jint ndx){ \
    return s3jni_utf8_to_jstring(                                       \
      CName(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx),               \
      CName(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx),               \
      -1);                                                              \
  }
/** Create a trivial JNI wrapper for (boolean CName(sqlite3*)). */
#define WRAP_BOOL_DB(JniNameSuffix,CName)                           \
  JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){     \
    return CName(S3JniLongPtr_sqlite3(jpDb)) ? JNI_TRUE : JNI_FALSE; \
    return CName(LongPtrGet_sqlite3(jpDb)) ? JNI_TRUE : JNI_FALSE; \
  }
/** Create a trivial JNI wrapper for (int CName(sqlite3*)). */
#define WRAP_INT_DB(JniNameSuffix,CName)                    \
  JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \
  return (jint)CName(S3JniLongPtr_sqlite3(jpDb)); \
  return (jint)CName(LongPtrGet_sqlite3(jpDb)); \
  }
/** Create a trivial JNI wrapper for (int64 CName(sqlite3*)). */
#define WRAP_INT64_DB(JniNameSuffix,CName)                   \
  JniDecl(jlong,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \
  return (jlong)CName(S3JniLongPtr_sqlite3(jpDb));  \
  return (jlong)CName(LongPtrGet_sqlite3(jpDb));  \
  }
/** Create a trivial JNI wrapper for (jstring CName(sqlite3*,int)). */
#define WRAP_STR_DB_INT(JniNameSuffix,CName)                             \
  JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jlong jpDb, jint ndx){ \
    return s3jni_utf8_to_jstring(                                       \
      CName(S3JniLongPtr_sqlite3(jpDb), (int)ndx),               \
      CName(LongPtrGet_sqlite3(jpDb), (int)ndx),               \
      -1);                                                              \
  }
/** Create a trivial JNI wrapper for (int CName(sqlite3_value*)). */
#define WRAP_INT_SVALUE(JniNameSuffix,CName,DfltOnNull)         \
  JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpSValue){ \
    sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSValue); \
    sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSValue); \
    return (jint)(sv ? CName(sv): DfltOnNull);                      \
  }
/** Create a trivial JNI wrapper for (boolean CName(sqlite3_value*)). */
#define WRAP_BOOL_SVALUE(JniNameSuffix,CName,DfltOnNull)            \
  JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jlong jpSValue){ \
    sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSValue); \
    sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSValue); \
    return (jint)(sv ? CName(sv) : DfltOnNull)                       \
      ? JNI_TRUE : JNI_FALSE;                                       \
  }

WRAP_INT_DB(1changes,                  sqlite3_changes)
WRAP_INT64_DB(1changes64,              sqlite3_changes64)
WRAP_INT_STMT(1clear_1bindings,        sqlite3_clear_bindings)
WRAP_INT_STMT_INT(1column_1bytes,      sqlite3_column_bytes)
WRAP_INT_STMT_INT(1column_1bytes16,    sqlite3_column_bytes16)
WRAP_INT_STMT(1column_1count,          sqlite3_column_count)
WRAP_STR_STMT_INT(1column_1decltype,   sqlite3_column_decltype)
WRAP_STR_STMT_INT(1column_1name,       sqlite3_column_name)
#ifdef SQLITE_ENABLE_COLUMN_METADATA
WRAP_STR_STMT_INT(1column_1database_1name,  sqlite3_column_database_name)
WRAP_STR_STMT_INT(1column_1origin_1name,    sqlite3_column_origin_name)
WRAP_STR_STMT_INT(1column_1table_1name,     sqlite3_column_table_name)
#endif
WRAP_INT_STMT_INT(1column_1type,       sqlite3_column_type)
WRAP_INT_STMT(1data_1count,            sqlite3_data_count)
WRAP_STR_DB_INT(1db_1name,             sqlite3_db_name)
WRAP_INT_DB(1error_1offset,            sqlite3_error_offset)
WRAP_INT_DB(1extended_1errcode,        sqlite3_extended_errcode)
WRAP_BOOL_DB(1get_1autocommit,         sqlite3_get_autocommit)
WRAP_MUTF8_VOID(1libversion,           sqlite3_libversion)
2177
2178
2179
2180
2181
2182
2183

2184


2185
2186
2187
2188
2189
2190
2191
2325
2326
2327
2328
2329
2330
2331
2332

2333
2334
2335
2336
2337
2338
2339
2340
2341







+
-
+
+







    ? sqlite3_aggregate_context(pCx, (int)(initialize
                                           ? (int)sizeof(void*)
                                           : 0))
    : 0;
  return S3JniCast_P2L(p);
}

/*
/* Central auto-extension handler. */
** Central auto-extension runner for auto-extensions created in Java.
*/
static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
                                          const struct sqlite3_api_routines *ignored){
  int rc = 0;
  unsigned i, go = 1;
  JNIEnv * env = 0;
  S3JniDb * ps;
  S3JniEnv * jc;
2314
2315
2316
2317
2318
2319
2320
2321

2322
2323
2324
2325
2326
2327
2328
2329
2330
2331


2332
2333
2334
2335
2336
2337
2338
2464
2465
2466
2467
2468
2469
2470

2471
2472
2473
2474
2475
2476
2477
2478
2479


2480
2481
2482
2483
2484
2485
2486
2487
2488







-
+








-
-
+
+







}

S3JniApi(sqlite3_backup_finish(),jint,1backup_1finish)(
  JniArgsEnvClass, jlong jpBack
){
  int rc = 0;
  if( jpBack!=0 ){
    rc = sqlite3_backup_finish( S3JniLongPtr_sqlite3_backup(jpBack) );
    rc = sqlite3_backup_finish( LongPtrGet_sqlite3_backup(jpBack) );
  }
  return rc;
}

S3JniApi(sqlite3_backup_init(),jobject,1backup_1init)(
  JniArgsEnvClass, jlong jpDbDest, jstring jTDest,
  jlong jpDbSrc, jstring jTSrc
){
  sqlite3 * const pDest = S3JniLongPtr_sqlite3(jpDbDest);
  sqlite3 * const pSrc = S3JniLongPtr_sqlite3(jpDbSrc);
  sqlite3 * const pDest = LongPtrGet_sqlite3(jpDbDest);
  sqlite3 * const pSrc = LongPtrGet_sqlite3(jpDbSrc);
  char * const zDest = s3jni_jstring_to_utf8(jTDest, 0);
  char * const zSrc = s3jni_jstring_to_utf8(jTSrc, 0);
  jobject rv = 0;

  if( pDest && pSrc && zDest && zSrc ){
    sqlite3_backup * const pB =
      sqlite3_backup_init(pDest, zDest, pSrc, zSrc);
2347
2348
2349
2350
2351
2352
2353
2354

2355
2356
2357
2358
2359
2360

2361
2362
2363
2364
2365
2366

2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379

2380
2381
2382
2383
2384
2385

2386
2387
2388
2389










































































































2390
2391
2392
2393

2394
2395
2396
2397
2398
2399
2400

2401
2402
2403
2404
2405
2406

2407
2408
2409
2410
2411
2412
2413
2414
2415

2416
2417
2418
2419
2420
2421

2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435

2436
2437
2438
2439
2440
2441

2442
2443
2444
2445
2446
2447
2448
2449
2450

2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461

2462
2463
2464
2465
2466
2467
2468
2497
2498
2499
2500
2501
2502
2503

2504
2505
2506
2507
2508
2509

2510
2511
2512
2513
2514
2515

2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528

2529
2530
2531
2532
2533
2534

2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648

2649
2650
2651
2652
2653
2654
2655

2656
2657
2658
2659
2660
2661

2662
2663
2664
2665
2666
2667
2668
2669
2670

2671
2672
2673
2674
2675
2676

2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690

2691
2692
2693
2694
2695
2696

2697
2698
2699
2700
2701
2702
2703
2704
2705

2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716

2717
2718
2719
2720
2721
2722
2723
2724







-
+





-
+





-
+












-
+





-
+




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



-
+






-
+





-
+








-
+





-
+













-
+





-
+








-
+










-
+







  sqlite3_free(zSrc);
  return rv;
}

S3JniApi(sqlite3_backup_pagecount(),jint,1backup_1pagecount)(
  JniArgsEnvClass, jlong jpBack
){
  return sqlite3_backup_pagecount(S3JniLongPtr_sqlite3_backup(jpBack));
  return sqlite3_backup_pagecount(LongPtrGet_sqlite3_backup(jpBack));
}

S3JniApi(sqlite3_backup_remaining(),jint,1backup_1remaining)(
  JniArgsEnvClass, jlong jpBack
){
  return sqlite3_backup_remaining(S3JniLongPtr_sqlite3_backup(jpBack));
  return sqlite3_backup_remaining(LongPtrGet_sqlite3_backup(jpBack));
}

S3JniApi(sqlite3_backup_step(),jint,1backup_1step)(
  JniArgsEnvClass, jlong jpBack, jint nPage
){
  return sqlite3_backup_step(S3JniLongPtr_sqlite3_backup(jpBack), (int)nPage);
  return sqlite3_backup_step(LongPtrGet_sqlite3_backup(jpBack), (int)nPage);
}

S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jbyteArray baData, jint nMax
){
  jsize nBA = 0;
  jbyte * const pBuf = baData ? s3jni_jbyteArray_bytes2(baData, &nBA) : 0;
  int rc;
  if( pBuf ){
    if( nMax>nBA ){
      nMax = nBA;
    }
    rc = sqlite3_bind_blob(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx,
    rc = sqlite3_bind_blob(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx,
                           pBuf, (int)nMax, SQLITE_TRANSIENT);
    s3jni_jbyteArray_release(baData, pBuf);
  }else{
    rc = baData
      ? SQLITE_NOMEM
      : sqlite3_bind_null( S3JniLongPtr_sqlite3_stmt(jpStmt), ndx );
      : sqlite3_bind_null( LongPtrGet_sqlite3_stmt(jpStmt), ndx );
  }
  return (jint)rc;
}

/**
   Helper for use with s3jni_setup_nio_args().
*/
struct S3JniNioArgs {
  jobject jBuf;        /* input - ByteBuffer */
  jint iOffset;        /* input - byte offset */
  jint iHowMany;       /* input - byte count to bind/read/write */
  jint nBuf;           /* output - jBuf's buffer size */
  void * p;            /* output - jBuf's buffer memory */
  void * pStart;       /* output - offset of p to bind/read/write */
  int nOut;            /* output - number of bytes from pStart to bind/read/write */
};
typedef struct S3JniNioArgs S3JniNioArgs;
static const S3JniNioArgs S3JniNioArgs_empty = {
  0,0,0,0,0,0,0
};

/*
** Internal helper for sqlite3_bind_nio_buffer(),
** sqlite3_result_nio_buffer(), and similar methods which take a
** ByteBuffer object as either input or output. Populates pArgs and
** returns 0 on success, non-0 if the operation should fail. The
** caller is required to check for SJG.g.byteBuffer.klazz!=0 before calling
** this and reporting it in a way appropriate for that routine.  This
** function may assert() that SJG.g.byteBuffer.klazz is not 0.
**
** The (jBuffer, iOffset, iHowMany) arguments are the (ByteBuffer, offset,
** length) arguments to the bind/result method.
**
** If iHowMany is negative then it's treated as "until the end" and
** the calculated slice is trimmed to fit if needed. If iHowMany is
** positive and extends past the end of jBuffer then SQLITE_ERROR is
** returned.
**
** Returns 0 if everything looks to be in order, else some SQLITE_...
** result code
*/
static int s3jni_setup_nio_args(
  JNIEnv *env, S3JniNioArgs * pArgs,
  jobject jBuffer, jint iOffset, jint iHowMany
){
  jlong iEnd = 0;
  const int bAllowTruncate = iHowMany<0;
  *pArgs = S3JniNioArgs_empty;
  pArgs->jBuf = jBuffer;
  pArgs->iOffset = iOffset;
  pArgs->iHowMany = iHowMany;
  assert( SJG.g.byteBuffer.klazz );
  if( pArgs->iOffset<0 ){
    return SQLITE_ERROR
      /* SQLITE_MISUSE or SQLITE_RANGE would fit better but we use
         SQLITE_ERROR for consistency with the code documented for a
         negative target blob offset in sqlite3_blob_read/write(). */;
  }
  s3jni_get_nio_buffer(pArgs->jBuf, &pArgs->p, &pArgs->nBuf);
  if( !pArgs->p ){
    return SQLITE_MISUSE;
  }else if( pArgs->iOffset>=pArgs->nBuf ){
    pArgs->pStart = 0;
    pArgs->nOut = 0;
    return 0;
  }
  assert( pArgs->nBuf > 0 );
  assert( pArgs->iOffset < pArgs->nBuf );
  iEnd = pArgs->iHowMany<0
    ? pArgs->nBuf - pArgs->iOffset
    : pArgs->iOffset + pArgs->iHowMany;
  if( iEnd>(jlong)pArgs->nBuf ){
    if( bAllowTruncate ){
      iEnd = pArgs->nBuf - pArgs->iOffset;
    }else{
      return SQLITE_ERROR
        /* again: for consistency with blob_read/write(), though
           SQLITE_MISUSE or SQLITE_RANGE would be a better fit. */;
    }
  }
  if( iEnd - pArgs->iOffset > (jlong)SQLITE_MAX_LENGTH ){
    return SQLITE_TOOBIG;
  }
  assert( pArgs->iOffset >= 0 );
  assert( iEnd > pArgs->iOffset );
  pArgs->pStart = pArgs->p + pArgs->iOffset;
  pArgs->nOut = (int)(iEnd - pArgs->iOffset);
  assert( pArgs->nOut > 0 );
  assert( (pArgs->pStart + pArgs->nOut) <= (pArgs->p + pArgs->nBuf) );
  return 0;
}

S3JniApi(sqlite3_bind_nio_buffer(),jint,1bind_1nio_1buffer)(
  JniArgsEnvClass, jobject jpStmt, jint ndx, jobject jBuffer,
  jint iOffset, jint iN
){
  sqlite3_stmt * pStmt = PtrGet_sqlite3_stmt(jpStmt);
  S3JniNioArgs args;
  int rc;
  if( !pStmt || !SJG.g.byteBuffer.klazz ) return SQLITE_MISUSE;
  rc = s3jni_setup_nio_args(env, &args, jBuffer, iOffset, iN);
  if(rc){
    return rc;
  }else if( !args.pStart || !args.nOut ){
    return sqlite3_bind_null(pStmt, ndx);
  }
  return sqlite3_bind_blob( pStmt, (int)ndx, args.pStart,
                            args.nOut, SQLITE_TRANSIENT );
}

S3JniApi(sqlite3_bind_double(),jint,1bind_1double)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jdouble val
){
  return (jint)sqlite3_bind_double(S3JniLongPtr_sqlite3_stmt(jpStmt),
  return (jint)sqlite3_bind_double(LongPtrGet_sqlite3_stmt(jpStmt),
                                   (int)ndx, (double)val);
}

S3JniApi(sqlite3_bind_int(),jint,1bind_1int)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jint val
){
  return (jint)sqlite3_bind_int(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, (int)val);
  return (jint)sqlite3_bind_int(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (int)val);
}

S3JniApi(sqlite3_bind_int64(),jint,1bind_1int64)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jlong val
){
  return (jint)sqlite3_bind_int64(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val);
  return (jint)sqlite3_bind_int64(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val);
}

/*
** Bind a new global ref to Object `val` using sqlite3_bind_pointer().
*/
S3JniApi(sqlite3_bind_java_object(),jint,1bind_1java_1object)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jobject val
){
  sqlite3_stmt * const pStmt = S3JniLongPtr_sqlite3_stmt(jpStmt);
  sqlite3_stmt * const pStmt = LongPtrGet_sqlite3_stmt(jpStmt);
  int rc = SQLITE_MISUSE;

  if(pStmt){
    jobject const rv = S3JniRefGlobal(val);
    if( rv ){
      rc = sqlite3_bind_pointer(pStmt, ndx, rv, ResultJavaValuePtrStr,
      rc = sqlite3_bind_pointer(pStmt, ndx, rv, s3jni__value_jref_key,
                                S3Jni_jobject_finalizer);
    }else if(val){
      rc = SQLITE_NOMEM;
    }else{
      rc = sqlite3_bind_null(pStmt, ndx);
    }
  }
  return rc;
}

S3JniApi(sqlite3_bind_null(),jint,1bind_1null)(
  JniArgsEnvClass, jlong jpStmt, jint ndx
){
  return (jint)sqlite3_bind_null(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx);
  return (jint)sqlite3_bind_null(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx);
}

S3JniApi(sqlite3_bind_parameter_count(),jint,1bind_1parameter_1count)(
  JniArgsEnvClass, jlong jpStmt
){
  return (jint)sqlite3_bind_parameter_count(S3JniLongPtr_sqlite3_stmt(jpStmt));
  return (jint)sqlite3_bind_parameter_count(LongPtrGet_sqlite3_stmt(jpStmt));
}

S3JniApi(sqlite3_bind_parameter_index(),jint,1bind_1parameter_1index)(
  JniArgsEnvClass, jlong jpStmt, jbyteArray jName
){
  int rc = 0;
  jbyte * const pBuf = s3jni_jbyteArray_bytes(jName);
  if( pBuf ){
    rc = sqlite3_bind_parameter_index(S3JniLongPtr_sqlite3_stmt(jpStmt),
    rc = sqlite3_bind_parameter_index(LongPtrGet_sqlite3_stmt(jpStmt),
                                      (const char *)pBuf);
    s3jni_jbyteArray_release(jName, pBuf);
  }
  return rc;
}

S3JniApi(sqlite3_bind_parameter_name(),jstring,1bind_1parameter_1name)(
  JniArgsEnvClass, jlong jpStmt, jint ndx
){
  const char *z =
    sqlite3_bind_parameter_name(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx);
    sqlite3_bind_parameter_name(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx);
  return z ? s3jni_utf8_to_jstring(z, -1) : 0;
}

/*
** Impl of sqlite3_bind_text/text16().
*/
static int s3jni__bind_text(int is16, JNIEnv *env, jlong jpStmt, jint ndx,
2476
2477
2478
2479
2480
2481
2482
2483

2484
2485

2486
2487
2488
2489
2490

2491
2492
2493
2494
2495
2496
2497
2732
2733
2734
2735
2736
2737
2738

2739
2740

2741
2742
2743
2744
2745

2746
2747
2748
2749
2750
2751
2752
2753







-
+

-
+




-
+







      nMax = nBA;
    }
    /* Note that we rely on the Java layer having assured that baData
       is NUL-terminated if nMax is negative. In order to avoid UB for
       such cases, we do not expose the byte-limit arguments in the
       public API. */
    rc = is16
      ? sqlite3_bind_text16(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx,
      ? sqlite3_bind_text16(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx,
                            pBuf, (int)nMax, SQLITE_TRANSIENT)
      : sqlite3_bind_text(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx,
      : sqlite3_bind_text(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx,
                          (const char *)pBuf,
                          (int)nMax, SQLITE_TRANSIENT);
  }else{
    rc = baData
      ? sqlite3_bind_null(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx)
      ? sqlite3_bind_null(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx)
      : SQLITE_NOMEM;
  }
  s3jni_jbyteArray_release(baData, pBuf);
  return (jint)rc;

}

2507
2508
2509
2510
2511
2512
2513
2514

2515
2516

2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531

2532
2533
2534
2535
2536
2537
2538

2539
2540
2541
2542
2543
2544
2545

2546
2547
2548
2549
2550
2551

2552
2553
2554
2555
2556
2557
2558
2559

2560
2561
2562
2563
2564
2565
2566
2763
2764
2765
2766
2767
2768
2769

2770
2771

2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786

2787
2788
2789
2790
2791
2792
2793

2794
2795
2796
2797
2798
2799
2800

2801
2802
2803
2804
2805
2806

2807
2808
2809
2810
2811
2812
2813
2814

2815
2816
2817
2818
2819
2820
2821
2822







-
+

-
+














-
+






-
+






-
+





-
+







-
+







  return s3jni__bind_text(1, env, jpStmt, ndx, baData, nMax);
}

S3JniApi(sqlite3_bind_value(),jint,1bind_1value)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jlong jpValue
){
  int rc = 0;
  sqlite3_stmt * pStmt = S3JniLongPtr_sqlite3_stmt(jpStmt);
  sqlite3_stmt * pStmt = LongPtrGet_sqlite3_stmt(jpStmt);
  if( pStmt ){
    sqlite3_value *v = S3JniLongPtr_sqlite3_value(jpValue);
    sqlite3_value *v = LongPtrGet_sqlite3_value(jpValue);
    if( v ){
      rc = sqlite3_bind_value(pStmt, (int)ndx, v);
    }else{
      rc = sqlite3_bind_null(pStmt, (int)ndx);
    }
  }else{
    rc = SQLITE_MISUSE;
  }
  return (jint)rc;
}

S3JniApi(sqlite3_bind_zeroblob(),jint,1bind_1zeroblob)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jint n
){
  return (jint)sqlite3_bind_zeroblob(S3JniLongPtr_sqlite3_stmt(jpStmt),
  return (jint)sqlite3_bind_zeroblob(LongPtrGet_sqlite3_stmt(jpStmt),
                                     (int)ndx, (int)n);
}

S3JniApi(sqlite3_bind_zeroblob64(),jint,1bind_1zeroblob64)(
  JniArgsEnvClass, jlong jpStmt, jint ndx, jlong n
){
  return (jint)sqlite3_bind_zeroblob64(S3JniLongPtr_sqlite3_stmt(jpStmt),
  return (jint)sqlite3_bind_zeroblob64(LongPtrGet_sqlite3_stmt(jpStmt),
                                       (int)ndx, (sqlite3_uint64)n);
}

S3JniApi(sqlite3_blob_bytes(),jint,1blob_1bytes)(
  JniArgsEnvClass, jlong jpBlob
){
  return sqlite3_blob_bytes(S3JniLongPtr_sqlite3_blob(jpBlob));
  return sqlite3_blob_bytes(LongPtrGet_sqlite3_blob(jpBlob));
}

S3JniApi(sqlite3_blob_close(),jint,1blob_1close)(
  JniArgsEnvClass, jlong jpBlob
){
  sqlite3_blob * const b = S3JniLongPtr_sqlite3_blob(jpBlob);
  sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
  return b ? (jint)sqlite3_blob_close(b) : SQLITE_MISUSE;
}

S3JniApi(sqlite3_blob_open(),jint,1blob_1open)(
  JniArgsEnvClass, jlong jpDb, jstring jDbName, jstring jTbl, jstring jCol,
  jlong jRowId, jint flags, jobject jOut
){
  sqlite3 * const db = S3JniLongPtr_sqlite3(jpDb);
  sqlite3 * const db = LongPtrGet_sqlite3(jpDb);
  sqlite3_blob * pBlob = 0;
  char * zDbName = 0, * zTableName = 0, * zColumnName = 0;
  int rc;

  if( !db || !jDbName || !jTbl || !jCol ) return SQLITE_MISUSE;
  zDbName = s3jni_jstring_to_utf8(jDbName,0);
  zTableName = zDbName ? s3jni_jstring_to_utf8(jTbl,0) : 0;
2586
2587
2588
2589
2590
2591
2592
2593

2594
2595
2596
2597
2598
2599
2600
2601
2602
























2603
2604
2605
2606
2607

2608
2609
2610
2611
2612
2613
2614

2615
2616
2617
2618
2619
2620
2621
2622
2623























2624
2625
2626
2627
2628
2629
2630
2842
2843
2844
2845
2846
2847
2848

2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886

2887
2888
2889
2890
2891
2892
2893

2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933







-
+









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




-
+






-
+









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







S3JniApi(sqlite3_blob_read(),jint,1blob_1read)(
  JniArgsEnvClass, jlong jpBlob, jbyteArray jTgt, jint iOffset
){
  jbyte * const pBa = s3jni_jbyteArray_bytes(jTgt);
  int rc = jTgt ? (pBa ? SQLITE_MISUSE : SQLITE_NOMEM) : SQLITE_MISUSE;
  if( pBa ){
    jsize const nTgt = (*env)->GetArrayLength(env, jTgt);
    rc = sqlite3_blob_read(S3JniLongPtr_sqlite3_blob(jpBlob), pBa,
    rc = sqlite3_blob_read(LongPtrGet_sqlite3_blob(jpBlob), pBa,
                           (int)nTgt, (int)iOffset);
    if( 0==rc ){
      s3jni_jbyteArray_commit(jTgt, pBa);
    }else{
      s3jni_jbyteArray_release(jTgt, pBa);
    }
  }
  return rc;
}

S3JniApi(sqlite3_blob_read_nio_buffer(),jint,1blob_1read_1nio_1buffer)(
  JniArgsEnvClass, jlong jpBlob, jint iSrcOff, jobject jBB, jint iTgtOff, jint iHowMany
){
  sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
  S3JniNioArgs args;
  int rc;
  if( !b || !SJG.g.byteBuffer.klazz || iHowMany<0 ){
    return SQLITE_MISUSE;
  }else if( iTgtOff<0 || iSrcOff<0 ){
    return SQLITE_ERROR
      /* for consistency with underlying sqlite3_blob_read() */;
  }else if( 0==iHowMany ){
    return 0;
  }
  rc = s3jni_setup_nio_args(env, &args, jBB, iTgtOff, iHowMany);
  if(rc){
    return rc;
  }else if( !args.pStart || !args.nOut ){
    return 0;
  }
  assert( args.iHowMany>0 );
  return sqlite3_blob_read( b, args.pStart, (int)args.nOut, (int)iSrcOff );
}

S3JniApi(sqlite3_blob_reopen(),jint,1blob_1reopen)(
  JniArgsEnvClass, jlong jpBlob, jlong iNewRowId
){
  return (jint)sqlite3_blob_reopen(S3JniLongPtr_sqlite3_blob(jpBlob),
  return (jint)sqlite3_blob_reopen(LongPtrGet_sqlite3_blob(jpBlob),
                                   (sqlite3_int64)iNewRowId);
}

S3JniApi(sqlite3_blob_write(),jint,1blob_1write)(
  JniArgsEnvClass, jlong jpBlob, jbyteArray jBa, jint iOffset
){
  sqlite3_blob * const b = S3JniLongPtr_sqlite3_blob(jpBlob);
  sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
  jbyte * const pBuf = b ? s3jni_jbyteArray_bytes(jBa) : 0;
  const jsize nBA = pBuf ? (*env)->GetArrayLength(env, jBa) : 0;
  int rc = SQLITE_MISUSE;
  if(b && pBuf){
    rc = sqlite3_blob_write( b, pBuf, (int)nBA, (int)iOffset );
  }
  s3jni_jbyteArray_release(jBa, pBuf);
  return (jint)rc;
}

S3JniApi(sqlite3_blob_write_nio_buffer(),jint,1blob_1write_1nio_1buffer)(
  JniArgsEnvClass, jlong jpBlob, jint iTgtOff, jobject jBB, jint iSrcOff, jint iHowMany
){
  sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
  S3JniNioArgs args;
  int rc;
  if( !b || !SJG.g.byteBuffer.klazz ){
    return SQLITE_MISUSE;
  }else if( iTgtOff<0 || iSrcOff<0 ){
    return SQLITE_ERROR
      /* for consistency with underlying sqlite3_blob_write() */;
  }else if( 0==iHowMany ){
    return 0;
  }
  rc = s3jni_setup_nio_args(env, &args, jBB, iSrcOff, iHowMany);
  if(rc){
    return rc;
  }else if( !args.pStart || !args.nOut ){
    return 0;
  }
  return sqlite3_blob_write( b, args.pStart, (int)args.nOut, (int)iTgtOff );
}

/* Central C-to-Java busy handler proxy. */
static int s3jni_busy_handler(void* pState, int n){
  S3JniDb * const ps = (S3JniDb *)pState;
  int rc = 0;
  S3JniDeclLocal_env;
  S3JniHook hook;
2816
2817
2818
2819
2820
2821
2822
2823

2824
2825
2826
2827
2828
2829
2830
3119
3120
3121
3122
3123
3124
3125

3126
3127
3128
3129
3130
3131
3132
3133







-
+







    rc = sqlite3_collation_needed(ps->pDb, 0, 0);
    if( 0==rc ){
      S3JniHook_unref(pHook);
    }
  }else{
    jclass const klazz = (*env)->GetObjectClass(env, jHook);
    jmethodID const xCallback = (*env)->GetMethodID(
      env, klazz, "call", "(Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I"
      env, klazz, "call", "(Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)V"
    );
    S3JniUnrefLocal(klazz);
    S3JniIfThrew {
      rc = s3jni_db_exception(ps->pDb, SQLITE_MISUSE,
                              "Cannot not find matching call() in "
                              "CollationNeededCallback object.");
    }else{
2865
2866
2867
2868
2869
2870
2871



































2872
2873
2874
2875
2876
2877
2878
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216







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







}

S3JniApi(sqlite3_column_int64(),jlong,1column_1int64)(
  JniArgsEnvClass, jobject jpStmt, jint ndx
){
  return (jlong)sqlite3_column_int64(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
}

S3JniApi(sqlite3_column_java_object(),jobject,1column_1java_1object)(
  JniArgsEnvClass, jlong jpStmt, jint ndx
){
  sqlite3_stmt * const stmt = LongPtrGet_sqlite3_stmt(jpStmt);
  jobject rv = 0;
  if( stmt ){
    sqlite3 * const db = sqlite3_db_handle(stmt);
    sqlite3_value * sv;
    sqlite3_mutex_enter(sqlite3_db_mutex(db));
    sv = sqlite3_column_value(stmt, (int)ndx);
    if( sv ){
      rv = S3JniRefLocal(
        sqlite3_value_pointer(sv, s3jni__value_jref_key)
      );
    }
    sqlite3_mutex_leave(sqlite3_db_mutex(db));
  }
  return rv;
}

S3JniApi(sqlite3_column_nio_buffer(),jobject,1column_1nio_1buffer)(
  JniArgsEnvClass, jobject jStmt, jint ndx
){
  sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jStmt);
  jobject rv = 0;
  if( stmt ){
    const void * const p = sqlite3_column_blob(stmt, (int)ndx);
    if( p ){
      const int n = sqlite3_column_bytes(stmt, (int)ndx);
      rv = s3jni__blob_to_ByteBuffer(env, p, n);
    }
  }
  return rv;
}

S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)(
  JniArgsEnvClass, jobject jpStmt, jint ndx
){
  sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt);
  const unsigned char * const p = stmt ? sqlite3_column_text(stmt, (int)ndx) : 0;
  const int n = p ? sqlite3_column_bytes(stmt, (int)ndx) : 0;
2921
2922
2923
2924
2925
2926
2927
2928




2929
2930
2931
2932
2933
2934
2935
3259
3260
3261
3262
3263
3264
3265

3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276







-
+
+
+
+







                     ? &ps->hooks.commit : &ps->hooks.rollback,
                     &hook);
  if( hook.jObj ){
    rc = isCommit
      ? (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback)
      : (int)((*env)->CallVoidMethod(env, hook.jObj, hook.midCallback), 0);
    S3JniIfThrew{
      rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR, "hook callback threw");
      rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR,
                              isCommit
                              ? "Commit hook callback threw"
                              : "Rollback hook callback threw");
    }
    S3JniHook_localundup(hook);
  }
  return rc;
}

/* C-to-Java commit hook wrapper. */
3024
3025
3026
3027
3028
3029
3030
3031

3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048



3049
3050
3051
3052
3053
3054
3055
3365
3366
3367
3368
3369
3370
3371

3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387


3388
3389
3390
3391
3392
3393
3394
3395
3396
3397







-
+















-
-
+
+
+







       hypothetically faster to convert). */;
  const jboolean rc =
    0==sqlite3_compileoption_used(zUtf8) ? JNI_FALSE : JNI_TRUE;
  s3jni_mutf8_release(name, zUtf8);
  return rc;
}

S3JniApi(sqlite3_complete(),int,1complete)(
S3JniApi(sqlite3_complete(),jint,1complete)(
  JniArgsEnvClass, jbyteArray jSql
){
  jbyte * const pBuf = s3jni_jbyteArray_bytes(jSql);
  const jsize nBA = pBuf ? (*env)->GetArrayLength(env, jSql) : 0;
  int rc;

  assert( (nBA>0 ? 0==pBuf[nBA-1] : (pBuf ? 0==*pBuf : 1))
          && "Byte array is not NUL-terminated." );
  rc = (pBuf && 0==pBuf[(nBA ? nBA-1 : 0)])
    ? sqlite3_complete( (const char *)pBuf )
    : (jSql ? SQLITE_NOMEM : SQLITE_MISUSE);
  s3jni_jbyteArray_release(jSql, pBuf);
  return rc;
}

S3JniApi(sqlite3_config() /*for a small subset of options.*/,
         jint,1config__I)(JniArgsEnvClass, jint n){
S3JniApi(sqlite3_config() /*for a small subset of options.*/
         sqlite3_config__enable()/* internal name to avoid name-mangling issues*/,
         jint,1config_1_1enable)(JniArgsEnvClass, jint n){
  switch( n ){
    case SQLITE_CONFIG_SINGLETHREAD:
    case SQLITE_CONFIG_MULTITHREAD:
    case SQLITE_CONFIG_SERIALIZED:
      return sqlite3_config( n );
    default:
      return SQLITE_MISUSE;
3071
3072
3073
3074
3075
3076
3077
3078
3079



3080
3081
3082
3083
3084
3085
3086
3413
3414
3415
3416
3417
3418
3419


3420
3421
3422
3423
3424
3425
3426
3427
3428
3429







-
-
+
+
+







      S3JniExceptionClear;
    }
    S3JniHook_localundup(hook);
    S3JniUnrefLocal(jArg1);
  }
}

S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_LOG */,
         jint, 1config__Lorg_sqlite_jni_ConfigLogCallback_2
S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_LOG */
         sqlite3_config__config_log() /* internal name */,
         jint, 1config_1_1CONFIG_1LOG
)(JniArgsEnvClass, jobject jLog){
  S3JniHook * const pHook = &SJG.hook.configlog;
  int rc = 0;

  S3JniGlobal_mutex_enter;
  if( !jLog ){
    rc = sqlite3_config( SQLITE_CONFIG_LOG, NULL, NULL );
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155




3156
3157
3158
3159
3160
3161
3162
3489
3490
3491
3492
3493
3494
3495



3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506







-
-
-
+
+
+
+







}
//! Requirement of SQLITE_CONFIG_SQLLOG.
void sqlite3_init_sqllog(void){
  sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 );
}
#endif

S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_SQLLOG */,
         jint, 1config__Lorg_sqlite_jni_ConfigSqllogCallback_2)(
           JniArgsEnvClass, jobject jLog){
S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_SQLLOG */
         sqlite3_config__SQLLOG() /*internal name*/,
         jint, 1config_1_1SQLLOG
)(JniArgsEnvClass, jobject jLog){
#ifndef SQLITE_ENABLE_SQLLOG
  return SQLITE_MISUSE;
#else
  S3JniHook * const pHook = &SJG.hook.sqllog;
  int rc = 0;

  S3JniGlobal_mutex_enter;
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3752
3753
3754
3755
3756
3757
3758

3759
3760
3761
3762
3763
3764
3765







-







      int pOut = 0;
      rc = sqlite3_db_config( ps->pDb, (int)op, onOff, &pOut );
      if( 0==rc && jOut ){
        OutputPointer_set_Int32(env, jOut, pOut);
      }
      break;
    }
    case 0:
    default:
      rc = SQLITE_MISUSE;
  }
  return (jint)rc;
}

/*
3471
3472
3473
3474
3475
3476
3477
3478

3479
3480
3481
3482
3483
3484
3485
3814
3815
3816
3817
3818
3819
3820

3821
3822
3823
3824
3825
3826
3827
3828







-
+







  S3JniDb * const ps = S3JniDb_from_java(jDb);
  char *zDbName = jDbName ? s3jni_jstring_to_utf8( jDbName, 0 ) : 0;
  rc = sqlite3_db_readonly(ps ? ps->pDb : 0, zDbName);
  sqlite3_free(zDbName);
  return (jint)rc;
}

S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory)(
S3JniApi(sqlite3_db_release_memory(),jint,1db_1release_1memory)(
  JniArgsEnvClass, jobject jDb
){
  sqlite3 * const pDb = PtrGet_sqlite3(jDb);
  return pDb ? sqlite3_db_release_memory(pDb) : SQLITE_MISUSE;
}

S3JniApi(sqlite3_db_status(),jint,1db_1status)(
3512
3513
3514
3515
3516
3517
3518







3519
3520
3521



3522
3523
3524
3525
3526
3527
3528
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868



3869
3870
3871
3872
3873
3874
3875
3876
3877
3878







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







       additional level of internal encoding in sqlite3. The end
       effect should be identical to using errmsg16(), however. */;
}

S3JniApi(sqlite3_errstr(),jstring,1errstr)(
  JniArgsEnvClass, jint rcCode
){
  jstring rv;
  const char * z = sqlite3_errstr((int)rcCode);
  if( !z ){
    /* This hypothetically cannot happen, but we'll behave like the
       low-level library would in such a case... */
    z = "unknown error";
  }
  jstring const rv = (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode))
    /* We know these values to be plain ASCII, so pose no MUTF-8
    ** incompatibility */;
  rv = (*env)->NewStringUTF(env, z)
      /* We know these values to be plain ASCII, so pose no MUTF-8
      ** incompatibility */;
  s3jni_oom_check( rv );
  return rv;
}

#ifndef SQLITE_ENABLE_NORMALIZE
/* Dummy stub for sqlite3_normalized_sql(). Never called. */
static const char * sqlite3_normalized_sql(sqlite3_stmt *s){
3566
3567
3568
3569
3570
3571
3572
3573

3574
3575
3576

3577
3578



3579
3580
3581
3582
3583
3584
3585

3586
3587
3588
3589
3590
3591
3592
3916
3917
3918
3919
3920
3921
3922

3923
3924
3925
3926
3927


3928
3929
3930
3931
3932
3933
3934
3935
3936

3937
3938
3939
3940
3941
3942
3943
3944







-
+



+
-
-
+
+
+






-
+







#ifdef SQLITE_ENABLE_NORMALIZE
  return s3jni_xn_sql(0, env, jpStmt);
#else
  return 0;
#endif
}

S3JniApi(sqlite3_extended_result_codes(),jboolean,1extended_1result_1codes)(
S3JniApi(sqlite3_extended_result_codes(),jint,1extended_1result_1codes)(
  JniArgsEnvClass, jobject jpDb, jboolean onoff
){
  sqlite3 * const pDb = PtrGet_sqlite3(jpDb);
  int const rc = pDb
  int const rc = pDb ? sqlite3_extended_result_codes(pDb, onoff ? 1 : 0) : 0;
  return rc ? JNI_TRUE : JNI_FALSE;
    ? sqlite3_extended_result_codes(pDb, onoff ? 1 : 0)
    : SQLITE_MISUSE;
  return rc;
}

S3JniApi(sqlite3_finalize(),jint,1finalize)(
  JniArgsEnvClass, jlong jpStmt
){
  return jpStmt
    ? sqlite3_finalize(S3JniLongPtr_sqlite3_stmt(jpStmt))
    ? sqlite3_finalize(LongPtrGet_sqlite3_stmt(jpStmt))
    : 0;
}

S3JniApi(sqlite3_get_auxdata(),jobject,1get_1auxdata)(
  JniArgsEnvClass, jobject jCx, jint n
){
  return sqlite3_get_auxdata(PtrGet_sqlite3_context(jCx), (int)n);
3619
3620
3621
3622
3623
3624
3625

3626


3627
3628
3629
3630
3631
3632























3633
3634
3635
3636
3637
3638
3639
3971
3972
3973
3974
3975
3976
3977
3978

3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016







+
-
+
+






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







}

/*
** Uncaches the current JNIEnv from the S3JniGlobal state, clearing
** any resources owned by that cache entry and making that slot
** available for re-use.
*/
S3JniApi(sqlite3_java_uncache_thread(), jboolean, 1java_1uncache_1thread)(
JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
  JniArgsEnvClass
){
  int rc;
  S3JniEnv_mutex_enter;
  rc = S3JniEnv_uncache(env);
  S3JniEnv_mutex_leave;
  return rc ? JNI_TRUE : JNI_FALSE;
}

S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
  JniArgsEnvClass, jobject jDb, jint jRc, jstring jStr
){
  S3JniDb * const ps = S3JniDb_from_java(jDb);
  int rc = SQLITE_MISUSE;
  if( ps ){
  char *zStr;
    zStr = jStr
      ? s3jni_jstring_to_utf8( jStr, 0)
      : NULL;
    rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
    sqlite3_free(zStr);
  }
  return rc;
}

S3JniApi(sqlite3_jni_supports_nio(), jboolean,1jni_1supports_1nio)(
  JniArgsEnvClass
){
  return SJG.g.byteBuffer.klazz ? JNI_TRUE : JNI_FALSE;
}


S3JniApi(sqlite3_keyword_check(),jboolean,1keyword_1check)(
  JniArgsEnvClass, jstring jWord
){
  int nWord = 0;
  char * zWord = s3jni_jstring_to_utf8(jWord, &nWord);
  int rc = 0;
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810





3811
3812
3813
3814

3815
3816
3817
3818
3819
3820
3821
4177
4178
4179
4180
4181
4182
4183




4184
4185
4186
4187
4188
4189
4190
4191

4192
4193
4194
4195
4196
4197
4198
4199







-
-
-
-
+
+
+
+
+



-
+







  assert(rc==0 ? pOut!=0 : 1);
  sqlite3_free(zName);
  sqlite3_free(zVfs);
  return (jint)rc;
}

/* Proxy for the sqlite3_prepare[_v2/3]() family. */
jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env, jclass self,
                               jlong jpDb, jbyteArray baSql,
                               jint nMax, jint prepFlags,
                               jobject jOutStmt, jobject outTail){
static jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env,
                                      jclass self,
                                      jlong jpDb, jbyteArray baSql,
                                      jint nMax, jint prepFlags,
                                      jobject jOutStmt, jobject outTail){
  sqlite3_stmt * pStmt = 0;
  jobject jStmt = 0;
  const char * zTail = 0;
  sqlite3 * const pDb = S3JniLongPtr_sqlite3(jpDb);
  sqlite3 * const pDb = LongPtrGet_sqlite3(jpDb);
  jbyte * const pBuf = pDb ? s3jni_jbyteArray_bytes(baSql)  : 0;
  int rc = SQLITE_ERROR;

  assert(prepVersion==1 || prepVersion==2 || prepVersion==3);
  if( !pDb || !jOutStmt ){
    rc = SQLITE_MISUSE;
    goto end;
3962
3963
3964
3965
3966
3967
3968
3969

3970
3971

3972
3973

3974
3975
3976
3977
3978
3979
3980
4340
4341
4342
4343
4344
4345
4346

4347
4348

4349
4350

4351
4352
4353
4354
4355
4356
4357
4358







-
+

-
+

-
+







static void s3jni_update_hook_impl(void * pState, int opId, const char *zDb,
                                   const char *zTable, sqlite3_int64 nRowid){
  return s3jni_updatepre_hook_impl(pState, NULL, opId, zDb, zTable, nRowid, 0);
}

#if !defined(SQLITE_ENABLE_PREUPDATE_HOOK)
/* We need no-op impls for preupdate_{count,depth,blobwrite}() */
S3JniApi(sqlite3_preupdate_blobwrite(),int,1preupdate_1blobwrite)(
S3JniApi(sqlite3_preupdate_blobwrite(),jint,1preupdate_1blobwrite)(
  JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; }
S3JniApi(sqlite3_preupdate_count(),int,1preupdate_1count)(
S3JniApi(sqlite3_preupdate_count(),jint,1preupdate_1count)(
  JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; }
S3JniApi(sqlite3_preupdate_depth(),int,1preupdate_1depth)(
S3JniApi(sqlite3_preupdate_depth(),jint,1preupdate_1depth)(
  JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; }
#endif /* !SQLITE_ENABLE_PREUPDATE_HOOK */

/*
** JNI wrapper for both sqlite3_update_hook() and
** sqlite3_preupdate_hook() (if isPre is true).
*/
4061
4062
4063
4064
4065
4066
4067
4068

4069
4070
4071
4072
4073
4074
4075
4439
4440
4441
4442
4443
4444
4445

4446
4447
4448
4449
4450
4451
4452
4453







-
+







#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
}

/* Impl for sqlite3_preupdate_{new,old}(). */
static int s3jni_preupdate_newold(JNIEnv * const env, int isNew, jlong jpDb,
                                  jint iCol, jobject jOut){
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  sqlite3 * const pDb = S3JniLongPtr_sqlite3(jpDb);
  sqlite3 * const pDb = LongPtrGet_sqlite3(jpDb);
  int rc = SQLITE_MISUSE;
  if( pDb ){
    sqlite3_value * pOut = 0;
    int (*fOrig)(sqlite3*,int,sqlite3_value**) =
      isNew ? sqlite3_preupdate_new : sqlite3_preupdate_old;
    rc = fOrig(pDb, (int)iCol, &pOut);
    if( 0==rc ){
4282
4283
4284
4285
4286
4287
4288
4289

4290
4291
4292
4293
4294
4295
4296
4660
4661
4662
4663
4664
4665
4666

4667
4668
4669
4670
4671
4672
4673
4674







-
+







S3JniApi(sqlite3_result_double(),void,1result_1double)(
  JniArgsEnvClass, jobject jpCx, jdouble v
){
  sqlite3_result_double(PtrGet_sqlite3_context(jpCx), v);
}

S3JniApi(sqlite3_result_error(),void,1result_1error)(
  JniArgsEnvClass, jobject jpCx, jbyteArray baMsg, int eTextRep
  JniArgsEnvClass, jobject jpCx, jbyteArray baMsg, jint eTextRep
){
  const char * zUnspecified = "Unspecified error.";
  jsize const baLen = (*env)->GetArrayLength(env, baMsg);
  jbyte * const pjBuf = baMsg ? s3jni_jbyteArray_bytes(baMsg) : NULL;
  switch( pjBuf ? eTextRep : SQLITE_UTF8 ){
    case SQLITE_UTF8: {
      const char *zMsg = pjBuf ? (const char *)pjBuf : zUnspecified;
4347
4348
4349
4350
4351
4352
4353
4354

4355
4356
4357
4358
4359
4360
4361


































4362
4363
4364
4365
4366
4367







4368
4369
4370
4371
4372
4373
4374
4725
4726
4727
4728
4729
4730
4731

4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793







-
+







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






+
+
+
+
+
+
+







){
  sqlite3_context * pCx = PtrGet_sqlite3_context(jpCx);
  if( !pCx ) return;
  else if( v ){
    jobject const rjv = S3JniRefGlobal(v);
    if( rjv ){
      sqlite3_result_pointer(pCx, rjv,
                             ResultJavaValuePtrStr, S3Jni_jobject_finalizer);
                             s3jni__value_jref_key, S3Jni_jobject_finalizer);
    }else{
      sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx));
    }
  }else{
    sqlite3_result_null(PtrGet_sqlite3_context(jpCx));
  }
}

S3JniApi(sqlite3_result_nio_buffer(),void,1result_1nio_1buffer)(
  JniArgsEnvClass, jobject jpCtx, jobject jBuffer,
  jint iOffset, jint iN
){
  sqlite3_context * pCx = PtrGet_sqlite3_context(jpCtx);
  int rc;
  S3JniNioArgs args;
  if( !pCx ){
    return;
  }else if( !SJG.g.byteBuffer.klazz ){
    sqlite3_result_error(
      pCx, "This JVM does not support JNI access to ByteBuffers.", -1
    );
    return;
  }
  rc = s3jni_setup_nio_args(env, &args, jBuffer, iOffset, iN);
  if(rc){
    if( iOffset<0 ){
      sqlite3_result_error(pCx, "Start index may not be negative.", -1);
    }else if( SQLITE_TOOBIG==rc ){
      sqlite3_result_error_toobig(pCx);
    }else{
      sqlite3_result_error(
        pCx, "Invalid arguments to sqlite3_result_nio_buffer().", -1
      );
    }
  }else if( !args.pStart || !args.nOut ){
    sqlite3_result_null(pCx);
  }else{
    sqlite3_result_blob(pCx, args.pStart, args.nOut, SQLITE_TRANSIENT);
  }
}


S3JniApi(sqlite3_result_null(),void,1result_1null)(
  JniArgsEnvClass, jobject jpCx
){
  sqlite3_result_null(PtrGet_sqlite3_context(jpCx));
}

S3JniApi(sqlite3_result_subtype(),void,1result_1subtype)(
  JniArgsEnvClass, jobject jpCx, jint v
){
  sqlite3_result_subtype(PtrGet_sqlite3_context(jpCx), (unsigned int)v);
}


S3JniApi(sqlite3_result_text(),void,1result_1text)(
  JniArgsEnvClass, jobject jpCx, jbyteArray jBa, jint nMax
){
  return result_blob_text(0, SQLITE_UTF8, env,
                          PtrGet_sqlite3_context(jpCx), jBa, nMax);
}
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549

4550
4551
4552
4553
4554
4555

4556
4557
4558
4559
4560
4561
4562
4954
4955
4956
4957
4958
4959
4960








4961






4962
4963
4964
4965
4966
4967
4968
4969







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







  } S3JniHook_mutex_leave;
  /* Free up env cache. */
  S3JniEnv_mutex_enter; {
    while( SJG.envCache.aHead ){
      S3JniEnv_uncache( SJG.envCache.aHead->env );
    }
  } S3JniEnv_mutex_leave;
#if 0
  /*
  ** Is automatically closing any still-open dbs a good idea? We will
  ** get rid of the perDb list once sqlite3 gets a per-db client
  ** state, at which point we won't have a central list of databases
  ** to close.
  */
  S3JniDb_mutex_enter;
  /* Do not clear S3JniGlobal.jvm or S3JniGlobal.g: it's legal to
  while( SJG.perDb.pHead ){
    s3jni_close_db(env, SJG.perDb.pHead->jDb, 2);
  }
  S3JniDb_mutex_leave;
#endif
  /* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
  ** restart the lib. */
  return sqlite3_shutdown();
}

S3JniApi(sqlite3_status(),jint,1status)(
  JniArgsEnvClass, jint op, jobject jOutCurrent, jobject jOutHigh,
                    jboolean reset
){
4590
4591
4592
4593
4594
4595
4596
4597

4598
4599
4600
4601
4602
4603
4604
4997
4998
4999
5000
5001
5002
5003

5004
5005
5006
5007
5008
5009
5010
5011







-
+







}


static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
                              jbyteArray baG, jbyteArray baT, jint escLike){
  int rc = 0;
  jbyte * const pG = s3jni_jbyteArray_bytes(baG);
  jbyte * const pT = pG ? s3jni_jbyteArray_bytes(baT) : 0;
  jbyte * const pT = s3jni_jbyteArray_bytes(baT);

  /* Note that we're relying on the byte arrays having been
     NUL-terminated on the Java side. */
  rc = isLike
    ? sqlite3_strlike((const char *)pG, (const char *)pT,
                      (unsigned int)escLike)
    : sqlite3_strglob((const char *)pG, (const char *)pT);
4629
4630
4631
4632
4633
4634
4635
4636

4637
4638

4639
4640
4641
4642

4643
4644
4645
4646
4647
4648
4649
5036
5037
5038
5039
5040
5041
5042

5043
5044

5045
5046
5047
5048

5049
5050
5051
5052
5053
5054
5055
5056







-
+

-
+



-
+







    zSql = sqlite3_sql(pStmt);
    rv = s3jni_utf8_to_jstring( zSql, -1);
  }
  return rv;
}

S3JniApi(sqlite3_step(),jint,1step)(
  JniArgsEnvClass,jobject jStmt
  JniArgsEnvClass, jlong jpStmt
){
  sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jStmt);
  sqlite3_stmt * const pStmt = LongPtrGet_sqlite3_stmt(jpStmt);
  return pStmt ? (jint)sqlite3_step(pStmt) : (jint)SQLITE_MISUSE;
}

S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)(
S3JniApi(sqlite3_table_column_metadata(),jint,1table_1column_1metadata)(
  JniArgsEnvClass, jobject jDb, jstring jDbName, jstring jTableName,
  jstring jColumnName, jobject jDataType, jobject jCollSeq, jobject jNotNull,
  jobject jPrimaryKey, jobject jAutoinc
){
  sqlite3 * const db = PtrGet_sqlite3(jDb);
  char * zDbName = 0, * zTableName = 0, * zColumnName = 0;
  const char * pzCollSeq = 0;
4811
4812
4813
4814
4815
4816
4817
4818

4819
4820
4821
4822
4823
4824
4825
4826
4827
4828

4829
4830
4831

4832
4833
4834
4835

4836
4837
4838

4839
4840
4841
4842
4843
4844
4845
4846

4847
4848
4849
4850
4851
4852
4853
4854

4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867

4868
4869
4870
4871
4872
4873
4874
4875
4876

4877
4878
4879
4880
4881
4882
4883

4884
4885
4886
4887
4888
4889
4890

4891
4892

4893
4894















4895
4896
4897
4898
4899

4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910

4911
4912
4913
4914
4915
4916
4917
4918
4919
4920

4921
4922
4923
4924
4925
4926
4927
5218
5219
5220
5221
5222
5223
5224

5225
5226
5227
5228
5229
5230
5231
5232
5233
5234

5235
5236
5237

5238
5239
5240
5241

5242
5243
5244

5245
5246
5247
5248
5249
5250
5251
5252

5253
5254
5255
5256
5257
5258
5259
5260

5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273

5274
5275
5276
5277
5278
5279
5280
5281
5282

5283
5284
5285
5286
5287
5288
5289

5290
5291
5292
5293
5294
5295
5296

5297
5298

5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320

5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331

5332
5333
5334
5335
5336
5337
5338
5339
5340
5341

5342
5343
5344
5345
5346
5347
5348
5349







-
+









-
+


-
+



-
+


-
+







-
+







-
+












-
+








-
+






-
+






-
+

-
+


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




-
+










-
+









-
+







  return s3jni_updatepre_hook(env, 0, jpDb, jHook);
}


S3JniApi(sqlite3_value_blob(),jbyteArray,1value_1blob)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  const jbyte * pBytes = sv ? sqlite3_value_blob(sv) : 0;
  int const nLen = pBytes ? sqlite3_value_bytes(sv) : 0;

  s3jni_oom_check( nLen ? !!pBytes : 1 );
  return pBytes
    ? s3jni_new_jbyteArray(pBytes, nLen)
    : NULL;
}

S3JniApi(sqlite3_value_bytes(),int,1value_1bytes)(
S3JniApi(sqlite3_value_bytes(),jint,1value_1bytes)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  return sv ? sqlite3_value_bytes(sv) : 0;
}

S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)(
S3JniApi(sqlite3_value_bytes16(),jint,1value_1bytes16)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  return sv ? sqlite3_value_bytes16(sv) : 0;
}


S3JniApi(sqlite3_value_double(),jdouble,1value_1double)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  return (jdouble) (sv ? sqlite3_value_double(sv) : 0.0);
}


S3JniApi(sqlite3_value_dup(),jobject,1value_1dup)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  sqlite3_value * const sd = sv ? sqlite3_value_dup(sv) : 0;
  jobject rv = sd ? new_java_sqlite3_value(env, sd) : 0;
  if( sd && !rv ) {
    /* OOM */
    sqlite3_value_free(sd);
  }
  return rv;
}

S3JniApi(sqlite3_value_free(),void,1value_1free)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  if( sv ){
    sqlite3_value_free(sv);
  }
}

S3JniApi(sqlite3_value_int(),jint,1value_1int)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  return (jint) (sv ? sqlite3_value_int(sv) : 0);
}

S3JniApi(sqlite3_value_int64(),jlong,1value_1int64)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  return (jlong) (sv ? sqlite3_value_int64(sv) : 0LL);
}

S3JniApi(sqlite3_value_java_object(),jobject,1value_1java_1object)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  return sv
    ? sqlite3_value_pointer(sv, ResultJavaValuePtrStr)
    ? sqlite3_value_pointer(sv, s3jni__value_jref_key)
    : 0;
}

S3JniApi(sqlite3_value_nio_buffer(),jobject,1value_1nio_1buffer)(
  JniArgsEnvClass, jobject jVal
){
  sqlite3_value * const sv = PtrGet_sqlite3_value(jVal);
  jobject rv = 0;
  if( sv ){
    const void * const p = sqlite3_value_blob(sv);
    if( p ){
      const int n = sqlite3_value_bytes(sv);
      rv = s3jni__blob_to_ByteBuffer(env, p, n);
    }
  }
  return rv;
}

S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  const unsigned char * const p = sv ? sqlite3_value_text(sv) : 0;
  int const n = p ? sqlite3_value_bytes(sv) : 0;
  return p ? s3jni_new_jbyteArray(p, n) : 0;
}

#if 0
// this impl might prove useful.
S3JniApi(sqlite3_value_text(),jstring,1value_1text)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  const unsigned char * const p = sv ? sqlite3_value_text(sv) : 0;
  int const n = p ? sqlite3_value_bytes(sv) : 0;
  return p ? s3jni_utf8_to_jstring( (const char *)p, n) : 0;
}
#endif

S3JniApi(sqlite3_value_text16(),jstring,1value_1text16)(
  JniArgsEnvClass, jlong jpSVal
){
  sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
  sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
  const int n = sv ? sqlite3_value_bytes16(sv) : 0;
  const void * const p = sv ? sqlite3_value_text16(sv) : 0;
  return p ? s3jni_text16_to_jstring(env, p, n) : 0;
}

JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
  MARKER(("\nVarious bits of internal info:\n"));
5495
5496
5497
5498
5499
5500
5501
5502

5503
5504
5505
5506
5507
5508
5509
5917
5918
5919
5920
5921
5922
5923

5924
5925
5926
5927
5928
5929
5930
5931







-
+







}

JniDeclFtsXA(jlong,xRowid)(JniArgsEnvObj,jobject jCtx){
  Fts5ExtDecl;
  return (jlong)ext->xRowid(PtrGet_Fts5Context(jCtx));
}

JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
JniDeclFtsXA(jint,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
  Fts5ExtDecl;
  int rc;
  S3JniFts5AuxData * pAux;

  pAux = s3jni_malloc( sizeof(*pAux));
  if( !pAux ){
    if( jAux ){
5888
5889
5890
5891
5892
5893
5894






















5895
5896
5897
5898
5899
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







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





  SJG.autoExt.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
  s3jni_oom_fatal( SJG.autoExt.mutex );

#if S3JNI_METRICS_MUTEX
  SJG.metrics.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
  s3jni_oom_fatal( SJG.metrics.mutex );
#endif

  {
    /* Test whether this JVM supports direct memory access via
       ByteBuffer. */
    unsigned char buf[16] = {0};
    jobject bb = (*env)->NewDirectByteBuffer(env, buf, 16);
    if( bb ){
      SJG.g.byteBuffer.klazz = S3JniRefGlobal((*env)->GetObjectClass(env, bb));
      SJG.g.byteBuffer.midAlloc = (*env)->GetStaticMethodID(
        env, SJG.g.byteBuffer.klazz, "allocateDirect", "(I)Ljava/nio/ByteBuffer;"
      );
      S3JniExceptionIsFatal("Error getting ByteBuffer.allocateDirect() method.");
      SJG.g.byteBuffer.midLimit = (*env)->GetMethodID(
        env, SJG.g.byteBuffer.klazz, "limit", "()I"
      );
      S3JniExceptionIsFatal("Error getting ByteBuffer.limit() method.");
      S3JniUnrefLocal(bb);
    }else{
      SJG.g.byteBuffer.klazz = 0;
      SJG.g.byteBuffer.midAlloc = 0;
    }
  }

  sqlite3_shutdown()
    /* So that it becomes legal for Java-level code to call
    ** sqlite3_config(). */;
}
Changes to ext/jni/src/c/sqlite3-jni.h.
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
423
424
425
426
427
428
429


430
431
432
433
434
435
436







-
-







#define org_sqlite_jni_capi_CApi_SQLITE_OPEN_PRIVATECACHE 262144L
#undef org_sqlite_jni_capi_CApi_SQLITE_OPEN_NOFOLLOW
#define org_sqlite_jni_capi_CApi_SQLITE_OPEN_NOFOLLOW 16777216L
#undef org_sqlite_jni_capi_CApi_SQLITE_OPEN_EXRESCODE
#define org_sqlite_jni_capi_CApi_SQLITE_OPEN_EXRESCODE 33554432L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE 2L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB 4L
#undef org_sqlite_jni_capi_CApi_SQLITE_OK
#define org_sqlite_jni_capi_CApi_SQLITE_OK 0L
#undef org_sqlite_jni_capi_CApi_SQLITE_ERROR
#define org_sqlite_jni_capi_CApi_SQLITE_ERROR 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_INTERNAL
703
704
705
706
707
708
709


710
711


712
713
714
715
716
717
718
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720







+
+


+
+







#define org_sqlite_jni_capi_CApi_SQLITE_TXN_READ 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_TXN_WRITE
#define org_sqlite_jni_capi_CApi_SQLITE_TXN_WRITE 2L
#undef org_sqlite_jni_capi_CApi_SQLITE_DETERMINISTIC
#define org_sqlite_jni_capi_CApi_SQLITE_DETERMINISTIC 2048L
#undef org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY
#define org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY 524288L
#undef org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE
#define org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE 1048576L
#undef org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS
#define org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS 2097152L
#undef org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE
#define org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE 16777216L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE
#define org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_EQ
#define org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_EQ 2L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_GT
#define org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_GT 4L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_LE
771
772
773
774
775
776
777
















778
779
780
781
782
783
784
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







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







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_java_uncache_thread
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1java_1uncache_1thread
  (JNIEnv *, jclass);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_jni_supports_nio
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio
  (JNIEnv *, jclass);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_jni_db_error
 * Signature: (Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1db_1error
  (JNIEnv *, jclass, jobject, jint, jstring);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_aggregate_context
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Z)J
 */
JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1aggregate_1context
  (JNIEnv *, jclass, jobject, jboolean);
867
868
869
870
871
872
873








874
875
876
877
878
879
880
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906







+
+
+
+
+
+
+
+







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_bind_java_object
 * Signature: (JILjava/lang/Object;)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1java_1object
  (JNIEnv *, jclass, jlong, jint, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_bind_nio_buffer
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;ILjava/nio/ByteBuffer;II)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1nio_1buffer
  (JNIEnv *, jclass, jobject, jint, jobject, jint, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_bind_null
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1null
  (JNIEnv *, jclass, jlong, jint);
971
972
973
974
975
976
977








978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993








994
995
996
997
998
999
1000
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042







+
+
+
+
+
+
+
+
















+
+
+
+
+
+
+
+







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_blob_read
 * Signature: (J[BI)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read
  (JNIEnv *, jclass, jlong, jbyteArray, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_blob_read_nio_buffer
 * Signature: (JILjava/nio/ByteBuffer;II)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read_1nio_1buffer
  (JNIEnv *, jclass, jlong, jint, jobject, jint, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_blob_reopen
 * Signature: (JJ)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1reopen
  (JNIEnv *, jclass, jlong, jlong);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_blob_write
 * Signature: (J[BI)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write
  (JNIEnv *, jclass, jlong, jbyteArray, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_blob_write_nio_buffer
 * Signature: (JILjava/nio/ByteBuffer;II)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write_1nio_1buffer
  (JNIEnv *, jclass, jlong, jint, jobject, jint, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_busy_handler
 * Signature: (JLorg/sqlite/jni/capi/BusyHandlerCallback;)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1busy_1handler
  (JNIEnv *, jclass, jlong, jobject);
1083
1084
1085
1086
1087
1088
1089








1090
1091
1092
1093
1094
1095
1096
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146







+
+
+
+
+
+
+
+







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_count
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1count
  (JNIEnv *, jclass, jlong);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_database_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
  (JNIEnv *, jclass, jlong, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_decltype
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1decltype
  (JNIEnv *, jclass, jlong, jint);
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
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







+
+
+
+
+
+
+
+










-
-
+
+

-
-
+
+







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_int64
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;I)J
 */
JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int64
  (JNIEnv *, jclass, jobject, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_java_object
 * Signature: (JI)Ljava/lang/Object;
 */
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1java_1object
  (JNIEnv *, jclass, jlong, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1name
  (JNIEnv *, jclass, jlong, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_database_name
 * Signature: (JI)Ljava/lang/String;
 * Method:    sqlite3_column_nio_buffer
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;I)Ljava/nio/ByteBuffer;
 */
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
  (JNIEnv *, jclass, jlong, jint);
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1nio_1buffer
  (JNIEnv *, jclass, jobject, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_column_origin_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1origin_1name
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
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







-
+


-
+




-
-
+
+

-
+




-
-
+
+

-
+







 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1complete
  (JNIEnv *, jclass, jbyteArray);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_config
 * Method:    sqlite3_config__enable
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__I
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1enable
  (JNIEnv *, jclass, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_config
 * Signature: (Lorg/sqlite/jni/capi/ConfigSqllogCallback;)I
 * Method:    sqlite3_config__CONFIG_LOG
 * Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigSqllogCallback_2
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1CONFIG_1LOG
  (JNIEnv *, jclass, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_config
 * Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
 * Method:    sqlite3_config__SQLLOG
 * Signature: (Lorg/sqlite/jni/capi/ConfigSqlLogCallback;)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigLogCallback_2
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1SQLLOG
  (JNIEnv *, jclass, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_context_db_handle
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)Lorg/sqlite/jni/capi/sqlite3;
 */
1390
1391
1392
1393
1394
1395
1396
1397

1398
1399

1400
1401
1402
1403
1404
1405
1406
1448
1449
1450
1451
1452
1453
1454

1455
1456

1457
1458
1459
1460
1461
1462
1463
1464







-
+

-
+







 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1errcode
  (JNIEnv *, jclass, jlong);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_extended_result_codes
 * Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)Z
 * Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)I
 */
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes
  (JNIEnv *, jclass, jobject, jboolean);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_get_autocommit
 * Signature: (J)Z
 */
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1733
1734
1735
1736
1737
1738
1739








1740
1741
1742
1743
1744
1745
1746







-
-
-
-
-
-
-
-







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_error_code
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;I)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error_1code
  (JNIEnv *, jclass, jobject, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_null
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1null
  (JNIEnv *, jclass, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_int
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;I)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1int
  (JNIEnv *, jclass, jobject, jint);
1707
1708
1709
1710
1711
1712
1713
























1714
1715
1716
1717
1718
1719
1720
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







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







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_java_object
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1java_1object
  (JNIEnv *, jclass, jobject, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_nio_buffer
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Ljava/nio/ByteBuffer;II)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1nio_1buffer
  (JNIEnv *, jclass, jobject, jobject, jint, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_null
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1null
  (JNIEnv *, jclass, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_subtype
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;I)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1subtype
  (JNIEnv *, jclass, jobject, jint);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_result_value
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Lorg/sqlite/jni/capi/sqlite3_value;)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1value
  (JNIEnv *, jclass, jobject, jobject);
1846
1847
1848
1849
1850
1851
1852
1853

1854
1855
1856

1857
1858
1859
1860
1861
1862
1863
1920
1921
1922
1923
1924
1925
1926

1927
1928
1929

1930
1931
1932
1933
1934
1935
1936
1937







-
+


-
+







 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1status64
  (JNIEnv *, jclass, jint, jobject, jobject, jboolean);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_step
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;)I
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1step
  (JNIEnv *, jclass, jobject);
  (JNIEnv *, jclass, jlong);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_stmt_busy
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;)Z
 */
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1stmt_1busy
2059
2060
2061
2062
2063
2064
2065








2066
2067
2068
2069
2070
2071
2072
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154







+
+
+
+
+
+
+
+







 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_value_java_object
 * Signature: (J)Ljava/lang/Object;
 */
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1java_1object
  (JNIEnv *, jclass, jlong);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_value_nio_buffer
 * Signature: (Lorg/sqlite/jni/capi/sqlite3_value;)Ljava/nio/ByteBuffer;
 */
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1nio_1buffer
  (JNIEnv *, jclass, jobject);

/*
 * Class:     org_sqlite_jni_capi_CApi
 * Method:    sqlite3_value_nochange
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1nochange
  (JNIEnv *, jclass, jlong);
Added ext/jni/src/org/sqlite/jni/annotation/Experimental.java.






























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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2023-09-27
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file houses the Experimental annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;

/**
   This annotation is for flagging methods, constructors, and types
   which are expressly experimental and subject to any amount of
   change or outright removal. Client code should not rely on such
   features.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({
    ElementType.METHOD,
    ElementType.CONSTRUCTOR,
    ElementType.TYPE
})
public @interface Experimental{}
Changes to ext/jni/src/org/sqlite/jni/annotation/NotNull.java.
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
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











-
+


+






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







-
+



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











-
+




-
-
-
+
+
+

/*
** 2023-09-27
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file houses the NotNull annotaion for the sqlite3 C API.
** This file houses the NotNull annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;

/**
   This annotation is for flagging parameters which may not legally be
   null or point to closed/finalized C-side resources.

   <p>In the case of Java types which map directly to C struct types
   (e.g. {@link org.sqlite.jni.sqlite3}, {@link
   org.sqlite.jni.sqlite3_stmt}, and {@link
   org.sqlite.jni.sqlite3_context}), a closed/finalized resource is
   also considered to be null for purposes this annotation because the
   C-side effect of passing such a handle is the same as if null is
   passed.</p>
   (e.g. {@link org.sqlite.jni.capi.sqlite3}, {@link
   org.sqlite.jni.capi.sqlite3_stmt}, and {@link
   org.sqlite.jni.capi.sqlite3_context}), a closed/finalized resource
   is also considered to be null for purposes this annotation because
   the C-side effect of passing such a handle is the same as if null
   is passed.</p>

   <p>When used in the context of Java interfaces which are called
   from the C APIs, this annotation communicates that the C API will
   never pass a null value to the callback for that parameter.</p>

   <p>Passing a null, for this annotation's definition of null, for
   any parameter marked with this annoation specifically invokes
   undefined behavior.</p>
   undefined behavior (see below).</p>

   <p>Passing 0 (i.e. C NULL) or a negative value for any long-type
   parameter marked with this annoation specifically invokes undefined
   behavior. Such values are treated as C pointers in the JNI
   layer.</p>
   behavior (see below). Such values are treated as C pointers in the
   JNI layer.</p>

   <p><b>Undefined behaviour:</b> the JNI build uses the {@code
   SQLITE_ENABLE_API_ARMOR} build flag, meaning that the C code
   invoked with invalid NULL pointers and the like will not invoke
   undefined behavior in the conventional C sense, but may, for
   example, return result codes which are not documented for the
   affected APIs or may otherwise behave unpredictably. In no known
   cases will such arguments result in C-level code dereferencing a
   NULL pointer or accessing out-of-bounds (or otherwise invalid)
   memory. In other words, they may cause unexpected behavior but
   should never cause an outright crash or security issue.</p>

   <p>Note that the C-style API does not throw any exceptions on its
   own because it has a no-throw policy in order to retain its C-style
   semantics, but it may trigger NullPointerExceptions (or similar) if
   passed a null for a parameter flagged with this annotation.</p>

   <p>This annotation is informational only. No policy is in place to
   programmatically ensure that NotNull is conformed to in client
   code.</p>

   <p>This annotation is solely for the use by the classes in the
   org.sqlite package and subpackages, but is made public so that
   org.sqlite.jni package and subpackages, but is made public so that
   javadoc will link to it from the annotated functions. It is not
   part of the public API and client-level code must not rely on
   it.</p>
*/
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
public @interface NotNull{}
Changes to ext/jni/src/org/sqlite/jni/annotation/Nullable.java.
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
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











-
+


+














-
-
-
+
+
+

/*
** 2023-09-27
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file houses the Nullable annotaion for the sqlite3 C API.
** This file houses the Nullable annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;

/**
   This annotation is for flagging parameters which may legally be
   null, noting that they may behave differently if passed null but
   are prepared to expect null as a value. When used in the context of
   callback methods which are called into from the C APIs, this
   annotation communicates that the C API may pass a null value to the
   callback.

   <p>This annotation is solely for the use by the classes in this
   package but is made public so that javadoc will link to it from the
   annotated functions. It is not part of the public API and
   client-level code must not rely on it.
*/
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
public @interface Nullable{}
Changes to ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java.
37
38
39
40
41
42
43
44



































































45
46

47
48
49
50
51
52
53
54
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








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

-
+
-







  public abstract void xFinal(sqlite3_context cx);

  /**
     Optionally override to be notified when the UDF is finalized by
     SQLite.
  */
  public void xDestroy() {}

  /**
     PerContextState assists aggregate and window functions in
     managing their accumulator state across calls to the UDF's
     callbacks.

     <p>T must be of a type which can be legally stored as a value in
     java.util.HashMap<KeyType,T>.

     <p>If a given aggregate or window function is called multiple times
     in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
     then the clients need some way of knowing which call is which so
     that they can map their state between their various UDF callbacks
     and reset it via xFinal(). This class takes care of such
     mappings.

     <p>This class works by mapping
     sqlite3_context.getAggregateContext() to a single piece of
     state, of a client-defined type (the T part of this class), which
     persists across a "matching set" of the UDF's callbacks.

     <p>This class is a helper providing commonly-needed functionality
     - it is not required for use with aggregate or window functions.
     Client UDFs are free to perform such mappings using custom
     approaches. The provided {@link AggregateFunction} and {@link
     WindowFunction} classes use this.
  */
  public static final class PerContextState<T> {
    private final java.util.Map<Long,ValueHolder<T>> map
      = new java.util.HashMap<>();

    /**
       Should be called from a UDF's xStep(), xValue(), and xInverse()
       methods, passing it that method's first argument and an initial
       value for the persistent state. If there is currently no
       mapping for the given context within the map, one is created
       using the given initial value, else the existing one is used
       and the 2nd argument is ignored.  It returns a ValueHolder<T>
       which can be used to modify that state directly without
       requiring that the client update the underlying map's entry.

       <p>The caller is obligated to eventually call
       takeAggregateState() to clear the mapping.
    */
    public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
      final Long key = cx.getAggregateContext(true);
      ValueHolder<T> rc = null==key ? null : map.get(key);
      if( null==rc ){
        map.put(key, rc = new ValueHolder<>(initialValue));
      }
      return rc;
    }

    /**
       Should be called from a UDF's xFinal() method and passed that
       method's first argument. This function removes the value
       associated with cx.getAggregateContext() from the map and
       returns it, returning null if no other UDF method has been
       called to set up such a mapping. The latter condition will be
       the case if a UDF is used in a statement which has no result
       rows.
    */
    public T takeAggregateState(sqlite3_context cx){
      final ValueHolder<T> h = map.remove(cx.getAggregateContext(false));
      return null==h ? null : h.value;
    }
  }

  /** Per-invocation state for the UDF. */
  private final SQLFunction.PerContextState<T> map =
  private final PerContextState<T> map = new PerContextState<>();
    new SQLFunction.PerContextState<>();

  /**
     To be called from the implementation's xStep() method, as well
     as the xValue() and xInverse() methods of the {@link WindowFunction}
     subclass, to fetch the current per-call UDF state. On the
     first call to this method for any given sqlite3_context
     argument, the context is set to the given initial value. On all other
Changes to ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java.
16
17
18
19
20
21
22
23


24
25
26
27
28
16
17
18
19
20
21
22

23
24
25
26
27
28
29







-
+
+






/**
   Callback for use with {@link CApi#sqlite3_set_authorizer}.
*/
public interface AuthorizerCallback extends CallbackProxy {
  /**
     Must function as described for the C-level
     sqlite3_set_authorizer() callback.
     sqlite3_set_authorizer() callback. If it throws, the error is
     converted to a db-level error and the exception is suppressed.
  */
  int call(int opId, @Nullable String s1, @Nullable String s2,
           @Nullable String s3, @Nullable String s4);

}
Changes to ext/jni/src/org/sqlite/jni/capi/CApi.java.
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











-
+







/*
** 2023-07-21
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file declares JNI bindings for the sqlite3 C API.
** This file declares the main JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
import java.nio.charset.StandardCharsets;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
28
29
30
31
32
33
34









35
36
37
38
39
40
41







-
-
-
-
-
-
-
-
-








  <pre>{@code
  import static org.sqlite.jni.capi.CApi.*;
  }</pre>

  <p>The C-side part can be found in sqlite3-jni.c.

  <p>This class is package-private in order to keep Java clients from
  having direct access to the low-level C-style APIs, a design
  decision made by Java developers based on the C-style API being
  riddled with opportunities for Java developers to proverbially shoot
  themselves in the foot with. Third-party copies of this code may
  eliminate that guard by simply changing this class from
  package-private to public. Its methods which are intended to be
  exposed that way are all public.

  <p>Only functions which materially differ from their C counterparts
  are documented here, and only those material differences are
  documented. The C documentation is otherwise applicable for these
  APIs:

  <p><a href="https://sqlite.org/c3ref/intro.html">https://sqlite.org/c3ref/intro.html</a>

74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
65
66
67
68
69
70
71

72
73
74
75
76
77
78
79







-
+








  <li>C functions which take C-style strings without a length argument
  require special care when taking input from Java. In particular,
  Java strings converted to byte arrays for encoding purposes are not
  NUL-terminated, and conversion to a Java byte array must sometimes
  be careful to add one. Functions which take a length do not require
  this so long as the length is provided. Search the CApi class
  for "\0" for many examples.
  for "\0" for examples.

  </ul>

  <p>Further reading:

  <p><a href="https://stackoverflow.com/questions/57419723">https://stackoverflow.com/questions/57419723</a>
  <p><a href="https://stackoverflow.com/questions/7921016">https://stackoverflow.com/questions/7921016</a>
124
125
126
127
128
129
130
131



132
133


























134
135
136
137
138
139
140
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







-
+
+
+


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







     required. Additional threads must call this before ending or they
     will leak cache entries in the C heap, which in turn may keep
     numerous Java-side global references active.

     <p>This routine returns false without side effects if the current
     JNIEnv is not cached, else returns true, but this information is
     primarily for testing of the JNI bindings and is not information
     which client-level code can use to make any informed decisions.
     which client-level code can use to make any informed
     decisions. Its return type and semantics are not considered
     stable and may change at any time.
  */
  public static native boolean sqlite3_java_uncache_thread();

  /**
     Returns true if this JVM has JNI-level support for C-level direct
     memory access using java.nio.ByteBuffer, else returns false.
  */
  @Experimental
  public static native boolean sqlite3_jni_supports_nio();

  /**
     For internal use only. Sets the given db's error code and
     (optionally) string. If rc is 0, it defaults to SQLITE_ERROR.

     On success it returns rc. On error it may return a more serious
     code, such as SQLITE_NOMEM. Returns SQLITE_MISUSE if db is null.
  */
  static native int sqlite3_jni_db_error(@NotNull sqlite3 db,
                                         int rc, @Nullable String msg);

  /**
     Convenience overload which uses e.toString() as the error
     message.
  */
  static int sqlite3_jni_db_error(@NotNull sqlite3 db,
                                  int rc, @NotNull Exception e){
    return sqlite3_jni_db_error(db, rc, e.toString());
  }

  //////////////////////////////////////////////////////////////////////
  // Maintenance reminder: please keep the sqlite3_.... functions
  // alphabetized.  The SQLITE_... values. on the other hand, are
  // grouped by category.

  /**
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
188
189
190
191
192
193
194

195
196
197

198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213

214
215
216
217
218
219

220
221
222
223
224
225

226
227
228
229
230
231

232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
305

306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376

377
378
379
380
381
382

383
384
385
386
387
388
389
390







-
+


-
+


-
+












-
+





-
+





-
+





-
+







-
+













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









-
+









-
+







-
+


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













-
+





-
+







     execute for the current database. That is, doing so will result
     in unpredictable, but not undefined, behavior.

     <p>See the AutoExtension class docs for more information.
  */
  public static native int sqlite3_auto_extension(@NotNull AutoExtensionCallback callback);

  static native int sqlite3_backup_finish(@NotNull long ptrToBackup);
  private static native int sqlite3_backup_finish(@NotNull long ptrToBackup);

  public static int sqlite3_backup_finish(@NotNull sqlite3_backup b){
    return sqlite3_backup_finish(b.clearNativePointer());
    return null==b ? 0 : sqlite3_backup_finish(b.clearNativePointer());
  }

  static native sqlite3_backup sqlite3_backup_init(
  private static native sqlite3_backup sqlite3_backup_init(
    @NotNull long ptrToDbDest, @NotNull String destTableName,
    @NotNull long ptrToDbSrc, @NotNull String srcTableName
  );

  public static sqlite3_backup sqlite3_backup_init(
    @NotNull sqlite3 dbDest, @NotNull String destTableName,
    @NotNull sqlite3 dbSrc, @NotNull String srcTableName
  ){
    return sqlite3_backup_init( dbDest.getNativePointer(), destTableName,
                                dbSrc.getNativePointer(), srcTableName );
  }

  static native int sqlite3_backup_pagecount(@NotNull long ptrToBackup);
  private static native int sqlite3_backup_pagecount(@NotNull long ptrToBackup);

  public static int sqlite3_backup_pagecount(@NotNull sqlite3_backup b){
    return sqlite3_backup_pagecount(b.getNativePointer());
  }

  static native int sqlite3_backup_remaining(@NotNull long ptrToBackup);
  private static native int sqlite3_backup_remaining(@NotNull long ptrToBackup);

  public static int sqlite3_backup_remaining(@NotNull sqlite3_backup b){
    return sqlite3_backup_remaining(b.getNativePointer());
  }

  static native int sqlite3_backup_step(@NotNull long ptrToBackup, int nPage);
  private static native int sqlite3_backup_step(@NotNull long ptrToBackup, int nPage);

  public static int sqlite3_backup_step(@NotNull sqlite3_backup b, int nPage){
    return sqlite3_backup_step(b.getNativePointer(), nPage);
  }

  static native int sqlite3_bind_blob(
  private static native int sqlite3_bind_blob(
    @NotNull long ptrToStmt, int ndx, @Nullable byte[] data, int n
  );

  /**
     If n is negative, SQLITE_MISUSE is returned. If n>data.length
     then n is silently truncated to data.length.
  */
  static int sqlite3_bind_blob(
  public static int sqlite3_bind_blob(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
  ){
    return sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, n);
  }

  public static int sqlite3_bind_blob(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
  ){
    return (null==data)
      ? sqlite3_bind_null(stmt.getNativePointer(), ndx)
      : sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, data.length);
  }

  /**
     Convenience overload which is a simple proxy for
     sqlite3_bind_nio_buffer().
  */
  @Experimental
  /*public*/ static int sqlite3_bind_blob(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
    int begin, int n
  ){
    return sqlite3_bind_nio_buffer(stmt, ndx, data, begin, n);
  }

  /**
     Convenience overload which is equivalant to passing its arguments
     to sqlite3_bind_nio_buffer() with the values 0 and -1 for the
     final two arguments.
  */
  @Experimental
  /*public*/ static int sqlite3_bind_blob(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
  ){
    return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
  }

  static native int sqlite3_bind_double(
  private static native int sqlite3_bind_double(
    @NotNull long ptrToStmt, int ndx, double v
  );

  public static int sqlite3_bind_double(
    @NotNull sqlite3_stmt stmt, int ndx, double v
  ){
    return sqlite3_bind_double(stmt.getNativePointer(), ndx, v);
  }

  static native int sqlite3_bind_int(
  private static native int sqlite3_bind_int(
    @NotNull long ptrToStmt, int ndx, int v
  );

  public static int sqlite3_bind_int(
    @NotNull sqlite3_stmt stmt, int ndx, int v
  ){
    return sqlite3_bind_int(stmt.getNativePointer(), ndx, v);
  }

  static native int sqlite3_bind_int64(
  private static native int sqlite3_bind_int64(
    @NotNull long ptrToStmt, int ndx, long v
  );

  public static int sqlite3_bind_int64(@NotNull sqlite3_stmt stmt, int ndx, long v){
    return sqlite3_bind_int64( stmt.getNativePointer(), ndx, v );
  }

  static native int sqlite3_bind_java_object(
  private static native int sqlite3_bind_java_object(
    @NotNull long ptrToStmt, int ndx, @Nullable Object o
  );

  /**
     Binds the contents of the given buffer object as a blob.

     The byte range of the buffer may be restricted by providing a
     start index and a number of bytes. beginPos may not be negative.
     Negative howMany is interpretated as the remainder of the buffer
     past the given start position, up to the buffer's limit() (as
     opposed its capacity()).

     If beginPos+howMany would extend past the limit() of the buffer
     then SQLITE_ERROR is returned.

     If any of the following are true, this function behaves like
     sqlite3_bind_null(): the buffer is null, beginPos is at or past
     the end of the buffer, howMany is 0, or the calculated slice of
     the blob has a length of 0.

     If ndx is out of range, it returns SQLITE_RANGE, as documented
     for sqlite3_bind_blob().  If beginPos is negative or if
     sqlite3_jni_supports_nio() returns false then SQLITE_MISUSE is
     returned.  Note that this function is bound (as it were) by the
     SQLITE_LIMIT_LENGTH constraint and SQLITE_TOOBIG is returned if
     the resulting slice of the buffer exceeds that limit.

     This function does not modify the buffer's streaming-related
     cursors.

     If the buffer is modified in a separate thread while this
     operation is running, results are undefined and will likely
     result in corruption of the bound data or a segmentation fault.

     Design note: this function should arguably take a java.nio.Buffer
     instead of ByteBuffer, but it can only operate on "direct"
     buffers and the only such class offered by Java is (apparently)
     ByteBuffer.

     @see https://docs.oracle.com/javase/8/docs/api/java/nio/Buffer.html
  */
  @Experimental
  /*public*/ static native int sqlite3_bind_nio_buffer(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
    int beginPos, int howMany
  );

  /**
     Convenience overload which binds the given buffer's entire
     contents, up to its limit() (as opposed to its capacity()).
  */
  @Experimental
  /*public*/ static int sqlite3_bind_nio_buffer(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
  ){
    return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
  }

  /**
     Binds the given object at the given index. If o is null then this behaves like
     sqlite3_bind_null().

     @see #sqlite3_result_java_object
  */
  public static int sqlite3_bind_java_object(
    @NotNull sqlite3_stmt stmt, int ndx, @Nullable Object o
  ){
    return sqlite3_bind_java_object(stmt.getNativePointer(), ndx, o);
  }

  static native int sqlite3_bind_null(@NotNull long ptrToStmt, int ndx);
  private static native int sqlite3_bind_null(@NotNull long ptrToStmt, int ndx);

  public static int sqlite3_bind_null(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_bind_null(stmt.getNativePointer(), ndx);
  }

  static native int sqlite3_bind_parameter_count(@NotNull long ptrToStmt);
  private static native int sqlite3_bind_parameter_count(@NotNull long ptrToStmt);

  public static int sqlite3_bind_parameter_count(@NotNull sqlite3_stmt stmt){
    return sqlite3_bind_parameter_count(stmt.getNativePointer());
  }

  /**
     Requires that paramName be a NUL-terminated UTF-8 string.
305
306
307
308
309
310
311
312

313
314
315
316
317
318
319
320

321
322
323
324
325
326
327
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417

418
419
420
421
422
423
424
425







-
+







-
+







  public static int sqlite3_bind_parameter_index(
    @NotNull sqlite3_stmt stmt, @NotNull String paramName
  ){
    final byte[] utf8 = nulTerminateUtf8(paramName);
    return null==utf8 ? 0 : sqlite3_bind_parameter_index(stmt.getNativePointer(), utf8);
  }

  static native String sqlite3_bind_parameter_name(
  private static native String sqlite3_bind_parameter_name(
    @NotNull long ptrToStmt, int index
  );

  public static String sqlite3_bind_parameter_name(@NotNull sqlite3_stmt stmt, int index){
    return sqlite3_bind_parameter_name(stmt.getNativePointer(), index);
  }

  static native int sqlite3_bind_text(
  private static native int sqlite3_bind_text(
    @NotNull long ptrToStmt, int ndx, @Nullable byte[] utf8, int maxBytes
  );

  /**
     Works like the C-level sqlite3_bind_text() but assumes
     SQLITE_TRANSIENT for the final C API parameter. The byte array is
     assumed to be in UTF-8 encoding.
357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
455
456
457
458
459
460
461

462
463
464
465
466
467
468
469







-
+







    @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] utf8
  ){
    return ( null==utf8 )
      ? sqlite3_bind_null(stmt.getNativePointer(), ndx)
      : sqlite3_bind_text(stmt.getNativePointer(), ndx, utf8, utf8.length);
  }

  static native int sqlite3_bind_text16(
  private static native int sqlite3_bind_text16(
    @NotNull long ptrToStmt, int ndx, @Nullable byte[] data, int maxBytes
  );

  /**
     Identical to the sqlite3_bind_text() overload with the same
     signature but requires that its input be encoded in UTF-16 in
     platform byte order.
398
399
400
401
402
403
404
405

406
407
408
409
410
411
412
413
414
415
416

417
418
419
420
421
422

423
424
425
426
427
428
429
430

431
432
433
434
435
436

437
438
439

440
441
442

443
444
445
446
447
448
449
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







-
+










-
+





-
+







-
+





-
+


-
+


-
+







    @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
  ){
    return (null == data)
      ? sqlite3_bind_null(stmt.getNativePointer(), ndx)
      : sqlite3_bind_text16(stmt.getNativePointer(), ndx, data, data.length);
  }

  static native int sqlite3_bind_value(@NotNull long ptrToStmt, int ndx, long ptrToValue);
  private static native int sqlite3_bind_value(@NotNull long ptrToStmt, int ndx, long ptrToValue);

  /**
     Functions like the C-level sqlite3_bind_value(), or
     sqlite3_bind_null() if val is null.
  */
  public static int sqlite3_bind_value(@NotNull sqlite3_stmt stmt, int ndx, sqlite3_value val){
    return sqlite3_bind_value(stmt.getNativePointer(), ndx,
                              null==val ? 0L : val.getNativePointer());
  }

  static native int sqlite3_bind_zeroblob(@NotNull long ptrToStmt, int ndx, int n);
  private static native int sqlite3_bind_zeroblob(@NotNull long ptrToStmt, int ndx, int n);

  public static int sqlite3_bind_zeroblob(@NotNull sqlite3_stmt stmt, int ndx, int n){
    return sqlite3_bind_zeroblob(stmt.getNativePointer(), ndx, n);
  }

  static native int sqlite3_bind_zeroblob64(
  private static native int sqlite3_bind_zeroblob64(
    @NotNull long ptrToStmt, int ndx, long n
  );

  public static int sqlite3_bind_zeroblob64(@NotNull sqlite3_stmt stmt, int ndx, long n){
    return sqlite3_bind_zeroblob64(stmt.getNativePointer(), ndx, n);
  }

  static native int sqlite3_blob_bytes(@NotNull long ptrToBlob);
  private static native int sqlite3_blob_bytes(@NotNull long ptrToBlob);

  public static int sqlite3_blob_bytes(@NotNull sqlite3_blob blob){
    return sqlite3_blob_bytes(blob.getNativePointer());
  }

  static native int sqlite3_blob_close(@Nullable long ptrToBlob);
  private static native int sqlite3_blob_close(@Nullable long ptrToBlob);

  public static int sqlite3_blob_close(@Nullable sqlite3_blob blob){
    return sqlite3_blob_close(blob.clearNativePointer());
    return null==blob ? 0 : sqlite3_blob_close(blob.clearNativePointer());
  }

  static native int sqlite3_blob_open(
  private static native int sqlite3_blob_open(
    @NotNull long ptrToDb, @NotNull String dbName,
    @NotNull String tableName, @NotNull String columnName,
    long iRow, int flags, @NotNull OutputPointer.sqlite3_blob out
  );

  public static int sqlite3_blob_open(
    @NotNull sqlite3 db, @NotNull String dbName,
463
464
465
466
467
468
469
470
471


472
473





474


























475


476














































477































478
479
480

481
482
483
484
485
486
487
488

489
490
491
492
493
494
495
496
497














































































498

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

514
515
516
517
518
519
520
521
522
523

524
525
526
527
528
529

530
531
532
533
534
535

536
537
538
539
540
541

542
543
544
545
546
547
548


549
550

551
552

553
554
555

556
557
558
559
560
561
562

563
564
565
566
567
568

569
570
571
572
573
574

575
576
577
578
579









580

581
582
583
584
585
586
587
588
589
590
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
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
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652

653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685

686
687
688
689
690
691
692
693

694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886

887
888
889
890
891
892
893
894
895
896
897


898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915

916
917


918
919
920
921
922
923
924
925
926
927
928
929
930
931
932

933
934
935
936
937
938
939
940
941

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







-
-
+
+


+
+
+
+
+

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

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


-
+







-
+









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














-
+









-
+





-
+





-
+





-
+


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


-
+






-
+





-
+





-
+





+
+
+
+
+
+
+
+
+
-
+

















+
-
+
+

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


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

-
-
+
+


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

+
+
+




-
+

+
+
+







    long iRow, int flags ){
    final OutputPointer.sqlite3_blob out = new OutputPointer.sqlite3_blob();
    sqlite3_blob_open(db.getNativePointer(), dbName, tableName, columnName,
                      iRow, flags, out);
    return out.take();
  };

  static native int sqlite3_blob_read(
    @NotNull long ptrToBlob, @NotNull byte[] target, int iOffset
  private static native int sqlite3_blob_read(
    @NotNull long ptrToBlob, @NotNull byte[] target, int srcOffset
  );

  /**
     As per C's sqlite3_blob_read(), but writes its output to the
     given byte array. Note that the final argument is the offset of
     the source buffer, not the target array.
   */
  public static int sqlite3_blob_read(
    @NotNull sqlite3_blob src, @NotNull byte[] target, int srcOffset
  ){
    return sqlite3_blob_read(src.getNativePointer(), target, srcOffset);
  }

  /**
     An internal level of indirection.
  */
  @Experimental
  private static native int sqlite3_blob_read_nio_buffer(
    @NotNull long ptrToBlob, int srcOffset,
    @NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
  );

  /**
     Reads howMany bytes from offset srcOffset of src into position
     tgtOffset of tgt.

     Returns SQLITE_MISUSE if src is null, tgt is null, or
     sqlite3_jni_supports_nio() returns false. Returns SQLITE_ERROR if
     howMany or either offset are negative.  If argument validation
     succeeds, it returns the result of the underlying call to
     sqlite3_blob_read() (0 on success).
  */
  @Experimental
  /*public*/ static int sqlite3_blob_read_nio_buffer(
    @NotNull sqlite3_blob b, @NotNull byte[] target, int iOffset
    @NotNull sqlite3_blob src, int srcOffset,
    @NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
  ){
    return (JNI_SUPPORTS_NIO && src!=null && tgt!=null)
      ? sqlite3_blob_read_nio_buffer(
        src.getNativePointer(), srcOffset, tgt, tgtOffset, howMany
      )
      : SQLITE_MISUSE;
  }

  /**
     Convenience overload which reads howMany bytes from position
     srcOffset of src and returns the result as a new ByteBuffer.

     srcOffset may not be negative. If howMany is negative, it is
     treated as all bytes following srcOffset.

     Returns null if sqlite3_jni_supports_nio(), any arguments are
     invalid, if the number of bytes to read is 0 or is larger than
     the src blob, or the underlying call to sqlite3_blob_read() fails
     for any reason.
  */
  @Experimental
  /*public*/ static java.nio.ByteBuffer sqlite3_blob_read_nio_buffer(
    @NotNull sqlite3_blob src, int srcOffset, int howMany
  ){
    if( !JNI_SUPPORTS_NIO || src==null ) return null;
    else if( srcOffset<0 ) return null;
    final int nB = sqlite3_blob_bytes(src);
    if( srcOffset>=nB ) return null;
    else if( howMany<0 ) howMany = nB - srcOffset;
    if( srcOffset + howMany > nB ) return null;
    final java.nio.ByteBuffer tgt =
      java.nio.ByteBuffer.allocateDirect(howMany);
    final int rc = sqlite3_blob_read_nio_buffer(
      src.getNativePointer(), srcOffset, tgt, 0, howMany
    );
    return 0==rc ? tgt : null;
  }

  /**
     Overload alias for sqlite3_blob_read_nio_buffer().
  */
  @Experimental
  /*public*/ static int sqlite3_blob_read(
    @NotNull sqlite3_blob src, int srcOffset,
    @NotNull java.nio.ByteBuffer tgt,
    int tgtOffset, int howMany
  ){
    return sqlite3_blob_read(b.getNativePointer(), target, iOffset);
    return sqlite3_blob_read_nio_buffer(
      src, srcOffset, tgt, tgtOffset, howMany
    );
  }

  /**
     Convenience overload which uses 0 for both src and tgt offsets
     and reads a number of bytes equal to the smaller of
     sqlite3_blob_bytes(src) and tgt.limit().

     On success it sets tgt.limit() to the number of bytes read. On
     error, tgt.limit() is not modified.

     Returns 0 on success. Returns SQLITE_MISUSE is either argument is
     null or sqlite3_jni_supports_nio() returns false. Else it returns
     the result of the underlying call to sqlite3_blob_read().
  */
  @Experimental
  /*public*/ static int sqlite3_blob_read(
    @NotNull sqlite3_blob src,
    @NotNull java.nio.ByteBuffer tgt
  ){
    if(!JNI_SUPPORTS_NIO || src==null || tgt==null) return SQLITE_MISUSE;
    final int nSrc = sqlite3_blob_bytes(src);
    final int nTgt = tgt.limit();
    final int nRead = nTgt<nSrc ? nTgt : nSrc;
    final int rc = sqlite3_blob_read_nio_buffer(
      src.getNativePointer(), 0, tgt, 0, nRead
    );
    if( 0==rc && nTgt!=nRead ) tgt.limit( nRead );
    return rc;
  }

  static native int sqlite3_blob_reopen(
  private static native int sqlite3_blob_reopen(
    @NotNull long ptrToBlob, long newRowId
  );

  public static int sqlite3_blob_reopen(@NotNull sqlite3_blob b, long newRowId){
    return sqlite3_blob_reopen(b.getNativePointer(), newRowId);
  }

  static native int sqlite3_blob_write(
  private static native int sqlite3_blob_write(
    @NotNull long ptrToBlob, @NotNull byte[] bytes, int iOffset
  );

  public static int sqlite3_blob_write(
    @NotNull sqlite3_blob b, @NotNull byte[] bytes, int iOffset
  ){
    return sqlite3_blob_write(b.getNativePointer(), bytes, iOffset);
  }

  /**
     An internal level of indirection.
  */
  @Experimental
  private static native int sqlite3_blob_write_nio_buffer(
    @NotNull long ptrToBlob, int tgtOffset,
    @NotNull java.nio.ByteBuffer src,
    int srcOffset, int howMany
  );

  /**
     Writes howMany bytes of memory from offset srcOffset of the src
     buffer at position tgtOffset of b.

     If howMany is negative then it's equivalent to the number of
     bytes remaining starting at srcOffset.

     Returns SQLITE_MISUSE if tgt is null or sqlite3_jni_supports_nio()
     returns false.

     Returns SQLITE_MISUSE if src is null or
     sqlite3_jni_supports_nio() returns false. Returns SQLITE_ERROR if
     either offset is negative.  If argument validation succeeds, it
     returns the result of the underlying call to sqlite3_blob_read().
  */
  @Experimental
  /*public*/ static int sqlite3_blob_write_nio_buffer(
    @NotNull sqlite3_blob tgt, int tgtOffset,
    @NotNull java.nio.ByteBuffer src,
    int srcOffset, int howMany
  ){
    return sqlite3_blob_write_nio_buffer(
      tgt.getNativePointer(), tgtOffset, src, srcOffset, howMany
    );
  }

  /**
     Overload alias for sqlite3_blob_write_nio_buffer().
  */
  @Experimental
  public static int sqlite3_blob_write(
    @NotNull sqlite3_blob tgt, int tgtOffset,
    @NotNull java.nio.ByteBuffer src,
    int srcOffset, int howMany
  ){
    return sqlite3_blob_write_nio_buffer(
      tgt.getNativePointer(), tgtOffset, src, srcOffset, howMany
    );
  }

  /**
     Convenience overload which writes all of src to the given offset
     of b.
  */
  @Experimental
  /*public*/ static int sqlite3_blob_write(
    @NotNull sqlite3_blob tgt, int tgtOffset,
    @NotNull java.nio.ByteBuffer src
  ){
    return sqlite3_blob_write_nio_buffer(
      tgt.getNativePointer(), tgtOffset, src, 0, -1
    );
  }

  /**
     Convenience overload which writes all of src to offset 0
     of tgt.
   */
  @Experimental
  /*public*/ static int sqlite3_blob_write(
    @NotNull sqlite3_blob tgt,
    @NotNull java.nio.ByteBuffer src
  ){
    return sqlite3_blob_write_nio_buffer(
      tgt.getNativePointer(), 0, src, 0, -1
    );
  }

  static native int sqlite3_busy_handler(
  private static native int sqlite3_busy_handler(
    @NotNull long ptrToDb, @Nullable BusyHandlerCallback handler
  );

  /**
     As for the C-level function of the same name, with a
     BusyHandlerCallback instance in place of a callback
     function. Pass it a null handler to clear the busy handler.
  */
  public static int sqlite3_busy_handler(
    @NotNull sqlite3 db, @Nullable BusyHandlerCallback handler
  ){
    return sqlite3_busy_handler(db.getNativePointer(), handler);
  }

  static native int sqlite3_busy_timeout(@NotNull long ptrToDb, int ms);
  private static native int sqlite3_busy_timeout(@NotNull long ptrToDb, int ms);

  public static int sqlite3_busy_timeout(@NotNull sqlite3 db, int ms){
    return sqlite3_busy_timeout(db.getNativePointer(), ms);
  }

  public static native boolean sqlite3_cancel_auto_extension(
    @NotNull AutoExtensionCallback ax
  );

  static native int sqlite3_changes(@NotNull long ptrToDb);
  private static native int sqlite3_changes(@NotNull long ptrToDb);

  public static int sqlite3_changes(@NotNull sqlite3 db){
    return sqlite3_changes(db.getNativePointer());
  }

  static native long sqlite3_changes64(@NotNull long ptrToDb);
  private static native long sqlite3_changes64(@NotNull long ptrToDb);

  public static long sqlite3_changes64(@NotNull sqlite3 db){
    return sqlite3_changes64(db.getNativePointer());
  }

  static native int sqlite3_clear_bindings(@NotNull long ptrToStmt);
  private static native int sqlite3_clear_bindings(@NotNull long ptrToStmt);

  public static int sqlite3_clear_bindings(@NotNull sqlite3_stmt stmt){
    return sqlite3_clear_bindings(stmt.getNativePointer());
  }

  static native int sqlite3_close(@Nullable long ptrToDb);
  private static native int sqlite3_close(@Nullable long ptrToDb);

  public static int sqlite3_close(@Nullable sqlite3 db){
    int rc = 0;
    if( null!=db ){
      rc = sqlite3_close(db.getNativePointer());
      if( 0==rc ) db.clearNativePointer();
    }
    return null==db ? 0 : sqlite3_close(db.clearNativePointer());
  }
    return rc;
  }


  static native int sqlite3_close_v2(@Nullable long ptrToDb);
  private static native int sqlite3_close_v2(@Nullable long ptrToDb);

  public static int sqlite3_close_v2(@Nullable sqlite3 db){
    return db==null ? 0 : sqlite3_close_v2(db.clearNativePointer());
    return null==db ? 0 : sqlite3_close_v2(db.clearNativePointer());
  }

  public static native byte[] sqlite3_column_blob(
    @NotNull sqlite3_stmt stmt, int ndx
  );

  static native int sqlite3_column_bytes(@NotNull long ptrToStmt, int ndx);
  private static native int sqlite3_column_bytes(@NotNull long ptrToStmt, int ndx);

  public static int sqlite3_column_bytes(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_bytes(stmt.getNativePointer(), ndx);
  }

  static native int sqlite3_column_bytes16(@NotNull long ptrToStmt, int ndx);
  private static native int sqlite3_column_bytes16(@NotNull long ptrToStmt, int ndx);

  public static int sqlite3_column_bytes16(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_bytes16(stmt.getNativePointer(), ndx);
  }

  static native int sqlite3_column_count(@NotNull long ptrToStmt);
  private static native int sqlite3_column_count(@NotNull long ptrToStmt);

  public static int sqlite3_column_count(@NotNull sqlite3_stmt stmt){
    return sqlite3_column_count(stmt.getNativePointer());
  }

  private static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx);

  /**
     Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
  */
  public static String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_database_name(stmt.getNativePointer(), ndx);
  }

  static native String sqlite3_column_decltype(@NotNull long ptrToStmt, int ndx);
  private static native String sqlite3_column_decltype(@NotNull long ptrToStmt, int ndx);

  public static String sqlite3_column_decltype(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_decltype(stmt.getNativePointer(), ndx);
  }

  public static native double sqlite3_column_double(
    @NotNull sqlite3_stmt stmt, int ndx
  );

  public static native int sqlite3_column_int(
    @NotNull sqlite3_stmt stmt, int ndx
  );

  public static native long sqlite3_column_int64(
    @NotNull sqlite3_stmt stmt, int ndx
  );

  private static native Object sqlite3_column_java_object(
  static native String sqlite3_column_name(@NotNull long ptrToStmt, int ndx);
    @NotNull long ptrToStmt, int ndx
  );

  /**
     If the given result column was bound with
     sqlite3_bind_java_object() or sqlite3_result_java_object() then
     that object is returned, else null is returned. This routine
     requires locking the owning database's mutex briefly in order to
     extract the object in a thread-safe way.
  */
  public static Object sqlite3_column_java_object(
  public static String sqlite3_column_name(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_name(stmt.getNativePointer(), ndx);
    @NotNull sqlite3_stmt stmt, int ndx
  ){
    return sqlite3_column_java_object( stmt.getNativePointer(), ndx );
  }

  /**
     If the two-parameter overload of sqlite3_column_java_object()
     returns non-null and the returned value is an instance of T then
     that object is returned, else null is returned.
  */
  @SuppressWarnings("unchecked")
  public static <T> T sqlite3_column_java_object(
    @NotNull sqlite3_stmt stmt, int ndx, @NotNull Class<T> type
  ){
    final Object o = sqlite3_column_java_object(stmt, ndx);
    return type.isInstance(o) ? (T)o : null;
  }

  static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx);
  private static native String sqlite3_column_name(@NotNull long ptrToStmt, int ndx);

  public static String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_database_name(stmt.getNativePointer(), ndx);
  public static String sqlite3_column_name(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_name(stmt.getNativePointer(), ndx);
  }

  /**
     A variant of sqlite3_column_blob() which returns the blob as a
     ByteBuffer object. Returns null if its argument is null, if
     sqlite3_jni_supports_nio() is false, or if sqlite3_column_blob()
     would return null for the same inputs.
  */
  @Experimental
  /*public*/ static native java.nio.ByteBuffer sqlite3_column_nio_buffer(
    @NotNull sqlite3_stmt stmt, int ndx
  );

  static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx);
  private static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx);

  /**
     Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
  */
  public static String sqlite3_column_origin_name(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_origin_name(stmt.getNativePointer(), ndx);
  }

  static native String sqlite3_column_table_name(@NotNull long ptrToStmt, int ndx);
  private static native String sqlite3_column_table_name(@NotNull long ptrToStmt, int ndx);

  /**
     Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
  */
  public static String sqlite3_column_table_name(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_table_name(stmt.getNativePointer(), ndx);
  }

  /**
     Functions identially to the C API, and this note is just to
     stress that the returned bytes are encoded as UTF-8. It returns
668
669
670
671
672
673
674
675

676
677
678
679
680
681
682
683
684
685

686
687
688
689
690
691
692
693
694
695
696
697
698
699

700
701
702
703
704
705
706
997
998
999
1000
1001
1002
1003

1004
1005
1006
1007
1008
1009
1010
1011
1012
1013

1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027

1028
1029
1030
1031
1032
1033
1034
1035







-
+









-
+













-
+







  //       default: break;
  //     }
  //   }
  //   sqlite3_value_free(v);
  //   return rv;
  // }

  static native int sqlite3_column_type(@NotNull long ptrToStmt, int ndx);
  private static native int sqlite3_column_type(@NotNull long ptrToStmt, int ndx);

  public static int sqlite3_column_type(@NotNull sqlite3_stmt stmt, int ndx){
    return sqlite3_column_type(stmt.getNativePointer(), ndx);
  }

  public static native sqlite3_value sqlite3_column_value(
    @NotNull sqlite3_stmt stmt, int ndx
  );

  static native int sqlite3_collation_needed(
  private static native int sqlite3_collation_needed(
    @NotNull long ptrToDb, @Nullable CollationNeededCallback callback
  );

  /**
     This functions like C's sqlite3_collation_needed16() because
     Java's string type is inherently compatible with that interface.
  */
  public static int sqlite3_collation_needed(
    @NotNull sqlite3 db, @Nullable CollationNeededCallback callback
  ){
    return sqlite3_collation_needed(db.getNativePointer(), callback);
  }

  static native CommitHookCallback sqlite3_commit_hook(
  private static native CommitHookCallback sqlite3_commit_hook(
    @NotNull long ptrToDb, @Nullable CommitHookCallback hook
  );

  public static CommitHookCallback sqlite3_commit_hook(
    @NotNull sqlite3 db, @Nullable CommitHookCallback hook
  ){
    return sqlite3_commit_hook(db.getNativePointer(), hook);
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
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







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
















-
+
+
+




-
+










-
+
+
+





-
+
+
+







     Unlike the C API, this returns SQLITE_MISUSE if its argument is
     null (as opposed to invoking UB).
  */
  public static int sqlite3_complete(@NotNull String sql){
    return sqlite3_complete( nulTerminateUtf8(sql) );
  }

  /**
     Internal level of indirection for sqlite3_config(int).
  */
  private static native int sqlite3_config__enable(int op);

  /**
     Internal level of indirection for sqlite3_config(ConfigLogCallback).
  */
  private static native int sqlite3_config__CONFIG_LOG(
    @Nullable ConfigLogCallback logger
  );

  /**
     Internal level of indirection for sqlite3_config(ConfigSqlLogCallback).
  */
  private static native int sqlite3_config__SQLLOG(
    @Nullable ConfigSqlLogCallback logger
  );

  /**
     <p>Works like in the C API with the exception that it only supports
     the following subset of configution flags:

     <p>SQLITE_CONFIG_SINGLETHREAD
     SQLITE_CONFIG_MULTITHREAD
     SQLITE_CONFIG_SERIALIZED

     <p>Others may be added in the future. It returns SQLITE_MISUSE if
     given an argument it does not handle.

     <p>Note that sqlite3_config() is not threadsafe with regards to
     the rest of the library. This must not be called when any other
     library APIs are being called.
  */
  public static native int sqlite3_config(int op);
  public static int sqlite3_config(int op){
    return sqlite3_config__enable(op);
  }

  /**
     If the native library was built with SQLITE_ENABLE_SQLLOG defined
     then this acts as a proxy for C's
     sqlite3_config(SQLITE_ENABLE_SQLLOG,...). This sets or clears the
     sqlite3_config(SQLITE_CONFIG_SQLLOG,...). This sets or clears the
     logger. If installation of a logger fails, any previous logger is
     retained.

     <p>If not built with SQLITE_ENABLE_SQLLOG defined, this returns
     SQLITE_MISUSE.

     <p>Note that sqlite3_config() is not threadsafe with regards to
     the rest of the library. This must not be called when any other
     library APIs are being called.
  */
  public static native int sqlite3_config( @Nullable ConfigSqllogCallback logger );
  public static int sqlite3_config( @Nullable ConfigSqlLogCallback logger ){
    return sqlite3_config__SQLLOG(logger);
  }

  /**
     The sqlite3_config() overload for handling the SQLITE_CONFIG_LOG
     option.
  */
  public static native int sqlite3_config( @Nullable ConfigLogCallback logger );
  public static int sqlite3_config( @Nullable ConfigLogCallback logger ){
    return sqlite3_config__CONFIG_LOG(logger);
  }

  /**
     Unlike the C API, this returns null if its argument is
     null (as opposed to invoking UB).
  */
  public static native sqlite3 sqlite3_context_db_handle(
    @NotNull sqlite3_context cx
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
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







-
+











-
+







     functionName arguments are null (as opposed to invoking UB).
  */
  public static native int sqlite3_create_function(
    @NotNull sqlite3 db, @NotNull String functionName,
    int nArg, int eTextRep, @NotNull SQLFunction func
  );

  static native int sqlite3_data_count(@NotNull long ptrToStmt);
  private static native int sqlite3_data_count(@NotNull long ptrToStmt);

  public static int sqlite3_data_count(@NotNull sqlite3_stmt stmt){
    return sqlite3_data_count(stmt.getNativePointer());
  }

  /**
     Overload for sqlite3_db_config() calls which take (int,int*)
     variadic arguments. Returns SQLITE_MISUSE if op is not one of the
     SQLITE_DBCONFIG_... options which uses this call form.

     <p>Unlike the C API, this returns SQLITE_MISUSE if its db argument
     are null (as opposed to invoking UB).
     is null (as opposed to invoking UB).
  */
  public static native int sqlite3_db_config(
    @NotNull sqlite3 db, int op, int onOff, @Nullable OutputPointer.Int32 out
  );

  /**
     Overload for sqlite3_db_config() calls which take a (const char*)
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
886
887

888
889
890
891
892
893
894
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







-



















-
+













-
+





-
-
+
+


-
+









-
+








  private static native String sqlite3_db_name(@NotNull long ptrToDb, int ndx);

  public static String sqlite3_db_name(@NotNull sqlite3 db, int ndx){
    return null==db ? null : sqlite3_db_name(db.getNativePointer(), ndx);
  }


  public static native String sqlite3_db_filename(
    @NotNull sqlite3 db, @NotNull String dbName
  );

  public static native sqlite3 sqlite3_db_handle(@NotNull sqlite3_stmt stmt);

  public static native int sqlite3_db_readonly(@NotNull sqlite3 db, String dbName);

  public static native int sqlite3_db_release_memory(sqlite3 db);

  public static native int sqlite3_db_status(
    @NotNull sqlite3 db, int op, @NotNull OutputPointer.Int32 pCurrent,
    @NotNull OutputPointer.Int32 pHighwater, boolean reset
  );

  public static native int sqlite3_errcode(@NotNull sqlite3 db);

  public static native String sqlite3_errmsg(@NotNull sqlite3 db);

  static native int sqlite3_error_offset(@NotNull long ptrToDb);
  private static native int sqlite3_error_offset(@NotNull long ptrToDb);

  /**
     Note that the returned byte offset values assume UTF-8-encoded
     inputs, so won't always match character offsets in Java Strings.
  */
  public static int sqlite3_error_offset(@NotNull sqlite3 db){
    return sqlite3_error_offset(db.getNativePointer());
  }

  public static native String sqlite3_errstr(int resultCode);

  public static native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt);

  static native int sqlite3_extended_errcode(@NotNull long ptrToDb);
  private static native int sqlite3_extended_errcode(@NotNull long ptrToDb);

  public static int sqlite3_extended_errcode(@NotNull sqlite3 db){
    return sqlite3_extended_errcode(db.getNativePointer());
  }

  public static native boolean sqlite3_extended_result_codes(
    @NotNull sqlite3 db, boolean onoff
  public static native int sqlite3_extended_result_codes(
    @NotNull sqlite3 db, boolean on
  );

  static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb);
  private static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb);

  public static boolean sqlite3_get_autocommit(@NotNull sqlite3 db){
    return sqlite3_get_autocommit(db.getNativePointer());
  }

  public static native Object sqlite3_get_auxdata(
    @NotNull sqlite3_context cx, int n
  );

  static native int sqlite3_finalize(long ptrToStmt);
  private static native int sqlite3_finalize(long ptrToStmt);

  public static int sqlite3_finalize(@NotNull sqlite3_stmt stmt){
    return null==stmt ? 0 : sqlite3_finalize(stmt.clearNativePointer());
  }

  public static native int sqlite3_initialize();

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
1514
1515
1516
1517
1518
1519
1520

1521
1522
1523
1524

1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536

1537
1538
1539
1540
1541
1542
1543

1544
1545

1546
1547
1548
1549
1550

1551
1552
1553
1554


1555
1556
1557
1558
1559

1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570







-
+
+
+

-
+
+
+









-
+






-
+

-
+




-
+



-
-
+
+


+
-
+
+
+
+








  /**
     A convenience wrapper around sqlite3_prepare_v3() which accepts
     an arbitrary amount of input provided as a UTF-8-encoded byte
     array.  It loops over the input bytes looking for
     statements. Each one it finds is passed to p.call(), passing
     ownership of it to that function. If p.call() returns 0, looping
     continues, else the loop stops.
     continues, else the loop stops and p.call()'s result code is
     returned. If preparation of any given segment fails, looping
     stops and that result code is returned.

     <p>If p.call() throws, the exception is propagated.
     <p>If p.call() throws, the exception is converted to a db-level
     error and a non-0 code is returned, in order to retain the
     C-style error semantics of the API.

     <p>How each statement is handled, including whether it is finalized
     or not, is up to the callback object. e.g. the callback might
     collect them for later use. If it does not collect them then it
     must finalize them. See PrepareMultiCallback.Finalize for a
     simple proxy which does that.
  */
  public static int sqlite3_prepare_multi(
    @NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
    int preFlags,
    int prepFlags,
    @NotNull PrepareMultiCallback p){
    final OutputPointer.Int32 oTail = new OutputPointer.Int32();
    int pos = 0, n = 1;
    byte[] sqlChunk = sqlUtf8;
    int rc = 0;
    final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
    while(0==rc && pos<sqlChunk.length){
    while( 0==rc && pos<sqlChunk.length ){
      sqlite3_stmt stmt = null;
      if(pos > 0){
      if( pos>0 ){
        sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
                                      sqlChunk.length);
      }
      if( 0==sqlChunk.length ) break;
      rc = sqlite3_prepare_v3(db, sqlChunk, preFlags, outStmt, oTail);
      rc = sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail);
      if( 0!=rc ) break;
      pos = oTail.value;
      stmt = outStmt.take();
      if( null == stmt ){
        // empty statement was parsed.
      if( null==stmt ){
        // empty statement (whitespace/comments)
        continue;
      }
      try{
      rc = p.call(stmt);
        rc = p.call(stmt);
      }catch(Exception e){
        rc = sqlite3_jni_db_error( db, SQLITE_ERROR, e );
      }
    }
    return rc;
  }

  /**
     Convenience overload which accepts its SQL as a String and uses
     no statement-preparation flags.
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
1612
1613
1614
1615
1616
1617
1618

1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629

1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640

1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651

1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666

1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698

1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715







-
+










-
+










-
+










-
+














-
+






+
+
+
+
+
+
+
+
+
















-
+






+
+
+







  */
  public static int sqlite3_prepare_multi(
    @NotNull sqlite3 db, @NotNull String[] sql,
    @NotNull PrepareMultiCallback p){
    return sqlite3_prepare_multi(db, sql, 0, p);
  }

  static native int sqlite3_preupdate_blobwrite(@NotNull long ptrToDb);
  private static native int sqlite3_preupdate_blobwrite(@NotNull long ptrToDb);

  /**
     If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
     acts as a proxy for C's sqlite3_preupdate_blobwrite(), else it returns
     SQLITE_MISUSE with no side effects.
  */
  public static int sqlite3_preupdate_blobwrite(@NotNull sqlite3 db){
    return sqlite3_preupdate_blobwrite(db.getNativePointer());
  }

  static native int sqlite3_preupdate_count(@NotNull long ptrToDb);
  private static native int sqlite3_preupdate_count(@NotNull long ptrToDb);

  /**
     If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
     acts as a proxy for C's sqlite3_preupdate_count(), else it returns
     SQLITE_MISUSE with no side effects.
  */
  public static int sqlite3_preupdate_count(@NotNull sqlite3 db){
    return sqlite3_preupdate_count(db.getNativePointer());
  }

  static native int sqlite3_preupdate_depth(@NotNull long ptrToDb);
  private static native int sqlite3_preupdate_depth(@NotNull long ptrToDb);

  /**
     If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
     acts as a proxy for C's sqlite3_preupdate_depth(), else it returns
     SQLITE_MISUSE with no side effects.
  */
  public static int sqlite3_preupdate_depth(@NotNull sqlite3 db){
    return sqlite3_preupdate_depth(db.getNativePointer());
  }

  static native PreupdateHookCallback sqlite3_preupdate_hook(
  private static native PreupdateHookCallback sqlite3_preupdate_hook(
    @NotNull long ptrToDb, @Nullable PreupdateHookCallback hook
  );

  /**
     If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
     acts as a proxy for C's sqlite3_preupdate_hook(), else it returns null
     with no side effects.
  */
  public static PreupdateHookCallback sqlite3_preupdate_hook(
    @NotNull sqlite3 db, @Nullable PreupdateHookCallback hook
  ){
    return sqlite3_preupdate_hook(db.getNativePointer(), hook);
  }

  static native int sqlite3_preupdate_new(@NotNull long ptrToDb, int col,
  private static native int sqlite3_preupdate_new(@NotNull long ptrToDb, int col,
                                                 @NotNull OutputPointer.sqlite3_value out);

  /**
     If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
     this acts as a proxy for C's sqlite3_preupdate_new(), else it
     returns SQLITE_MISUSE with no side effects.

     WARNING: client code _must not_ hold a reference to the returned
     sqlite3_value object beyond the scope of the preupdate hook in
     which this function is called. Doing so will leave the client
     holding a stale pointer, the address of which could point to
     anything at all after the pre-update hook is complete. This API
     has no way to record such objects and clear/invalidate them at
     the end of a pre-update hook. We "could" add infrastructure to do
     so, but would require significant levels of bookkeeping.
  */
  public static int sqlite3_preupdate_new(@NotNull sqlite3 db, int col,
                                          @NotNull OutputPointer.sqlite3_value out){
    return sqlite3_preupdate_new(db.getNativePointer(), col, out);
  }

  /**
     Convenience wrapper for the 3-arg sqlite3_preupdate_new() which returns
     null on error.
  */
  public static sqlite3_value sqlite3_preupdate_new(@NotNull sqlite3 db, int col){
    final OutputPointer.sqlite3_value out = new OutputPointer.sqlite3_value();
    sqlite3_preupdate_new(db.getNativePointer(), col, out);
    return out.take();
  }

  static native int sqlite3_preupdate_old(@NotNull long ptrToDb, int col,
  private static native int sqlite3_preupdate_old(@NotNull long ptrToDb, int col,
                                                 @NotNull OutputPointer.sqlite3_value out);

  /**
     If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
     this acts as a proxy for C's sqlite3_preupdate_old(), else it
     returns SQLITE_MISUSE with no side effects.

     WARNING: see warning in sqlite3_preupdate_new() regarding the
     potential for stale sqlite3_value handles.
  */
  public static int sqlite3_preupdate_old(@NotNull sqlite3 db, int col,
                                          @NotNull OutputPointer.sqlite3_value out){
    return sqlite3_preupdate_old(db.getNativePointer(), col, out);
  }

  /**
1374
1375
1376
1377
1378
1379
1380
1381

1382
1383
1384
1385
1386
1387
1388
1746
1747
1748
1749
1750
1751
1752

1753
1754
1755
1756
1757
1758
1759
1760







-
+







  /**
     The main sqlite3_result_error() impl of which all others are
     proxies. eTextRep must be one of SQLITE_UTF8 or SQLITE_UTF16 and
     msg must be encoded correspondingly. Any other eTextRep value
     results in the C-level sqlite3_result_error() being called with a
     complaint about the invalid argument.
  */
  static native void sqlite3_result_error(
  private static native void sqlite3_result_error(
    @NotNull sqlite3_context cx, @NotNull byte[] msg, int eTextRep
  );

  public static void sqlite3_result_error(
    @NotNull sqlite3_context cx, @NotNull byte[] utf8
  ){
    sqlite3_result_error(cx, utf8, SQLITE_UTF8);
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
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







-
-
-
-


















-
-
-






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







    @NotNull sqlite3_context cx
  );

  public static native void sqlite3_result_error_code(
    @NotNull sqlite3_context cx, int c
  );

  public static native void sqlite3_result_null(
    @NotNull sqlite3_context cx
  );

  public static native void sqlite3_result_int(
    @NotNull sqlite3_context cx, int v
  );

  public static native void sqlite3_result_int64(
    @NotNull sqlite3_context cx, long v
  );

  /**
     Binds the SQL result to the given object, or {@link
     #sqlite3_result_null} if {@code o} is null. Use {@link
     #sqlite3_value_java_object} to fetch it.

     <p>This is implemented in terms of C's sqlite3_result_pointer(),
     but that function is not exposed to JNI because (A)
     cross-language semantic mismatch and (B) Java doesn't need that
     argument for its intended purpose (type safety).

     <p>Note that there is no sqlite3_column_java_object(), as the
     C-level API has no sqlite3_column_pointer() to proxy.

     @see #sqlite3_value_java_object
     @see #sqlite3_bind_java_object
  */
  public static native void sqlite3_result_java_object(
    @NotNull sqlite3_context cx, @NotNull Object o
  );

  /**
     Similar to sqlite3_bind_nio_buffer(), this works like
     sqlite3_result_blob() but accepts a java.nio.ByteBuffer as its
     input source. See sqlite3_bind_nio_buffer() for the semantics of
     the second and subsequent arguments.

     If cx is null then this function will silently fail. If
     sqlite3_jni_supports_nio() returns false or iBegin is negative,
     an error result is set. If (begin+n) extends beyond the end of
     the buffer, it is silently truncated to fit.

     If any of the following apply, this function behaves like
     sqlite3_result_null(): the blob is null, the resulting slice of
     the blob is empty.

     If the resulting slice of the buffer exceeds SQLITE_LIMIT_LENGTH
     then this function behaves like sqlite3_result_error_toobig().
  */
  @Experimental
  /*public*/ static native void sqlite3_result_nio_buffer(
    @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
    int begin, int n
  );

  /**
     Convenience overload which uses the whole input object
     as the result blob content.
  */
  @Experimental
  /*public*/ static void sqlite3_result_nio_buffer(
    @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
  ){
    sqlite3_result_nio_buffer(cx, blob, 0, -1);
  }

  public static native void sqlite3_result_null(
    @NotNull sqlite3_context cx
  );

  public static void sqlite3_result_set(
    @NotNull sqlite3_context cx, @NotNull Boolean v
  ){
    sqlite3_result_int(cx, v ? 1 : 0);
  }

1519
1520
1521
1522
1523
1524
1525




1526
1527
1528
1529
1530
1531
1532
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940







+
+
+
+








  public static void sqlite3_result_set(
    @NotNull sqlite3_context cx, @Nullable byte[] blob
  ){
    if( null==blob ) sqlite3_result_null(cx);
    else sqlite3_result_blob(cx, blob, blob.length);
  }

  public static native void sqlite3_result_subtype(
    @NotNull sqlite3_context cx, int val
  );

  public static native void sqlite3_result_value(
    @NotNull sqlite3_context cx, @NotNull sqlite3_value v
  );

  public static native void sqlite3_result_zeroblob(
    @NotNull sqlite3_context cx, int n
1545
1546
1547
1548
1549
1550
1551























1552
1553
1554
1555
1556
1557
1558
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







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







  );

  public static void sqlite3_result_blob(
    @NotNull sqlite3_context cx, @Nullable byte[] blob
  ){
    sqlite3_result_blob(cx, blob, (int)(null==blob ? 0 : blob.length));
  }

  /**
     Convenience overload which behaves like
     sqlite3_result_nio_buffer().
  */
  @Experimental
  /*public*/ static void sqlite3_result_blob(
    @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
    int begin, int n
  ){
    sqlite3_result_nio_buffer(cx, blob, begin, n);
  }

  /**
     Convenience overload which behaves like the two-argument overload of
     sqlite3_result_nio_buffer().
  */
  @Experimental
  /*public*/ static void sqlite3_result_blob(
    @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
  ){
    sqlite3_result_nio_buffer(cx, blob);
  }

  /**
     Binds the given text using C's sqlite3_result_blob64() unless:

     <ul>

     <li>@param blob is null: translates to sqlite3_result_null()</li>
1603
1604
1605
1606
1607
1608
1609
1610


1611
1612
1613
1614
1615
1616
1617
2034
2035
2036
2037
2038
2039
2040

2041
2042
2043
2044
2045
2046
2047
2048
2049







-
+
+







  }

  /**
     Binds the given text using C's sqlite3_result_text64() unless:

     <ul>

     <li>text is null: translates to a call to sqlite3_result_null()</li>
     <li>text is null: translates to a call to {@link
     #sqlite3_result_null}</li>

     <li>text is too large: translates to a call to
     {@link #sqlite3_result_error_toobig}</li>

     <li>The @param encoding argument has an invalid value: translates to
     {@link sqlite3_result_error_code} with code SQLITE_FORMAT.</li>

1647
1648
1649
1650
1651
1652
1653
1654

1655
1656
1657
1658
1659
1660
1661
2079
2080
2081
2082
2083
2084
2085

2086
2087
2088
2089
2090
2091
2092
2093







-
+







    if(null == text) sqlite3_result_null(cx);
    else{
      final byte[] b = text.getBytes(StandardCharsets.UTF_16);
      sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16);
    }
  }

  static native RollbackHookCallback sqlite3_rollback_hook(
  private static native RollbackHookCallback sqlite3_rollback_hook(
    @NotNull long ptrToDb, @Nullable RollbackHookCallback hook
  );

  public static RollbackHookCallback sqlite3_rollback_hook(
    @NotNull sqlite3 db, @Nullable RollbackHookCallback hook
  ){
    return sqlite3_rollback_hook(db.getNativePointer(), hook);
1699
1700
1701
1702
1703
1704
1705


1706



1707
1708
1709
1710

1711
1712
1713

1714
1715
1716

1717
1718
1719

1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740

1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754

1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766

1767
1768
1769
1770
1771
1772
1773
2131
2132
2133
2134
2135
2136
2137
2138
2139

2140
2141
2142
2143
2144
2145

2146
2147
2148

2149
2150
2151

2152
2153
2154

2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175

2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189

2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201

2202
2203
2204
2205
2206
2207
2208
2209







+
+
-
+
+
+



-
+


-
+


-
+


-
+




















-
+













-
+











-
+







  );

  public static native int sqlite3_status64(
    int op, @NotNull OutputPointer.Int64 pCurrent,
    @NotNull OutputPointer.Int64 pHighwater, boolean reset
  );

  private static native int sqlite3_step(@NotNull long ptrToStmt);

  public static native int sqlite3_step(@NotNull sqlite3_stmt stmt);
  public static int sqlite3_step(@NotNull sqlite3_stmt stmt){
    return null==stmt ? SQLITE_MISUSE : sqlite3_step(stmt.getNativePointer());
  }

  public static native boolean sqlite3_stmt_busy(@NotNull sqlite3_stmt stmt);

  static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op);
  private static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op);

  public static int sqlite3_stmt_explain(@NotNull sqlite3_stmt stmt, int op){
    return sqlite3_stmt_explain(stmt.getNativePointer(), op);
    return null==stmt ? SQLITE_MISUSE : sqlite3_stmt_explain(stmt.getNativePointer(), op);
  }

  static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt);
  private static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt);

  public static int sqlite3_stmt_isexplain(@NotNull sqlite3_stmt stmt){
    return sqlite3_stmt_isexplain(stmt.getNativePointer());
    return null==stmt ? 0 : sqlite3_stmt_isexplain(stmt.getNativePointer());
  }

  public static native boolean sqlite3_stmt_readonly(@NotNull sqlite3_stmt stmt);

  public static native int sqlite3_stmt_status(
    @NotNull sqlite3_stmt stmt, int op, boolean reset
  );

  /**
     Internal impl of the public sqlite3_strglob() method. Neither
     argument may be null and both must be NUL-terminated UTF-8.

     This overload is private because: (A) to keep users from
     inadvertently passing non-NUL-terminated byte arrays (an easy
     thing to do). (B) it is cheaper to NUL-terminate the
     String-to-byte-array conversion in the Java implementation
     (sqlite3_strglob(String,String)) than to do that in C, so that
     signature is the public-facing one.
  */
  private static native int sqlite3_strglob(
    @NotNull byte[] glob, @NotNull byte[] nullTerminatedUtf8
    @NotNull byte[] glob, @NotNull byte[] nulTerminatedUtf8
  );

  public static int sqlite3_strglob(
    @NotNull String glob, @NotNull String txt
  ){
    return sqlite3_strglob(nulTerminateUtf8(glob),
                           nulTerminateUtf8(txt));
  }

  /**
     The LIKE counterpart of the private sqlite3_strglob() method.
  */
  private static native int sqlite3_strlike(
    @NotNull byte[] glob, @NotNull byte[] nullTerminatedUtf8,
    @NotNull byte[] glob, @NotNull byte[] nulTerminatedUtf8,
    int escChar
  );

  public static int sqlite3_strlike(
    @NotNull String glob, @NotNull String txt, char escChar
  ){
    return sqlite3_strlike(nulTerminateUtf8(glob),
                           nulTerminateUtf8(txt),
                           (int)escChar);
  }

  static native int sqlite3_system_errno(@NotNull long ptrToDb);
  private static native int sqlite3_system_errno(@NotNull long ptrToDb);

  public static int sqlite3_system_errno(@NotNull sqlite3 db){
    return sqlite3_system_errno(db.getNativePointer());
  }

  public static native int sqlite3_table_column_metadata(
    @NotNull sqlite3 db, @NotNull String zDbName,
1805
1806
1807
1808
1809
1810
1811
1812

1813
1814
1815
1816
1817
1818

1819
1820
1821
1822
1823
1824
1825
2241
2242
2243
2244
2245
2246
2247

2248
2249
2250
2251
2252
2253

2254
2255
2256
2257
2258
2259
2260
2261







-
+





-
+







    return 0==sqlite3_table_column_metadata(
      db, zDbName, zTableName, zColumnName, out
    ) ? out : null;
  }

  public static native int sqlite3_threadsafe();

  static native int sqlite3_total_changes(@NotNull long ptrToDb);
  private static native int sqlite3_total_changes(@NotNull long ptrToDb);

  public static int sqlite3_total_changes(@NotNull sqlite3 db){
    return sqlite3_total_changes(db.getNativePointer());
  }

  static native long sqlite3_total_changes64(@NotNull long ptrToDb);
  private static native long sqlite3_total_changes64(@NotNull long ptrToDb);

  public static long sqlite3_total_changes64(@NotNull sqlite3 db){
    return sqlite3_total_changes64(db.getNativePointer());
  }

  /**
     Works like C's sqlite3_trace_v2() except that the 3rd argument to that
1834
1835
1836
1837
1838
1839
1840
1841

1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861

1862
1863
1864
1865
1866
1867

1868
1869
1870
1871
1872
1873

1874
1875
1876
1877
1878
1879

1880
1881
1882
1883
1884
1885

1886
1887
1888
1889
1890
1891

1892
1893
1894
1895
1896
1897

1898
1899
1900

1901
1902
1903

1904
1905
1906
1907
1908
1909

1910
1911
1912
1913
1914
1915

1916
1917
1918
1919
1920
1921

1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941

1942
1943
1944
1945
1946











1947

1948
1949
1950
1951
1952
1953

1954
1955
1956
1957
1958
1959

1960
1961
1962
1963
1964
1965

1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977

1978
1979
1980
1981
1982
1983

1984
1985
1986
1987
1988
1989
1990
2270
2271
2272
2273
2274
2275
2276

2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296

2297
2298
2299
2300
2301
2302

2303
2304
2305
2306
2307
2308

2309
2310
2311
2312
2313
2314

2315
2316
2317
2318
2319
2320

2321
2322
2323
2324
2325
2326

2327
2328
2329
2330
2331
2332

2333
2334
2335

2336
2337
2338

2339
2340
2341
2342
2343
2344

2345
2346
2347
2348
2349
2350

2351
2352
2353
2354
2355
2356

2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376

2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393

2394
2395
2396
2397
2398
2399

2400
2401
2402
2403
2404
2405

2406
2407
2408
2409
2410
2411

2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423

2424
2425
2426
2427
2428
2429

2430
2431
2432
2433
2434
2435
2436
2437







-
+



















-
+





-
+





-
+





-
+





-
+





-
+





-
+


-
+


-
+





-
+





-
+





-
+



















-
+





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





-
+





-
+





-
+











-
+





-
+







    @NotNull sqlite3 db, int traceMask, @Nullable TraceV2Callback tracer
  );

  public static native int sqlite3_txn_state(
    @NotNull sqlite3 db, @Nullable String zSchema
  );

  static native UpdateHookCallback sqlite3_update_hook(
  private static native UpdateHookCallback sqlite3_update_hook(
    @NotNull long ptrToDb, @Nullable UpdateHookCallback hook
  );

  public static UpdateHookCallback sqlite3_update_hook(
    @NotNull sqlite3 db, @Nullable UpdateHookCallback hook
  ){
    return sqlite3_update_hook(db.getNativePointer(), hook);
  }

  /*
     Note that:

     void * sqlite3_user_data(sqlite3_context*)

     Is not relevant in the JNI binding, as its feature is replaced by
     the ability to pass an object, including any relevant state, to
     sqlite3_create_function().
  */

  static native byte[] sqlite3_value_blob(@NotNull long ptrToValue);
  private static native byte[] sqlite3_value_blob(@NotNull long ptrToValue);

  public static byte[] sqlite3_value_blob(@NotNull sqlite3_value v){
    return sqlite3_value_blob(v.getNativePointer());
  }

  static native int sqlite3_value_bytes(@NotNull long ptrToValue);
  private static native int sqlite3_value_bytes(@NotNull long ptrToValue);

  public static int sqlite3_value_bytes(@NotNull sqlite3_value v){
    return sqlite3_value_bytes(v.getNativePointer());
  }

  static native int sqlite3_value_bytes16(@NotNull long ptrToValue);
  private static native int sqlite3_value_bytes16(@NotNull long ptrToValue);

  public static int sqlite3_value_bytes16(@NotNull sqlite3_value v){
    return sqlite3_value_bytes16(v.getNativePointer());
  }

  static native double sqlite3_value_double(@NotNull long ptrToValue);
  private static native double sqlite3_value_double(@NotNull long ptrToValue);

  public static double sqlite3_value_double(@NotNull sqlite3_value v){
    return sqlite3_value_double(v.getNativePointer());
  }

  static native sqlite3_value sqlite3_value_dup(@NotNull long ptrToValue);
  private static native sqlite3_value sqlite3_value_dup(@NotNull long ptrToValue);

  public static sqlite3_value sqlite3_value_dup(@NotNull sqlite3_value v){
    return sqlite3_value_dup(v.getNativePointer());
  }

  static native int sqlite3_value_encoding(@NotNull long ptrToValue);
  private static native int sqlite3_value_encoding(@NotNull long ptrToValue);

  public static int sqlite3_value_encoding(@NotNull sqlite3_value v){
    return sqlite3_value_encoding(v.getNativePointer());
  }

  static native void sqlite3_value_free(@Nullable long ptrToValue);
  private static native void sqlite3_value_free(@Nullable long ptrToValue);

  public static void sqlite3_value_free(@Nullable sqlite3_value v){
    sqlite3_value_free(v.getNativePointer());
    if( null!=v ) sqlite3_value_free(v.clearNativePointer());
  }

  static native boolean sqlite3_value_frombind(@NotNull long ptrToValue);
  private static native boolean sqlite3_value_frombind(@NotNull long ptrToValue);

  public static boolean sqlite3_value_frombind(@NotNull sqlite3_value v){
    return sqlite3_value_frombind(v.getNativePointer());
  }

  static native int sqlite3_value_int(@NotNull long ptrToValue);
  private static native int sqlite3_value_int(@NotNull long ptrToValue);

  public static int sqlite3_value_int(@NotNull sqlite3_value v){
    return sqlite3_value_int(v.getNativePointer());
  }

  static native long sqlite3_value_int64(@NotNull long ptrToValue);
  private static native long sqlite3_value_int64(@NotNull long ptrToValue);

  public static long sqlite3_value_int64(@NotNull sqlite3_value v){
    return sqlite3_value_int64(v.getNativePointer());
  }

  static native Object sqlite3_value_java_object(@NotNull long ptrToValue);
  private static native Object sqlite3_value_java_object(@NotNull long ptrToValue);

  /**
     If the given value was set using {@link
     #sqlite3_result_java_object} then this function returns that
     object, else it returns null.

     <p>It is up to the caller to inspect the object to determine its
     type, and cast it if necessary.
  */
  public static Object sqlite3_value_java_object(@NotNull sqlite3_value v){
    return sqlite3_value_java_object(v.getNativePointer());
  }

  /**
     A variant of sqlite3_value_java_object() which returns the
     fetched object cast to T if the object is an instance of the
     given Class, else it returns null.
  */
  @SuppressWarnings("unchecked")
  public static <T> T sqlite3_value_java_casted(@NotNull sqlite3_value v,
  public static <T> T sqlite3_value_java_object(@NotNull sqlite3_value v,
                                                @NotNull Class<T> type){
    final Object o = sqlite3_value_java_object(v);
    return type.isInstance(o) ? (T)o : null;
  }

  /**
     A variant of sqlite3_column_blob() which returns the blob as a
     ByteBuffer object. Returns null if its argument is null, if
     sqlite3_jni_supports_nio() is false, or if sqlite3_value_blob()
     would return null for the same input.
  */
  @Experimental
  /*public*/ static native java.nio.ByteBuffer sqlite3_value_nio_buffer(
    @NotNull sqlite3_value v
  );

  static native int sqlite3_value_nochange(@NotNull long ptrToValue);
  private static native int sqlite3_value_nochange(@NotNull long ptrToValue);

  public static int sqlite3_value_nochange(@NotNull sqlite3_value v){
    return sqlite3_value_nochange(v.getNativePointer());
  }

  static native int sqlite3_value_numeric_type(@NotNull long ptrToValue);
  private static native int sqlite3_value_numeric_type(@NotNull long ptrToValue);

  public static int sqlite3_value_numeric_type(@NotNull sqlite3_value v){
    return sqlite3_value_numeric_type(v.getNativePointer());
  }

  static native int sqlite3_value_subtype(@NotNull long ptrToValue);
  private static native int sqlite3_value_subtype(@NotNull long ptrToValue);

  public static int sqlite3_value_subtype(@NotNull sqlite3_value v){
    return sqlite3_value_subtype(v.getNativePointer());
  }

  static native byte[] sqlite3_value_text(@NotNull long ptrToValue);
  private static native byte[] sqlite3_value_text(@NotNull long ptrToValue);

  /**
     Functions identially to the C API, and this note is just to
     stress that the returned bytes are encoded as UTF-8. It returns
     null if the underlying C-level sqlite3_value_text() returns NULL
     or on allocation error.
  */
  public static byte[] sqlite3_value_text(@NotNull sqlite3_value v){
    return sqlite3_value_text(v.getNativePointer());
  }

  static native String sqlite3_value_text16(@NotNull long ptrToValue);
  private static native String sqlite3_value_text16(@NotNull long ptrToValue);

  public static String sqlite3_value_text16(@NotNull sqlite3_value v){
    return sqlite3_value_text16(v.getNativePointer());
  }

  static native int sqlite3_value_type(@NotNull long ptrToValue);
  private static native int sqlite3_value_type(@NotNull long ptrToValue);

  public static int sqlite3_value_type(@NotNull sqlite3_value v){
    return sqlite3_value_type(v.getNativePointer());
  }

  /**
     This is NOT part of the public API. It exists solely as a place
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2698
2699
2700
2701
2702
2703
2704

2705
2706
2707
2708
2709
2710
2711







-







  public static final int SQLITE_OPEN_PRIVATECACHE  = 0x00040000  /* Ok for sqlite3_open_v2() */;
  //public static final int SQLITE_OPEN_WAL         = 0x00080000  /* VFS only */;
  public static final int SQLITE_OPEN_NOFOLLOW      = 0x01000000  /* Ok for sqlite3_open_v2() */;
  public static final int SQLITE_OPEN_EXRESCODE     = 0x02000000  /* Extended result codes */;

  // prepare flags
  public static final int SQLITE_PREPARE_PERSISTENT = 1;
  public static final int SQLITE_PREPARE_NORMALIZE = 2;
  public static final int SQLITE_PREPARE_NO_VTAB = 4;

  // result codes
  public static final int SQLITE_OK = 0;
  public static final int SQLITE_ERROR = 1;
  public static final int SQLITE_INTERNAL = 2;
  public static final int SQLITE_PERM = 3;
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416





2417
2418
2419
2420
2421
2422
2423
2853
2854
2855
2856
2857
2858
2859



2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871







-
-
-
+
+
+
+
+








  // transaction state
  public static final int SQLITE_TXN_NONE = 0;
  public static final int SQLITE_TXN_READ = 1;
  public static final int SQLITE_TXN_WRITE = 2;

  // udf flags
  public static final int SQLITE_DETERMINISTIC = 0x000000800;
  public static final int SQLITE_DIRECTONLY    = 0x000080000;
  public static final int SQLITE_INNOCUOUS     = 0x000200000;
  public static final int SQLITE_DETERMINISTIC =  0x000000800;
  public static final int SQLITE_DIRECTONLY    =  0x000080000;
  public static final int SQLITE_SUBTYPE =        0x000100000;
  public static final int SQLITE_INNOCUOUS     =  0x000200000;
  public static final int SQLITE_RESULT_SUBTYPE = 0x001000000;

  // virtual tables
  public static final int SQLITE_INDEX_SCAN_UNIQUE = 1;
  public static final int SQLITE_INDEX_CONSTRAINT_EQ = 2;
  public static final int SQLITE_INDEX_CONSTRAINT_GT = 4;
  public static final int SQLITE_INDEX_CONSTRAINT_LE = 8;
  public static final int SQLITE_INDEX_CONSTRAINT_LT = 16;
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448


2449
2886
2887
2888
2889
2890
2891
2892


2893
2894
2895
2896
2897







-
-


+
+

  public static final int SQLITE_VTAB_INNOCUOUS = 2;
  public static final int SQLITE_VTAB_DIRECTONLY = 3;
  public static final int SQLITE_VTAB_USES_ALL_SCHEMAS = 4;
  public static final int SQLITE_ROLLBACK = 1;
  public static final int SQLITE_FAIL = 3;
  public static final int SQLITE_REPLACE = 5;
  static {
    // This MUST come after the SQLITE_MAX_... values or else
    // attempting to modify them silently fails.
    init();
  }
  /* Must come after static init(). */
  private static final boolean JNI_SUPPORTS_NIO = sqlite3_jni_supports_nio();
}
Changes to ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java.
20
21
22
23
24
25
26

27
28


29
30
31
32
33
34
35
20
21
22
23
24
25
26
27


28
29
30
31
32
33
34
35
36







+
-
-
+
+








   <p>Unless very explicitely documented otherwise, callbacks must
   never throw. Any which do throw but should not might trigger debug
   output regarding the error, but the exception will not be
   propagated.  For callback interfaces which support returning error
   info to the core, the JNI binding will convert any exceptions to
   C-level error information. For callback interfaces which do not
   support returning error information, all exceptions will
   support, all exceptions will necessarily be suppressed in order to
   retain the C-style no-throw semantics.
   necessarily be suppressed in order to retain the C-style no-throw
   semantics and avoid invoking undefined behavior in the C layer.

   <p>Callbacks of this style follow a common naming convention:

   <p>1) They use the UpperCamelCase form of the C function they're
   proxying for, minus the {@code sqlite3_} prefix, plus a {@code
   Callback} suffix. e.g. {@code sqlite3_busy_handler()}'s callback is
   named {@code BusyHandlerCallback}. Exceptions are made where that
Changes to ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java.
17
18
19
20
21
22
23

24
25


26
27

28
17
18
19
20
21
22
23
24


25
26
27

28
29







+
-
-
+
+

-
+

   Callback for use with {@link CApi#sqlite3_collation_needed}.
*/
public interface CollationNeededCallback extends CallbackProxy {
  /**
     Has the same semantics as the C-level sqlite3_create_collation()
     callback.

     <p>Because the C API has no mechanism for reporting errors
     <p>If it throws, the exception message is passed on to the db and
     the exception is suppressed.
     from this callbacks, any exceptions thrown by this callback
     are suppressed.
  */
  int call(sqlite3 db, int eTextRep, String collationName);
  void call(sqlite3 db, int eTextRep, String collationName);
}
Changes to ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java.
15
16
17
18
19
20
21
22


23
24
25
15
16
17
18
19
20
21

22
23
24
25
26







-
+
+




/**
   Callback for use with {@link CApi#sqlite3_commit_hook}.
*/
public interface CommitHookCallback extends CallbackProxy {
  /**
     Works as documented for the C-level sqlite3_commit_hook()
     callback.  Must not throw.
     callback. If it throws, the exception is translated into
     a db-level error.
  */
  int call();
}
Added ext/jni/src/org/sqlite/jni/capi/ConfigSqlLogCallback.java.

























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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2023-08-23
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;

/**
   A callback for use with sqlite3_config().
*/
public interface ConfigSqlLogCallback {
  /**
     Must function as described for a C-level callback for
     {@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
  */
  void call(sqlite3 db, String msg, int msgType );
}
Deleted ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java.
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

























-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
** 2023-08-23
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;

/**
   A callback for use with sqlite3_config().
*/
public interface ConfigSqllogCallback {
  /**
     Must function as described for a C-level callback for
     {@link CApi#sqlite3_config(ConfigSqllogCallback)}, with the slight signature change.
  */
  void call(sqlite3 db, String msg, int msgType );
}
Changes to ext/jni/src/org/sqlite/jni/capi/OutputPointer.java.
224
225
226
227
228
229
230






















231
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







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

    /** Initializes with the value v. */
    public ByteArray(byte[] v){value = v;}
    /** Returns the current value. */
    public final byte[] get(){return value;}
    /** Sets the current value. */
    public final void set(byte[] v){value = v;}
  }

  /**
     Output pointer for use with native routines which return
     blobs via java.nio.ByteBuffer.

     See {@link org.sqlite.jni.capi.CApi#sqlite3_jni_supports_nio}
  */
  public static final class ByteBuffer {
    /**
       This is public for ease of use. Accessors are provided for
       consistency with the higher-level types.
    */
    public java.nio.ByteBuffer value;
    /** Initializes with the value null. */
    public ByteBuffer(){this(null);}
    /** Initializes with the value v. */
    public ByteBuffer(java.nio.ByteBuffer v){value = v;}
    /** Returns the current value. */
    public final java.nio.ByteBuffer get(){return value;}
    /** Sets the current value. */
    public final void set(java.nio.ByteBuffer v){value = v;}
  }
}
Changes to ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java.
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
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







-
+
+
+
+











-
+







  /**
     Gets passed a sqlite3_stmt which it may handle in arbitrary ways,
     transfering ownership of it to this function.

     sqlite3_prepare_multi() will _not_ finalize st - it is up
     to the call() implementation how st is handled.

     Must return 0 on success or an SQLITE_... code on error.
     Must return 0 on success or an SQLITE_... code on error. If it
     throws, sqlite3_prepare_multi() will transform the exception into
     a db-level error in order to retain the C-style error semantics
     of the API.

     See the {@link Finalize} class for a wrapper which finalizes the
     statement after calling a proxy PrepareMultiCallback.
  */
  int call(sqlite3_stmt st);

  /**
     A PrepareMultiCallback impl which wraps a separate impl and finalizes
     any sqlite3_stmt passed to its callback.
  */
  public static final class Finalize implements PrepareMultiCallback {
    private PrepareMultiCallback p;
    private final PrepareMultiCallback p;
    /**
       p is the proxy to call() when this.call() is called.
    */
    public Finalize( PrepareMultiCallback p ){
      this.p = p;
    }
    /**
Changes to ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java.
15
16
17
18
19
20
21
22


23
24
25
26
15
16
17
18
19
20
21

22
23
24
25
26
27







-
+
+





/**
   Callback for use with {@link CApi#sqlite3_preupdate_hook}.
*/
public interface PreupdateHookCallback extends CallbackProxy {
  /**
     Must function as described for the C-level sqlite3_preupdate_hook()
     callback.
     callback. If it throws, the exception is translated to a
     db-level error and the exception is suppressed.
  */
  void call(sqlite3 db, int op, String dbName, String dbTable,
            long iKey1, long iKey2 );
}
Changes to ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java.
14
15
16
17
18
19
20
21
22



23
24
25
14
15
16
17
18
19
20


21
22
23
24
25
26







-
-
+
+
+



package org.sqlite.jni.capi;

/**
   Callback for use with {@link CApi#sqlite3_rollback_hook}.
*/
public interface RollbackHookCallback extends CallbackProxy {
  /**
     Works as documented for the C-level sqlite3_rollback_hook()
     callback.
     Must function as documented for the C-level sqlite3_rollback_hook()
     callback. If it throws, the exception is translated into
     a db-level error.
  */
  void call();
}
Changes to ext/jni/src/org/sqlite/jni/capi/SQLFunction.java.
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
29
30
31
32
33
34
35



































































36







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

   UDFs, so long as they conform to the public interfaces defined by
   those three classes. The JNI layer only actively relies on the
   SQLFunction base class and the method names and signatures used by
   the UDF callback interfaces.
*/
public interface SQLFunction {

  /**
     PerContextState assists aggregate and window functions in
     managing their accumulator state across calls to the UDF's
     callbacks.

     <p>T must be of a type which can be legally stored as a value in
     java.util.HashMap<KeyType,T>.

     <p>If a given aggregate or window function is called multiple times
     in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
     then the clients need some way of knowing which call is which so
     that they can map their state between their various UDF callbacks
     and reset it via xFinal(). This class takes care of such
     mappings.

     <p>This class works by mapping
     sqlite3_context.getAggregateContext() to a single piece of
     state, of a client-defined type (the T part of this class), which
     persists across a "matching set" of the UDF's callbacks.

     <p>This class is a helper providing commonly-needed functionality
     - it is not required for use with aggregate or window functions.
     Client UDFs are free to perform such mappings using custom
     approaches. The provided {@link AggregateFunction} and {@link
     WindowFunction} classes use this.
  */
  public static final class PerContextState<T> {
    private final java.util.Map<Long,ValueHolder<T>> map
      = new java.util.HashMap<>();

    /**
       Should be called from a UDF's xStep(), xValue(), and xInverse()
       methods, passing it that method's first argument and an initial
       value for the persistent state. If there is currently no
       mapping for the given context within the map, one is created
       using the given initial value, else the existing one is used
       and the 2nd argument is ignored.  It returns a ValueHolder<T>
       which can be used to modify that state directly without
       requiring that the client update the underlying map's entry.

       <p>The caller is obligated to eventually call
       takeAggregateState() to clear the mapping.
    */
    public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
      final Long key = cx.getAggregateContext(true);
      ValueHolder<T> rc = null==key ? null : map.get(key);
      if( null==rc ){
        map.put(key, rc = new ValueHolder<>(initialValue));
      }
      return rc;
    }

    /**
       Should be called from a UDF's xFinal() method and passed that
       method's first argument. This function removes the value
       associated with cx.getAggregateContext() from the map and
       returns it, returning null if no other UDF method has been
       called to set up such a mapping. The latter condition will be
       the case if a UDF is used in a statement which has no result
       rows.
    */
    public T takeAggregateState(sqlite3_context cx){
      final ValueHolder<T> h = map.remove(cx.getAggregateContext(false));
      return null==h ? null : h.value;
    }
  }

}
Changes to ext/jni/src/org/sqlite/jni/capi/Tester1.java.
34
35
36
37
38
39
40








41
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
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







+
+
+
+
+
+
+
+








-
+







   Annotation for Tester1 tests which mark those which must be skipped
   in multi-threaded mode.
*/
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
@interface SingleThreadOnly{}

/**
   Annotation for Tester1 tests which must only be run if
   sqlite3_jni_supports_nio() is true.
*/
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
@interface RequiresJniNio{}

public class Tester1 implements Runnable {
  //! True when running in multi-threaded mode.
  private static boolean mtMode = false;
  //! True to sleep briefly between tests.
  private static boolean takeNaps = false;
  //! True to shuffle the order of the tests.
  private static boolean shuffle = false;
  //! True to dump the list of to-run tests to stdout.
  private static boolean listRunTests = false;
  private static int listRunTests = 0;
  //! True to squelch all out() and outln() output.
  private static boolean quietMode = false;
  //! Total number of runTests() calls.
  private static int nTestRuns = 0;
  //! List of test*() methods to run.
  private static List<java.lang.reflect.Method> testMethods = null;
  //! List of exceptions collected by run()
323
324
325
326
327
328
329
330

331
332
333
334
335
336
337
331
332
333
334
335
336
337

338
339
340
341
342
343
344
345







-
+







        sqlite3_finalize(stmt);
        affirm(0 == stmt.getNativePointer());
      }
    }


    rc = sqlite3_prepare_v3(db, "INSERT INTO t2(a) VALUES(1),(2),(3)",
                            SQLITE_PREPARE_NORMALIZE, outStmt);
                            0, outStmt);
    affirm(0 == rc);
    stmt = outStmt.get();
    affirm(0 != stmt.getNativePointer());
    sqlite3_finalize(stmt);
    affirm(0 == stmt.getNativePointer() );

    affirm( 0==sqlite3_errcode(db) );
378
379
380
381
382
383
384









385
386
387
388
389
390
391
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408







+
+
+
+
+
+
+
+
+







    affirm(sqlite3_changes(db) > changes);
    affirm(sqlite3_total_changes(db) > changesT);
    affirm(sqlite3_changes64(db) > changes64);
    affirm(sqlite3_total_changes64(db) > changesT64);
    stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
    affirm( sqlite3_stmt_readonly(stmt) );
    affirm( !sqlite3_stmt_busy(stmt) );
    if( sqlite3_compileoption_used("ENABLE_COLUMN_METADATA") ){
      /* Unlike in native C code, JNI won't trigger an
         UnsatisfiedLinkError until these are called (on Linux, at
         least). */
      affirm("t".equals(sqlite3_column_table_name(stmt,0)));
      affirm("main".equals(sqlite3_column_database_name(stmt,0)));
      affirm("a".equals(sqlite3_column_origin_name(stmt,0)));
    }

    int total2 = 0;
    while( SQLITE_ROW == sqlite3_step(stmt) ){
      affirm( sqlite3_stmt_busy(stmt) );
      total2 += sqlite3_column_int(stmt, 0);
      sqlite3_value sv = sqlite3_column_value(stmt, 0);
      affirm( null != sv );
      affirm( 0 != sv.getNativePointer() );
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
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







+














+
+
+
+
+
+
+
+
+







      affirm(SQLITE_DONE==rc);
      sqlite3_reset(stmt);
    }
    sqlite3_finalize(stmt);
    stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
    StringBuilder sbuf = new StringBuilder();
    n = 0;
    final boolean tryNio = sqlite3_jni_supports_nio();
    while( SQLITE_ROW == sqlite3_step(stmt) ){
      final sqlite3_value sv = sqlite3_value_dup(sqlite3_column_value(stmt,0));
      final String txt = sqlite3_column_text16(stmt, 0);
      sbuf.append( txt );
      affirm( txt.equals(new String(
                           sqlite3_column_text(stmt, 0),
                           StandardCharsets.UTF_8
                         )) );
      affirm( txt.length() < sqlite3_value_bytes(sv) );
      affirm( txt.equals(new String(
                           sqlite3_value_text(sv),
                           StandardCharsets.UTF_8)) );
      affirm( txt.length() == sqlite3_value_bytes16(sv)/2 );
      affirm( txt.equals(sqlite3_value_text16(sv)) );
      if( tryNio ){
        java.nio.ByteBuffer bu = sqlite3_value_nio_buffer(sv);
        byte ba[] = sqlite3_value_blob(sv);
        affirm( ba.length == bu.capacity() );
        int i = 0;
        for( byte b : ba ){
          affirm( b == bu.get(i++) );
        }
      }
      sqlite3_value_free(sv);
      ++n;
    }
    sqlite3_finalize(stmt);
    affirm(3 == n);
    affirm("w😃rldhell🤩!🤩".equals(sbuf.toString()));

543
544
545
546
547
548
549









































































550
551
552
553
554
555
556
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
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







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







      ++n;
    }
    sqlite3_finalize(stmt);
    affirm(1 == n);
    affirm(total == 0x32 + 0x33 + 0x34);
    sqlite3_close_v2(db);
  }

  @RequiresJniNio
  private void testBindByteBuffer(){
    /* TODO: these tests need to be much more extensive to check the
       begin/end range handling. */

    java.nio.ByteBuffer zeroCheck =
      java.nio.ByteBuffer.allocateDirect(0);
    affirm( null != zeroCheck );
    zeroCheck = null;
    sqlite3 db = createNewDb();
    execSql(db, "CREATE TABLE t(a)");

    final java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocateDirect(10);
    buf.put((byte)0x31)/*note that we'll skip this one*/
      .put((byte)0x32)
      .put((byte)0x33)
      .put((byte)0x34)
      .put((byte)0x35)/*we'll skip this one too*/;

    final int expectTotal = buf.get(1) + buf.get(2) + buf.get(3);
    sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
    affirm( SQLITE_ERROR == sqlite3_bind_blob(stmt, 1, buf, -1, 0),
            "Buffer offset may not be negative." );
    affirm( 0 == sqlite3_bind_blob(stmt, 1, buf, 1, 3) );
    affirm( SQLITE_DONE == sqlite3_step(stmt) );
    sqlite3_finalize(stmt);
    stmt = prepare(db, "SELECT a FROM t;");
    int total = 0;
    affirm( SQLITE_ROW == sqlite3_step(stmt) );
    byte blob[] = sqlite3_column_blob(stmt, 0);
    java.nio.ByteBuffer nioBlob =
      sqlite3_column_nio_buffer(stmt, 0);
    affirm(3 == blob.length);
    affirm(blob.length == nioBlob.capacity());
    affirm(blob.length == nioBlob.limit());
    int i = 0;
    for(byte b : blob){
      affirm( i<=3 );
      affirm(b == buf.get(1 + i));
      affirm(b == nioBlob.get(i));
      ++i;
      total += b;
    }
    affirm( SQLITE_DONE == sqlite3_step(stmt) );
    sqlite3_finalize(stmt);
    affirm(total == expectTotal);

    SQLFunction func =
      new ScalarFunction(){
        public void xFunc(sqlite3_context cx, sqlite3_value[] args){
          sqlite3_result_blob(cx, buf, 1, 3);
        }
      };

    affirm( 0 == sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func) );
    stmt = prepare(db, "SELECT myfunc()");
    affirm( SQLITE_ROW == sqlite3_step(stmt) );
    blob = sqlite3_column_blob(stmt, 0);
    affirm(3 == blob.length);
    i = 0;
    total = 0;
    for(byte b : blob){
      affirm( i<=3 );
      affirm(b == buf.get(1 + i++));
      total += b;
    }
    affirm( SQLITE_DONE == sqlite3_step(stmt) );
    sqlite3_finalize(stmt);
    affirm(total == expectTotal);

    sqlite3_close_v2(db);
  }

  private void testSql(){
    sqlite3 db = createNewDb();
    sqlite3_stmt stmt = prepare(db, "SELECT 1");
    affirm( "SELECT 1".equals(sqlite3_sql(stmt)) );
    sqlite3_finalize(stmt);
    stmt = prepare(db, "SELECT ?");
589
590
591
592
593
594
595
596

597
598

599
600
601
602
603
604
605
689
690
691
692
693
694
695

696
697

698
699
700
701
702
703
704
705







-
+

-
+







        public void xDestroy() {
          // Just demonstrates that xDestroy is called.
          ++xDestroyCalled.value;
        }
      };
    final CollationNeededCallback collLoader = new CollationNeededCallback(){
        @Override
        public int call(sqlite3 dbArg, int eTextRep, String collationName){
        public void call(sqlite3 dbArg, int eTextRep, String collationName){
          affirm(dbArg == db/* as opposed to a temporary object*/);
          return sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation);
          sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation);
        }
      };
    int rc = sqlite3_collation_needed(db, collLoader);
    affirm( 0 == rc );
    rc = sqlite3_collation_needed(db, collLoader);
    affirm( 0 == rc /* Installing the same object again is a no-op */);
    sqlite3_stmt stmt = prepare(db, "SELECT a FROM t ORDER BY a COLLATE reversi");
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
899
900
901
902
903
904
905
906
907
908
909
910
911

912
913



914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959







+
+
+
+


-
+

-
-
-
+
+
+














+
+



+
+
+
+
+
+
+
+






+
+
+







    sqlite3_stmt stmt = prepare(db, "select myfunc(?)");
    affirm( 0 != stmt.getNativePointer() );
    affirm( testResult.value == db );
    rc = sqlite3_bind_java_object(stmt, 1, boundObj);
    affirm( 0==rc );
    int n = 0;
    if( SQLITE_ROW == sqlite3_step(stmt) ){
      affirm( testResult.value == sqlite3_column_java_object(stmt, 0) );
      affirm( testResult.value == sqlite3_column_java_object(stmt, 0, sqlite3.class) );
      affirm( null == sqlite3_column_java_object(stmt, 0, sqlite3_stmt.class) );
      affirm( null == sqlite3_column_java_object(stmt,1) );
      final sqlite3_value v = sqlite3_column_value(stmt, 0);
      affirm( testResult.value == sqlite3_value_java_object(v) );
      affirm( testResult.value == sqlite3_value_java_casted(v, sqlite3.class) );
      affirm( testResult.value == sqlite3_value_java_object(v, sqlite3.class) );
      affirm( testResult.value ==
              sqlite3_value_java_casted(v, testResult.value.getClass()) );
      affirm( testResult.value == sqlite3_value_java_casted(v, Object.class) );
      affirm( null == sqlite3_value_java_casted(v, String.class) );
              sqlite3_value_java_object(v, testResult.value.getClass()) );
      affirm( testResult.value == sqlite3_value_java_object(v, Object.class) );
      affirm( null == sqlite3_value_java_object(v, String.class) );
      ++n;
    }
    sqlite3_finalize(stmt);
    affirm( 1 == n );
    affirm( 0==sqlite3_db_release_memory(db) );
    sqlite3_close_v2(db);
  }

  private void testUdfAggregate(){
    final sqlite3 db = createNewDb();
    final ValueHolder<Boolean> xFinalNull =
      // To confirm that xFinal() is called with no aggregate state
      // when the corresponding result set is empty.
      new ValueHolder<>(false);
    final ValueHolder<sqlite3_value[]> neverEverDoThisInClientCode = new ValueHolder<>(null);
    final ValueHolder<sqlite3_context> neverEverDoThisInClientCode2 = new ValueHolder<>(null);
    SQLFunction func = new AggregateFunction<Integer>(){
        @Override
        public void xStep(sqlite3_context cx, sqlite3_value[] args){
          if( null==neverEverDoThisInClientCode.value ){
            /* !!!NEVER!!! hold a reference to an sqlite3_value or
               sqlite3_context object like this in client code! They
               are ONLY legal for the duration of their single
               call. We do it here ONLY to test that the defenses
               against clients doing this are working. */
            neverEverDoThisInClientCode.value = args;
          }
          final ValueHolder<Integer> agg = this.getAggregateState(cx, 0);
          agg.value += sqlite3_value_int(args[0]);
          affirm( agg == this.getAggregateState(cx, 0) );
        }
        @Override
        public void xFinal(sqlite3_context cx){
          if( null==neverEverDoThisInClientCode2.value ){
            neverEverDoThisInClientCode2.value = cx;
          }
          final Integer v = this.takeAggregateState(cx);
          if(null == v){
            xFinalNull.value = true;
            sqlite3_result_null(cx);
          }else{
            sqlite3_result_int(cx, v);
          }
853
854
855
856
857
858
859




860
861
862
863
864
865
866
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987







+
+
+
+







      affirm( 6 == v );
      int v2 = sqlite3_column_int(stmt, 1);
      affirm( 30+v == v2 );
      ++n;
    }
    affirm( 1==n );
    affirm(!xFinalNull.value);
    affirm( null!=neverEverDoThisInClientCode.value );
    affirm( null!=neverEverDoThisInClientCode2.value );
    affirm( 0<neverEverDoThisInClientCode.value.length );
    affirm( 0==neverEverDoThisInClientCode2.value.getNativePointer() );
    sqlite3_reset(stmt);
    affirm( 1==sqlite3_stmt_status(stmt, SQLITE_STMTSTATUS_RUN, false) );
    // Ensure that the accumulator is reset on subsequent calls...
    n = 0;
    if( SQLITE_ROW == sqlite3_step(stmt) ){
      final int v = sqlite3_column_int(stmt, 0);
      affirm( 6 == v );
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
1042
1043
1044
1045
1046
1047
1048

1049
1050
1051
1052
1053
1054
1055







-







        "('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
      });
    final sqlite3_stmt stmt = prepare(db,
                         "SELECT x, winsumint(y) OVER ("+
                         "ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"+
                         ") AS sum_y "+
                         "FROM twin ORDER BY x;");
    affirm( 0 == rc );
    int n = 0;
    while( SQLITE_ROW == sqlite3_step(stmt) ){
      final String s = sqlite3_column_text16(stmt, 0);
      final int i = sqlite3_column_int(stmt, 1);
      switch(++n){
        case 1: affirm( "a".equals(s) && 9==i ); break;
        case 2: affirm( "b".equals(s) && 12==i ); break;
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
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







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

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







    sqlite3_close_v2(db);
    affirm( 7 == counter.value );
  }

  @SingleThreadOnly /* because threads inherently break this test */
  private static void testBusy(){
    final String dbName = "_busy-handler.db";
    final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3();
    final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();

    int rc = sqlite3_open(dbName, outDb);
    ++metrics.dbOpen;
    affirm( 0 == rc );
    final sqlite3 db1 = outDb.get();
    execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
    rc = sqlite3_open(dbName, outDb);
    ++metrics.dbOpen;
    affirm( 0 == rc );
    affirm( outDb.get() != db1 );
    final sqlite3 db2 = outDb.get();

    affirm( "main".equals( sqlite3_db_name(db1, 0) ) );
    rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo");
    affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) );
    affirm( "foo".equals( sqlite3_db_name(db1, 0) ) );

    final ValueHolder<Integer> xBusyCalled = new ValueHolder<>(0);
    BusyHandlerCallback handler = new BusyHandlerCallback(){
        @Override public int call(int n){
          //outln("busy handler #"+n);
          return n > 2 ? 0 : ++xBusyCalled.value;
        }
      };
    rc = sqlite3_busy_handler(db2, handler);
    affirm(0 == rc);

    // Force a locked condition...
    execSql(db1, "BEGIN EXCLUSIVE");
    rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
    affirm( SQLITE_BUSY == rc);
    affirm( null == outStmt.get() );
    affirm( 3 == xBusyCalled.value );
    sqlite3_close_v2(db1);
    sqlite3_close_v2(db2);
    try{
      final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3();
      final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
      final java.io.File f = new java.io.File(dbName);
      f.delete();
    }catch(Exception e){
      /* ignore */

      int rc = sqlite3_open(dbName, outDb);
      ++metrics.dbOpen;
      affirm( 0 == rc );
      final sqlite3 db1 = outDb.get();
      execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
      rc = sqlite3_open(dbName, outDb);
      ++metrics.dbOpen;
      affirm( 0 == rc );
      affirm( outDb.get() != db1 );
      final sqlite3 db2 = outDb.get();

      affirm( "main".equals( sqlite3_db_name(db1, 0) ) );
      rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo");
      affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) );
      affirm( "foo".equals( sqlite3_db_name(db1, 0) ) );
      affirm( SQLITE_MISUSE == sqlite3_db_config(db1, 0, 0, null) );

      final ValueHolder<Integer> xBusyCalled = new ValueHolder<>(0);
      BusyHandlerCallback handler = new BusyHandlerCallback(){
          @Override public int call(int n){
            //outln("busy handler #"+n);
            return n > 2 ? 0 : ++xBusyCalled.value;
          }
        };
      rc = sqlite3_busy_handler(db2, handler);
      affirm(0 == rc);

      // Force a locked condition...
      execSql(db1, "BEGIN EXCLUSIVE");
      rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
      affirm( SQLITE_BUSY == rc);
      affirm( null == outStmt.get() );
      affirm( 3 == xBusyCalled.value );
      sqlite3_close_v2(db1);
      sqlite3_close_v2(db2);
    }finally{
      try{(new java.io.File(dbName)).delete();}
      catch(Exception e){/* ignore */}
    }
  }

  private void testProgress(){
    final sqlite3 db = createNewDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    sqlite3_progress_handler(db, 1, new ProgressHandlerCallback(){
1089
1090
1091
1092
1093
1094
1095

1096
1097
1098
1099
1100
1101
1102
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223







+







    execSql(db, "SELECT 1; SELECT 2;");
    affirm( nOld == counter.value );
    sqlite3_close_v2(db);
  }

  private void testCommitHook(){
    final sqlite3 db = createNewDb();
    sqlite3_extended_result_codes(db, true);
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    final ValueHolder<Integer> hookResult = new ValueHolder<>(0);
    final CommitHookCallback theHook = new CommitHookCallback(){
        @Override public int call(){
          ++counter.value;
          return hookResult.value;
        }
1131
1132
1133
1134
1135
1136
1137
1138

1139
1140
1141
1142
1143
1144
1145
1252
1253
1254
1255
1256
1257
1258

1259
1260
1261
1262
1263
1264
1265
1266







-
+







    affirm( 4 == counter.value );
    oldHook = sqlite3_commit_hook(db, theHook);
    affirm( newHook == oldHook );
    execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
    affirm( 5 == counter.value );
    hookResult.value = SQLITE_ERROR;
    int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
    affirm( SQLITE_CONSTRAINT == rc );
    affirm( SQLITE_CONSTRAINT_COMMITHOOK == rc );
    affirm( 6 == counter.value );
    sqlite3_close_v2(db);
  }

  private void testUpdateHook(){
    final sqlite3 db = createNewDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
1350
1351
1352
1353
1354
1355
1356



1357
1358
1359
1360
1361
1362
1363
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487







+
+
+







    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
    sqlite3_set_authorizer(db, auth);
    execSql(db, "UPDATE t SET a=1");
    affirm( 1 == counter.value );
    authRc.value = SQLITE_DENY;
    int rc = execSql(db, false, "UPDATE t SET a=2");
    affirm( SQLITE_AUTH==rc );
    sqlite3_set_authorizer(db, null);
    rc = execSql(db, false, "UPDATE t SET a=2");
    affirm( 0==rc );
    // TODO: expand these tests considerably
    sqlite3_close(db);
  }

  @SingleThreadOnly /* because multiple threads legitimately make these
                       results unpredictable */
  private synchronized void testAutoExtension(){
1411
1412
1413
1414
1415
1416
1417
1418

1419
1420
1421
1422
1423
1424
1425
1535
1536
1537
1538
1539
1540
1541

1542
1543
1544
1545
1546
1547
1548
1549







-
+







    }
    affirm( err!=null );
    affirm( err.getMessage().indexOf(toss.value)>0 );
    toss.value = null;

    val.value = 0;
    final AutoExtensionCallback ax2 = new AutoExtensionCallback(){
        @Override public synchronized int call(sqlite3 db){
        @Override public int call(sqlite3 db){
          ++val.value;
          return 0;
        }
      };
    rc = sqlite3_auto_extension( ax2 );
    affirm( 0 == rc );
    sqlite3_close(createNewDb());
1622
1623
1624
1625
1626
1627
1628
1629

1630
1631
1632
1633
1634
1635
1636
1637
1638
















































































1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650

1651
1652
1653



1654
1655
1656
1657
1658
1659
1660
1661
1662




1663
1664
1665
1666
1667
1668
1669
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
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







-
+









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












+



+
+
+









+
+
+
+







    sqlite3_stmt stmt = prepare(db,"SELECT length(a), a FROM t ORDER BY a");
    affirm( SQLITE_ROW == sqlite3_step(stmt) );
    affirm( 3 == sqlite3_column_int(stmt,0) );
    affirm( "def".equals(sqlite3_column_text16(stmt,1)) );
    sqlite3_finalize(stmt);

    b = sqlite3_blob_open(db, "main", "t", "a",
                          sqlite3_last_insert_rowid(db), 1);
                          sqlite3_last_insert_rowid(db), 0);
    affirm( null!=b );
    rc = sqlite3_blob_reopen(b, 2);
    affirm( 0==rc );
    final byte[] tgt = new byte[3];
    rc = sqlite3_blob_read(b, tgt, 0);
    affirm( 0==rc );
    affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
    rc = sqlite3_blob_close(b);
    affirm( 0==rc );

    if( !sqlite3_jni_supports_nio() ){
      outln("WARNING: skipping tests for ByteBuffer-using sqlite3_blob APIs ",
            "because this platform lacks that support.");
      sqlite3_close_v2(db);
      return;
    }
    /* Sanity checks for the java.nio.ByteBuffer-taking overloads of
       sqlite3_blob_read/write(). */
    execSql(db, "UPDATE t SET a=zeroblob(10)");
    b = sqlite3_blob_open(db, "main", "t", "a", 1, 1);
    affirm( null!=b );
    java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocateDirect(10);
    for( byte i = 0; i < 10; ++i ){
      bb.put((int)i, (byte)(48+i & 0xff));
    }
    rc = sqlite3_blob_write(b, 1, bb, 1, 10);
    affirm( rc==SQLITE_ERROR, "b length < (srcOffset + bb length)" );
    rc = sqlite3_blob_write(b, -1, bb);
    affirm( rc==SQLITE_ERROR, "Target offset may not be negative" );
    rc = sqlite3_blob_write(b, 0, bb, -1, -1);
    affirm( rc==SQLITE_ERROR, "Source offset may not be negative" );
    rc = sqlite3_blob_write(b, 1, bb, 1, 8);
    affirm( rc==0 );
    // b's contents: 0 49  50  51  52  53  54  55  56  0
    //        ascii: 0 '1' '2' '3' '4' '5' '6' '7' '8' 0
    byte br[] = new byte[10];
    java.nio.ByteBuffer bbr =
      java.nio.ByteBuffer.allocateDirect(bb.limit());
    rc = sqlite3_blob_read( b, br, 0 );
    affirm( rc==0 );
    rc = sqlite3_blob_read( b, bbr );
    affirm( rc==0 );
    java.nio.ByteBuffer bbr2 = sqlite3_blob_read_nio_buffer(b, 0, 12);
    affirm( null==bbr2, "Read size is too big");
    bbr2 = sqlite3_blob_read_nio_buffer(b, -1, 3);
    affirm( null==bbr2, "Source offset is negative");
    bbr2 = sqlite3_blob_read_nio_buffer(b, 5, 6);
    affirm( null==bbr2, "Read pos+size is too big");
    bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 7);
    affirm( null==bbr2, "Read pos+size is too big");
    bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 6);
    affirm( null!=bbr2 );
    java.nio.ByteBuffer bbr3 =
      java.nio.ByteBuffer.allocateDirect(2 * bb.limit());
    java.nio.ByteBuffer bbr4 =
      java.nio.ByteBuffer.allocateDirect(5);
    rc = sqlite3_blob_read( b, bbr3 );
    affirm( rc==0 );
    rc = sqlite3_blob_read( b, bbr4 );
    affirm( rc==0 );
    affirm( sqlite3_blob_bytes(b)==bbr3.limit() );
    affirm( 5==bbr4.limit() );
    sqlite3_blob_close(b);
    affirm( 0==br[0] );
    affirm( 0==br[9] );
    affirm( 0==bbr.get(0) );
    affirm( 0==bbr.get(9) );
    affirm( bbr2.limit() == 6 );
    affirm( 0==bbr3.get(0) );
    {
      Exception ex = null;
      try{ bbr3.get(11); }
      catch(Exception e){ex = e;}
      affirm( ex instanceof IndexOutOfBoundsException,
              "bbr3.limit() was reset by read()" );
      ex = null;
    }
    affirm( 0==bbr4.get(0) );
    for( int i = 1; i < 9; ++i ){
      affirm( br[i] == 48 + i );
      affirm( br[i] == bbr.get(i) );
      affirm( br[i] == bbr3.get(i) );
      if( i>3 ){
        affirm( br[i] == bbr2.get(i-4) );
      }
      if( i < bbr4.limit() ){
        affirm( br[i] == bbr4.get(i) );
      }
    }
    sqlite3_close_v2(db);
  }

  private void testPrepareMulti(){
    final sqlite3 db = createNewDb();
    final String[] sql = {
      "create table t(","a)",
      "; insert into t(a) values(1),(2),(3);",
      "select a from t;"
    };
    final List<sqlite3_stmt> liStmt = new ArrayList<sqlite3_stmt>();
    final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
    final ValueHolder<String> toss = new ValueHolder<>(null);
    PrepareMultiCallback m = new PrepareMultiCallback() {
        @Override public int call(sqlite3_stmt st){
          liStmt.add(st);
          if( null!=toss.value ){
            throw new RuntimeException(toss.value);
          }
          return proxy.call(st);
        }
      };
    int rc = sqlite3_prepare_multi(db, sql, m);
    affirm( 0==rc );
    affirm( liStmt.size() == 3 );
    for( sqlite3_stmt st : liStmt ){
      sqlite3_finalize(st);
    }
    toss.value = "This is an exception.";
    rc = sqlite3_prepare_multi(db, "SELECT 1", m);
    affirm( SQLITE_ERROR==rc );
    affirm( sqlite3_errmsg(db).indexOf(toss.value)>0 );
    sqlite3_close_v2(db);
  }

  /* Copy/paste/rename this to add new tests. */
  private void _testTemplate(){
    final sqlite3 db = createNewDb();
    sqlite3_stmt stmt = prepare(db,"SELECT 1");
1694
1695
1696
1697
1698
1699
1700
1701

1702
1703
1704
1705
1706
1707
1708
1906
1907
1908
1909
1910
1911
1912

1913
1914
1915
1916
1917
1918
1919
1920







-
+







    if(false) showCompileOption();
    List<java.lang.reflect.Method> mlist = testMethods;
    affirm( null!=mlist );
    if( shuffle ){
      mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
      java.util.Collections.shuffle(mlist);
    }
    if( listRunTests ){
    if( (!fromThread && listRunTests>0) || listRunTests>1 ){
      synchronized(this.getClass()){
        if( !fromThread ){
          out("Initial test"," list: ");
          for(java.lang.reflect.Method m : testMethods){
            out(m.getName()+" ");
          }
          outln();
1755
1756
1757
1758
1759
1760
1761
1762

1763
1764



1765
1766
1767
1768
1769
1770
1771
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976

1977
1978
1979
1980
1981
1982
1983
1984
1985
1986








+

-
+
+
+







     -r|-repeat N: repeats the tests in a loop N times, each one
      consisting of the -thread value's threads.

     -shuffle: randomizes the order of most of the test functions.

     -naps: sleep small random intervals between tests in order to add
     some chaos for cross-thread contention.


     -list-tests: outputs the list of tests being run, minus some
      which are hard-coded. This is noisy in multi-threaded mode.
      which are hard-coded. In multi-threaded mode, use this twice to
      to emit the list run by each thread (which may differ from the initial
      list, in particular if -shuffle is used).

     -fail: forces an exception to be thrown during the test run.  Use
     with -shuffle to make its appearance unpredictable.

     -v: emit some developer-mode info at the end.
  */
  public static void main(String[] args) throws Exception {
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
2001
2002
2003
2004
2005
2006
2007

2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026

2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037

2038
2039
2040
2041
2042
2043
2044
2045







-
+


















-
+










-
+







        }else if(arg.equals("t") || arg.equals("thread")){
          nThread = Integer.parseInt(args[i++]);
        }else if(arg.equals("r") || arg.equals("repeat")){
          nRepeat = Integer.parseInt(args[i++]);
        }else if(arg.equals("shuffle")){
          shuffle = true;
        }else if(arg.equals("list-tests")){
          listRunTests = true;
          ++listRunTests;
        }else if(arg.equals("fail")){
          forceFail = true;
        }else if(arg.equals("sqllog")){
          sqlLog = true;
        }else if(arg.equals("configlog")){
          configLog = true;
        }else if(arg.equals("naps")){
          takeNaps = true;
        }else if(arg.equals("q") || arg.equals("quiet")){
          squelchTestOutput = true;
        }else{
          throw new IllegalArgumentException("Unhandled flag:"+arg);
        }
      }
    }

    if( sqlLog ){
      if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
        final ConfigSqllogCallback log = new ConfigSqllogCallback() {
        final ConfigSqlLogCallback log = new ConfigSqlLogCallback() {
            @Override public void call(sqlite3 db, String msg, int op){
              switch(op){
                case 0: outln("Opening db: ",db); break;
                case 1: outln("SQL ",db,": ",msg); break;
                case 2: outln("Closing db: ",db); break;
              }
            }
          };
        int rc = sqlite3_config( log );
        affirm( 0==rc );
        rc = sqlite3_config( (ConfigSqllogCallback)null );
        rc = sqlite3_config( (ConfigSqlLogCallback)null );
        affirm( 0==rc );
        rc = sqlite3_config( log );
        affirm( 0==rc );
      }else{
        outln("WARNING: -sqllog is not active because library was built ",
              "without SQLITE_ENABLE_SQLLOG.");
      }
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
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083

2084



2085
2086
2087
2088
2089

2090
2091
2092
2093
2094
2095
2096







+
+
+
+
+


+
-
+
-
-
-





-







      int nSkipped = 0;
      for(final java.lang.reflect.Method m : Tester1.class.getDeclaredMethods()){
        final String name = m.getName();
        if( name.equals("testFail") ){
          if( forceFail ){
            testMethods.add(m);
          }
        }else if( m.isAnnotationPresent( RequiresJniNio.class )
                  && !sqlite3_jni_supports_nio() ){
          outln("Skipping test for lack of JNI java.nio.ByteBuffer support: ",
                name,"()\n");
          ++nSkipped;
        }else if( !m.isAnnotationPresent( ManualTest.class ) ){
          if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
            out("Skipping test in multi-thread mode: ",name,"()\n");
            if( 0==nSkipped++ ){
            ++nSkipped;
              out("Skipping tests in multi-thread mode:");
            }
            out(" "+name+"()");
          }else if( name.startsWith("test") ){
            testMethods.add(m);
          }
        }
      }
      if( nSkipped>0 ) out("\n");
    }

    final long timeStart = System.currentTimeMillis();
    int nLoop = 0;
    switch( sqlite3_threadsafe() ){ /* Sanity checking */
      case 0:
        affirm( SQLITE_ERROR==sqlite3_config( SQLITE_CONFIG_SINGLETHREAD ),
1897
1898
1899
1900
1901
1902
1903

1904
1905
1906
1907
1908
1909
1910
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128







+







      default:
        affirm( false, "Unhandled SQLITE_THREADSAFE value." );
    }
    outln("libversion_number: ",
          sqlite3_libversion_number(),"\n",
          sqlite3_libversion(),"\n",SQLITE_SOURCE_ID,"\n",
          "SQLITE_THREADSAFE=",sqlite3_threadsafe());
    outln("JVM NIO support? ",sqlite3_jni_supports_nio() ? "YES" : "NO");
    final boolean showLoopCount = (nRepeat>1 && nThread>1);
    if( showLoopCount ){
      outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
    }
    if( takeNaps ) outln("Napping between tests is enabled.");
    for( int n = 0; n < nRepeat; ++n ){
      ++nLoop;
Changes to ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java.
15
16
17
18
19
20
21
22


23
24
25
15
16
17
18
19
20
21

22
23
24
25
26







-
+
+




/**
   Callback for use with {@link CApi#sqlite3_update_hook}.
*/
public interface UpdateHookCallback extends CallbackProxy {
  /**
     Must function as described for the C-level sqlite3_update_hook()
     callback.
     callback. If it throws, the exception is translated into
     a db-level error.
  */
  void call(int opId, String dbName, String tableName, long rowId);
}
Changes to ext/jni/src/org/sqlite/jni/capi/ValueHolder.java.
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
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











+
-
+






-
+
+






/*
** 2023-10-16
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the ValueHolder utility class for the sqlite3
** This file contains a set of tests for the sqlite3 JNI bindings.
** JNI bindings.
*/
package org.sqlite.jni.capi;

/**
   A helper class which simply holds a single value. Its primary use
   is for communicating values out of anonymous classes, as doing so
   requires a "final" reference.
   requires a "final" reference, as well as communicating aggregate
   SQL function state across calls to such functions.
*/
public class ValueHolder<T> {
  public T value;
  public ValueHolder(){}
  public ValueHolder(T v){value = v;}
}
Changes to ext/jni/src/org/sqlite/jni/capi/sqlite3.java.
34
35
36
37
38
39
40
41

42
43
34
35
36
37
38
39
40

41
42
43







-
+


    return sqlite3.class.getSimpleName()
      +"@"+String.format("0x%08x",ptr)
      +"["+((null == fn) ? "<unnamed>" : fn)+"]"
      ;
  }

  @Override public void close(){
    CApi.sqlite3_close_v2(this.clearNativePointer());
    CApi.sqlite3_close_v2(this);
  }
}
Changes to ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java.
21
22
23
24
25
26
27
28

29
30
31
21
22
23
24
25
26
27

28
29

30







-
+

-

*/
public final class sqlite3_blob extends NativePointerHolder<sqlite3_blob>
  implements AutoCloseable {
  // Only invoked from JNI.
  private sqlite3_blob(){}

  @Override public void close(){
    CApi.sqlite3_blob_close(this.clearNativePointer());
    CApi.sqlite3_blob_close(this);
  }

}
Changes to ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java.
21
22
23
24
25
26
27
28

29
30
21
22
23
24
25
26
27

28
29
30







-
+


*/
public final class sqlite3_stmt extends NativePointerHolder<sqlite3_stmt>
  implements AutoCloseable {
  // Only invoked from JNI.
  private sqlite3_stmt(){}

  @Override public void close(){
    CApi.sqlite3_finalize(this.clearNativePointer());
    CApi.sqlite3_finalize(this);
  }
}
Changes to ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java.
621
622
623
624
625
626
627




628
629
630
631










632
633
634
635
636
637
638
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







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







      "SELECT fts5_columntext(ft, 0) FROM ft('x') ORDER BY rowid",
      "[x, x, x y z, x y z, x y z, x]"
    );
    do_execsql_test(db, 
      "SELECT fts5_columntext(ft, 1) FROM ft('x') ORDER BY rowid",
      "[x, x, x y z, x z, x y z, x]"
    );
    boolean threw = false;
    try{
      /* columntext() used to return NULLs when given an out-of bounds column
         but now results in a range error. */
    do_execsql_test(db, 
      "SELECT fts5_columntext(ft, 2) FROM ft('x') ORDER BY rowid",
      "[null, null, null, null, null, null]"
    );
      do_execsql_test(db, 
        "SELECT fts5_columntext(ft, 2) FROM ft('x') ORDER BY rowid",
        "[null, null, null, null, null, null]"
      );
    }catch(Exception e){
      threw = true;
      affirm( e.getMessage().matches(".*column index out of range") );
    }
    affirm( threw );
    threw = false;

    /* Test fts5_columntotalsize() */
    do_execsql_test(db, 
      "SELECT fts5_columntotalsize(ft, 0) FROM ft('x') ORDER BY rowid",
      "[12, 12, 12, 12, 12, 12]"
    );
    do_execsql_test(db, 
Changes to ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
8
9
10
11
12
13
14




15
16
17
18
19
20
21







-
-
-
-







**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.annotation.*;
import org.sqlite.jni.capi.sqlite3_context;
import org.sqlite.jni.capi.sqlite3_value;

/**
   EXPERIMENTAL/INCOMPLETE/UNTESTED

   A SqlFunction implementation for aggregate functions. The T type
   represents the type of data accumulated by this aggregate while it
   works. e.g. a SUM()-like UDF might use Integer or Long and a
46
47
48
49
50
51
52
53



































































54
55

56
57
58
59
60
61
62
63
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








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

-
+
-







  public abstract void xFinal(SqlFunction.Arguments args);

  /**
     Optionally override to be notified when the UDF is finalized by
     SQLite.
  */
  public void xDestroy() {}

  /**
     PerContextState assists aggregate and window functions in
     managing their accumulator state across calls to the UDF's
     callbacks.

     <p>T must be of a type which can be legally stored as a value in
     java.util.HashMap<KeyType,T>.

     <p>If a given aggregate or window function is called multiple times
     in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
     then the clients need some way of knowing which call is which so
     that they can map their state between their various UDF callbacks
     and reset it via xFinal(). This class takes care of such
     mappings.

     <p>This class works by mapping
     sqlite3_context.getAggregateContext() to a single piece of
     state, of a client-defined type (the T part of this class), which
     persists across a "matching set" of the UDF's callbacks.

     <p>This class is a helper providing commonly-needed functionality
     - it is not required for use with aggregate or window functions.
     Client UDFs are free to perform such mappings using custom
     approaches. The provided {@link AggregateFunction} and {@link
     WindowFunction} classes use this.
  */
  public static final class PerContextState<T> {
    private final java.util.Map<Long,ValueHolder<T>> map
      = new java.util.HashMap<>();

    /**
       Should be called from a UDF's xStep(), xValue(), and xInverse()
       methods, passing it that method's first argument and an initial
       value for the persistent state. If there is currently no
       mapping for the given context within the map, one is created
       using the given initial value, else the existing one is used
       and the 2nd argument is ignored.  It returns a ValueHolder<T>
       which can be used to modify that state directly without
       requiring that the client update the underlying map's entry.

       <p>The caller is obligated to eventually call
       takeAggregateState() to clear the mapping.
    */
    public ValueHolder<T> getAggregateState(SqlFunction.Arguments args, T initialValue){
      final Long key = args.getContext().getAggregateContext(true);
      ValueHolder<T> rc = null==key ? null : map.get(key);
      if( null==rc ){
        map.put(key, rc = new ValueHolder<>(initialValue));
      }
      return rc;
    }

    /**
       Should be called from a UDF's xFinal() method and passed that
       method's first argument. This function removes the value
       associated with with the arguments' aggregate context from the
       map and returns it, returning null if no other UDF method has
       been called to set up such a mapping. The latter condition will
       be the case if a UDF is used in a statement which has no result
       rows.
    */
    public T takeAggregateState(SqlFunction.Arguments args){
      final ValueHolder<T> h = map.remove(args.getContext().getAggregateContext(false));
      return null==h ? null : h.value;
    }
  }

  /** Per-invocation state for the UDF. */
  private final SqlFunction.PerContextState<T> map =
  private final PerContextState<T> map = new PerContextState<>();
    new SqlFunction.PerContextState<>();

  /**
     To be called from the implementation's xStep() method, as well
     as the xValue() and xInverse() methods of the {@link WindowFunction}
     subclass, to fetch the current per-call UDF state. On the
     first call to this method for any given sqlite3_context
     argument, the context is set to the given initial value. On all other
Changes to ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java.
18
19
20
21
22
23
24








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







+
+
+
+
+
+
+
+








/**
   Base marker interface for SQLite's three types of User-Defined SQL
   Functions (UDFs): Scalar, Aggregate, and Window functions.
*/
public interface SqlFunction  {

  public static final int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC;
  public static final int INNOCUOUS = CApi.SQLITE_INNOCUOUS;
  public static final int DIRECTONLY = CApi.SQLITE_DIRECTONLY;
  public static final int SUBTYPE = CApi.SQLITE_SUBTYPE;
  public static final int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE;
  public static final int UTF8 = CApi.SQLITE_UTF8;
  public static final int UTF16 = CApi.SQLITE_UTF16;

  /**
     The Arguments type is an abstraction on top of the lower-level
     UDF function argument types. It provides _most_ of the functionality
     of the lower-level interface, insofar as possible without "leaking"
     those types into this API.
  */
  public final static class Arguments implements Iterable<SqlFunction.Arguments.Arg>{
41
42
43
44
45
46
47
48

49
50
51
52










































































































53

54
55
56
57
58
59
60
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







-
+




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







       AggregateAdapter.

       Passing null for the args is equivalent to passing a length-0
       array.
    */
    Arguments(sqlite3_context cx, sqlite3_value args[]){
      this.cx = cx;
      this.args = args==null ? new sqlite3_value[0] : args;;
      this.args = args==null ? new sqlite3_value[0] : args;
      this.length = this.args.length;
    }

    /**
       Returns the sqlite3_value at the given argument index or throws
       an IllegalArgumentException exception if ndx is out of range.
    */
    private sqlite3_value valueAt(int ndx){
      if(ndx<0 || ndx>=args.length){
        throw new IllegalArgumentException(
          "SQL function argument index "+ndx+" is out of range."
        );
      }
      return args[ndx];
    }

    //! Returns the underlying sqlite3_context for these arguments.
    sqlite3_context getContext(){return cx;}

    /**
       Returns the Sqlite (db) object associated with this UDF call,
       or null if the UDF is somehow called without such an object or
       the db has been closed in an untimely manner (e.g. closed by a
       UDF call).
    */
    public Sqlite getDb(){
      return Sqlite.fromNative( CApi.sqlite3_context_db_handle(cx) );
    }

    public int getArgCount(){ return args.length; }

    public int getInt(int argNdx){return CApi.sqlite3_value_int(valueAt(argNdx));}
    public long getInt64(int argNdx){return CApi.sqlite3_value_int64(valueAt(argNdx));}
    public double getDouble(int argNdx){return CApi.sqlite3_value_double(valueAt(argNdx));}
    public byte[] getBlob(int argNdx){return CApi.sqlite3_value_blob(valueAt(argNdx));}
    public byte[] getText(int argNdx){return CApi.sqlite3_value_text(valueAt(argNdx));}
    public String getText16(int argNdx){return CApi.sqlite3_value_text16(valueAt(argNdx));}
    public int getBytes(int argNdx){return CApi.sqlite3_value_bytes(valueAt(argNdx));}
    public int getBytes16(int argNdx){return CApi.sqlite3_value_bytes16(valueAt(argNdx));}
    public Object getObject(int argNdx){return CApi.sqlite3_value_java_object(valueAt(argNdx));}
    public <T> T getObject(int argNdx, Class<T> type){
      return CApi.sqlite3_value_java_object(valueAt(argNdx), type);
    }

    public int getType(int argNdx){return CApi.sqlite3_value_type(valueAt(argNdx));}
    public int getSubtype(int argNdx){return CApi.sqlite3_value_subtype(valueAt(argNdx));}
    public int getNumericType(int argNdx){return CApi.sqlite3_value_numeric_type(valueAt(argNdx));}
    public int getNoChange(int argNdx){return CApi.sqlite3_value_nochange(valueAt(argNdx));}
    public boolean getFromBind(int argNdx){return CApi.sqlite3_value_frombind(valueAt(argNdx));}
    public int getEncoding(int argNdx){return CApi.sqlite3_value_encoding(valueAt(argNdx));}

    public void resultInt(int v){ CApi.sqlite3_result_int(cx, v); }
    public void resultInt64(long v){ CApi.sqlite3_result_int64(cx, v); }
    public void resultDouble(double v){ CApi.sqlite3_result_double(cx, v); }
    public void resultError(String msg){CApi.sqlite3_result_error(cx, msg);}
    public void resultError(Exception e){CApi.sqlite3_result_error(cx, e);}
    public void resultErrorTooBig(){CApi.sqlite3_result_error_toobig(cx);}
    public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);}
    public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);}
    public void resultNull(){CApi.sqlite3_result_null(cx);}
    /**
       Analog to sqlite3_result_value(), using the Value object at the
       given argument index.
    */
    public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));}
    public void resultSubtype(int subtype){CApi.sqlite3_result_subtype(cx, subtype);}
    public void resultZeroBlob(long n){
      // Throw on error? If n is too big,
      // sqlite3_result_error_toobig() is automatically called.
      CApi.sqlite3_result_zeroblob64(cx, n);
    }

    public void resultBlob(byte[] blob){CApi.sqlite3_result_blob(cx, blob);}
    public void resultText(byte[] utf8){CApi.sqlite3_result_text(cx, utf8);}
    public void resultText(String txt){CApi.sqlite3_result_text(cx, txt);}
    public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);}
    public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);}

    /**
       Callbacks should invoke this on OOM errors, instead of throwing
       OutOfMemoryError, because the latter cannot be propagated
       through the C API.
    */
    public void resultNoMem(){CApi.sqlite3_result_error_nomem(cx);}

    /**
       Analog to sqlite3_set_auxdata() but throws if argNdx is out of
       range.
    */
    public void setAuxData(int argNdx, Object o){
      /* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html

         The value of the N parameter to these interfaces should be
         non-negative. Future enhancements may make use of negative N
         values to define new kinds of function caching behavior.
      */
      valueAt(argNdx);
      CApi.sqlite3_set_auxdata(cx, argNdx, o);
    }

    /**
       Analog to sqlite3_get_auxdata() but throws if argNdx is out of
       range.
    */
    public Object getAuxData(int argNdx){
      valueAt(argNdx);
      return CApi.sqlite3_get_auxdata(cx, argNdx);
    }

    /**
       Wrapper for a single SqlFunction argument. Primarily intended
       Represents a single SqlFunction argument. Primarily intended
       for use with the Arguments class's Iterable interface.
    */
    public final static class Arg {
      private final Arguments a;
      private final int ndx;
      /* Only for use by the Arguments class. */
      private Arg(Arguments a, int ndx){
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
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







-
+














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

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




-
+







      public double getDouble(){return a.getDouble(ndx);}
      public byte[] getBlob(){return a.getBlob(ndx);}
      public byte[] getText(){return a.getText(ndx);}
      public String getText16(){return a.getText16(ndx);}
      public int getBytes(){return a.getBytes(ndx);}
      public int getBytes16(){return a.getBytes16(ndx);}
      public Object getObject(){return a.getObject(ndx);}
      public <T> T getObjectCasted(Class<T> type){ return a.getObjectCasted(ndx, type); }
      public <T> T getObject(Class<T> type){ return a.getObject(ndx, type); }
      public int getType(){return a.getType(ndx);}
      public Object getAuxData(){return a.getAuxData(ndx);}
      public void setAuxData(Object o){a.setAuxData(ndx, o);}
    }

    @Override
    public java.util.Iterator<SqlFunction.Arguments.Arg> iterator(){
      final Arg[] proxies = new Arg[args.length];
      for( int i = 0; i < args.length; ++i ){
        proxies[i] = new Arg(this, i);
      }
      return java.util.Arrays.stream(proxies).iterator();
    }

    /**
       Returns the sqlite3_value at the given argument index or throws
       an IllegalArgumentException exception if ndx is out of range.
    */
    private sqlite3_value valueAt(int ndx){
      if(ndx<0 || ndx>=args.length){
        throw new IllegalArgumentException(
          "SQL function argument index "+ndx+" is out of range."
        );
      }
  }
      return args[ndx];
    }


    sqlite3_context getContext(){return cx;}

    public int getArgCount(){ return args.length; }

    public int getInt(int arg){return CApi.sqlite3_value_int(valueAt(arg));}
    public long getInt64(int arg){return CApi.sqlite3_value_int64(valueAt(arg));}
    public double getDouble(int arg){return CApi.sqlite3_value_double(valueAt(arg));}
    public byte[] getBlob(int arg){return CApi.sqlite3_value_blob(valueAt(arg));}
    public byte[] getText(int arg){return CApi.sqlite3_value_text(valueAt(arg));}
    public String getText16(int arg){return CApi.sqlite3_value_text16(valueAt(arg));}
    public int getBytes(int arg){return CApi.sqlite3_value_bytes(valueAt(arg));}
    public int getBytes16(int arg){return CApi.sqlite3_value_bytes16(valueAt(arg));}
    public Object getObject(int arg){return CApi.sqlite3_value_java_object(valueAt(arg));}
    public <T> T getObjectCasted(int arg, Class<T> type){
      return CApi.sqlite3_value_java_casted(valueAt(arg), type);
    }

    public int getType(int arg){return CApi.sqlite3_value_type(valueAt(arg));}
    public int getSubtype(int arg){return CApi.sqlite3_value_subtype(valueAt(arg));}
    public int getNumericType(int arg){return CApi.sqlite3_value_numeric_type(valueAt(arg));}
    public int getNoChange(int arg){return CApi.sqlite3_value_nochange(valueAt(arg));}
    public boolean getFromBind(int arg){return CApi.sqlite3_value_frombind(valueAt(arg));}
    public int getEncoding(int arg){return CApi.sqlite3_value_encoding(valueAt(arg));}

    public void resultInt(int v){ CApi.sqlite3_result_int(cx, v); }
    public void resultInt64(long v){ CApi.sqlite3_result_int64(cx, v); }
    public void resultDouble(double v){ CApi.sqlite3_result_double(cx, v); }
    public void resultError(String msg){CApi.sqlite3_result_error(cx, msg);}
    public void resultError(Exception e){CApi.sqlite3_result_error(cx, e);}
    public void resultErrorTooBig(){CApi.sqlite3_result_error_toobig(cx);}
    public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);}
    public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);}
    public void resultNull(){CApi.sqlite3_result_null(cx);}
    public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));}
    public void resultZeroBlob(long n){
      // Throw on error? If n is too big,
      // sqlite3_result_error_toobig() is automatically called.
      CApi.sqlite3_result_zeroblob64(cx, n);
    }

    public void resultBlob(byte[] blob){CApi.sqlite3_result_blob(cx, blob);}
    public void resultText(byte[] utf8){CApi.sqlite3_result_text(cx, utf8);}
    public void resultText(String txt){CApi.sqlite3_result_text(cx, txt);}
    public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);}
    public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);}

    public void setAuxData(int arg, Object o){
      /* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html

         The value of the N parameter to these interfaces should be
         non-negative. Future enhancements may make use of negative N
         values to define new kinds of function caching behavior.
      */
      valueAt(arg);
      CApi.sqlite3_set_auxdata(cx, arg, o);
    }

    public Object getAuxData(int arg){
      valueAt(arg);
      return CApi.sqlite3_get_auxdata(cx, arg);
    }
  }

  /**
     PerContextState assists aggregate and window functions in
     managing their accumulator state across calls to the UDF's
     callbacks.

     <p>T must be of a type which can be legally stored as a value in
     java.util.HashMap<KeyType,T>.

     <p>If a given aggregate or window function is called multiple times
     in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
     then the clients need some way of knowing which call is which so
     that they can map their state between their various UDF callbacks
     and reset it via xFinal(). This class takes care of such
     mappings.

     <p>This class works by mapping
     sqlite3_context.getAggregateContext() to a single piece of
     state, of a client-defined type (the T part of this class), which
     persists across a "matching set" of the UDF's callbacks.

     <p>This class is a helper providing commonly-needed functionality
     - it is not required for use with aggregate or window functions.
     Client UDFs are free to perform such mappings using custom
     approaches. The provided {@link AggregateFunction} and {@link
     WindowFunction} classes use this.
  */
  public static final class PerContextState<T> {
    private final java.util.Map<Long,ValueHolder<T>> map
      = new java.util.HashMap<>();

    /**
       Should be called from a UDF's xStep(), xValue(), and xInverse()
       methods, passing it that method's first argument and an initial
       value for the persistent state. If there is currently no
       mapping for the given context within the map, one is created
       using the given initial value, else the existing one is used
       and the 2nd argument is ignored.  It returns a ValueHolder<T>
       which can be used to modify that state directly without
       requiring that the client update the underlying map's entry.

       <p>The caller is obligated to eventually call
       takeAggregateState() to clear the mapping.
    */
    public ValueHolder<T> getAggregateState(SqlFunction.Arguments args, T initialValue){
      final Long key = args.getContext().getAggregateContext(true);
      ValueHolder<T> rc = null==key ? null : map.get(key);
      if( null==rc ){
        map.put(key, rc = new ValueHolder<>(initialValue));
      }
      return rc;
    }

    /**
       Should be called from a UDF's xFinal() method and passed that
       method's first argument. This function removes the value
       associated with with the arguments' aggregate context from the
       map and returns it, returning null if no other UDF method has
       been called to set up such a mapping. The latter condition will
       be the case if a UDF is used in a statement which has no result
       rows.
    */
    public T takeAggregateState(SqlFunction.Arguments args){
      final ValueHolder<T> h = map.remove(args.getContext().getAggregateContext(false));
      return null==h ? null : h.value;
    }
  }

  /**
     Internal-use adapter for wrapping this package's ScalarFunction
     for use with the org.sqlite.jni.capi.ScalarFunction interface.
  */
  static final class ScalarAdapter extends org.sqlite.jni.capi.ScalarFunction {
    final ScalarFunction impl;
    private final ScalarFunction impl;
    ScalarAdapter(ScalarFunction impl){
      this.impl = impl;
    }
    /**
       Proxies this.impl.xFunc(), adapting the call arguments to that
       function's signature. If the proxy throws, it's translated to
       sqlite_result_error() with the exception's message.
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
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







+
-
-
+
+



















-
-
+
+
+








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







    }
  }

  /**
     Internal-use adapter for wrapping this package's AggregateFunction
     for use with the org.sqlite.jni.capi.AggregateFunction interface.
  */
  static /*cannot be final without duplicating the whole body in WindowAdapter*/
  static final class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
    final AggregateFunction impl;
  class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
    private final AggregateFunction impl;
    AggregateAdapter(AggregateFunction impl){
      this.impl = impl;
    }

    /**
       Proxies this.impl.xStep(), adapting the call arguments to that
       function's signature. If the proxied function throws, it is
       translated to sqlite_result_error() with the exception's
       message.
    */
    public void xStep(sqlite3_context cx, sqlite3_value[] args){
      try{
        impl.xStep( new SqlFunction.Arguments(cx, args) );
      }catch(Exception e){
        CApi.sqlite3_result_error(cx, e);
      }
    }

    /**
       As for the xFinal() argument of the C API's sqlite3_create_function().
       If the proxied function throws, it is translated into a sqlite3_result_error().
       As for the xFinal() argument of the C API's
       sqlite3_create_function().  If the proxied function throws, it
       is translated into a sqlite3_result_error().
    */
    public void xFinal(sqlite3_context cx){
      try{
        impl.xFinal( new SqlFunction.Arguments(cx, null) );
      }catch(Exception e){
        CApi.sqlite3_result_error(cx, e);
      }
    }

    public void xDestroy(){
      impl.xDestroy();
    }
  }

  /**
     Internal-use adapter for wrapping this package's WindowFunction
     for use with the org.sqlite.jni.capi.WindowFunction interface.
  */
  static final class WindowAdapter extends AggregateAdapter {
    private final WindowFunction impl;
    WindowAdapter(WindowFunction impl){
      super(impl);
      this.impl = impl;
    }

    /**
       Proxies this.impl.xInverse(), adapting the call arguments to that
       function's signature. If the proxied function throws, it is
       translated to sqlite_result_error() with the exception's
       message.
    */
    public void xInverse(sqlite3_context cx, sqlite3_value[] args){
      try{
        impl.xInverse( new SqlFunction.Arguments(cx, args) );
      }catch(Exception e){
        CApi.sqlite3_result_error(cx, e);
      }
    }

    /**
       As for the xValue() argument of the C API's sqlite3_create_window_function().
       If the proxied function throws, it is translated into a sqlite3_result_error().
    */
    public void xValue(sqlite3_context cx){
      try{
        impl.xValue( new SqlFunction.Arguments(cx, null) );
      }catch(Exception e){
        CApi.sqlite3_result_error(cx, e);
      }
    }

    public void xDestroy(){
      impl.xDestroy();
    }
  }

}
Changes to ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java.
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
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

333
334
335
336
337
338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506

507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527

528
529
530
531
532
533
534

535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996

997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052

1053
1054
1055
1056
1057
1058
1059
1060
1061
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
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
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
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941


1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991







-



+
+

+










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





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











-
+







+
+
+
+
+
-
+







-
+


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


+
+
+












-
+










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

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


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





-
+


+




+
+
+






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





+
+
+
+
+
+
+
+
+






-
+
+
+




+
+
+
-
+

+










-
+
+
+




-
-
+
+

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




-
-
+
+
+
+
+
+
+

-
-
+
+
+
+
+


+
+
+
+
-
+





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



-
+

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

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

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

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


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



**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
import java.nio.charset.StandardCharsets;
import static org.sqlite.jni.capi.CApi.*;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.capi.sqlite3;
import org.sqlite.jni.capi.sqlite3_stmt;
import org.sqlite.jni.capi.sqlite3_backup;
import org.sqlite.jni.capi.sqlite3_blob;
import org.sqlite.jni.capi.OutputPointer;
import java.nio.ByteBuffer;

/**
   This class represents a database connection, analog to the C-side
   sqlite3 class but with added argument validation, exceptions, and
   similar "smoothing of sharp edges" to make the API safe to use from
   Java. It also acts as a namespace for other types for which
   individual instances are tied to a specific database connection.
*/
public final class Sqlite implements AutoCloseable  {
  private sqlite3 db;
  private static final boolean JNI_SUPPORTS_NIO =
    CApi.sqlite3_jni_supports_nio();

  // Result codes
  public static final int OK = CApi.SQLITE_OK;
  public static final int ERROR = CApi.SQLITE_ERROR;
  public static final int INTERNAL = CApi.SQLITE_INTERNAL;
  public static final int PERM = CApi.SQLITE_PERM;
  public static final int ABORT = CApi.SQLITE_ABORT;
  public static final int BUSY = CApi.SQLITE_BUSY;
  public static final int LOCKED = CApi.SQLITE_LOCKED;
  public static final int NOMEM = CApi.SQLITE_NOMEM;
  public static final int READONLY = CApi.SQLITE_READONLY;
  public static final int INTERRUPT = CApi.SQLITE_INTERRUPT;
  public static final int IOERR = CApi.SQLITE_IOERR;
  public static final int CORRUPT = CApi.SQLITE_CORRUPT;
  public static final int NOTFOUND = CApi.SQLITE_NOTFOUND;
  public static final int FULL = CApi.SQLITE_FULL;
  public static final int CANTOPEN = CApi.SQLITE_CANTOPEN;
  public static final int PROTOCOL = CApi.SQLITE_PROTOCOL;
  public static final int EMPTY = CApi.SQLITE_EMPTY;
  public static final int SCHEMA = CApi.SQLITE_SCHEMA;
  public static final int TOOBIG = CApi.SQLITE_TOOBIG;
  public static final int CONSTRAINT = CApi. SQLITE_CONSTRAINT;
  public static final int MISMATCH = CApi.SQLITE_MISMATCH;
  public static final int MISUSE = CApi.SQLITE_MISUSE;
  public static final int NOLFS = CApi.SQLITE_NOLFS;
  public static final int AUTH = CApi.SQLITE_AUTH;
  public static final int FORMAT = CApi.SQLITE_FORMAT;
  public static final int RANGE = CApi.SQLITE_RANGE;
  public static final int NOTADB = CApi.SQLITE_NOTADB;
  public static final int NOTICE = CApi.SQLITE_NOTICE;
  public static final int WARNING = CApi.SQLITE_WARNING;
  public static final int ROW = CApi.SQLITE_ROW;
  public static final int DONE = CApi.SQLITE_DONE;
  public static final int ERROR_MISSING_COLLSEQ = CApi.SQLITE_ERROR_MISSING_COLLSEQ;
  public static final int ERROR_RETRY = CApi.SQLITE_ERROR_RETRY;
  public static final int ERROR_SNAPSHOT = CApi.SQLITE_ERROR_SNAPSHOT;
  public static final int IOERR_READ = CApi.SQLITE_IOERR_READ;
  public static final int IOERR_SHORT_READ = CApi.SQLITE_IOERR_SHORT_READ;
  public static final int IOERR_WRITE = CApi.SQLITE_IOERR_WRITE;
  public static final int IOERR_FSYNC = CApi.SQLITE_IOERR_FSYNC;
  public static final int IOERR_DIR_FSYNC = CApi.SQLITE_IOERR_DIR_FSYNC;
  public static final int IOERR_TRUNCATE = CApi.SQLITE_IOERR_TRUNCATE;
  public static final int IOERR_FSTAT = CApi.SQLITE_IOERR_FSTAT;
  public static final int IOERR_UNLOCK = CApi.SQLITE_IOERR_UNLOCK;
  public static final int IOERR_RDLOCK = CApi.SQLITE_IOERR_RDLOCK;
  public static final int IOERR_DELETE = CApi.SQLITE_IOERR_DELETE;
  public static final int IOERR_BLOCKED = CApi.SQLITE_IOERR_BLOCKED;
  public static final int IOERR_NOMEM = CApi.SQLITE_IOERR_NOMEM;
  public static final int IOERR_ACCESS = CApi.SQLITE_IOERR_ACCESS;
  public static final int IOERR_CHECKRESERVEDLOCK = CApi.SQLITE_IOERR_CHECKRESERVEDLOCK;
  public static final int IOERR_LOCK = CApi.SQLITE_IOERR_LOCK;
  public static final int IOERR_CLOSE = CApi.SQLITE_IOERR_CLOSE;
  public static final int IOERR_DIR_CLOSE = CApi.SQLITE_IOERR_DIR_CLOSE;
  public static final int IOERR_SHMOPEN = CApi.SQLITE_IOERR_SHMOPEN;
  public static final int IOERR_SHMSIZE = CApi.SQLITE_IOERR_SHMSIZE;
  public static final int IOERR_SHMLOCK = CApi.SQLITE_IOERR_SHMLOCK;
  public static final int IOERR_SHMMAP = CApi.SQLITE_IOERR_SHMMAP;
  public static final int IOERR_SEEK = CApi.SQLITE_IOERR_SEEK;
  public static final int IOERR_DELETE_NOENT = CApi.SQLITE_IOERR_DELETE_NOENT;
  public static final int IOERR_MMAP = CApi.SQLITE_IOERR_MMAP;
  public static final int IOERR_GETTEMPPATH = CApi.SQLITE_IOERR_GETTEMPPATH;
  public static final int IOERR_CONVPATH = CApi.SQLITE_IOERR_CONVPATH;
  public static final int IOERR_VNODE = CApi.SQLITE_IOERR_VNODE;
  public static final int IOERR_AUTH = CApi.SQLITE_IOERR_AUTH;
  public static final int IOERR_BEGIN_ATOMIC = CApi.SQLITE_IOERR_BEGIN_ATOMIC;
  public static final int IOERR_COMMIT_ATOMIC = CApi.SQLITE_IOERR_COMMIT_ATOMIC;
  public static final int IOERR_ROLLBACK_ATOMIC = CApi.SQLITE_IOERR_ROLLBACK_ATOMIC;
  public static final int IOERR_DATA = CApi.SQLITE_IOERR_DATA;
  public static final int IOERR_CORRUPTFS = CApi.SQLITE_IOERR_CORRUPTFS;
  public static final int LOCKED_SHAREDCACHE = CApi.SQLITE_LOCKED_SHAREDCACHE;
  public static final int LOCKED_VTAB = CApi.SQLITE_LOCKED_VTAB;
  public static final int BUSY_RECOVERY = CApi.SQLITE_BUSY_RECOVERY;
  public static final int BUSY_SNAPSHOT = CApi.SQLITE_BUSY_SNAPSHOT;
  public static final int BUSY_TIMEOUT = CApi.SQLITE_BUSY_TIMEOUT;
  public static final int CANTOPEN_NOTEMPDIR = CApi.SQLITE_CANTOPEN_NOTEMPDIR;
  public static final int CANTOPEN_ISDIR = CApi.SQLITE_CANTOPEN_ISDIR;
  public static final int CANTOPEN_FULLPATH = CApi.SQLITE_CANTOPEN_FULLPATH;
  public static final int CANTOPEN_CONVPATH = CApi.SQLITE_CANTOPEN_CONVPATH;
  public static final int CANTOPEN_SYMLINK = CApi.SQLITE_CANTOPEN_SYMLINK;
  public static final int CORRUPT_VTAB = CApi.SQLITE_CORRUPT_VTAB;
  public static final int CORRUPT_SEQUENCE = CApi.SQLITE_CORRUPT_SEQUENCE;
  public static final int CORRUPT_INDEX = CApi.SQLITE_CORRUPT_INDEX;
  public static final int READONLY_RECOVERY = CApi.SQLITE_READONLY_RECOVERY;
  public static final int READONLY_CANTLOCK = CApi.SQLITE_READONLY_CANTLOCK;
  public static final int READONLY_ROLLBACK = CApi.SQLITE_READONLY_ROLLBACK;
  public static final int READONLY_DBMOVED = CApi.SQLITE_READONLY_DBMOVED;
  public static final int READONLY_CANTINIT = CApi.SQLITE_READONLY_CANTINIT;
  public static final int READONLY_DIRECTORY = CApi.SQLITE_READONLY_DIRECTORY;
  public static final int ABORT_ROLLBACK = CApi.SQLITE_ABORT_ROLLBACK;
  public static final int CONSTRAINT_CHECK = CApi.SQLITE_CONSTRAINT_CHECK;
  public static final int CONSTRAINT_COMMITHOOK = CApi.SQLITE_CONSTRAINT_COMMITHOOK;
  public static final int CONSTRAINT_FOREIGNKEY = CApi.SQLITE_CONSTRAINT_FOREIGNKEY;
  public static final int CONSTRAINT_FUNCTION = CApi.SQLITE_CONSTRAINT_FUNCTION;
  public static final int CONSTRAINT_NOTNULL = CApi.SQLITE_CONSTRAINT_NOTNULL;
  public static final int CONSTRAINT_PRIMARYKEY = CApi.SQLITE_CONSTRAINT_PRIMARYKEY;
  public static final int CONSTRAINT_TRIGGER = CApi.SQLITE_CONSTRAINT_TRIGGER;
  public static final int CONSTRAINT_UNIQUE = CApi.SQLITE_CONSTRAINT_UNIQUE;
  public static final int CONSTRAINT_VTAB = CApi.SQLITE_CONSTRAINT_VTAB;
  public static final int CONSTRAINT_ROWID = CApi.SQLITE_CONSTRAINT_ROWID;
  public static final int CONSTRAINT_PINNED = CApi.SQLITE_CONSTRAINT_PINNED;
  public static final int CONSTRAINT_DATATYPE = CApi.SQLITE_CONSTRAINT_DATATYPE;
  public static final int NOTICE_RECOVER_WAL = CApi.SQLITE_NOTICE_RECOVER_WAL;
  public static final int NOTICE_RECOVER_ROLLBACK = CApi.SQLITE_NOTICE_RECOVER_ROLLBACK;
  public static final int WARNING_AUTOINDEX = CApi.SQLITE_WARNING_AUTOINDEX;
  public static final int AUTH_USER = CApi.SQLITE_AUTH_USER;
  public static final int OK_LOAD_PERMANENTLY = CApi.SQLITE_OK_LOAD_PERMANENTLY;

  // sqlite3_open() flags
  public static final int OPEN_READWRITE = CApi.SQLITE_OPEN_READWRITE;
  public static final int OPEN_CREATE = CApi.SQLITE_OPEN_CREATE;
  public static final int OPEN_EXRESCODE = CApi.SQLITE_OPEN_EXRESCODE;

  // transaction state
  public static final int TXN_NONE = CApi.SQLITE_TXN_NONE;
  public static final int TXN_READ = CApi.SQLITE_TXN_READ;
  public static final int TXN_WRITE = CApi.SQLITE_TXN_WRITE;

  // sqlite3_status() ops
  public static final int STATUS_MEMORY_USED = CApi.SQLITE_STATUS_MEMORY_USED;
  public static final int STATUS_PAGECACHE_USED = CApi.SQLITE_STATUS_PAGECACHE_USED;
  public static final int STATUS_PAGECACHE_OVERFLOW = CApi.SQLITE_STATUS_PAGECACHE_OVERFLOW;
  public static final int STATUS_MALLOC_SIZE = CApi.SQLITE_STATUS_MALLOC_SIZE;
  public static final int STATUS_PARSER_STACK = CApi.SQLITE_STATUS_PARSER_STACK;
  public static final int STATUS_PAGECACHE_SIZE = CApi.SQLITE_STATUS_PAGECACHE_SIZE;
  public static final int STATUS_MALLOC_COUNT = CApi.SQLITE_STATUS_MALLOC_COUNT;

  // sqlite3_db_status() ops
  public static final int DBSTATUS_LOOKASIDE_USED = CApi.SQLITE_DBSTATUS_LOOKASIDE_USED;
  public static final int DBSTATUS_CACHE_USED = CApi.SQLITE_DBSTATUS_CACHE_USED;
  public static final int DBSTATUS_SCHEMA_USED = CApi.SQLITE_DBSTATUS_SCHEMA_USED;
  public static final int DBSTATUS_STMT_USED = CApi.SQLITE_DBSTATUS_STMT_USED;
  public static final int DBSTATUS_LOOKASIDE_HIT = CApi.SQLITE_DBSTATUS_LOOKASIDE_HIT;
  public static final int DBSTATUS_LOOKASIDE_MISS_SIZE = CApi.SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE;
  public static final int DBSTATUS_LOOKASIDE_MISS_FULL = CApi.SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL;
  public static final int DBSTATUS_CACHE_HIT = CApi.SQLITE_DBSTATUS_CACHE_HIT;
  public static final int DBSTATUS_CACHE_MISS = CApi.SQLITE_DBSTATUS_CACHE_MISS;
  public static final int DBSTATUS_CACHE_WRITE = CApi.SQLITE_DBSTATUS_CACHE_WRITE;
  public static final int DBSTATUS_DEFERRED_FKS = CApi.SQLITE_DBSTATUS_DEFERRED_FKS;
  public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED;
  public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL;

  // Limits
  public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH;
  public static final int LIMIT_SQL_LENGTH = CApi.SQLITE_LIMIT_SQL_LENGTH;
  public static final int LIMIT_COLUMN = CApi.SQLITE_LIMIT_COLUMN;
  public static final int LIMIT_EXPR_DEPTH = CApi.SQLITE_LIMIT_EXPR_DEPTH;
  public static final int LIMIT_COMPOUND_SELECT = CApi.SQLITE_LIMIT_COMPOUND_SELECT;
  public static final int LIMIT_VDBE_OP = CApi.SQLITE_LIMIT_VDBE_OP;
  public static final int LIMIT_FUNCTION_ARG = CApi.SQLITE_LIMIT_FUNCTION_ARG;
  public static final int LIMIT_ATTACHED = CApi.SQLITE_LIMIT_ATTACHED;
  public static final int LIMIT_LIKE_PATTERN_LENGTH = CApi.SQLITE_LIMIT_LIKE_PATTERN_LENGTH;
  public static final int LIMIT_VARIABLE_NUMBER = CApi.SQLITE_LIMIT_VARIABLE_NUMBER;
  public static final int LIMIT_TRIGGER_DEPTH = CApi.SQLITE_LIMIT_TRIGGER_DEPTH;
  public static final int LIMIT_WORKER_THREADS = CApi.SQLITE_LIMIT_WORKER_THREADS;

  // sqlite3_prepare_v3() flags
  public static final int PREPARE_PERSISTENT = CApi.SQLITE_PREPARE_PERSISTENT;
  public static final int PREPARE_NO_VTAB = CApi.SQLITE_PREPARE_NO_VTAB;

  // sqlite3_trace_v2() flags
  public static final int TRACE_STMT = CApi.SQLITE_TRACE_STMT;
  public static final int TRACE_PROFILE = CApi.SQLITE_TRACE_PROFILE;
  public static final int TRACE_ROW = CApi.SQLITE_TRACE_ROW;
  public static final int TRACE_CLOSE = CApi.SQLITE_TRACE_CLOSE;
  public static final int TRACE_ALL = TRACE_STMT | TRACE_PROFILE | TRACE_ROW | TRACE_CLOSE;

  // sqlite3_db_config() ops
  public static final int DBCONFIG_ENABLE_FKEY = CApi.SQLITE_DBCONFIG_ENABLE_FKEY;
  public static final int DBCONFIG_ENABLE_TRIGGER = CApi.SQLITE_DBCONFIG_ENABLE_TRIGGER;
  public static final int DBCONFIG_ENABLE_FTS3_TOKENIZER = CApi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER;
  public static final int DBCONFIG_ENABLE_LOAD_EXTENSION = CApi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION;
  public static final int DBCONFIG_NO_CKPT_ON_CLOSE = CApi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE;
  public static final int DBCONFIG_ENABLE_QPSG = CApi.SQLITE_DBCONFIG_ENABLE_QPSG;
  public static final int DBCONFIG_TRIGGER_EQP = CApi.SQLITE_DBCONFIG_TRIGGER_EQP;
  public static final int DBCONFIG_RESET_DATABASE = CApi.SQLITE_DBCONFIG_RESET_DATABASE;
  public static final int DBCONFIG_DEFENSIVE = CApi.SQLITE_DBCONFIG_DEFENSIVE;
  public static final int DBCONFIG_WRITABLE_SCHEMA = CApi.SQLITE_DBCONFIG_WRITABLE_SCHEMA;
  public static final int DBCONFIG_LEGACY_ALTER_TABLE = CApi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE;
  public static final int DBCONFIG_DQS_DML = CApi.SQLITE_DBCONFIG_DQS_DML;
  public static final int DBCONFIG_DQS_DDL = CApi.SQLITE_DBCONFIG_DQS_DDL;
  public static final int DBCONFIG_ENABLE_VIEW = CApi.SQLITE_DBCONFIG_ENABLE_VIEW;
  public static final int DBCONFIG_LEGACY_FILE_FORMAT = CApi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT;
  public static final int DBCONFIG_TRUSTED_SCHEMA = CApi.SQLITE_DBCONFIG_TRUSTED_SCHEMA;
  public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS;
  public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER;

  // sqlite3_config() ops
  public static final int CONFIG_SINGLETHREAD = CApi.SQLITE_CONFIG_SINGLETHREAD;
  public static final int CONFIG_MULTITHREAD = CApi.SQLITE_CONFIG_MULTITHREAD;
  public static final int CONFIG_SERIALIZED = CApi.SQLITE_CONFIG_SERIALIZED;

  // Encodings
  public static final int UTF8 = CApi.SQLITE_UTF8;
  public static final int UTF16 = CApi.SQLITE_UTF16;
  public static final int UTF16LE = CApi.SQLITE_UTF16LE;
  public static final int UTF16BE = CApi.SQLITE_UTF16BE;
  /* We elide the UTF16_ALIGNED from this interface because it
     is irrelevant for the Java interface. */

  // SQL data type IDs
  public static final int INTEGER = CApi.SQLITE_INTEGER;
  public static final int FLOAT = CApi.SQLITE_FLOAT;
  public static final int TEXT = CApi.SQLITE_TEXT;
  public static final int BLOB = CApi.SQLITE_BLOB;
  public static final int NULL = CApi.SQLITE_NULL;

  // Authorizer codes.
  public static final int DENY = CApi.SQLITE_DENY;
  public static final int IGNORE = CApi.SQLITE_IGNORE;
  public static final int CREATE_INDEX = CApi.SQLITE_CREATE_INDEX;
  public static final int CREATE_TABLE = CApi.SQLITE_CREATE_TABLE;
  public static final int CREATE_TEMP_INDEX = CApi.SQLITE_CREATE_TEMP_INDEX;
  public static final int CREATE_TEMP_TABLE = CApi.SQLITE_CREATE_TEMP_TABLE;
  public static final int CREATE_TEMP_TRIGGER = CApi.SQLITE_CREATE_TEMP_TRIGGER;
  public static final int CREATE_TEMP_VIEW = CApi.SQLITE_CREATE_TEMP_VIEW;
  public static final int CREATE_TRIGGER = CApi.SQLITE_CREATE_TRIGGER;
  public static final int CREATE_VIEW = CApi.SQLITE_CREATE_VIEW;
  public static final int DELETE = CApi.SQLITE_DELETE;
  public static final int DROP_INDEX = CApi.SQLITE_DROP_INDEX;
  public static final int DROP_TABLE = CApi.SQLITE_DROP_TABLE;
  public static final int DROP_TEMP_INDEX = CApi.SQLITE_DROP_TEMP_INDEX;
  public static final int DROP_TEMP_TABLE = CApi.SQLITE_DROP_TEMP_TABLE;
  public static final int DROP_TEMP_TRIGGER = CApi.SQLITE_DROP_TEMP_TRIGGER;
  public static final int DROP_TEMP_VIEW = CApi.SQLITE_DROP_TEMP_VIEW;
  public static final int DROP_TRIGGER = CApi.SQLITE_DROP_TRIGGER;
  public static final int DROP_VIEW = CApi.SQLITE_DROP_VIEW;
  public static final int INSERT = CApi.SQLITE_INSERT;
  public static final int PRAGMA = CApi.SQLITE_PRAGMA;
  public static final int READ = CApi.SQLITE_READ;
  public static final int SELECT = CApi.SQLITE_SELECT;
  public static final int TRANSACTION = CApi.SQLITE_TRANSACTION;
  public static final int UPDATE = CApi.SQLITE_UPDATE;
  public static final int ATTACH = CApi.SQLITE_ATTACH;
  public static final int DETACH = CApi.SQLITE_DETACH;
  public static final int ALTER_TABLE = CApi.SQLITE_ALTER_TABLE;
  public static final int REINDEX = CApi.SQLITE_REINDEX;
  public static final int ANALYZE = CApi.SQLITE_ANALYZE;
  public static final int CREATE_VTABLE = CApi.SQLITE_CREATE_VTABLE;
  public static final int DROP_VTABLE = CApi.SQLITE_DROP_VTABLE;
  public static final int FUNCTION = CApi.SQLITE_FUNCTION;
  public static final int SAVEPOINT = CApi.SQLITE_SAVEPOINT;
  public static final int RECURSIVE = CApi.SQLITE_RECURSIVE;

  //! Used only by the open() factory functions.
  private Sqlite(sqlite3 db){
    this.db = db;
  }

  /** Maps org.sqlite.jni.capi.sqlite3 to Sqlite instances. */
  private static final java.util.Map<org.sqlite.jni.capi.sqlite3, Sqlite> nativeToWrapper
    = new java.util.HashMap<>();


  /**
     When any given thread is done using the SQLite library, calling
     this will free up any native-side resources which may be
     associated specifically with that thread. This is not strictly
     necessary, in particular in applications which only use SQLite
     from a single thread, but may help free some otherwise errant
     resources.

     Calling into SQLite from a given thread after this has been
     called in that thread is harmless. The library will simply start
     to re-cache certain state for that thread.

     Contrariwise, failing to call this will effectively leak a small
     amount of cached state for the thread, which may add up to
     significant amounts if the application uses SQLite from many
     threads.

     This must never be called while actively using SQLite from this
     thread, e.g. from within a query loop or a callback which is
     operating on behalf of the library.
  */
  static void uncacheThread(){
    CApi.sqlite3_java_uncache_thread();
  }

  /**
     Returns the Sqlite object associated with the given sqlite3
     object, or null if there is no such mapping.
  */
  static Sqlite fromNative(sqlite3 low){
    synchronized(nativeToWrapper){
      return nativeToWrapper.get(low);
    }
  }

  /**
     Returns a newly-opened db connection or throws SqliteException if
     opening fails. All arguments are as documented for
     sqlite3_open_v2().

     Design question: do we want static factory functions or should
     this be reformulated as a constructor?
  */
  public static Sqlite open(String filename, int flags, String vfsName){
    final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
    final int rc = sqlite3_open_v2(filename, out, flags, vfsName);
    final int rc = CApi.sqlite3_open_v2(filename, out, flags, vfsName);
    final sqlite3 n = out.take();
    if( 0!=rc ){
      if( null==n ) throw new SqliteException(rc);
      final SqliteException ex = new SqliteException(n);
      n.close();
      throw ex;
    }
    final Sqlite rv = new Sqlite(n);
    synchronized(nativeToWrapper){
      nativeToWrapper.put(n, rv);
    }
    runAutoExtensions(rv);
    return new Sqlite(n);
    return rv;
  }

  public static Sqlite open(String filename, int flags){
    return open(filename, flags, null);
  }

  public static Sqlite open(String filename){
    return open(filename, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, null);
    return open(filename, OPEN_READWRITE|OPEN_CREATE, null);
  }

  public static String libVersion(){
    return CApi.sqlite3_libversion();
  }

  public static int libVersionNumber(){
    return CApi.sqlite3_libversion_number();
  }

  public static String libSourceId(){
    return CApi.sqlite3_sourceid();
  }

  /**
     Returns the value of the native library's build-time value of the
     SQLITE_THREADSAFE build option.
  */
  public static int libThreadsafe(){
    return CApi.sqlite3_threadsafe();
  }

  /**
     Analog to sqlite3_compileoption_get().
  */
  public static String compileOptionGet(int n){
    return CApi.sqlite3_compileoption_get(n);
  }

  /**
     Analog to sqlite3_compileoption_used().
  */
  public static boolean compileOptionUsed(String optName){
    return CApi.sqlite3_compileoption_used(optName);
  }

  private static boolean hasNormalizeSql =
    compileOptionUsed("ENABLE_NORMALIZE");

  private static boolean hasSqlLog =
    compileOptionUsed("ENABLE_SQLLOG");

  /**
     Throws UnsupportedOperationException if check is false.
     flag is expected to be the name of an SQLITE_ENABLE_...
     build flag.
  */
  private static void checkSupported(boolean check, String flag){
    if( !check ){
      throw new UnsupportedOperationException(
        "Library was built without "+flag
      );
    }
  }

  /**
     Analog to sqlite3_complete().
  */
  public static boolean isCompleteStatement(String sql){
    switch(CApi.sqlite3_complete(sql)){
      case 0: return false;
      case CApi.SQLITE_MISUSE:
        throw new IllegalArgumentException("Input may not be null.");
      case CApi.SQLITE_NOMEM:
        throw new OutOfMemoryError();
      default:
        return true;
    }
  }

  public static int keywordCount(){
    return CApi.sqlite3_keyword_count();
  }

  public static boolean keywordCheck(String word){
    return CApi.sqlite3_keyword_check(word);
  }

  public static String keywordName(int index){
    return CApi.sqlite3_keyword_name(index);
  }

  public static boolean strglob(String glob, String txt){
    return 0==CApi.sqlite3_strglob(glob, txt);
  }

  public static boolean strlike(String glob, String txt, char escChar){
    return 0==CApi.sqlite3_strlike(glob, txt, escChar);
  }

  /**
     Output object for use with status() and libStatus().
  */
  public static final class Status {
    /** The current value for the requested status() or libStatus() metric. */
    long current;
    /** The peak value for the requested status() or libStatus() metric. */
    long peak;
  };

  /**
     As per sqlite3_status64(), but returns its current and high-water
     results as a Status object. Throws if the first argument is
     not one of the STATUS_... constants.
  */
  public static Status libStatus(int op, boolean resetStats){
    org.sqlite.jni.capi.OutputPointer.Int64 pCurrent =
      new org.sqlite.jni.capi.OutputPointer.Int64();
    org.sqlite.jni.capi.OutputPointer.Int64 pHighwater =
      new org.sqlite.jni.capi.OutputPointer.Int64();
    checkRcStatic( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) );
    final Status s = new Status();
    s.current = pCurrent.value;
    s.peak = pHighwater.value;
    return s;
  }

  /**
     As per sqlite3_db_status(), but returns its current and
     high-water results as a Status object. Throws if the first
     argument is not one of the DBSTATUS_... constants or on any other
     misuse.
  */
  public Status status(int op, boolean resetStats){
    org.sqlite.jni.capi.OutputPointer.Int32 pCurrent =
      new org.sqlite.jni.capi.OutputPointer.Int32();
    org.sqlite.jni.capi.OutputPointer.Int32 pHighwater =
      new org.sqlite.jni.capi.OutputPointer.Int32();
    checkRc( CApi.sqlite3_db_status(thisDb(), op, pCurrent, pHighwater, resetStats) );
    final Status s = new Status();
    s.current = pCurrent.value;
    s.peak = pHighwater.value;
    return s;
  }

  @Override public void close(){
    if(null!=this.db){
      synchronized(nativeToWrapper){
        nativeToWrapper.remove(this.db);
      }
      this.db.close();
      this.db = null;
    }
  }

  /**
     Returns this object's underlying native db handle, or null if
     this instance has been closed. This is very specifically not
     public.
  */
  sqlite3 nativeHandle(){ return this.db; }

  private sqlite3 affirmOpen(){
  private sqlite3 thisDb(){
    if( null==db || 0==db.getNativePointer() ){
      throw new IllegalArgumentException("This database instance is closed.");
    }
    return this.db;
  }

  // private byte[] stringToUtf8(String s){
  //   return s==null ? null : s.getBytes(StandardCharsets.UTF_8);
  // }

  /**
     If rc!=0, throws an SqliteException. If this db is currently
     opened and has non-0 sqlite3_errcode(), the error state is
     extracted from it, else only the string form of rc is used. It is
     the caller's responsibility to filter out non-error codes such as
     SQLITE_ROW and SQLITE_DONE before calling this.

     As a special case, if rc is SQLITE_NOMEM, an OutOfMemoryError is
     thrown.
  */
  private void affirmRcOk(int rc){
  private void checkRc(int rc){
    if( 0!=rc ){
      if( CApi.SQLITE_NOMEM==rc ){
        throw new OutOfMemoryError();
      }else if( null==db || 0==CApi.sqlite3_errcode(db) ){
        throw new SqliteException(rc);
      }else{
      throw new SqliteException(db);
        throw new SqliteException(db);
      }
    }
  }

  /**
     Like checkRc() but behaves as if that function were
     called with a null db object.
  */
  private static void checkRcStatic(int rc){
    if( 0!=rc ){
      if( CApi.SQLITE_NOMEM==rc ){
        throw new OutOfMemoryError();
      }else{
        throw new SqliteException(rc);
      }
    }
  }

  /**
     Toggles the use of extended result codes on or off. By default
     they are turned off, but they can be enabled by default by
     including the OPEN_EXRESCODE flag when opening a database.

     Because this API reports db-side errors using exceptions,
     enabling this may change the values returned by
     SqliteException.errcode().
  */
  public void useExtendedResultCodes(boolean on){
    checkRc( CApi.sqlite3_extended_result_codes(thisDb(), on) );
  }

  /**
     Analog to sqlite3_prepare_v3(), this prepares the first SQL
     statement from the given input string and returns it as a
     Stmt. It throws an SqliteException if preparation fails or an
     IllegalArgumentException if the input is empty (e.g. contains
     only comments or whitespace).

     The first argument must be SQL input in UTF-8 encoding.

     prepFlags must be 0 or a bitmask of the PREPARE_... constants.

     For processing multiple statements from a single input, use
     prepareMulti().

     Design note: though the C-level API succeeds with a null
     statement object for empty inputs, that approach is cumbersome to
     use in higher-level APIs because every prepared statement has to
     be checked for null before using it.
  */
  public Stmt prepare(byte utf8Sql[], int prepFlags){
    final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
    final int rc = CApi.sqlite3_prepare_v3(thisDb(), utf8Sql, prepFlags, out);
    checkRc(rc);
    final sqlite3_stmt q = out.take();
    if( null==q ){
      /* The C-level API treats input which is devoid of SQL
         statements (e.g. all comments or an empty string) as success
         but returns a NULL sqlite3_stmt object. In higher-level APIs,
         wrapping a "successful NULL" object that way is tedious to
         use because it forces clients and/or wrapper-level code to
         check for that unusual case. In practice, higher-level
         bindings are generally better-served by treating empty SQL
         input as an error. */
      throw new IllegalArgumentException("Input contains no SQL statements.");
    }
    return new Stmt(this, q);
  }

  /**
     Equivalent to prepare(X, prepFlags), where X is
     sql.getBytes(StandardCharsets.UTF_8).
  */
  public Stmt prepare(String sql, int prepFlags){
    return prepare( sql.getBytes(StandardCharsets.UTF_8), prepFlags );
  }

  /**
     Equivalent to prepare(sql, 0).
  */
  public Stmt prepare(String sql){
    return prepare(sql, 0);
  }


  /**
     Callback type for use with prepareMulti().
  */
  public interface PrepareMulti {
    /**
       Gets passed a Stmt which it may handle in arbitrary ways.
       Ownership of st is passed to this function. It must throw on
       error.
    */
    void call(Sqlite.Stmt st);
  }

  /**
     A PrepareMulti implementation which calls another PrepareMulti
     object and then finalizes its statement.
  */
  public static class PrepareMultiFinalize implements PrepareMulti {
    private final PrepareMulti pm;
    /**
       Proxies the given PrepareMulti via this object's call() method.
    */
    public PrepareMultiFinalize(PrepareMulti proxy){
      this.pm = proxy;
    }
    /**
       Passes st to the call() method of the object this one proxies,
       then finalizes st, propagating any exceptions from call() after
       finalizing st.
    */
    @Override public void call(Stmt st){
      try{ pm.call(st); }
      finally{ st.finalizeStmt(); }
    }
  }

  /**
     Equivalent to prepareMulti(sql,0,visitor).
  */
  public void prepareMulti(String sql, PrepareMulti visitor){
    prepareMulti( sql, 0, visitor );
  }

  /**
     Equivallent to prepareMulti(X,prepFlags,visitor), where X is
     sql.getBytes(StandardCharsets.UTF_8).
  */
  public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){
    prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor);
  }

  /**
     A variant of prepare() which can handle multiple SQL statements
     in a single input string. For each statement in the given string,
     the statement is passed to visitor.call() a single time, passing
     ownership of the statement to that function. This function does
     not step() or close() statements - those operations are left to
     caller or the visitor function.

     Unlike prepare(), this function does not fail if the input
     contains only whitespace or SQL comments. In that case it is up
     to the caller to arrange for that to be an error (if desired).

     PrepareMultiFinalize offers a proxy which finalizes each
     statement after it is passed to another client-defined visitor.

     Be aware that certain legal SQL constructs may fail in the
     preparation phase, before the corresponding statement can be
     stepped. Most notably, authorizer checks which disallow access to
     something in a statement behave that way.
  */
  public void prepareMulti(byte sqlUtf8[], int prepFlags, PrepareMulti visitor){
    int pos = 0, n = 1;
    byte[] sqlChunk = sqlUtf8;
    final org.sqlite.jni.capi.OutputPointer.sqlite3_stmt outStmt =
      new org.sqlite.jni.capi.OutputPointer.sqlite3_stmt();
    final org.sqlite.jni.capi.OutputPointer.Int32 oTail =
      new org.sqlite.jni.capi.OutputPointer.Int32();
    while( pos < sqlChunk.length ){
      sqlite3_stmt stmt = null;
      if( pos>0 ){
        sqlChunk = java.util.Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length);
      }
      if( 0==sqlChunk.length ) break;
      checkRc(
        CApi.sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail)
      );
      pos = oTail.value;
      stmt = outStmt.take();
      if( null==stmt ){
        /* empty statement, e.g. only comments or whitespace, was parsed. */
        continue;
      }
      visitor.call(new Stmt(this, stmt));
    }
  }

  public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f){
    int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
                                           new SqlFunction.ScalarAdapter(f));
    if( 0!=rc ) throw new SqliteException(db);
  }

  public void createFunction(String name, int nArg, ScalarFunction f){
    this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);
  }

  public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f){
    int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
                                           new SqlFunction.AggregateAdapter(f));
    if( 0!=rc ) throw new SqliteException(db);
  }

  public void createFunction(String name, int nArg, AggregateFunction f){
    this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);
  }

  public void createFunction(String name, int nArg, int eTextRep, WindowFunction f){
    int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
                                          new SqlFunction.WindowAdapter(f));
    if( 0!=rc ) throw new SqliteException(db);
  }

  public void createFunction(String name, int nArg, WindowFunction f){
    this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);
  }

  public long changes(){
    return CApi.sqlite3_changes64(thisDb());
  }

  public long totalChanges(){
    return CApi.sqlite3_total_changes64(thisDb());
  }

  public long lastInsertRowId(){
    return CApi.sqlite3_last_insert_rowid(thisDb());
  }

  public void setLastInsertRowId(long rowId){
    CApi.sqlite3_set_last_insert_rowid(thisDb(), rowId);
  }

  public void interrupt(){
    CApi.sqlite3_interrupt(thisDb());
  }

  public boolean isInterrupted(){
    return CApi.sqlite3_is_interrupted(thisDb());
  }

  public boolean isAutoCommit(){
    return CApi.sqlite3_get_autocommit(thisDb());
  }

  /**
     Analog to sqlite3_txn_state(). Returns one of TXN_NONE, TXN_READ,
     or TXN_WRITE to denote this database's current transaction state
     for the given schema name (or the most restrictive state of any
     schema if zSchema is null).
  */
  public int transactionState(String zSchema){
    return CApi.sqlite3_txn_state(thisDb(), zSchema);
  }

  /**
     Analog to sqlite3_db_name(). Returns null if passed an unknown
     index.
  */
  public String dbName(int dbNdx){
    return CApi.sqlite3_db_name(thisDb(), dbNdx);
  }

  /**
     Analog to sqlite3_db_filename(). Returns null if passed an
     unknown db name.
  */
  public String dbFileName(String dbName){
    return CApi.sqlite3_db_filename(thisDb(), dbName);
  }

  /**
     Analog to sqlite3_db_config() for the call forms which take one
     of the boolean-type db configuration flags (namely the
     DBCONFIG_... constants defined in this class). On success it
     returns the result of that underlying call. Throws on error.
  */
  public boolean dbConfig(int op, boolean on){
    org.sqlite.jni.capi.OutputPointer.Int32 pOut =
      new org.sqlite.jni.capi.OutputPointer.Int32();
    checkRc( CApi.sqlite3_db_config(thisDb(), op, on ? 1 : 0, pOut) );
    return pOut.get()!=0;
  }

  /**
     Analog to the variant of sqlite3_db_config() for configuring the
     SQLITE_DBCONFIG_MAINDBNAME option. Throws on error.
  */
  public void setMainDbName(String name){
    checkRc(
      CApi.sqlite3_db_config(thisDb(), CApi.SQLITE_DBCONFIG_MAINDBNAME,
                             name)
    );
  }

  /**
     Analog to sqlite3_db_readonly() but throws an SqliteException
     with result code SQLITE_NOTFOUND if given an unknown database
     name.
  */
  public boolean readOnly(String dbName){
    final int rc = CApi.sqlite3_db_readonly(thisDb(), dbName);
    if( 0==rc ) return false;
    else if( rc>0 ) return true;
    throw new SqliteException(CApi.SQLITE_NOTFOUND);
  }

  /**
     Analog to sqlite3_db_release_memory().
  */
  public void releaseMemory(){
    CApi.sqlite3_db_release_memory(thisDb());
  }

  /**
     Analog to sqlite3_release_memory().
  */
  public static int libReleaseMemory(int n){
    return CApi.sqlite3_release_memory(n);
  }

  /**
     Analog to sqlite3_limit(). limitId must be one of the
     LIMIT_... constants.

     Returns the old limit for the given option. If newLimit is
     negative, it returns the old limit without modifying the limit.

     If sqlite3_limit() returns a negative value, this function throws
     an SqliteException with the SQLITE_RANGE result code but no
     further error info (because that case does not qualify as a
     db-level error). Such errors may indicate an invalid argument
     value or an invalid range for newLimit (the underlying function
     does not differentiate between those).
  */
  public int limit(int limitId, int newLimit){
    final int rc = CApi.sqlite3_limit(thisDb(), limitId, newLimit);
    if( rc<0 ){
      throw new SqliteException(CApi.SQLITE_RANGE);
    }
    return rc;
  }

  /**
     Analog to sqlite3_errstr().
  */
  static String errstr(int resultCode){
    return CApi.sqlite3_errstr(resultCode);
  }

  /**
     A wrapper object for use with tableColumnMetadata().  They are
     created and populated only via that interface.
  */
  public final class TableColumnMetadata {
    Boolean pNotNull = null;
    Boolean pPrimaryKey = null;
    Boolean pAutoinc = null;
    String pzCollSeq = null;
    String pzDataType = null;

    private TableColumnMetadata(){}

    public String getDataType(){ return pzDataType; }
    public String getCollation(){ return pzCollSeq; }
    public boolean isNotNull(){ return pNotNull; }
    public boolean isPrimaryKey(){ return pPrimaryKey; }
    public boolean isAutoincrement(){ return pAutoinc; }
  }

  /**
     Returns data about a database, table, and (optionally) column
     (which may be null), as per sqlite3_table_column_metadata().
     Throws if passed invalid arguments, else returns the result as a
     new TableColumnMetadata object.
  */
  TableColumnMetadata tableColumnMetadata(
    String zDbName, String zTableName, String zColumnName
  ){
    org.sqlite.jni.capi.OutputPointer.String pzDataType
      = new org.sqlite.jni.capi.OutputPointer.String();
    org.sqlite.jni.capi.OutputPointer.String pzCollSeq
      = new org.sqlite.jni.capi.OutputPointer.String();
    org.sqlite.jni.capi.OutputPointer.Bool pNotNull
      = new org.sqlite.jni.capi.OutputPointer.Bool();
    org.sqlite.jni.capi.OutputPointer.Bool pPrimaryKey
      = new org.sqlite.jni.capi.OutputPointer.Bool();
    org.sqlite.jni.capi.OutputPointer.Bool pAutoinc
      = new org.sqlite.jni.capi.OutputPointer.Bool();
    final int rc = CApi.sqlite3_table_column_metadata(
      thisDb(), zDbName, zTableName, zColumnName,
      pzDataType, pzCollSeq, pNotNull, pPrimaryKey, pAutoinc
    );
    checkRc(rc);
    TableColumnMetadata rv = new TableColumnMetadata();
    rv.pzDataType = pzDataType.value;
    rv.pzCollSeq = pzCollSeq.value;
    rv.pNotNull = pNotNull.value;
    rv.pPrimaryKey = pPrimaryKey.value;
    rv.pAutoinc = pAutoinc.value;
    return rv;
  }

  public interface TraceCallback {
    /**
       Called by sqlite3 for various tracing operations, as per
       sqlite3_trace_v2(). Note that this interface elides the 2nd
       argument to the native trace callback, as that role is better
       filled by instance-local state.

       <p>These callbacks may throw, in which case their exceptions are
       converted to C-level error information.

       <p>The 2nd argument to this function, if non-null, will be a an
       Sqlite or Sqlite.Stmt object, depending on the first argument
       (see below).

       <p>The final argument to this function is the "X" argument
       documented for sqlite3_trace() and sqlite3_trace_v2(). Its type
       depends on value of the first argument:

       <p>- SQLITE_TRACE_STMT: pNative is a Sqlite.Stmt. pX is a String
       containing the prepared SQL.

       <p>- SQLITE_TRACE_PROFILE: pNative is a sqlite3_stmt. pX is a Long
       holding an approximate number of nanoseconds the statement took
       to run.

       <p>- SQLITE_TRACE_ROW: pNative is a sqlite3_stmt. pX is null.

       <p>- SQLITE_TRACE_CLOSE: pNative is a sqlite3. pX is null.
    */
    void call(int traceFlag, Object pNative, Object pX);
  }

  /**
     Analog to sqlite3_trace_v2(). traceMask must be a mask of the
     TRACE_...  constants. Pass a null callback to remove tracing.

     Throws on error.
  */
  public void trace(int traceMask, TraceCallback callback){
    final Sqlite self = this;
    final org.sqlite.jni.capi.TraceV2Callback tc =
      (null==callback) ? null : new org.sqlite.jni.capi.TraceV2Callback(){
          @SuppressWarnings("unchecked")
          @Override public int call(int flag, Object pNative, Object pX){
            switch(flag){
              case TRACE_ROW:
              case TRACE_PROFILE:
              case TRACE_STMT:
                callback.call(flag, Sqlite.Stmt.fromNative((sqlite3_stmt)pNative), pX);
                break;
              case TRACE_CLOSE:
                callback.call(flag, self, pX);
                break;
            }
            return 0;
          }
        };
    checkRc( CApi.sqlite3_trace_v2(thisDb(), traceMask, tc) );
  };

  /**
     Corresponds to the sqlite3_stmt class. Use Sqlite.prepare() to
     create new instances.
  */
  public final class Stmt implements AutoCloseable {
  public static final class Stmt implements AutoCloseable {
    private Sqlite _db = null;
    private sqlite3_stmt stmt = null;

    /** Only called by the prepare() factory functions. */
    Stmt(Sqlite db, sqlite3_stmt stmt){
      this._db = db;
      this.stmt = stmt;
      synchronized(nativeToWrapper){
        nativeToWrapper.put(this.stmt, this);
      }
    }

    sqlite3_stmt nativeHandle(){
      return stmt;
    }

    /** Maps org.sqlite.jni.capi.sqlite3_stmt to Stmt instances. */
    private static final java.util.Map<org.sqlite.jni.capi.sqlite3_stmt, Stmt> nativeToWrapper
      = new java.util.HashMap<>();

    /**
       Returns the Stmt object associated with the given sqlite3_stmt
       object, or null if there is no such mapping.
    */
    static Stmt fromNative(sqlite3_stmt low){
      synchronized(nativeToWrapper){
        return nativeToWrapper.get(low);
      }
    }

    /**
       If this statement is still opened, its low-level handle is
       returned, else an IllegalArgumentException is thrown.
    */
    private sqlite3_stmt affirmOpen(){
    private sqlite3_stmt thisStmt(){
      if( null==stmt || 0==stmt.getNativePointer() ){
        throw new IllegalArgumentException("This Stmt has been finalized.");
      }
      return stmt;
    }

    /** Throws if n is out of range of this statement's result column
        count. Intended to be used by the columnXyz() methods. */
    private sqlite3_stmt checkColIndex(int n){
      if(n<0 || n>=columnCount()){
        throw new IllegalArgumentException("Column index "+n+" is out of range.");
      }
      return thisStmt();
    }

    /**
       Corresponds to sqlite3_finalize(), but we cannot override the
       name finalize() here because this one requires a different
       signature. It does not throw on error here because "destructors
       do not throw." If it returns non-0, the object is still
       finalized.
       finalized, but the result code is an indication that something
       went wrong in a prior call into the statement's API, as
       documented for sqlite3_finalize().
    */
    public int finalizeStmt(){
      int rc = 0;
      if( null!=stmt ){
        synchronized(nativeToWrapper){
          nativeToWrapper.remove(this.stmt);
        }
        sqlite3_finalize(stmt);
        CApi.sqlite3_finalize(stmt);
        stmt = null;
        _db = null;
      }
      return rc;
    }

    @Override public void close(){
      finalizeStmt();
    }

    /**
       Throws if rc is any value other than 0, SQLITE_ROW, or
       SQLITE_DONE, else returns rc.
       SQLITE_DONE, else returns rc. Error state for the exception is
       extracted from this statement object (if it's opened) or the
       string form of rc.
    */
    private int checkRc(int rc){
      switch(rc){
        case 0:
        case SQLITE_ROW:
        case SQLITE_DONE: return rc;
        case CApi.SQLITE_ROW:
        case CApi.SQLITE_DONE: return rc;
        default:
          if( null==stmt ) throw new SqliteException(rc);
          throw new SqliteException(this);
          else throw new SqliteException(this);
      }
    }

    /**
       Works like sqlite3_step() but returns true for SQLITE_ROW,
       false for SQLITE_DONE, and throws SqliteException for any other
       result.
    */
    public boolean step(){
      switch(checkRc(CApi.sqlite3_step(thisStmt()))){
        case CApi.SQLITE_ROW: return true;
        case CApi.SQLITE_DONE: return false;
        default:
          throw new IllegalStateException(
            "This \"cannot happen\": all possible result codes were checked already."
          );
      }
    }

    /**
       Works like sqlite3_step() but throws SqliteException for any
       result other than 0, SQLITE_ROW, or SQLITE_DONE.
       Works like sqlite3_step(), returning the same result codes as
       that function unless throwOnError is true, in which case it
       will throw an SqliteException for any result codes other than
       Sqlite.ROW or Sqlite.DONE.

       The utility of this overload over the no-argument one is the
       ability to handle BUSY and LOCKED errors more easily.
    */
    public int step(){
      return checkRc(sqlite3_step(affirmOpen()));
    public int step(boolean throwOnError){
      final int rc = (null==stmt)
              ? Sqlite.MISUSE
              : CApi.sqlite3_step(stmt);
      return throwOnError ? checkRc(rc) : rc;
    }

    /**
       Returns the Sqlite which prepared this statement, or null if
       this statement has been finalized.
    */
    public Sqlite db(){ return this._db; }
    public Sqlite getDb(){ return this._db; }

    /**
       Works like sqlite3_reset() but throws on error.
    */
    public void reset(){
      checkRc(sqlite3_reset(affirmOpen()));
      checkRc(CApi.sqlite3_reset(thisStmt()));
    }

    public boolean isBusy(){
      return CApi.sqlite3_stmt_busy(thisStmt());
    }

    public boolean isReadOnly(){
      return CApi.sqlite3_stmt_readonly(thisStmt());
    }

    public String sql(){
      return CApi.sqlite3_sql(thisStmt());
    }

    public String expandedSql(){
      return CApi.sqlite3_expanded_sql(thisStmt());
    }

    /**
       Analog to sqlite3_stmt_explain() but throws if op is invalid.
    */
    public void explain(int op){
      checkRc(CApi.sqlite3_stmt_explain(thisStmt(), op));
    }

    /**
       Analog to sqlite3_stmt_isexplain().
    */
    public int isExplain(){
      return CApi.sqlite3_stmt_isexplain(thisStmt());
    }

    /**
       Analog to sqlite3_normalized_sql(), but throws
       UnsupportedOperationException if the library was built without
       the SQLITE_ENABLE_NORMALIZE flag.
    */
    public String normalizedSql(){
      Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_NORMALIZE");
      return CApi.sqlite3_normalized_sql(thisStmt());
    }

    public void clearBindings(){
      sqlite3_clear_bindings( affirmOpen() );
      CApi.sqlite3_clear_bindings( thisStmt() );
    }
    public void bindInt(int ndx, int val){
      checkRc(CApi.sqlite3_bind_int(thisStmt(), ndx, val));
  }


  /**
     prepare() TODOs include:

     - overloads taking byte[] and ByteBuffer.
    }
    public void bindInt64(int ndx, long val){
      checkRc(CApi.sqlite3_bind_int64(thisStmt(), ndx, val));
    }
    public void bindDouble(int ndx, double val){
      checkRc(CApi.sqlite3_bind_double(thisStmt(), ndx, val));
    }
    public void bindObject(int ndx, Object o){
      checkRc(CApi.sqlite3_bind_java_object(thisStmt(), ndx, o));
    }
    public void bindNull(int ndx){
      checkRc(CApi.sqlite3_bind_null(thisStmt(), ndx));
    }
    public int bindParameterCount(){
      return CApi.sqlite3_bind_parameter_count(thisStmt());
    }
    public int bindParameterIndex(String paramName){
      return CApi.sqlite3_bind_parameter_index(thisStmt(), paramName);
    }
    public String bindParameterName(int ndx){
      return CApi.sqlite3_bind_parameter_name(thisStmt(), ndx);
    }
    public void bindText(int ndx, byte[] utf8){
      checkRc(CApi.sqlite3_bind_text(thisStmt(), ndx, utf8));
    }
    public void bindText(int ndx, String asUtf8){
      checkRc(CApi.sqlite3_bind_text(thisStmt(), ndx, asUtf8));
    }
    public void bindText16(int ndx, byte[] utf16){
      checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, utf16));
    }
    public void bindText16(int ndx, String asUtf16){
      checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, asUtf16));
    }
    public void bindZeroBlob(int ndx, int n){
      checkRc(CApi.sqlite3_bind_zeroblob(thisStmt(), ndx, n));
    }
    public void bindBlob(int ndx, byte[] bytes){
      checkRc(CApi.sqlite3_bind_blob(thisStmt(), ndx, bytes));
    }

    public byte[] columnBlob(int ndx){
      return CApi.sqlite3_column_blob( checkColIndex(ndx), ndx );
    }
    public byte[] columnText(int ndx){
      return CApi.sqlite3_column_text( checkColIndex(ndx), ndx );
    }
    public String columnText16(int ndx){
      return CApi.sqlite3_column_text16( checkColIndex(ndx), ndx );
    }
    public int columnBytes(int ndx){
      return CApi.sqlite3_column_bytes( checkColIndex(ndx), ndx );
    }
    public int columnBytes16(int ndx){
      return CApi.sqlite3_column_bytes16( checkColIndex(ndx), ndx );
    }
    public int columnInt(int ndx){
      return CApi.sqlite3_column_int( checkColIndex(ndx), ndx );
    }
    public long columnInt64(int ndx){
      return CApi.sqlite3_column_int64( checkColIndex(ndx), ndx );
    }
    public double columnDouble(int ndx){
      return CApi.sqlite3_column_double( checkColIndex(ndx), ndx );
    }
    public int columnType(int ndx){
      return CApi.sqlite3_column_type( checkColIndex(ndx), ndx );
    }
    public String columnDeclType(int ndx){
      return CApi.sqlite3_column_decltype( checkColIndex(ndx), ndx );
    }
    /**
       Analog to sqlite3_column_count() but throws if this statement
       has been finalized.
    */
    public int columnCount(){
      /* We cannot reliably cache the column count in a class
         member because an ALTER TABLE from a separate statement
         can invalidate that count and we have no way, short of
         installing a COMMIT handler or the like, of knowing when
         to re-read it. We cannot install such a handler without
         interfering with a client's ability to do so. */
      return CApi.sqlite3_column_count(thisStmt());
    }
    public int columnDataCount(){
      return CApi.sqlite3_data_count( thisStmt() );
    }
    public Object columnObject(int ndx){
      return CApi.sqlite3_column_java_object( checkColIndex(ndx), ndx );
    }
    public <T> T columnObject(int ndx, Class<T> type){
      return CApi.sqlite3_column_java_object( checkColIndex(ndx), ndx, type );
    }
    public String columnName(int ndx){
      return CApi.sqlite3_column_name( checkColIndex(ndx), ndx );
    }
    public String columnDatabaseName(int ndx){
      return CApi.sqlite3_column_database_name( checkColIndex(ndx), ndx );
    }
    public String columnOriginName(int ndx){
      return CApi.sqlite3_column_origin_name( checkColIndex(ndx), ndx );
    }
    public String columnTableName(int ndx){
      return CApi.sqlite3_column_table_name( checkColIndex(ndx), ndx );
    }
  } /* Stmt class */

  /**
     Interface for auto-extensions, as per the
     sqlite3_auto_extension() API.

     Design note: the chicken/egg timing of auto-extension execution
     requires that this feature be entirely re-implemented in Java
     because the C-level API has no access to the Sqlite type so
     cannot pass on an object of that type while the database is being
     opened.  One side effect of this reimplementation is that this
     class's list of auto-extensions is 100% independent of the
     C-level list so, e.g., clearAutoExtensions() will have no effect
     on auto-extensions added via the C-level API and databases opened
     from that level of API will not be passed to this level's
     AutoExtension instances.
  */
  public interface AutoExtension {
    public void call(Sqlite db);
  }
     - multi-statement processing, like CApi.sqlite3_prepare_multi()
     but using a callback specific to the higher-level Stmt class
     rather than the sqlite3_stmt class.

  private static final java.util.Set<AutoExtension> autoExtensions =
    new java.util.LinkedHashSet<>();

  /**
     Passes db to all auto-extensions. If any one of them throws,
     db.close() is called before the exception is propagated.
  */
  private static void runAutoExtensions(Sqlite db){
    AutoExtension list[];
    synchronized(autoExtensions){
      /* Avoid that modifications to the AutoExtension list from within
         auto-extensions affect this execution of this list. */
      list = autoExtensions.toArray(new AutoExtension[0]);
    }
    try {
      for( AutoExtension ax : list ) ax.call(db);
    }catch(Exception e){
      db.close();
      throw e;
    }
  }

  /**
     Analog to sqlite3_auto_extension(), adds the given object to the
     list of auto-extensions if it is not already in that list. The
     given object will be run as part of Sqlite.open(), and passed the
     being-opened database. If the extension throws then open() will
     fail.

     This API does not guaranty whether or not manipulations made to
     the auto-extension list from within auto-extension callbacks will
     affect the current traversal of the auto-extension list.  Whether
     or not they do is unspecified and subject to change between
     versions. e.g. if an AutoExtension calls addAutoExtension(),
     whether or not the new extension will be run on the being-opened
     database is undefined.

     Note that calling Sqlite.open() from an auto-extension will
     necessarily result in recursion loop and (eventually) a stack
     overflow.
  */
  public static void addAutoExtension( AutoExtension e ){
    if( null==e ){
      throw new IllegalArgumentException("AutoExtension may not be null.");
    }
    synchronized(autoExtensions){
      autoExtensions.add(e);
    }
  }

  /**
     Removes the given object from the auto-extension list if it is in
     that list, otherwise this has no side-effects beyond briefly
     locking that list.
  */
  public static void removeAutoExtension( AutoExtension e ){
    synchronized(autoExtensions){
      autoExtensions.remove(e);
    }
  }

  /**
     Removes all auto-extensions which were added via addAutoExtension().
  */
  public static void clearAutoExtensions(){
    synchronized(autoExtensions){
      autoExtensions.clear();
    }
  }

  /**
     Encapsulates state related to the sqlite3 backup API. Use
     Sqlite.initBackup() to create new instances.
  */
  public static final class Backup implements AutoCloseable {
    private sqlite3_backup b = null;
    private Sqlite dbTo = null;
    private Sqlite dbFrom = null;
  public Stmt prepare(String sql, int prepFlags){
    final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
    final int rc = sqlite3_prepare_v3(affirmOpen(), sql, prepFlags, out);
    affirmRcOk(rc);
    return new Stmt(this, out.take());
  }

  public Stmt prepare(String sql){
    return prepare(sql, 0);
  }

  public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f ){
    int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep,
                                           new SqlFunction.ScalarAdapter(f));
    if( 0!=rc ) throw new SqliteException(db);
  }

  public void createFunction(String name, int nArg, ScalarFunction f){
    this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);

    Backup(Sqlite dbDest, String schemaDest,Sqlite dbSrc, String schemaSrc){
      this.dbTo = dbDest;
      this.dbFrom = dbSrc;
      b = CApi.sqlite3_backup_init(dbDest.nativeHandle(), schemaDest,
                                   dbSrc.nativeHandle(), schemaSrc);
      if(null==b) toss();
    }

    private void toss(){
      int rc = CApi.sqlite3_errcode(dbTo.nativeHandle());
      if(0!=rc) throw new SqliteException(dbTo);
      rc = CApi.sqlite3_errcode(dbFrom.nativeHandle());
      if(0!=rc) throw new SqliteException(dbFrom);
      throw new SqliteException(CApi.SQLITE_ERROR);
    }

    private sqlite3_backup getNative(){
      if( null==b ) throw new IllegalStateException("This Backup is already closed.");
      return b;
    }
    /**
       If this backup is still active, this completes the backup and
       frees its native resources, otherwise it this is a no-op.
    */
    public void finish(){
      if( null!=b ){
        CApi.sqlite3_backup_finish(b);
        b = null;
        dbTo = null;
        dbFrom = null;
      }
    }

    /** Equivalent to finish(). */
    @Override public void close(){
      this.finish();
    }

    /**
       Analog to sqlite3_backup_step(). Returns 0 if stepping succeeds
       or, Sqlite.DONE if the end is reached, Sqlite.BUSY if one of
       the databases is busy, Sqlite.LOCKED if one of the databases is
       locked, and throws for any other result code or if this object
       has been closed. Note that BUSY and LOCKED are not necessarily
       permanent errors, so do not trigger an exception.
    */
    public int step(int pageCount){
      final int rc = CApi.sqlite3_backup_step(getNative(), pageCount);
      switch(rc){
        case 0:
        case Sqlite.DONE:
        case Sqlite.BUSY:
        case Sqlite.LOCKED:
          return rc;
        default:
          toss();
          return CApi.SQLITE_ERROR/*not reached*/;
      }
    }

    /**
       Analog to sqlite3_backup_pagecount().
    */
    public int pageCount(){
      return CApi.sqlite3_backup_pagecount(getNative());
    }

    /**
       Analog to sqlite3_backup_remaining().
    */
    public int remaining(){
      return CApi.sqlite3_backup_remaining(getNative());
    }
  }

  /**
     Analog to sqlite3_backup_init(). If schemaSrc is null, "main" is
     assumed. Throws if either this db or dbSrc (the source db) are
     not opened, if either of schemaDest or schemaSrc are null, or if
     the underlying call to sqlite3_backup_init() fails.

     The returned object must eventually be cleaned up by either
     arranging for it to be auto-closed (e.g. using
     try-with-resources) or by calling its finish() method.
  */
  public Backup initBackup(String schemaDest, Sqlite dbSrc, String schemaSrc){
    thisDb();
    dbSrc.thisDb();
    if( null==schemaSrc || null==schemaDest ){
      throw new IllegalArgumentException(
        "Neither the source nor destination schema name may be null."
      );
    }
    return new Backup(this, schemaDest, dbSrc, schemaSrc);
  }


  /**
     Callback type for use with createCollation().
   */
  public interface Collation {
    /**
       Called by the SQLite core to compare inputs. Implementations
       must compare its two arguments using memcmp(3) semantics.

       Warning: the SQLite core has no mechanism for reporting errors
       from custom collations and its workflow does not accommodate
       propagation of exceptions from callbacks. Any exceptions thrown
       from collations will be silently supressed and sorting results
       will be unpredictable.
    */
    int call(byte[] lhs, byte[] rhs);
  }

  /**
     Analog to sqlite3_create_collation().

     Throws if name is null or empty, c is null, or the encoding flag
     is invalid. The encoding must be one of the UTF8, UTF16, UTF16LE,
     or UTF16BE constants.
  */
  public void createCollation(String name, int encoding, Collation c){
    thisDb();
    if( null==name || 0==name.length()){
      throw new IllegalArgumentException("Collation name may not be null or empty.");
    }
    if( null==c ){
      throw new IllegalArgumentException("Collation may not be null.");
    }
    switch(encoding){
      case UTF8:
      case UTF16:
      case UTF16LE:
      case UTF16BE:
        break;
      default:
        throw new IllegalArgumentException("Invalid Collation encoding.");
    }
    checkRc(
      CApi.sqlite3_create_collation(
        thisDb(), name, encoding, new org.sqlite.jni.capi.CollationCallback(){
            @Override public int call(byte[] lhs, byte[] rhs){
              try{return c.call(lhs, rhs);}
              catch(Exception e){return 0;}
            }
            @Override public void xDestroy(){}
          }
      )
    );
  }

  /**
     Callback for use with onCollationNeeded().
  */
  public interface CollationNeeded {
    /**
       Must behave as documented for the callback for
       sqlite3_collation_needed().

       Warning: the C API has no mechanism for reporting or
       propagating errors from this callback, so any exceptions it
       throws are suppressed.
    */
    void call(Sqlite db, int encoding, String collationName);
  }

  /**
     Sets up the given object to be called by the SQLite core when it
     encounters a collation name which it does not know. Pass a null
     object to disconnect the object from the core. This replaces any
     existing collation-needed loader, or is a no-op if the given
     object is already registered. Throws if registering the loader
     fails.
  */
  public void onCollationNeeded( CollationNeeded cn ){
    org.sqlite.jni.capi.CollationNeededCallback cnc = null;
    if( null!=cn ){
      cnc = new org.sqlite.jni.capi.CollationNeededCallback(){
          @Override public void call(sqlite3 db, int encoding, String collationName){
            final Sqlite xdb = Sqlite.fromNative(db);
            if(null!=xdb) cn.call(xdb, encoding, collationName);
          }
        };
    }
    checkRc( CApi.sqlite3_collation_needed(thisDb(), cnc) );
  }

  /**
     Callback for use with busyHandler().
  */
  public interface BusyHandler {
    /**
       Must function as documented for the C-level
       sqlite3_busy_handler() callback argument, minus the (void*)
       argument the C-level function requires.

       If this function throws, it is translated to a database-level
       error.
    */
    int call(int n);
  }

  /**
     Analog to sqlite3_busy_timeout().
  */
  public void setBusyTimeout(int ms){
    checkRc(CApi.sqlite3_busy_timeout(thisDb(), ms));
  }

  /**
     Analog to sqlite3_busy_handler(). If b is null then any
     current handler is cleared.
  */
  public void setBusyHandler( BusyHandler b ){
    org.sqlite.jni.capi.BusyHandlerCallback bhc = null;
    if( null!=b ){
      bhc = new org.sqlite.jni.capi.BusyHandlerCallback(){
          @Override public int call(int n){
            return b.call(n);
          }
        };
    }
    checkRc( CApi.sqlite3_busy_handler(thisDb(), bhc) );
  }

  public interface CommitHook {
    /**
       Must behave as documented for the C-level sqlite3_commit_hook()
       callback. If it throws, the exception is translated into
       a db-level error.
    */
    int call();
  }

  /**
     A level of indirection to permit setCommitHook() to have similar
     semantics as the C API, returning the previous hook. The caveat
     is that if the low-level API is used to install a hook, it will
     have a different hook type than Sqlite.CommitHook so
     setCommitHook() will return null instead of that object.
  */
  private static class CommitHookProxy
    implements org.sqlite.jni.capi.CommitHookCallback {
    final CommitHook commitHook;
    CommitHookProxy(CommitHook ch){
      this.commitHook = ch;
    }
    @Override public int call(){
      return commitHook.call();
    }
  }

  /**
     Analog to sqlite3_commit_hook(). Returns the previous hook, if
     any (else null). Throws if this db is closed.

     Minor caveat: if a commit hook is set on this object's underlying
     db handle using the lower-level SQLite API, this function may
     return null when replacing it, despite there being a hook,
     because it will have a different callback type. So long as the
     handle is only manipulated via the high-level API, this caveat
     does not apply.
  */
  public CommitHook setCommitHook( CommitHook c ){
    CommitHookProxy chp = null;
    if( null!=c ){
      chp = new CommitHookProxy(c);
    }
    final org.sqlite.jni.capi.CommitHookCallback rv =
      CApi.sqlite3_commit_hook(thisDb(), chp);
    return (rv instanceof CommitHookProxy)
      ? ((CommitHookProxy)rv).commitHook
      : null;
  }


  public interface RollbackHook {
    /**
       Must behave as documented for the C-level sqlite3_rollback_hook()
       callback. If it throws, the exception is translated into
       a db-level error.
    */
    void call();
  }

  /**
     A level of indirection to permit setRollbackHook() to have similar
     semantics as the C API, returning the previous hook. The caveat
     is that if the low-level API is used to install a hook, it will
     have a different hook type than Sqlite.RollbackHook so
     setRollbackHook() will return null instead of that object.
  */
  private static class RollbackHookProxy
    implements org.sqlite.jni.capi.RollbackHookCallback {
    final RollbackHook rollbackHook;
    RollbackHookProxy(RollbackHook ch){
      this.rollbackHook = ch;
    }
    @Override public void call(){rollbackHook.call();}
  }

  /**
     Analog to sqlite3_rollback_hook(). Returns the previous hook, if
     any (else null). Throws if this db is closed.

     Minor caveat: if a rollback hook is set on this object's underlying
     db handle using the lower-level SQLite API, this function may
     return null when replacing it, despite there being a hook,
     because it will have a different callback type. So long as the
     handle is only manipulated via the high-level API, this caveat
     does not apply.
  */
  public RollbackHook setRollbackHook( RollbackHook c ){
    RollbackHookProxy chp = null;
    if( null!=c ){
      chp = new RollbackHookProxy(c);
    }
    final org.sqlite.jni.capi.RollbackHookCallback rv =
      CApi.sqlite3_rollback_hook(thisDb(), chp);
    return (rv instanceof RollbackHookProxy)
      ? ((RollbackHookProxy)rv).rollbackHook
      : null;
  }

  public interface UpdateHook {
    /**
       Must function as described for the C-level sqlite3_update_hook()
       callback.
    */
    void call(int opId, String dbName, String tableName, long rowId);
  }

  /**
     A level of indirection to permit setUpdateHook() to have similar
     semantics as the C API, returning the previous hook. The caveat
     is that if the low-level API is used to install a hook, it will
     have a different hook type than Sqlite.UpdateHook so
     setUpdateHook() will return null instead of that object.
  */
  private static class UpdateHookProxy
    implements org.sqlite.jni.capi.UpdateHookCallback {
    final UpdateHook updateHook;
    UpdateHookProxy(UpdateHook ch){
      this.updateHook = ch;
    }
    @Override public void call(int opId, String dbName, String tableName, long rowId){
      updateHook.call(opId, dbName, tableName, rowId);
    }
  }

  /**
     Analog to sqlite3_update_hook(). Returns the previous hook, if
     any (else null). Throws if this db is closed.

     Minor caveat: if a update hook is set on this object's underlying
     db handle using the lower-level SQLite API, this function may
     return null when replacing it, despite there being a hook,
     because it will have a different callback type. So long as the
     handle is only manipulated via the high-level API, this caveat
     does not apply.
  */
  public UpdateHook setUpdateHook( UpdateHook c ){
    UpdateHookProxy chp = null;
    if( null!=c ){
      chp = new UpdateHookProxy(c);
    }
    final org.sqlite.jni.capi.UpdateHookCallback rv =
      CApi.sqlite3_update_hook(thisDb(), chp);
    return (rv instanceof UpdateHookProxy)
      ? ((UpdateHookProxy)rv).updateHook
      : null;
  }


  /**
     Callback interface for use with setProgressHandler().
  */
  public interface ProgressHandler {
    /**
       Must behave as documented for the C-level sqlite3_progress_handler()
       callback. If it throws, the exception is translated into
       a db-level error.
    */
    int call();
  }

  /**
     Analog to sqlite3_progress_handler(), sets the current progress
     handler or clears it if p is null.

     Note that this API, in contrast to setUpdateHook(),
     setRollbackHook(), and setCommitHook(), cannot return the
     previous handler. That inconsistency is part of the lower-level C
     API.
  */
  public void setProgressHandler( int n, ProgressHandler p ){
    org.sqlite.jni.capi.ProgressHandlerCallback phc = null;
    if( null!=p ){
      phc = new org.sqlite.jni.capi.ProgressHandlerCallback(){
          @Override public int call(){ return p.call(); }
        };
    }
    CApi.sqlite3_progress_handler( thisDb(), n, phc );
  }


  /**
     Callback for use with setAuthorizer().
  */
  public interface Authorizer {
    /**
       Must function as described for the C-level
       sqlite3_set_authorizer() callback. If it throws, the error is
       converted to a db-level error and the exception is suppressed.
    */
    int call(int opId, String s1, String s2, String s3, String s4);
  }

  /**
     Analog to sqlite3_set_authorizer(), this sets the current
     authorizer callback, or clears if it passed null.
  */
  public void setAuthorizer( Authorizer a ) {
    org.sqlite.jni.capi.AuthorizerCallback ac = null;
    if( null!=a ){
      ac = new org.sqlite.jni.capi.AuthorizerCallback(){
          @Override public int call(int opId, String s1, String s2, String s3, String s4){
            return a.call(opId, s1, s2, s3, s4);
          }
        };
    }
    checkRc( CApi.sqlite3_set_authorizer( thisDb(), ac ) );
  }

  /**
     Object type for use with blobOpen()
  */
  public final class Blob implements AutoCloseable {
    private Sqlite db;
    private sqlite3_blob b;
    Blob(Sqlite db, sqlite3_blob b){
      this.db = db;
      this.b = b;
    }

    /**
       If this blob is still opened, its low-level handle is
       returned, else an IllegalArgumentException is thrown.
    */
    private sqlite3_blob thisBlob(){
      if( null==b || 0==b.getNativePointer() ){
        throw new IllegalArgumentException("This Blob has been finalized.");
      }
      return b;
    }

    /**
       Analog to sqlite3_blob_close().
    */
    @Override public void close(){
      if( null!=b ){
        CApi.sqlite3_blob_close(b);
        b = null;
        db = null;
      }
    }

    /**
       Throws if the JVM does not have JNI-level support for
       ByteBuffer.
    */
    private void checkNio(){
      if( !Sqlite.JNI_SUPPORTS_NIO ){
        throw new UnsupportedOperationException(
          "This JVM does not support JNI access to ByteBuffer."
        );
      }
    }
    /**
       Analog to sqlite3_blob_reopen() but throws on error.
    */
    public void reopen(long newRowId){
      db.checkRc( CApi.sqlite3_blob_reopen(thisBlob(), newRowId) );
    }

    /**
       Analog to sqlite3_blob_write() but throws on error.
    */
    public void write( byte[] bytes, int atOffset ){
      db.checkRc( CApi.sqlite3_blob_write(thisBlob(), bytes, atOffset) );
    }

    /**
       Analog to sqlite3_blob_read() but throws on error.
    */
    public void read( byte[] dest, int atOffset ){
      db.checkRc( CApi.sqlite3_blob_read(thisBlob(), dest, atOffset) );
    }

    /**
       Analog to sqlite3_blob_bytes().
    */
    public int bytes(){
      return CApi.sqlite3_blob_bytes(thisBlob());

  public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f ){
    int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep,
                                           new SqlFunction.AggregateAdapter(f));
    if( 0!=rc ) throw new SqliteException(db);
    }
  }

  /**
     Analog to sqlite3_blob_open(). Returns a Blob object for the
     given database, table, column, and rowid. The blob is opened for
     read-write mode if writeable is true, else it is read-only.

     The returned object must eventually be freed, before this
     database is closed, by either arranging for it to be auto-closed
     or calling its close() method.

     Throws on error.
  */
  public Blob blobOpen(String dbName, String tableName, String columnName,
                       long iRow, boolean writeable){
    final OutputPointer.sqlite3_blob out = new OutputPointer.sqlite3_blob();
    checkRc(
      CApi.sqlite3_blob_open(thisDb(), dbName, tableName, columnName,
                             iRow, writeable ? 1 : 0, out)
    );
    return new Blob(this, out.take());
  }

  /**
     Callback for use with libConfigLog().
  */
  public interface ConfigLog {
    /**
     Must function as described for a C-level callback for
     sqlite3_config()'s SQLITE_CONFIG_LOG callback, with the slight
     signature change. Any exceptions thrown from this callback are
     necessarily suppressed.
    */
    void call(int errCode, String msg);
  }

  /**
     Analog to sqlite3_config() with the SQLITE_CONFIG_LOG option,
     this sets or (if log is null) clears the current logger.
  */
  public static void libConfigLog(ConfigLog log){
    final org.sqlite.jni.capi.ConfigLogCallback l =
      null==log
      ? null
      : new org.sqlite.jni.capi.ConfigLogCallback() {
          @Override public void call(int errCode, String msg){
            log.call(errCode, msg);
          }
        };
      checkRcStatic(CApi.sqlite3_config(l));
  }
  public void createFunction(String name, int nArg, AggregateFunction f){
    this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);

  /**
     Callback for use with libConfigSqlLog().
  */
  public interface ConfigSqlLog {
    /**
       Must function as described for a C-level callback for
       sqlite3_config()'s SQLITE_CONFIG_SQLLOG callback, with the
       slight signature change. Any exceptions thrown from this
       callback are necessarily suppressed.
     */
    void call(Sqlite db, String msg, int msgType);
  }

  /**
     Analog to sqlite3_config() with the SQLITE_CONFIG_SQLLOG option,
     this sets or (if log is null) clears the current logger.

     If SQLite is built without SQLITE_ENABLE_SQLLOG defined then this
     will throw an UnsupportedOperationException.
  */
  public static void libConfigSqlLog(ConfigSqlLog log){
    Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_SQLLOG");
    final org.sqlite.jni.capi.ConfigSqlLogCallback l =
      null==log
      ? null
      : new org.sqlite.jni.capi.ConfigSqlLogCallback() {
          @Override public void call(sqlite3 db, String msg, int msgType){
            try{
              log.call(fromNative(db), msg, msgType);
            }catch(Exception e){
              /* Suppressed */
            }
          }
        };
      checkRcStatic(CApi.sqlite3_config(l));
  }

  /**
     Analog to the C-level sqlite3_config() with one of the
     SQLITE_CONFIG_... constants defined as CONFIG_... in this
     class. Throws on error, including passing of an unknown option or
     if a specified option is not supported by the underlying build of
     the SQLite library.
   */
  public static void libConfigOp( int op ){
    checkRcStatic(CApi.sqlite3_config(op));
  }

}
Changes to ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java.
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
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







-
+









-
-
-
-
+
+
+
+












-
+
+
+
+


-
+





-
+


-
+




-
-
-
-
-
+
+
+
+
+











-
+







**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
import static org.sqlite.jni.capi.CApi.*;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.capi.sqlite3;

/**
   A wrapper for communicating C-level (sqlite3*) instances with
   Java. These wrappers do not own their associated pointer, they
   simply provide a type-safe way to communicate it between Java
   and C via JNI.
*/
public final class SqliteException extends java.lang.RuntimeException {
  int errCode = SQLITE_ERROR;
  int xerrCode = SQLITE_ERROR;
  int errOffset = -1;
  int sysErrno = 0;
  private int errCode = CApi.SQLITE_ERROR;
  private int xerrCode = CApi.SQLITE_ERROR;
  private int errOffset = -1;
  private int sysErrno = 0;

  /**
     Records the given error string and uses SQLITE_ERROR for both the
     error code and extended error code.
  */
  public SqliteException(String msg){
    super(msg);
  }

  /**
     Uses sqlite3_errstr(sqlite3ResultCode) for the error string and
     sets both the error code and extended error code to the given
     value.
     value. This approach includes no database-level information and
     systemErrno() will be 0, so is intended only for use with sqlite3
     APIs for which a result code is not an error but which the
     higher-level wrapper should treat as one.
  */
  public SqliteException(int sqlite3ResultCode){
    super(sqlite3_errstr(sqlite3ResultCode));
    super(CApi.sqlite3_errstr(sqlite3ResultCode));
    errCode = xerrCode = sqlite3ResultCode;
  }

  /**
     Records the current error state of db (which must not be null and
     must refer to an opened db object). Note that this does NOT close
     must refer to an opened db object). Note that this does not close
     the db.

     Design note: closing the db on error is likely only useful during
     Design note: closing the db on error is really only useful during
     a failed db-open operation, and the place(s) where that can
     happen are inside this library, not client-level code.
  */
  SqliteException(sqlite3 db){
    super(sqlite3_errmsg(db));
    errCode = sqlite3_errcode(db);
    xerrCode = sqlite3_extended_errcode(db);
    errOffset = sqlite3_error_offset(db);
    sysErrno = sqlite3_system_errno(db);
    super(CApi.sqlite3_errmsg(db));
    errCode = CApi.sqlite3_errcode(db);
    xerrCode = CApi.sqlite3_extended_errcode(db);
    errOffset = CApi.sqlite3_error_offset(db);
    sysErrno = CApi.sqlite3_system_errno(db);
  }

  /**
     Records the current error state of db (which must not be null and
     must refer to an open database).
  */
  public SqliteException(Sqlite db){
    this(db.nativeHandle());
  }

  public SqliteException(Sqlite.Stmt stmt){
    this( stmt.db() );
    this(stmt.getDb());
  }

  public int errcode(){ return errCode; }
  public int extendedErrcode(){ return xerrCode; }
  public int errorOffset(){ return errOffset; }
  public int systemErrno(){ return sysErrno; }

Changes to ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
8
9
10
11
12
13
14

15
16
17
18
19
20

21
22
23
24
25
26
27
28







-






-
+







**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains a set of tests for the sqlite3 JNI bindings.
*/
package org.sqlite.jni.wrapper1;
//import static org.sqlite.jni.capi.CApi.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.sqlite.jni.capi.*;
import org.sqlite.jni.capi.CApi;

/**
   An annotation for Tester2 tests which we do not want to run in
   reflection-driven test mode because either they are not suitable
   for multi-threaded threaded mode or we have to control their execution
   order.
*/
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55







-
+







  //! True when running in multi-threaded mode.
  private static boolean mtMode = false;
  //! True to sleep briefly between tests.
  private static boolean takeNaps = false;
  //! True to shuffle the order of the tests.
  private static boolean shuffle = false;
  //! True to dump the list of to-run tests to stdout.
  private static boolean listRunTests = false;
  private static int listRunTests = 0;
  //! True to squelch all out() and outln() output.
  private static boolean quietMode = false;
  //! Total number of runTests() calls.
  private static int nTestRuns = 0;
  //! List of test*() methods to run.
  private static List<java.lang.reflect.Method> testMethods = null;
  //! List of exceptions collected by run()
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
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
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951

952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968

969
970
971
972
973
974
975
976







-
+



+
+
+
+
+

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

-
+








-
+
-
-
-
-
-
-
-
-









-
-
-
+
+
+









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



-
-
-
-
+
+
-
-









-
+
+

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

-
-
+
+



-
-
-
+
+
+
+
+
+
+












+



+






-
+
+

+
+
+

-
+
+

+

+






-
+













-





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

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

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









-
+







  }

  public static void affirm(Boolean v){
    affirm(v, "Affirmation failed.");
  }


  public static void execSql(Sqlite db, String[] sql){
  public static void execSql(Sqlite db, String sql[]){
    execSql(db, String.join("", sql));
  }

  /**
     Executes all SQL statements in the given string. If throwOnError
     is true then it will throw for any prepare/step errors, else it
     will return the corresponding non-0 result code.
  */
  public static int execSql(Sqlite dbw, boolean throwOnError, String sql){
    final sqlite3 db = dbw.nativeHandle();
    OutputPointer.Int32 oTail = new OutputPointer.Int32();
    final ValueHolder<Integer> rv = new ValueHolder<>(0);
    final Sqlite.PrepareMulti pm = new Sqlite.PrepareMulti(){
    final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
    int pos = 0, n = 1;
    byte[] sqlChunk = sqlUtf8;
    int rc = 0;
    sqlite3_stmt stmt = null;
        @Override public void call(Sqlite.Stmt stmt){
    final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
    while(pos < sqlChunk.length){
          try{
            while( Sqlite.ROW == (rv.value = stmt.step(throwOnError)) ){}
      if(pos > 0){
        sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
                                      sqlChunk.length);
      }
          }
      if( 0==sqlChunk.length ) break;
      rc = CApi.sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
      if(throwOnError) affirm(0 == rc);
      else if( 0!=rc ) break;
      pos = oTail.value;
      stmt = outStmt.take();
      if( null == stmt ){
          finally{ stmt.finalizeStmt(); }
        // empty statement was parsed.
        continue;
      }
        }
      affirm(0 != stmt.getNativePointer());
      while( CApi.SQLITE_ROW == (rc = CApi.sqlite3_step(stmt)) ){
      }
      CApi.sqlite3_finalize(stmt);
      };
    try {
      dbw.prepareMulti(sql, pm);
    }catch(SqliteException se){
      affirm(0 == stmt.getNativePointer());
      if(0!=rc && CApi.SQLITE_ROW!=rc && CApi.SQLITE_DONE!=rc){
        break;
      }
    }
      if( throwOnError ){
        throw se;
      }else{
        /* This error (likely) happened in the prepare() phase and we
           need to preempt it. */
        rv.value = se.errcode();
      }
    CApi.sqlite3_finalize(stmt);
    if(CApi.SQLITE_ROW==rc || CApi.SQLITE_DONE==rc) rc = 0;
    if( 0!=rc && throwOnError){
      throw new SqliteException(db);
    }
    return rc;
    return (rv.value==Sqlite.DONE) ? 0 : rv.value;
  }

  static void execSql(Sqlite db, String sql){
    execSql(db, true, sql);
  }

  @SingleThreadOnly /* because it's thread-agnostic */
  private void test1(){
    affirm(CApi.sqlite3_libversion_number() == CApi.SQLITE_VERSION_NUMBER);
    affirm(Sqlite.libVersionNumber() == CApi.SQLITE_VERSION_NUMBER);
  }

  /* Copy/paste/rename this to add new tests. */
  private void _testTemplate(){
    //final sqlite3 db = createNewDb();
    //sqlite3_stmt stmt = prepare(db,"SELECT 1");
    //sqlite3_finalize(stmt);
    //sqlite3_close_v2(db);
  }

  private void nap() throws InterruptedException {
    if( takeNaps ){
      Thread.sleep(java.util.concurrent.ThreadLocalRandom.current().nextInt(3, 17), 0);
    }
  }

  Sqlite openDb(String name){
    final Sqlite db = Sqlite.open(name, CApi.SQLITE_OPEN_READWRITE|
                                  CApi.SQLITE_OPEN_CREATE|
                                  CApi.SQLITE_OPEN_EXRESCODE);
    final Sqlite db = Sqlite.open(name, Sqlite.OPEN_READWRITE|
                                  Sqlite.OPEN_CREATE|
                                  Sqlite.OPEN_EXRESCODE);
    ++metrics.dbOpen;
    return db;
  }

  Sqlite openDb(){ return openDb(":memory:"); }

  void testOpenDb1(){
    Sqlite db = openDb();
    affirm( 0!=db.nativeHandle().getNativePointer() );
    affirm( "main".equals( db.dbName(0) ) );
    db.setMainDbName("foo");
    affirm( "foo".equals( db.dbName(0) ) );
    affirm( db.dbConfig(Sqlite.DBCONFIG_DEFENSIVE, true)
      /* The underlying function has different mangled names in jdk8
         vs jdk19, and this call is here to ensure that the build
         fails if it cannot find both names. */ );
    affirm( !db.dbConfig(Sqlite.DBCONFIG_DEFENSIVE, false) );
    SqliteException ex = null;
    try{ db.dbConfig(0, false); }
    catch(SqliteException e){ ex = e; }
    affirm( null!=ex );
    ex = null;
    db.close();
    affirm( null==db.nativeHandle() );

    SqliteException ex = null;
    try {
      db = openDb("/no/such/dir/.../probably");
    }catch(SqliteException e){
    try{ db = openDb("/no/such/dir/.../probably"); }
    catch(SqliteException e){ ex = e; }
      ex = e;
    }
    affirm( ex!=null );
    affirm( ex.errcode() != 0 );
    affirm( ex.extendedErrcode() != 0 );
    affirm( ex.errorOffset() < 0 );
    // there's no reliable way to predict what ex.systemErrno() might be
  }

  void testPrepare1(){
    try (Sqlite db = openDb()) {
      Sqlite.Stmt stmt = db.prepare("SELECT 1");
      Sqlite.Stmt stmt = db.prepare("SELECT ?1");
      Exception e = null;
      affirm( null!=stmt.nativeHandle() );
      affirm( db == stmt.getDb() );
      affirm( 1==stmt.bindParameterCount() );
      affirm( "?1".equals(stmt.bindParameterName(1)) );
      affirm( null==stmt.bindParameterName(2) );
      stmt.bindInt64(1, 1);
      stmt.bindDouble(1, 1.1);
      stmt.bindObject(1, db);
      stmt.bindNull(1);
      stmt.bindText(1, new byte[] {32,32,32});
      stmt.bindText(1, "123");
      stmt.bindText16(1, "123".getBytes(StandardCharsets.UTF_16));
      stmt.bindText16(1, "123");
      stmt.bindZeroBlob(1, 8);
      stmt.bindBlob(1, new byte[] {1,2,3,4});
      stmt.bindInt(1, 17);
      try{ stmt.bindInt(2,1); }
      catch(Exception ex){ e = ex; }
      affirm( null!=e );
      e = null;
      affirm( CApi.SQLITE_ROW == stmt.step() );
      affirm( CApi.SQLITE_DONE == stmt.step() );
      affirm( stmt.step() );
      try{ stmt.columnInt(1); }
      catch(Exception ex){ e = ex; }
      affirm( null!=e );
      e = null;
      affirm( 17 == stmt.columnInt(0) );
      affirm( 17L == stmt.columnInt64(0) );
      affirm( 17.0 == stmt.columnDouble(0) );
      affirm( "17".equals(stmt.columnText16(0)) );
      affirm( !stmt.step() );
      stmt.reset();
      affirm( CApi.SQLITE_ROW == stmt.step() );
      affirm( CApi.SQLITE_DONE == stmt.step() );
      affirm( Sqlite.ROW==stmt.step(false) );
      affirm( !stmt.step() );
      affirm( 0 == stmt.finalizeStmt() );
      affirm( null==stmt.nativeHandle() );

      stmt = db.prepare("SELECT 1");
      affirm( CApi.SQLITE_ROW == stmt.step() );
      affirm( 0 == stmt.finalizeStmt() )
      stmt = db.prepare("SELECT ?");
      stmt.bindObject(1, db);
      affirm( Sqlite.ROW == stmt.step(false) );
      affirm( db==stmt.columnObject(0) );
      affirm( db==stmt.columnObject(0, Sqlite.class ) );
      affirm( null==stmt.columnObject(0, Sqlite.Stmt.class ) );
      affirm( 0==stmt.finalizeStmt() )
        /* getting a non-0 out of sqlite3_finalize() is tricky */;
      affirm( null==stmt.nativeHandle() );
    }
  }

  void testUdfScalar(){
    final ValueHolder<Integer> xDestroyCalled = new ValueHolder<>(0);
    try (Sqlite db = openDb()) {
      execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
      final ValueHolder<Integer> vh = new ValueHolder<>(0);
      final ScalarFunction f = new ScalarFunction(){
          public void xFunc(SqlFunction.Arguments args){
            affirm( db == args.getDb() );
            for( SqlFunction.Arguments.Arg arg : args ){
              vh.value += arg.getInt();
            }
            args.resultInt(vh.value);
          }
          public void xDestroy(){
            ++xDestroyCalled.value;
          }
        };
      db.createFunction("myfunc", -1, f);
      execSql(db, "select myfunc(1,2,3)");
      Sqlite.Stmt q = db.prepare("select myfunc(1,2,3)");
      affirm( q.step() );
      affirm( 6 == vh.value );
      affirm( 6 == q.columnInt(0) );
      q.finalizeStmt();
      affirm( 0 == xDestroyCalled.value );
      vh.value = 0;
      execSql(db, "select myfunc(-1,-2,-3)");
      q = db.prepare("select myfunc(-1,-2,-3)");
      affirm( q.step() );
      affirm( -6 == vh.value );
      affirm( -6 == q.columnInt(0) );
      affirm( 0 == xDestroyCalled.value );
      q.finalizeStmt();
    }
    affirm( 1 == xDestroyCalled.value );
  }

  void testUdfAggregate(){
    final ValueHolder<Integer> xDestroyCalled = new ValueHolder<>(0);
    final ValueHolder<Integer> vh = new ValueHolder<>(0);
    Sqlite.Stmt q = null;
    try (Sqlite db = openDb()) {
      execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
      final AggregateFunction f = new AggregateFunction<Integer>(){
          public void xStep(SqlFunction.Arguments args){
            final ValueHolder<Integer> agg = this.getAggregateState(args, 0);
            for( SqlFunction.Arguments.Arg arg : args ){
              agg.value += arg.getInt();
            }
          }
          public void xFinal(SqlFunction.Arguments args){
            final Integer v = this.takeAggregateState(args);
            if( null==v ) args.resultNull();
            else args.resultInt(v);
            vh.value = v;
          }
          public void xDestroy(){
            ++xDestroyCalled.value;
          }
        };
      db.createFunction("myagg", -1, f);
      execSql(db, "select myagg(a) from t");
      affirm( 6 == vh.value );
      db.createFunction("summer", 1, f);
      q = db.prepare(
        "with cte(v) as ("+
        "select 3 union all select 5 union all select 7"+
        ") select summer(v), summer(v+1) from cte"
        /* ------------------^^^^^^^^^^^ ensures that we're handling
           sqlite3_aggregate_context() properly. */
      );
      affirm( q.step() );
      affirm( 15==q.columnInt(0) );
      q.finalizeStmt();
      q = null;
      affirm( 0 == xDestroyCalled.value );
      db.createFunction("summerN", -1, f);

      q = db.prepare("select summerN(1,8,9), summerN(2,3,4)");
      affirm( q.step() );
      affirm( 18==q.columnInt(0) );
      affirm( 9==q.columnInt(1) );
      q.finalizeStmt();
      q = null;

    }/*db*/
    finally{
      if( null!=q ) q.finalizeStmt();
    }
    affirm( 2 == xDestroyCalled.value
            /* because we've bound the same instance twice */ );
  }

  private void testUdfWindow(){
    final Sqlite db = openDb();
    /* Example window function, table, and results taken from:
       https://sqlite.org/windowfunctions.html#udfwinfunc */
    final WindowFunction func = new WindowFunction<Integer>(){
        //! Impl of xStep() and xInverse()
        private void xStepInverse(SqlFunction.Arguments args, int v){
          this.getAggregateState(args,0).value += v;
        }
        @Override public void xStep(SqlFunction.Arguments args){
          this.xStepInverse(args, args.getInt(0));
        }
        @Override public void xInverse(SqlFunction.Arguments args){
          this.xStepInverse(args, -args.getInt(0));
        }
        //! Impl of xFinal() and xValue()
        private void xFinalValue(SqlFunction.Arguments args, Integer v){
          if(null == v) args.resultNull();
          else args.resultInt(v);
        }
        @Override public void xFinal(SqlFunction.Arguments args){
          xFinalValue(args, this.takeAggregateState(args));
          affirm( null == this.getAggregateState(args,null).value );
        }
        @Override public void xValue(SqlFunction.Arguments args){
          xFinalValue(args, this.getAggregateState(args,null).value);
        }
      };
    db.createFunction("winsumint", 1, func);
    execSql(db, new String[] {
        "CREATE TEMP TABLE twin(x, y); INSERT INTO twin VALUES",
        "('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
      });
    final Sqlite.Stmt stmt = db.prepare(
      "SELECT x, winsumint(y) OVER ("+
      "ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"+
      ") AS sum_y "+
      "FROM twin ORDER BY x;"
    );
    int n = 0;
    while( stmt.step() ){
      final String s = stmt.columnText16(0);
      final int i = stmt.columnInt(1);
      switch(++n){
        case 1: affirm( "a".equals(s) && 9==i ); break;
        case 2: affirm( "b".equals(s) && 12==i ); break;
        case 3: affirm( "c".equals(s) && 16==i ); break;
        case 4: affirm( "d".equals(s) && 12==i ); break;
        case 5: affirm( "e".equals(s) && 9==i ); break;
        default: affirm( false /* cannot happen */ );
      }
    }
    stmt.close();
    affirm( 5 == n );
    db.close();
  }

  private void testKeyword(){
    final int n = Sqlite.keywordCount();
    affirm( n>0 );
    affirm( !Sqlite.keywordCheck("_nope_") );
    affirm( Sqlite.keywordCheck("seLect") );
    affirm( null!=Sqlite.keywordName(0) );
    affirm( null!=Sqlite.keywordName(n-1) );
    affirm( null==Sqlite.keywordName(n) );
  }


  private void testExplain(){
    final Sqlite db = openDb();
    Sqlite.Stmt q = db.prepare("SELECT 1");
    affirm( 0 == q.isExplain() );
    q.explain(0);
    affirm( 0 == q.isExplain() );
    q.explain(1);
    affirm( 1 == q.isExplain() );
    q.explain(2);
    affirm( 2 == q.isExplain() );
    Exception ex = null;
    try{
      q.explain(-1);
    }catch(Exception e){
      ex = e;
    }
    affirm( ex instanceof SqliteException );
    q.finalizeStmt();
    db.close();
  }


  private void testTrace(){
    final Sqlite db = openDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    /* Ensure that characters outside of the UTF BMP survive the trip
       from Java to sqlite3 and back to Java. (At no small efficiency
       penalty.) */
    final String nonBmpChar = "😃";
    db.trace(
      Sqlite.TRACE_ALL,
      new Sqlite.TraceCallback(){
        @Override public void call(int traceFlag, Object pNative, Object x){
          ++counter.value;
          //outln("TRACE "+traceFlag+" pNative = "+pNative.getClass().getName());
          switch(traceFlag){
            case Sqlite.TRACE_STMT:
              affirm(pNative instanceof Sqlite.Stmt);
              //outln("TRACE_STMT sql = "+x);
              affirm(x instanceof String);
              affirm( ((String)x).indexOf(nonBmpChar) > 0 );
              break;
            case Sqlite.TRACE_PROFILE:
              affirm(pNative instanceof Sqlite.Stmt);
              affirm(x instanceof Long);
              //outln("TRACE_PROFILE time = "+x);
              break;
            case Sqlite.TRACE_ROW:
              affirm(pNative instanceof Sqlite.Stmt);
              affirm(null == x);
              //outln("TRACE_ROW = "+sqlite3_column_text16((sqlite3_stmt)pNative, 0));
              break;
            case Sqlite.TRACE_CLOSE:
              affirm(pNative instanceof Sqlite);
              affirm(null == x);
              break;
            default:
              affirm(false /*cannot happen*/);
              break;
          }
        }
      });
    execSql(db, "SELECT coalesce(null,null,'"+nonBmpChar+"'); "+
            "SELECT 'w"+nonBmpChar+"orld'");
    affirm( 6 == counter.value );
    db.close();
    affirm( 7 == counter.value );
  }

  private void testStatus(){
    final Sqlite db = openDb();
    execSql(db, "create table t(a); insert into t values(1),(2),(3)");

    Sqlite.Status s = Sqlite.libStatus(Sqlite.STATUS_MEMORY_USED, false);
    affirm( s.current > 0 );
    affirm( s.peak >= s.current );

    s = db.status(Sqlite.DBSTATUS_SCHEMA_USED, false);
    affirm( s.current > 0 );
    affirm( s.peak == 0 /* always 0 for SCHEMA_USED */ );

    db.close();
  }

  @SingleThreadOnly /* because multiple threads legitimately make these
                       results unpredictable */
  private synchronized void testAutoExtension(){
    final ValueHolder<Integer> val = new ValueHolder<>(0);
    final ValueHolder<String> toss = new ValueHolder<>(null);
    final Sqlite.AutoExtension ax = new Sqlite.AutoExtension(){
        @Override public void call(Sqlite db){
          ++val.value;
          if( null!=toss.value ){
            throw new RuntimeException(toss.value);
          }
        }
      };
    Sqlite.addAutoExtension(ax);
    openDb().close();
    affirm( 1==val.value );
    openDb().close();
    affirm( 2==val.value );
    Sqlite.clearAutoExtensions();
    openDb().close();
    affirm( 2==val.value );

    Sqlite.addAutoExtension( ax );
    Sqlite.addAutoExtension( ax ); // Must not add a second entry
    Sqlite.addAutoExtension( ax ); // or a third one
    openDb().close();
    affirm( 3==val.value );

    Sqlite db = openDb();
    affirm( 4==val.value );
    execSql(db, "ATTACH ':memory:' as foo");
    affirm( 4==val.value, "ATTACH uses the same connection, not sub-connections." );
    db.close();
    db = null;

    Sqlite.removeAutoExtension(ax);
    openDb().close();
    affirm( 4==val.value );
    Sqlite.addAutoExtension(ax);
    Exception err = null;
    toss.value = "Throwing from auto_extension.";
    try{
      openDb();
    }catch(Exception e){
      err = e;
    }
    affirm( err!=null );
    affirm( err.getMessage().indexOf(toss.value)>=0 );
    toss.value = null;

    val.value = 0;
    final Sqlite.AutoExtension ax2 = new Sqlite.AutoExtension(){
        @Override public void call(Sqlite db){
          ++val.value;
        }
      };
    Sqlite.addAutoExtension(ax2);
    openDb().close();
    affirm( 2 == val.value );
    Sqlite.removeAutoExtension(ax);
    openDb().close();
    affirm( 3 == val.value );
    Sqlite.addAutoExtension(ax);
    openDb().close();
    affirm( 5 == val.value );
    Sqlite.removeAutoExtension(ax2);
    openDb().close();
    affirm( 6 == val.value );
    Sqlite.addAutoExtension(ax2);
    openDb().close();
    affirm( 8 == val.value );

    Sqlite.clearAutoExtensions();
    openDb().close();
    affirm( 8 == val.value );
  }

  private void testBackup(){
    final Sqlite dbDest = openDb();

    try (Sqlite dbSrc = openDb()) {
      execSql(dbSrc, new String[]{
          "pragma page_size=512; VACUUM;",
          "create table t(a);",
          "insert into t(a) values(1),(2),(3);"
        });
      Exception e = null;
      try {
        dbSrc.initBackup("main",dbSrc,"main");
      }catch(Exception x){
        e = x;
      }
      affirm( e instanceof SqliteException );
      e = null;
      try (Sqlite.Backup b = dbDest.initBackup("main",dbSrc,"main")) {
        affirm( null!=b );
        int rc;
        while( Sqlite.DONE!=(rc = b.step(1)) ){
          affirm( 0==rc );
        }
        affirm( b.pageCount() > 0 );
        b.finish();
      }
    }

    try (Sqlite.Stmt q = dbDest.prepare("SELECT sum(a) from t")) {
      q.step();
      affirm( q.columnInt(0) == 6 );
    }
    dbDest.close();
  }

  private void testCollation(){
    final Sqlite db = openDb();
    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
    final Sqlite.Collation myCollation = new Sqlite.Collation() {
        private String myState =
          "this is local state. There is much like it, but this is mine.";
        @Override
        // Reverse-sorts its inputs...
        public int call(byte[] lhs, byte[] rhs){
          int len = lhs.length > rhs.length ? rhs.length : lhs.length;
          int c = 0, i = 0;
          for(i = 0; i < len; ++i){
            c = lhs[i] - rhs[i];
            if(0 != c) break;
          }
          if(0==c){
            if(i < lhs.length) c = 1;
            else if(i < rhs.length) c = -1;
          }
          return -c;
        }
      };
    final Sqlite.CollationNeeded collLoader = new Sqlite.CollationNeeded(){
        @Override
        public void call(Sqlite dbArg, int eTextRep, String collationName){
          affirm(dbArg == db);
          db.createCollation("reversi", eTextRep, myCollation);
        }
      };
    db.onCollationNeeded(collLoader);
    Sqlite.Stmt stmt = db.prepare("SELECT a FROM t ORDER BY a COLLATE reversi");
    int counter = 0;
    while( stmt.step() ){
      final String val = stmt.columnText16(0);
      ++counter;
      switch(counter){
        case 1: affirm("c".equals(val)); break;
        case 2: affirm("b".equals(val)); break;
        case 3: affirm("a".equals(val)); break;
      }
    }
    affirm(3 == counter);
    stmt.finalizeStmt();
    stmt = db.prepare("SELECT a FROM t ORDER BY a");
    counter = 0;
    while( stmt.step() ){
      final String val = stmt.columnText16(0);
      ++counter;
      //outln("Non-REVERSI'd row#"+counter+": "+val);
      switch(counter){
        case 3: affirm("c".equals(val)); break;
        case 2: affirm("b".equals(val)); break;
        case 1: affirm("a".equals(val)); break;
      }
    }
    affirm(3 == counter);
    stmt.finalizeStmt();
    db.onCollationNeeded(null);
    db.close();
  }

  @SingleThreadOnly /* because threads inherently break this test */
  private void testBusy(){
    final String dbName = "_busy-handler.db";
    try{
      Sqlite db1 = openDb(dbName);
      ++metrics.dbOpen;
      execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
      Sqlite db2 = openDb(dbName);
      ++metrics.dbOpen;

      final ValueHolder<Integer> xBusyCalled = new ValueHolder<>(0);
      Sqlite.BusyHandler handler = new Sqlite.BusyHandler(){
          @Override public int call(int n){
            return n > 2 ? 0 : ++xBusyCalled.value;
          }
        };
      db2.setBusyHandler(handler);

      // Force a locked condition...
      execSql(db1, "BEGIN EXCLUSIVE");
      int rc = 0;
      SqliteException ex = null;
      try{
        db2.prepare("SELECT * from t");
      }catch(SqliteException x){
        ex = x;
      }
      affirm( null!=ex );
      affirm( Sqlite.BUSY == ex.errcode() );
      affirm( 3 == xBusyCalled.value );
      db1.close();
      db2.close();
    }finally{
      try{(new java.io.File(dbName)).delete();}
      catch(Exception e){/* ignore */}
    }
  }

  private void testCommitHook(){
    final Sqlite db = openDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    final ValueHolder<Integer> hookResult = new ValueHolder<>(0);
    final Sqlite.CommitHook theHook = new Sqlite.CommitHook(){
        @Override public int call(){
          ++counter.value;
          return hookResult.value;
        }
      };
    Sqlite.CommitHook oldHook = db.setCommitHook(theHook);
    affirm( null == oldHook );
    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
    affirm( 2 == counter.value );
    execSql(db, "BEGIN; SELECT 1; SELECT 2; COMMIT;");
    affirm( 2 == counter.value /* NOT invoked if no changes are made */ );
    execSql(db, "BEGIN; update t set a='d' where a='c'; COMMIT;");
    affirm( 3 == counter.value );
    oldHook = db.setCommitHook(theHook);
    affirm( theHook == oldHook );
    execSql(db, "BEGIN; update t set a='e' where a='d'; COMMIT;");
    affirm( 4 == counter.value );
    oldHook = db.setCommitHook(null);
    affirm( theHook == oldHook );
    execSql(db, "BEGIN; update t set a='f' where a='e'; COMMIT;");
    affirm( 4 == counter.value );
    oldHook = db.setCommitHook(null);
    affirm( null == oldHook );
    execSql(db, "BEGIN; update t set a='g' where a='f'; COMMIT;");
    affirm( 4 == counter.value );

    final Sqlite.CommitHook newHook = new Sqlite.CommitHook(){
        @Override public int call(){return 0;}
      };
    oldHook = db.setCommitHook(newHook);
    affirm( null == oldHook );
    execSql(db, "BEGIN; update t set a='h' where a='g'; COMMIT;");
    affirm( 4 == counter.value );
    oldHook = db.setCommitHook(theHook);
    affirm( newHook == oldHook );
    execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
    affirm( 5 == counter.value );
    hookResult.value = Sqlite.ERROR;
    int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
    affirm( Sqlite.CONSTRAINT_COMMITHOOK == rc );
    affirm( 6 == counter.value );
    db.close();
  }

  private void testRollbackHook(){
    final Sqlite db = openDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    final Sqlite.RollbackHook theHook = new Sqlite.RollbackHook(){
        @Override public void call(){
          ++counter.value;
        }
      };
    Sqlite.RollbackHook oldHook = db.setRollbackHook(theHook);
    affirm( null == oldHook );
    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
    affirm( 0 == counter.value );
    execSql(db, false, "BEGIN; SELECT 1; SELECT 2; ROLLBACK;");
    affirm( 1 == counter.value /* contra to commit hook, is invoked if no changes are made */ );

    final Sqlite.RollbackHook newHook = new Sqlite.RollbackHook(){
        @Override public void call(){}
      };
    oldHook = db.setRollbackHook(newHook);
    affirm( theHook == oldHook );
    execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
    affirm( 1 == counter.value );
    oldHook = db.setRollbackHook(theHook);
    affirm( newHook == oldHook );
    execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
    affirm( 2 == counter.value );
    int rc = execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
    affirm( 0 == rc );
    affirm( 3 == counter.value );
    db.close();
  }

  private void testUpdateHook(){
    final Sqlite db = openDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    final ValueHolder<Integer> expectedOp = new ValueHolder<>(0);
    final Sqlite.UpdateHook theHook = new Sqlite.UpdateHook(){
        @Override
        public void call(int opId, String dbName, String tableName, long rowId){
          ++counter.value;
          if( 0!=expectedOp.value ){
            affirm( expectedOp.value == opId );
          }
        }
      };
    Sqlite.UpdateHook oldHook = db.setUpdateHook(theHook);
    affirm( null == oldHook );
    expectedOp.value = Sqlite.INSERT;
    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
    affirm( 3 == counter.value );
    expectedOp.value = Sqlite.UPDATE;
    execSql(db, "update t set a='d' where a='c';");
    affirm( 4 == counter.value );
    oldHook = db.setUpdateHook(theHook);
    affirm( theHook == oldHook );
    expectedOp.value = Sqlite.DELETE;
    execSql(db, "DELETE FROM t where a='d'");
    affirm( 5 == counter.value );
    oldHook = db.setUpdateHook(null);
    affirm( theHook == oldHook );
    execSql(db, "update t set a='e' where a='b';");
    affirm( 5 == counter.value );
    oldHook = db.setUpdateHook(null);
    affirm( null == oldHook );

    final Sqlite.UpdateHook newHook = new Sqlite.UpdateHook(){
        @Override public void call(int opId, String dbName, String tableName, long rowId){
        }
      };
    oldHook = db.setUpdateHook(newHook);
    affirm( null == oldHook );
    execSql(db, "update t set a='h' where a='a'");
    affirm( 5 == counter.value );
    oldHook = db.setUpdateHook(theHook);
    affirm( newHook == oldHook );
    expectedOp.value = Sqlite.UPDATE;
    execSql(db, "update t set a='i' where a='h'");
    affirm( 6 == counter.value );
    db.close();
  }

  private void testProgress(){
    final Sqlite db = openDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    db.setProgressHandler(1, new Sqlite.ProgressHandler(){
        @Override public int call(){
          ++counter.value;
          return 0;
        }
      });
    execSql(db, "SELECT 1; SELECT 2;");
    affirm( counter.value > 0 );
    int nOld = counter.value;
    db.setProgressHandler(0, null);
    execSql(db, "SELECT 1; SELECT 2;");
    affirm( nOld == counter.value );
    db.close();
  }

  private void testAuthorizer(){
    final Sqlite db = openDb();
    final ValueHolder<Integer> counter = new ValueHolder<>(0);
    final ValueHolder<Integer> authRc = new ValueHolder<>(0);
    final Sqlite.Authorizer auth = new Sqlite.Authorizer(){
        public int call(int op, String s0, String s1, String s2, String s3){
          ++counter.value;
          //outln("xAuth(): "+s0+" "+s1+" "+s2+" "+s3);
          return authRc.value;
        }
      };
    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
    db.setAuthorizer(auth);
    execSql(db, "UPDATE t SET a=1");
    affirm( 1 == counter.value );
    authRc.value = Sqlite.DENY;
    int rc = execSql(db, false, "UPDATE t SET a=2");
    affirm( Sqlite.AUTH==rc );
    db.setAuthorizer(null);
    rc = execSql(db, false, "UPDATE t SET a=2");
    affirm( 0==rc );
    db.close();
  }

  private void testBlobOpen(){
    final Sqlite db = openDb();

    execSql(db, "CREATE TABLE T(a BLOB);"
            +"INSERT INTO t(rowid,a) VALUES(1, 'def'),(2, 'XYZ');"
    );
    Sqlite.Blob b = db.blobOpen("main", "t", "a",
                                db.lastInsertRowId(), true);
    affirm( 3==b.bytes() );
    b.write(new byte[] {100, 101, 102 /*"DEF"*/}, 0);
    b.close();
    Sqlite.Stmt stmt = db.prepare("SELECT length(a), a FROM t ORDER BY a");
    affirm( stmt.step() );
    affirm( 3 == stmt.columnInt(0) );
    affirm( "def".equals(stmt.columnText16(1)) );
    stmt.finalizeStmt();

    b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), false);
    final byte[] tgt = new byte[3];
    b.read( tgt, 0 );
    affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
    execSql(db,"UPDATE t SET a=zeroblob(10) WHERE rowid=2");
    b.close();
    b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), true);
    byte[] bw = new byte[]{
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    };
    b.write(bw, 0);
    byte[] br = new byte[10];
    b.read(br, 0);
    for( int i = 0; i < br.length; ++i ){
      affirm(bw[i] == br[i]);
    }
    b.close();
    db.close();
  }

  void testPrepareMulti(){
    final ValueHolder<Integer> fCount = new ValueHolder<>(0);
    final ValueHolder<Integer> mCount = new ValueHolder<>(0);
    try (Sqlite db = openDb()) {
      execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
      db.createFunction("counter", -1, new ScalarFunction(){
          @Override public void xFunc(SqlFunction.Arguments args){
            ++fCount.value;
            args.resultNull();
          }
        }
      );
      final Sqlite.PrepareMulti pm = new Sqlite.PrepareMultiFinalize(
        new Sqlite.PrepareMulti() {
          @Override public void call(Sqlite.Stmt q){
            ++mCount.value;
            while(q.step()){}
          }
        }
      );
      final String sql = "select counter(*) from t;"+
        "select counter(*) from t; /* comment */"+
        "select counter(*) from t; -- comment\n"
        ;
      db.prepareMulti(sql, pm);
    }
    affirm( 3 == mCount.value );
    affirm( 9 == fCount.value );
  }
    affirm( 1 == xDestroyCalled.value );


  /* Copy/paste/rename this to add new tests. */
  private void _testTemplate(){
    try (Sqlite db = openDb()) {
      Sqlite.Stmt stmt = db.prepare("SELECT 1");
      stmt.finalizeStmt();
    }
  }

  private void runTests(boolean fromThread) throws Exception {
    List<java.lang.reflect.Method> mlist = testMethods;
    affirm( null!=mlist );
    if( shuffle ){
      mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
      java.util.Collections.shuffle(mlist);
    }
    if( listRunTests ){
    if( (!fromThread && listRunTests>0) || listRunTests>1 ){
      synchronized(this.getClass()){
        if( !fromThread ){
          out("Initial test"," list: ");
          for(java.lang.reflect.Method m : testMethods){
            out(m.getName()+" ");
          }
          outln();
340
341
342
343
344
345
346
347

348
349
350
351
352
353
354
355
1001
1002
1003
1004
1005
1006
1007

1008

1009
1010
1011
1012
1013
1014
1015







-
+
-







    try {
      runTests(0!=this.tId);
    }catch(Exception e){
      synchronized( listErrors ){
        listErrors.add(e);
      }
    }finally{
      affirm( CApi.sqlite3_java_uncache_thread() );
      Sqlite.uncacheThread();
      affirm( !CApi.sqlite3_java_uncache_thread() );
    }
  }

  /**
     Runs the basic sqlite3 JNI binding sanity-check suite.

     CLI flags:
364
365
366
367
368
369
370
371



372
373
374
375
376
377
378
1024
1025
1026
1027
1028
1029
1030

1031
1032
1033
1034
1035
1036
1037
1038
1039
1040







-
+
+
+








     -shuffle: randomizes the order of most of the test functions.

     -naps: sleep small random intervals between tests in order to add
     some chaos for cross-thread contention.

     -list-tests: outputs the list of tests being run, minus some
      which are hard-coded. This is noisy in multi-threaded mode.
      which are hard-coded. In multi-threaded mode, use this twice to
      to emit the list run by each thread (which may differ from the initial
      list, in particular if -shuffle is used).

     -fail: forces an exception to be thrown during the test run.  Use
     with -shuffle to make its appearance unpredictable.

     -v: emit some developer-mode info at the end.
  */
  public static void main(String[] args) throws Exception {
393
394
395
396
397
398
399
400

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420



421
422
423
424
425
426
427
428
429


430
431
432
433
434
435
436
437
438
439
440

441
442

443
444
445
446


447
448
449
450
451
452
453
454
455
456
457
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







-
+

















-
-
-
+
+
+






-
-
-
+
+
-
-
-
-






-
+

-
+

-
-
-
+
+
-
-
-
-







        }else if(arg.equals("t") || arg.equals("thread")){
          nThread = Integer.parseInt(args[i++]);
        }else if(arg.equals("r") || arg.equals("repeat")){
          nRepeat = Integer.parseInt(args[i++]);
        }else if(arg.equals("shuffle")){
          shuffle = true;
        }else if(arg.equals("list-tests")){
          listRunTests = true;
          ++listRunTests;
        }else if(arg.equals("fail")){
          forceFail = true;
        }else if(arg.equals("sqllog")){
          sqlLog = true;
        }else if(arg.equals("configlog")){
          configLog = true;
        }else if(arg.equals("naps")){
          takeNaps = true;
        }else if(arg.equals("q") || arg.equals("quiet")){
          squelchTestOutput = true;
        }else{
          throw new IllegalArgumentException("Unhandled flag:"+arg);
        }
      }
    }

    if( sqlLog ){
      if( CApi.sqlite3_compileoption_used("ENABLE_SQLLOG") ){
        final ConfigSqllogCallback log = new ConfigSqllogCallback() {
            @Override public void call(sqlite3 db, String msg, int op){
      if( Sqlite.compileOptionUsed("ENABLE_SQLLOG") ){
        Sqlite.libConfigSqlLog( new Sqlite.ConfigSqlLog() {
            @Override public void call(Sqlite db, String msg, int op){
              switch(op){
                case 0: outln("Opening db: ",db); break;
                case 1: outln("SQL ",db,": ",msg); break;
                case 2: outln("Closing db: ",db); break;
              }
            }
          };
        int rc = CApi.sqlite3_config( log );
        affirm( 0==rc );
          }
        );
        rc = CApi.sqlite3_config( (ConfigSqllogCallback)null );
        affirm( 0==rc );
        rc = CApi.sqlite3_config( log );
        affirm( 0==rc );
      }else{
        outln("WARNING: -sqllog is not active because library was built ",
              "without SQLITE_ENABLE_SQLLOG.");
      }
    }
    if( configLog ){
      final ConfigLogCallback log = new ConfigLogCallback() {
      Sqlite.libConfigLog( new Sqlite.ConfigLog() {
          @Override public void call(int code, String msg){
            outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
            outln("ConfigLog: ",Sqlite.errstr(code),": ", msg);
          };
        };
      int rc = CApi.sqlite3_config( log );
      affirm( 0==rc );
        }
      );
      rc = CApi.sqlite3_config( (ConfigLogCallback)null );
      affirm( 0==rc );
      rc = CApi.sqlite3_config( log );
      affirm( 0==rc );
    }

    quietMode = squelchTestOutput;
    outln("If you just saw warning messages regarding CallStaticObjectMethod, ",
          "you are very likely seeing the side effects of a known openjdk8 ",
          "bug. It is unsightly but does not affect the library.");

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
1128
1129
1130
1131
1132
1133
1134
























1135


1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151







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

-
-
+
+






+







          }
        }
      }
      if( nSkipped>0 ) out("\n");
    }

    final long timeStart = System.currentTimeMillis();
    int nLoop = 0;
    switch( CApi.sqlite3_threadsafe() ){ /* Sanity checking */
      case 0:
        affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
                "Could not switch to single-thread mode." );
        affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
                "Could switch to multithread mode."  );
        affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
                "Could not switch to serialized threading mode."  );
        outln("This is a single-threaded build. Not using threads.");
        nThread = 1;
        break;
      case 1:
      case 2:
        affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
                "Could not switch to single-thread mode." );
        affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
                "Could not switch to multithread mode."  );
        affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
                "Could not switch to serialized threading mode."  );
        break;
      default:
        affirm( false, "Unhandled SQLITE_THREADSAFE value." );
    }
    outln("libversion_number: ",
          CApi.sqlite3_libversion_number(),"\n",
          CApi.sqlite3_libversion(),"\n",CApi.SQLITE_SOURCE_ID,"\n",
          Sqlite.libVersionNumber(),"\n",
          Sqlite.libVersion(),"\n",Sqlite.libSourceId(),"\n",
          "SQLITE_THREADSAFE=",CApi.sqlite3_threadsafe());
    final boolean showLoopCount = (nRepeat>1 && nThread>1);
    if( showLoopCount ){
      outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
    }
    if( takeNaps ) outln("Napping between tests is enabled.");
    int nLoop = 0;
    for( int n = 0; n < nRepeat; ++n ){
      ++nLoop;
      if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
      if( nThread<=1 ){
        new Tester2(0).runTests(false);
        continue;
      }
550
551
552
553
554
555
556
557

558
559
560
561
562
563
564
1179
1180
1181
1182
1183
1184
1185

1186
1187
1188
1189
1190
1191
1192
1193







-
+







    final long timeEnd = System.currentTimeMillis();
    outln("Tests done. Metrics across ",nTestRuns," total iteration(s):");
    outln("\tAssertions checked: ",affirmCount);
    outln("\tDatabases opened: ",metrics.dbOpen);
    if( doSomethingForDev ){
      CApi.sqlite3_jni_internal_details();
    }
    affirm( 0==CApi.sqlite3_release_memory(1) );
    affirm( 0==Sqlite.libReleaseMemory(1) );
    CApi.sqlite3_shutdown();
    int nMethods = 0;
    int nNatives = 0;
    int nCanonical = 0;
    final java.lang.reflect.Method[] declaredMethods =
      CApi.class.getDeclaredMethods();
    for(java.lang.reflect.Method m : declaredMethods){
Changes to ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java.
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
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











-
+





-
+







/*
** 2023-10-16
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains a set of tests for the sqlite3 JNI bindings.
** This file contains the ValueHolder utility class.
*/
package org.sqlite.jni.wrapper1;

/**
   A helper class which simply holds a single value. Its primary use
   is for communicating values out of anonymous classes, as doing so
   is for communicating values out of anonymous callbacks, as doing so
   requires a "final" reference.
*/
public class ValueHolder<T> {
  public T value;
  public ValueHolder(){}
  public ValueHolder(T v){value = v;}
}
Added ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java.










































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2023-10-16
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;

/**
   A SqlFunction implementation for window functions. The T type
   represents the type of data accumulated by this function while it
   works. e.g. a SUM()-like UDF might use Integer or Long and a
   CONCAT()-like UDF might use a StringBuilder or a List<String>.
*/
public abstract class WindowFunction<T> extends AggregateFunction<T>  {

  /**
     As for the xInverse() argument of the C API's
     sqlite3_create_window_function().  If this function throws, the
     exception is reported via sqlite3_result_error().
  */
  public abstract void xInverse(SqlFunction.Arguments args);

  /**
     As for the xValue() argument of the C API's
     sqlite3_create_window_function(). If this function throws, it is
     translated into sqlite3_result_error().

     Note that the passed-in object will not actually contain any
     arguments for xValue() but will contain the context object needed
     for setting the call's result or error state.
  */
  public abstract void xValue(SqlFunction.Arguments args);

}
Changes to ext/misc/cksumvfs.c.
442
443
444
445
446
447
448
449
450
451



452
453
454
455
456
457
458
442
443
444
445
446
447
448



449
450
451
452
453
454
455
456
457
458







-
-
-
+
+
+







    }
    /* Verify the checksum if
    **    (1) the size indicates that we are dealing with a complete
    **        database page
    **    (2) checksum verification is enabled
    **    (3) we are not in the middle of checkpoint
    */
    if( iAmt>=512           /* (1) */
     && p->verifyCksm       /* (2) */
     && !p->inCkpt          /* (3) */
    if( iAmt>=512 && (iAmt & (iAmt-1))==0   /* (1) */
     && p->verifyCksm                       /* (2) */
     && !p->inCkpt                          /* (3) */
    ){
      u8 cksum[8];
      cksmCompute((u8*)zBuf, iAmt-8, cksum);
      if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){
        sqlite3_log(SQLITE_IOERR_DATA,
           "checksum fault offset %lld of \"%s\"",
           iOfst, p->zFName);
Changes to ext/misc/noop.c.
33
34
35
36
37
38
39


















40
41
42
43
44
45
46
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







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







  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  assert( argc==1 );
  sqlite3_result_value(context, argv[0]);
}

/*
** Implementation of the multitype_text() function.
**
** The function returns its argument.  The result will always have a
** TEXT value.  But if the original input is numeric, it will also
** have that numeric value.
*/
static void multitypeTextFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  assert( argc==1 );
  (void)argc;
  (void)sqlite3_value_text(argv[0]);
  sqlite3_result_value(context, argv[0]);
}

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_noop_init(
  sqlite3 *db, 
  char **pzErrMsg, 
60
61
62
63
64
65
66




67
68
78
79
80
81
82
83
84
85
86
87
88
89
90







+
+
+
+


  rc = sqlite3_create_function(db, "noop_do", 1,
                     SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY,
                     0, noopfunc, 0, 0);
  if( rc ) return rc;
  rc = sqlite3_create_function(db, "noop_nd", 1,
                     SQLITE_UTF8,
                     0, noopfunc, 0, 0);
  if( rc ) return rc;
  rc = sqlite3_create_function(db, "multitype_text", 1,
                     SQLITE_UTF8,
                     0, multitypeTextFunc, 0, 0);
  return rc;
}
Changes to ext/misc/randomjson.c.
22
23
24
25
26
27
28

29



30
31



32
33
34
35
36
37
38
22
23
24
25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43







+

+
+
+
-
-
+
+
+







**
**     gcc --shared -fPIC -o randomjson.so -I. ext/misc/randomjson.c
**
** USING FROM THE CLI:
**
**     .load ./randomjson
**     SELECT random_json(1);
**     SELECT random_json5(1);
*/
#ifdef SQLITE_STATIC_RANDOMJSON
#  include "sqlite3.h"
#else
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#  include "sqlite3ext.h"
   SQLITE_EXTENSION_INIT1
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>

/* Pseudo-random number generator */
typedef struct Prng {
  unsigned int x, y;
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
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







-
-
+
+




-
-
+
+



+











-
+





+
+










+
+


-
+

-
+

-
+


-
+

-
-
+




















-
+
+

+


-
+
-
-
-
-


















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


-
+







/* Extract a random number */
static unsigned int prngInt(Prng *p){
  p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001);
  p->y = p->y*1103515245 + 12345;
  return p->x ^ p->y;
}

static const char *azJsonAtoms[] = {
  /* JSON                    /* JSON-5 */
static char *azJsonAtoms[] = {
  /* JSON                    JSON-5 */
  "0",                       "0",
  "1",                       "1",
  "-1",                      "-1",
  "2",                       "+2",
  "3",                       "3",
  "2.5",                     "2.5",
  "3DDDD",                   "3DDDD",
  "2.5DD",                   "2.5DD",
  "0.75",                    ".75",
  "-4.0e2",                  "-4.e2",
  "5.0e-3",                  "+5e-3",
  "6.DDe+0DD",                "6.DDe+0DD",
  "0",                       "0x0",
  "512",                     "0x200",
  "256",                     "+0x100",
  "-2748",                   "-0xabc",
  "true",                    "true",
  "false",                   "false",
  "null",                    "null",
  "9.0e999",                 "Infinity",
  "-9.0e999",                "-Infinity",
  "9.0e999",                 "+Infinity",
  "null",                    "NaN",
  "-0.0005123",              "-0.0005123",
  "-0.0005DD",              "-0.0005DD",
  "4.35e-3",                 "+4.35e-3",
  "\"gem\\\"hay\"",          "\"gem\\\"hay\"",
  "\"icy'joy\"",             "'icy\\'joy\'",
  "\"keylog\"",              "\"key\\\nlog\"",
  "\"mix\\\\\\tnet\"",       "\"mix\\\\\\tnet\"",
  "\"oat\\r\\n\"",           "\"oat\\r\\n\"",
  "\"\\fpan\\b\"",           "\"\\fpan\\b\"",
  "{}",                      "{}",
  "[]",                      "[]",
  "[]",                      "[/*empty*/]",
  "{}",                      "{//empty\n}",
  "\"ask\"",                 "\"ask\"",
  "\"bag\"",                 "\"bag\"",
  "\"can\"",                 "\"can\"",
  "\"day\"",                 "\"day\"",
  "\"end\"",                 "'end'",
  "\"fly\"",                 "\"fly\"",
  "\"\\u00XX\\u00XX\"",      "\"\\xXX\\xXX\"",
  "\"y\\uXXXXz\"",           "\"y\\uXXXXz\"",
  "\"\"",                    "\"\"",
};
static const char *azJsonTemplate[] = {
static char *azJsonTemplate[] = {
  /* JSON                                      JSON-5 */
  "{\"a\":%,\"b\":%,\"c\":%}",                 "{a:%,b:%,c:%}",
  "{\"a\":%,\"b\":%,\"cDD\":%}",               "{a:%,b:%,cDD:%}",
  "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"e\":%}", "{a:%,b:%,c:%,d:%,e:%}",
  "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}",  "{a:%,b:%,c:%,d:%,\"\":%}",
  "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}",  "{a:%,b:%,c:%,d:%,'':%}",
  "{\"d\":%}",                                 "{d:%}",
  "{\"eeee\":%, \"ffff\":%}",                  "{eeee:% /*and*/, ffff:%}",
  "{\"$g\":%,\"_h_\":%}",                      "{$g:%,_h_:%,}",
  "{\"$g\":%,\"_h_\":%,\"a b c d\":%}",        "{$g:%,_h_:%,\"a b c d\":%}",
  "{\"x\":%,\n  \"y\":%}",                     "{\"x\":%,\n  \"y\":%}",
  "{\"a b c d\":%,\"e\":%,\"f\":%,\"x\":%,\"y\":%}",
                                           "{\"a b c d\":%,e:%,f:%,x:%,y:%}",
  "{\"\\u00XX\":%,\"\\uXXXX\":%}",             "{\"\\xXX\":%,\"\\uXXXX\":%}",
  "{\"Z\":%}",                                 "{Z:%,}",
  "[%]",                                       "[%,]",
  "[%,%]",                                     "[%,%]",
  "[%,%,%]",                                   "[%,%,%,]",
  "[%,%,%,%]",                                 "[%,%,%,%]",
  "[%,%,%,%,%]",                               "[%,%,%,%,%]",
};

#define count(X)  (sizeof(X)/sizeof(X[0]))

#define STRSZ 10000

static void jsonExpand(
  const char *zSrc,
  char *zDest,
  Prng *p,
  int eType,            /* 0 for JSON, 1 for JSON5 */
  unsigned int r        /* Growth probability 0..1000.  0 means no growth */
){
  unsigned int i, j, k;
  const char *z;
  char *z;
  char *zX;
  size_t n;
  char zBuf[200];

  j = 0;
  if( zSrc==0 ){
  if( zSrc==0 ) zSrc = "%";
    k = prngInt(p)%(count(azJsonTemplate)/2);
    k = k*2 + eType;
    zSrc = azJsonTemplate[k];
  }
  if( strlen(zSrc)>=STRSZ/10 ) r = 0;
  for(i=0; zSrc[i]; i++){
    if( zSrc[i]!='%' ){
      if( j<STRSZ ) zDest[j++] = zSrc[i];
      continue;
    }
    if( r==0 || (r<1000 && (prngInt(p)%1000)<=r) ){
      /* Fill in without values without any new % */
      k = prngInt(p)%(count(azJsonAtoms)/2);
      k = k*2 + eType;
      z = azJsonAtoms[k];
    }else{
      /* Add new % terms */
      k = prngInt(p)%(count(azJsonTemplate)/2);
      k = k*2 + eType;
      z = azJsonTemplate[k];
    }
    n = strlen(z);
    if( (zX = strstr(z,"XX"))!=0 ){
      unsigned int y = prngInt(p);
      if( (y&0xff)==((y>>8)&0xff) ) y += 0x100;
      while( (y&0xff)==((y>>16)&0xff) || ((y>>8)&0xff)==((y>>16)&0xff) ){
        y += 0x10000;
      }
      memcpy(zBuf, z, n+1);
      z = zBuf;
      zX = strstr(z,"XX");
      while( zX!=0 ){
        zX[0] = "0123456789abcdef"[y%16];  y /= 16;
        zX[1] = "0123456789abcdef"[y%16];  y /= 16;
        zX = strstr(zX, "XX");
      }
    }else if( (zX = strstr(z,"DD"))!=0 ){
      unsigned int y = prngInt(p);
      memcpy(zBuf, z, n+1);
      z = zBuf;
      zX = strstr(z,"DD");
      while( zX!=0 ){
        zX[0] = "0123456789"[y%10];  y /= 10;
        zX[1] = "0123456789"[y%10];  y /= 10;
        zX = strstr(zX, "DD");
      }
    }
    assert( strstr(z, "XX")==0 );
    assert( strstr(z, "DD")==0 );
    if( j+n<STRSZ ){
      memcpy(&zDest[j], z, n);
      j += n;
      j += (int)n;
    }
  }
  zDest[STRSZ-1] = 0;
  if( j<STRSZ ) zDest[j] = 0;
}

static void randJsonFunc(
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
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







-
+









+
+
+

+











  jsonExpand(z2, z1, &prng, eType, 1000);
  jsonExpand(z1, z2, &prng, eType, 100);
  jsonExpand(z2, z1, &prng, eType, 0);
  sqlite3_result_text(context, z1, -1, SQLITE_TRANSIENT);
}

#ifdef _WIN32
__declspec(dllexport)
  __declspec(dllexport)
#endif
int sqlite3_randomjson_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  static int cOne = 1;
  static int cZero = 0;
  int rc = SQLITE_OK;
#ifdef SQLITE_STATIC_RANDOMJSON
  (void)pApi;      /* Unused parameter */
#else
  SQLITE_EXTENSION_INIT2(pApi);
#endif
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "random_json", 1,
                   SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
                   &cZero, randJsonFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "random_json5", 1,
                   SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
                   &cOne, randJsonFunc, 0, 0);
  }
  return rc;
}
Changes to ext/misc/series.c.
99
100
101
102
103
104
105
106
107
108
109








110
111

112
113
114
115


116
117
118
119
120
121
122
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







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

-
+


-
-
+
+








#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Return that member of a generate_series(...) sequence whose 0-based
** index is ix. The 0th member is given by smBase. The sequence members
** progress per ix increment by smStep.
*/
static sqlite3_int64 genSeqMember(sqlite3_int64 smBase,
                                  sqlite3_int64 smStep,
                                  sqlite3_uint64 ix){
  if( ix>=(sqlite3_uint64)LLONG_MAX ){
static sqlite3_int64 genSeqMember(
  sqlite3_int64 smBase,
  sqlite3_int64 smStep,
  sqlite3_uint64 ix
){
  static const sqlite3_uint64 mxI64 =
      ((sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff;
  if( ix>=mxI64 ){
    /* Get ix into signed i64 range. */
    ix -= (sqlite3_uint64)LLONG_MAX;
    ix -= mxI64;
    /* With 2's complement ALU, this next can be 1 step, but is split into
     * 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
    smBase += (LLONG_MAX/2) * smStep;
    smBase += (LLONG_MAX - LLONG_MAX/2) * smStep;
    smBase += (mxI64/2) * smStep;
    smBase += (mxI64 - mxI64/2) * smStep;
  }
  /* Under UBSAN (or on 1's complement machines), must do this last term
   * in steps to avoid the dreaded (and harmless) signed multiply overlow. */
  if( ix>=2 ){
    sqlite3_int64 ix2 = (sqlite3_int64)ix/2;
    smBase += ix2*smStep;
    ix -= ix2;
Changes to ext/misc/totype.c.
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
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







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
















-
+








  /* store the result */
  *pResult = result;

  /* return true if number and no extra non-whitespace chracters after */
  return z>=zEnd && nDigits>0 && eValid && nonNum==0;
}

/* 
** Convert a floating point value to an integer. Or, if this cannot be
** done in a way that avoids 'outside the range of representable values' 
** warnings from UBSAN, return 0.
**
** This function is a modified copy of internal SQLite function
** sqlite3RealToI64().
*/
static sqlite3_int64 totypeDoubleToInt(double r){
  if( r<-9223372036854774784.0 ) return 0;
  if( r>+9223372036854774784.0 ) return 0;
  return (sqlite3_int64)r;
}

/*
** tointeger(X):  If X is any value (integer, double, blob, or string) that
** can be losslessly converted into an integer, then make the conversion and
** return the result.  Otherwise, return NULL.
*/
static void tointegerFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  assert( argc==1 );
  (void)argc;
  switch( sqlite3_value_type(argv[0]) ){
    case SQLITE_FLOAT: {
      double rVal = sqlite3_value_double(argv[0]);
      sqlite3_int64 iVal = (sqlite3_int64)rVal;
      sqlite3_int64 iVal = totypeDoubleToInt(rVal);
      if( rVal==(double)iVal ){
        sqlite3_result_int64(context, iVal);
      }
      break;
    }
    case SQLITE_INTEGER: {
      sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
436
437
438
439
440
441
442
443

444
445
446
447
448
449
450
450
451
452
453
454
455
456

457
458
459
460
461
462
463
464







-
+







    case SQLITE_FLOAT: {
      sqlite3_result_double(context, sqlite3_value_double(argv[0]));
      break;
    }
    case SQLITE_INTEGER: {
      sqlite3_int64 iVal = sqlite3_value_int64(argv[0]);
      double rVal = (double)iVal;
      if( iVal==(sqlite3_int64)rVal ){
      if( iVal==totypeDoubleToInt(rVal) ){
        sqlite3_result_double(context, rVal);
      }
      break;
    }
    case SQLITE_BLOB: {
      const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
      if( zBlob ){
Changes to ext/rbu/sqlite3rbu.c.
195
196
197
198
199
200
201

202
203
204
205
206
207
208
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209







+







typedef struct RbuUpdateStmt RbuUpdateStmt;

#if !defined(SQLITE_AMALGAMATION)
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
#endif

/*
** These values must match the values defined in wal.c for the equivalent
** locks. These are not magic numbers as they are part of the SQLite file
** format.
*/
881
882
883
884
885
886
887

888
889
890
891
892
893
894
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896







+







      if( pIter->bCleanup ){
        rbuObjIterFreeCols(pIter);
        pIter->bCleanup = 0;
        rc = sqlite3_step(pIter->pTblIter);
        if( rc!=SQLITE_ROW ){
          rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg);
          pIter->zTbl = 0;
          pIter->zDataTbl = 0;
        }else{
          pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0);
          pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1);
          rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM;
        }
      }else{
        if( pIter->zIdx==0 ){
2975
2976
2977
2978
2979
2980
2981
2982

2983
2984
2985
2986
2987
2988
2989
2977
2978
2979
2980
2981
2982
2983

2984
2985
2986
2987
2988
2989
2990
2991







-
+







static i64 rbuShmChecksum(sqlite3rbu *p){
  i64 iRet = 0;
  if( p->rc==SQLITE_OK ){
    sqlite3_file *pDb = p->pTargetFd->pReal;
    u32 volatile *ptr;
    p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
    if( p->rc==SQLITE_OK ){
      iRet = ((i64)ptr[10] << 32) + ptr[11];
      iRet = (i64)(((u64)ptr[10] << 32) + ptr[11]);
    }
  }
  return iRet;
}

/*
** This function is called as part of initializing or reinitializing an
Changes to ext/recover/dbdata.c.
578
579
580
581
582
583
584

585
586
587
588
589
590
591
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592







+







          iOff += nPointer;
    
          /* Load the "byte of payload including overflow" field */
          if( bNextPage || iOff>pCsr->nPage ){
            bNextPage = 1;
          }else{
            iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload);
            if( nPayload>0x7fffff00 ) nPayload &= 0x3fff;
          }
    
          /* If this is a leaf intkey cell, load the rowid */
          if( bHasRowid && !bNextPage && iOff<pCsr->nPage ){
            iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
          }
    
Changes to ext/recover/test_recover.c.
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246







-
+







    Tcl_WrongNumArgs(interp, 1, objv, zErr);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, objv[1], &db) ) return TCL_ERROR;
  zDb = Tcl_GetString(objv[2]);
  if( zDb[0]=='\0' ) zDb = 0;

  pNew = ckalloc(sizeof(TestRecover));
  pNew = (TestRecover*)ckalloc(sizeof(TestRecover));
  if( bSql==0 ){
    zUri = Tcl_GetString(objv[3]);
    pNew->p = sqlite3_recover_init(db, zDb, zUri);
  }else{
    pNew->interp = interp;
    pNew->pScript = objv[3];
    Tcl_IncrRefCount(pNew->pScript);
Changes to ext/rtree/rtree.c.
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
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







-
-
-
-
+
+
+
-


















-
+







  return pNode;
}

/*
** Clear the Rtree.pNodeBlob object
*/
static void nodeBlobReset(Rtree *pRtree){
  if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    pRtree->pNodeBlob = 0;
    sqlite3_blob_close(pBlob);
  sqlite3_blob *pBlob = pRtree->pNodeBlob;
  pRtree->pNodeBlob = 0;
  sqlite3_blob_close(pBlob);
  }
}

/*
** Obtain a reference to an r-tree node.
*/
static int nodeAcquire(
  Rtree *pRtree,             /* R-tree structure */
  i64 iNode,                 /* Node number to load */
  RtreeNode *pParent,        /* Either the parent node or NULL */
  RtreeNode **ppNode         /* OUT: Acquired node */
){
  int rc = SQLITE_OK;
  RtreeNode *pNode = 0;

  /* Check if the requested node is already in the hash table. If so,
  ** increase its reference count and return it.
  */
  if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
    if( pParent && pParent!=pNode->pParent ){
    if( pParent && ALWAYS(pParent!=pNode->pParent) ){
      RTREE_IS_CORRUPT(pRtree);
      return SQLITE_CORRUPT_VTAB;
    }
    pNode->nRef++;
    *ppNode = pNode;
    return SQLITE_OK;
  }
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
736
737
738
739
740
741
742

743
744
745
746
747
748
749







-







  }
  if( pRtree->pNodeBlob==0 ){
    rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName,
                           "data", iNode, 0,
                           &pRtree->pNodeBlob);
  }
  if( rc ){
    nodeBlobReset(pRtree);
    *ppNode = 0;
    /* If unable to open an sqlite3_blob on the desired row, that can only
    ** be because the shadow tables hold erroneous data. */
    if( rc==SQLITE_ERROR ){
      rc = SQLITE_CORRUPT_VTAB;
      RTREE_IS_CORRUPT(pRtree);
    }
798
799
800
801
802
803
804

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







+







      nodeHashInsert(pRtree, pNode);
    }else{
      rc = SQLITE_CORRUPT_VTAB;
      RTREE_IS_CORRUPT(pRtree);
    }
    *ppNode = pNode;
  }else{
    nodeBlobReset(pRtree);
    if( pNode ){
      pRtree->nNodeRef--;
      sqlite3_free(pNode);
    }
    *ppNode = 0;
  }

942
943
944
945
946
947
948

949
950
951
952
953
954
955
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954







+







static void nodeGetCoord(
  Rtree *pRtree,               /* The overall R-Tree */
  RtreeNode *pNode,            /* The node from which to extract a coordinate */
  int iCell,                   /* The index of the cell within the node */
  int iCoord,                  /* Which coordinate to extract */
  RtreeCoord *pCoord           /* OUT: Space to write result to */
){
  assert( iCell<NCELL(pNode) );
  readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
}

/*
** Deserialize cell iCell of node pNode. Populate the structure pointed
** to by pCell with the results.
*/
1131
1132
1133
1134
1135
1136
1137

1138


1139
1140
1141
1142
1143
1144
1145
1130
1131
1132
1133
1134
1135
1136
1137

1138
1139
1140
1141
1142
1143
1144
1145
1146







+
-
+
+







  Rtree *pRtree = (Rtree *)(cur->pVtab);
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  assert( pRtree->nCursor>0 );
  resetCursor(pCsr);
  sqlite3_finalize(pCsr->pReadAux);
  sqlite3_free(pCsr);
  pRtree->nCursor--;
  if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
  nodeBlobReset(pRtree);
    nodeBlobReset(pRtree);
  }
  return SQLITE_OK;
}

/*
** Rtree virtual table module xEof method.
**
** Return non-zero if the cursor does not currently point to a valid 
1716
1717
1718
1719
1720
1721
1722



1723


1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740

1741
1742
1743
1744
1745
1746
1747
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726

1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753







+
+
+
-
+
+

















+







*/
static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
  int rc = SQLITE_OK;
  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
  if( rc==SQLITE_OK && ALWAYS(p) ){
    if( p->iCell>=NCELL(pNode) ){
      rc = SQLITE_ABORT;
    }else{
    *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
      *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
    }
  }
  return rc;
}

/* 
** Rtree virtual table module xColumn method.
*/
static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  Rtree *pRtree = (Rtree *)cur->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
  RtreeCoord c;
  int rc = SQLITE_OK;
  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);

  if( rc ) return rc;
  if( NEVER(p==0) ) return SQLITE_OK;
  if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT;
  if( i==0 ){
    sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
  }else if( i<=pRtree->nDim2 ){
    nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
    if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
      sqlite3_result_double(ctx, c.f);
1831
1832
1833
1834
1835
1836
1837


1838
1839
1840
1841
1842
1843
1844
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852







+
+







    pCons->op = RTREE_QUERY;
    pCons->u.xQueryFunc = pBlob->cb.xQueryFunc;
  }
  pCons->pInfo = pInfo;
  return SQLITE_OK;
}

int sqlite3IntFloatCompare(i64,double);

/* 
** Rtree virtual table module xFilter method.
*/
static int rtreeFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
1860
1861
1862
1863
1864
1865
1866
1867


1868
1869
1870
1871
1872
1873
1874
1868
1869
1870
1871
1872
1873
1874

1875
1876
1877
1878
1879
1880
1881
1882
1883







-
+
+







    /* Special case - lookup by rowid. */
    RtreeNode *pLeaf;        /* Leaf on which the required cell resides */
    RtreeSearchPoint *p;     /* Search point for the leaf */
    i64 iRowid = sqlite3_value_int64(argv[0]);
    i64 iNode = 0;
    int eType = sqlite3_value_numeric_type(argv[0]);
    if( eType==SQLITE_INTEGER
     || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid)
     || (eType==SQLITE_FLOAT 
         && 0==sqlite3IntFloatCompare(iRowid,sqlite3_value_double(argv[0])))
    ){
      rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
    }else{
      rc = SQLITE_OK;
      pLeaf = 0;
    }
    if( rc==SQLITE_OK && pLeaf!=0 ){
3216
3217
3218
3219
3220
3221
3222
3223

3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235



3236
3237
3238
3239
3240
3241
3242
3225
3226
3227
3228
3229
3230
3231

3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254







-
+












+
+
+








/*
** Called when a transaction starts.
*/
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
  Rtree *pRtree = (Rtree *)pVtab;
  assert( pRtree->inWrTrans==0 );
  pRtree->inWrTrans++;
  pRtree->inWrTrans = 1;
  return SQLITE_OK;
}

/*
** Called when a transaction completes (either by COMMIT or ROLLBACK).
** The sqlite3_blob object should be released at this point.
*/
static int rtreeEndTransaction(sqlite3_vtab *pVtab){
  Rtree *pRtree = (Rtree *)pVtab;
  pRtree->inWrTrans = 0;
  nodeBlobReset(pRtree);
  return SQLITE_OK;
}
static int rtreeRollback(sqlite3_vtab *pVtab){
  return rtreeEndTransaction(pVtab);  
}

/*
** The xRename method for rtree module virtual tables.
*/
static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
  Rtree *pRtree = (Rtree *)pVtab;
3348
3349
3350
3351
3352
3353
3354
3355

3356
3357
3358
3359
3360
3361
3362
3360
3361
3362
3363
3364
3365
3366

3367
3368
3369
3370
3371
3372
3373
3374







-
+







  rtreeEof,                   /* xEof */
  rtreeColumn,                /* xColumn - read data */
  rtreeRowid,                 /* xRowid - read data */
  rtreeUpdate,                /* xUpdate - write data */
  rtreeBeginTransaction,      /* xBegin - begin transaction */
  rtreeEndTransaction,        /* xSync - sync transaction */
  rtreeEndTransaction,        /* xCommit - commit transaction */
  rtreeEndTransaction,        /* xRollback - rollback transaction */
  rtreeRollback,              /* xRollback - rollback transaction */
  0,                          /* xFindFunction - function overloading */
  rtreeRename,                /* xRename - rename the table */
  rtreeSavepoint,             /* xSavepoint */
  0,                          /* xRelease */
  0,                          /* xRollbackTo */
  rtreeShadowName,            /* xShadowName */
  rtreeIntegrity              /* xIntegrity */
3448
3449
3450
3451
3452
3453
3454
3455

3456
3457
3458
3459
3460
3461
3462
3460
3461
3462
3463
3464
3465
3466

3467
3468
3469
3470
3471
3472
3473
3474







-
+







    if( zSql ){
      rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0); 
    }else{
      rc = SQLITE_NOMEM;
    }
    sqlite3_free(zSql);
  }
  if( pRtree->nAux ){
  if( pRtree->nAux && rc!=SQLITE_NOMEM ){
    pRtree->zReadAuxSql = sqlite3_mprintf(
       "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
       zDb, zPrefix);
    if( pRtree->zReadAuxSql==0 ){
      rc = SQLITE_NOMEM;
    }else{
      sqlite3_str *p = sqlite3_str_new(db);
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151







4152
4153
4154
4155
4156
4157
4158
4159
4149
4150
4151
4152
4153
4154
4155








4156
4157
4158
4159
4160
4161
4162

4163
4164
4165
4166
4167
4168
4169







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







  /* Initialize the context object */
  memset(&check, 0, sizeof(check));
  check.db = db;
  check.zDb = zDb;
  check.zTab = zTab;

  /* Find the number of auxiliary columns */
  if( check.rc==SQLITE_OK ){
    pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
    if( pStmt ){
      nAux = sqlite3_column_count(pStmt) - 2;
      sqlite3_finalize(pStmt);
    }else 
    if( check.rc!=SQLITE_NOMEM ){
      check.rc = SQLITE_OK;
  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
  if( pStmt ){
    nAux = sqlite3_column_count(pStmt) - 2;
    sqlite3_finalize(pStmt);
  }else 
  if( check.rc!=SQLITE_NOMEM ){
    check.rc = SQLITE_OK;
    }
  }

  /* Find number of dimensions in the rtree table. */
  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
  if( pStmt ){
    int rc;
    check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;
4200
4201
4202
4203
4204
4205
4206

4207
4208
4209
4210
4211
4212
4213
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224







+







  UNUSED_PARAMETER(zSchema);
  UNUSED_PARAMETER(zName);
  UNUSED_PARAMETER(isQuick);
  rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr);
  if( rc==SQLITE_OK && *pzErr ){
    *pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z",
                 pRtree->zDb, pRtree->zName, *pzErr);
    if( (*pzErr)==0 ) rc = SQLITE_NOMEM;
  }
  return rc;
}

/*
** Usage:
**
Changes to ext/rtree/rtree1.test.
792
793
794
795
796
797
798


















799
800
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







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


#
reset_db
do_test 23.0 {
  db eval {CREATE TABLE t1(a,b,c);}
  catch {db eval {CREATE TABLE t2 AS SELECT rtreecheck('t1') AS y;}}
  db eval {PRAGMA integrity_check;}
} {ok}

reset_db
do_execsql_test 24.0 {
  CREATE VIRTUAL TABLE rt1 USING rtree_i32(rid, c1, c2);
  INSERT INTO rt1(rid, c1, c2) VALUES (9223372036854775807, 10, 18);
}

do_execsql_test 24.1 {
  SELECT (rid = (CAST (9223372036854775807 AS REAL)))
  FROM rt1 WHERE
         (rid = (CAST (9223372036854775807 AS REAL)));
}

do_execsql_test 24.2 {
  DELETE FROM rt1;
  INSERT INTO rt1(rid, c1, c2) VALUES(1,2,3);
  SELECT * FROM rt1 WHERE rid=1.005;
} {}

finish_test
Added ext/rtree/rtreeJ.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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024-02-03
#
# 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.
#
#***********************************************************************
# 
# ROLLBACK in the middle of an RTREE query
#
if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
} 
source $testdir/tester.tcl
set testprefix rtreeJ
ifcapable !rtree { finish_test ; return }

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2);
  INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2);
} {}

do_execsql_test 1.1 {
  SELECT * FROM t1
} {1 1.0 1.0 2 2.0 2.0}

# If a ROLLBACK occurs that backs out changes to the RTREE, then
# all pending queries to the RTREE are aborted.
#
do_test 1.2 {
  db eval {
    BEGIN;
      INSERT INTO t1 VALUES(3, 3, 3);
      INSERT INTO t1 VALUES(4, 4, 4);
  }
  set rc [catch {
    db eval { SELECT * FROM t1 } {
      if {$id==1} {
        db eval { ROLLBACK }
      }
      lappend res $id $x1 $x2
    }
  } msg]
  list $rc $msg
} {1 {query aborted}}

do_execsql_test 1.3 {
  SELECT * FROM t1;
} {1 1.0 1.0 2 2.0 2.0}

# A COMMIT of changes to the RTREE does not affect pending queries
#
do_test 1.4 {
  set res {}
  db eval {
    BEGIN;
      INSERT INTO t1 VALUES(5, 5, 5);
      INSERT INTO t1 VALUES(6, 6, 6);
  }
  db eval { SELECT * FROM t1 } {
    if {$id==1} {
      db eval { COMMIT }
    }
    lappend res $id $x1 $x2
  }
  set res
} {1 1.0 1.0 2 2.0 2.0 5 5.0 5.0 6 6.0 6.0}

do_execsql_test 1.5 {
  SELECT * FROM t1;
} {1 1.0 1.0 2 2.0 2.0 5 5.0 5.0 6 6.0 6.0}

do_execsql_test 1.6 {
  DELETE  FROM t1;
  INSERT INTO t1 VALUES(1,1,1),(2,2,2),(3,3,3),(4,4,4);
  CREATE TABLE t2(x);
  SELECT * FROM t1;
} {1 1.0 1.0 2 2.0 2.0 3 3.0 3.0 4 4.0 4.0}

# A rollback that does not affect the rtree table because
# the rtree table has not been written to does not cause
# a query abort.
#
do_test 1.7 {
  set res {}
  db eval {
    BEGIN;
    INSERT INTO t2(x) VALUES(12345);
  }
  db eval { SELECT * FROM t1 } {
    if {$id==1} {
      db eval { ROLLBACK }
    }
    lappend res $id $x1 $x2
  }
  set res
} {1 1.0 1.0 2 2.0 2.0 3 3.0 3.0 4 4.0 4.0}

# ROLLBACK TO that affects the RTREE does cause a query abort.
#
do_test 1.8 {
  db eval {
    DELETE FROM t1 WHERE rowid>1;
    BEGIN;
    DELETE FROM t2;
    INSERT INTO t2(x) VALUES(23456);
    SAVEPOINT 'one';
    INSERT INTO t1 VALUES(2,2,2),(3,3,3);
  }
  set rc [catch {
    db eval { SELECT * FROM t1 } {
      if {$id==1} {
        db eval { ROLLBACK TO 'one'; }
      }
      lappend res $id $x1 $x2
    }
  } msg]
  list $rc $msg
} {1 {query aborted}}

do_execsql_test 1.9 {
  COMMIT;
  SELECT * FROM t1;
} {1 1.0 1.0}

# ROLLBACK TO that does not affect the RTREE does not cause a query abort.
#
do_execsql_test 1.10 {
  DELETE FROM t1;
  INSERT INTO t1 VALUES(1,1,1),(2,2,2),(3,3,3);
  BEGIN;
  DELETE FROM t2;
  INSERT INTO t2(x) VALUES(34567);
  SAVEPOINT 'one';
  INSERT INTO t2(x) VALUES('a string');
  SELECT * FROM t1;
} {1 1.0 1.0 2 2.0 2.0 3 3.0 3.0}
do_test 1.11 {
  set rc [catch {
    set res {}
    db eval { SELECT * FROM t1 } {
      if {$id==2} {
        # db eval { ROLLBACK TO 'one'; }
      }
      lappend res $id $x1 $x2
    }
    set res
  } msg]
  list $rc $msg
} {0 {1 1.0 1.0 2 2.0 2.0 3 3.0 3.0}}

do_execsql_test 1.12 {
  COMMIT;
  SELECT * FROM t1;
} {1 1.0 1.0 2 2.0 2.0 3 3.0 3.0}

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

reset_db
do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2);
  INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2);
  CREATE TABLE t2(x);
} {}

do_test 2.1 {
  db eval {
    BEGIN;
    INSERT INTO t1 VALUES(3, 3, 3);
    PRAGMA writable_schema = RESET;
  }

  set rc [catch {
    db eval { SELECT x1, x2 FROM t1 } {
      if {$x1==1} {
        db eval { ROLLBACK }
      }
      lappend res $x1 $x2
    }
  } msg]
  list $rc $msg
}  {1 {query aborted}}

do_execsql_test 2.1 {
  CREATE TABLE bak_node(nodeno, data);
  CREATE TABLE bak_parent(nodeno, parentnode);
  CREATE TABLE bak_rowid(rowid, nodeno);
}
proc save_t1 {} {
  db eval {
    DELETE FROM bak_node;
    DELETE FROM bak_parent;
    DELETE FROM bak_rowid;
    INSERT INTO bak_node SELECT * FROM t1_node;
    INSERT INTO bak_parent SELECT * FROM t1_parent;
    INSERT INTO bak_rowid SELECT * FROM t1_rowid;
  }
}
proc restore_t1 {} {
  db eval {
    DELETE FROM t1_node;
    DELETE FROM t1_parent;
    DELETE FROM t1_rowid;
    INSERT INTO t1_node SELECT * FROM bak_node;
    INSERT INTO t1_parent SELECT * FROM bak_parent;
    INSERT INTO t1_rowid SELECT * FROM bak_rowid;
  }
}

do_test 2.3 {
  save_t1
  db eval {
    INSERT INTO t1 VALUES(3, 3, 3);
  }
  set rc [catch {
    db eval { SELECT rowid, x1, x2 FROM t1 } {
      if {$x1==1} {
        restore_t1
      }
      lappend res $x1 $x2
    }
  } msg]
  list $rc $msg
}  {1 {query aborted}}
do_execsql_test 2.4 {
  SELECT * FROM t1
} {1 1.0 1.0 2 2.0 2.0}

do_test 2.5 {
  save_t1
  db eval {
    INSERT INTO t1 VALUES(3, 3, 3);
  }
  set rc [catch {
    db eval { SELECT x1 FROM t1 } {
      if {$x1==1} {
        restore_t1
      }
      lappend res $x1 $x2
    }
  } msg]
  list $rc $msg
}  {1 {query aborted}}
do_execsql_test 2.6 {
  SELECT * FROM t1
} {1 1.0 1.0 2 2.0 2.0}

do_test 2.7 {
  save_t1
  db eval {
    INSERT INTO t1 VALUES(3, 3, 3);
  }
  set ::res [list]
  set rc [catch {
    db eval { SELECT 'abc' FROM t1 } {
      if {$::res==[list]} {
        restore_t1
        set ::bDone 1
      }
      lappend res abc
    }
  } msg]
  set res
} {abc abc abc}
do_execsql_test 2.6 {
  SELECT * FROM t1
} {1 1.0 1.0 2 2.0 2.0}


finish_test
Changes to ext/session/sessionstat1.test.
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
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







-
+











-
+







    )
    INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
    ANALYZE;
  }
} {}

do_execsql_test -db db2 2.2 {
  SELECT * FROM sqlite_stat1
  SELECT * FROM sqlite_stat1 ORDER BY tbl, idx
} {
  t1 sqlite_autoindex_t1_1 {32 1} 
  t1 t1b {32 4} 
  t1 t1c {32 16}
}

do_test 2.3 {
  do_then_apply_sql -ignorenoop { DROP INDEX t1c }
} {}

do_execsql_test -db db2 2.4 {
  SELECT * FROM sqlite_stat1
  SELECT * FROM sqlite_stat1 ORDER BY tbl, idx;
} {
  t1 sqlite_autoindex_t1_1 {32 1} 
  t1 t1b {32 4} 
}

do_test 2.3 {
  do_then_apply_sql -ignorenoop { DROP TABLE t1 }
Changes to ext/session/sqlite3session.c.
2344
2345
2346
2347
2348
2349
2350
2351
2352

2353
2354
2355
2356
2357
2358
2359
2360
2344
2345
2346
2347
2348
2349
2350


2351

2352
2353
2354
2355
2356
2357
2358







-
-
+
-







  sqlite3_mutex_leave(sqlite3_db_mutex(db));
  sqlite3ValueFree(pSession->pZeroBlob);

  /* Delete all attached table objects. And the contents of their 
  ** associated hash-tables. */
  sessionDeleteTable(pSession, pSession->pTable);

  /* Assert that all allocations have been freed and then free the 
  ** session object itself. */
  /* Free the session object. */
  // assert( pSession->nMalloc==0 );
  sqlite3_free(pSession);
}

/*
** Set a table filter on a Session Object.
*/
void sqlite3session_table_filter(
Changes to ext/userauth/user-auth.txt.












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







*********************************** NOTICE ************************************
* This extension is deprecated. The SQLite developers do not maintain this    *
* extension. At some point in the future, it might disappear from the source  *
* tree.                                                                       *
*                                                                             *
* If you are using this extension and think it should be supported moving     *
* forward, visit the SQLite Forum (https://sqlite.org/forum) and argue your   *
* case there.                                                                 *
*                                                                             *
* This deprecation notice was added on 2024-01-22.                            *
*******************************************************************************

Activate the user authentication logic by including the
ext/userauth/userauth.c source code file in the build and
adding the -DSQLITE_USER_AUTHENTICATION compile-time option.
The ext/userauth/sqlite3userauth.h header file is available to
applications to define the interface.

When using the SQLite amalgamation, it is sufficient to append
Changes to ext/wasm/GNUmakefile.
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
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







-
+
+
+
+








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

+
+







#
# Significant TODOs for this build include, but are not necessarily
# limited to:
#
# 1) Consolidate the code generation for sqlite3*.*js into a script
#    which generates the makefile code, rather than using $(call) and
#    $(eval), or at least centralize the setup of the numerous vars
#    related to each build variant $(JS_BUILD_MODES).
#    related to each build variant $(JS_BUILD_MODES). (Update: an
#    external script was attempted but generating properly-escaped
#    makefile code from within a shell script is even less legible
#    than the $(eval) indirection going on in this file.)
#
default: all
#default: quick
SHELL := $(shell which bash 2>/dev/null)
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CLEAN_FILES :=
DISTCLEAN_FILES := ./--dummy--
release: oz
# JS_BUILD_MODES exists solely to reduce repetition in documentation
# below.

########################################################################
# JS_BUILD_NAMES exists for documentation purposes only. It enumerates
# the core build styles:
#
# - sqlite3 = canonical library build
#
# - sqlite3-wasmfs = WASMFS-capable library build
#
JS_BUILD_NAMES := sqlite3 sqlite3-wasmfs

########################################################################
# JS_BUILD_MODES exists for documentation purposes only. It enumerates
# the various "flavors" of build, each of which requires slight
# customization of the output:
#
# - vanilla = plain-vanilla JS for use in browsers. This is the
#   canonical build mode.
#
# - esm = ES6 module, a.k.a. ESM, for use in browsers.
#
# - bundler-friendly = esm slightly tweaked for "bundler"
#   tools. Bundlers are invariably based on node.js, so these builds
#   are intended to be read at build-time by node.js but with a final
#   target of browsers.
#
# - node = for use by node.js for node.js, as opposed to by node.js on
#   behalf o browser-side code (use bundler-friendly for that). Note
#   that persistent storage (OPFS) is not available in these builds.
#
JS_BUILD_MODES := vanilla esm bunder-friendly node

########################################################################
# Emscripten SDK home dir and related binaries...
EMSDK_HOME ?= $(word 1,$(wildcard $(HOME)/emsdk $(HOME)/src/emsdk))
emcc.bin ?= $(word 1,$(wildcard $(EMSDK_HOME)/upstream/emscripten/emcc) $(shell which emcc))
ifeq (,$(emcc.bin))
  $(error Cannot find emcc.)
endif
emcc.version := $(shell "$(emcc.bin)" --version | sed -n 1p \
89
90
91
92
93
94
95



96
97
98
99
100




101
102
103
104
105
106
107
122
123
124
125
126
127
128
129
130
131
132




133
134
135
136
137
138
139
140
141
142
143







+
+
+

-
-
-
-
+
+
+
+








ifeq (,$(wasm-strip))
  maybe-wasm-strip = echo "not wasm-stripping"
else
  maybe-wasm-strip = $(wasm-strip)
endif

########################################################################
# dir.top = the top dir of the canonical build tree, where
# sqlite3.[ch] live.
dir.top := ../..
# Reminder: some Emscripten flags require absolute paths but we want
# relative paths for most stuff simply to reduce noise. The
# $(abspath...) GNU make function can transform relative paths to
# absolute.
# Maintenance reminder: some Emscripten flags require absolute paths
# but we want relative paths for most stuff simply to reduce
# noise. The $(abspath...) GNU make function can transform relative
# paths to absolute.
dir.wasm := $(patsubst %/,%,$(dir $(MAKEFILE)))
dir.api := api
dir.jacc := jaccwabyt
dir.common := common
dir.fiddle := fiddle
dir.tool := $(dir.top)/tool
CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~
139
140
141
142
143
144
145
146
147
148
149
150
151








152
153
154
155
156
157
158
175
176
177
178
179
180
181






182
183
184
185
186
187
188
189
190
191
192
193
194
195
196







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







  dir._tmp := $(shell mkdir -p $(dir.tmp))
endif

########################################################################
# Set up sqlite3.c and sqlite3.h...
#
# To build with SEE (https://sqlite.org/see), either put sqlite3-see.c
# in the top of this build tree or pass
# sqlite3.c=PATH_TO_sqlite3-see.c to the build. Note that only
# encryption modules with no 3rd-party dependencies will currently
# work here: AES256-OFB, AES128-OFB, and AES128-CCM. Not
# coincidentally, those 3 modules are included in the sqlite3-see.c
# bundle.
# in $(dir.top) or pass sqlite3.c=PATH_TO_sqlite3-see.c to the $(MAKE)
# invocation. Note that only encryption modules with no 3rd-party
# dependencies will currently work here: AES256-OFB, AES128-OFB, and
# AES128-CCM. Not coincidentally, those 3 modules are included in the
# sqlite3-see.c bundle. Note, however, that distributing an SEE build
# of the WASM on a public site is in violation of the SEE license
# because it effectively provides a usable copy of the SEE build to
# all visitors.
#
# A custom sqlite3.c must not have any spaces in its name.
# $(sqlite3.canonical.c) must point to the sqlite3.c in
# the sqlite3 canonical source tree, as that source file
# is required for certain utility and test code.
sqlite3.canonical.c := $(dir.top)/sqlite3.c
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
189
190
191
192
193
194
195




196
197
198
199
200
201
202
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244







+
+
+
+







#SQLITE_OPT += -DSQLITE_DEBUG
# Enabling SQLITE_DEBUG will break sqlite3_wasm_vfs_create_file()
# (and thus sqlite3_js_vfs_create_file()). Those functions are
# deprecated and alternatives are in place, but this crash behavior
# can be used to find errant uses of sqlite3_js_vfs_create_file()
# in client code.

########################################################################@
# It's important that sqlite3.h be built to completion before any
# other parts of the build run, thus we use .NOTPARALLEL to disable
# parallel build of that file and its dependants.
.NOTPARALLEL: $(sqlite3.h)
$(sqlite3.h):
	$(MAKE) -C $(dir.top) sqlite3.c
$(sqlite3.c): $(sqlite3.h)

.PHONY: clean distclean
clean:
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
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







+









+




-
+







-
-
+
+
+







sqlite3_wasm_extra_init.c ?= $(wildcard sqlite3_wasm_extra_init.c)
cflags.wasm_extra_init :=
ifneq (,$(sqlite3_wasm_extra_init.c))
  $(info Enabling SQLITE_EXTRA_INIT via $(sqlite3_wasm_extra_init.c).)
  cflags.wasm_extra_init := -DSQLITE_WASM_EXTRA_INIT
endif

#########################################################################
# bin.version-info = binary to output various sqlite3 version info for
# embedding in the JS files and in building the distribution zip file.
# It must NOT be in $(dir.tmp) because we need it to survive the
# cleanup process for the dist build to work properly.
bin.version-info := $(dir.top)/version-info
.NOTPARALLEL: $(bin.version-info)
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
	$(MAKE) -C $(dir.top) version-info

#########################################################################
# bin.stripcomments is used for stripping C/C++-style comments from JS
# files. The JS files contain large chunks of documentation which we
# don't need for all builds. That app's -k flag is of particular
# importance here, as it allows us to retain the opening comment
# blocks, which contain the license header and version info.
# block(s), which contain the license header and version info.
bin.stripccomments := $(dir.tool)/stripccomments
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
	$(CC) -o $@ $<
DISTCLEAN_FILES += $(bin.stripccomments)


########################################################################
# C-PP.FILTER: a $(call)able to transform $(1) to $(2) via ./c-pp -f
# $(1) ...
# C-PP.FILTER: a $(call)able to transform $(1) to $(2) via:
#
#   ./c-pp -f $(1) -o $(2) $(3)
#
# Historical notes:
#
# - We first attempted to use gcc and/or clang to preprocess JS files
#   in the same way we would normally do C files, but C-specific quirks
#   of each makes that untennable.
#
283
284
285
286
287
288
289



290
291
292
293
294
295
296
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344







+
+
+







#   preprocessing, would be to have separate source files for ES6
#   builds, which would have a higher maintenance burden than c-pp.c
#   seems likely to.
#
# c-pp.c was written specifically for the sqlite project's JavaScript
# builds but is maintained as a standalone project:
# https://fossil.wanderinghorse.net/r/c-pp
#
# Note that the SQLITE_... build flags used here have NO EFFECT on the
# JS/WASM build. They are solely for use with $(bin.c-pp) itself.
bin.c-pp := ./c-pp
$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
	$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
		-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_UTF16 \
		-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_WAL -DSQLITE_THREADSAFE=0 \
		-DSQLITE_TEMP_STORE=3
define C-PP.FILTER
343
344
345
346
347
348
349

350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365
366
367
368
369
370
371
372

373


374
375

376

377

378

379

380




381

382



383
384

385
386


387
388




389

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

438
439
440
441
442
443
444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
459

460
461
462
463



464
465
466
467
468
469
470







+











+












+

+
+


+

+

+

+

+
-
+
+
+
+

+

+
+
+


+

-
+
+


+
+
+
+
-
+



-
-
-







# difficult to say whether -Os gives any speed benefit over -Oz.
#
# Much practice has demonstrated that -O2 consistently gives the best
# runtime speeds, but not by a large enough factor to rule out use of
# -Oz when small deliverable size is a priority.
########################################################################

########################################################################
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
# -sEXPORTED_FUNCTION flag.
EXPORTED_FUNCTIONS.api.main := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api)
EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.main)
ifeq (1,$(SQLITE_C_IS_SEE))
  EXPORTED_FUNCTIONS.api.in += $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see)
endif
EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
	cat $(EXPORTED_FUNCTIONS.api.in) > $@

########################################################################
# sqlite3-license-version.js = generated JS file with the license
# header and version info.
sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js
# sqlite3-license-version-header.js = JS file containing only the
# license header.
sqlite3-license-version-header.js := $(dir.api)/sqlite3-license-version-header.js
# sqlite3-api-build-version.js = generated JS file which populates the
# sqlite3.version object using $(bin.version-info).
sqlite3-api-build-version.js := $(dir.tmp)/sqlite3-api-build-version.js
# sqlite3-api.jses = the list of JS files which make up
# $(sqlite3-api.js.in), in the order they need to be assembled.
sqlite3-api.jses := $(sqlite3-license-version.js)
# sqlite3-api-prologue.js: initial boostrapping bits:
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
# whwhasm.js and jaccwabyt.js: Low-level utils, mostly replacing
# Emscripten glue:
sqlite3-api.jses += $(dir.common)/whwasmutil.js
sqlite3-api.jses += $(dir.jacc)/jaccwabyt.js
# sqlite3-api-glue.js Glues the previous part together:
sqlite3-api.jses += $(dir.api)/sqlite3-api-glue.js
# $(sqlite3-api-build-version.js) = library version info
sqlite3-api.jses += $(sqlite3-api-build-version.js)
# sqlite3-api-oo1.js = the oo1 API:
sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.js
# sqlite3-api-worker.js = the Worker1 API:
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js
# sqlite3-vfs-helper = helper APIs for VFSes:
sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js
# sqlite3-vtab-helper = helper APIs for VTABLEs:
sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js
# sqlite3-vfs-opfs.c-pp.js = the first OPFS VFS:
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
# sqlite3-vfs-opfs-sahpool.c-pp.js = the second OPFS VFS:
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
# sqlite3-api-cleanup.js = "finalizes" the build and cleans up
# any extraneous global symbols which are needed temporarily
# by the previous files.
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js

########################################################################
# SOAP.js is an external API file which is part of our distribution
# but not part of the sqlite3-api.js amalgamation.
# but not part of the sqlite3-api.js amalgamation. It's a component of
# the first OPFS VFS and necessarily an external file.
SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
SOAP.js.bld := $(dir.dout)/$(notdir $(SOAP.js))
#
# $(sqlite3-api.ext.jses) = API-related files which are standalone files,
#   not part of the amalgamation.
#
sqlite3-api.ext.jses += $(SOAP.js.bld)
sqlite3-api.ext.jses := $(SOAP.js.bld)
$(SOAP.js.bld): $(SOAP.js)
	cp $< $@

all quick: $(sqlite3-api.ext.jses)
q: quick

########################################################################
# $(sqlite3-api*.*js) contain the core library code but not the
# Emscripten-related glue which deals with loading sqlite3.wasm. In
# theory they can be used by arbitrary build environments and WASM
# loaders, but in practice that breaks down because the WASM loader
# has to be able to provide all of the necessary "imports" to
# sqlite3.wasm, and that list of imports is unknown until sqlite3.wasm
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
502
503
504
505
506
507
508

509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531

532
533
534
535
536
537
538
539
540
541
542
543
544

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







-
+
+
+




















-
+
+
+
+
+
+
+






-
+














+
+
+
+
+







# -v is _very_ loud but also informative about what it's doing
endif

########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
emcc.cflags += -std=c99 -fPIC
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c).
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c), primarily
# for variadic macros and snprintf() to implement
# sqlite3_wasm_enum_json().
emcc.cflags += -I. -I$(dir.top)
########################################################################
# emcc flags specific to building .js/.wasm files...
emcc.jsflags := -fPIC
emcc.jsflags += --minify 0
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE
emcc.jsflags += -sDYNAMIC_EXECUTION=0
emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
    -sEXPORTED_RUNTIME_METHODS=wasmMemory
    # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY
emcc.jsflags += -sSTRICT_JS=0
# STRICT_JS disabled due to:
#   https://github.com/emscripten-core/emscripten/issues/18610
# TL;DR: does not work with MODULARIZE or EXPORT_ES6 as of version 3.1.31.
# TL;DR: does not work with MODULARIZE or EXPORT_ES6 as of version
# 3.1.31.  The fix for that in newer emcc's is to throw a built-time
# error if STRICT_JS is used together with those options.

# emcc.jsflags += -sSTRICT=1
# -sSTRICT=1 Causes failures about unknown symbols which the build
# tools should be installing, e.g. __syscall_geteuid32

# -sENVIRONMENT values for the various build modes:
emcc.environment.vanilla := web,worker
emcc.environment.bundler-friendly := $(emcc.environment.vanilla)
emcc.environment.esm := $(emcc.environment.vanilla)
emcc.environment.node := node
# Note that adding "node" to the list for the other builds causes
# Note that adding ",node" to the list for the other builds causes
# Emscripten to generate code which confuses node: it cannot reliably
# determine whether the build is for a browser or for node.

########################################################################
# -sINITIAL_MEMORY: How much memory we need to start with is governed
# at least in part by whether -sALLOW_MEMORY_GROWTH is enabled. If so,
# we can start with less. If not, we need as much as we'll ever
# possibly use (which, of course, we can't know for sure).  Note,
# however, that speedtest1 shows that performance for even moderate
# workloads MAY suffer considerably if we start small and have to grow
# at runtime. e.g. OPFS-backed (speedtest1 --size 75) take MAY take X
# time with 16mb+ memory and 3X time when starting with 8MB. However,
# such test results are inconsistent due to browser internals which
# are opaque to us.
#
# 2024-03-04: emsdk 3.1.55 replaces INITIAL_MEMORY with INITIAL_HEAP,
# but also says (in its changelog): "Note that it is currently not
# supported in all configurations (#21071)."
# https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md
emcc.jsflags += -sALLOW_MEMORY_GROWTH
emcc.INITIAL_MEMORY.128 := 134217728
emcc.INITIAL_MEMORY.96  := 100663296
emcc.INITIAL_MEMORY.64  := 67108864
emcc.INITIAL_MEMORY.32  := 33554432
emcc.INITIAL_MEMORY.16  := 16777216
emcc.INITIAL_MEMORY.8   := 8388608
514
515
516
517
518
519
520

521

522
523
524
525
526
527

528
529
530
531
532
533
534
595
596
597
598
599
600
601
602

603
604
605
606
607
608

609
610
611
612
613
614
615
616







+
-
+





-
+







#
# That said... we can change $(sqlite3.js.init-func) as long as the
# name "sqlite3InitModule" is the one which gets exposed via the
# resulting JS files. That can be accomplished via
# extern-post-js.js. However...  using a temporary symbol name here
# and then adding sqlite3InitModule() ourselves results in 2 global
# symbols: we cannot "delete" the Emscripten-defined
# $(sqlite3.js.init-func) from vanilla builds (as opposed to ESM
# $(sqlite3.js.init-func) because it's declared with "var".
# builds) because it's declared with "var".
sqlite3.js.init-func := sqlite3InitModule
emcc.jsflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.jsflags += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
#emcc.jsflags += -sSTRICT # fails due to missing __syscall_...()
#emcc.jsflags += -sALLOW_UNIMPLEMENTED_SYSCALLS
#emcc.jsflags += -sFILESYSTEM=0 # only for experimentation. sqlite3 needs the FS API
#emcc.jsflags += -sFILESYSTEM=0 # only for experimentation. fiddle needs the FS API
#emcc.jsflags += -sABORTING_MALLOC # only for experimentation
emcc.jsflags += -sALLOW_TABLE_GROWTH
# ^^^^ -sALLOW_TABLE_GROWTH is required for installing new SQL UDFs
emcc.jsflags += -Wno-limited-postlink-optimizations
# ^^^^ emcc likes to warn when we have "limited optimizations" via the
# -g3 flag.
# emcc.jsflags += -sSTANDALONE_WASM # causes OOM errors, not sure why.
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
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
646
647
648
649
650
651
652
653
654
655
656
657
658





659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678


679
680
681
682
683
684
685
686
687
688

689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710


711
712
713
714
715
716
717
718
719
720
721
722
723
724
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







+
+
+



-
-
-
-
-
+
+
+
+
+

+
+
+
+
+
+
+







-
-
+
+








-
+
+
+
+
+

















-
-
+
+






+
+
+
+
+
+


+
-
-
+
+
+










-
-
+
+







-
+


-
+







# -sSINGLE_FILE=1 would be _really_ nice but we have to build with -g3
# for -O2 and higher to work (else minification breaks the code) and
# cannot wasm-strip the binary before it gets encoded into the JS
# file. The result is that the generated JS file is, because of the
# -g3 debugging info, _huge_.
########################################################################

########################################################################
# $(sqlite3-api-build-version.js) injects the build version info into
# the bundle in JSON form.
$(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
	@echo "Making $@..."
	@{ \
  echo 'globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \
	echo -n '  sqlite3.version = '; \
  $(bin.version-info) --json; \
  echo ';'; \
	echo '});'; \
    echo 'globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \
    echo -n '  sqlite3.version = '; \
    $(bin.version-info) --json; \
    echo ';'; \
    echo '});'; \
  } > $@

########################################################################
# $(sqlite3-license-version.js) contains the license header and
# in-comment build version info.
#
# Maintenance reminder: there are awk binaries out there which do not
# support -e SCRIPT.
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) \
  $(MAKEFILE)
	@echo "Making $@..."; { \
    cat $(sqlite3-license-version-header.js); \
    echo '/*'; \
    echo '** This code was built from sqlite3 version...'; \
    echo "**"; \
    awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
        -e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
    awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
    awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
    echo "**"; \
    echo "** Using the Emscripten SDK version $(emcc.version)."; \
    echo '*/'; \
   } > $@

########################################################################
# --post-js and --pre-js are emcc flags we use to append/prepend JS to
# the generated emscripten module file. These rules set up the core
# pre/post files for use by the various builds.
# pre/post files for use by the various builds. --pre-js is used to
# inject code which needs to run as part of the pre-WASM-load phase.
# --post-js injects code which runs after the WASM module is loaded
# and includes the entirety of the library plus some
# Emscripten-specific post-bootstrapping code.
pre-js.js.in := $(dir.api)/pre-js.c-pp.js
post-js.js.in := $(dir.tmp)/post-js.c-pp.js
post-jses.js := \
  $(dir.api)/post-js-header.js \
  $(sqlite3-api.js.in) \
  $(dir.api)/post-js-footer.js
$(post-js.js.in): $(post-jses.js) $(MAKEFILE)
	@echo "Making $@..."
	@for i in $(post-jses.js); do \
		echo "/* BEGIN FILE: $$i */"; \
		cat $$i; \
		echo "/* END FILE: $$i */"; \
	done > $@


########################################################################
# call-make-pre-post is a $(call)able which creates rules for
# pre-js-$(1)-$(2).js. $1 = the base name of the JS file on whose
# behalf this pre-js is for (one of: sqlite3, sqlite3-wasmfs). $2 is
# pre-js.$(1)-$(2).js. $1 = the base name of the JS file on whose
# behalf this pre-js is for (one of: $(JS_BUILD_NAMES)). $2 is
# the build mode: one of $(JS_BUILD_MODES).  This sets up
# --[extern-][pre/post]-js flags in $(pre-post-$(1)-$(2).flags) and
# dependencies in $(pre-post-$(1)-$(2).deps). The resulting files get
# filtered using $(C-PP.FILTER). Any flags necessary for such
# filtering need to be set in $(c-pp.D.$(1)-$(2)) before $(call)ing
# this.
#
# Maintenance note: a shell script was written to generate these rules
# with the hope that it would make them more legible and maintainable,
# but embedding makefile code in another language makes it even less
# legible than having the level of $(eval) indirection which we have
# here.
define call-make-pre-post
pre-post-$(1)-$(2).flags ?=
pre-js.js.$(1)-$(2).intermediary := $$(dir.tmp)/pre-js.$(1)-$(2).intermediary.js
pre-js.js.$(1)-$(2) := $$(dir.tmp)/pre-js.$(1)-$(2).intermediary.js
$$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
pre-js.js.$(1)-$(2) := $$(dir.tmp)/pre-js.$(1)-$(2).js
#$$(error $$(pre-js.js.$(1)-$(2).intermediary) $$(pre-js.js.$(1)-$(2)))
$$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)-$(2).intermediary),$$(c-pp.D.$(1)-$(2))))
post-js.js.$(1)-$(2) := $$(dir.tmp)/post-js.$(1)-$(2).js
$$(eval $$(call C-PP.FILTER,$$(post-js.js.in),$$(post-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
extern-post-js.js.$(1)-$(2) := $$(dir.tmp)/extern-post-js.$(1)-$(2).js
$$(eval $$(call C-PP.FILTER,$$(extern-post-js.js.in),$$(extern-post-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
pre-post-common.flags.$(1)-$(2) := \
  $$(pre-post-common.flags) \
  --post-js=$$(post-js.js.$(1)-$(2)) \
  --extern-post-js=$$(extern-post-js.js.$(1)-$(2))
pre-post-jses.$(1)-$(2).deps := $$(pre-post-jses.deps.common) \
  $$(post-js.js.$(1)-$(2)) $$(extern-post-js.js.$(1)-$(2))
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(1)-$(2)) $$(MAKEFILE)
	cp $$(pre-js.js.$(1)-$(2)) $$@
$$(pre-js.js.$(1)-$(2)): $$(pre-js.js.$(1)-$(2).intermediary) $$(MAKEFILE)
	cp $$(pre-js.js.$(1)-$(2).intermediary) $$@
	@if [ sqlite3-wasmfs = $(1) ]; then \
		echo "delete Module[xNameOfInstantiateWasm] /*for WASMFS build*/;"; \
	elif [ sqlite3 != $(1) ]; then \
		echo "Module[xNameOfInstantiateWasm].uri = '$(1).wasm';"; \
	fi >> $$@
pre-post-$(1)-$(2).deps := \
  $$(pre-post-jses.$(1)-$(2).deps) \
  $$(dir.tmp)/pre-js-$(1)-$(2).js
  $$(dir.tmp)/pre-js.$(1)-$(2).js
pre-post-$(1)-$(2).flags += \
  $$(pre-post-common.flags.$(1)-$(2)) \
  --pre-js=$$(dir.tmp)/pre-js-$(1)-$(2).js
  --pre-js=$$(dir.tmp)/pre-js.$(1)-$(2).js
endef
# /post-js and pre-js
########################################################################

# Undocumented Emscripten feature: if the target file extension is
# "mjs", it defaults to ES6 module builds:
# https://github.com/emscripten-core/emscripten/issues/14383
679
680
681
682
683
684
685
686
687


688
689
690
691
692
693
694
695
696
697
698
699
700
701
702

703
704
705
706
707
708
709
710
711
712
713

714
715
716
717
718

719
720
721
722
723
724

725
726
727
728
729


730
731
732
733
734
735
736
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







-
-
+
+















+











+




-
+





-
+




-
+
+







# overwritten version of that function and cannot "export default"
# twice. Because of this, we have to sed *.mjs to remove the _first_
# instance (only) of /^export default/.
#
# Upstream RFE:
# https://github.com/emscripten-core/emscripten/issues/18237
#
# Maintenance reminder: Mac sed works differently than GNU sed, so
# don't use sed for this.
# Maintenance reminder: Mac sed works differently than GNU sed, so we
# use awk instead of sed for this.
define SQLITE3.xJS.ESM-EXPORT-DEFAULT
if [ x1 = x$(1) ]; then \
		echo "Fragile workaround for emscripten/issues/18237. See SQLITE3.xJS.RECIPE."; \
		{\
			awk '/^export default/ && !f{f=1; next} 1' $@ > $@.tmp && mv $@.tmp $@; \
		} || exit $$?; \
		if [ x != x$(2) ]; then \
			if ! grep -q '^export default' $@; then \
				echo "Cannot find export default." 1>&2; \
				exit 1; \
			fi; \
		fi; \
fi
endef

########################################################################
# extern-post-js* and extern-pre-js* are files for use with
# Emscripten's --extern-pre-js and --extern-post-js flags.
extern-pre-js.js := $(dir.api)/extern-pre-js.js
extern-post-js.js.in := $(dir.api)/extern-post-js.c-pp.js
# Emscripten flags for --[extern-][pre|post]-js=... for the
# various builds.
pre-post-common.flags := \
  --extern-pre-js=$(sqlite3-license-version.js)
# pre-post-jses.deps.* = a list of dependencies for the
# --[extern-][pre/post]-js files.
pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)

########################################################################
# SETUP_LIB_BUILD_MODE is a $(call)'able which sets up numerous pieces
# for one of the build modes.
#
# $1 = one of: sqlite3, sqlite3-wasmfs
# $1 = one of: $(JS_BUILD_NAMES)
# $2 = build mode name: one of $(JS_BUILD_MODES)
# $3 = 1 for ESM build mode, else 0
# $4 = resulting sqlite-api JS/MJS file
# $5 = resulting JS/MJS file
# $6 = -D... flags for $(bin.c-pp)
# $7 = emcc -sXYZ flags (CURRENTLY UNUSED - was factored out)
# $7 = optional extra flags for emcc
#
# Maintenance reminder: be careful not to introduce spaces around args
# ($1, $2), otherwise string concatenation will malfunction.
#
# emcc.environment.$(2) must be set to a value for the -sENVIRONMENT flag.
# Before calling this, emcc.environment.$(2) must be set to a value
# for emcc's -sENVIRONMENT flag.
#
# $(cflags.$(1)) and $(cflags.$(1).$(2)) may be defined to append
# CFLAGS to a given build mode.
#
# $(emcc.flags.$(1)) and $(emcc.flags.$(1).$(2)) may be defined to
# append emcc-specific flags to a given build mode.
define SETUP_LIB_BUILD_MODE
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
884
885
886
887
888
889
890

891

892
893
894
895
896
897
898
899
900
901
902
903
904
905
906

907
908
909
910
911
912
913
914







-
+
-















-
+







sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs
sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs
sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
#$(info $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0, $(sqlite3-api.js), $(sqlite3.js)))
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0,\
         $(sqlite3-api.js), $(sqlite3.js)))
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,esm,1,\
         $(sqlite3-api.mjs), $(sqlite3.mjs), \
         $(sqlite3-api.mjs), $(sqlite3.mjs), -Dtarget=es6-module))
       -Dtarget=es6-module, -sEXPORT_ES6 -sUSE_ES6_IMPORT_META))
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,bundler-friendly,1,\
       $(sqlite3-api-bundler-friendly.mjs),$(sqlite3-bundler-friendly.mjs),\
       $(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly))
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,node,1,\
       $(sqlite3-api-node.mjs),$(sqlite3-node.mjs),\
       $(c-pp.D.sqlite3-bundler-friendly) -Dtarget=node))
# The various -D... values used by *.c-pp.js include:
#
# -Dtarget=es6-module: for all ESM module builds
#
# -Dtarget=node: for node.js builds
#
# -Dtarget=es6-module -Dtarget=es6-bundler-friendly: intended for
#    "bundler-friendly" ESM module build. These have some restrictions
#    on how URL() objects are constructed in some contexts: URLs which
#    refer to files which are part of this project must be references
#    refer to files which are part of this project must be referenced
#    as string literals so that bundlers' static-analysis tools can
#    find those files and include them in their bundles.
#
# -Dtarget=es6-module -Dtarget=es6-bundler-friendly -Dtarget=node: is
#    intended for use by node.js for node.js, as opposed to by
#    node.js on behalf of a browser. Mixing -sENVIRONMENT=web and
#    -sENVIRONMENT=node leads to ambiguity and confusion on node's
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
936
937
938
939
940
941
942
943

944
945
946

947
948
949
950
951
952
953
954

955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970

971
972
973
974
975
976
977
978
979
980
981
982
983

984
985
986
987
988
989
990
991







+
-
+


-
+





+
+
-
+

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








-
+







# themselves use importScripts() or Workers or URL() constructors
# which refer to other in-tree (m)JS files quire a bundler-friendly
# copy.
sqlite3-worker1.js.in := $(dir.api)/sqlite3-worker1.c-pp.js
sqlite3-worker1-promiser.js.in := $(dir.api)/sqlite3-worker1-promiser.c-pp.js
sqlite3-worker1.js := $(dir.dout)/sqlite3-worker1.js
sqlite3-worker1-promiser.js := $(dir.dout)/sqlite3-worker1-promiser.js
sqlite3-worker1-promiser.mjs := $(dir.dout)/sqlite3-worker1-promiser.mjs
sqlite3-worker1-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs
sqlite3-worker1-bundler-friendly.mjs := $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs
sqlite3-worker1-promiser-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js
$(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1.js)))
$(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.js),\
$(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.mjs),\
    $(c-pp.D.sqlite3-bundler-friendly)))
$(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.js)))
$(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),\
    $(sqlite3-worker1-promiser-bundler-friendly.js),\
    $(c-pp.D.sqlite3-bundler-friendly)))
$(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.mjs),\
    -Dtarget=es6-module -Dtarget=es6-bundler-friendly))
$(sqlite3-bundler-friendly.mjs): $(sqlite3-worker1-bundler-friendly.js) \
$(sqlite3-bundler-friendly.mjs): $(sqlite3-worker1-bundler-friendly.mjs) \
    $(sqlite3-worker1-promiser-bundler-friendly.js)
$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.js))
$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.mjs,\
    -Dtarget=es6-module))
$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser.html))
$(eval $(call C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser-esm.html,\
    -Dtarget=es6-module))
all: $(sqlite3-worker1.js) \
    $(sqlite3-worker1-promiser.js) $(sqlite3-worker1-promiser.mjs)

demo-worker1-promiser.html: $(sqlite3-worker1-promiser.js) demo-worker1-promiser.js
demo-worker1-promiser-esm.html: $(sqlite3-worker1-promiser.mjs) demo-worker1-promiser.mjs
all: demo-worker1-promiser.html demo-worker1-promiser-esm.html

sqlite3-api.ext.jses += \
$(sqlite3.js) $(sqlite3.mjs): $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js)
  $(sqlite3-worker1-promiser.mjs) \
  $(sqlite3-worker1-bundler-friendly.mjs) \
  $(sqlite3-worker1.js)
all quick: $(sqlite3-api.ext.jses)
q: quick

########################################################################
# batch-runner.js is part of one of the test apps which reads in SQL
# dumps generated by $(speedtest1) and executes them.
dir.sql := sql
speedtest1 := ../../speedtest1
speedtest1.c := ../../test/speedtest1.c
speedtest1.sql := $(dir.sql)/speedtest1.sql
speedtest1.cliflags := --size 25 --big-transactions
speedtest1.cliflags := --size 10 --big-transactions
$(speedtest1):
	$(MAKE) -C ../.. speedtest1
$(speedtest1.sql): $(speedtest1) $(MAKEFILE)
	$(speedtest1) $(speedtest1.cliflags) --script $@
batch-runner.list: $(MAKEFILE) $(speedtest1.sql) $(dir.sql)/000-mandelbrot.sql
	bash split-speedtest1-script.sh $(dir.sql)/speedtest1.sql
	ls -1 $(dir.sql)/*.sql | grep -v speedtest1.sql | sort > $@
882
883
884
885
886
887
888



889
890
891
892
893
894
895
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025







+
+
+







emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
emcc.speedtest1.common += -sINVOKE_RUN=0
emcc.speedtest1.common += --no-entry
emcc.speedtest1.common += -sABORTING_MALLOC
emcc.speedtest1.common += -sSTRICT_JS=0
emcc.speedtest1.common += -sMODULARIZE
emcc.speedtest1.common += -Wno-limited-postlink-optimizations
emcc.speedtest1.common += -Wno-unused-main
# ^^^^ -Wno-unused-main is for emcc 3.1.52+. speedtest1 has a wasm_main() which is
# exported and called by the JS code.
EXPORTED_FUNCTIONS.speedtest1 := $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
emcc.speedtest1.common += -sSTACK_SIZE=512KB
emcc.speedtest1.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
emcc.speedtest1.common += $(emcc.exportedRuntimeMethods)
emcc.speedtest1.common += -sALLOW_TABLE_GROWTH
emcc.speedtest1.common += -sDYNAMIC_EXECUTION=0
emcc.speedtest1.common += --minify 0
1083
1084
1085
1086
1087
1088
1089
1090

1213
1214
1215
1216
1217
1218
1219

1220







-
+
# Create main client downloadable zip file:
ifneq (,$(filter dist snapshot,$(MAKECMDGOALS)))
include dist.make
endif

# Run local web server for the test/demo pages.
httpd:
	althttpd -max-age 1 -enable-sab -page index.html
	althttpd -max-age 1 -enable-sab 1 -page index.html
Changes to ext/wasm/SQLTester/SQLTester.mjs.
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
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







+
+




-
-
+
+
+
+
+
+


















-
+







  scriptModuleName: / SCRIPT_MODULE_NAME:[ \t]*(\S+)\s*$/,
  mixedModuleName: / ((MIXED_)?MODULE_NAME):[ \t]*(\S+)\s*$/,
  command: /^--(([a-z-]+)( .*)?)$/,
  //! "Special" characters - we have to escape output if it contains any.
  special: /[\x00-\x20\x22\x5c\x7b\x7d]/,
  squiggly: /[{}]/
});



const Util = newObj({
  toss,

  unlink: function(fn){
    return 0==sqlite3.wasm.sqlite3_wasm_vfs_unlink(0,fn);
  unlink: function f(fn){
    if(!f.unlink){
      f.unlink = sqlite3.wasm.xWrap('sqlite3__wasm_vfs_unlink','int',
                                    ['*','string']);
    }
    return 0==f.unlink(0,fn);
  },

  argvToString: (list)=>{
    const m = [...list];
    m.shift() /* strip command name */;
    return m.join(" ")
  },

  utf8Decode: function(arrayBuffer, begin, end){
    return __utf8Decoder.decode(
      (arrayBuffer.buffer instanceof __SAB)
        ? arrayBuffer.slice(begin, end)
        : arrayBuffer.subarray(begin, end)
    );
  },

  utf8Encode: (str)=>__utf8Encoder.encode(str),

  strglob: sqlite3.wasm.xWrap('sqlite3_wasm_SQLTester_strglob','int',
  strglob: sqlite3.wasm.xWrap('sqlite3__wasm_SQLTester_strglob','int',
                              ['string','string'])
})/*Util*/;

class Outer {
  #lnBuf = [];
  #verbosity = 0;
  #logger = console.log.bind(console);
Changes to ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api.
59
60
61
62
63
64
65

66
67
68
69
70
71
72
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73







+







_sqlite3_expanded_sql
_sqlite3_extended_errcode
_sqlite3_extended_result_codes
_sqlite3_file_control
_sqlite3_finalize
_sqlite3_free
_sqlite3_get_auxdata
_sqlite3_get_autocommit
_sqlite3_initialize
_sqlite3_keyword_count
_sqlite3_keyword_name
_sqlite3_keyword_check
_sqlite3_last_insert_rowid
_sqlite3_libversion
_sqlite3_libversion_number
Changes to ext/wasm/api/README.md.
74
75
76
77
78
79
80
81
82
83
84






85
86
87
88
89
90
91
74
75
76
77
78
79
80




81
82
83
84
85
86
87
88
89
90
91
92
93







-
-
-
-
+
+
+
+
+
+







      and runs the Worker #1 API which is implemented in
      `sqlite3-api-worker1.js`.
    - **`sqlite3-worker1-promiser.js`**\  
      Is likewise not part of the amalgamated sources and provides
      a Promise-based interface into the Worker #1 API. This is
      a far user-friendlier way to interface with databases running
      in a Worker thread.
- **`sqlite3-v-helper.js`**\  
  Installs `sqlite3.vfs` and `sqlite3.vtab`, namespaces which contain
  helpers for use by downstream code which creates `sqlite3_vfs`
  and `sqlite3_module` implementations.
- **`sqlite3-vfs-helper.js`**\  
  Installs the `sqlite3.vfs` namespace, which contain helpers for use
  by downstream code which creates `sqlite3_vfs` implementations.
- **`sqlite3-vtab-helper.js`**\  
  Installs the `sqlite3.vtab` namespace, which contain helpers for use
  by downstream code which creates `sqlite3_module` implementations.
- **`sqlite3-vfs-opfs.c-pp.js`**\  
  is an sqlite3 VFS implementation which supports the Origin-Private
  FileSystem (OPFS) as a storage layer to provide persistent storage
  for database files in a browser. It requires...
    - **`sqlite3-opfs-async-proxy.js`**\  
      is the asynchronous backend part of the OPFS proxy. It speaks
      directly to the (async) OPFS API and channels those results back
Changes to ext/wasm/api/post-js-header.js.
15
16
17
18
19
20
21
22
23




24
25
26
15
16
17
18
19
20
21


22
23
24
25
26
27
28







-
-
+
+
+
+



     - post-js-header.js (this file)
     - sqlite3-api-prologue.js  => Bootstrapping bits to attach the rest to
     - common/whwasmutil.js     => Replacements for much of Emscripten's glue
     - jaccwaby/jaccwabyt.js    => Jaccwabyt (C/JS struct binding)
     - sqlite3-api-glue.js      => glues previous parts together
     - sqlite3-api-oo.js        => SQLite3 OO API #1
     - sqlite3-api-worker1.js   => Worker-based API
     - sqlite3-vfs-helper.js    => Internal-use utilities for...
     - sqlite3-vfs-opfs.js      => OPFS VFS
     - sqlite3-vfs-helper.c-pp.js  => Utilities for VFS impls
     - sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
     - sqlite3-vfs-opfs.c-pp.js  => OPFS VFS
     - sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
     - sqlite3-api-cleanup.js   => final API cleanup
     - post-js-footer.js        => closes this postRun() function
  */
Changes to ext/wasm/api/sqlite3-api-glue.js.
10
11
12
13
14
15
16
17


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

17
18
19
20
21
22
23
24
25







-
+
+








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

  This file glues together disparate pieces of JS which are loaded in
  previous steps of the sqlite3-api.js bootstrapping process:
  sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
  initializes the main API pieces so that the downstream components
  (e.g. sqlite3-api-oo1.js) have all that they need.
  (e.g. sqlite3-api-oo1.js) have all of the infrastructure that they
  need.
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  'use strict';
  const toss = (...args)=>{throw new Error(args.join(' '))};
  const toss3 = sqlite3.SQLite3Error.toss;
  const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
  globalThis.WhWasmUtilInstaller(wasm);
184
185
186
187
188
189
190

191
192
193
194
195
196
197
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199







+







    ]],
    ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
    ["sqlite3_extended_errcode", "int", "sqlite3*"],
    ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
    ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
    ["sqlite3_finalize", "int", "sqlite3_stmt*"],
    ["sqlite3_free", undefined,"*"],
    ["sqlite3_get_autocommit", "int", "sqlite3*"],
    ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
    ["sqlite3_initialize", undefined],
    /*["sqlite3_interrupt", undefined, "sqlite3*"
       ^^^ we cannot actually currently support this because JS is
        single-threaded and we don't have a portable way to access a DB
        from 2 SharedWorkers concurrently. ],*/
    ["sqlite3_keyword_count", "int"],
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
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







+
+
+
+
+
+
+
+












+
+


















-
+
+
+
+







    /* ^^^ "the problem" is that this is an option feature and the
       build-time function-export list does not currently take
       optional features into account. */
    wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
  }

  if(wasm.exports.sqlite3_activate_see instanceof Function){
    /**
       This code is capable of using an SEE build but note that an SEE
       WASM build is generally incompatible with SEE's license
       conditions. It is permitted for use internally in organizations
       which have licensed SEE, but not for public sites because
       exposing an SEE build of sqlite3.wasm effectively provides all
       clients with a working copy of the commercial SEE code.
    */
    wasm.bindingSignatures.push(
      ["sqlite3_key", "int", "sqlite3*", "string", "int"],
      ["sqlite3_key_v2","int","sqlite3*","string","*","int"],
      ["sqlite3_rekey", "int", "sqlite3*", "string", "int"],
      ["sqlite3_rekey_v2", "int", "sqlite3*", "string", "*", "int"],
      ["sqlite3_activate_see", undefined, "string"]
    );
  }
  /**
     Functions which require BigInt (int64) support are separated from
     the others because we need to conditionally bind them or apply
     dummy impls, depending on the capabilities of the environment.
     (That said: we never actually build without BigInt support,
     and such builds are untested.)

     Note that not all of these functions directly require int64
     but are only for use with APIs which require int64. For example,
     the vtab-related functions.
  */
  wasm.bindingSignatures.int64 = [
    ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
    ["sqlite3_changes64","i64", ["sqlite3*"]],
    ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
    ["sqlite3_create_module", "int",
     ["sqlite3*","string","sqlite3_module*","*"]],
    ["sqlite3_create_module_v2", "int",
     ["sqlite3*","string","sqlite3_module*","*","*"]],
    ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
    ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
    /* Careful! Short version: de/serialize() are problematic because they
       might use a different allocator than the user for managing the
       deserialized block. de/serialize() are ONLY safe to use with
       sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
       sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. Because
       of this, the canonical builds of sqlite3.wasm/js guarantee that
       sqlite3.wasm.alloc() and friends use those allocators. Custom builds
       may not guarantee that, however. */,
    ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
    ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
    ["sqlite3_malloc64", "*","i64"],
    ["sqlite3_msize", "i64", "*"],
    ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
    ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
    ["sqlite3_preupdate_count", "int", "sqlite3*"],
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
432
433
434
435
436
437
438


439
440
441
442
443
444
445







-
-







    ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
    ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
    ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
  ];

  // Add session/changeset APIs...
  if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
    /* ACHTUNG: 2022-12-23: the session/changeset API bindings are
       COMPLETELY UNTESTED. */
    /**
       FuncPtrAdapter options for session-related callbacks with the
       native signature "i(ps)". This proxy converts the 2nd argument
       from a C string to a JS string before passing the arguments on
       to the client-provided JS callback.
    */
    const __ipsProxy = {
596
597
598
599
600
601
602
603
604







605
606
607
608
609




610
611
612


613
614
615
616
617
618
619
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







-
-
+
+
+
+
+
+
+

-
-
-
-
+
+
+
+

-
-
+
+







      ]]
    ]);
  }/*session/changeset APIs*/

  /**
     Functions which are intended solely for API-internal use by the
     WASM components, not client code. These get installed into
     sqlite3.wasm. Some of them get exposed to clients via variants
     named sqlite3_js_...().
     sqlite3.util. Some of them get exposed to clients via variants
     in sqlite3_js_...().

     2024-01-11: these were renamed, with two underscores in the
     prefix, to ensure that clients do not accidentally depend on
     them.  They have always been documented as internal-use-only, so
     no clients "should" be depending on the old names.
  */
  wasm.bindingSignatures.wasm = [
    ["sqlite3_wasm_db_reset", "int", "sqlite3*"],
    ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
    ["sqlite3_wasm_vfs_create_file", "int",
  wasm.bindingSignatures.wasmInternal = [
    ["sqlite3__wasm_db_reset", "int", "sqlite3*"],
    ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
    ["sqlite3__wasm_vfs_create_file", "int",
     "sqlite3_vfs*","string","*", "int"],
    ["sqlite3_wasm_posix_create_file", "int", "string","*", "int"],
    ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
    ["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
    ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
  ];

  /**
     Install JS<->C struct bindings for the non-opaque struct types we
     need... */
  sqlite3.StructBinder = globalThis.Jaccwabyt({
    heap: 0 ? wasm.memory : wasm.heap8u,
647
648
649
650
651
652
653
654

655
656
657
658
659
660
661
665
666
667
668
669
670
671

672
673
674
675
676
677
678
679







-
+







         string, map its pointer to (''+v) for the remainder of the
         application's life, and returns that pointer value for this
         call and all future calls which are passed a
         string-equivalent argument.

       Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
       call for "a static string and preferably a string
       literal". This converter is used to ensure that the string
       literal." This converter is used to ensure that the string
       value seen by those functions is long-lived and behaves as they
       need it to.
    */
    wasm.xWrap.argAdapter(
      'string:static',
      function(v){
        if(wasm.isPtr(v)) return v;
669
670
671
672
673
674
675
676



677
678
679
680
681
682
683
684
685
686
687
688
689
690
687
688
689
690
691
692
693

694
695
696
697
698
699
700
701
702

703
704
705
706
707
708
709







-
+
+
+






-







       Add some descriptive xWrap() aliases for '*' intended to (A)
       initially improve readability/correctness of
       wasm.bindingSignatures and (B) provide automatic conversion
       from higher-level representations, e.g. capi.sqlite3_vfs to
       `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
    */
    const __xArgPtr = wasm.xWrap.argAdapter('*');
    const nilType = function(){}/*a class no value can ever be an instance of*/;
    const nilType = function(){
      /*a class which no value can ever be an instance of*/
    };
    wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
    ('sqlite3_context*', __xArgPtr)
    ('sqlite3_value*', __xArgPtr)
    ('void*', __xArgPtr)
    ('sqlite3_changegroup*', __xArgPtr)
    ('sqlite3_changeset_iter*', __xArgPtr)
    //('sqlite3_rebaser*', __xArgPtr)
    ('sqlite3_session*', __xArgPtr)
    ('sqlite3_stmt*', (v)=>
      __xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
           ? v.pointer : v))
    ('sqlite3*', (v)=>
      __xArgPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
           ? v.pointer : v))
737
738
739
740
741
742
743
744
745


746
747
748
749
750
751
752
756
757
758
759
760
761
762


763
764
765
766
767
768
769
770
771







-
-
+
+







      sqlite3.config.warn(
        "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks."
      );
    }
    for(const e of wasm.bindingSignatures){
      capi[e[0]] = wasm.xWrap.apply(null, e);
    }
    for(const e of wasm.bindingSignatures.wasm){
      wasm[e[0]] = wasm.xWrap.apply(null, e);
    for(const e of wasm.bindingSignatures.wasmInternal){
      util[e[0]] = wasm.xWrap.apply(null, e);
    }

    /* For C API functions which cannot work properly unless
       wasm.bigIntEnabled is true, install a bogus impl which throws
       if called when bigIntEnabled is false. The alternative would be
       to elide these functions altogether, which seems likely to
       cause more confusion. */
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
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







-
+

-
+

















-
+










-
-
+
+






-
+

-
+







        : fI64Disabled(e[0]);
    }

    /* There's no need to expose bindingSignatures to clients,
       implicitly making it part of the public interface. */
    delete wasm.bindingSignatures;

    if(wasm.exports.sqlite3_wasm_db_error){
    if(wasm.exports.sqlite3__wasm_db_error){
      const __db_err = wasm.xWrap(
        'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
        'sqlite3__wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
      );
      /**
         Sets the given db's error state. Accepts:

         - (sqlite3*, int code, string msg)
         - (sqlite3*, Error e [,string msg = ''+e])

         If passed a WasmAllocError, the message is ignored and the
         result code is SQLITE_NOMEM. If passed any other Error type,
         the result code defaults to SQLITE_ERROR unless the Error
         object has a resultCode property, in which case that is used
         (e.g. SQLite3Error has that). If passed a non-WasmAllocError
         exception, the message string defaults to theError.message.

         Returns the resulting code. Pass (pDb,0,0) to clear the error
         state.
       */
      util.sqlite3_wasm_db_error = function(pDb, resultCode, message){
      util.sqlite3__wasm_db_error = function(pDb, resultCode, message){
        if(resultCode instanceof sqlite3.WasmAllocError){
          resultCode = capi.SQLITE_NOMEM;
          message = 0 /*avoid allocating message string*/;
        }else if(resultCode instanceof Error){
          message = message || ''+resultCode;
          resultCode = (resultCode.resultCode || capi.SQLITE_ERROR);
        }
        return pDb ? __db_err(pDb, resultCode, message) : resultCode;
      };
    }else{
      util.sqlite3_wasm_db_error = function(pDb,errCode,msg){
        console.warn("sqlite3_wasm_db_error() is not exported.",arguments);
      util.sqlite3__wasm_db_error = function(pDb,errCode,msg){
        console.warn("sqlite3__wasm_db_error() is not exported.",arguments);
        return errCode;
      };
    }
  }/*xWrap() bindings*/

  {/* Import C-level constants and structs... */
    const cJson = wasm.xCall('sqlite3_wasm_enum_json');
    const cJson = wasm.xCall('sqlite3__wasm_enum_json');
    if(!cJson){
      toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
      toss("Maintenance required: increase sqlite3__wasm_enum_json()'s",
           "static buffer size!");
    }
    //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
    wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
    // Groups of SQLITE_xyz macros...
    const defineGroups = ['access', 'authorizer',
                          'blobFinalizers', 'changeset',
872
873
874
875
876
877
878
879

880
881
882
883
884
885
886
887
888
889
890
891

892
893
894
895
896
897
898
899
900

901
902
903
904
905
906
907
891
892
893
894
895
896
897

898
899
900
901
902
903
904
905
906
907
908
909

910
911
912
913
914
915
916
917
918

919
920
921
922
923
924
925
926







-
+











-
+








-
+







      for(const k of ['sqlite3_index_constraint',
                      'sqlite3_index_orderby',
                      'sqlite3_index_constraint_usage']){
        capi.sqlite3_index_info[k] = capi[k];
        delete capi[k];
      }
      capi.sqlite3_vtab_config = wasm.xWrap(
        'sqlite3_wasm_vtab_config','int',[
        'sqlite3__wasm_vtab_config','int',[
          'sqlite3*', 'int', 'int']
      );
    }/* end vtab-related setup */
  }/*end C constant and struct imports*/

  /**
     Internal helper to assist in validating call argument counts in
     the hand-written sqlite3_xyz() wrappers. We do this only for
     consistency with non-special-case wrappings.
  */
  const __dbArgcMismatch = (pDb,f,n)=>{
    return util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE,
    return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE,
                                      f+"() requires "+n+" argument"+
                                      (1===n?"":'s')+".");
  };

  /** Code duplication reducer for functions which take an encoding
      argument and require SQLITE_UTF8.  Sets the db error code to
      SQLITE_FORMAT and returns that code. */
  const __errEncoding = (pDb)=>{
    return util.sqlite3_wasm_db_error(
    return util.sqlite3__wasm_db_error(
      pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
    );
  };

  /**
     __dbCleanupMap is infrastructure for recording registration of
     UDFs and collations so that sqlite3_close_v2() can clean up any
1123
1124
1125
1126
1127
1128
1129
1130

1131
1132
1133
1134
1135
1136
1137
1142
1143
1144
1145
1146
1147
1148

1149
1150
1151
1152
1153
1154
1155
1156







-
+







      try{
        const rc = __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
        if(0===rc && xCompare instanceof Function){
          __dbCleanupMap.addCollation(pDb, zName);
        }
        return rc;
      }catch(e){
        return util.sqlite3_wasm_db_error(pDb, e);
        return util.sqlite3__wasm_db_error(pDb, e);
      }
    };

    capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
      return (5===arguments.length)
        ? capi.sqlite3_create_collation_v2(pDb,zName,eTextRep,pArg,xCompare,0)
        : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5);
1249
1250
1251
1252
1253
1254
1255
1256

1257
1258
1259
1260
1261
1262
1263
1268
1269
1270
1271
1272
1273
1274

1275
1276
1277
1278
1279
1280
1281
1282







-
+







                      || xFinal instanceof Function
                      || xDestroy instanceof Function)){
          __dbCleanupMap.addFunction(pDb, funcName, nArg);
        }
        return rc;
      }catch(e){
        console.error("sqlite3_create_function_v2() setup threw:",e);
        return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
        return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
      }
    };

    /* Documented in the api object's initializer. */
    capi.sqlite3_create_function = function f(
      pDb, funcName, nArg, eTextRep, pApp,
      xFunc, xStep, xFinal
1294
1295
1296
1297
1298
1299
1300
1301

1302
1303
1304
1305
1306
1307
1308
1313
1314
1315
1316
1317
1318
1319

1320
1321
1322
1323
1324
1325
1326
1327







-
+







                      || xInverse instanceof Function
                      || xDestroy instanceof Function)){
          __dbCleanupMap.addWindowFunc(pDb, funcName, nArg);
        }
        return rc;
      }catch(e){
        console.error("sqlite3_create_window_function() setup threw:",e);
        return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
        return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
      }
    };
    /**
       A _deprecated_ alias for capi.sqlite3_result_js() which
       predates the addition of that function in the public API.
    */
    capi.sqlite3_create_function_v2.udfSetResult =
1389
1390
1391
1392
1393
1394
1395
1396

1397
1398
1399
1400
1401
1402
1403
1408
1409
1410
1411
1412
1413
1414

1415
1416
1417
1418
1419
1420
1421
1422







-
+







        return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
      }
      const [xSql, xSqlLen] = __flexiString(sql, sqlLen);
      switch(typeof xSql){
          case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
          case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
          default:
            return util.sqlite3_wasm_db_error(
            return util.sqlite3__wasm_db_error(
              pDb, capi.SQLITE_MISUSE,
              "Invalid SQL argument type for sqlite3_prepare_v2/v3()."
            );
      }
    };

    /* Documented in the capi object's initializer. */
1433
1434
1435
1436
1437
1438
1439
1440

1441
1442
1443
1444
1445
1446
1447
1448

1449
1450
1451
1452
1453
1454
1455
1452
1453
1454
1455
1456
1457
1458

1459
1460
1461
1462
1463
1464
1465
1466

1467
1468
1469
1470
1471
1472
1473
1474







-
+







-
+







      try{
        if(util.isSQLableTypedArray(text)){
          p = wasm.allocFromTypedArray(text);
          n = text.byteLength;
        }else if('string'===typeof text){
          [p, n] = wasm.allocCString(text);
        }else{
          return util.sqlite3_wasm_db_error(
          return util.sqlite3__wasm_db_error(
            capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
            "Invalid 3rd argument type for sqlite3_bind_text()."
          );
        }
        return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
      }catch(e){
        wasm.dealloc(p);
        return util.sqlite3_wasm_db_error(
        return util.sqlite3__wasm_db_error(
          capi.sqlite3_db_handle(pStmt), e
        );
      }
    }/*sqlite3_bind_text()*/;

    /** Documented in the capi object's initializer. */
    capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){
1467
1468
1469
1470
1471
1472
1473
1474

1475
1476
1477
1478
1479
1480
1481
1482

1483
1484
1485
1486
1487
1488
1489
1486
1487
1488
1489
1490
1491
1492

1493
1494
1495
1496
1497
1498
1499
1500

1501
1502
1503
1504
1505
1506
1507
1508







-
+







-
+







      try{
        if(util.isBindableTypedArray(pMem)){
          p = wasm.allocFromTypedArray(pMem);
          n = nMem>=0 ? nMem : pMem.byteLength;
        }else if('string'===typeof pMem){
          [p, n] = wasm.allocCString(pMem);
        }else{
          return util.sqlite3_wasm_db_error(
          return util.sqlite3__wasm_db_error(
            capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
            "Invalid 3rd argument type for sqlite3_bind_blob()."
          );
        }
        return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
      }catch(e){
        wasm.dealloc(p);
        return util.sqlite3_wasm_db_error(
        return util.sqlite3__wasm_db_error(
          capi.sqlite3_db_handle(pStmt), e
        );
      }
    }/*sqlite3_bind_blob()*/;

  }/*sqlite3_bind_text/blob()*/

1499
1500
1501
1502
1503
1504
1505
1506

1507
1508

1509
1510

1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524

1525
1526

1527
1528

1529
1530
1531
1532
1533
1534
1535
1536







-
+

-
+

-
+







      switch(op){
          case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: // 20  /* int */
          case capi.SQLITE_CONFIG_MEMSTATUS:// 9  /* boolean */
          case capi.SQLITE_CONFIG_SMALL_MALLOC: // 27  /* boolean */
          case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28  /* int nByte */
          case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26  /* int nByte */
          case capi.SQLITE_CONFIG_URI:// 17  /* int */
            return wasm.exports.sqlite3_wasm_config_i(op, args[0]);
            return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
          case capi.SQLITE_CONFIG_LOOKASIDE: // 13  /* int int */
            return wasm.exports.sqlite3_wasm_config_ii(op, args[0], args[1]);
            return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
          case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29  /* sqlite3_int64 */
            return wasm.exports.sqlite3_wasm_config_j(op, args[0]);
            return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
          case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
          case capi.SQLITE_CONFIG_GETMUTEX: // 11  /* sqlite3_mutex_methods* */
          case capi.SQLITE_CONFIG_GETPCACHE2: // 19  /* sqlite3_pcache_methods2* */
          case capi.SQLITE_CONFIG_GETPCACHE: // 15  /* no-op */
          case capi.SQLITE_CONFIG_HEAP: // 8  /* void*, int nByte, int min */
          case capi.SQLITE_CONFIG_LOG: // 16  /* xFunc, void* */
          case capi.SQLITE_CONFIG_MALLOC:// 4  /* sqlite3_mem_methods* */
1569
1570
1571
1572
1573
1574
1575
1576

1577
1578
1579
1580

1581
1582
1583
1584
1585
1586
1587
1588
1589

1590
1591
1592
1593
1594
1595
1596
1588
1589
1590
1591
1592
1593
1594

1595
1596
1597
1598

1599
1600
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1615







-
+



-
+








-
+







    };
  }/* auto-extension */

  const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
  if( pKvvfs ){/* kvvfs-specific glue */
    if(util.isUIThread()){
      const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
        wasm.exports.sqlite3_wasm_kvvfs_methods()
        wasm.exports.sqlite3__wasm_kvvfs_methods()
      );
      delete capi.sqlite3_kvvfs_methods;

      const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
      const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
            pstack = wasm.pstack;

      const kvvfsStorage = (zClass)=>
            ((115/*=='s'*/===wasm.peek(zClass))
             ? sessionStorage : localStorage);

      /**
         Implementations for members of the object referred to by
         sqlite3_wasm_kvvfs_methods(). We swap out the native
         sqlite3__wasm_kvvfs_methods(). We swap out the native
         implementations with these, which use localStorage or
         sessionStorage for their backing store.
      */
      const kvvfsImpls = {
        xRead: (zClass, zKey, zBuf, nBuf)=>{
          const stack = pstack.pointer,
                astack = wasm.scopedAllocPush();
1662
1663
1664
1665
1666
1667
1668

1669















































































































































































1670
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
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







+

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

      /* Worker thread: unregister kvvfs to avoid it being used
         for anything other than local/sessionStorage. It "can"
         be used that way but it's not really intended to be. */
      capi.sqlite3_vfs_unregister(pKvvfs);
    }
  }/*pKvvfs*/

  /* Warn if client-level code makes use of FuncPtrAdapter. */
  wasm.xWrap.FuncPtrAdapter.warnOnUse = true;

  const StructBinder = sqlite3.StructBinder
  /* we require a local alias b/c StructBinder is removed from the sqlite3
     object during the final steps of the API cleanup. */;
  /**
     Installs a StructBinder-bound function pointer member of the
     given name and function in the given StructBinder.StructType
     target object.

     It creates a WASM proxy for the given function and arranges for
     that proxy to be cleaned up when tgt.dispose() is called. Throws
     on the slightest hint of error, e.g. tgt is-not-a StructType,
     name does not map to a struct-bound member, etc.

     As a special case, if the given function is a pointer, then
     `wasm.functionEntry()` is used to validate that it is a known
     function. If so, it is used as-is with no extra level of proxying
     or cleanup, else an exception is thrown. It is legal to pass a
     value of 0, indicating a NULL pointer, with the caveat that 0
     _is_ a legal function pointer in WASM but it will not be accepted
     as such _here_. (Justification: the function at address zero must
     be one which initially came from the WASM module, not a method we
     want to bind to a virtual table or VFS.)

     This function returns a proxy for itself which is bound to tgt
     and takes 2 args (name,func). That function returns the same
     thing as this one, permitting calls to be chained.

     If called with only 1 arg, it has no side effects but returns a
     func with the same signature as described above.

     ACHTUNG: because we cannot generically know how to transform JS
     exceptions into result codes, the installed functions do no
     automatic catching of exceptions. It is critical, to avoid
     undefined behavior in the C layer, that methods mapped via
     this function do not throw. The exception, as it were, to that
     rule is...

     If applyArgcCheck is true then each JS function (as opposed to
     function pointers) gets wrapped in a proxy which asserts that it
     is passed the expected number of arguments, throwing if the
     argument count does not match expectations. That is only intended
     for dev-time usage for sanity checking, and may leave the C
     environment in an undefined state.
  */
  const installMethod = function callee(
    tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
  ){
    if(!(tgt instanceof StructBinder.StructType)){
      toss("Usage error: target object is-not-a StructType.");
    }else if(!(func instanceof Function) && !wasm.isPtr(func)){
      toss("Usage errror: expecting a Function or WASM pointer to one.");
    }
    if(1===arguments.length){
      return (n,f)=>callee(tgt, n, f, applyArgcCheck);
    }
    if(!callee.argcProxy){
      callee.argcProxy = function(tgt, funcName, func,sig){
        return function(...args){
          if(func.length!==arguments.length){
            toss("Argument mismatch for",
                 tgt.structInfo.name+"::"+funcName
                 +": Native signature is:",sig);
          }
          return func.apply(this, args);
        }
      };
      /* An ondispose() callback for use with
         StructBinder-created types. */
      callee.removeFuncList = function(){
        if(this.ondispose.__removeFuncList){
          this.ondispose.__removeFuncList.forEach(
            (v,ndx)=>{
              if('number'===typeof v){
                try{wasm.uninstallFunction(v)}
                catch(e){/*ignore*/}
              }
              /* else it's a descriptive label for the next number in
                 the list. */
            }
          );
          delete this.ondispose.__removeFuncList;
        }
      };
    }/*static init*/
    const sigN = tgt.memberSignature(name);
    if(sigN.length<2){
      toss("Member",name,"does not have a function pointer signature:",sigN);
    }
    const memKey = tgt.memberKey(name);
    const fProxy = (applyArgcCheck && !wasm.isPtr(func))
    /** This middle-man proxy is only for use during development, to
        confirm that we always pass the proper number of
        arguments. We know that the C-level code will always use the
        correct argument count. */
          ? callee.argcProxy(tgt, memKey, func, sigN)
          : func;
    if(wasm.isPtr(fProxy)){
      if(fProxy && !wasm.functionEntry(fProxy)){
        toss("Pointer",fProxy,"is not a WASM function table entry.");
      }
      tgt[memKey] = fProxy;
    }else{
      const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
      tgt[memKey] = pFunc;
      if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
        tgt.addOnDispose('ondispose.__removeFuncList handler',
                         callee.removeFuncList);
        tgt.ondispose.__removeFuncList = [];
      }
      tgt.ondispose.__removeFuncList.push(memKey, pFunc);
    }
    return (n,f)=>callee(tgt, n, f, applyArgcCheck);
  }/*installMethod*/;
  installMethod.installMethodArgcCheck = false;

  /**
     Installs methods into the given StructBinder.StructType-type
     instance. Each entry in the given methods object must map to a
     known member of the given StructType, else an exception will be
     triggered.  See installMethod() for more details, including the
     semantics of the 3rd argument.

     As an exception to the above, if any two or more methods in the
     2nd argument are the exact same function, installMethod() is
     _not_ called for the 2nd and subsequent instances, and instead
     those instances get assigned the same method pointer which is
     created for the first instance. This optimization is primarily to
     accommodate special handling of sqlite3_module::xConnect and
     xCreate methods.

     On success, returns its first argument. Throws on error.
  */
  const installMethods = function(
    structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
  ){
    const seen = new Map /* map of <Function, memberName> */;
    for(const k of Object.keys(methods)){
      const m = methods[k];
      const prior = seen.get(m);
      if(prior){
        const mkey = structInstance.memberKey(k);
        structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
      }else{
        installMethod(structInstance, k, m, applyArgcCheck);
        seen.set(m, k);
      }
    }
    return structInstance;
  };

  /**
     Equivalent to calling installMethod(this,...arguments) with a
     first argument of this object. If called with 1 or 2 arguments
     and the first is an object, it's instead equivalent to calling
     installMethods(this,...arguments).
  */
  StructBinder.StructType.prototype.installMethod = function callee(
    name, func, applyArgcCheck = installMethod.installMethodArgcCheck
  ){
    return (arguments.length < 3 && name && 'object'===typeof name)
      ? installMethods(this, ...arguments)
      : installMethod(this, ...arguments);
  };

  /**
     Equivalent to calling installMethods() with a first argument
     of this object.
  */
  StructBinder.StructType.prototype.installMethods = function(
    methods, applyArgcCheck = installMethod.installMethodArgcCheck
  ){
    return installMethods(this, methods, applyArgcCheck);
  };

});
Changes to ext/wasm/api/sqlite3-api-oo1.js.

1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
+







//#ifnot omit-oo1
/*
  2022-07-22

  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.
1936
1937
1938
1939
1940
1941
1942
1943



1937
1938
1939
1940
1941
1942
1943

1944
1945
1946







-
+
+
+
    */
    jdb.prototype.storageSize = function(){
      return jdb.storageSize(affirmDbOpen(this).filename);
    };
  }/*main-window-only bits*/

});

//#else
/* Built with the omit-oo1 flag. */
//#endif ifnot omit-oo1
Changes to ext/wasm/api/sqlite3-api-prologue.js.
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47







-
+








   This function is not intended for client-level use. It is intended
   for use in creating bundles configured for specific WASM
   environments.

   This function expects a configuration object, intended to abstract
   away details specific to any given WASM environment, primarily so
   that it can be used without any _direct_ dependency on
   that it can be used without any direct dependency on
   Emscripten. (Note the default values for the config object!) The
   config object is only honored the first time this is
   called. Subsequent calls ignore the argument and return the same
   (configured) object which gets initialized by the first call.  This
   function will throw if any of the required config options are
   missing.

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







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






+
-
-
+
+
+








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








   [^1] = This property may optionally be a function, in which case
          this function calls that function to fetch the value,
          enabling delayed evaluation.

   The returned object is the top-level sqlite3 namespace object.


   Client code may optionally assign sqlite3ApiBootstrap.defaultConfig
   an object-type value before calling sqlite3ApiBootstrap() (without
   arguments) in order to tell that call to use this object as its
   default config value. The intention of this is to provide
   downstream clients with a reasonably flexible approach for plugging
   in an environment-suitable configuration without having to define a
   new global-scope symbol.

   However, because clients who access this library via an
   Emscripten-hosted module will not have an opportunity to call
   sqlite3ApiBootstrap() themselves, nor to access it before it is
   called, an alternative option for setting the configuration is to
   define globalThis.sqlite3ApiConfig to an object. If it is set, it
   is used instead of sqlite3ApiBootstrap.defaultConfig if
   sqlite3ApiBootstrap() is called without arguments.

   Both sqlite3ApiBootstrap.defaultConfig and
   globalThis.sqlite3ApiConfig get deleted by sqlite3ApiBootstrap()
   because any changes to them made after that point would have no
   useful effect.
*/
'use strict';
globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
  apiConfig = (globalThis.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig)
){
  if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */
    (sqlite3ApiBootstrap.sqlite3.config || console).warn(
    console.warn("sqlite3ApiBootstrap() called multiple times.",
                 "Config and external initializers are ignored on calls after the first.");
      "sqlite3ApiBootstrap() called multiple times.",
      "Config and external initializers are ignored on calls after the first."
    );
    return sqlite3ApiBootstrap.sqlite3;
  }
  const config = Object.assign(Object.create(null),{
    exports: undefined,
    memory: undefined,
    bigIntEnabled: (()=>{
      if('undefined'!==typeof Module){
        /* Emscripten module will contain HEAPU64 when built with
           -sWASM_BIGINT=1, else it will not. */
        return !!Module.HEAPU64;
           -sWASM_BIGINT=1, else it will not.

           As of emsdk 3.1.55, when building in strict mode, HEAPxyz
           are only available if _explicitly_ included in the exports,
           else they are not. We do not (as of 2024-03-04) use -sSTRICT
           for the canonical builds.
        */
        if( !!Module.HEAPU64 ) return true;
        /* Else fall through and hope for the best. Nobody _really_
           builds this without BigInt support, do they? */
      }
      return !!globalThis.BigInt64Array;
    })(),
    debug: console.debug.bind(console),
    warn: console.warn.bind(console),
    error: console.error.bind(console),
    log: console.log.bind(console),
145
146
147
148
149
150
151









152
153
154
155
156
157
158
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198







+
+
+
+
+
+
+
+
+







    // the result of calling that function...
    'exports', 'memory', 'wasmfsOpfsDir'
  ].forEach((k)=>{
    if('function' === typeof config[k]){
      config[k] = config[k]();
    }
  });

  /**
     Eliminate any confusion about whether these config objects may
     be used after library initialization by eliminating the outward-facing
     objects...
  */
  delete globalThis.sqlite3ApiConfig;
  delete sqlite3ApiBootstrap.defaultConfig;

  /**
      The main sqlite3 binding API gets installed into this object,
      mimicking the C API as closely as we can. The numerous members
      names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
      possible, identically to the C-native counterparts, as documented at:

      https://www.sqlite.org/c3ref/intro.html
1057
1058
1059
1060
1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
1097
1098
1099
1100
1101
1102
1103

1104
1105
1106
1107
1108
1109
1110
1111







-
+







  */
  wasm.pstack = Object.assign(Object.create(null),{
    /**
       Sets the current pstack position to the given pointer. Results
       are undefined if the passed-in value did not come from
       this.pointer.
    */
    restore: wasm.exports.sqlite3_wasm_pstack_restore,
    restore: wasm.exports.sqlite3__wasm_pstack_restore,
    /**
       Attempts to allocate the given number of bytes from the
       pstack. On success, it zeroes out a block of memory of the
       given size, adjusts the pstack pointer, and returns a pointer
       to the memory. On error, throws a WasmAllocError. The
       memory must eventually be released using restore().

1079
1080
1081
1082
1083
1084
1085
1086

1087
1088
1089
1090
1091
1092
1093
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
1133







-
+







       results when reading and writing 64-bit values from/to the WASM
       heap. Similarly, the returned address is always 8-byte aligned.
    */
    alloc: function(n){
      if('string'===typeof n && !(n = wasm.sizeofIR(n))){
        WasmAllocError.toss("Invalid value for pstack.alloc(",arguments[0],")");
      }
      return wasm.exports.sqlite3_wasm_pstack_alloc(n)
      return wasm.exports.sqlite3__wasm_pstack_alloc(n)
        || WasmAllocError.toss("Could not allocate",n,
                               "bytes from the pstack.");
    },
    /**
       alloc()'s n chunks, each sz bytes, as a single memory block and
       returns the addresses as an array of n element, each holding
       the address of one chunk.
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
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







-
+


-
+








-
+







-
+







       position pointer. This value is intended _only_ to be saved
       for passing to restore(). Writing to this memory, without
       first reserving it via wasm.pstack.alloc() and friends, leads
       to undefined results.
    */
    pointer: {
      configurable: false, iterable: true, writeable: false,
      get: wasm.exports.sqlite3_wasm_pstack_ptr
      get: wasm.exports.sqlite3__wasm_pstack_ptr
      //Whether or not a setter as an alternative to restore() is
      //clearer or would just lead to confusion is unclear.
      //set: wasm.exports.sqlite3_wasm_pstack_restore
      //set: wasm.exports.sqlite3__wasm_pstack_restore
    },
    /**
       sqlite3.wasm.pstack.quota to the total number of bytes
       available in the pstack, including any space which is currently
       allocated. This value is a compile-time constant.
    */
    quota: {
      configurable: false, iterable: true, writeable: false,
      get: wasm.exports.sqlite3_wasm_pstack_quota
      get: wasm.exports.sqlite3__wasm_pstack_quota
    },
    /**
       sqlite3.wasm.pstack.remaining resolves to the amount of space
       remaining in the pstack.
    */
    remaining: {
      configurable: false, iterable: true, writeable: false,
      get: wasm.exports.sqlite3_wasm_pstack_remaining
      get: wasm.exports.sqlite3__wasm_pstack_remaining
    }
  })/*wasm.pstack properties*/;

  capi.sqlite3_randomness = (...args)=>{
    if(1===args.length && util.isTypedArray(args[0])
      && 1===args[0].BYTES_PER_ELEMENT){
      const ta = args[0];
1252
1253
1254
1255
1256
1257
1258
1259

1260
1261
1262
1263
1264
1265
1266

1267
1268
1269
1270
1271
1272
1273
1292
1293
1294
1295
1296
1297
1298

1299
1300
1301
1302
1303
1304
1305

1306
1307
1308
1309
1310
1311
1312
1313







-
+






-
+







       || !globalThis.FileSystemHandle
       || !globalThis.FileSystemDirectoryHandle
       || !globalThis.FileSystemFileHandle){
      return __wasmfsOpfsDir = "";
    }
    try{
      if(pdir && 0===wasm.xCallWrapped(
        'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
        'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir
      )){
        return __wasmfsOpfsDir = pdir;
      }else{
        return __wasmfsOpfsDir = "";
      }
    }catch(e){
      // sqlite3_wasm_init_wasmfs() is not available
      // sqlite3__wasm_init_wasmfs() is not available
      return __wasmfsOpfsDir = "";
    }
  };

  /**
     Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
     non-empty string and the given name starts with (that string +
1361
1362
1363
1364
1365
1366
1367
1368

1369
1370
1371
1372
1373
1374
1375
1401
1402
1403
1404
1405
1406
1407

1408
1409
1410
1411
1412
1413
1414
1415







-
+







         that memory block, fetching the value of pSize after the
         export reads a garbage size because it's not on an 8-byte
         memory boundary!
      */
      const zSchema = schema
            ? (wasm.isPtr(schema) ? schema : wasm.scopedAllocCString(''+schema))
            : 0;
      let rc = wasm.exports.sqlite3_wasm_db_serialize(
      let rc = wasm.exports.sqlite3__wasm_db_serialize(
        pDb, zSchema, ppOut, pSize, 0
      );
      if(rc){
        toss3("Database serialization failed with code",
             sqlite3.capi.sqlite3_js_rc_str(rc));
      }
      pOut = wasm.peekPtr(ppOut);
1387
1388
1389
1390
1391
1392
1393
1394

1395
1396
1397
1398
1399
1400
1401
1427
1428
1429
1430
1431
1432
1433

1434
1435
1436
1437
1438
1439
1440
1441







-
+







  /**
     Given a `sqlite3*` and a database name (JS string or WASM
     C-string pointer, which may be 0), returns a pointer to the
     sqlite3_vfs responsible for it. If the given db name is null/0,
     or not provided, then "main" is assumed.
  */
  capi.sqlite3_js_db_vfs =
    (dbPointer, dbName=0)=>wasm.sqlite3_wasm_db_vfs(dbPointer, dbName);
    (dbPointer, dbName=0)=>util.sqlite3__wasm_db_vfs(dbPointer, dbName);

  /**
     A thin wrapper around capi.sqlite3_aggregate_context() which
     behaves the same except that it throws a WasmAllocError if that
     function returns 0. As a special case, if n is falsy it does
     _not_ throw if that function returns 0. That special case is
     intended for use with xFinal() implementations.
1445
1446
1447
1448
1449
1450
1451
1452

1453
1454
1455
1456
1457
1458
1459
1485
1486
1487
1488
1489
1490
1491

1492
1493
1494
1495
1496
1497
1498
1499







-
+







    }else{
      SQLite3Error.toss("Invalid 2nd argument for sqlite3_js_posix_create_file().");
    }
    try{
      if(!util.isInt32(dataLen) || dataLen<0){
        SQLite3Error.toss("Invalid 3rd argument for sqlite3_js_posix_create_file().");
      }
      const rc = wasm.sqlite3_wasm_posix_create_file(filename, pData, dataLen);
      const rc = util.sqlite3__wasm_posix_create_file(filename, pData, dataLen);
      if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
                               capi.sqlite3_js_rc_str(rc));
    }finally{
       wasm.dealloc(pData);
    }
  };

1547
1548
1549
1550
1551
1552
1553
1554

1555
1556
1557
1558
1559
1560
1561
1587
1588
1589
1590
1591
1592
1593

1594
1595
1596
1597
1598
1599
1600
1601







-
+







       pData = 0;
    }
    if(!util.isInt32(dataLen) || dataLen<0){
      wasm.dealloc(pData);
      SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file().");
    }
    try{
      const rc = wasm.sqlite3_wasm_vfs_create_file(vfs, filename, pData, dataLen);
      const rc = util.sqlite3__wasm_vfs_create_file(vfs, filename, pData, dataLen);
      if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
                               capi.sqlite3_js_rc_str(rc));
    }finally{
       wasm.dealloc(pData);
    }
  };

1668
1669
1670
1671
1672
1673
1674
1675

1676
1677
1678

1679
1680

1681
1682
1683
1684
1685
1686
1687
1708
1709
1710
1711
1712
1713
1714

1715
1716
1717

1718
1719

1720
1721
1722
1723
1724
1725
1726
1727







-
+


-
+

-
+







     Returns capi.SQLITE_MISUSE if op is not a valid operation ID.

     The variants which take `(int, int*)` arguments treat a
     missing or falsy pointer argument as 0.
  */
  capi.sqlite3_db_config = function(pDb, op, ...args){
    if(!this.s){
      this.s = wasm.xWrap('sqlite3_wasm_db_config_s','int',
      this.s = wasm.xWrap('sqlite3__wasm_db_config_s','int',
                          ['sqlite3*', 'int', 'string:static']
                          /* MAINDBNAME requires a static string */);
      this.pii = wasm.xWrap('sqlite3_wasm_db_config_pii', 'int',
      this.pii = wasm.xWrap('sqlite3__wasm_db_config_pii', 'int',
                            ['sqlite3*', 'int', '*','int', 'int']);
      this.ip = wasm.xWrap('sqlite3_wasm_db_config_ip','int',
      this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int',
                           ['sqlite3*', 'int', 'int','*']);
    }
    switch(op){
        case capi.SQLITE_DBCONFIG_ENABLE_FKEY:
        case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER:
        case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
        case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
Changes to ext/wasm/api/sqlite3-api-worker1.js.

1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
+







//#ifnot omit-oo1
/**
  2022-07-22

  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.
58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73







-
+







  Common message format...

  Each message posted to the worker has an operation-independent
  envelope and operation-dependent arguments:

  ```
  {
    type: string, // one of: 'open', 'close', 'exec', 'config-get'
    type: string, // one of: 'open', 'close', 'exec', 'export', 'config-get'

    messageId: OPTIONAL arbitrary value. The worker will copy it as-is
    into response messages to assist in client-side dispatching.

    dbId: a db identifier string (returned by 'open') which tells the
    operation which database instance to work on. If not provided, the
    first-opened db is used. This is an "opaque" value, with no
321
322
323
324
325
326
327































328
329

330
331
332
333
334
335
336
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







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


+







  call will tie up the Worker thread, causing any recursion attempt
  to wait until the first exec() is completed.

  The response is the input options object (or a synthesized one if
  passed only a string), noting that options.resultRows and
  options.columnNames may be populated by the call to db.exec().


  ====================================================================
  "export" the current db

  To export the underlying database as a byte array...

  Message format:

  ```
  {
    type: "export",
    messageId: ...as above...,
    dbId: ...as above...
  }
  ```

  Response:

  ```
  {
    type: "export",
    messageId: ...as above...,
    dbId: ...as above...
    result: {
      byteArray: Uint8Array (as per sqlite3_js_db_export()),
      filename: the db filename,
      mimetype: "application/x-sqlite3"
    }
  }
  ```

*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const util = sqlite3.util;
sqlite3.initWorker1API = function(){
  'use strict';
  const toss = (...args)=>{throw new Error(args.join(' '))};
  if(!(globalThis.WorkerGlobalScope instanceof Function)){
    toss("initWorker1API() must be run from a Worker thread.");
  }
  const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object.");
373
374
375
376
377
378
379
380

381
382
383
384
385

386
387
388
389
390
391
392
406
407
408
409
410
411
412

413
414
415
416
417

418
419
420
421
422
423
424
425







-
+




-
+







      if(this.dbList.indexOf(db)<0) this.dbList.push(db);
      return db;
    },
    close: function(db,alsoUnlink){
      if(db){
        delete this.dbs[getDbId(db)];
        const filename = db.filename;
        const pVfs = sqlite3.wasm.sqlite3_wasm_db_vfs(db.pointer, 0);
        const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0);
        db.close();
        const ddNdx = this.dbList.indexOf(db);
        if(ddNdx>=0) this.dbList.splice(ddNdx, 1);
        if(alsoUnlink && filename && pVfs){
          sqlite3.wasm.sqlite3_wasm_vfs_unlink(pVfs, filename);
          util.sqlite3__wasm_vfs_unlink(pVfs, filename);
        }
      }
    },
    /**
       Posts the given worker message value. If xferList is provided,
       it must be an array, in which case a copy of it passed as
       postMessage()'s second argument and xferList.length is set to
459
460
461
462
463
464
465
466

467
468
469
470
471

472
473
474
475
476
477
478
492
493
494
495
496
497
498

499
500
501
502
503

504
505
506
507
508
509
510
511







-
+




-
+







      }else{
        oargs.filename = args.filename;
        byteArray = args.byteArray;
        if(byteArray) pVfs = guessVfs(args.filename);
      }
      if(pVfs){
        /* 2022-11-02: this feature is as-yet untested except that
           sqlite3_wasm_vfs_create_file() has been tested from the
           sqlite3__wasm_vfs_create_file() has been tested from the
           browser dev console. */
        let pMem;
        try{
          pMem = sqlite3.wasm.allocFromTypedArray(byteArray);
          const rc = sqlite3.wasm.sqlite3_wasm_vfs_create_file(
          const rc = util.sqlite3__wasm_vfs_create_file(
            pVfs, oargs.filename, pMem, byteArray.byteLength
          );
          if(rc) sqlite3.SQLite3Error.toss(rc);
        }catch(e){
          throw new sqlite3.SQLite3Error(
            e.name+' creating '+args.filename+": "+e.message, {
              cause: e
654
655
656
657
658
659
660



687
688
689
690
691
692
693
694
695
696







+
+
+
      //},
      result: result
    }, wState.xfer);
  };
  globalThis.postMessage({type:'sqlite3-api',result:'worker1-ready'});
}.bind({sqlite3});
});
//#else
/* Built with the omit-oo1 flag. */
//#endif ifnot omit-oo1
Changes to ext/wasm/api/sqlite3-opfs-async-proxy.js.
47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61







-
+







  synchronous, but we do do not use those APIs that way. i.e. we don't
  _need_ to change anything for this, but at some point (after Chrome
  versions (approximately) 104-107 are extinct) should change our
  usage of those methods to remove the "await".
*/
"use strict";
const wPost = (type,...args)=>postMessage({type, payload:args});
const installAsyncProxy = function(self){
const installAsyncProxy = function(){
  const toss = function(...args){throw new Error(args.join(' '))};
  if(globalThis.window === globalThis){
    toss("This code cannot run from the main thread.",
         "Load it as a Worker from a separate Worker.");
  }else if(!navigator?.storage?.getDirectory){
    toss("This API requires navigator.storage.getDirectory.");
  }
557
558
559
560
561
562
563








564
565
566
567
568
569
570
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578







+
+
+
+
+
+
+
+







          [hDir, filenamePart] = await getDirForFilename(filename, !!create);
        }catch(e){
          state.s11n.storeException(1,e);
          storeAndNotify(opName, state.sq3Codes.SQLITE_NOTFOUND);
          mTimeEnd();
          wTimeEnd();
          return;
        }
        if( state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags ){
          try{
            await hDir.removeEntry(filenamePart);
          }catch(e){
            /* ignoring */
            //warn("Ignoring failed Unlink of",filename,":",e);
          }
        }
        const hFile = await hDir.getFileHandle(filenamePart, {create});
        wTimeEnd();
        const fh = Object.assign(Object.create(null),{
          fid: fid,
          filenameAbs: filename,
          filenamePart: filenamePart,
907
908
909
910
911
912
913
914

915
915
916
917
918
919
920
921

922
923







-
+

}else if(!globalThis.FileSystemHandle ||
         !globalThis.FileSystemDirectoryHandle ||
         !globalThis.FileSystemFileHandle ||
         !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle ||
         !navigator?.storage?.getDirectory){
  wPost('opfs-unavailable',"Missing required OPFS APIs.");
}else{
  installAsyncProxy(self);
  installAsyncProxy();
}
Deleted ext/wasm/api/sqlite3-v-helper.js.
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718














































































































































































































































































































































































































































































































































































































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
** 2022-11-30
**
** The author disclaims copyright to this source code.  In place of a
** legal notice, here is a blessing:
**
** *   May you do good and not evil.
** *   May you find forgiveness for yourself and forgive others.
** *   May you share freely, never taking more than you give.
*/

/**
   This file installs sqlite3.vfs, and object which exists to assist
   in the creation of JavaScript implementations of sqlite3_vfs, along
   with its virtual table counterpart, sqlite3.vtab.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
  const vfs = Object.create(null), vtab = Object.create(null);

  const StructBinder = sqlite3.StructBinder
  /* we require a local alias b/c StructBinder is removed from the sqlite3
     object during the final steps of the API cleanup. */;
  sqlite3.vfs = vfs;
  sqlite3.vtab = vtab;

  const sii = capi.sqlite3_index_info;
  /**
     If n is >=0 and less than this.$nConstraint, this function
     returns either a WASM pointer to the 0-based nth entry of
     this.$aConstraint (if passed a truthy 2nd argument) or an
     sqlite3_index_info.sqlite3_index_constraint object wrapping that
     address (if passed a falsy value or no 2nd argument). Returns a
     falsy value if n is out of range.
  */
  sii.prototype.nthConstraint = function(n, asPtr=false){
    if(n<0 || n>=this.$nConstraint) return false;
    const ptr = this.$aConstraint + (
      sii.sqlite3_index_constraint.structInfo.sizeof * n
    );
    return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr);
  };

  /**
     Works identically to nthConstraint() but returns state from
     this.$aConstraintUsage, so returns an
     sqlite3_index_info.sqlite3_index_constraint_usage instance
     if passed no 2nd argument or a falsy 2nd argument.
  */
  sii.prototype.nthConstraintUsage = function(n, asPtr=false){
    if(n<0 || n>=this.$nConstraint) return false;
    const ptr = this.$aConstraintUsage + (
      sii.sqlite3_index_constraint_usage.structInfo.sizeof * n
    );
    return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr);
  };

  /**
     If n is >=0 and less than this.$nOrderBy, this function
     returns either a WASM pointer to the 0-based nth entry of
     this.$aOrderBy (if passed a truthy 2nd argument) or an
     sqlite3_index_info.sqlite3_index_orderby object wrapping that
     address (if passed a falsy value or no 2nd argument). Returns a
     falsy value if n is out of range.
  */
  sii.prototype.nthOrderBy = function(n, asPtr=false){
    if(n<0 || n>=this.$nOrderBy) return false;
    const ptr = this.$aOrderBy + (
      sii.sqlite3_index_orderby.structInfo.sizeof * n
    );
    return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr);
  };

  /**
     Installs a StructBinder-bound function pointer member of the
     given name and function in the given StructType target object.

     It creates a WASM proxy for the given function and arranges for
     that proxy to be cleaned up when tgt.dispose() is called. Throws
     on the slightest hint of error, e.g. tgt is-not-a StructType,
     name does not map to a struct-bound member, etc.

     As a special case, if the given function is a pointer, then
     `wasm.functionEntry()` is used to validate that it is a known
     function. If so, it is used as-is with no extra level of proxying
     or cleanup, else an exception is thrown. It is legal to pass a
     value of 0, indicating a NULL pointer, with the caveat that 0
     _is_ a legal function pointer in WASM but it will not be accepted
     as such _here_. (Justification: the function at address zero must
     be one which initially came from the WASM module, not a method we
     want to bind to a virtual table or VFS.)

     This function returns a proxy for itself which is bound to tgt
     and takes 2 args (name,func). That function returns the same
     thing as this one, permitting calls to be chained.

     If called with only 1 arg, it has no side effects but returns a
     func with the same signature as described above.

     ACHTUNG: because we cannot generically know how to transform JS
     exceptions into result codes, the installed functions do no
     automatic catching of exceptions. It is critical, to avoid
     undefined behavior in the C layer, that methods mapped via
     this function do not throw. The exception, as it were, to that
     rule is...

     If applyArgcCheck is true then each JS function (as opposed to
     function pointers) gets wrapped in a proxy which asserts that it
     is passed the expected number of arguments, throwing if the
     argument count does not match expectations. That is only intended
     for dev-time usage for sanity checking, and will leave the C
     environment in an undefined state.
  */
  const installMethod = function callee(
    tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
  ){
    if(!(tgt instanceof StructBinder.StructType)){
      toss("Usage error: target object is-not-a StructType.");
    }else if(!(func instanceof Function) && !wasm.isPtr(func)){
      toss("Usage errror: expecting a Function or WASM pointer to one.");
    }
    if(1===arguments.length){
      return (n,f)=>callee(tgt, n, f, applyArgcCheck);
    }
    if(!callee.argcProxy){
      callee.argcProxy = function(tgt, funcName, func,sig){
        return function(...args){
          if(func.length!==arguments.length){
            toss("Argument mismatch for",
                 tgt.structInfo.name+"::"+funcName
                 +": Native signature is:",sig);
          }
          return func.apply(this, args);
        }
      };
      /* An ondispose() callback for use with
         StructBinder-created types. */
      callee.removeFuncList = function(){
        if(this.ondispose.__removeFuncList){
          this.ondispose.__removeFuncList.forEach(
            (v,ndx)=>{
              if('number'===typeof v){
                try{wasm.uninstallFunction(v)}
                catch(e){/*ignore*/}
              }
              /* else it's a descriptive label for the next number in
                 the list. */
            }
          );
          delete this.ondispose.__removeFuncList;
        }
      };
    }/*static init*/
    const sigN = tgt.memberSignature(name);
    if(sigN.length<2){
      toss("Member",name,"does not have a function pointer signature:",sigN);
    }
    const memKey = tgt.memberKey(name);
    const fProxy = (applyArgcCheck && !wasm.isPtr(func))
    /** This middle-man proxy is only for use during development, to
        confirm that we always pass the proper number of
        arguments. We know that the C-level code will always use the
        correct argument count. */
          ? callee.argcProxy(tgt, memKey, func, sigN)
          : func;
    if(wasm.isPtr(fProxy)){
      if(fProxy && !wasm.functionEntry(fProxy)){
        toss("Pointer",fProxy,"is not a WASM function table entry.");
      }
      tgt[memKey] = fProxy;
    }else{
      const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
      tgt[memKey] = pFunc;
      if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
        tgt.addOnDispose('ondispose.__removeFuncList handler',
                         callee.removeFuncList);
        tgt.ondispose.__removeFuncList = [];
      }
      tgt.ondispose.__removeFuncList.push(memKey, pFunc);
    }
    return (n,f)=>callee(tgt, n, f, applyArgcCheck);
  }/*installMethod*/;
  installMethod.installMethodArgcCheck = false;

  /**
     Installs methods into the given StructType-type instance. Each
     entry in the given methods object must map to a known member of
     the given StructType, else an exception will be triggered.  See
     installMethod() for more details, including the semantics of the
     3rd argument.

     As an exception to the above, if any two or more methods in the
     2nd argument are the exact same function, installMethod() is
     _not_ called for the 2nd and subsequent instances, and instead
     those instances get assigned the same method pointer which is
     created for the first instance. This optimization is primarily to
     accommodate special handling of sqlite3_module::xConnect and
     xCreate methods.

     On success, returns its first argument. Throws on error.
  */
  const installMethods = function(
    structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
  ){
    const seen = new Map /* map of <Function, memberName> */;
    for(const k of Object.keys(methods)){
      const m = methods[k];
      const prior = seen.get(m);
      if(prior){
        const mkey = structInstance.memberKey(k);
        structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
      }else{
        installMethod(structInstance, k, m, applyArgcCheck);
        seen.set(m, k);
      }
    }
    return structInstance;
  };

  /**
     Equivalent to calling installMethod(this,...arguments) with a
     first argument of this object. If called with 1 or 2 arguments
     and the first is an object, it's instead equivalent to calling
     installMethods(this,...arguments).
  */
  StructBinder.StructType.prototype.installMethod = function callee(
    name, func, applyArgcCheck = installMethod.installMethodArgcCheck
  ){
    return (arguments.length < 3 && name && 'object'===typeof name)
      ? installMethods(this, ...arguments)
      : installMethod(this, ...arguments);
  };

  /**
     Equivalent to calling installMethods() with a first argument
     of this object.
  */
  StructBinder.StructType.prototype.installMethods = function(
    methods, applyArgcCheck = installMethod.installMethodArgcCheck
  ){
    return installMethods(this, methods, applyArgcCheck);
  };

  /**
     Uses sqlite3_vfs_register() to register this
     sqlite3.capi.sqlite3_vfs. This object must have already been
     filled out properly. If the first argument is truthy, the VFS is
     registered as the default VFS, else it is not.

     On success, returns this object. Throws on error.
  */
  capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
    if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
      toss("Expecting a sqlite3_vfs-type argument.");
    }
    const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
    if(rc){
      toss("sqlite3_vfs_register(",this,") failed with rc",rc);
    }
    if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
      toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
           this);
    }
    return this;
  };

  /**
     A wrapper for installMethods() or registerVfs() to reduce
     installation of a VFS and/or its I/O methods to a single
     call.

     Accepts an object which contains the properties "io" and/or
     "vfs", each of which is itself an object with following properties:

     - `struct`: an sqlite3.StructType-type struct. This must be a
       populated (except for the methods) object of type
       sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
       "vfs" entry).

     - `methods`: an object mapping sqlite3_io_methods method names
       (e.g. 'xClose') to JS implementations of those methods. The JS
       implementations must be call-compatible with their native
       counterparts.

     For each of those object, this function passes its (`struct`,
     `methods`, (optional) `applyArgcCheck`) properties to
     installMethods().

     If the `vfs` entry is set then:

     - Its `struct` property's registerVfs() is called. The
       `vfs` entry may optionally have an `asDefault` property, which
       gets passed as the argument to registerVfs().

     - If `struct.$zName` is falsy and the entry has a string-type
       `name` property, `struct.$zName` is set to the C-string form of
       that `name` value before registerVfs() is called. That string
       gets added to the on-dispose state of the struct.

     On success returns this object. Throws on error.
  */
  vfs.installVfs = function(opt){
    let count = 0;
    const propList = ['io','vfs'];
    for(const key of propList){
      const o = opt[key];
      if(o){
        ++count;
        installMethods(o.struct, o.methods, !!o.applyArgcCheck);
        if('vfs'===key){
          if(!o.struct.$zName && 'string'===typeof o.name){
            o.struct.addOnDispose(
              o.struct.$zName = wasm.allocCString(o.name)
            );
          }
          o.struct.registerVfs(!!o.asDefault);
        }
      }
    }
    if(!count) toss("Misuse: installVfs() options object requires at least",
                    "one of:", propList);
    return this;
  };

  /**
     Internal factory function for xVtab and xCursor impls.
  */
  const __xWrapFactory = function(methodName,StructType){
    return function(ptr,removeMapping=false){
      if(0===arguments.length) ptr = new StructType;
      if(ptr instanceof StructType){
        //T.assert(!this.has(ptr.pointer));
        this.set(ptr.pointer, ptr);
        return ptr;
      }else if(!wasm.isPtr(ptr)){
        sqlite3.SQLite3Error.toss("Invalid argument to",methodName+"()");
      }
      let rc = this.get(ptr);
      if(removeMapping) this.delete(ptr);
      return rc;
    }.bind(new Map);
  };

  /**
     A factory function which implements a simple lifetime manager for
     mappings between C struct pointers and their JS-level wrappers.
     The first argument must be the logical name of the manager
     (e.g. 'xVtab' or 'xCursor'), which is only used for error
     reporting. The second must be the capi.XYZ struct-type value,
     e.g. capi.sqlite3_vtab or capi.sqlite3_vtab_cursor.

     Returns an object with 4 methods: create(), get(), unget(), and
     dispose(), plus a StructType member with the value of the 2nd
     argument. The methods are documented in the body of this
     function.
  */
  const StructPtrMapper = function(name, StructType){
    const __xWrap = __xWrapFactory(name,StructType);
    /**
       This object houses a small API for managing mappings of (`T*`)
       to StructType<T> objects, specifically within the lifetime
       requirements of sqlite3_module methods.
    */
    return Object.assign(Object.create(null),{
      /** The StructType object for this object's API. */
      StructType,
      /**
         Creates a new StructType object, writes its `pointer`
         value to the given output pointer, and returns that
         object. Its intended usage depends on StructType:

         sqlite3_vtab: to be called from sqlite3_module::xConnect()
         or xCreate() implementations.

         sqlite3_vtab_cursor: to be called from xOpen().

         This will throw if allocation of the StructType instance
         fails or if ppOut is not a pointer-type value.
      */
      create: (ppOut)=>{
        const rc = __xWrap();
        wasm.pokePtr(ppOut, rc.pointer);
        return rc;
      },
      /**
         Returns the StructType object previously mapped to the
         given pointer using create(). Its intended usage depends
         on StructType:

         sqlite3_vtab: to be called from sqlite3_module methods which
         take a (sqlite3_vtab*) pointer _except_ for
         xDestroy()/xDisconnect(), in which case unget() or dispose().

         sqlite3_vtab_cursor: to be called from any sqlite3_module methods
         which take a `sqlite3_vtab_cursor*` argument except xClose(),
         in which case use unget() or dispose().

         Rule to remember: _never_ call dispose() on an instance
         returned by this function.
      */
      get: (pCObj)=>__xWrap(pCObj),
      /**
         Identical to get() but also disconnects the mapping between the
         given pointer and the returned StructType object, such that
         future calls to this function or get() with the same pointer
         will return the undefined value. Its intended usage depends
         on StructType:

         sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or
         xDestroy() implementations or in error handling of a failed
         xCreate() or xConnect().

         sqlite3_vtab_cursor: to be called from xClose() or during
         cleanup in a failed xOpen().

         Calling this method obligates the caller to call dispose() on
         the returned object when they're done with it.
      */
      unget: (pCObj)=>__xWrap(pCObj,true),
      /**
         Works like unget() plus it calls dispose() on the
         StructType object.
      */
      dispose: (pCObj)=>{
        const o = __xWrap(pCObj,true);
        if(o) o.dispose();
      }
    });
  };

  /**
     A lifetime-management object for mapping `sqlite3_vtab*`
     instances in sqlite3_module methods to capi.sqlite3_vtab
     objects.

     The API docs are in the API-internal StructPtrMapper().
  */
  vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);

  /**
     A lifetime-management object for mapping `sqlite3_vtab_cursor*`
     instances in sqlite3_module methods to capi.sqlite3_vtab_cursor
     objects.

     The API docs are in the API-internal StructPtrMapper().
  */
  vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);

  /**
     Convenience form of creating an sqlite3_index_info wrapper,
     intended for use in xBestIndex implementations. Note that the
     caller is expected to call dispose() on the returned object
     before returning. Though not _strictly_ required, as that object
     does not own the pIdxInfo memory, it is nonetheless good form.
  */
  vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);

  /**
     Given an error object, this function returns
     sqlite3.capi.SQLITE_NOMEM if (e instanceof
     sqlite3.WasmAllocError), else it returns its
     second argument. Its intended usage is in the methods
     of a sqlite3_vfs or sqlite3_module:

     ```
     try{
      let rc = ...
      return rc;
     }catch(e){
       return sqlite3.vtab.exceptionToRc(e, sqlite3.capi.SQLITE_XYZ);
       // where SQLITE_XYZ is some call-appropriate result code.
     }
     ```
  */
  /**vfs.exceptionToRc = vtab.exceptionToRc =
    (e, defaultRc=capi.SQLITE_ERROR)=>(
      (e instanceof sqlite3.WasmAllocError)
        ? capi.SQLITE_NOMEM
        : defaultRc
    );*/

  /**
     Given an sqlite3_module method name and error object, this
     function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof
     sqlite3.WasmAllocError), else it returns its second argument. Its
     intended usage is in the methods of a sqlite3_vfs or
     sqlite3_module:

     ```
     try{
      let rc = ...
      return rc;
     }catch(e){
       return sqlite3.vtab.xError(
                'xColumn', e, sqlite3.capi.SQLITE_XYZ);
       // where SQLITE_XYZ is some call-appropriate result code.
     }
     ```

     If no 3rd argument is provided, its default depends on
     the error type:

     - An sqlite3.WasmAllocError always resolves to capi.SQLITE_NOMEM.

     - If err is an SQLite3Error then its `resultCode` property
       is used.

     - If all else fails, capi.SQLITE_ERROR is used.

     If xError.errorReporter is a function, it is called in
     order to report the error, else the error is not reported.
     If that function throws, that exception is ignored.
  */
  vtab.xError = function f(methodName, err, defaultRc){
    if(f.errorReporter instanceof Function){
      try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);}
      catch(e){/*ignored*/}
    }
    let rc;
    if(err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM;
    else if(arguments.length>2) rc = defaultRc;
    else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
    return rc || capi.SQLITE_ERROR;
  };
  vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;

  /**
     "The problem" with this is that it introduces an outer function with
     a different arity than the passed-in method callback. That means we
     cannot do argc validation on these. Additionally, some methods (namely
     xConnect) may have call-specific error handling. It would be a shame to
     hard-coded that per-method support in this function.
  */
  /** vtab.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
    return function(...args){
      try { method(...args); }
      }catch(e){ return vtab.xError(methodName, e, defaultRc) }
  };
  */

  /**
     A helper for sqlite3_vtab::xRowid() and xUpdate()
     implementations. It must be passed the final argument to one of
     those methods (an output pointer to an int64 row ID) and the
     value to store at the output pointer's address. Returns the same
     as wasm.poke() and will throw if the 1st or 2nd arguments
     are invalid for that function.

     Example xRowid impl:

     ```
     const xRowid = (pCursor, ppRowid64)=>{
       const c = vtab.xCursor(pCursor);
       vtab.xRowid(ppRowid64, c.myRowId);
       return 0;
     };
     ```
  */
  vtab.xRowid = (ppRowid64, value)=>wasm.poke(ppRowid64, value, 'i64');

  /**
     A helper to initialize and set up an sqlite3_module object for
     later installation into individual databases using
     sqlite3_create_module(). Requires an object with the following
     properties:

     - `methods`: an object containing a mapping of properties with
       the C-side names of the sqlite3_module methods, e.g. xCreate,
       xBestIndex, etc., to JS implementations for those functions.
       Certain special-case handling is performed, as described below.

     - `catchExceptions` (default=false): if truthy, the given methods
       are not mapped as-is, but are instead wrapped inside wrappers
       which translate exceptions into result codes of SQLITE_ERROR or
       SQLITE_NOMEM, depending on whether the exception is an
       sqlite3.WasmAllocError. In the case of the xConnect and xCreate
       methods, the exception handler also sets the output error
       string to the exception's error string.

     - OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If
       not set, one will be created automatically. If the current
       "this" is-a sqlite3_module then it is unconditionally used in
       place of `struct`.

     - OPTIONAL `iVersion`: if set, it must be an integer value and it
       gets assigned to the `$iVersion` member of the struct object.
       If it's _not_ set, and the passed-in `struct` object's `$iVersion`
       is 0 (the default) then this function attempts to define a value
       for that property based on the list of methods it has.

     If `catchExceptions` is false, it is up to the client to ensure
     that no exceptions escape the methods, as doing so would move
     them through the C API, leading to undefined
     behavior. (vtab.xError() is intended to assist in reporting
     such exceptions.)

     Certain methods may refer to the same implementation. To simplify
     the definition of such methods:

     - If `methods.xConnect` is `true` then the value of
       `methods.xCreate` is used in its place, and vice versa. sqlite
       treats xConnect/xCreate functions specially if they are exactly
       the same function (same pointer value).

     - If `methods.xDisconnect` is true then the value of
       `methods.xDestroy` is used in its place, and vice versa.

     This is to facilitate creation of those methods inline in the
     passed-in object without requiring the client to explicitly get a
     reference to one of them in order to assign it to the other
     one.

     The `catchExceptions`-installed handlers will account for
     identical references to the above functions and will install the
     same wrapper function for both.

     The given methods are expected to return integer values, as
     expected by the C API. If `catchExceptions` is truthy, the return
     value of the wrapped function will be used as-is and will be
     translated to 0 if the function returns a falsy value (e.g. if it
     does not have an explicit return). If `catchExceptions` is _not_
     active, the method implementations must explicitly return integer
     values.

     Throws on error. On success, returns the sqlite3_module object
     (`this` or `opt.struct` or a new sqlite3_module instance,
     depending on how it's called).
  */
  vtab.setupModule = function(opt){
    let createdMod = false;
    const mod = (this instanceof capi.sqlite3_module)
          ? this : (opt.struct || (createdMod = new capi.sqlite3_module()));
    try{
      const methods = opt.methods || toss("Missing 'methods' object.");
      for(const e of Object.entries({
        // -----^ ==> [k,v] triggers a broken code transformation in
        // some versions of the emsdk toolchain.
        xConnect: 'xCreate', xDisconnect: 'xDestroy'
      })){
        // Remap X=true to X=Y for certain X/Y combinations
        const k = e[0], v = e[1];
        if(true === methods[k]) methods[k] = methods[v];
        else if(true === methods[v]) methods[v] = methods[k];
      }
      if(opt.catchExceptions){
        const fwrap = function(methodName, func){
          if(['xConnect','xCreate'].indexOf(methodName) >= 0){
            return function(pDb, pAux, argc, argv, ppVtab, pzErr){
              try{return func(...arguments) || 0}
              catch(e){
                if(!(e instanceof sqlite3.WasmAllocError)){
                  wasm.dealloc(wasm.peekPtr(pzErr));
                  wasm.pokePtr(pzErr, wasm.allocCString(e.message));
                }
                return vtab.xError(methodName, e);
              }
            };
          }else{
            return function(...args){
              try{return func(...args) || 0}
              catch(e){
                return vtab.xError(methodName, e);
              }
            };
          }
        };
        const mnames = [
          'xCreate', 'xConnect', 'xBestIndex', 'xDisconnect',
          'xDestroy', 'xOpen', 'xClose', 'xFilter', 'xNext',
          'xEof', 'xColumn', 'xRowid', 'xUpdate',
          'xBegin', 'xSync', 'xCommit', 'xRollback',
          'xFindFunction', 'xRename', 'xSavepoint', 'xRelease',
          'xRollbackTo', 'xShadowName'
        ];
        const remethods = Object.create(null);
        for(const k of mnames){
          const m = methods[k];
          if(!(m instanceof Function)) continue;
          else if('xConnect'===k && methods.xCreate===m){
            remethods[k] = methods.xCreate;
          }else if('xCreate'===k && methods.xConnect===m){
            remethods[k] = methods.xConnect;
          }else{
            remethods[k] = fwrap(k, m);
          }
        }
        installMethods(mod, remethods, false);
      }else{
        // No automatic exception handling. Trust the client
        // to not throw.
        installMethods(
          mod, methods, !!opt.applyArgcCheck/*undocumented option*/
        );
      }
      if(0===mod.$iVersion){
        let v;
        if('number'===typeof opt.iVersion) v = opt.iVersion;
        else if(mod.$xShadowName) v = 3;
        else if(mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2;
        else v = 1;
        mod.$iVersion = v;
      }
    }catch(e){
      if(createdMod) createdMod.dispose();
      throw e;
    }
    return mod;
  }/*setupModule()*/;

  /**
     Equivalent to calling vtab.setupModule() with this sqlite3_module
     object as the call's `this`.
  */
  capi.sqlite3_module.prototype.setupModule = function(opt){
    return vtab.setupModule.call(this, opt);
  };
}/*sqlite3ApiBootstrap.initializers.push()*/);
Added ext/wasm/api/sqlite3-vfs-helper.c-pp.js.







































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2022-11-30
**
** The author disclaims copyright to this source code.  In place of a
** legal notice, here is a blessing:
**
** *   May you do good and not evil.
** *   May you find forgiveness for yourself and forgive others.
** *   May you share freely, never taking more than you give.
*/

/**
   This file installs sqlite3.vfs, a namespace of helpers for use in
   the creation of JavaScript implementations of sqlite3_vfs.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
  const vfs = Object.create(null);
  sqlite3.vfs = vfs;

  /**
     Uses sqlite3_vfs_register() to register this
     sqlite3.capi.sqlite3_vfs instance. This object must have already
     been filled out properly. If the first argument is truthy, the
     VFS is registered as the default VFS, else it is not.

     On success, returns this object. Throws on error.
  */
  capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
    if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
      toss("Expecting a sqlite3_vfs-type argument.");
    }
    const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
    if(rc){
      toss("sqlite3_vfs_register(",this,") failed with rc",rc);
    }
    if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
      toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
           this);
    }
    return this;
  };

  /**
     A wrapper for
     sqlite3.StructBinder.StructType.prototype.installMethods() or
     registerVfs() to reduce installation of a VFS and/or its I/O
     methods to a single call.

     Accepts an object which contains the properties "io" and/or
     "vfs", each of which is itself an object with following properties:

     - `struct`: an sqlite3.StructBinder.StructType-type struct. This
       must be a populated (except for the methods) object of type
       sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
       "vfs" entry).

     - `methods`: an object mapping sqlite3_io_methods method names
       (e.g. 'xClose') to JS implementations of those methods. The JS
       implementations must be call-compatible with their native
       counterparts.

     For each of those object, this function passes its (`struct`,
     `methods`, (optional) `applyArgcCheck`) properties to
     installMethods().

     If the `vfs` entry is set then:

     - Its `struct` property's registerVfs() is called. The
       `vfs` entry may optionally have an `asDefault` property, which
       gets passed as the argument to registerVfs().

     - If `struct.$zName` is falsy and the entry has a string-type
       `name` property, `struct.$zName` is set to the C-string form of
       that `name` value before registerVfs() is called. That string
       gets added to the on-dispose state of the struct.

     On success returns this object. Throws on error.
  */
  vfs.installVfs = function(opt){
    let count = 0;
    const propList = ['io','vfs'];
    for(const key of propList){
      const o = opt[key];
      if(o){
        ++count;
        o.struct.installMethods(o.methods, !!o.applyArgcCheck);
        if('vfs'===key){
          if(!o.struct.$zName && 'string'===typeof o.name){
            o.struct.addOnDispose(
              o.struct.$zName = wasm.allocCString(o.name)
            );
          }
          o.struct.registerVfs(!!o.asDefault);
        }
      }
    }
    if(!count) toss("Misuse: installVfs() options object requires at least",
                    "one of:", propList);
    return this;
  };
}/*sqlite3ApiBootstrap.initializers.push()*/);
Changes to ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js.
1133
1134
1135
1136
1137
1138
1139

1140
1141


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


1141
1142
1143
1144
1145
1146
1147
1148
1149







+
-
-
+
+







     - void importDb(name, bytes)

     Imports the contents of an SQLite database, provided as a byte
     array or ArrayBuffer, under the given name, overwriting any
     existing content. Throws if the pool has no available file slots,
     on I/O error, or if the input does not appear to be a
     database. In the latter case, only a cursory examination is made.
     Results are undefined if the given db name refers to an opened
     Note that this routine is _only_ for importing database files,
     not arbitrary files, the reason being that this VFS will
     db.  Note that this routine is _only_ for importing database
     files, not arbitrary files, the reason being that this VFS will
     automatically clean up any non-database files so importing them
     is pointless.

     If passed a function for its second argument, its behavior
     changes to asynchronous and it imports its data in chunks fed to
     it by the given callback function. It calls the callback (which
     may be async) repeatedly, expecting either a Uint8Array or
Changes to ext/wasm/api/sqlite3-vfs-opfs.c-pp.js.
241
242
243
244
245
246
247
248


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

248
249
250
251
252
253
254
255
256







-
+
+







    const dVfs = pDVfs
          ? new sqlite3_vfs(pDVfs)
          : null /* dVfs will be null when sqlite3 is built with
                    SQLITE_OS_OTHER. */;
    opfsIoMethods.$iVersion = 1;
    opfsVfs.$iVersion = 2/*yes, two*/;
    opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
    opfsVfs.$mxPathname = 1024/*sure, why not?*/;
    opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit
                                 is undocumented/unspecified. */;
    opfsVfs.$zName = wasm.allocCString("opfs");
    // All C-side memory of opfsVfs is zeroed out, but just to be explicit:
    opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
    opfsVfs.addOnDispose(
      '$zName', opfsVfs.$zName,
      'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null)
    );
418
419
420
421
422
423
424
425
426


427
428















429
430
431
432
433
434
435
419
420
421
422
423
424
425


426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451







-
-
+
+


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







    ].forEach((k)=>{
      if(undefined === (state.sq3Codes[k] = capi[k])){
        toss("Maintenance required: not found:",k);
      }
    });
    state.opfsFlags = Object.assign(Object.create(null),{
      /**
         Flag for use with xOpen(). "opfs-unlock-asap=1" enables
         this. See defaultUnlockAsap, below.
         Flag for use with xOpen(). URI flag "opfs-unlock-asap=1"
         enables this. See defaultUnlockAsap, below.
       */
      OPFS_UNLOCK_ASAP: 0x01,
      /**
         Flag for use with xOpen(). URI flag "delete-before-open=1"
         tells the VFS to delete the db file before attempting to open
         it. This can be used, e.g., to replace a db which has been
         corrupted (without forcing us to expose a delete/unlink()
         function in the public API).

         Failure to unlink the file is ignored but may lead to
         downstream errors.  An unlink can fail if, e.g., another tab
         has the handle open.

         It goes without saying that deleting a file out from under another
         instance results in Undefined Behavior.
      */
      OPFS_UNLINK_BEFORE_OPEN: 0x02,
      /**
         If true, any async routine which implicitly acquires a sync
         access handle (i.e. an OPFS lock) will release that locks at
         the end of the call which acquires it. If false, such
         "autolocks" are not released until the VFS is idle for some
         brief amount of time.

870
871
872
873
874
875
876
877

878
879
880
881
882



883

884
885
886
887
888
889
890
886
887
888
889
890
891
892

893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910







-
+





+
+
+

+







      },
      //xSleep is optionally defined below
      xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
        mTimeStart('xOpen');
        let opfsFlags = 0;
        if(0===zName){
          zName = randomFilename();
        }else if('number'===typeof zName){
        }else if(wasm.isPtr(zName)){
          if(capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)){
            /* -----------------------^^^^^ MUST pass the untranslated
               C-string here. */
            opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP;
          }
          if(capi.sqlite3_uri_boolean(zName, "delete-before-open", 0)){
            opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN;
          }
          zName = wasm.cstrToJs(zName);
          //warn("xOpen zName =",zName, "opfsFlags =",opfsFlags);
        }
        const fh = Object.create(null);
        fh.fid = pFile;
        fh.filename = zName;
        fh.sab = new SharedArrayBuffer(state.fileBufferSize);
        fh.flags = flags;
        const rc = opRun('xOpen', pFile, zName, flags, opfsFlags);
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1009
1010
1011
1012
1013
1014
1015





















1016
1017
1018
1019
1020
1021
1022







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







    /**
       Generates a random ASCII string, intended for use as a
       temporary file name. Its argument is the length of the string,
       defaulting to 16.
    */
    opfsUtil.randomFilename = randomFilename;

    /**
       Re-registers the OPFS VFS. This is intended only for odd use
       cases which have to call sqlite3_shutdown() as part of their
       initialization process, which will unregister the VFS
       registered by installOpfsVfs(). If passed a truthy value, the
       OPFS VFS is registered as the default VFS, else it is not made
       the default. Returns the result of the the
       sqlite3_vfs_register() call.

       Design note: the problem of having to re-register things after
       a shutdown/initialize pair is more general. How to best plug
       that in to the library is unclear. In particular, we cannot
       hook in to any C-side calls to sqlite3_initialize(), so we
       cannot add an after-initialize callback mechanism.
    */
    opfsUtil.registerVfs = (asDefault=false)=>{
      return wasm.exports.sqlite3_vfs_register(
        opfsVfs.pointer, asDefault ? 1 : 0
      );
    };

    /**
       Returns a promise which resolves to an object which represents
       all files and directories in the OPFS tree. The top-most object
       has two properties: `dirs` is an array of directory entries
       (described below) and `files` is a list of file names for all
       files in that directory.

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








+
+
+

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







        if( sah ) await sah.close();
      }
    };

    /**
       Asynchronously imports the given bytes (a byte array or
       ArrayBuffer) into the given database file.

       Results are undefined if the given db name refers to an opened
       db.

       If passed a function for its second argument, its behaviour
       changes to async and it imports its data in chunks fed to it by
       the given callback function. It calls the callback (which may
       be async) repeatedly, expecting either a Uint8Array or
       ArrayBuffer (to denote new input) or undefined (to denote
       EOF). For so long as the callback continues to return
       non-undefined, it will append incoming data to the given
       VFS-hosted database file. When called this way, the resolved
       value of the returned Promise is the number of bytes written to
       changes: imports its data in chunks fed to it by the given
       callback function. It calls the callback (which may be async)
       repeatedly, expecting either a Uint8Array or ArrayBuffer (to
       denote new input) or undefined (to denote EOF). For so long as
       the callback continues to return non-undefined, it will append
       incoming data to the given VFS-hosted database file. When
       called this way, the resolved value of the returned Promise is
       the number of bytes written to the target file.
       the target file.

       It very specifically requires the input to be an SQLite3
       database and throws if that's not the case.  It does so in
       order to prevent this function from taking on a larger scope
       than it is specifically intended to. i.e. we do not want it to
       become a convenience for importing arbitrary files into OPFS.

Added ext/wasm/api/sqlite3-vtab-helper.c-pp.js.







































































































































































































































































































































































































































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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** 2022-11-30
**
** The author disclaims copyright to this source code.  In place of a
** legal notice, here is a blessing:
**
** *   May you do good and not evil.
** *   May you find forgiveness for yourself and forgive others.
** *   May you share freely, never taking more than you give.
*/

/**
   This file installs sqlite3.vtab, a namespace of helpers for use in
   the creation of JavaScript implementations virtual tables.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
  const vtab = Object.create(null);
  sqlite3.vtab = vtab;

  const sii = capi.sqlite3_index_info;
  /**
     If n is >=0 and less than this.$nConstraint, this function
     returns either a WASM pointer to the 0-based nth entry of
     this.$aConstraint (if passed a truthy 2nd argument) or an
     sqlite3_index_info.sqlite3_index_constraint object wrapping that
     address (if passed a falsy value or no 2nd argument). Returns a
     falsy value if n is out of range.
  */
  sii.prototype.nthConstraint = function(n, asPtr=false){
    if(n<0 || n>=this.$nConstraint) return false;
    const ptr = this.$aConstraint + (
      sii.sqlite3_index_constraint.structInfo.sizeof * n
    );
    return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr);
  };

  /**
     Works identically to nthConstraint() but returns state from
     this.$aConstraintUsage, so returns an
     sqlite3_index_info.sqlite3_index_constraint_usage instance
     if passed no 2nd argument or a falsy 2nd argument.
  */
  sii.prototype.nthConstraintUsage = function(n, asPtr=false){
    if(n<0 || n>=this.$nConstraint) return false;
    const ptr = this.$aConstraintUsage + (
      sii.sqlite3_index_constraint_usage.structInfo.sizeof * n
    );
    return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr);
  };

  /**
     If n is >=0 and less than this.$nOrderBy, this function
     returns either a WASM pointer to the 0-based nth entry of
     this.$aOrderBy (if passed a truthy 2nd argument) or an
     sqlite3_index_info.sqlite3_index_orderby object wrapping that
     address (if passed a falsy value or no 2nd argument). Returns a
     falsy value if n is out of range.
  */
  sii.prototype.nthOrderBy = function(n, asPtr=false){
    if(n<0 || n>=this.$nOrderBy) return false;
    const ptr = this.$aOrderBy + (
      sii.sqlite3_index_orderby.structInfo.sizeof * n
    );
    return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr);
  };

  /**
     Internal factory function for xVtab and xCursor impls.
  */
  const __xWrapFactory = function(methodName,StructType){
    return function(ptr,removeMapping=false){
      if(0===arguments.length) ptr = new StructType;
      if(ptr instanceof StructType){
        //T.assert(!this.has(ptr.pointer));
        this.set(ptr.pointer, ptr);
        return ptr;
      }else if(!wasm.isPtr(ptr)){
        sqlite3.SQLite3Error.toss("Invalid argument to",methodName+"()");
      }
      let rc = this.get(ptr);
      if(removeMapping) this.delete(ptr);
      return rc;
    }.bind(new Map);
  };

  /**
     A factory function which implements a simple lifetime manager for
     mappings between C struct pointers and their JS-level wrappers.
     The first argument must be the logical name of the manager
     (e.g. 'xVtab' or 'xCursor'), which is only used for error
     reporting. The second must be the capi.XYZ struct-type value,
     e.g. capi.sqlite3_vtab or capi.sqlite3_vtab_cursor.

     Returns an object with 4 methods: create(), get(), unget(), and
     dispose(), plus a StructType member with the value of the 2nd
     argument. The methods are documented in the body of this
     function.
  */
  const StructPtrMapper = function(name, StructType){
    const __xWrap = __xWrapFactory(name,StructType);
    /**
       This object houses a small API for managing mappings of (`T*`)
       to StructType<T> objects, specifically within the lifetime
       requirements of sqlite3_module methods.
    */
    return Object.assign(Object.create(null),{
      /** The StructType object for this object's API. */
      StructType,
      /**
         Creates a new StructType object, writes its `pointer`
         value to the given output pointer, and returns that
         object. Its intended usage depends on StructType:

         sqlite3_vtab: to be called from sqlite3_module::xConnect()
         or xCreate() implementations.

         sqlite3_vtab_cursor: to be called from xOpen().

         This will throw if allocation of the StructType instance
         fails or if ppOut is not a pointer-type value.
      */
      create: (ppOut)=>{
        const rc = __xWrap();
        wasm.pokePtr(ppOut, rc.pointer);
        return rc;
      },
      /**
         Returns the StructType object previously mapped to the
         given pointer using create(). Its intended usage depends
         on StructType:

         sqlite3_vtab: to be called from sqlite3_module methods which
         take a (sqlite3_vtab*) pointer _except_ for
         xDestroy()/xDisconnect(), in which case unget() or dispose().

         sqlite3_vtab_cursor: to be called from any sqlite3_module methods
         which take a `sqlite3_vtab_cursor*` argument except xClose(),
         in which case use unget() or dispose().

         Rule to remember: _never_ call dispose() on an instance
         returned by this function.
      */
      get: (pCObj)=>__xWrap(pCObj),
      /**
         Identical to get() but also disconnects the mapping between the
         given pointer and the returned StructType object, such that
         future calls to this function or get() with the same pointer
         will return the undefined value. Its intended usage depends
         on StructType:

         sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or
         xDestroy() implementations or in error handling of a failed
         xCreate() or xConnect().

         sqlite3_vtab_cursor: to be called from xClose() or during
         cleanup in a failed xOpen().

         Calling this method obligates the caller to call dispose() on
         the returned object when they're done with it.
      */
      unget: (pCObj)=>__xWrap(pCObj,true),
      /**
         Works like unget() plus it calls dispose() on the
         StructType object.
      */
      dispose: (pCObj)=>{
        const o = __xWrap(pCObj,true);
        if(o) o.dispose();
      }
    });
  };

  /**
     A lifetime-management object for mapping `sqlite3_vtab*`
     instances in sqlite3_module methods to capi.sqlite3_vtab
     objects.

     The API docs are in the API-internal StructPtrMapper().
  */
  vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);

  /**
     A lifetime-management object for mapping `sqlite3_vtab_cursor*`
     instances in sqlite3_module methods to capi.sqlite3_vtab_cursor
     objects.

     The API docs are in the API-internal StructPtrMapper().
  */
  vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);

  /**
     Convenience form of creating an sqlite3_index_info wrapper,
     intended for use in xBestIndex implementations. Note that the
     caller is expected to call dispose() on the returned object
     before returning. Though not _strictly_ required, as that object
     does not own the pIdxInfo memory, it is nonetheless good form.
  */
  vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);

  /**
     Given an sqlite3_module method name and error object, this
     function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof
     sqlite3.WasmAllocError), else it returns its second argument. Its
     intended usage is in the methods of a sqlite3_vfs or
     sqlite3_module:

     ```
     try{
      let rc = ...
      return rc;
     }catch(e){
       return sqlite3.vtab.xError(
                'xColumn', e, sqlite3.capi.SQLITE_XYZ);
       // where SQLITE_XYZ is some call-appropriate result code.
     }
     ```

     If no 3rd argument is provided, its default depends on
     the error type:

     - An sqlite3.WasmAllocError always resolves to capi.SQLITE_NOMEM.

     - If err is an SQLite3Error then its `resultCode` property
       is used.

     - If all else fails, capi.SQLITE_ERROR is used.

     If xError.errorReporter is a function, it is called in
     order to report the error, else the error is not reported.
     If that function throws, that exception is ignored.
  */
  vtab.xError = function f(methodName, err, defaultRc){
    if(f.errorReporter instanceof Function){
      try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);}
      catch(e){/*ignored*/}
    }
    let rc;
    if(err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM;
    else if(arguments.length>2) rc = defaultRc;
    else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
    return rc || capi.SQLITE_ERROR;
  };
  vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;

  /**
     A helper for sqlite3_vtab::xRowid() and xUpdate()
     implementations. It must be passed the final argument to one of
     those methods (an output pointer to an int64 row ID) and the
     value to store at the output pointer's address. Returns the same
     as wasm.poke() and will throw if the 1st or 2nd arguments
     are invalid for that function.

     Example xRowid impl:

     ```
     const xRowid = (pCursor, ppRowid64)=>{
       const c = vtab.xCursor(pCursor);
       vtab.xRowid(ppRowid64, c.myRowId);
       return 0;
     };
     ```
  */
  vtab.xRowid = (ppRowid64, value)=>wasm.poke(ppRowid64, value, 'i64');

  /**
     A helper to initialize and set up an sqlite3_module object for
     later installation into individual databases using
     sqlite3_create_module(). Requires an object with the following
     properties:

     - `methods`: an object containing a mapping of properties with
       the C-side names of the sqlite3_module methods, e.g. xCreate,
       xBestIndex, etc., to JS implementations for those functions.
       Certain special-case handling is performed, as described below.

     - `catchExceptions` (default=false): if truthy, the given methods
       are not mapped as-is, but are instead wrapped inside wrappers
       which translate exceptions into result codes of SQLITE_ERROR or
       SQLITE_NOMEM, depending on whether the exception is an
       sqlite3.WasmAllocError. In the case of the xConnect and xCreate
       methods, the exception handler also sets the output error
       string to the exception's error string.

     - OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If
       not set, one will be created automatically. If the current
       "this" is-a sqlite3_module then it is unconditionally used in
       place of `struct`.

     - OPTIONAL `iVersion`: if set, it must be an integer value and it
       gets assigned to the `$iVersion` member of the struct object.
       If it's _not_ set, and the passed-in `struct` object's `$iVersion`
       is 0 (the default) then this function attempts to define a value
       for that property based on the list of methods it has.

     If `catchExceptions` is false, it is up to the client to ensure
     that no exceptions escape the methods, as doing so would move
     them through the C API, leading to undefined
     behavior. (vtab.xError() is intended to assist in reporting
     such exceptions.)

     Certain methods may refer to the same implementation. To simplify
     the definition of such methods:

     - If `methods.xConnect` is `true` then the value of
       `methods.xCreate` is used in its place, and vice versa. sqlite
       treats xConnect/xCreate functions specially if they are exactly
       the same function (same pointer value).

     - If `methods.xDisconnect` is true then the value of
       `methods.xDestroy` is used in its place, and vice versa.

     This is to facilitate creation of those methods inline in the
     passed-in object without requiring the client to explicitly get a
     reference to one of them in order to assign it to the other
     one.

     The `catchExceptions`-installed handlers will account for
     identical references to the above functions and will install the
     same wrapper function for both.

     The given methods are expected to return integer values, as
     expected by the C API. If `catchExceptions` is truthy, the return
     value of the wrapped function will be used as-is and will be
     translated to 0 if the function returns a falsy value (e.g. if it
     does not have an explicit return). If `catchExceptions` is _not_
     active, the method implementations must explicitly return integer
     values.

     Throws on error. On success, returns the sqlite3_module object
     (`this` or `opt.struct` or a new sqlite3_module instance,
     depending on how it's called).
  */
  vtab.setupModule = function(opt){
    let createdMod = false;
    const mod = (this instanceof capi.sqlite3_module)
          ? this : (opt.struct || (createdMod = new capi.sqlite3_module()));
    try{
      const methods = opt.methods || toss("Missing 'methods' object.");
      for(const e of Object.entries({
        // -----^ ==> [k,v] triggers a broken code transformation in
        // some versions of the emsdk toolchain.
        xConnect: 'xCreate', xDisconnect: 'xDestroy'
      })){
        // Remap X=true to X=Y for certain X/Y combinations
        const k = e[0], v = e[1];
        if(true === methods[k]) methods[k] = methods[v];
        else if(true === methods[v]) methods[v] = methods[k];
      }
      if(opt.catchExceptions){
        const fwrap = function(methodName, func){
          if(['xConnect','xCreate'].indexOf(methodName) >= 0){
            return function(pDb, pAux, argc, argv, ppVtab, pzErr){
              try{return func(...arguments) || 0}
              catch(e){
                if(!(e instanceof sqlite3.WasmAllocError)){
                  wasm.dealloc(wasm.peekPtr(pzErr));
                  wasm.pokePtr(pzErr, wasm.allocCString(e.message));
                }
                return vtab.xError(methodName, e);
              }
            };
          }else{
            return function(...args){
              try{return func(...args) || 0}
              catch(e){
                return vtab.xError(methodName, e);
              }
            };
          }
        };
        const mnames = [
          'xCreate', 'xConnect', 'xBestIndex', 'xDisconnect',
          'xDestroy', 'xOpen', 'xClose', 'xFilter', 'xNext',
          'xEof', 'xColumn', 'xRowid', 'xUpdate',
          'xBegin', 'xSync', 'xCommit', 'xRollback',
          'xFindFunction', 'xRename', 'xSavepoint', 'xRelease',
          'xRollbackTo', 'xShadowName'
        ];
        const remethods = Object.create(null);
        for(const k of mnames){
          const m = methods[k];
          if(!(m instanceof Function)) continue;
          else if('xConnect'===k && methods.xCreate===m){
            remethods[k] = methods.xCreate;
          }else if('xCreate'===k && methods.xConnect===m){
            remethods[k] = methods.xConnect;
          }else{
            remethods[k] = fwrap(k, m);
          }
        }
        mod.installMethods(remethods, false);
      }else{
        // No automatic exception handling. Trust the client
        // to not throw.
        mod.installMethods(
          methods, !!opt.applyArgcCheck/*undocumented option*/
        );
      }
      if(0===mod.$iVersion){
        let v;
        if('number'===typeof opt.iVersion) v = opt.iVersion;
        else if(mod.$xShadowName) v = 3;
        else if(mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2;
        else v = 1;
        mod.$iVersion = v;
      }
    }catch(e){
      if(createdMod) createdMod.dispose();
      throw e;
    }
    return mod;
  }/*setupModule()*/;

  /**
     Equivalent to calling vtab.setupModule() with this sqlite3_module
     object as the call's `this`.
  */
  capi.sqlite3_module.prototype.setupModule = function(opt){
    return vtab.setupModule.call(this, opt);
  };
}/*sqlite3ApiBootstrap.initializers.push()*/);
Changes to ext/wasm/api/sqlite3-wasm.c.
142
143
144
145
146
147
148






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







+
+
+
+
+
+







#endif
#ifndef SQLITE_OMIT_UTF16
# define SQLITE_OMIT_UTF16 1
#endif
#ifndef SQLITE_OS_KV_OPTIONAL
# define SQLITE_OS_KV_OPTIONAL 1
#endif

/**********************************************************************/
/* SQLITE_S... */
#ifndef SQLITE_STRICT_SUBTYPE
# define SQLITE_STRICT_SUBTYPE 1
#endif

/**********************************************************************/
/* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 2
#endif
#ifndef SQLITE_THREADSAFE
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
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







-
+




-
+




-
-
+
+


-
+


-
+


-
-
+
+







-
+







** Emscripten defines its own native one and we'd stomp on each
** other's memory. Other than that complication, basic tests show it
** to work just fine.
**
** Another option is to malloc() a chunk of our own and call that our
** "stack".
*/
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_end(void){
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_end(void){
  extern void __heap_base
    /* see https://stackoverflow.com/questions/10038964 */;
  return &__heap_base;
}
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_begin(void){
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_begin(void){
  extern void __data_end;
  return &__data_end;
}
static void * pWasmStackPtr = 0;
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_ptr(void){
  if(!pWasmStackPtr) pWasmStackPtr = sqlite3_wasm_stack_end();
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_ptr(void){
  if(!pWasmStackPtr) pWasmStackPtr = sqlite3__wasm_stack_end();
  return pWasmStackPtr;
}
SQLITE_WASM_EXPORT void sqlite3_wasm_stack_restore(void * p){
SQLITE_WASM_EXPORT void sqlite3__wasm_stack_restore(void * p){
  pWasmStackPtr = p;
}
SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_alloc(int n){
SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_alloc(int n){
  if(n<=0) return 0;
  n = (n + 7) & ~7 /* align to 8-byte boundary */;
  unsigned char * const p = (unsigned char *)sqlite3_wasm_stack_ptr();
  unsigned const char * const b = (unsigned const char *)sqlite3_wasm_stack_begin();
  unsigned char * const p = (unsigned char *)sqlite3__wasm_stack_ptr();
  unsigned const char * const b = (unsigned const char *)sqlite3__wasm_stack_begin();
  if(b + n >= p || b + n < b/*overflow*/) return 0;
  return pWasmStackPtr = p - n;
}
#endif /* stack allocator experiment */

/*
** State for the "pseudo-stack" allocator implemented in
** sqlite3_wasm_pstack_xyz(). In order to avoid colliding with
** sqlite3__wasm_pstack_xyz(). In order to avoid colliding with
** Emscripten-controled stack space, it carves out a bit of stack
** memory to use for that purpose. This memory ends up in the
** WASM-managed memory, such that routines which manipulate the wasm
** heap can also be used to manipulate this memory.
**
** This particular allocator is intended for small allocations such as
** storage for output pointers. We cannot reasonably size it large
281
282
283
284
285
286
287
288

289
290
291
292
293

294
295

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

311
312
313
314
315
316
317
318
319
320
321

322
323

324
325
326
327
328
329
330
331
332
333
334

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

354
355
356
357
358
359
360
287
288
289
290
291
292
293

294
295
296
297
298

299
300

301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323
324
325
326

327
328

329
330
331
332
333
334
335
336
337
338
339

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358

359
360
361
362
363
364
365
366







-
+




-
+

-
+














-
+










-
+

-
+










-
+


















-
+







  &PStack_mem[0],
  &PStack_mem[0] + sizeof(PStack_mem),
  &PStack_mem[0] + sizeof(PStack_mem)
};
/*
** Returns the current pstack position.
*/
SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_ptr(void){
SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_ptr(void){
  return PStack.pPos;
}
/*
** Sets the pstack position poitner to p. Results are undefined if the
** given value did not come from sqlite3_wasm_pstack_ptr().
** given value did not come from sqlite3__wasm_pstack_ptr().
*/
SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){
SQLITE_WASM_EXPORT void sqlite3__wasm_pstack_restore(unsigned char * p){
  assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos);
  assert(0==((unsigned long long)p & 0x7));
  if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
    PStack.pPos = p;
  }
}
/*
** Allocate and zero out n bytes from the pstack. Returns a pointer to
** the memory on success, 0 on error (including a negative n value). n
** is always adjusted to be a multiple of 8 and returned memory is
** always zeroed out before returning (because this keeps the client
** JS code from having to do so, and most uses of the pstack will
** call for doing so).
*/
SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_alloc(int n){
SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){
  if( n<=0 ) return 0;
  //if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */;
  n = (n + 7) & ~7 /* align to 8-byte boundary */;
  if( PStack.pBegin + n > PStack.pPos /*not enough space left*/
      || PStack.pBegin + n <= PStack.pBegin /*overflow*/ ) return 0;
  memset((PStack.pPos = PStack.pPos - n), 0, (unsigned int)n);
  return PStack.pPos;
}
/*
** Return the number of bytes left which can be
** sqlite3_wasm_pstack_alloc()'d.
** sqlite3__wasm_pstack_alloc()'d.
*/
SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_remaining(void){
SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_remaining(void){
  assert(PStack.pPos >= PStack.pBegin);
  assert(PStack.pPos <= PStack.pEnd);
  return (int)(PStack.pPos - PStack.pBegin);
}

/*
** Return the total number of bytes available in the pstack, including
** any space which is currently allocated. This value is a
** compile-time constant.
*/
SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_quota(void){
SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_quota(void){
  return (int)(PStack.pEnd - PStack.pBegin);
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** For purposes of certain hand-crafted C/Wasm function bindings, we
** need a way of reporting errors which is consistent with the rest of
** the C API, as opposed to throwing JS exceptions. To that end, this
** internal-use-only function is a thin proxy around
** sqlite3ErrorWithMessage(). The intent is that it only be used from
** Wasm bindings such as sqlite3_prepare_v2/v3(), and definitely not
** from client code.
**
** Returns err_code.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
int sqlite3__wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
  if( db!=0 ){
    if( 0!=zMsg ){
      const int nMsg = sqlite3Strlen30(zMsg);
      sqlite3_mutex_enter(sqlite3_db_mutex(db));
      sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
      sqlite3_mutex_leave(sqlite3_db_mutex(db));
    }else{
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
376
377
378
379
380
381
382

383
384
385
386
387
388
389
390







-
+







  void * ppV;
  const char * cstr;
  int64_t v8;
  void (*xFunc)(void*);
};
typedef struct WasmTestStruct WasmTestStruct;
SQLITE_WASM_EXPORT
void sqlite3_wasm_test_struct(WasmTestStruct * s){
void sqlite3__wasm_test_struct(WasmTestStruct * s){
  if(s){
    s->v4 *= 2;
    s->v8 = s->v4 * 2;
    s->ppV = s;
    s->cstr = __FILE__;
    if(s->xFunc) s->xFunc(s);
  }
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
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







-
+
















-
+







** function is called and that result is reused for all future calls.
**
** If this function returns NULL then it means that the internal
** buffer is not large enough for the generated JSON and needs to be
** increased. In debug builds that will trigger an assert().
*/
SQLITE_WASM_EXPORT
const char * sqlite3_wasm_enum_json(void){
const char * sqlite3__wasm_enum_json(void){
  static char aBuffer[1024 * 20] = {0} /* where the JSON goes */;
  int n = 0, nChildren = 0, nStruct = 0
    /* output counters for figuring out where commas go */;
  char * zPos = &aBuffer[1] /* skip first byte for now to help protect
                            ** against a small race condition */;
  char const * const zEnd = &aBuffer[0] + sizeof(aBuffer) /* one-past-the-end */;
  if(aBuffer[0]) return aBuffer;
  /* Leave aBuffer[0] at 0 until the end to help guard against a tiny
  ** race condition. If this is called twice concurrently, they might
  ** end up both writing to aBuffer, but they'll both write the same
  ** thing, so that's okay. If we set byte 0 up front then the 2nd
  ** instance might return and use the string before the 1st instance
  ** is done filling it. */

/* Core output macros... */
#define lenCheck assert(zPos < zEnd - 128 \
  && "sqlite3_wasm_enum_json() buffer is too small."); \
  && "sqlite3__wasm_enum_json() buffer is too small."); \
  if( zPos >= zEnd - 128 ) return 0
#define outf(format,...) \
  zPos += snprintf(zPos, ((size_t)(zEnd - zPos)), format, __VA_ARGS__); \
  lenCheck
#define out(TXT) outf("%s",TXT)
#define CloseBrace(LEVEL) \
  assert(LEVEL<5); memset(zPos, '}', LEVEL); zPos+=LEVEL; lenCheck
1093
1094
1095
1096
1097
1098
1099
1100

1101
1102
1103
1104
1105
1106
1107
1099
1100
1101
1102
1103
1104
1105

1106
1107
1108
1109
1110
1111
1112
1113







-
+







      M(xSavepoint,     "i(pi)");
      M(xRelease,       "i(pi)");
      M(xRollbackTo,    "i(pi)");
      // ^^^ v2. v3+ follows...
      M(xShadowName,    "i(s)");
    } _StructBinder;
#undef CurrentStruct
    

    /**
     ** Workaround: in order to map the various inner structs from
     ** sqlite3_index_info, we have to uplift those into constructs we
     ** can access by type name. These structs _must_ match their
     ** in-sqlite3_index_info counterparts byte for byte.
    */
    typedef struct {
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
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







-
+

















-
+







** This function invokes the xDelete method of the given VFS (or the
** default VFS if pVfs is NULL), passing on the given filename. If
** zName is NULL, no default VFS is found, or it has no xDelete
** method, SQLITE_MISUSE is returned, else the result of the xDelete()
** call is returned.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
int sqlite3__wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){
  int rc = SQLITE_MISUSE /* ??? */;
  if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0);
  if( zName && pVfs && pVfs->xDelete ){
    rc = pVfs->xDelete(pVfs, zName, 1);
  }
  return rc;
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Returns a pointer to the given DB's VFS for the given DB name,
** defaulting to "main" if zDbName is 0. Returns 0 if no db with the
** given name is open.
*/
SQLITE_WASM_EXPORT
sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
sqlite3_vfs * sqlite3__wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
  sqlite3_vfs * pVfs = 0;
  sqlite3_file_control(pDb, zDbName ? zDbName : "main",
                       SQLITE_FCNTL_VFS_POINTER, &pVfs);
  return pVfs;
}

/*
1251
1252
1253
1254
1255
1256
1257
1258

1259
1260
1261
1262
1263
1264
1265
1257
1258
1259
1260
1261
1262
1263

1264
1265
1266
1267
1268
1269
1270
1271







-
+







** xDestroy() called, so will leak if they require that function for
** proper cleanup.
**
** Returns 0 on success, an SQLITE_xxx code on error. Returns
** SQLITE_MISUSE if pDb is NULL.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_reset(sqlite3 *pDb){
int sqlite3__wasm_db_reset(sqlite3 *pDb){
  int rc = SQLITE_MISUSE;
  if( pDb ){
    sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0);
    rc = sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
    if( 0==rc ){
      rc = sqlite3_exec(pDb, "VACUUM", 0, 0, 0);
      sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
1278
1279
1280
1281
1282
1283
1284
1285

1286
1287
1288
1289

1290
1291
1292
1293
1294
1295
1296
1284
1285
1286
1287
1288
1289
1290

1291
1292
1293
1294

1295
1296
1297
1298
1299
1300
1301
1302







-
+



-
+







** on success, non-0 on error. This function returns 0 on success,
** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
** code from the callback. Note that this is not thread-friendly: it
** expects that it will be the only thread reading the db file and
** takes no measures to ensure that is the case.
**
** This implementation appears to work fine, but
** sqlite3_wasm_db_serialize() is arguably the better way to achieve
** sqlite3__wasm_db_serialize() is arguably the better way to achieve
** this.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
int sqlite3__wasm_db_export_chunked( sqlite3* pDb,
                                    int (*xCallback)(unsigned const char *zOut, int n) ){
  sqlite3_int64 nSize = 0;
  sqlite3_int64 nPos = 0;
  sqlite3_file * pFile = 0;
  unsigned char buf[1024 * 8];
  int nBuf = (int)sizeof(buf);
  int rc = pDb
1333
1334
1335
1336
1337
1338
1339
1340

1341
1342
1343
1344
1345
1346
1347
1339
1340
1341
1342
1343
1344
1345

1346
1347
1348
1349
1350
1351
1352
1353







-
+







** contiguous memory representation, in which case `*pOut` will be
** NULL but 0 will be returned.
**
** If `*pOut` is not NULL, the caller is responsible for passing it to
** sqlite3_free() to free it.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
int sqlite3__wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
                               unsigned char **pOut,
                               sqlite3_int64 *nOut, unsigned int mFlags ){
  unsigned char * z;
  if( !pDb || !pOut ) return SQLITE_MISUSE;
  if( nOut ) *nOut = 0;
  z = sqlite3_serialize(pDb, zSchema ? zSchema : "main", nOut, mFlags);
  if( z || (SQLITE_SERIALIZE_NOCOPY & mFlags) ){
1356
1357
1358
1359
1360
1361
1362
1363

1364
1365
1366
1367
1368
1369
1370
1362
1363
1364
1365
1366
1367
1368

1369
1370
1371
1372
1373
1374
1375
1376







-
+







** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** ACHTUNG: it was discovered on 2023-08-11 that, with SQLITE_DEBUG,
** this function's out-of-scope use of the sqlite3_vfs/file/io_methods
** APIs leads to triggering of assertions in the core library. Its use
** is now deprecated and VFS-specific APIs for importing files need to
** be found to replace it. sqlite3_wasm_posix_create_file() is
** be found to replace it. sqlite3__wasm_posix_create_file() is
** suitable for the "unix" family of VFSes.
**
** Creates a new file using the I/O API of the given VFS, containing
** the given number of bytes of the given data. If the file exists, it
** is truncated to the given length and populated with the given
** data.
**
1397
1398
1399
1400
1401
1402
1403
1404

1405
1406
1407
1408
1409
1410
1411
1403
1404
1405
1406
1407
1408
1409

1410
1411
1412
1413
1414
1415
1416
1417







-
+







** or propagates a code from one of the I/O methods.
**
** Design note: nData is an integer, instead of int64, for WASM
** portability, so that the API can still work in builds where BigInt
** support is disabled or unavailable.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
int sqlite3__wasm_vfs_create_file( sqlite3_vfs *pVfs,
                                  const char *zFilename,
                                  const unsigned char * pData,
                                  int nData ){
  int rc;
  sqlite3_file *pFile = 0;
  sqlite3_io_methods const *pIo;
  const int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
1487
1488
1489
1490
1491
1492
1493
1494

1495
1496
1497
1498
1499
1500
1501
1493
1494
1495
1496
1497
1498
1499

1500
1501
1502
1503
1504
1505
1506
1507







-
+







**
** Creates or overwrites a file using the POSIX file API,
** i.e. Emscripten's virtual filesystem. Creates or truncates
** zFilename, appends pData bytes to it, and returns 0 on success or
** SQLITE_IOERR on error.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_posix_create_file( const char *zFilename,
int sqlite3__wasm_posix_create_file( const char *zFilename,
                                    const unsigned char * pData,
                                    int nData ){
  int rc;
  FILE * pFile = 0;
  int fileExisted = 0;
  size_t nWrote = 1;

1510
1511
1512
1513
1514
1515
1516
1517

1518
1519
1520

1521
1522
1523

1524
1525
1526
1527

1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542

1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557

1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577

1578
1579
1580
1581
1582
1583
1584
1516
1517
1518
1519
1520
1521
1522

1523
1524
1525

1526
1527
1528

1529
1530
1531
1532

1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547

1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562

1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582

1583
1584
1585
1586
1587
1588
1589
1590







-
+


-
+


-
+



-
+














-
+














-
+



















-
+







}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Allocates sqlite3KvvfsMethods.nKeySize bytes from
** sqlite3_wasm_pstack_alloc() and returns 0 if that allocation fails,
** sqlite3__wasm_pstack_alloc() and returns 0 if that allocation fails,
** else it passes that string to kvstorageMakeKey() and returns a
** NUL-terminated pointer to that string. It is up to the caller to
** use sqlite3_wasm_pstack_restore() to free the returned pointer.
** use sqlite3__wasm_pstack_restore() to free the returned pointer.
*/
SQLITE_WASM_EXPORT
char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass,
char * sqlite3__wasm_kvvfsMakeKeyOnPstack(const char *zClass,
                                         const char *zKeyIn){
  assert(sqlite3KvvfsMethods.nKeySize>24);
  char *zKeyOut =
    (char *)sqlite3_wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
    (char *)sqlite3__wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
  if(zKeyOut){
    kvstorageMakeKey(zClass, zKeyIn, zKeyOut);
  }
  return zKeyOut;
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Returns the pointer to the singleton object which holds the kvvfs
** I/O methods and associated state.
*/
SQLITE_WASM_EXPORT
sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){
sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){
  return &sqlite3KvvfsMethods;
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** This is a proxy for the variadic sqlite3_vtab_config() which passes
** its argument on, or not, to sqlite3_vtab_config(), depending on the
** value of its 2nd argument. Returns the result of
** sqlite3_vtab_config(), or SQLITE_MISUSE if the 2nd arg is not a
** valid value.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){
int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){
  switch(op){
  case SQLITE_VTAB_DIRECTONLY:
  case SQLITE_VTAB_INNOCUOUS:
    return sqlite3_vtab_config(pDb, op);
  case SQLITE_VTAB_CONSTRAINT_SUPPORT:
    return sqlite3_vtab_config(pDb, op, arg);
  default:
    return SQLITE_MISUSE;
  }
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Wrapper for the variants of sqlite3_db_config() which take
** (int,int*) variadic args.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
  switch(op){
    case SQLITE_DBCONFIG_ENABLE_FKEY:
    case SQLITE_DBCONFIG_ENABLE_TRIGGER:
    case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
    case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
    case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
    case SQLITE_DBCONFIG_ENABLE_QPSG:
1603
1604
1605
1606
1607
1608
1609
1610

1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626

1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643

1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655

1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667

1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686

1687
1688
1689
1690
1691

1692
1693
1694
1695
1696

1697
1698
1699
1700
1701
1702
1703
1609
1610
1611
1612
1613
1614
1615

1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631

1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648

1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660

1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672

1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691

1692
1693
1694
1695
1696

1697
1698
1699
1700
1701

1702
1703
1704
1705
1706
1707
1708
1709







-
+















-
+
















-
+











-
+











-
+


















-
+




-
+




-
+







** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Wrapper for the variants of sqlite3_db_config() which take
** (void*,int,int) variadic args.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
int sqlite3__wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){
  switch(op){
    case SQLITE_DBCONFIG_LOOKASIDE:
      return sqlite3_db_config(pDb, op, pArg1, arg2, arg3);
    default: return SQLITE_MISUSE;
  }
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Wrapper for the variants of sqlite3_db_config() which take
** (const char *) variadic args.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
int sqlite3__wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){
  switch(op){
    case SQLITE_DBCONFIG_MAINDBNAME:
      return sqlite3_db_config(pDb, op, zArg);
    default: return SQLITE_MISUSE;
  }
}


/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Binding for combinations of sqlite3_config() arguments which take
** a single integer argument.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_config_i(int op, int arg){
int sqlite3__wasm_config_i(int op, int arg){
  return sqlite3_config(op, arg);
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Binding for combinations of sqlite3_config() arguments which take
** two int arguments.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_config_ii(int op, int arg1, int arg2){
int sqlite3__wasm_config_ii(int op, int arg1, int arg2){
  return sqlite3_config(op, arg1, arg2);
}

/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Binding for combinations of sqlite3_config() arguments which take
** a single i64 argument.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){
int sqlite3__wasm_config_j(int op, sqlite3_int64 arg){
  return sqlite3_config(op, arg);
}

#if 0
// Pending removal after verification of a workaround discussed in the
// forum post linked to below.
/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own JS/WASM bindings.
**
** Returns a pointer to sqlite3_free(). In compliant browsers the
** return value, when passed to sqlite3.wasm.exports.functionEntry(),
** must resolve to the same function as
** sqlite3.wasm.exports.sqlite3_free. i.e. from a dev console where
** sqlite3 is exported globally, the following must be true:
**
** ```
** sqlite3.wasm.functionEntry(
**   sqlite3.wasm.exports.sqlite3_wasm_ptr_to_sqlite3_free()
**   sqlite3.wasm.exports.sqlite3__wasm_ptr_to_sqlite3_free()
** ) === sqlite3.wasm.exports.sqlite3_free
** ```
**
** Using a function to return this pointer, as opposed to exporting it
** via sqlite3_wasm_enum_json(), is an attempt to work around a
** via sqlite3__wasm_enum_json(), is an attempt to work around a
** Safari-specific quirk covered at
** https://sqlite.org/forum/info/e5b20e1feb37a19a.
**/
SQLITE_WASM_EXPORT
void * sqlite3_wasm_ptr_to_sqlite3_free(void){
void * sqlite3__wasm_ptr_to_sqlite3_free(void){
  return (void*)sqlite3_free;
}
#endif

#if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS)
#include <emscripten/wasmfs.h>

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







-
+



















-
+









-
+




-
+




-
+




-
-
+
+



-
+




-
-
-
+
+
+




-
-
+
+




-
-
+
+




-
+







**
** Returns 0 on success, SQLITE_NOMEM if instantiation of the backend
** object fails, SQLITE_IOERR if mkdir() of the zMountPoint dir in
** the virtual FS fails. In builds compiled without SQLITE_ENABLE_WASMFS
** defined, SQLITE_NOTFOUND is returned without side effects.
*/
SQLITE_WASM_EXPORT
int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
int sqlite3__wasm_init_wasmfs(const char *zMountPoint){
  static backend_t pOpfs = 0;
  if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
  if( !pOpfs ){
    pOpfs = wasmfs_create_opfs_backend();
  }
  /** It's not enough to instantiate the backend. We have to create a
      mountpoint in the VFS and attach the backend to it. */
  if( pOpfs && 0!=access(zMountPoint, F_OK) ){
    /* Note that this check and is not robust but it will
       hypothetically suffice for the transient wasm-based virtual
       filesystem we're currently running in. */
    const int rc = wasmfs_create_directory(zMountPoint, 0777, pOpfs);
    /*emscripten_console_logf("OPFS mkdir(%s) rc=%d", zMountPoint, rc);*/
    if(rc) return SQLITE_IOERR;
  }
  return pOpfs ? 0 : SQLITE_NOMEM;
}
#else
SQLITE_WASM_EXPORT
int sqlite3_wasm_init_wasmfs(const char *zUnused){
int sqlite3__wasm_init_wasmfs(const char *zUnused){
  //emscripten_console_warn("WASMFS OPFS is not compiled in.");
  if(zUnused){/*unused*/}
  return SQLITE_NOTFOUND;
}
#endif /* __EMSCRIPTEN__ && SQLITE_ENABLE_WASMFS */

#if SQLITE_WASM_TESTS

SQLITE_WASM_EXPORT
int sqlite3_wasm_test_intptr(int * p){
int sqlite3__wasm_test_intptr(int * p){
  return *p = *p * 2;
}

SQLITE_WASM_EXPORT
void * sqlite3_wasm_test_voidptr(void * p){
void * sqlite3__wasm_test_voidptr(void * p){
  return p;
}

SQLITE_WASM_EXPORT
int64_t sqlite3_wasm_test_int64_max(void){
int64_t sqlite3__wasm_test_int64_max(void){
  return (int64_t)0x7fffffffffffffff;
}

SQLITE_WASM_EXPORT
int64_t sqlite3_wasm_test_int64_min(void){
  return ~sqlite3_wasm_test_int64_max();
int64_t sqlite3__wasm_test_int64_min(void){
  return ~sqlite3__wasm_test_int64_max();
}

SQLITE_WASM_EXPORT
int64_t sqlite3_wasm_test_int64_times2(int64_t x){
int64_t sqlite3__wasm_test_int64_times2(int64_t x){
  return x * 2;
}

SQLITE_WASM_EXPORT
void sqlite3_wasm_test_int64_minmax(int64_t * min, int64_t *max){
  *max = sqlite3_wasm_test_int64_max();
  *min = sqlite3_wasm_test_int64_min();
void sqlite3__wasm_test_int64_minmax(int64_t * min, int64_t *max){
  *max = sqlite3__wasm_test_int64_max();
  *min = sqlite3__wasm_test_int64_min();
  /*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
}

SQLITE_WASM_EXPORT
int64_t sqlite3_wasm_test_int64ptr(int64_t * p){
  /*printf("sqlite3_wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
int64_t sqlite3__wasm_test_int64ptr(int64_t * p){
  /*printf("sqlite3__wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
  return *p = *p * 2;
}

SQLITE_WASM_EXPORT
void sqlite3_wasm_test_stack_overflow(int recurse){
  if(recurse) sqlite3_wasm_test_stack_overflow(recurse);
void sqlite3__wasm_test_stack_overflow(int recurse){
  if(recurse) sqlite3__wasm_test_stack_overflow(recurse);
}

/* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */
SQLITE_WASM_EXPORT
char * sqlite3_wasm_test_str_hello(int fail){
char * sqlite3__wasm_test_str_hello(int fail){
  char * s = fail ? 0 : (char *)sqlite3_malloc(6);
  if(s){
    memcpy(s, "hello", 5);
    s[5] = 0;
  }
  return s;
}
1828
1829
1830
1831
1832
1833
1834
1835

1836
1837
1838
1839
1840

1841
1842
1843
1844
1845
1846
1847
1834
1835
1836
1837
1838
1839
1840

1841
1842
1843
1844
1845

1846
1847
1848
1849
1850
1851
1852
1853







-
+




-
+







**
**     [^...]     Matches one character not in the enclosed list.
**
**      '#'       Matches any sequence of one or more digits with an
**                optional + or - sign in front, or a hexadecimal
**                literal of the form 0x...
*/
static int sqlite3_wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
static int sqlite3__wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
  int c, c2;
  int invert;
  int seen;
  typedef int (*recurse_f)(const char *,const char *);
  static const recurse_f recurse = sqlite3_wasm_SQLTester_strnotglob;
  static const recurse_f recurse = sqlite3__wasm_SQLTester_strnotglob;

  while( (c = (*(zGlob++)))!=0 ){
    if( c=='*' ){
      while( (c=(*(zGlob++))) == '*' || c=='?' ){
        if( c=='?' && (*(z++))==0 ) return 0;
      }
      if( c==0 ){
1908
1909
1910
1911
1912
1913
1914
1915
1916


1917
1918
1919
1920
1921
1922
1914
1915
1916
1917
1918
1919
1920


1921
1922
1923

1924
1925
1926
1927







-
-
+
+

-




      if( c!=(*(z++)) ) return 0;
    }
  }
  return *z==0;
}

SQLITE_WASM_EXPORT
int sqlite3_wasm_SQLTester_strglob(const char *zGlob, const char *z){
 return !sqlite3_wasm_SQLTester_strnotglob(zGlob, z);
int sqlite3__wasm_SQLTester_strglob(const char *zGlob, const char *z){
 return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z);
}


#endif /* SQLITE_WASM_TESTS */

#undef SQLITE_WASM_EXPORT
Changes to ext/wasm/api/sqlite3-worker1-promiser.c-pp.js.

1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
+







//#ifnot omit-oo1
/*
  2022-08-24

  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.
37
38
39
40
41
42
43
44
45
46







47
48
49
50
51
52
53
38
39
40
41
42
43
44



45
46
47
48
49
50
51
52
53
54
55
56
57
58







-
-
-
+
+
+
+
+
+
+







   config option may alternately be a function, in which case this
   function re-assigns this property with the result of calling that
   function, enabling delayed instantiation of a Worker.

   - `onready` (optional, but...): this callback is called with no
   arguments when the worker fires its initial
   'sqlite3-api'/'worker1-ready' message, which it does when
   sqlite3.initWorker1API() completes its initialization. This is
   the simplest way to tell the worker to kick off work at the
   earliest opportunity.
   sqlite3.initWorker1API() completes its initialization. This is the
   simplest way to tell the worker to kick off work at the earliest
   opportunity, and the only way to know when the worker module has
   completed loading. The irony of using a callback for this, instead
   of returning a promise from sqlite3Worker1Promiser() is not lost on
   the developers: see sqlite3Worker1Promiser.v2() which uses a
   Promise instead.

   - `onunhandled` (optional): a callback which gets passed the
   message event object for any worker.onmessage() events which
   are not handled by this proxy. Ideally that "should" never
   happen, as this proxy aims to handle all known message types.

   - `generateMessageId` (optional): a function which, when passed an
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165

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

171
172
173
174
175
176
177
178







+







-
+







  const genMsgId = config.generateMessageId || function(msg){
    return msg.type+'#'+(idTypeMap[msg.type] = (idTypeMap[msg.type]||0) + 1);
  };
  const toss = (...args)=>{throw new Error(args.join(' '))};
  if(!config.worker) config.worker = callee.defaultConfig.worker;
  if('function'===typeof config.worker) config.worker = config.worker();
  let dbId;
  let promiserFunc;
  config.worker.onmessage = function(ev){
    ev = ev.data;
    debug('worker1.onmessage',ev);
    let msgHandler = handlerMap[ev.messageId];
    if(!msgHandler){
      if(ev && 'sqlite3-api'===ev.type && 'worker1-ready'===ev.result) {
        /*fired one time when the Worker1 API initializes*/
        if(config.onready) config.onready();
        if(config.onready) config.onready(promiserFunc);
        return;
      }
      msgHandler = handlerMap[ev.type] /* check for exec per-row callback */;
      if(msgHandler && msgHandler.onrow){
        msgHandler.onrow(ev);
        return;
      }
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
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







-
+







+



-
+







          break;
        default:
          break;
    }
    try {msgHandler.resolve(ev)}
    catch(e){msgHandler.reject(e)}
  }/*worker.onmessage()*/;
  return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
  return promiserFunc = function(/*(msgType, msgArgs) || (msgEnvelope)*/){
    let msg;
    if(1===arguments.length){
      msg = arguments[0];
    }else if(2===arguments.length){
      msg = Object.create(null);
      msg.type = arguments[0];
      msg.args = arguments[1];
      msg.dbId = msg.args.dbId;
    }else{
      toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
    }
    if(!msg.dbId) msg.dbId = dbId;
    if(!msg.dbId && msg.type!=='open') msg.dbId = dbId;
    msg.messageId = genMsgId(msg);
    msg.departureTime = performance.now();
    const proxy = Object.create(null);
    proxy.message = msg;
    let rowCallbackId /* message handler ID for exec on-row callback proxy */;
    if('exec'===msg.type && msg.args){
      if('function'===typeof msg.args.callback){
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






























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







+


-
-
-
+
+
+
-

















+
+
-
+

-
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
      debug("Posting",msg.type,"message to Worker dbId="+(dbId||'default')+':',msg);
      config.worker.postMessage(msg);
    });
    if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]);
    return p;
  };
}/*sqlite3Worker1Promiser()*/;

globalThis.sqlite3Worker1Promiser.defaultConfig = {
  worker: function(){
//#if target=es6-bundler-friendly
    return new Worker("sqlite3-worker1-bundler-friendly.mjs",{
      type: 'module' /* Noting that neither Firefox nor Safari suppor this,
//#if target=es6-module
    return new Worker(new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url),{
      type: 'module'
                        as of this writing. */
    });
//#else
    let theJs = "sqlite3-worker1.js";
    if(this.currentScript){
      const src = this.currentScript.src.split('/');
      src.pop();
      theJs = src.join('/')+'/' + theJs;
      //sqlite3.config.warn("promiser currentScript, theJs =",this.currentScript,theJs);
    }else if(globalThis.location){
      //sqlite3.config.warn("promiser globalThis.location =",globalThis.location);
      const urlParams = new URL(globalThis.location.href).searchParams;
      if(urlParams.has('sqlite3.dir')){
        theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
      }
    }
    return new Worker(theJs + globalThis.location.search);
//#endif
  }
//#ifnot target=es6-module
  }.bind({
  .bind({
    currentScript: globalThis?.document?.currentScript
  }),
  })
//#endif
  ,
  onerror: (...args)=>console.error('worker1 promiser error',...args)
}/*defaultConfig*/;

/**
   sqlite3Worker1Promiser.v2() works identically to
   sqlite3Worker1Promiser() except that it returns a Promise instead
   of relying an an onready callback in the config object. The Promise
   resolves to the same factory function which
   sqlite3Worker1Promiser() returns.

   If config is-a function or is an object which contains an onready
   function, that function is replaced by a proxy which will resolve
   after calling the original function and will reject if that
   function throws.
*/
sqlite3Worker1Promiser.v2 = function(config){
  let oldFunc;
  if( 'function' == typeof config ){
    oldFunc = config;
    config = {};
  }else if('function'===typeof config?.onready){
    oldFunc = config.onready;
    delete config.onready;
  }
  const promiseProxy = Object.create(null);
  config = Object.assign((config || Object.create(null)),{
    onready: async function(func){
      try {
        if( oldFunc ) await oldFunc(func);
        promiseProxy.resolve(func);
      }
      catch(e){promiseProxy.reject(e)}
    }
};
  });
  const p = new Promise(function(resolve,reject){
    promiseProxy.resolve = resolve;
    promiseProxy.reject = reject;
  });
  try{
    this.original(config);
  }catch(e){
    promiseProxy.reject(e);
  }
  return p;
}.bind({
   /* We do this because clients are
      recommended to delete globalThis.sqlite3Worker1Promiser. */
  original: sqlite3Worker1Promiser
});

//#if target=es6-module
/**
  When built as a module, we export sqlite3Worker1Promiser.v2()
  instead of sqlite3Worker1Promise() because (A) its interface is more
  conventional for ESM usage and (B) the ESM option export option for
  this API did not exist until v2 was created, so there's no backwards
  incompatibility.
*/
export default sqlite3Worker1Promiser.v2;
//#endif /* target=es6-module */
//#else
/* Built with the omit-oo1 flag. */
//#endif ifnot omit-oo1
Changes to ext/wasm/api/sqlite3-worker1.c-pp.js.

1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
+







//#ifnot omit-oo1
/*
  2022-05-23

  The author disclaims copyright to this source code.  In place of a
  legal notice, here is a blessing:

  *   May you do good and not evil.
44
45
46
47
48
49
50



45
46
47
48
49
50
51
52
53
54







+
+
+
    theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
  }
  //console.warn("worker1 theJs =",theJs);
  importScripts(theJs);
}
//#endif
sqlite3InitModule().then(sqlite3 => sqlite3.initWorker1API());
//#else
/* Built with the omit-oo1 flag. */
//#endif ifnot omit-oo1
Added ext/wasm/batch-runner-sahpool.html.






















































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
    <link rel="stylesheet" href="common/testing.css"/>
    <title>sqlite3-api batch SQL runner for the SAHPool VFS</title>
  </head>
  <body>
    <header id='titlebar'><span>sqlite3-api batch SQL runner for the SAHPool VFS</span></header>
    <div>
      <span class='input-wrapper'>
        <input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input>
        <label for='cb-reverse-log-order' id='lbl-reverse-log-order'>Reverse log order</label>
      </span>
    </div>
    <div id='test-output' class='reverse'></div>
    <script>
      (function(){
        const E = (sel)=>document.querySelector(sel);

        const eOut = E('#test-output');
        const log2 = function(cssClass,...args){
          let ln;
          if(1 || cssClass){
            ln = document.createElement('div');
            if(cssClass) ln.classList.add(cssClass);
            ln.append(document.createTextNode(args.join(' ')));
          }else{
            // This doesn't work with the "reverse order" option!
            ln = document.createTextNode(args.join(' ')+'\n');
          }
          eOut.append(ln);
        };
        const log = (...args)=>{
          //console.log(...args);
          log2('', ...args);
        };
        const logErr = function(...args){
          console.error(...args);
          log2('error', ...args);
        };
        const logWarn = function(...args){
          console.warn(...args);
          log2('warning', ...args);
        };

        const cbReverseLog = E('#cb-reverse-log-order');
        const lblReverseLog = E('#lbl-reverse-log-order');
        if(cbReverseLog.checked){
            lblReverseLog.classList.add('warning');
            eOut.classList.add('reverse');
        }
        cbReverseLog.addEventListener('change', function(){
            if(this.checked){
                eOut.classList.add('reverse');
                lblReverseLog.classList.add('warning');
            }else{
                eOut.classList.remove('reverse');
                lblReverseLog.classList.remove('warning');
            }
        }, false);

        const w = new Worker('batch-runner-sahpool.js?sqlite3.dir=jswasm');
        w.onmessage = function(msg){
          msg = msg.data;
          switch(msg.type){
            case 'stdout': log(...msg.data); break;
            case 'warn': logWarn(...msg.data); break;
            case 'error': logErr(...msg.data); break;
            default:
              logErr("Unhandled worker message type:",msg);
              break;
          }
        };
      })();
    </script>
    <style>
      #test-output {
          white-space: break-spaces;
          overflow: auto;
      }
    </style>
  </body>
</html>
Added ext/wasm/batch-runner-sahpool.js.





















































































































































































































































































































































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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
  2023-11-30

  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.

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

  A basic batch SQL runner for the SAHPool VFS. This file must be run in
  a worker thread. This is not a full-featured app, just a way to get some
  measurements for batch execution of SQL for the OPFS SAH Pool VFS.
*/
'use strict';

const wMsg = function(msgType,...args){
  postMessage({
    type: msgType,
    data: args
  });
};
const toss = function(...args){throw new Error(args.join(' '))};
const warn = (...args)=>{ wMsg('warn',...args); };
const error = (...args)=>{ wMsg('error',...args); };
const log = (...args)=>{ wMsg('stdout',...args); }
let sqlite3;
const urlParams = new URL(globalThis.location.href).searchParams;
const cacheSize = (()=>{
  if(urlParams.has('cachesize')) return +urlParams.get('cachesize');
  return 200;
})();


/** Throws if the given sqlite3 result code is not 0. */
const checkSqliteRc = (dbh,rc)=>{
  if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh));
};

const sqlToDrop = [
  "SELECT type,name FROM sqlite_schema ",
  "WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ",
  "AND name NOT LIKE '\\_%' escape '\\'"
].join('');

const clearDbSqlite = function(db){
  // This would be SO much easier with the oo1 API, but we specifically want to
  // inject metrics we can't get via that API, and we cannot reliably (OPFS)
  // open the same DB twice to clear it using that API, so...
  const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle);
  log("reset db rc =",rc,db.id, db.filename);
};

const App = {
  db: undefined,
  cache:Object.create(null),
  log: log,
  warn: warn,
  error: error,
  metrics: {
    fileCount: 0,
    runTimeMs: 0,
    prepareTimeMs: 0,
    stepTimeMs: 0,
    stmtCount: 0,
    strcpyMs: 0,
    sqlBytes: 0
  },
  fileList: undefined,
  execSql: async function(name,sql){
    const db = this.db;
    const banner = "========================================";
    this.log(banner,
             "Running",name,'('+sql.length,'bytes)');
    const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
    let pStmt = 0, pSqlBegin;
    const metrics = db.metrics = Object.create(null);
    metrics.prepTotal = metrics.stepTotal = 0;
    metrics.stmtCount = 0;
    metrics.malloc = 0;
    metrics.strcpy = 0;
    if(this.gotErr){
      this.error("Cannot run SQL: error cleanup is pending.");
      return;
    }
    // Run this async so that the UI can be updated for the above header...
    const endRun = ()=>{
      metrics.evalSqlEnd = performance.now();
      metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart);
      this.log("metrics:",JSON.stringify(metrics, undefined, ' '));
      this.log("prepare() count:",metrics.stmtCount);
      this.log("Time in prepare_v2():",metrics.prepTotal,"ms",
               "("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())");
      this.log("Time in step():",metrics.stepTotal,"ms",
               "("+(metrics.stepTotal / metrics.stmtCount),"ms per step())");
      this.log("Total runtime:",metrics.evalTimeTotal,"ms");
      this.log("Overhead (time - prep - step):",
               (metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
      this.log(banner,"End of",name);
      this.metrics.prepareTimeMs += metrics.prepTotal;
      this.metrics.stepTimeMs += metrics.stepTotal;
      this.metrics.stmtCount += metrics.stmtCount;
      this.metrics.strcpyMs += metrics.strcpy;
      this.metrics.sqlBytes += sql.length;
    };

    const runner = function(resolve, reject){
      ++this.metrics.fileCount;
      metrics.evalSqlStart = performance.now();
      const stack = wasm.scopedAllocPush();
      try {
        let t, rc;
        let sqlByteLen = sql.byteLength;
        const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
        t = performance.now();
        pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed");
        metrics.malloc = performance.now() - t;
        metrics.byteLength = sqlByteLen;
        let pSql = pSqlBegin;
        const pSqlEnd = pSqlBegin + sqlByteLen;
        t = performance.now();
        wasm.heap8().set(sql, pSql);
        wasm.poke(pSql + sqlByteLen, 0);
        //log("SQL:",wasm.cstrToJs(pSql));
        metrics.strcpy = performance.now() - t;
        let breaker = 0;
        while(pSql && wasm.peek8(pSql)){
          wasm.pokePtr(ppStmt, 0);
          wasm.pokePtr(pzTail, 0);
          t = performance.now();
          rc = capi.sqlite3_prepare_v2(
            db.handle, pSql, sqlByteLen, ppStmt, pzTail
          );
          metrics.prepTotal += performance.now() - t;
          checkSqliteRc(db.handle, rc);
          pStmt = wasm.peekPtr(ppStmt);
          pSql = wasm.peekPtr(pzTail);
          sqlByteLen = pSqlEnd - pSql;
          if(!pStmt) continue/*empty statement*/;
          ++metrics.stmtCount;
          t = performance.now();
          rc = capi.sqlite3_step(pStmt);
          capi.sqlite3_finalize(pStmt);
          pStmt = 0;
          metrics.stepTotal += performance.now() - t;
          switch(rc){
            case capi.SQLITE_ROW:
            case capi.SQLITE_DONE: break;
            default: checkSqliteRc(db.handle, rc); toss("Not reached.");
          }
        }
        resolve(this);
      }catch(e){
        if(pStmt) capi.sqlite3_finalize(pStmt);
        this.gotErr = e;
        reject(e);
      }finally{
        capi.sqlite3_exec(db.handle,"rollback;",0,0,0);
        wasm.scopedAllocPop(stack);
      }
    }.bind(this);
    const p = new Promise(runner);
    return p.catch(
      (e)=>this.error("Error via execSql("+name+",...):",e.message)
    ).finally(()=>{
      endRun();
    });
  },

  /**
     Loads batch-runner.list and populates the selection list from
     it. Returns a promise which resolves to nothing in particular
     when it completes. Only intended to be run once at the start
     of the app.
  */
  loadSqlList: async function(){
    const infile = 'batch-runner.list';
    this.log("Loading list of SQL files:", infile);
    let txt;
    try{
      const r = await fetch(infile);
      if(404 === r.status){
        toss("Missing file '"+infile+"'.");
      }
      if(!r.ok) toss("Loading",infile,"failed:",r.statusText);
      txt = await r.text();
    }catch(e){
      this.error(e.message);
      throw e;
    }
    App.fileList = txt.split(/\n+/).filter(x=>!!x);
    this.log("Loaded",infile);
  },

  /** Fetch ./fn and return its contents as a Uint8Array. */
  fetchFile: async function(fn, cacheIt=false){
    if(cacheIt && this.cache[fn]) return this.cache[fn];
    this.log("Fetching",fn,"...");
    let sql;
    try {
      const r = await fetch(fn);
      if(!r.ok) toss("Fetch failed:",r.statusText);
      sql = new Uint8Array(await r.arrayBuffer());
    }catch(e){
      this.error(e.message);
      throw e;
    }
    this.log("Fetched",sql.length,"bytes from",fn);
    if(cacheIt) this.cache[fn] = sql;
    return sql;
  }/*fetchFile()*/,

  /**
     Converts this.metrics() to a form which is suitable for easy conversion to
     CSV. It returns an array of arrays. The first sub-array is the column names.
     The 2nd and subsequent are the values, one per test file (only the most recent
     metrics are kept for any given file).
  */
  metricsToArrays: function(){
    const rc = [];
    Object.keys(this.dbs).sort().forEach((k)=>{
      const d = this.dbs[k];
      const m = d.metrics;
      delete m.evalSqlStart;
      delete m.evalSqlEnd;
      const mk = Object.keys(m).sort();
      if(!rc.length){
        rc.push(['db', ...mk]);
      }
      const row = [k.split('/').pop()/*remove dir prefix from filename*/];
      rc.push(row);
      row.push(...mk.map((kk)=>m[kk]));
    });
    return rc;
  },

  metricsToBlob: function(colSeparator='\t'){
    const ar = [], ma = this.metricsToArrays();
    if(!ma.length){
      this.error("Metrics are empty. Run something.");
      return;
    }
    ma.forEach(function(row){
      ar.push(row.join(colSeparator),'\n');
    });
    return new Blob(ar);
  },

  /**
     Fetch file fn and eval it as an SQL blob. This is an async
     operation and returns a Promise which resolves to this
     object on success.
  */
  evalFile: async function(fn){
    const sql = await this.fetchFile(fn);
    return this.execSql(fn,sql);
  }/*evalFile()*/,

  /**
     Fetches the handle of the db associated with
     this.e.selImpl.value, opening it if needed.
  */
  initDb: function(){
    const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
    const stack = wasm.scopedAllocPush();
    let pDb = 0;
    const d = Object.create(null);
    d.filename = "/batch.db";
    try{
      const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
      const ppDb = wasm.scopedAllocPtr();
      const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, this.PoolUtil.vfsName);
      pDb = wasm.peekPtr(ppDb)
      if(rc) toss("sqlite3_open_v2() failed with code",rc);
      capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0);
      this.log("cache_size =",cacheSize);
    }catch(e){
      if(pDb) capi.sqlite3_close_v2(pDb);
      throw e;
    }finally{
      wasm.scopedAllocPop(stack);
    }
    d.handle = pDb;
    this.log("Opened db:",d.filename,'@',d.handle);
    return d;
  },

  closeDb: function(){
    if(this.db.handle){
      this.sqlite3.capi.sqlite3_close_v2(this.db.handle);
      this.db.handle = undefined;
    }
  },

  run: async function(sqlite3){
    delete this.run;
    this.sqlite3 = sqlite3;
    const capi = sqlite3.capi, wasm = sqlite3.wasm;
    this.log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
    this.log("WASM heap size =",wasm.heap8().length);
    let timeStart;
    sqlite3.installOpfsSAHPoolVfs({
      clearOnInit: true, initialCapacity: 4,
      name: 'batch-sahpool',
      verbosity: 2
    }).then(PoolUtil=>{
      App.PoolUtil = PoolUtil;
      App.db = App.initDb();
    })
      .then(async ()=>this.loadSqlList())
      .then(async ()=>{
        timeStart = performance.now();
        for(let i = 0; i < App.fileList.length; ++i){
          const fn = App.fileList[i];
          await App.evalFile(fn);
          if(App.gotErr) throw App.gotErr;
        }
      })
      .then(()=>{
        App.metrics.runTimeMs = performance.now() - timeStart;
        App.log("total metrics:",JSON.stringify(App.metrics, undefined, ' '));
        App.log("Reload the page to run this again.");
        App.closeDb();
        App.PoolUtil.removeVfs();
      })
      .catch(e=>this.error("ERROR:",e));
  }/*run()*/
}/*App*/;

let sqlite3Js = 'sqlite3.js';
if(urlParams.has('sqlite3.dir')){
  sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
}
importScripts(sqlite3Js);
globalThis.sqlite3InitModule().then(async function(sqlite3_){
  log("Done initializing. Running batch runner...");
  sqlite3 = sqlite3_;
  App.run(sqlite3_);
});
Changes to ext/wasm/batch-runner.js.
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
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







-


















+
+
+
+
+
+
+
+
+







    // This would be SO much easier with the oo1 API, but we specifically want to
    // inject metrics we can't get via that API, and we cannot reliably (OPFS)
    // open the same DB twice to clear it using that API, so...
    const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle);
    App.logHtml("reset db rc =",rc,db.id, db.filename);
  };

  
  const E = (s)=>document.querySelector(s);
  const App = {
    e: {
      output: E('#test-output'),
      selSql: E('#sql-select'),
      btnRun: E('#sql-run'),
      btnRunNext: E('#sql-run-next'),
      btnRunRemaining: E('#sql-run-remaining'),
      btnExportMetrics: E('#export-metrics'),
      btnClear: E('#output-clear'),
      btnReset: E('#db-reset'),
      cbReverseLog: E('#cb-reverse-log-order'),
      selImpl: E('#select-impl'),
      fsToolbar: E('#toolbar')
    },
    db: Object.create(null),
    dbs: Object.create(null),
    cache:{},
    metrics: {
      fileCount: 0,
      runTimeMs: 0,
      prepareTimeMs: 0,
      stepTimeMs: 0,
      stmtCount: 0,
      strcpyMs: 0,
      sqlBytes: 0
    },
    log: console.log.bind(console),
    warn: console.warn.bind(console),
    cls: function(){this.e.output.innerHTML = ''},
    logHtml2: function(cssClass,...args){
      const ln = document.createElement('div');
      if(cssClass) ln.classList.add(cssClass);
      ln.append(document.createTextNode(args.join(' ')));
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
121
122
123
124
125
126
127

128
129
130
131
132
133
134







-







    execSql: async function(name,sql){
      const db = this.getSelectedDb();
      const banner = "========================================";
      this.logHtml(banner,
                   "Running",name,'('+sql.length,'bytes) using',db.id);
      const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
      let pStmt = 0, pSqlBegin;
      const stack = wasm.scopedAllocPush();
      const metrics = db.metrics = Object.create(null);
      metrics.prepTotal = metrics.stepTotal = 0;
      metrics.stmtCount = 0;
      metrics.malloc = 0;
      metrics.strcpy = 0;
      this.blockControls(true);
      if(this.gotErr){
138
139
140
141
142
143
144





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







+
+
+
+
+







                     "("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())");
        this.logHtml("Time in step():",metrics.stepTotal,"ms",
                     "("+(metrics.stepTotal / metrics.stmtCount),"ms per step())");
        this.logHtml("Total runtime:",metrics.evalTimeTotal,"ms");
        this.logHtml("Overhead (time - prep - step):",
                     (metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
        this.logHtml(banner,"End of",name);
        this.metrics.prepareTimeMs += metrics.prepTotal;
        this.metrics.stepTimeMs += metrics.stepTotal;
        this.metrics.stmtCount += metrics.stmtCount;
        this.metrics.strcpyMs += metrics.strcpy;
        this.metrics.sqlBytes += sql.length;
      };

      let runner;
      if('websql'===db.id){
        const who = this;
        runner = function(resolve, reject){
          /* WebSQL cannot execute multiple statements, nor can it execute SQL without
210
211
212
213
214
215
216

217

218
219
220
221
222
223
224
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238







+

+







            console.error("websql error:",e);
            who.logErr(e.message);
            //reject(e);
          }
        }.bind(this);
      }else{/*sqlite3 db...*/
        runner = function(resolve, reject){
          ++this.metrics.fileCount;
          metrics.evalSqlStart = performance.now();
          const stack = wasm.scopedAllocPush();
          try {
            let t;
            let sqlByteLen = sql.byteLength;
            const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
            t = performance.now();
            pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed");
            metrics.malloc = performance.now() - t;
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
279
280
281
282
283
284
285

286
287
288
289
290
291
292
293







-
+







            wasm.scopedAllocPop(stack);
          }
        }.bind(this);
      }
      let p;
      if(1){
        p = new Promise(function(res,rej){
          setTimeout(()=>runner(res, rej), 50)/*give UI a chance to output the "running" banner*/;
          setTimeout(()=>runner(res, rej), 0)/*give UI a chance to output the "running" banner*/;
        });
      }else{
        p = new Promise(runner);
      }
      return p.catch(
        (e)=>this.logErr("Error via execSql("+name+",...):",e.message)
      ).finally(()=>{
397
398
399
400
401
402
403
404

405
406
407
408
409
410
411
411
412
413
414
415
416
417

418
419
420
421
422
423
424
425







-
+







        return;
      }
      ma.forEach(function(row){
        ar.push(row.join(colSeparator),'\n');
      });
      return new Blob(ar);
    },
    

    downloadMetrics: function(){
      const b = this.metricsToBlob();
      if(!b) return;
      const url = URL.createObjectURL(b);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'batch-runner-js-'+((new Date().getTime()/1000) | 0)+'.csv';
572
573
574
575
576
577
578


579
580
581
582
583
584
585
586
587
588
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604







+
+










          }
          ++who.e.selSql.selectedIndex;
          v = who.e.selSql.value;
        }
        const timeTotal = performance.now() - timeStart;
        who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))");
        who.clearStorage();
        App.metrics.runTimeMs = timeTotal;
        who.logHtml("Total metrics:",JSON.stringify(App.metrics,undefined,'  '));
      }, false);
    }/*run()*/
  }/*App*/;

  self.sqlite3TestModule.initSqlite3().then(function(sqlite3_){
    sqlite3 = sqlite3_;
    self.App = App /* only to facilitate dev console access */;
    App.run(sqlite3);
  });
})();
Changes to ext/wasm/demo-123.js.
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30







-
+







(function(){
  /**
     Set up our output channel differently depending
     on whether we are running in a worker thread or
     the main (UI) thread.
  */
  let logHtml;
  if(self.window === self /* UI thread */){
  if(globalThis.window === globalThis /* UI thread */){
    console.log("Running demo from main UI thread.");
    logHtml = function(cssClass,...args){
      const ln = document.createElement('div');
      if(cssClass) ln.classList.add(cssClass);
      ln.append(document.createTextNode(args.join(' ')));
      document.body.append(ln);
    };
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
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







-
+











-
+



-
+





-
-
-
+
+
+
+












         e.g. getInt(), getFloat(), getBlob(), getJSON()
       - getColumnName(ndx), getColumnNames()
       - getParamIndex(name)
    */
  }/*demo1()*/;

  log("Loading and initializing sqlite3 module...");
  if(self.window!==self) /*worker thread*/{
  if(globalThis.window!==globalThis) /*worker thread*/{
    /*
      If sqlite3.js is in a directory other than this script, in order
      to get sqlite3.js to resolve sqlite3.wasm properly, we have to
      explicitly tell it where sqlite3.js is being loaded from. We do
      that by passing the `sqlite3.dir=theDirName` URL argument to
      _this_ script. That URL argument will be seen by the JS/WASM
      loader and it will adjust the sqlite3.wasm path accordingly. If
      sqlite3.js/.wasm are in the same directory as this script then
      that's not needed.

      URL arguments passed as part of the filename via importScripts()
      are simply lost, and such scripts see the self.location of
      are simply lost, and such scripts see the globalThis.location of
      _this_ script.
    */
    let sqlite3Js = 'sqlite3.js';
    const urlParams = new URL(self.location.href).searchParams;
    const urlParams = new URL(globalThis.location.href).searchParams;
    if(urlParams.has('sqlite3.dir')){
      sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
    }
    importScripts(sqlite3Js);
  }
  self.sqlite3InitModule({
    // We can redirect any stdout/stderr from the module
    // like so...
  globalThis.sqlite3InitModule({
    /* We can redirect any stdout/stderr from the module like so, but
       note that doing so makes use of Emscripten-isms, not
       well-defined sqlite APIs. */
    print: log,
    printErr: error
  }).then(function(sqlite3){
    //console.log('sqlite3 =',sqlite3);
    log("Done initializing. Running demo...");
    try {
      demo1(sqlite3);
    }catch(e){
      error("Exception:",e.message);
    }
  });
})();
Added ext/wasm/demo-worker1-promiser.c-pp.html.










































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
    <link rel="stylesheet" href="common/emscripten.css"/>
    <link rel="stylesheet" href="common/testing.css"/>
//#if target=es6-module
    <title>worker-promise (via ESM) tests</title>
//#else
    <title>worker-promise tests</title>
//#endif
  </head>
  <body>
    <header id='titlebar'><span>worker-promise tests</span></header>
    <!-- emscripten bits -->
    <figure id="module-spinner">
      <div class="spinner"></div>
      <div class='center'><strong>Initializing app...</strong></div>
      <div class='center'>
        On a slow internet connection this may take a moment.  If this
        message displays for "a long time", intialization may have
        failed and the JavaScript console may contain clues as to why.
      </div>
    </figure>
    <div class="emscripten" id="module-status">Downloading...</div>
    <div class="emscripten">
      <progress value="0" max="100" id="module-progress" hidden='1'></progress>
    </div><!-- /emscripten bits -->
    <div>Most stuff on this page happens in the dev console.</div>
    <hr>
    <div id='test-output'></div>
    <script src="common/SqliteTestUtil.js"></script>
//#if target=es6-module
    <script src="demo-worker1-promiser.mjs" type="module"></script>
//#else
    <script src="jswasm/sqlite3-worker1-promiser.js"></script>
    <script src="demo-worker1-promiser.js"></script>
//#endif
  </body>
</html>
Added ext/wasm/demo-worker1-promiser.c-pp.js.





























































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
  2022-08-23

  The author disclaims copyright to this source code.  In place of a
  legal notice, here is a blessing:

  *   May you do good and not evil.
  *   May you find forgiveness for yourself and forgive others.
  *   May you share freely, never taking more than you give.

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

  Demonstration of the sqlite3 Worker API #1 Promiser: a Promise-based
  proxy for for the sqlite3 Worker #1 API.
*/
//#if target=es6-module
import {default as promiserFactory} from "./jswasm/sqlite3-worker1-promiser.mjs";
//#else
"use strict";
const promiserFactory = globalThis.sqlite3Worker1Promiser.v2;
delete globalThis.sqlite3Worker1Promiser;
//#endif
(async function(){
  const T = globalThis.SqliteTestUtil;
  const eOutput = document.querySelector('#test-output');
  const warn = console.warn.bind(console);
  const error = console.error.bind(console);
  const log = console.log.bind(console);
  const logHtml = async function(cssClass,...args){
    log.apply(this, args);
    const ln = document.createElement('div');
    if(cssClass) ln.classList.add(cssClass);
    ln.append(document.createTextNode(args.join(' ')));
    eOutput.append(ln);
  };

  let startTime;
  const testCount = async ()=>{
    logHtml("","Total test count:",T.counter+". Total time =",(performance.now() - startTime),"ms");
  };

  const promiserConfig = {
//#ifnot target=es6-module
    /**
       The v1 interfaces uses an onready function. The v2 interface optionally
       accepts one but does not require it. If provided, it is called _before_
       the promise is resolved, and the promise is rejected if onready() throws.
    */
    onready: function(f){
      /* f === the function returned by promiserFactory().
         Ostensibly (f === workerPromise) but this function is
         called before the promiserFactory() Promise resolves, so
         before workerPromise is set. */
      console.warn("This is the v2 interface - you don't need an onready() function.");
    },
//#endif
    debug: 1 ? undefined : (...args)=>console.debug('worker debug',...args),
    onunhandled: function(ev){
      error("Unhandled worker message:",ev.data);
    },
    onerror: function(ev){
      error("worker1 error:",ev);
    }
  };
  const workerPromise = await promiserFactory(promiserConfig)
        .then((func)=>{
          console.log("Init complete. Starting tests momentarily.");
          globalThis.sqlite3TestModule.setStatus(null)/*hide the HTML-side is-loading spinner*/;
          return func;
        });

  const wtest = async function(msgType, msgArgs, callback){
    if(2===arguments.length && 'function'===typeof msgArgs){
      callback = msgArgs;
      msgArgs = undefined;
    }
    const p = 1
          ? workerPromise({type: msgType, args:msgArgs})
          : workerPromise(msgType, msgArgs);
    return callback ? p.then(callback).finally(testCount) : p;
  };

  let sqConfig;
  const runTests = async function(){
    const dbFilename = '/testing2.sqlite3';
    startTime = performance.now();

    await wtest('config-get', (ev)=>{
      const r = ev.result;
      log('sqlite3.config subset:', r);
      T.assert('boolean' === typeof r.bigIntEnabled);
      sqConfig = r;
    });
    logHtml('',
            "Sending 'open' message and waiting for its response before continuing...");

    await wtest('open', {
      filename: dbFilename,
      simulateError: 0 /* if true, fail the 'open' */,
    }, function(ev){
      const r = ev.result;
      log("then open result",r);
      T.assert(ev.dbId === r.dbId)
        .assert(ev.messageId)
        .assert('string' === typeof r.vfs);
      promiserConfig.dbId = ev.dbId;
    }).then(runTests2);
  };

  const runTests2 = async function(){
    const mustNotReach = ()=>toss("This is not supposed to be reached.");

    await wtest('exec',{
      sql: ["create table t(a,b)",
            "insert into t(a,b) values(1,2),(3,4),(5,6)"
           ].join(';'),
      resultRows: [], columnNames: [],
      countChanges: sqConfig.bigIntEnabled ? 64 : true
    }, function(ev){
      ev = ev.result;
      T.assert(0===ev.resultRows.length)
        .assert(0===ev.columnNames.length)
        .assert(sqConfig.bigIntEnabled
                ? (3n===ev.changeCount)
                : (3===ev.changeCount));
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0][0])
        .assert(6===ev.resultRows[2][1])
        .assert(2===ev.columnNames.length)
        .assert('b'===ev.columnNames[1]);
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
      rowMode: 'object',
      countChanges: true
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0].a)
        .assert(6===ev.resultRows[2].b)
        .assert(0===ev.changeCount);
    });

    await wtest(
      'exec',
      {sql:'intentional_error'},
      mustNotReach
    ).catch((e)=>{
      warn("Intentional error:",e);
    });

    await wtest('exec',{
      sql:'select 1 union all select 3',
      resultRows: []
    }, function(ev){
      ev = ev.result;
      T.assert(2 === ev.resultRows.length)
        .assert(1 === ev.resultRows[0][0])
        .assert(3 === ev.resultRows[1][0])
        .assert(undefined === ev.changeCount);
    });

    const resultRowTest1 = function f(ev){
      if(undefined === f.counter) f.counter = 0;
      if(null === ev.rowNumber){
        /* End of result set. */
        T.assert(undefined === ev.row)
          .assert(2===ev.columnNames.length)
          .assert('a'===ev.columnNames[0])
          .assert('B'===ev.columnNames[1]);
      }else{
        T.assert(ev.rowNumber > 0);
        ++f.counter;
      }
      log("exec() result row:",ev);
      T.assert(null === ev.rowNumber || 'number' === typeof ev.row.B);
    };
    await wtest('exec',{
      sql: 'select a a, b B from t order by a limit 3',
      callback: resultRowTest1,
      rowMode: 'object'
    }, function(ev){
      T.assert(3===resultRowTest1.counter);
      resultRowTest1.counter = 0;
    });

    const resultRowTest2 = function f(ev){
      if(null === ev.rowNumber){
        /* End of result set. */
        T.assert(undefined === ev.row)
          .assert(1===ev.columnNames.length)
          .assert('a'===ev.columnNames[0])
      }else{
        T.assert(ev.rowNumber > 0);
        f.counter = ev.rowNumber;
      }
      log("exec() result row:",ev);
      T.assert(null === ev.rowNumber || 'number' === typeof ev.row);
    };
    await wtest('exec',{
      sql: 'select a a from t limit 3',
      callback: resultRowTest2,
      rowMode: 0
    }, function(ev){
      T.assert(3===resultRowTest2.counter);
    });

    const resultRowTest3 = function f(ev){
      if(null === ev.rowNumber){
        T.assert(3===ev.columnNames.length)
          .assert('foo'===ev.columnNames[0])
          .assert('bar'===ev.columnNames[1])
          .assert('baz'===ev.columnNames[2]);
      }else{
        f.counter = ev.rowNumber;
        T.assert('number' === typeof ev.row);
      }
    };
    await wtest('exec',{
      sql: "select 'foo' foo, a bar, 'baz' baz  from t limit 2",
      callback: resultRowTest3,
      columnNames: [],
      rowMode: '$bar'
    }, function(ev){
      log("exec() result row:",ev);
      T.assert(2===resultRowTest3.counter);
    });

    await wtest('exec',{
      sql:[
        'pragma foreign_keys=0;',
        // ^^^ arbitrary query with no result columns
        'select a, b from t order by a desc; select a from t;'
        // exec() only honors SELECT results from the first
        // statement with result columns (regardless of whether
        // it has any rows).
      ],
      rowMode: 1,
      resultRows: []
    },function(ev){
      const rows = ev.result.resultRows;
      T.assert(3===rows.length).
        assert(6===rows[0]);
    });

    await wtest('exec',{sql: 'delete from t where a>3'});

    await wtest('exec',{
      sql: 'select count(a) from t',
      resultRows: []
    },function(ev){
      ev = ev.result;
      T.assert(1===ev.resultRows.length)
        .assert(2===ev.resultRows[0][0]);
    });

    await wtest('export', function(ev){
      ev = ev.result;
      T.assert('string' === typeof ev.filename)
        .assert(ev.byteArray instanceof Uint8Array)
        .assert(ev.byteArray.length > 1024)
        .assert('application/x-sqlite3' === ev.mimetype);
    });

    /***** close() tests must come last. *****/
    await wtest('close',{},function(ev){
      T.assert('string' === typeof ev.result.filename);
    });

    await wtest('close', (ev)=>{
      T.assert(undefined === ev.result.filename);
    }).finally(()=>logHtml('',"That's all, folks!"));
  }/*runTests2()*/;

  runTests();
})();
Deleted ext/wasm/demo-worker1-promiser.html.
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


































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
    <link rel="stylesheet" href="common/emscripten.css"/>
    <link rel="stylesheet" href="common/testing.css"/>
    <title>worker-promise tests</title>
  </head>
  <body>
    <header id='titlebar'><span>worker-promise tests</span></header>
    <!-- emscripten bits -->
    <figure id="module-spinner">
      <div class="spinner"></div>
      <div class='center'><strong>Initializing app...</strong></div>
      <div class='center'>
        On a slow internet connection this may take a moment.  If this
        message displays for "a long time", intialization may have
        failed and the JavaScript console may contain clues as to why.
      </div>
    </figure>
    <div class="emscripten" id="module-status">Downloading...</div>
    <div class="emscripten">
      <progress value="0" max="100" id="module-progress" hidden='1'></progress>  
    </div><!-- /emscripten bits -->
    <div>Most stuff on this page happens in the dev console.</div>
    <hr>
    <div id='test-output'></div>
    <script src="common/SqliteTestUtil.js"></script>
    <script src="jswasm/sqlite3-worker1-promiser.js"></script>
    <script src="demo-worker1-promiser.js"></script>
  </body>
</html>
Deleted ext/wasm/demo-worker1-promiser.js.
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



















































































































































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
  2022-08-23

  The author disclaims copyright to this source code.  In place of a
  legal notice, here is a blessing:

  *   May you do good and not evil.
  *   May you find forgiveness for yourself and forgive others.
  *   May you share freely, never taking more than you give.

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

  Demonstration of the sqlite3 Worker API #1 Promiser: a Promise-based
  proxy for for the sqlite3 Worker #1 API.
*/
'use strict';
(function(){
  const T = self.SqliteTestUtil;
  const eOutput = document.querySelector('#test-output');
  const warn = console.warn.bind(console);
  const error = console.error.bind(console);
  const log = console.log.bind(console);
  const logHtml = async function(cssClass,...args){
    log.apply(this, args);
    const ln = document.createElement('div');
    if(cssClass) ln.classList.add(cssClass);
    ln.append(document.createTextNode(args.join(' ')));
    eOutput.append(ln);
  };

  let startTime;
  const testCount = async ()=>{
    logHtml("","Total test count:",T.counter+". Total time =",(performance.now() - startTime),"ms");
  };

  //why is this triggered even when we catch() a Promise?
  //window.addEventListener('unhandledrejection', function(event) {
  //  warn('unhandledrejection',event);
  //});

  const promiserConfig = {
    worker: ()=>{
      const w = new Worker("jswasm/sqlite3-worker1.js");
      w.onerror = (event)=>error("worker.onerror",event);
      return w;
    },
    debug: 1 ? undefined : (...args)=>console.debug('worker debug',...args),
    onunhandled: function(ev){
      error("Unhandled worker message:",ev.data);
    },
    onready: function(){
      self.sqlite3TestModule.setStatus(null)/*hide the HTML-side is-loading spinner*/;
      runTests();
    },
    onerror: function(ev){
      error("worker1 error:",ev);
    }
  };
  const workerPromise = self.sqlite3Worker1Promiser(promiserConfig);
  delete self.sqlite3Worker1Promiser;

  const wtest = async function(msgType, msgArgs, callback){
    if(2===arguments.length && 'function'===typeof msgArgs){
      callback = msgArgs;
      msgArgs = undefined;
    }
    const p = 1
          ? workerPromise({type: msgType, args:msgArgs})
          : workerPromise(msgType, msgArgs);
    return callback ? p.then(callback).finally(testCount) : p;
  };

  let sqConfig;
  const runTests = async function(){
    const dbFilename = '/testing2.sqlite3';
    startTime = performance.now();

    await wtest('config-get', (ev)=>{
      const r = ev.result;
      log('sqlite3.config subset:', r);
      T.assert('boolean' === typeof r.bigIntEnabled);
      sqConfig = r;
    });
    logHtml('',
            "Sending 'open' message and waiting for its response before continuing...");

    await wtest('open', {
      filename: dbFilename,
      simulateError: 0 /* if true, fail the 'open' */,
    }, function(ev){
      const r = ev.result;
      log("then open result",r);
      T.assert(ev.dbId === r.dbId)
        .assert(ev.messageId)
        .assert('string' === typeof r.vfs);
      promiserConfig.dbId = ev.dbId;
    }).then(runTests2);
  };

  const runTests2 = async function(){
    const mustNotReach = ()=>toss("This is not supposed to be reached.");

    await wtest('exec',{
      sql: ["create table t(a,b)",
            "insert into t(a,b) values(1,2),(3,4),(5,6)"
           ].join(';'),
      resultRows: [], columnNames: [],
      countChanges: sqConfig.bigIntEnabled ? 64 : true
    }, function(ev){
      ev = ev.result;
      T.assert(0===ev.resultRows.length)
        .assert(0===ev.columnNames.length)
        .assert(sqConfig.bigIntEnabled
                ? (3n===ev.changeCount)
                : (3===ev.changeCount));
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0][0])
        .assert(6===ev.resultRows[2][1])
        .assert(2===ev.columnNames.length)
        .assert('b'===ev.columnNames[1]);
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
      rowMode: 'object',
      countChanges: true
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0].a)
        .assert(6===ev.resultRows[2].b)
        .assert(0===ev.changeCount);
    });

    await wtest(
      'exec',
      {sql:'intentional_error'},
      mustNotReach
    ).catch((e)=>{
      warn("Intentional error:",e);
    });

    await wtest('exec',{
      sql:'select 1 union all select 3',
      resultRows: []
    }, function(ev){
      ev = ev.result;
      T.assert(2 === ev.resultRows.length)
        .assert(1 === ev.resultRows[0][0])
        .assert(3 === ev.resultRows[1][0])
        .assert(undefined === ev.changeCount);
    });

    const resultRowTest1 = function f(ev){
      if(undefined === f.counter) f.counter = 0;
      if(null === ev.rowNumber){
        /* End of result set. */
        T.assert(undefined === ev.row)
          .assert(2===ev.columnNames.length)
          .assert('a'===ev.columnNames[0])
          .assert('B'===ev.columnNames[1]);
      }else{
        T.assert(ev.rowNumber > 0);
        ++f.counter;
      }
      log("exec() result row:",ev);
      T.assert(null === ev.rowNumber || 'number' === typeof ev.row.B);
    };
    await wtest('exec',{
      sql: 'select a a, b B from t order by a limit 3',
      callback: resultRowTest1,
      rowMode: 'object'
    }, function(ev){
      T.assert(3===resultRowTest1.counter);
      resultRowTest1.counter = 0;
    });

    const resultRowTest2 = function f(ev){
      if(null === ev.rowNumber){
        /* End of result set. */
        T.assert(undefined === ev.row)
          .assert(1===ev.columnNames.length)
          .assert('a'===ev.columnNames[0])
      }else{
        T.assert(ev.rowNumber > 0);
        f.counter = ev.rowNumber;
      }
      log("exec() result row:",ev);
      T.assert(null === ev.rowNumber || 'number' === typeof ev.row);
    };
    await wtest('exec',{
      sql: 'select a a from t limit 3',
      callback: resultRowTest2,
      rowMode: 0
    }, function(ev){
      T.assert(3===resultRowTest2.counter);
    });

    const resultRowTest3 = function f(ev){
      if(null === ev.rowNumber){
        T.assert(3===ev.columnNames.length)
          .assert('foo'===ev.columnNames[0])
          .assert('bar'===ev.columnNames[1])
          .assert('baz'===ev.columnNames[2]);
      }else{
        f.counter = ev.rowNumber;
        T.assert('number' === typeof ev.row);
      }
    };
    await wtest('exec',{
      sql: "select 'foo' foo, a bar, 'baz' baz  from t limit 2",
      callback: resultRowTest3,
      columnNames: [],
      rowMode: '$bar'
    }, function(ev){
      log("exec() result row:",ev);
      T.assert(2===resultRowTest3.counter);
    });

    await wtest('exec',{
      sql:[
        'pragma foreign_keys=0;',
        // ^^^ arbitrary query with no result columns
        'select a, b from t order by a desc; select a from t;'
        // exec() only honors SELECT results from the first
        // statement with result columns (regardless of whether
        // it has any rows).
      ],
      rowMode: 1,
      resultRows: []
    },function(ev){
      const rows = ev.result.resultRows;
      T.assert(3===rows.length).
        assert(6===rows[0]);
    });

    await wtest('exec',{sql: 'delete from t where a>3'});

    await wtest('exec',{
      sql: 'select count(a) from t',
      resultRows: []
    },function(ev){
      ev = ev.result;
      T.assert(1===ev.resultRows.length)
        .assert(2===ev.resultRows[0][0]);
    });

    await wtest('export', function(ev){
      ev = ev.result;
      T.assert('string' === typeof ev.filename)
        .assert(ev.byteArray instanceof Uint8Array)
        .assert(ev.byteArray.length > 1024)
        .assert('application/x-sqlite3' === ev.mimetype);
    });

    /***** close() tests must come last. *****/
    await wtest('close',{},function(ev){
      T.assert('string' === typeof ev.result.filename);
    });

    await wtest('close', (ev)=>{
      T.assert(undefined === ev.result.filename);
    }).finally(()=>logHtml('',"That's all, folks!"));
  }/*runTests2()*/;

  log("Init complete, but async init bits may still be running.");
})();
Changes to ext/wasm/dist.make.
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
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







-
-
+
+
+
+




+
+
+
+












-
+
+




















+







dist-dir.common := $(dist-dir.top)/common
dist.top.extras := \
    demo-123.html demo-123-worker.html demo-123.js \
    tester1.html tester1-worker.html tester1-esm.html \
    tester1.js tester1.mjs \
    demo-jsstorage.html demo-jsstorage.js \
    demo-worker1.html demo-worker1.js \
    demo-worker1-promiser.html demo-worker1-promiser.js
dist.jswasm.extras := $(sqlite3-api.ext.jses) $(sqlite3.wasm)
    demo-worker1-promiser.html demo-worker1-promiser.js \
    demo-worker1-promiser-esm.html demo-worker1-promiser.mjs
dist.jswasm.extras := $(sqlite3.wasm) \
  $(sqlite3-api.ext.jses)
dist.common.extras := \
    $(wildcard $(dir.common)/*.css) \
    $(dir.common)/SqliteTestUtil.js

#$(info sqlite3-worker1-promiser.mjs = $(sqlite3-worker1-promiser.mjs))
#$(info sqlite3-worker1.js = $(sqlite3-worker1.js))
#$(info sqlite3-api.ext.jses = $(sqlite3-api.ext.jses))
#$(info dist.jswasm.extras = $(dist.jswasm.extras))
.PHONY: dist snapshot
# DIST_STRIP_COMMENTS $(call)able to be used in stripping C-style
# from the dist copies of certain files.
#
#  $1 = source js file
#  $2 = flags for $(bin.stripcomments)
define DIST_STRIP_COMMENTS
$(bin.stripccomments) $(2) < $(1) > $(dist-dir.jswasm)/$(notdir $(1)) || exit;
endef
# STRIP_K1.js = list of JS files which need to be passed through
# $(bin.stripcomments) with a single -k flag.
STRIP_K1.js := $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js) \
  $(sqlite3-worker1-bundler-friendly.js) $(sqlite3-worker1-promiser-bundler-friendly.js)
  $(sqlite3-worker1-bundler-friendly.js) \
  $(sqlite3-api.ext.jses)
# STRIP_K2.js = list of JS files which need to be passed through
# $(bin.stripcomments) with two -k flags.
STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \
  $(sqlite3-bundler-friendly.mjs) $(sqlite3-node.mjs)
########################################################################
# dist: create the end-user deliverable archive.
#
# Maintenance reminder: because dist depends on $(dist.build), and
# $(dist.build) will depend on clean, having any deps on
# $(dist-archive) which themselves may be cleaned up by the clean
# target will lead to grief in parallel builds (-j #). Thus
# dist's deps must be trimmed to non-generated files or
# files which are _not_ cleaned up by the clean target.
#
# Note that we require $(bin.version-info) in order to figure out the
# dist file's name, so cannot (without a recursive make) have the
# target name equal to the archive name.
dist: \
    $(bin.stripccomments) $(bin.version-info) \
    $(dist.build) $(STRIP_K1.js) $(STRIP_K2.js) \
    $(dist.jswasm.extras) $(dist.common.extras) \
    $(MAKEFILE) $(MAKEFILE.dist)
	@echo "Making end-user deliverables..."
	@rm -fr $(dist-dir.top)
	@mkdir -p $(dist-dir.jswasm) $(dist-dir.common)
	@cp -p $(dist.top.extras) $(dist-dir.top)
	@cp -p README-dist.txt $(dist-dir.top)/README.txt
	@cp -p index-dist.html $(dist-dir.top)/index.html
Changes to ext/wasm/fiddle.make.
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
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











+
+

-
+




-
-
+
+

-
+







#!/do/not/make
#^^^ help emacs select edit mode
#
# Intended to include'd by ./GNUmakefile.
#######################################################################
MAKEFILE.fiddle := $(lastword $(MAKEFILE_LIST))

########################################################################
# shell.c and its build flags...
make-np-0 := make -C  $(dir.top) -n -p
make-np-1 := sed -e 's/(TOP)/(dir.top)/g'
# Extract SHELL_OPT and SHELL_DEP from the top-most makefile and import
# them as vars here...
$(eval $(shell $(make-np-0) | grep -e '^SHELL_OPT ' | $(make-np-1)))
$(eval $(shell $(make-np-0) | grep -e '^SHELL_SRC ' | $(make-np-1)))
$(eval $(shell $(make-np-0) | grep -e '^SHELL_DEP ' | $(make-np-1)))
# ^^^ can't do that in 1 invocation b/c newlines get stripped
ifeq (,$(SHELL_OPT))
$(error Could not parse SHELL_OPT from $(dir.top)/Makefile.)
endif
ifeq (,$(SHELL_SRC))
$(error Could not parse SHELL_SRC from $(dir.top)/Makefile.)
ifeq (,$(SHELL_DEP))
$(error Could not parse SHELL_DEP from $(dir.top)/Makefile.)
endif
$(dir.top)/shell.c: $(SHELL_SRC) $(dir.top)/tool/mkshellc.tcl $(sqlite3.c)
$(dir.top)/shell.c: $(SHELL_DEP) $(dir.top)/tool/mkshellc.tcl $(sqlite3.c)
	$(MAKE) -C $(dir.top) shell.c
# /shell.c
########################################################################

EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
fiddle.emcc-flags = \
  $(emcc.cflags) $(emcc_opt_full) \
Changes to ext/wasm/fiddle/fiddle-worker.js.
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177
178
179
180
162
163
164
165
166
167
168

169
170
171
172

173
174
175
176
177
178
179







-
+



-







        stderr("Fatal error initializing sqlite3 shell.");
        fiddleModule.isDead = true;
        return false;
      }
      stdout("SQLite version", capi.sqlite3_libversion(),
             capi.sqlite3_sourceid().substr(0,19));
      stdout('Welcome to the "fiddle" shell.');
      if(sqlite3.opfs){
      if(capi.sqlite3_vfs_find("opfs")){
        stdout("\nOPFS is available. To open a persistent db, use:\n\n",
               "  .open file:name?vfs=opfs\n\nbut note that some",
               "features (e.g. upload) do not yet work with OPFS.");
        sqlite3.opfs.registerVfs();
      }
      stdout('\nEnter ".help" for usage hints.');
      this.exec([ // initialization commands...
        '.nullvalue NULL',
        '.headers on'
      ].join('\n'));
      return true;
313
314
315
316
317
318
319
320

321
322
323
324
325
326
327
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326







-
+







            stderr("Error installing db",fn+":",e.message);
          }
          return;
        }
    };
    console.warn("Unknown fiddle-worker message type:",ev);
  };
  

  /**
     emscripten module for use with build mode -sMODULARIZE.
  */
  const fiddleModule = {
    print: stdout,
    printErr: stderr,
    /**
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
369
370
371
372
373
374
375

376


377
378
379
380
381







-
+
-
-





  */
  sqlite3InitModule(fiddleModule).then((_sqlite3)=>{
    sqlite3 = _sqlite3;
    console.warn("Installing sqlite3 module globally (in Worker)",
                 "for use in the dev console.", sqlite3);
    globalThis.sqlite3 = sqlite3;
    const dbVfs = sqlite3.wasm.xWrap('fiddle_db_vfs', "*", ['string']);
    fiddleModule.fsUnlink = (fn)=>{
    fiddleModule.fsUnlink = (fn)=>fiddleModule.FS.unlink(fn);
      return sqlite3.wasm.sqlite3_wasm_vfs_unlink(dbVfs(0), fn);
    };
    wMsg('fiddle-ready');
  }).catch(e=>{
    console.error("Fiddle worker init failed:",e);
  });
})();
Changes to ext/wasm/fiddle/fiddle.js.
399
400
401
402
403
404
405

406
407

408
409
410
411
412
413
414
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416







+


+







  self.onSFLoaded = function(){
    delete this.onSFLoaded;
    // Unhide all elements which start out hidden
    EAll('.initially-hidden').forEach((e)=>e.classList.remove('initially-hidden'));
    E('#btn-reset').addEventListener('click',()=>SF.resetDb());
    const taInput = E('#input');
    const btnClearIn = E('#btn-clear');
    const selectExamples = E('#select-examples');
    btnClearIn.addEventListener('click',function(){
      taInput.value = '';
      selectExamples.selectedIndex = 0;
    },false);
    // Ctrl-enter and shift-enter both run the current SQL.
    taInput.addEventListener('keydown',function(ev){
      if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        btnShellExec.click();
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
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







+






-
+
-
-
-
+

















-
+
+
+
+
+
+
+







          "-- If a subset of the text is currently selected,\n",
          "-- only that part is executed.\n",
          "-- ================================================\n",
          ".help\n"
        ]},
              //{name: "Timer on", sql: ".timer on"},
              // ^^^ re-enable if emscripten re-enables getrusage()
        {name: "Box Mode", sql: ".mode box"},
        {name: "Setup table T", sql:[
          ".nullvalue NULL\n",
          "CREATE TABLE t(a,b);\n",
          "INSERT INTO t(a,b) VALUES('abc',123),('def',456),(NULL,789),('ghi',012);\n",
          "SELECT * FROM t;\n"
        ]},
        {name: "Table list", sql: ".tables"},
        {name: "sqlite_schema", sql: "select * from sqlite_schema"},
        {name: "Box Mode", sql: ".mode box"},
        {name: "JSON Mode", sql: ".mode json"},
        {name: "Mandlebrot", sql:[
        {name: "Mandelbrot", sql:[
          "WITH RECURSIVE",
          "  xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),\n",
          "  yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),\n",
          "  m(iter, cx, cy, x, y) AS (\n",
          "    SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis\n",
          "    UNION ALL\n",
          "    SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m \n",
          "     WHERE (x*x + y*y) < 4.0 AND iter<28\n",
          "  ),\n",
          "  m2(iter, cx, cy) AS (\n",
          "    SELECT max(iter), cx, cy FROM m GROUP BY cx, cy\n",
          "  ),\n",
          "  a(t) AS (\n",
          "    SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') \n",
          "    FROM m2 GROUP BY cy\n",
          "  )\n",
          "SELECT group_concat(rtrim(t),x'0a') as Mandelbrot FROM a;\n",
        ]}
        ]},
        {name: "JSON pretty-print",
         sql: "select json_pretty(json_object('ex',json('[52,3.14159]')))"
        },
        {name: "JSON pretty-print (with tabs)",
         sql: "select json_pretty(json_object('ex',json('[52,3.14159]')),char(0x09))"
        }
      ];
      const newOpt = function(lbl,val){
        const o = document.createElement('option');
        if(Array.isArray(val)) val = val.join('');
        o.value = val;
        if(!val) o.setAttribute('disabled',true);
        o.appendChild(document.createTextNode(lbl));
Changes to ext/wasm/index-dist.html.
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58






59
60
61
62
63
64
65







+
+
+







-
-
-
-
-
-







      Warnings and Caveats:
      <ul class='warning'>
        <li>All of these pages must be served via an HTTP
          server. Browsers do not support loading WASM files via
          file:// URLs.</li>
        <li>Any OPFS-related pages or tests require:
          <ul>
            <li>An OPFS-capable browser released after February
              2023. Some tests will work with Chromium-based browsers
              going back to around v102.</li>
            <li>That the web server emit the so-called
              <a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy'>COOP</a>
              and
              <a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy'>COEP</a>
              headers. <a href='https://sqlite.org/althttpd'>althttpd</a> requires the
              <code>-enable-sab</code> flag for that.
            </li>
            <li>A very recent version of a Chromium-based browser
              (v102 at least, possibly newer). OPFS support in the
              other major browsers is pending. Development and testing
              is currently done against a dev-channel release of
              Chrome (v111 as of 2023-02-10).
            </li>
          </ul>
        </li>
      </ul>
    </div>
    <div>The tests and demos...
      <ul id='test-list'>
        <li>Core-most tests
96
97
98
99
100
101
102


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







+
+







              demo of using the key-value VFS for storing a persistent db
              in JS <code>localStorage</code> or <code>sessionStorage</code>.</li>
            <li><a href='demo-worker1.html'>demo-worker1</a>:
              Worker-based wrapper of the OO API #1. Its Promise-based
              wrapper is significantly easier to use, however.</li>
            <li><a href='demo-worker1-promiser.html'>demo-worker1-promiser</a>:
              a demo of the Promise-based wrapper of the Worker1 API.</li>
            <li><a href='demo-worker1-promiser-esm.html'>demo-worker1-promiser-esm</a>:
              same as the previous demo except loads the promiser from an ESM module.</li>
          </ul>
        </li>
      </ul>
    </div>
    <style>
      #test-list { font-size: 120%; }
    </style>
Changes to ext/wasm/index.html.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43






44
45
46
47
48
49
50







+
+
+







-
-
-
-
-
-







      Warnings and Caveats:
      <ul class='warning'>
        <li>All of these pages must be served via an HTTP
          server. Browsers do not support loading WASM files via
          file:// URLs.</li>
        <li>Any OPFS-related pages or tests require:
          <ul>
            <li>An OPFS-capable browser released after February
              2023. Some tests will work with Chromium-based browsers
              going back to around v102.</li>
            <li>That the web server emit the so-called
              <a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy'>COOP</a>
              and
              <a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy'>COEP</a>
              headers. <a href='https://sqlite.org/althttpd'>althttpd</a> requires the
              <code>-enable-sab</code> flag for that.
            </li>
            <li>A very recent version of a
              Chromium-based browser (v102 at least, possibly newer). OPFS
              support in the other major browsers is pending. Development
              and testing is currently done against a dev-channel release
              of Chrome (v111 as of 2023-02-10).
            </li>
          </ul>
        </li>
      </ul>
    </div>
    <div>The tests and demos...
      <ul id='test-list'>
        <li>Core-most tests
83
84
85
86
87
88
89


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







+
+







              demo of using the key-value VFS for storing a persistent db
              in JS <code>localStorage</code> or <code>sessionStorage</code>.</li>
            <li><a href='demo-worker1.html'>demo-worker1</a>:
              Worker-based wrapper of the OO API #1. Its Promise-based
              wrapper is significantly easier to use, however.</li>
            <li><a href='demo-worker1-promiser.html'>demo-worker1-promiser</a>:
              a demo of the Promise-based wrapper of the Worker1 API.</li>
            <li><a href='demo-worker1-promiser-esm.html'>demo-worker1-promiser-esm</a>:
              same as the previous demo except loads the promiser from an ESM module.</li>
          </ul>
        </li>
        <li>speedtest1 ports (sqlite3's primary benchmarking tool)...
          <ul>
            <li><a href='speedtest1.html'>speedtest1</a>: a main-thread WASM build of speedtest1.</li>
            <li><a href='speedtest1.html?vfs=kvvfs'>speedtest1?vfs=kvvfs</a>: speedtest1 with the kvvfs.</li>
            <li><a href='speedtest1-worker.html?size=15'>speedtest1-worker</a>: an interactive Worker-thread variant of speedtest1.</li>
Changes to ext/wasm/jaccwabyt/jaccwabyt.md.
202
203
204
205
206
207
208
209
210


211
212
213
214
215
216
217
218
202
203
204
205
206
207
208


209
210

211
212
213
214
215
216
217







-
-
+
+
-







  dealloc: function(pointerToFree){...}
});
```

It also offers a number of other settings, but all are optional except
for the ones shown above. Those three config options abstract away
details which are specific to a given WASM environment. They provide
the WASM "heap" memory (a byte array), the memory allocator, and the
deallocator. In a conventional Emscripten setup, that config might
the WASM "heap" memory, the memory allocator, and the deallocator. In
a conventional Emscripten setup, that config might simply look like:
simply look like:

>  
```javascript
{
    heap:    Module['asm']['memory'],
    //Or:
    // heap: ()=>Module['HEAP8'],
Changes to ext/wasm/speedtest1-worker.html.
346
347
348
349
350
351
352
353

354
355
356
357
358
359
360
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360







-
+







        msg = msg.data;
        switch(msg.type){
            case 'ready':
                log("Worker is ready.");
                eControls.classList.remove('hidden');
                break;
            case 'stdout': log(msg.data); break;
            case 'stdout': logErr(msg.data); break;
            case 'stderr': logErr(msg.data); break;
            case 'run-start':
                eControls.disabled = true;
                log("Running speedtest1 with argv =",msg.data.join(' '));
                break;
            case 'run-end':
                log("speedtest1 finished.");
                eControls.disabled = false;
Changes to ext/wasm/speedtest1-worker.js.
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









-
-
-
+
+
+







'use strict';
(function(){
  let speedtestJs = 'speedtest1.js';
  const urlParams = new URL(self.location.href).searchParams;
  if(urlParams.has('sqlite3.dir')){
    speedtestJs = urlParams.get('sqlite3.dir') + '/' + speedtestJs;
  }
  importScripts(speedtestJs);
  /**
     If this environment contains OPFS, this function initializes it and
     returns the name of the dir on which OPFS is mounted, else it returns
     an empty string.
     If this build includes WASMFS, this function initializes it and
     returns the name of the dir on which OPFS is mounted, else it
     returns an empty string.
  */
  const wasmfsDir = function f(wasmUtil){
    if(undefined !== f._) return f._;
    const pdir = '/opfs';
    if( !self.FileSystemHandle
        || !self.FileSystemDirectoryHandle
        || !self.FileSystemFileHandle){
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
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







+










-















-
+







  const logMsg = (type,msgArgs)=>{
    const msg = msgArgs.join(' ');
    App.logBuffer.push(msg);
    mPost(type,msg);
  };
  const log = (...args)=>logMsg('stdout',args);
  const logErr = (...args)=>logMsg('stderr',args);
  const realSahName = 'opfs-sahpool-speedtest1';

  const runSpeedtest = async function(cliFlagsArray){
    const scope = App.wasm.scopedAllocPush();
    const dbFile = App.pDir+"/speedtest1.sqlite3";
    try{
      const argv = [
        "speedtest1.wasm", ...cliFlagsArray, dbFile
      ];
      App.logBuffer.length = 0;
      const ndxSahPool = argv.indexOf('opfs-sahpool');
      const realSahName = 'opfs-sahpool-speedtest1';
      if(ndxSahPool>0){
        argv[ndxSahPool] = realSahName;
        log("Updated argv for opfs-sahpool: --vfs",realSahName);
      }
      mPost('run-start', [...argv]);
      if(App.sqlite3.installOpfsSAHPoolVfs
         && !App.sqlite3.$SAHPoolUtil
         && ndxSahPool>0){
        log("Installing opfs-sahpool as",realSahName,"...");
        await App.sqlite3.installOpfsSAHPoolVfs({
          name: realSahName,
          initialCapacity: 3,
          clearOnInit: true,
          verbosity: 2
        }).then(PoolUtil=>{
          log("opfs-sahpool successfully installed as",realSahName);
          log("opfs-sahpool successfully installed as",PoolUtil.vfsName);
          App.sqlite3.$SAHPoolUtil = PoolUtil;
          //console.log("sqlite3.oo1.OpfsSAHPoolDb =", App.sqlite3.oo1.OpfsSAHPoolDb);
        });
      }
      App.wasm.xCall('wasm_main', argv.length,
                     App.wasm.scopedAllocMainArgv(argv));
    }catch(e){
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
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







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









-
-
-
-










          break;
        default:
          logErr("Unhandled worker message type:",msg.type);
          break;
    }
  };

  const sahpSanityChecks = function(sqlite3){
    log("Attempting OpfsSAHPoolDb sanity checks...");
    const db = new sqlite3.oo1.OpfsSAHPoolDb('opfs-sahpoool.db');
    const fn = db.filename;
    db.exec([
      'create table t(a);',
      'insert into t(a) values(1),(2),(3);'
    ]);
    db.close();
    sqlite3.wasm.sqlite3_wasm_vfs_unlink(sqlite3_vfs_find("opfs-sahpool"), fn);
    log("SAH sanity checks done.");
  };

  const EmscriptenModule = {
    print: log,
    printErr: logErr,
    setStatus: (text)=>mPost('load-status',text)
  };
  log("Initializing speedtest1 module...");
  self.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
    const S = globalThis.S = App.sqlite3 = sqlite3;
    log("Loaded speedtest1 module. Setting up...");
    App.vfsUnlink = function(pDb, fname){
      const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0);
      if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0);
    };
    App.pDir = wasmfsDir(S.wasm);
    App.wasm = S.wasm;
    //if(App.pDir) log("Persistent storage:",pDir);
    //else log("Using transient storage.");
    mPost('ready',true);
    log("Registered VFSes:", ...S.capi.sqlite3_js_vfs_list());
  }).catch(e=>{
    logErr(e);
  });
})();
Changes to ext/wasm/test-opfs-vfs.js.
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
18
19
20
21
22
23
24

25
26
27
28
29
30
31
32







-
+







  const logPrefix = "OPFS tester:";
  const log = (...args)=>console.log(logPrefix,...args);
  const warn =  (...args)=>console.warn(logPrefix,...args);
  const error =  (...args)=>console.error(logPrefix,...args);
  const opfs = sqlite3.opfs;
  log("tryOpfsVfs()");
  if(!sqlite3.opfs){
    const e = toss("OPFS is not available.");
    const e = new Error("OPFS is not available.");
    error(e);
    throw e;
  }
  const capi = sqlite3.capi;
  const pVfs = capi.sqlite3_vfs_find("opfs") || toss("Missing 'opfs' VFS.");
  const oVfs = new capi.sqlite3_vfs(pVfs);
  log("OPFS VFS:",pVfs, oVfs);
Changes to ext/wasm/tester1.c-pp.js.
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73







-
+







  /* Predicate for tests/groups. */
  const isUIThread = ()=>(globalThis.window===self && globalThis.document);
  /* Predicate for tests/groups. */
  const isWorker = ()=>!isUIThread();
  /* Predicate for tests/groups. */
  const testIsTodo = ()=>false;
  const haveWasmCTests = ()=>{
    return !!wasm.exports.sqlite3_wasm_test_intptr;
    return !!wasm.exports.sqlite3__wasm_test_intptr;
  };
  const hasOpfs = ()=>{
    return globalThis.FileSystemHandle
      && globalThis.FileSystemDirectoryHandle
      && globalThis.FileSystemFileHandle
      && globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle
      && navigator?.storage?.getDirectory;
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
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







-
+













-
+

-
+







            .assert(0===w.peek8(cstr+n))
            .assert(chr('d')===w.peek8(cstr+n-1));
        });
      }/*scopedAlloc()*/

      //log("xCall()...");
      {
        const pJson = w.xCall('sqlite3_wasm_enum_json');
        const pJson = w.xCall('sqlite3__wasm_enum_json');
        T.assert(Number.isFinite(pJson)).assert(w.cstrlen(pJson)>300);
      }

      //log("xWrap()...");
      {
        T.mustThrowMatching(()=>w.xWrap('sqlite3_libversion',null,'i32'),
                            /requires 0 arg/).
          assert(w.xWrap.resultAdapter('i32') instanceof Function).
          assert(w.xWrap.argAdapter('i32') instanceof Function);
        let fw = w.xWrap('sqlite3_libversion','utf8');
        T.mustThrowMatching(()=>fw(1), /requires 0 arg/);
        let rc = fw();
        T.assert('string'===typeof rc).assert(rc.length>5);
        rc = w.xCallWrapped('sqlite3_wasm_enum_json','*');
        rc = w.xCallWrapped('sqlite3__wasm_enum_json','*');
        T.assert(rc>0 && Number.isFinite(rc));
        rc = w.xCallWrapped('sqlite3_wasm_enum_json','utf8');
        rc = w.xCallWrapped('sqlite3__wasm_enum_json','utf8');
        T.assert('string'===typeof rc).assert(rc.length>300);


        { // 'string:static' argAdapter() sanity checks...
          let argAd = w.xWrap.argAdapter('string:static');
          let p0 = argAd('foo'), p1 = argAd('bar');
          T.assert(w.isPtr(p0) && w.isPtr(p1))
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
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







-
+









-
+






-
+







          }finally{
            wasm.uninstallFunction(fp);
          }
        }

        if(haveWasmCTests()){
          if(!sqlite3.config.useStdAlloc){
            fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:dealloc',['i32']);
            fw = w.xWrap('sqlite3__wasm_test_str_hello', 'utf8:dealloc',['i32']);
            rc = fw(0);
            T.assert('hello'===rc);
            rc = fw(1);
            T.assert(null===rc);
          }

          if(w.bigIntEnabled){
            w.xWrap.resultAdapter('thrice', (v)=>3n*BigInt(v));
            w.xWrap.argAdapter('twice', (v)=>2n*BigInt(v));
            fw = w.xWrap('sqlite3_wasm_test_int64_times2','thrice','twice');
            fw = w.xWrap('sqlite3__wasm_test_int64_times2','thrice','twice');
            rc = fw(1);
            T.assert(12n===rc);

            w.scopedAllocCall(function(){
              const pI1 = w.scopedAlloc(8), pI2 = pI1+4;
              w.pokePtr([pI1, pI2], 0);
              const f = w.xWrap('sqlite3_wasm_test_int64_minmax',undefined,['i64*','i64*']);
              const f = w.xWrap('sqlite3__wasm_test_int64_minmax',undefined,['i64*','i64*']);
              const [r1, r2] = w.peek64([pI1, pI2]);
              T.assert(!Number.isSafeInteger(r1)).assert(!Number.isSafeInteger(r2));
            });
          }
        }
      }/*xWrap()*/
    }/*WhWasmUtil*/)
938
939
940
941
942
943
944
945

946
947
948
949
950
951
952
938
939
940
941
942
943
944

945
946
947
948
949
950
951
952







-
+







          assert(WTStruct.isA(wts)).
          assert(wts instanceof WTStruct).
          assert(wts instanceof StructType).
          assert(StructType.isA(wts)).
          assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8).
          assert(0===wts.$ppV).assert(0===wts.$xFunc);
        const testFunc =
              W.xGet('sqlite3_wasm_test_struct'/*name gets mangled in -O3 builds!*/);
              W.xGet('sqlite3__wasm_test_struct'/*name gets mangled in -O3 builds!*/);
        let counter = 0;
        //log("wts.pointer =",wts.pointer);
        const wtsFunc = function(arg){
          /*log("This from a JS function called from C, "+
              "which itself was called from JS. arg =",arg);*/
          ++counter;
          if(3===counter){
1124
1125
1126
1127
1128
1129
1130
1131

1132
1133
1134
1135
1136
1137
1138
1124
1125
1126
1127
1128
1129
1130

1131
1132
1133
1134
1135
1136
1137
1138







-
+







    })
  ;/*end sqlite3_randomness() checks*/

  ////////////////////////////////////////////////////////////////////////
  T.g('sqlite3.oo1')
    .t('Create db', function(sqlite3){
      const dbFile = '/tester1.db';
      wasm.sqlite3_wasm_vfs_unlink(0, dbFile);
      sqlite3.util.sqlite3__wasm_vfs_unlink(0, dbFile);
      const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c');
      db.onclose = {
        disposeAfter: [],
        disposeBefore: [
          (db)=>{
            //console.debug("db.onclose.before dropping modules");
            //sqlite3.capi.sqlite3_drop_modules(db.pointer, 0);
1455
1456
1457
1458
1459
1460
1461
1462

1463
1464
1465
1466
1467
1468
1469
1455
1456
1457
1458
1459
1460
1461

1462
1463
1464
1465
1466
1467
1468
1469







-
+







        rowMode: 0
      });
      T.assert(Array.isArray(rv)).assert(3===rv.length)
        .assert(-1===rv[0]).assert(-3===rv[2]);
      rv = db.exec("SELECT 1 WHERE 0",{rowMode: 0});
      T.assert(Array.isArray(rv)).assert(0===rv.length);
      if(wasm.bigIntEnabled && haveWasmCTests()){
        const mI = wasm.xCall('sqlite3_wasm_test_int64_max');
        const mI = wasm.xCall('sqlite3__wasm_test_int64_max');
        const b = BigInt(Number.MAX_SAFE_INTEGER * 2);
        T.assert(b === db.selectValue("SELECT "+b)).
          assert(b === db.selectValue("SELECT ?", b)).
          assert(mI == db.selectValue("SELECT $x", {$x:mI}));
      }else{
        /* Curiously, the JS spec seems to be off by one with the definitions
           of MIN/MAX_SAFE_INTEGER:
1681
1682
1683
1684
1685
1686
1687
1688

1689
1690
1691

1692
1693
1694
1695
1696
1697
1698
1681
1682
1683
1684
1685
1686
1687

1688
1689
1690

1691
1692
1693
1694
1695
1696
1697
1698







-
+


-
+







        const db2 = new sqlite3.oo1.DB(filename,'r');
        try {
          const sql = "select count(*) from t";
          const n = db.selectValue(sql);
          T.assert(n>0 && db2.selectValue(sql) === n);
        }finally{
          db2.close();
          wasm.sqlite3_wasm_vfs_unlink(0, filename);
          sqlite3.util.sqlite3__wasm_vfs_unlink(0, filename);
        }
      }
    }/*sqlite3_js_vfs_create_file()*/)
    }/*sqlite3_js_posix_create_file()*/)

  ////////////////////////////////////////////////////////////////////
    .t({
      name:'Scalar UDFs',
      test: function(sqlite3){
        const db = this.db;
        db.createFunction("foo",(pCx,a,b)=>a+b);
2071
2072
2073
2074
2075
2076
2077
2078

2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093

2094
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
2071
2072
2073
2074
2075
2076
2077

2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092

2093
2094
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







-
+














-
+





-
+









-
-
+
+




-
+







        const w = wasm, db = this.db;
        const stack = w.scopedAllocPush();
        let ptrInt;
        const origValue = 512;
        try{
          ptrInt = w.scopedAlloc(4);
          w.poke32(ptrInt,origValue);
          const cf = w.xGet('sqlite3_wasm_test_intptr');
          const cf = w.xGet('sqlite3__wasm_test_intptr');
          const oldPtrInt = ptrInt;
          T.assert(origValue === w.peek32(ptrInt));
          const rc = cf(ptrInt);
          T.assert(2*origValue === rc).
            assert(rc === w.peek32(ptrInt)).
            assert(oldPtrInt === ptrInt);
          const pi64 = w.scopedAlloc(8)/*ptr to 64-bit integer*/;
          const o64 = 0x010203040506/*>32-bit integer*/;
          if(w.bigIntEnabled){
            w.poke64(pi64, o64);
            //log("pi64 =",pi64, "o64 = 0x",o64.toString(16), o64);
            const v64 = ()=>w.peek64(pi64)
            T.assert(v64() == o64);
            //T.assert(o64 === w.peek64(pi64));
            const cf64w = w.xGet('sqlite3_wasm_test_int64ptr');
            const cf64w = w.xGet('sqlite3__wasm_test_int64ptr');
            cf64w(pi64);
            T.assert(v64() == BigInt(2 * o64));
            cf64w(pi64);
            T.assert(v64() == BigInt(4 * o64));

            const biTimes2 = w.xGet('sqlite3_wasm_test_int64_times2');
            const biTimes2 = w.xGet('sqlite3__wasm_test_int64_times2');
            T.assert(BigInt(2 * o64) ===
                     biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError
                                           in the call :/ */));

            const pMin = w.scopedAlloc(16);
            const pMax = pMin + 8;
            const g64 = (p)=>w.peek64(p);
            w.poke64([pMin, pMax], 0);
            const minMaxI64 = [
              w.xCall('sqlite3_wasm_test_int64_min'),
              w.xCall('sqlite3_wasm_test_int64_max')
              w.xCall('sqlite3__wasm_test_int64_min'),
              w.xCall('sqlite3__wasm_test_int64_max')
            ];
            T.assert(minMaxI64[0] < BigInt(Number.MIN_SAFE_INTEGER)).
              assert(minMaxI64[1] > BigInt(Number.MAX_SAFE_INTEGER));
            //log("int64_min/max() =",minMaxI64, typeof minMaxI64[0]);
            w.xCall('sqlite3_wasm_test_int64_minmax', pMin, pMax);
            w.xCall('sqlite3__wasm_test_int64_minmax', pMin, pMax);
            T.assert(g64(pMin) === minMaxI64[0], "int64 mismatch").
              assert(g64(pMax) === minMaxI64[1], "int64 mismatch");
            //log("pMin",g64(pMin), "pMax",g64(pMax));
            w.poke64(pMin, minMaxI64[0]);
            T.assert(g64(pMin) === minMaxI64[0]).
              assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))).
              assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax)));
2556
2557
2558
2559
2560
2561
2562
2563

2564
2565
2566
2567
2568
2569
2570
2556
2557
2558
2559
2560
2561
2562

2563
2564
2565
2566
2567
2568
2569
2570







-
+







      }
      T.assert(capi.SQLITE_ERROR_MISSING_COLLSEQ === rc);
    })/*custom collation*/

  ////////////////////////////////////////////////////////////////////////
    .t('Close db', function(){
      T.assert(this.db).assert(wasm.isPtr(this.db.pointer));
      //wasm.sqlite3_wasm_db_reset(this.db); // will leak virtual tables!
      //wasm.sqlite3__wasm_db_reset(this.db); // will leak virtual tables!
      this.db.close();
      T.assert(!this.db.pointer);
    })
  ;/* end of oo1 checks */

  ////////////////////////////////////////////////////////////////////////
  T.g('kvvfs')
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646

2647
2648
2649
2650
2651
2652
2653




2654
2655
2656
2657
2658
2659
2660
2601
2602
2603
2604
2605
2606
2607






















2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631

2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642







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

















+






-
+
+
+
+







          db.exec('insert into kvvfs(a) values(4),(5),(6)');
          T.assert(6 === db.selectValue('select count(*) from kvvfs'));
        }finally{
          db.close();
        }
      }
    }/*kvvfs sanity checks*/)
    .t({
      name: 'kvvfs sqlite3_js_vfs_create_file()',
      predicate: ()=>"kvvfs does not currently support this",
      test: function(sqlite3){
        let db;
        try {
          db = new this.JDb(this.kvvfsDbFile);
          const exp = capi.sqlite3_js_db_export(db);
          db.close();
          this.kvvfsUnlink();
          capi.sqlite3_js_vfs_create_file("kvvfs", this.kvvfsDbFile, exp);
          db = new this.JDb(filename);
          T.assert(6 === db.selectValue('select count(*) from kvvfs'));
        }finally{
          db.close();
          this.kvvfsUnlink();
        }
        delete this.kvvfsDbFile;
        delete this.kvvfsUnlink;
        delete this.JDb;
      }
   }/*kvvfs sqlite3_js_vfs_create_file()*/)
  ;/* end kvvfs tests */

  ////////////////////////////////////////////////////////////////////////
  T.g('Hook APIs')
    .t({
      name: "sqlite3_commit/rollback/update_hook()",
      predicate: ()=>wasm.bigIntEnabled || "Update hook requires int64",
      test: function(sqlite3){
        let countCommit = 0, countRollback = 0;;
        const db = new sqlite3.oo1.DB(':memory:',1 ? 'c' : 'ct');
        let rc = capi.sqlite3_commit_hook(db, (p)=>{
          ++countCommit;
          return (1 === p) ? 0 : capi.SQLITE_ERROR;
        }, 1);
        T.assert( 0 === rc /*void pointer*/ );

        // Commit hook...
        T.assert( 0!=capi.sqlite3_get_autocommit(db) );
        db.exec("BEGIN; SELECT 1; COMMIT");
        T.assert(0 === countCommit,
                 "No-op transactions (mostly) do not trigger commit hook.");
        db.exec("BEGIN EXCLUSIVE; SELECT 1; COMMIT");
        T.assert(1 === countCommit,
                 "But EXCLUSIVE transactions do.");
        db.transaction((d)=>{d.exec("create table t(a)");});
        db.transaction((d)=>{
          T.assert( 0==capi.sqlite3_get_autocommit(db) );
          d.exec("create table t(a)");
        });
        T.assert(2 === countCommit);

        // Rollback hook:
        rc = capi.sqlite3_rollback_hook(db, (p)=>{
          ++countRollback;
          T.assert( 2 === p );
        }, 2);
2902
2903
2904
2905
2906
2907
2908


2909
2910

2911
2912

2913
2914
2915




2916
2917

2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931






2932


2933
2934
2935
2936
2937
2938
2939

2940
2941
2942
2943
2944
2945
2946
2947
2948


2949
2950
2951
2952
2953
2954
2955
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893

2894


2895



2896
2897
2898
2899
2900

2901



2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918

2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930

2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945







+
+

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

-
+
-
-
-











+
+
+
+
+
+
-
+
+







+


-






+
+







  ////////////////////////////////////////////////////////////////////////
  T.g('OPFS: Origin-Private File System',
      (sqlite3)=>(sqlite3.capi.sqlite3_vfs_find("opfs")
                  || 'requires "opfs" VFS'))
    .t({
      name: 'OPFS db sanity checks',
      test: async function(sqlite3){
        T.assert(capi.sqlite3_vfs_find('opfs'));
        const opfs = sqlite3.opfs;
        const filename = this.opfsDbFile = '/dir/sqlite3-tester1.db';
        const pVfs = this.opfsVfs = capi.sqlite3_vfs_find('opfs');
        const fileUri = 'file://'+filename+'?delete-before-open=1';
        T.assert(pVfs);
        const unlink = this.opfsUnlink =
        const initSql = [
              (fn=filename)=>{wasm.sqlite3_wasm_vfs_unlink(pVfs,fn)};
        unlink();
        let db = new sqlite3.oo1.OpfsDb(filename);
          'create table p(a);',
          'insert into p(a) values(1),(2),(3)'
        ];
        let db = new sqlite3.oo1.OpfsDb(fileUri);
        try {
          db.exec([
          db.exec(initSql);
            'create table p(a);',
            'insert into p(a) values(1),(2),(3)'
          ]);
          T.assert(3 === db.selectValue('select count(*) from p'));
          db.close();
          db = new sqlite3.oo1.OpfsDb(filename);
          db.exec('insert into p(a) values(4),(5),(6)');
          T.assert(6 === db.selectValue('select count(*) from p'));
          this.opfsDbExport = capi.sqlite3_js_db_export(db);
          T.assert(this.opfsDbExport instanceof Uint8Array)
            .assert(this.opfsDbExport.byteLength>0
                    && 0===this.opfsDbExport.byteLength % 512);
        }finally{
          db.close();
        }
        T.assert(await opfs.entryExists(filename));
        try {
          db = new sqlite3.oo1.OpfsDb(fileUri);
          db.exec(initSql) /* will throw if delete-before-open did not work */;
          T.assert(3 === db.selectValue('select count(*) from p'));
          unlink();
        }finally{
          if(db) db.close();
        }
      }
    }/*OPFS db sanity checks*/)
    .t({
      name: 'OPFS import',
      test: async function(sqlite3){
        let db;
        const filename = this.opfsDbFile;
        try {
          const exp = this.opfsDbExport;
          const filename = this.opfsDbFile;
          delete this.opfsDbExport;
          this.opfsImportSize = await sqlite3.oo1.OpfsDb.importDb(filename, exp);
          db = new sqlite3.oo1.OpfsDb(this.opfsDbFile);
          T.assert(6 === db.selectValue('select count(*) from p')).
            assert( this.opfsImportSize == exp.byteLength );
          db.close();
          const unlink = this.opfsUnlink =
                (fn=filename)=>sqlite3.util.sqlite3__wasm_vfs_unlink("opfs",fn);
          this.opfsUnlink(filename);
          T.assert(!(await sqlite3.opfs.entryExists(filename)));
          // Try again with a function as an input source:
          let cursor = 0;
          const blockSize = 512, end = exp.byteLength;
          const reader = async function(){
            if(cursor >= exp.byteLength){
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977

2978
2979
2980
2981
2982
2983
2984
2985
2986
2958
2959
2960
2961
2962
2963
2964

2965

2966
2967

2968
2969
2970
2971
2972
2973
2974







-

-
+

-







        }
      }
    }/*OPFS export/import*/)
    .t({
      name: '(Internal-use) OPFS utility APIs',
      test: async function(sqlite3){
        const filename = this.opfsDbFile;
        const pVfs = this.opfsVfs;
        const unlink = this.opfsUnlink;
        T.assert(filename && pVfs && !!unlink);
        T.assert(filename && !!unlink);
        delete this.opfsDbFile;
        delete this.opfsVfs;
        delete this.opfsUnlink;
        /**************************************************************
           ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended
           for client-side use. It is only for this project's own
           internal use. Its APIs are subject to change or removal at
           any time.
        ***************************************************************/
3223
3224
3225
3226
3227
3228
3229

3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248

3249
3250

3251
3252
3253
3254
3255
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236

3237
3238

3239
3240
3241
3242
3243
3244







+


















-
+

-
+





  globalThis.sqlite3InitModule.__isUnderTest =
    true /* disables certain API-internal cleanup so that we can
            test internal APIs from here */;
  globalThis.sqlite3InitModule({
    print: log,
    printErr: error
  }).then(async function(sqlite3){
    TestUtil.assert(!!sqlite3.util);
    log("Done initializing WASM/JS bits. Running tests...");
    sqlite3.config.warn("Installing sqlite3 bits as global S for local dev/test purposes.");
    globalThis.S = sqlite3;
    /*await sqlite3.installOpfsSAHPoolVfs(sahPoolConfig)
      .then((u)=>log("Loaded",u.vfsName,"VFS"))
      .catch(e=>{
        log("Cannot install OpfsSAHPool.",e);
      });*/
    capi = sqlite3.capi;
    wasm = sqlite3.wasm;
    log("sqlite3 version:",capi.sqlite3_libversion(),
        capi.sqlite3_sourceid());
    if(wasm.bigIntEnabled){
      log("BigInt/int64 support is enabled.");
    }else{
      logClass('warning',"BigInt/int64 support is disabled.");
    }
    if(haveWasmCTests()){
      log("sqlite3_wasm_test_...() APIs are available.");
      log("sqlite3__wasm_test_...() APIs are available.");
    }else{
      logClass('warning',"sqlite3_wasm_test_...() APIs unavailable.");
      logClass('warning',"sqlite3__wasm_test_...() APIs unavailable.");
    }
    log("registered vfs list =",capi.sqlite3_js_vfs_list().join(', '));
    TestUtil.runTests(sqlite3);
  });
})(self);
Changes to main.mk.
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
226
227
228
229
230
231
232

233
234
235
236
237
238
239







-







  $(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
  $(TOP)/ext/rbu/sqlite3rbu.c \
  $(TOP)/ext/rbu/sqlite3rbu.h
SRC += \
  $(TOP)/ext/misc/stmt.c


# FTS5 things
#
FTS5_HDR = \
   $(TOP)/ext/fts5/fts5.h \
   $(TOP)/ext/fts5/fts5Int.h \
   fts5parse.h

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







+














-
+
+
+







  $(TOP)/ext/misc/ieee754.c \
  $(TOP)/ext/misc/mmapwarm.c \
  $(TOP)/ext/misc/nextchar.c \
  $(TOP)/ext/misc/normalize.c \
  $(TOP)/ext/misc/percentile.c \
  $(TOP)/ext/misc/prefixes.c \
  $(TOP)/ext/misc/qpvtab.c \
  $(TOP)/ext/misc/randomjson.c \
  $(TOP)/ext/misc/regexp.c \
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \
  $(TOP)/ext/misc/zipfile.c \
  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \
  $(TOP)/ext/fts5/fts5_test_tok.c \
  $(TOP)/ext/rtree/test_rtreedoc.c \
  $(TOP)/ext/recover/sqlite3recover.c \
  $(TOP)/ext/recover/dbdata.c \
  $(TOP)/ext/recover/test_recover.c
  $(TOP)/ext/recover/test_recover.c \
  $(TOP)/ext/intck/test_intck.c  \
  $(TOP)/ext/intck/sqlite3intck.c 


#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
522
523
524
525
526
527
528


529
530
531
532
533
534

535
536
537
538
539
540
541
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546







+
+






+







FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_OPT += -DSQLITE_STRICT_SUBTYPE=1
FUZZCHECK_OPT += -DSQLITE_STATIC_RANDOMJSON
FUZZSRC += $(TOP)/test/fuzzcheck.c
FUZZSRC += $(TOP)/test/ossfuzz.c
FUZZSRC += $(TOP)/test/vt02.c
FUZZSRC += $(TOP)/test/fuzzinvariants.c
FUZZSRC += $(TOP)/ext/recover/dbdata.c
FUZZSRC += $(TOP)/ext/recover/sqlite3recover.c
FUZZSRC += $(TOP)/ext/misc/randomjson.c
DBFUZZ_OPT =
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
ST_OPT = -DSQLITE_THREADSAFE=0

# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
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
656
657
658
659
660
661
662

663
664
665
666
667
668
669
670
671
672
673
674

675
676
677
678
679
680
681
682







-
+











-
+







	rm tsrc/sqlite.h.in tsrc/parse.y
	tclsh $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
	mv vdbe.new tsrc/vdbe.c
	cp fts5.c fts5.h tsrc
	touch target_source

sqlite3.c:	target_source $(TOP)/tool/mksqlite3c.tcl src-verify
	tclsh $(TOP)/tool/mksqlite3c.tcl
	tclsh $(TOP)/tool/mksqlite3c.tcl $(EXTRA_SRC)
	cp tsrc/sqlite3ext.h .
	cp $(TOP)/ext/session/sqlite3session.h .
	echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
	cat sqlite3.c >>tclsqlite3.c
	echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
	cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c

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

sqlite3.c-debug:	target_source $(TOP)/tool/mksqlite3c.tcl src-verify
	tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1
	tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1 $(EXTRA_SRC)
	echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
	cat sqlite3.c >>tclsqlite3.c
	echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
	echo '#line 1 "tclsqlite.c"' >>tclsqlite3.c
	cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c

sqlite3-all.c:	sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
709
710
711
712
713
714
715
716

717
718
719
720
721
722
723
724
714
715
716
717
718
719
720

721

722
723
724
725
726
727
728







-
+
-








# Rules to build opcodes.c and opcodes.h
#
opcodes.c:	opcodes.h $(TOP)/tool/mkopcodec.tcl
	tclsh $(TOP)/tool/mkopcodec.tcl opcodes.h >opcodes.c

opcodes.h:	parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
	cat parse.h $(TOP)/src/vdbe.c | \
	cat parse.h $(TOP)/src/vdbe.c | tclsh $(TOP)/tool/mkopcodeh.tcl >opcodes.h
		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
	cp $(TOP)/src/parse.y .
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
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







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

-
+







	cat $(TOP)/VERSION | tclsh $(TOP)/tool/replace.tcl exact . , >>$@
	echo '#endif' >>sqlite3rc.h

keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash >keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/completion.c \
        $(TOP)/ext/misc/base64.c \
        $(TOP)/ext/misc/base85.c \
        $(TOP)/ext/misc/decimal.c \
	$(TOP)/ext/misc/fileio.c \
        $(TOP)/ext/misc/ieee754.c \
        $(TOP)/ext/misc/regexp.c \
        $(TOP)/ext/misc/series.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/sqlar.c \
        $(TOP)/ext/misc/uint.c \
# Source and header files that shell.c depends on
SHELL_DEP = \
    $(TOP)/src/shell.c.in \
    $(TOP)/ext/consio/console_io.c \
    $(TOP)/ext/consio/console_io.h \
    $(TOP)/ext/expert/sqlite3expert.c \
    $(TOP)/ext/expert/sqlite3expert.h \
    $(TOP)/ext/intck/sqlite3intck.c \
    $(TOP)/ext/intck/sqlite3intck.h \
    $(TOP)/ext/misc/appendvfs.c \
    $(TOP)/ext/misc/base64.c \
    $(TOP)/ext/misc/base85.c \
    $(TOP)/ext/misc/completion.c \
    $(TOP)/ext/misc/decimal.c \
    $(TOP)/ext/misc/fileio.c \
    $(TOP)/ext/misc/ieee754.c \
    $(TOP)/ext/misc/memtrace.c \
    $(TOP)/ext/misc/pcachetrace.c \
    $(TOP)/ext/misc/regexp.c \
    $(TOP)/ext/misc/series.c \
    $(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
	$(TOP)/ext/misc/memtrace.c \
	$(TOP)/ext/misc/pcachetrace.c \
	$(TOP)/ext/recover/dbdata.c \
	$(TOP)/ext/recover/sqlite3recover.c \
	$(TOP)/ext/recover/sqlite3recover.h \
        $(TOP)/src/test_windirent.c
    $(TOP)/ext/misc/sqlar.c \
    $(TOP)/ext/misc/uint.c \
    $(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_SRC) $(TOP)/tool/mkshellc.tcl
shell.c:	$(SHELL_DEP) $(TOP)/tool/mkshellc.tcl
	tclsh $(TOP)/tool/mkshellc.tcl >shell.c



# Rules to build the extension objects.
#
icu.o:	$(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR)
894
895
896
897
898
899
900


901
902
903
904
905
906
907
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918







+
+







TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
TESTFIXTURE_FLAGS += -DSQLITE_STATIC_RANDOMJSON
TESTFIXTURE_FLAGS += -DSQLITE_STRICT_SUBTYPE=1

testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
	$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS)                            \
		$(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c                \
		-o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB)

amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c  \
Changes to src/analyze.c.
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
260
261
262
263
264
265
266

267
268
269
270
271
272
273
274
275
276







-


+







** Three SQL functions - stat_init(), stat_push(), and stat_get() -
** share an instance of the following structure to hold their state
** information.
*/
typedef struct StatAccum StatAccum;
typedef struct StatSample StatSample;
struct StatSample {
  tRowcnt *anEq;                  /* sqlite_stat4.nEq */
  tRowcnt *anDLt;                 /* sqlite_stat4.nDLt */
#ifdef SQLITE_ENABLE_STAT4
  tRowcnt *anEq;                  /* sqlite_stat4.nEq */
  tRowcnt *anLt;                  /* sqlite_stat4.nLt */
  union {
    i64 iRowid;                     /* Rowid in main table of the key */
    u8 *aRowid;                     /* Key for WITHOUT ROWID tables */
  } u;
  u32 nRowid;                     /* Sizeof aRowid[] */
  u8 isPSample;                   /* True if a periodic sample */
420
421
422
423
424
425
426
427
428

429

430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452

453
454
455
456
457
458
459
420
421
422
423
424
425
426


427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449

450
451
452
453
454
455
456
457
458
459







-
-
+

+




















-


+







  nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol;
  nKeyCol = sqlite3_value_int(argv[1]);
  assert( nKeyCol<=nCol );
  assert( nKeyCol>0 );

  /* Allocate the space required for the StatAccum object */
  n = sizeof(*p) 
    + sizeof(tRowcnt)*nColUp                  /* StatAccum.anEq */
    + sizeof(tRowcnt)*nColUp;                 /* StatAccum.anDLt */
    + sizeof(tRowcnt)*nColUp;                    /* StatAccum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
  n += sizeof(tRowcnt)*nColUp;                   /* StatAccum.anEq */
  if( mxSample ){
    n += sizeof(tRowcnt)*nColUp                  /* StatAccum.anLt */
      + sizeof(StatSample)*(nCol+mxSample)       /* StatAccum.aBest[], a[] */
      + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
  }
#endif
  p = sqlite3DbMallocZero(db, n);
  if( p==0 ){
    sqlite3_result_error_nomem(context);
    return;
  }

  p->db = db;
  p->nEst = sqlite3_value_int64(argv[2]);
  p->nRow = 0;
  p->nLimit = sqlite3_value_int64(argv[3]);
  p->nCol = nCol;
  p->nKeyCol = nKeyCol;
  p->nSkipAhead = 0;
  p->current.anDLt = (tRowcnt*)&p[1];
  p->current.anEq = &p->current.anDLt[nColUp];

#ifdef SQLITE_ENABLE_STAT4
  p->current.anEq = &p->current.anDLt[nColUp];
  p->mxSample = p->nLimit==0 ? mxSample : 0;
  if( mxSample ){
    u8 *pSpace;                     /* Allocated space not yet assigned */
    int i;                          /* Used to iterate through p->aSample[] */

    p->iGet = -1;
    p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
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
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







+

+








+



+




-

+







  UNUSED_PARAMETER( argc );
  UNUSED_PARAMETER( context );
  assert( p->nCol>0 );
  assert( iChng<p->nCol );

  if( p->nRow==0 ){
    /* This is the first call to this function. Do initialization. */
#ifdef SQLITE_ENABLE_STAT4
    for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
#endif
  }else{
    /* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
    if( p->mxSample ) samplePushPrevious(p, iChng);
#endif

    /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
    ** to the current row of the index. */
#ifdef SQLITE_ENABLE_STAT4
    for(i=0; i<iChng; i++){
      p->current.anEq[i]++;
    }
#endif
    for(i=iChng; i<p->nCol; i++){
      p->current.anDLt[i]++;
#ifdef SQLITE_ENABLE_STAT4
      if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
#endif
      p->current.anEq[i] = 1;
#endif
    }
  }

  p->nRow++;
#ifdef SQLITE_ENABLE_STAT4
  if( p->mxSample ){
    tRowcnt nLt;
863
864
865
866
867
868
869

870


871
872
873
874
875
876
877
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
882
883







+
-
+
+







    sqlite3_str_appendf(&sStat, "%llu", 
        p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
    for(i=0; i<p->nKeyCol; i++){
      u64 nDistinct = p->current.anDLt[i] + 1;
      u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
      if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
      sqlite3_str_appendf(&sStat, " %llu", iVal);
#ifdef SQLITE_ENABLE_STAT4
      assert( p->current.anEq[i] );
      assert( p->current.anEq[i] || p->nRow==0 );
#endif
    }
    sqlite3ResultStrAccum(context, &sStat);
  }
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
1047
1048
1049
1050
1051
1052
1053
1054

1055
1056
1057
1058
1059
1060
1061
1053
1054
1055
1056
1057
1058
1059

1060
1061
1062
1063
1064
1065
1066
1067







-
+







  iIdxCur = iTab++;
  pParse->nTab = MAX(pParse->nTab, iTab);
  sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
  sqlite3VdbeLoadString(v, regTabname, pTab->zName);

  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    int nCol;                     /* Number of columns in pIdx. "N" */
    int addrRewind;               /* Address of "OP_Rewind iIdxCur" */
    int addrGotoEnd;               /* Address of "OP_Rewind iIdxCur" */
    int addrNextRow;              /* Address of "next_row:" */
    const char *zIdxName;         /* Name of the index */
    int nColTest;                 /* Number of columns to test for changes */

    if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
    if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
    if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){
1071
1072
1073
1074
1075
1076
1077

1078
1079
1080






1081
1082
1083
1084
1085
1086
1087
1077
1078
1079
1080
1081
1082
1083
1084
1085


1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098







+

-
-
+
+
+
+
+
+







    /* Populate the register containing the index name. */
    sqlite3VdbeLoadString(v, regIdxname, zIdxName);
    VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName));

    /*
    ** Pseudo-code for loop that calls stat_push():
    **
    **   regChng = 0
    **   Rewind csr
    **   if eof(csr) goto end_of_scan;
    **   regChng = 0
    **   if eof(csr){
    **      stat_init() with count = 0;
    **      goto end_of_scan;
    **   }
    **   count()
    **   stat_init()
    **   goto chng_addr_0;
    **
    **  next_row:
    **   regChng = 0
    **   if( idx(0) != regPrev(0) ) goto chng_addr_0
    **   regChng = 1
    **   if( idx(1) != regPrev(1) ) goto chng_addr_1
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
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







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



-
+
-



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


+
+

-
-
-
-
-
-
-
-








    /* Open a read-only cursor on the index being analyzed. */
    assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
    sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb);
    sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    VdbeComment((v, "%s", pIdx->zName));

    /* Invoke the stat_init() function. The arguments are:
    ** 
    /* Implementation of the following:
    **
    **   regChng = 0
    **   Rewind csr
    **   if eof(csr){
    **      stat_init() with count = 0;
    **      goto end_of_scan;
    **   }
    **   count()
    **   stat_init()
    **   goto chng_addr_0;
    */
    assert( regTemp2==regStat+4 );
    sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);

    /* Arguments to stat_init(): 
    **    (1) the number of columns in the index including the rowid
    **        (or for a WITHOUT ROWID table, the number of PK columns),
    **    (2) the number of columns in the key without the rowid/pk
    **    (3) estimated number of rows in the index,
    **    (3) estimated number of rows in the index. */
    */
    sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
    assert( regRowid==regStat+2 );
    sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
#ifdef SQLITE_ENABLE_STAT4
    if( OptimizationEnabled(db, SQLITE_Stat4) ){
      sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
      addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
      VdbeCoverage(v);
    }else
#endif
    {
      addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
      VdbeCoverage(v);
      sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
    sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp,
    }
    assert( regTemp2==regStat+4 );
                      OptimizationDisabled(db, SQLITE_Stat4));
    sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
    sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
                               &statInitFuncdef, 0);
    addrGotoEnd = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
    VdbeCoverage(v);

    /* Implementation of the following:
    **
    **   Rewind csr
    **   if eof(csr) goto end_of_scan;
    **   regChng = 0
    **   goto next_push_0;
    **
    */
    sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
    addrNextRow = sqlite3VdbeCurrentAddr(v);

    if( nColTest>0 ){
      int endDistinctTest = sqlite3VdbeMakeLabel(pParse);
      int *aGotoChng;               /* Array of jump instruction addresses */
      aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
1253
1254
1255
1256
1257
1258
1259






1260
1261
1262
1263
1264
1265
1266
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278







+
+
+
+
+
+







        sqlite3VdbeJumpHere(v, j3);
      }else{
        sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
      }
    }

    /* Add the entry to the stat1 table. */
    if( pIdx->pPartIdxWhere ){
      /* Partial indexes might get a zero-entry in sqlite_stat1.  But
      ** an empty table is omitted from sqlite_stat1. */
      sqlite3VdbeJumpHere(v, addrGotoEnd);
      addrGotoEnd = 0;
    }
    callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
    assert( "BBB"[0]==SQLITE_AFF_TEXT );
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
1275
1276
1277
1278
1279
1280
1281







1282
1283
1284
1285
1286
1287
1288
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307







+
+
+
+
+
+
+







      int regDLt = regStat1+2;
      int regSample = regStat1+3;
      int regCol = regStat1+4;
      int regSampleRowid = regCol + nCol;
      int addrNext;
      int addrIsNull;
      u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;

      /* No STAT4 data is generated if the number of rows is zero */
      if( addrGotoEnd==0 ){
        sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER);
        addrGotoEnd = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
        VdbeCoverage(v);
      }

      if( doOnce ){
        int mxCol = nCol;
        Index *pX;

        /* Compute the maximum number of columns in any index */
        for(pX=pTab->pIndex; pX; pX=pX->pNext){
1328
1329
1330
1331
1332
1333
1334
1335

1336
1337
1338
1339
1340
1341
1342
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357
1358
1359
1360
1361







-
+







      sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
      sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
      sqlite3VdbeJumpHere(v, addrIsNull);
    }
#endif /* SQLITE_ENABLE_STAT4 */

    /* End of analysis */
    sqlite3VdbeJumpHere(v, addrRewind);
    if( addrGotoEnd ) sqlite3VdbeJumpHere(v, addrGotoEnd);
  }


  /* Create a single sqlite_stat1 entry containing NULL as the index
  ** name and the row count as the content.
  */
  if( pOnlyIdx==0 && needTableCnt ){
1552
1553
1554
1555
1556
1557
1558










1559
1560
1561
1562
1563
1564
1565
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594







+
+
+
+
+
+
+
+
+
+







      else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
        pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
      }
#endif
      while( z[0]!=0 && z[0]!=' ' ) z++;
      while( z[0]==' ' ) z++;
    }

    /* Set the bLowQual flag if the peak number of rows obtained
    ** from a full equality match is so large that a full table scan
    ** seems likely to be faster than using the index.
    */
    if( aLog[0] > 66              /* Index has more than 100 rows */
     && aLog[0] <= aLog[nOut-1]   /* And only a single value seen */
    ){
      pIndex->bLowQual = 1;
    }
  }
}

/*
** This callback is invoked once for each index when reading the
** sqlite_stat1 table.  
**
Changes to src/btree.c.
147
148
149
150
151
152
153






154
155

































156
157
158
159
160
161
162
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







+
+
+
+
+
+


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







  return SQLITE_CORRUPT_BKPT;
}
# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
#else
# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
#endif

/* Default value for SHARED_LOCK_TRACE macro if shared-cache is disabled
** or if the lock tracking is disabled.  This is always the value for
** release builds.
*/
#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE)  /*no-op*/

#ifndef SQLITE_OMIT_SHARED_CACHE

#if 0
/*  ^----  Change to 1 and recompile to enable shared-lock tracing
**         for debugging purposes.
**
** Print all shared-cache locks on a BtShared.  Debugging use only.
*/
static void sharedLockTrace(
  BtShared *pBt,
  const char *zMsg,
  int iRoot,
  int eLockType
){
  BtLock *pLock;
  if( iRoot>0 ){
    printf("%s-%p %u%s:", zMsg, pBt, iRoot, eLockType==READ_LOCK?"R":"W");
  }else{
    printf("%s-%p:", zMsg, pBt);
  }
  for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
    printf(" %p/%u%s", pLock->pBtree, pLock->iTable,
           pLock->eLock==READ_LOCK ? "R" : "W");
    while( pLock->pNext && pLock->pBtree==pLock->pNext->pBtree ){
      pLock = pLock->pNext;
      printf(",%u%s", pLock->iTable, pLock->eLock==READ_LOCK ? "R" : "W");
    }
  }
  printf("\n");
  fflush(stdout);
}
#undef SHARED_LOCK_TRACE
#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE)  sharedLockTrace(X,MSG,TAB,TYPE)
#endif /* Shared-lock tracing */

#ifdef SQLITE_DEBUG
/*
**** This function is only used as part of an assert() statement. ***
**
** Check to see if pBtree holds the required locks to read or write to the
** table with root page iRoot.   Return 1 if it does and 0 if not.
**
224
225
226
227
228
229
230


231
232
233
234
235
236
237
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278







+
+







        iTab = pIdx->pTable->tnum;
        bSeen = 1;
      }
    }
  }else{
    iTab = iRoot;
  }

  SHARED_LOCK_TRACE(pBtree->pBt,"hasLock",iRoot,eLockType);

  /* Search for the required lock. Either a write-lock on root-page iTab, a
  ** write-lock on the schema table, or (if the client is reading) a
  ** read-lock on iTab will suffice. Return 1 if any of these are found.  */
  for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){
    if( pLock->pBtree==pBtree
     && (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1))
358
359
360
361
362
363
364


365
366
367
368
369
370
371
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414







+
+







** is returned if a malloc attempt fails.
*/
static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
  BtShared *pBt = p->pBt;
  BtLock *pLock = 0;
  BtLock *pIter;

  SHARED_LOCK_TRACE(pBt,"setLock", iTable, eLock);

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
  assert( p->db!=0 );

  /* A connection with the read-uncommitted flag set will never try to
  ** obtain a read-lock using this function. The only read-lock obtained
  ** by a connection in read-uncommitted mode is on the sqlite_schema
425
426
427
428
429
430
431


432
433
434
435
436
437
438
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483







+
+







  BtShared *pBt = p->pBt;
  BtLock **ppIter = &pBt->pLock;

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( p->sharable || 0==*ppIter );
  assert( p->inTrans>0 );

  SHARED_LOCK_TRACE(pBt, "clearAllLocks", 0, 0);

  while( *ppIter ){
    BtLock *pLock = *ppIter;
    assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree );
    assert( pLock->pBtree->inTrans>=pLock->eLock );
    if( pLock->pBtree==p ){
      *ppIter = pLock->pNext;
      assert( pLock->iTable!=1 || pLock==&p->lock );
463
464
465
466
467
468
469



470
471
472
473
474
475
476
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524







+
+
+







}

/*
** This function changes all write-locks held by Btree p into read-locks.
*/
static void downgradeAllSharedCacheTableLocks(Btree *p){
  BtShared *pBt = p->pBt;

  SHARED_LOCK_TRACE(pBt, "downgradeLocks", 0, 0);

  if( pBt->pWriter==p ){
    BtLock *pLock;
    pBt->pWriter = 0;
    pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
    for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
      assert( pLock->eLock==READ_LOCK || pLock->pBtree==p );
      pLock->eLock = READ_LOCK;
5076
5077
5078
5079
5080
5081
5082
5083
5084





5085

5086
5087
5088
5089
5090
5091
5092
5124
5125
5126
5127
5128
5129
5130


5131
5132
5133
5134
5135

5136
5137
5138
5139
5140
5141
5142
5143







-
-
+
+
+
+
+
-
+







    ** means "not yet known" (the cache is lazily populated).
    */
    if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
      int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
      if( pCur->aOverflow==0
       || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
      ){
        Pgno *aNew = (Pgno*)sqlite3Realloc(
            pCur->aOverflow, nOvfl*2*sizeof(Pgno)
        Pgno *aNew;
        if( sqlite3FaultSim(413) ){
          aNew = 0;
        }else{
          aNew = (Pgno*)sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno));
        );
        }
        if( aNew==0 ){
          return SQLITE_NOMEM_BKPT;
        }else{
          pCur->aOverflow = aNew;
        }
      }
      memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5208
5209
5210
5211
5212
5213
5214

5215
5216
5217
5218
5219
5220
5221







-







        ){
          sqlite3_file *fd = sqlite3PagerFile(pBt->pPager);
          u8 aSave[4];
          u8 *aWrite = &pBuf[-4];
          assert( aWrite>=pBufStart );                         /* due to (6) */
          memcpy(aSave, aWrite, 4);
          rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
          if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
          nextPage = get4byte(aWrite);
          memcpy(aWrite, aSave, 4);
        }else
#endif

        {
          DbPage *pDbPage;
6128
6129
6130
6131
6132
6133
6134
6135
6136



6137
6138

6139
6140
6141
6142
6143
6144
6145
6178
6179
6180
6181
6182
6183
6184


6185
6186
6187


6188
6189
6190
6191
6192
6193
6194
6195







-
-
+
+
+
-
-
+







i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
  i64 n;
  u8 i;

  assert( cursorOwnsBtShared(pCur) );
  assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );

  /* Currently this interface is only called by the OP_IfSmaller
  ** opcode, and it that case the cursor will always be valid and
  /* Currently this interface is only called by the OP_IfSizeBetween
  ** opcode and the OP_Count opcode with P3=1.  In either case,
  ** the cursor will always be valid unless the btree is empty. */
  ** will always point to a leaf node. */
  if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
  if( pCur->eState!=CURSOR_VALID ) return 0;
  if( NEVER(pCur->pPage->leaf==0) ) return -1;

  n = pCur->pPage->nCell;
  for(i=0; i<pCur->iPage; i++){
    n *= pCur->apPage[i]->nCell;
  }
  return n;
6277
6278
6279
6280
6281
6282
6283

6284



6285
6286
6287
6288
6289
6290
6291
6327
6328
6329
6330
6331
6332
6333
6334

6335
6336
6337
6338
6339
6340
6341
6342
6343
6344







+
-
+
+
+







    if( CURSOR_SKIPNEXT==pCur->eState ){
      pCur->eState = CURSOR_VALID;
      if( pCur->skipNext<0 ) return SQLITE_OK;
    }
  }

  pPage = pCur->pPage;
  if( sqlite3FaultSim(412) ) pPage->isInit = 0;
  assert( pPage->isInit );
  if( !pPage->isInit ){
    return SQLITE_CORRUPT_BKPT;
  }
  if( !pPage->leaf ){
    int idx = pCur->ix;
    rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
    if( rc ) return rc;
    rc = moveToRightmost(pCur);
  }else{
    while( pCur->ix==0 ){
6950
6951
6952
6953
6954
6955
6956
6957




6958
6959
6960
6961
6962
6963
6964
7003
7004
7005
7006
7007
7008
7009

7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020







-
+
+
+
+







  pPayload = &pCell[nHeader];
  if( nPayload<=pPage->maxLocal ){
    /* This is the common case where everything fits on the btree page
    ** and no overflow pages are required. */
    n = nHeader + nPayload;
    testcase( n==3 );
    testcase( n==4 );
    if( n<4 ) n = 4;
    if( n<4 ){
      n = 4;
      pPayload[nPayload] = 0;
    }
    *pnSize = n;
    assert( nSrc<=nPayload );
    testcase( nSrc<nPayload );
    memcpy(pPayload, pSrc, nSrc);
    memset(pPayload+nSrc, 0, nPayload-nSrc);
    return SQLITE_OK;
  }
8256
8257
8258
8259
8260
8261
8262
8263

8264
8265
8266
8267
8268
8269
8270
8312
8313
8314
8315
8316
8317
8318

8319
8320
8321
8322
8323
8324
8325
8326







-
+







    u8 *piEnd;
    VVA_ONLY( int nCellAtStart = b.nCell; )

    /* Verify that all sibling pages are of the same "type" (table-leaf,
    ** table-interior, index-leaf, or index-interior).
    */
    if( pOld->aData[0]!=apOld[0]->aData[0] ){
      rc = SQLITE_CORRUPT_BKPT;
      rc = SQLITE_CORRUPT_PAGE(pOld);
      goto balance_cleanup;
    }

    /* Load b.apCell[] with pointers to all cells in pOld.  If pOld
    ** contains overflow cells, include them in the b.apCell[] array
    ** in the correct spot.
    **
8280
8281
8282
8283
8284
8285
8286
8287

8288
8289
8290
8291
8292
8293
8294
8336
8337
8338
8339
8340
8341
8342

8343
8344
8345
8346
8347
8348
8349
8350







-
+







    ** offset section of the btree page will be overwritten and we will no
    ** long be able to find the cells if a pointer to each cell is not saved
    ** first.
    */
    memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
    if( pOld->nOverflow>0 ){
      if( NEVER(limit<pOld->aiOvfl[0]) ){
        rc = SQLITE_CORRUPT_BKPT;
        rc = SQLITE_CORRUPT_PAGE(pOld);
        goto balance_cleanup;
      }
      limit = pOld->aiOvfl[0];
      for(j=0; j<limit; j++){
        b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
        piCell += 2;
        b.nCell++;
8923
8924
8925
8926
8927
8928
8929
8930

8931
8932
8933
8934
8935
8936
8937
8979
8980
8981
8982
8983
8984
8985

8986
8987
8988
8989
8990
8991
8992
8993







-
+







static int anotherValidCursor(BtCursor *pCur){
  BtCursor *pOther;
  for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){
    if( pOther!=pCur
     && pOther->eState==CURSOR_VALID
     && pOther->pPage==pCur->pPage
    ){
      return SQLITE_CORRUPT_BKPT;
      return SQLITE_CORRUPT_PAGE(pCur->pPage);
    }
  }
  return SQLITE_OK;
}

/*
** The page that pCur currently points to has just been modified in
8983
8984
8985
8986
8987
8988
8989
8990

8991
8992
8993
8994
8995
8996
8997
9039
9040
9041
9042
9043
9044
9045

9046
9047
9048
9049
9050
9051
9052
9053







-
+







      }else{
        break;
      }
    }else if( sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){
      /* The page being written is not a root page, and there is currently
      ** more than one reference to it. This only happens if the page is one
      ** of its own ancestor pages. Corruption. */
      rc = SQLITE_CORRUPT_BKPT;
      rc = SQLITE_CORRUPT_PAGE(pPage);
    }else{
      MemPage * const pParent = pCur->apPage[iPage-1];
      int const iIdx = pCur->aiIdx[iPage-1];

      rc = sqlite3PagerWrite(pParent->pDbPage);
      if( rc==SQLITE_OK && pParent->nFree<0 ){
        rc = btreeComputeFreeSpace(pParent);
9147
9148
9149
9150
9151
9152
9153
9154

9155
9156
9157
9158
9159
9160
9161
9203
9204
9205
9206
9207
9208
9209

9210
9211
9212
9213
9214
9215
9216
9217







-
+







  ovflPgno = get4byte(pCur->info.pPayload + iOffset);
  pBt = pPage->pBt;
  ovflPageSize = pBt->usableSize - 4;
  do{
    rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
    if( rc ) return rc;
    if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){
      rc = SQLITE_CORRUPT_BKPT;
      rc = SQLITE_CORRUPT_PAGE(pPage);
    }else{
      if( iOffset+ovflPageSize<(u32)nTotal ){
        ovflPgno = get4byte(pPage->aData);
      }else{
        ovflPageSize = nTotal - iOffset;
      }
      rc = btreeOverwriteContent(pPage, pPage->aData+4, pX,
9175
9176
9177
9178
9179
9180
9181
9182

9183
9184
9185
9186
9187
9188
9189
9231
9232
9233
9234
9235
9236
9237

9238
9239
9240
9241
9242
9243
9244
9245







-
+







static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
  int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
  MemPage *pPage = pCur->pPage;       /* Page being written */

  if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
   || pCur->info.pPayload < pPage->aData + pPage->cellOffset
  ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PAGE(pPage);
  }
  if( pCur->info.nLocal==nTotal ){
    /* The entire cell is local */
    return btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
                                 0, pCur->info.nLocal);
  }else{
    /* The cell contains overflow content */
9256
9257
9258
9259
9260
9261
9262
9263

9264
9265
9266
9267
9268
9269
9270
9312
9313
9314
9315
9316
9317
9318

9319
9320
9321
9322
9323
9324
9325
9326







-
+







    if( rc ) return rc;
    if( loc && pCur->iPage<0 ){
      /* This can only happen if the schema is corrupt such that there is more
      ** than one table or index with the same root page as used by the cursor.
      ** Which can only happen if the SQLITE_NoSchemaError flag was set when
      ** the schema was loaded. This cannot be asserted though, as a user might
      ** set the flag, load the schema, and then unset the flag.  */
      return SQLITE_CORRUPT_BKPT;
      return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot);
    }
  }

  /* Ensure that the cursor is not in the CURSOR_FAULT state and that it
  ** points to a valid cell.
  */
  if( pCur->eState>=CURSOR_REQUIRESEEK ){
9379
9380
9381
9382
9383
9384
9385
9386

9387
9388
9389
9390
9391
9392
9393
9394
9395
9396
9397
9398
9399
9400
9401
9402
9403




9404
9405
9406
9407
9408
9409
9410
9435
9436
9437
9438
9439
9440
9441

9442
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
9457
9458

9459
9460
9461
9462
9463
9464
9465
9466
9467
9468
9469







-
+
















-
+
+
+
+








  pPage = pCur->pPage;
  assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
  assert( pPage->leaf || !pPage->intKey );
  if( pPage->nFree<0 ){
    if( NEVER(pCur->eState>CURSOR_INVALID) ){
     /* ^^^^^--- due to the moveToRoot() call above */
      rc = SQLITE_CORRUPT_BKPT;
      rc = SQLITE_CORRUPT_PAGE(pPage);
    }else{
      rc = btreeComputeFreeSpace(pPage);
    }
    if( rc ) return rc;
  }

  TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
          pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
          loc==0 ? "overwrite" : "new entry"));
  assert( pPage->isInit || CORRUPT_DB );
  newCell = p->pBt->pTmpSpace;
  assert( newCell!=0 );
  assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
  if( flags & BTREE_PREFORMAT ){
    rc = SQLITE_OK;
    szNew = p->pBt->nPreformatSize;
    if( szNew<4 ) szNew = 4;
    if( szNew<4 ){
      szNew = 4;
      newCell[3] = 0;
    }
    if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
      CellInfo info;
      pPage->xParseCell(pPage, newCell, &info);
      if( info.nPayload!=info.nLocal ){
        Pgno ovfl = get4byte(&newCell[szNew-4]);
        ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
        if( NEVER(rc) ) goto end_insert;
9418
9419
9420
9421
9422
9423
9424
9425

9426
9427
9428
9429
9430
9431
9432
9477
9478
9479
9480
9481
9482
9483

9484
9485
9486
9487
9488
9489
9490
9491







-
+







  assert( szNew <= MX_CELL_SIZE(p->pBt) );
  idx = pCur->ix;
  pCur->info.nSize = 0;
  if( loc==0 ){
    CellInfo info;
    assert( idx>=0 );
    if( idx>=pPage->nCell ){
      return SQLITE_CORRUPT_BKPT;
      return SQLITE_CORRUPT_PAGE(pPage);
    }
    rc = sqlite3PagerWrite(pPage->pDbPage);
    if( rc ){
      goto end_insert;
    }
    oldCell = findCell(pPage, idx);
    if( !pPage->leaf ){
9445
9446
9447
9448
9449
9450
9451
9452

9453
9454
9455

9456
9457
9458
9459
9460
9461
9462
9504
9505
9506
9507
9508
9509
9510

9511
9512
9513

9514
9515
9516
9517
9518
9519
9520
9521







-
+


-
+







      ** calling dropCell() and insertCell().
      **
      ** This optimization cannot be used on an autovacuum database if the
      ** new entry uses overflow pages, as the insertCell() call below is
      ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry.  */
      assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
      if( oldCell < pPage->aData+pPage->hdrOffset+10 ){
        return SQLITE_CORRUPT_BKPT;
        return SQLITE_CORRUPT_PAGE(pPage);
      }
      if( oldCell+szNew > pPage->aDataEnd ){
        return SQLITE_CORRUPT_BKPT;
        return SQLITE_CORRUPT_PAGE(pPage);
      }
      memcpy(oldCell, newCell, szNew);
      return SQLITE_OK;
    }
    dropCell(pPage, idx, info.nSize, &rc);
    if( rc ) goto end_insert;
  }else if( loc<0 && pPage->nCell>0 ){
9550
9551
9552
9553
9554
9555
9556
9557

9558
9559
9560
9561
9562
9563
9564
9609
9610
9611
9612
9613
9614
9615

9616
9617
9618
9619
9620
9621
9622
9623







-
+







  }else{
    aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
  }
  if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
  nIn = pSrc->info.nLocal;
  aIn = pSrc->info.pPayload;
  if( aIn+nIn>pSrc->pPage->aDataEnd ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PAGE(pSrc->pPage);
  }
  nRem = pSrc->info.nPayload;
  if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
    memcpy(aOut, aIn, nIn);
    pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
    return SQLITE_OK;
  }else{
9575
9576
9577
9578
9579
9580
9581
9582

9583
9584
9585
9586
9587
9588
9589
9634
9635
9636
9637
9638
9639
9640

9641
9642
9643
9644
9645
9646
9647
9648







-
+







    if( nOut<pSrc->info.nPayload ){
      pPgnoOut = &aOut[nOut];
      pBt->nPreformatSize += 4;
    }
 
    if( nRem>nIn ){
      if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
        return SQLITE_CORRUPT_BKPT;
        return SQLITE_CORRUPT_PAGE(pSrc->pPage);
      }
      ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
    }
 
    do {
      nRem -= nOut;
      do{
9671
9672
9673
9674
9675
9676
9677
9678

9679
9680
9681
9682
9683
9684
9685
9686
9687

9688
9689
9690
9691

9692
9693
9694

9695
9696
9697
9698
9699
9700
9701
9730
9731
9732
9733
9734
9735
9736

9737
9738
9739
9740
9741
9742
9743
9744
9745

9746
9747
9748
9749

9750
9751
9752

9753
9754
9755
9756
9757
9758
9759
9760







-
+








-
+



-
+


-
+







  assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
  if( pCur->eState!=CURSOR_VALID ){
    if( pCur->eState>=CURSOR_REQUIRESEEK ){
      rc = btreeRestoreCursorPosition(pCur);
      assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
      if( rc || pCur->eState!=CURSOR_VALID ) return rc;
    }else{
      return SQLITE_CORRUPT_BKPT;
      return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot);
    }
  }
  assert( pCur->eState==CURSOR_VALID );

  iCellDepth = pCur->iPage;
  iCellIdx = pCur->ix;
  pPage = pCur->pPage;
  if( pPage->nCell<=iCellIdx ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PAGE(pPage);
  }
  pCell = findCell(pPage, iCellIdx);
  if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PAGE(pPage);
  }
  if( pCell<&pPage->aCellIdx[pPage->nCell] ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PAGE(pPage);
  }

  /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
  ** be preserved following this delete operation. If the current delete
  ** will cause a b-tree rebalance, then this is done by saving the cursor
  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
  ** returning.
9778
9779
9780
9781
9782
9783
9784
9785

9786
9787
9788
9789
9790
9791
9792
9837
9838
9839
9840
9841
9842
9843

9844
9845
9846
9847
9848
9849
9850
9851







-
+







    }
    if( iCellDepth<pCur->iPage-1 ){
      n = pCur->apPage[iCellDepth+1]->pgno;
    }else{
      n = pCur->pPage->pgno;
    }
    pCell = findCell(pLeaf, pLeaf->nCell-1);
    if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
    if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf);
    nCell = pLeaf->xCellSize(pLeaf, pCell);
    assert( MX_CELL_SIZE(pBt) >= nCell );
    pTmp = pBt->pTmpSpace;
    assert( pTmp!=0 );
    rc = sqlite3PagerWrite(pLeaf->pDbPage);
    if( rc==SQLITE_OK ){
      rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
9894
9895
9896
9897
9898
9899
9900
9901

9902
9903
9904
9905
9906
9907
9908
9953
9954
9955
9956
9957
9958
9959

9960
9961
9962
9963
9964
9965
9966
9967







-
+








    /* Read the value of meta[3] from the database to determine where the
    ** root page of the new table should go. meta[3] is the largest root-page
    ** created so far, so the new root-page is (meta[3]+1).
    */
    sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
    if( pgnoRoot>btreePagecount(pBt) ){
      return SQLITE_CORRUPT_BKPT;
      return SQLITE_CORRUPT_PGNO(pgnoRoot);
    }
    pgnoRoot++;

    /* The new root-page may not be allocated on a pointer-map page, or the
    ** PENDING_BYTE page.
    */
    while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
9942
9943
9944
9945
9946
9947
9948
9949

9950
9951
9952
9953
9954
9955
9956
10001
10002
10003
10004
10005
10006
10007

10008
10009
10010
10011
10012
10013
10014
10015







-
+







      /* Move the page currently at pgnoRoot to pgnoMove. */
      rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage);
      if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){
        rc = SQLITE_CORRUPT_BKPT;
        rc = SQLITE_CORRUPT_PGNO(pgnoRoot);
      }
      if( rc!=SQLITE_OK ){
        releasePage(pRoot);
        return rc;
      }
      assert( eType!=PTRMAP_ROOTPAGE );
      assert( eType!=PTRMAP_FREEPAGE );
10032
10033
10034
10035
10036
10037
10038
10039

10040
10041
10042
10043
10044
10045
10046

10047
10048
10049
10050
10051
10052
10053
10091
10092
10093
10094
10095
10096
10097

10098
10099
10100
10101
10102
10103
10104

10105
10106
10107
10108
10109
10110
10111
10112







-
+






-
+







  unsigned char *pCell;
  int i;
  int hdr;
  CellInfo info;

  assert( sqlite3_mutex_held(pBt->mutex) );
  if( pgno>btreePagecount(pBt) ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PGNO(pgno);
  }
  rc = getAndInitPage(pBt, pgno, &pPage, 0);
  if( rc ) return rc;
  if( (pBt->openFlags & BTREE_SINGLE)==0
   && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
  ){
    rc = SQLITE_CORRUPT_BKPT;
    rc = SQLITE_CORRUPT_PAGE(pPage);
    goto cleardatabasepage_out;
  }
  hdr = pPage->hdrOffset;
  for(i=0; i<pPage->nCell; i++){
    pCell = findCell(pPage, i);
    if( !pPage->leaf ){
      rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
10143
10144
10145
10146
10147
10148
10149
10150

10151
10152
10153
10154
10155
10156
10157
10202
10203
10204
10205
10206
10207
10208

10209
10210
10211
10212
10213
10214
10215
10216







-
+







  MemPage *pPage = 0;
  BtShared *pBt = p->pBt;

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( p->inTrans==TRANS_WRITE );
  assert( iTable>=2 );
  if( iTable>btreePagecount(pBt) ){
    return SQLITE_CORRUPT_BKPT;
    return SQLITE_CORRUPT_PGNO(iTable);
  }

  rc = sqlite3BtreeClearTable(p, iTable, 0);
  if( rc ) return rc;
  rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
  if( NEVER(rc) ){
    releasePage(pPage);
10737
10738
10739
10740
10741
10742
10743



10744
10745
10746
10747
10748
10749
10750
10796
10797
10798
10799
10800
10801
10802
10803
10804
10805
10806
10807
10808
10809
10810
10811
10812







+
+
+







  contentOffset = get2byteNotZero(&data[hdr+5]);
  assert( contentOffset<=usableSize );  /* Enforced by btreeInitPage() */

  /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
  ** number of cells on the page. */
  nCell = get2byte(&data[hdr+3]);
  assert( pPage->nCell==nCell );
  if( pPage->leaf || pPage->intKey==0 ){
    pCheck->nRow += nCell;
  }

  /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
  ** immediately follows the b-tree page header. */
  cellStart = hdr + 12 - 4*pPage->leaf;
  assert( pPage->aCellIdx==&data[cellStart] );
  pCellIdx = &data[cellStart + 2*(nCell-1)];

10848
10849
10850
10851
10852
10853
10854

10855
10856
10857
10858
10859
10860
10861
10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922
10923
10924







+







      for(i=nCell-1; i>=0; i--){
        u32 size;
        pc = get2byteAligned(&data[cellStart+i*2]);
        size = pPage->xCellSize(pPage, &data[pc]);
        btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
      }
    }
    assert( heap!=0 );
    /* Add the freeblocks to the min-heap
    **
    ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
    ** is the offset of the first freeblock, or zero if there are no
    ** freeblocks on the page.
    */
    i = get2byte(&data[hdr+1]);
10947
10948
10949
10950
10951
10952
10953

10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965
10966

10967

10968
10969
10970
10971
10972
10973
10974
11010
11011
11012
11013
11014
11015
11016
11017
11018
11019
11020
11021
11022
11023
11024
11025
11026
11027
11028
11029
11030
11031
11032
11033
11034
11035
11036
11037
11038
11039
11040







+













+

+







** the unverified btrees.  Except, if aRoot[1] is 1, then the freelist
** checks are still performed.
*/
int sqlite3BtreeIntegrityCheck(
  sqlite3 *db,  /* Database connection that is running the check */
  Btree *p,     /* The btree to be checked */
  Pgno *aRoot,  /* An array of root pages numbers for individual trees */
  Mem *aCnt,    /* Memory cells to write counts for each tree to */
  int nRoot,    /* Number of entries in aRoot[] */
  int mxErr,    /* Stop reporting errors after this many */
  int *pnErr,   /* OUT: Write number of errors seen to this variable */
  char **pzOut  /* OUT: Write the error message string here */
){
  Pgno i;
  IntegrityCk sCheck;
  BtShared *pBt = p->pBt;
  u64 savedDbFlags = pBt->db->flags;
  char zErr[100];
  int bPartial = 0;            /* True if not checking all btrees */
  int bCkFreelist = 1;         /* True to scan the freelist */
  VVA_ONLY( int nRef );

  assert( nRoot>0 );
  assert( aCnt!=0 );

  /* aRoot[0]==0 means this is a partial check */
  if( aRoot[0]==0 ){
    assert( nRoot>1 );
    bPartial = 1;
    if( aRoot[1]!=1 ) bCkFreelist = 0;
  }
11033
11034
11035
11036
11037
11038
11039


11040

11041
11042
11043
11044
11045



11046
11047
11048




11049
11050
11051
11052
11053
11054
11055
11099
11100
11101
11102
11103
11104
11105
11106
11107

11108

11109



11110
11111
11112
11113


11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124







+
+
-
+
-

-
-
-
+
+
+

-
-
+
+
+
+







      );
    }
  }
#endif
  testcase( pBt->db->flags & SQLITE_CellSizeCk );
  pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
  for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
    sCheck.nRow = 0;
    if( aRoot[i] ){
    i64 notUsed;
      i64 notUsed;
    if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
    if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
      checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
    }
      if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
        checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
      }
#endif
    sCheck.v0 = aRoot[i];
    checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
      sCheck.v0 = aRoot[i];
      checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
    }
    sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow);
  }
  pBt->db->flags = savedDbFlags;

  /* Make sure every page in the file is referenced
  */
  if( !bPartial ){
    for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){
Changes to src/btree.h.
327
328
329
330
331
332
333

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







+







u32 sqlite3BtreePayloadSize(BtCursor*);
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);

int sqlite3BtreeIntegrityCheck(
  sqlite3 *db,  /* Database connection that is running the check */
  Btree *p,     /* The btree to be checked */
  Pgno *aRoot,  /* An array of root pages numbers for individual trees */
  sqlite3_value *aCnt,  /* OUT: entry counts for each btree in aRoot[] */
  int nRoot,    /* Number of entries in aRoot[] */
  int mxErr,    /* Stop reporting errors after this many */
  int *pnErr,   /* OUT: Write number of errors seen to this variable */
  char **pzOut  /* OUT: Write the error message string here */
);
struct Pager *sqlite3BtreePager(Btree*);
i64 sqlite3BtreeRowCountEst(BtCursor*);
Changes to src/btreeInt.h.
60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74







-
+







**     18       1     File format write version
**     19       1     File format read version
**     20       1     Bytes of unused space at the end of each page
**     21       1     Max embedded payload fraction (must be 64)
**     22       1     Min embedded payload fraction (must be 32)
**     23       1     Min leaf payload fraction (must be 32)
**     24       4     File change counter
**     28       4     Reserved for future use
**     28       4     The size of the database in pages
**     32       4     First freelist page
**     36       4     Number of freelist pages in the file
**     40      60     15 4-byte meta values passed to higher layers
**
**     40       4     Schema cookie
**     44       4     File format of schema layer
**     48       4     Size of page cache
703
704
705
706
707
708
709

710
711
712
713
714
715
716
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717







+







  const char *zPfx; /* Error message prefix */
  Pgno v0;          /* Value for first %u substitution in zPfx (root page) */
  Pgno v1;          /* Value for second %u substitution in zPfx (current pg) */
  int v2;           /* Value for third %d substitution in zPfx */
  StrAccum errMsg;  /* Accumulate the error message text here */
  u32 *heap;        /* Min-heap used for analyzing cell coverage */
  sqlite3 *db;      /* Database connection running the check */
  i64 nRow;         /* Number of rows visited in current tree */
};

/*
** Routines to read or write a two- and four-byte big-endian integer values.
*/
#define get2byte(x)   ((x)[0]<<8 | (x)[1])
#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
Changes to src/build.c.
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
185
186
187
188
189
190
191

192
193
194
195
196
197
198
199







-
+







        sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1);
        VdbeCoverage(v);
        sqlite3VdbeJumpHere(v, addrRewind);
      }
    }
    sqlite3VdbeAddOp0(v, OP_Halt);

#if SQLITE_USER_AUTHENTICATION
#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE)
    if( pParse->nTableLock>0 && db->init.busy==0 ){
      sqlite3UserAuthInit(db);
      if( db->auth.authLevel<UAUTH_User ){
        sqlite3ErrorMsg(pParse, "user not authenticated");
        pParse->rc = SQLITE_AUTH_USER;
        return;
      }
716
717
718
719
720
721
722
723

724
725
726
727
728
729
730
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730







-
+







/*
** Return the expression associated with a column.  The expression might be
** the DEFAULT clause or the AS clause of a generated column.
** Return NULL if the column has no associated expression.
*/
Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){
  if( pCol->iDflt==0 ) return 0;
  if( NEVER(!IsOrdinaryTable(pTab)) ) return 0;
  if( !IsOrdinaryTable(pTab) ) return 0;
  if( NEVER(pTab->u.tab.pDfltList==0) ) return 0;
  if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0;
  return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
}

/*
** Set the collating sequence name for a column.
868
869
870
871
872
873
874



875
876
877
878
879
880
881
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884







+
+
+







}
void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
  /* Do not delete the table until the reference count reaches zero. */
  assert( db!=0 );
  if( !pTable ) return;
  if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
  deleteTable(db, pTable);
}
void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){
  sqlite3DeleteTable(db, (Table*)pTable);
}


/*
** Unlink the given table from the hash tables and the delete the
** table structure with all its indices and foreign keys.
*/
1406
1407
1408
1409
1410
1411
1412
1413


1414
1415
1416
1417
1418
1419
1420
1409
1410
1411
1412
1413
1414
1415

1416
1417
1418
1419
1420
1421
1422
1423
1424







-
+
+







  }
}
#endif

/*
** Clean up the data structures associated with the RETURNING clause.
*/
static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){
static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){
  Returning *pRet = (Returning*)pArg;
  Hash *pHash;
  pHash = &(db->aDb[1].pSchema->trigHash);
  sqlite3HashInsert(pHash, pRet->zName, 0);
  sqlite3ExprListDelete(db, pRet->pReturnEL);
  sqlite3DbFree(db, pRet);
}

1448
1449
1450
1451
1452
1453
1454
1455

1456
1457
1458
1459
1460
1461
1462
1463
1452
1453
1454
1455
1456
1457
1458

1459

1460
1461
1462
1463
1464
1465
1466







-
+
-







  if( pRet==0 ){
    sqlite3ExprListDelete(db, pList);
    return;
  }
  pParse->u1.pReturning = pRet;
  pRet->pParse = pParse;
  pRet->pReturnEL = pList;
  sqlite3ParserAddCleanup(pParse,
  sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet);
     (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
  testcase( pParse->earlyCleanup );
  if( db->mallocFailed ) return;
  sqlite3_snprintf(sizeof(pRet->zName), pRet->zName,
                   "sqlite_returning_%p", pParse);
  pRet->retTrig.zName = pRet->zName;
  pRet->retTrig.op = TK_RETURNING;
  pRet->retTrig.tr_tm = TRIGGER_AFTER;
1648
1649
1650
1651
1652
1653
1654

1655

1656
1657
1658
1659
1660
1661
1662
1651
1652
1653
1654
1655
1656
1657
1658

1659
1660
1661
1662
1663
1664
1665
1666







+
-
+







char sqlite3AffinityType(const char *zIn, Column *pCol){
  u32 h = 0;
  char aff = SQLITE_AFF_NUMERIC;
  const char *zChar = 0;

  assert( zIn!=0 );
  while( zIn[0] ){
    u8 x = *(u8*)zIn;
    h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
    h = (h<<8) + sqlite3UpperToLower[x];
    zIn++;
    if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){             /* CHAR */
      aff = SQLITE_AFF_TEXT;
      zChar = zIn;
    }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){       /* CLOB */
      aff = SQLITE_AFF_TEXT;
    }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){       /* TEXT */
2915
2916
2917
2918
2919
2920
2921
2922

2923
2924
2925
2926

2927
2928
2929
2930
2931
2932
2933
2919
2920
2921
2922
2923
2924
2925

2926
2927
2928
2929

2930
2931
2932
2933
2934
2935
2936
2937







-
+



-
+







    /* Reparse everything to update our internal data structures */
    sqlite3VdbeAddParseSchemaOp(v, iDb,
           sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);

    /* Test for cycles in generated columns and illegal expressions
    ** in CHECK constraints and in DEFAULT clauses. */
    if( p->tabFlags & TF_HasGenerated ){
      sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
      sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
             sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
                   db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
    }
    sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
    sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
           sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)",
                 db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
  }

  /* Add the table to the in-memory representation of the database.
  */
  if( db->init.busy ){
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007






3008
3009
3010
3011
3012
3013
3014
3002
3003
3004
3005
3006
3007
3008



3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021







-
-
-
+
+
+
+
+
+







  p = pParse->pNewTable;
  if( p==0 || pParse->nErr ) goto create_view_fail;

  /* Legacy versions of SQLite allowed the use of the magic "rowid" column
  ** on a view, even though views do not have rowids.  The following flag
  ** setting fixes this problem.  But the fix can be disabled by compiling
  ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that
  ** depend upon the old buggy behavior. */
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
  p->tabFlags |= TF_NoVisibleRowid;
  ** depend upon the old buggy behavior.  The ability can also be toggled
  ** using SQLITE_TESTCTRL_ROWID_IN_VIEW */
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
  p->tabFlags |= sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */
#else
  p->tabFlags |= TF_NoVisibleRowid;             /* Never allow rowid in view */
#endif

  sqlite3TwoPartName(pParse, pName1, pName2, &pName);
  iDb = sqlite3SchemaToIndex(db, p->pSchema);
  sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
  if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;

5513
5514
5515
5516
5517
5518
5519
5520

5521
5522
5523
5524
5525
5526
5527
5528
5529

5530
5531
5532
5533
5534
5535
5536
5520
5521
5522
5523
5524
5525
5526

5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544







-
+









+







    }
    sqlite3DbFree(db, zColl);
  }
  iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
  if( iDb<0 ) return;
  z = sqlite3NameFromToken(db, pObjName);
  if( z==0 ) return;
  zDb = db->aDb[iDb].zDbSName;
  zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
  pTab = sqlite3FindTable(db, z, zDb);
  if( pTab ){
    reindexTable(pParse, pTab, 0);
    sqlite3DbFree(db, z);
    return;
  }
  pIndex = sqlite3FindIndex(db, z, zDb);
  sqlite3DbFree(db, z);
  if( pIndex ){
    iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
    sqlite3BeginWriteOperation(pParse, 0, iDb);
    sqlite3RefillIndex(pParse, pIndex, -1);
    return;
  }
  sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
}
#endif
5687
5688
5689
5690
5691
5692
5693
5694



5695
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706








+
+
+

  if( pWith ){
    int i;
    for(i=0; i<pWith->nCte; i++){
      cteClear(db, &pWith->a[i]);
    }
    sqlite3DbFree(db, pWith);
  }
}
void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){
  sqlite3WithDelete(db, (With*)pWith);
}
#endif /* !defined(SQLITE_OMIT_CTE) */
Changes to src/date.c.
67
68
69
70
71
72
73
74
75
76
77
78
79
80






81
82
83
84
85
86
87
67
68
69
70
71
72
73

74
75




76
77
78
79
80
81
82
83
84
85
86
87
88







-


-
-
-
-
+
+
+
+
+
+







struct DateTime {
  sqlite3_int64 iJD;  /* The julian day number times 86400000 */
  int Y, M, D;        /* Year, month, and day */
  int h, m;           /* Hour and minutes */
  int tz;             /* Timezone offset in minutes */
  double s;           /* Seconds */
  char validJD;       /* True (1) if iJD is valid */
  char rawS;          /* Raw numeric value stored in s */
  char validYMD;      /* True (1) if Y,M,D are valid */
  char validHMS;      /* True (1) if h,m,s are valid */
  char validTZ;       /* True (1) if tz is valid */
  char tzSet;         /* Timezone was set explicitly */
  char isError;       /* An overflow has occurred */
  char useSubsec;     /* Display subsecond precision */
  char nFloor;            /* Days to implement "floor" */
  unsigned rawS      : 1; /* Raw numeric value stored in s */
  unsigned isError   : 1; /* An overflow has occurred */
  unsigned useSubsec : 1; /* Display subsecond precision */
  unsigned isUtc     : 1; /* Time is known to be UTC */
  unsigned isLocal   : 1; /* Time is known to be localtime */
};


/*
** Convert zDate into one or more integers according to the conversion
** specifier zFormat.
**
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
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







+
+












-







  c = *zDate;
  if( c=='-' ){
    sgn = -1;
  }else if( c=='+' ){
    sgn = +1;
  }else if( c=='Z' || c=='z' ){
    zDate++;
    p->isLocal = 0;
    p->isUtc = 1;
    goto zulu_time;
  }else{
    return c!=0;
  }
  zDate++;
  if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
    return 1;
  }
  zDate += 5;
  p->tz = sgn*(nMn + nHr*60);
zulu_time:
  while( sqlite3Isspace(*zDate) ){ zDate++; }
  p->tzSet = 1;
  return *zDate!=0;
}

/*
** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
** The HH, MM, and SS must each be exactly 2 digits.  The
** fractional seconds FFFF can be one or more digits.
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
229
230
231
232
233
234
235

236
237
238
239
240
241
242







-







  p->validJD = 0;
  p->rawS = 0;
  p->validHMS = 1;
  p->h = h;
  p->m = m;
  p->s = s + ms;
  if( parseTimezone(zDate, p) ) return 1;
  p->validTZ = (p->tz!=0)?1:0;
  return 0;
}

/*
** Put the DateTime object into its error state.
*/
static void datetimeError(DateTime *p){
274
275
276
277
278
279
280
281

282
283
284
285



286
287
288























289
290
291
292
293
294
295
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







-
+



-
+
+
+



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







  B = 2 - A + (A/4);
  X1 = 36525*(Y+4716)/100;
  X2 = 306001*(M+1)/10000;
  p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
  p->validJD = 1;
  if( p->validHMS ){
    p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
    if( p->validTZ ){
    if( p->tz ){
      p->iJD -= p->tz*60000;
      p->validYMD = 0;
      p->validHMS = 0;
      p->validTZ = 0;
      p->tz = 0;
      p->isUtc = 1;
      p->isLocal = 0;
    }
  }
}

/*
** Given the YYYY-MM-DD information current in p, determine if there
** is day-of-month overflow and set nFloor to the number of days that
** would need to be subtracted from the date in order to bring the
** date back to the end of the month.
*/
static void computeFloor(DateTime *p){
  assert( p->validYMD || p->isError );
  assert( p->D>=0 && p->D<=31 );
  assert( p->M>=0 && p->M<=12 );
  if( p->D<=28 ){
    p->nFloor = 0;
  }else if( (1<<p->M) & 0x15aa ){
    p->nFloor = 0;
  }else if( p->M!=2 ){
    p->nFloor = (p->D==31);
  }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){
    p->nFloor = p->D - 28;
  }else{
    p->nFloor = p->D - 29;
  }
}

/*
** Parse dates of the form
**
**     YYYY-MM-DD HH:MM:SS.FFF
**     YYYY-MM-DD HH:MM:SS
**     YYYY-MM-DD HH:MM
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
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







+
-
+





+
+
+









+
+
+







    return 1;
  }
  p->validJD = 0;
  p->validYMD = 1;
  p->Y = neg ? -Y : Y;
  p->M = M;
  p->D = D;
  computeFloor(p);
  if( p->validTZ ){
  if( p->tz ){
    computeJD(p);
  }
  return 0;
}


static void clearYMD_HMS_TZ(DateTime *p);  /* Forward declaration */

/*
** Set the time to the current time reported by the VFS.
**
** Return the number of errors.
*/
static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
  p->iJD = sqlite3StmtCurrentTime(context);
  if( p->iJD>0 ){
    p->validJD = 1;
    p->isUtc = 1;
    p->isLocal = 0;
    clearYMD_HMS_TZ(p);
    return 0;
  }else{
    return 1;
  }
}

/*
474
475
476
477
478
479
480
481

482
483
484
485
486
487
488
507
508
509
510
511
512
513

514
515
516
517
518
519
520
521







-
+








/*
** Clear the YMD and HMS and the TZ
*/
static void clearYMD_HMS_TZ(DateTime *p){
  p->validYMD = 0;
  p->validHMS = 0;
  p->validTZ = 0;
  p->tz = 0;
}

#ifndef SQLITE_OMIT_LOCALTIME
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to 
** localtime_r() available under most POSIX platforms, except that the 
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
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







-
+



















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







  p->h = sLocal.tm_hour;
  p->m = sLocal.tm_min;
  p->s = sLocal.tm_sec + (p->iJD%1000)*0.001;
  p->validYMD = 1;
  p->validHMS = 1;
  p->validJD = 0;
  p->rawS = 0;
  p->validTZ = 0;
  p->tz = 0;
  p->isError = 0;
  return SQLITE_OK;
}
#endif /* SQLITE_OMIT_LOCALTIME */

/*
** The following table defines various date transformations of the form
**
**            'NNN days'
**
** Where NNN is an arbitrary floating-point number and "days" can be one
** of several units of time.
*/
static const struct {
  u8 nName;           /* Length of the name */
  char zName[7];      /* Name of the transformation */
  float rLimit;       /* Maximum NNN value for this transform */
  float rXform;       /* Constant used for this transform */
} aXformType[] = {
  { 6, "second", 4.6427e+14,       1.0  },
  { 6, "minute", 7.7379e+12,      60.0  },
  { 4, "hour",   1.2897e+11,    3600.0  },
  { 3, "day",    5373485.0,    86400.0  },
  { 5, "month",  176546.0,   2592000.0  },
  { 4, "year",   14713.0,   31536000.0  },
  /* 0 */ { 6, "second",   4.6427e+14,         1.0  },
  /* 1 */ { 6, "minute",   7.7379e+12,        60.0  },
  /* 2 */ { 4, "hour",     1.2897e+11,      3600.0  },
  /* 3 */ { 3, "day",      5373485.0,      86400.0  },
  /* 4 */ { 5, "month",    176546.0,  30.0*86400.0  },
  /* 5 */ { 4, "year",     14713.0,  365.0*86400.0  },
};

/*
** If the DateTime p is raw number, try to figure out if it is
** a julian day number of a unix timestamp.  Set the p value
** appropriately.
*/
663
664
665
666
667
668
669



670
671
672
673
674
675

676
677


678
679
680
681
682
683
684
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







+
+
+






+


+
+







**
**     NNN days
**     NNN hours
**     NNN minutes
**     NNN.NNNN seconds
**     NNN months
**     NNN years
**     +/-YYYY-MM-DD HH:MM:SS.SSS
**     ceiling
**     floor
**     start of month
**     start of year
**     start of week
**     start of day
**     weekday N
**     unixepoch
**     auto
**     localtime
**     utc
**     subsec
**     subsecond
**
** Return 0 on success and 1 if there is any kind of error. If the error
** is in a system call (i.e. localtime()), then an error message is written
** to context pCtx. If the error is an unrecognized modifier, no error is
** written to pCtx.
*/
static int parseModifier(
700
701
702
703
704
705
706































707
708
709
710
711
712
713
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







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







      */
      if( sqlite3_stricmp(z, "auto")==0 ){
        if( idx>1 ) return 1; /* IMP: R-33611-57934 */
        autoAdjustDate(p);
        rc = 0;
      }
      break;
    }
    case 'c': {
      /*
      **    ceiling
      **
      ** Resolve day-of-month overflow by rolling forward into the next
      ** month.  As this is the default action, this modifier is really
      ** a no-op that is only included for symmetry.  See "floor".
      */
      if( sqlite3_stricmp(z, "ceiling")==0 ){
        computeJD(p);
        clearYMD_HMS_TZ(p);
        rc = 0;
        p->nFloor = 0;
      }
      break;
    }
    case 'f': {
      /*
      **    floor
      **
      ** Resolve day-of-month overflow by rolling back to the end of the
      ** previous month.
      */
      if( sqlite3_stricmp(z, "floor")==0 ){
        computeJD(p);
        p->iJD -= p->nFloor*86400000;
        clearYMD_HMS_TZ(p);
        rc = 0;
      }
      break;
    }
    case 'j': {
      /*
      **    julianday
      **
      ** Always interpret the prior number as a julian-day value.  If this
      ** is not the first modifier, or if the prior argument is not a numeric
727
728
729
730
731
732
733
734



735
736
737
738
739
740
741
797
798
799
800
801
802
803

804
805
806
807
808
809
810
811
812
813







-
+
+
+







    case 'l': {
      /*    localtime
      **
      ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
      ** show local time.
      */
      if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
        rc = toLocaltime(p, pCtx);
        rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx);
        p->isUtc = 0;
        p->isLocal = 1;
      }
      break;
    }
#endif
    case 'u': {
      /*
      **    unixepoch
752
753
754
755
756
757
758
759

760
761
762
763
764
765
766
824
825
826
827
828
829
830

831
832
833
834
835
836
837
838







-
+







          p->validJD = 1;
          p->rawS = 0;
          rc = 0;
        }
      }
#ifndef SQLITE_OMIT_LOCALTIME
      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
        if( p->tzSet==0 ){
        if( p->isUtc==0 ){
          i64 iOrigJD;              /* Original localtime */
          i64 iGuess;               /* Guess at the corresponding utc time */
          int cnt = 0;              /* Safety to prevent infinite loop */
          i64 iErr;                 /* Guess is off by this much */

          computeJD(p);
          iGuess = iOrigJD = p->iJD;
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
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







-
+
+



















-
+







            if( rc ) return rc;
            computeJD(&new);
            iErr = new.iJD - iOrigJD;
          }while( iErr && cnt++<3 );
          memset(p, 0, sizeof(*p));
          p->iJD = iGuess;
          p->validJD = 1;
          p->tzSet = 1;
          p->isUtc = 1;
          p->isLocal = 0;
        }
        rc = SQLITE_OK;
      }
#endif
      break;
    }
    case 'w': {
      /*
      **    weekday N
      **
      ** Move the date to the same time on the next occurrence of
      ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
      ** date is already on the appropriate weekday, this is a no-op.
      */
      if( sqlite3_strnicmp(z, "weekday ", 8)==0
               && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
               && r>=0.0 && r<7.0 && (n=(int)r)==r ){
        sqlite3_int64 Z;
        computeYMD_HMS(p);
        p->validTZ = 0;
        p->tz = 0;
        p->validJD = 0;
        computeJD(p);
        Z = ((p->iJD + 129600000)/86400000) % 7;
        if( Z>n ) Z -= 7;
        p->iJD += (n - Z)*86400000;
        clearYMD_HMS_TZ(p);
        rc = 0;
835
836
837
838
839
840
841
842

843
844
845
846
847
848
849
908
909
910
911
912
913
914

915
916
917
918
919
920
921
922







-
+







      if( !p->validJD && !p->validYMD && !p->validHMS ) break;
      z += 9;
      computeYMD(p);
      p->validHMS = 1;
      p->h = p->m = 0;
      p->s = 0.0;
      p->rawS = 0;
      p->validTZ = 0;
      p->tz = 0;
      p->validJD = 0;
      if( sqlite3_stricmp(z,"month")==0 ){
        p->D = 1;
        rc = 0;
      }else if( sqlite3_stricmp(z,"year")==0 ){
        p->M = 1;
        p->D = 1;
906
907
908
909
910
911
912

913
914
915
916
917
918
919
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993







+







        }else{
          p->Y += Y;
          p->M += M;
        }
        x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
        p->Y += x;
        p->M -= x*12;
        computeFloor(p);
        computeJD(p);
        p->validHMS = 0;
        p->validYMD = 0;
        p->iJD += (i64)D*86400000;
        if( z[11]==0 ){
          rc = 0;
          break;
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
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







-
+




+







-
+





+






-
+

+

+







      }

      /* If control reaches this point, it means the transformation is
      ** one of the forms like "+NNN days".  */
      z += n;
      while( sqlite3Isspace(*z) ) z++;
      n = sqlite3Strlen30(z);
      if( n>10 || n<3 ) break;
      if( n<3 || n>10 ) break;
      if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
      computeJD(p);
      assert( rc==1 );
      rRounder = r<0 ? -0.5 : +0.5;
      p->nFloor = 0;
      for(i=0; i<ArraySize(aXformType); i++){
        if( aXformType[i].nName==n
         && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
         && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
        ){
          switch( i ){
            case 4: { /* Special processing to add months */
              assert( strcmp(aXformType[i].zName,"month")==0 );
              assert( strcmp(aXformType[4].zName,"month")==0 );
              computeYMD_HMS(p);
              p->M += (int)r;
              x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
              p->Y += x;
              p->M -= x*12;
              computeFloor(p);
              p->validJD = 0;
              r -= (int)r;
              break;
            }
            case 5: { /* Special processing to add years */
              int y = (int)r;
              assert( strcmp(aXformType[i].zName,"year")==0 );
              assert( strcmp(aXformType[5].zName,"year")==0 );
              computeYMD_HMS(p);
              assert( p->M>=0 && p->M<=12 );
              p->Y += y;
              computeFloor(p);
              p->validJD = 0;
              r -= (int)r;
              break;
            }
          }
          computeJD(p);
          p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder);
1039
1040
1041
1042
1043
1044
1045






1046
1047
1048
1049
1050
1051
1052
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136







+
+
+
+
+
+







  for(i=1; i<argc; i++){
    z = sqlite3_value_text(argv[i]);
    n = sqlite3_value_bytes(argv[i]);
    if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1;
  }
  computeJD(p);
  if( p->isError || !validJulianDay(p->iJD) ) return 1;
  if( argc==1 && p->validYMD && p->D>28 ){
    /* Make sure a YYYY-MM-DD is normalized.
    ** Example: 2023-02-31 -> 2023-03-03 */
    assert( p->validJD );
    p->validYMD = 0;  
  }
  return 0;
}


/*
** The following routines implement the various date and time functions
** of SQLite.
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
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









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




-
+
+

+
+
+

+
+
-
+

+


+
+
+


+
+
-
-
+
+
+
+







      zBuf[0] = '-';
      sqlite3_result_text(context, zBuf, 11, SQLITE_TRANSIENT);
    }else{
      sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT);
    }
  }
}

/*
** Compute the number of days after the most recent January 1.
**
** In other words, compute the zero-based day number for the
** current year:
**
**   Jan01 = 0,  Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ...
**   Dec31 = 364 or 365.
*/
static int daysAfterJan01(DateTime *pDate){
  DateTime jan01 = *pDate;
  assert( jan01.validYMD );
  assert( jan01.validHMS );
  assert( pDate->validJD );
  jan01.validJD = 0;
  jan01.M = 1;
  jan01.D = 1;
  computeJD(&jan01);
  return (int)((pDate->iJD-jan01.iJD+43200000)/86400000);
}

/*
** Return the number of days after the most recent Monday.
**
** In other words, return the day of the week according
** to this code:
**
**   0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday.
*/
static int daysAfterMonday(DateTime *pDate){
  assert( pDate->validJD );
  return (int)((pDate->iJD+43200000)/86400000) % 7;
}

/*
** Return the number of days after the most recent Sunday.
**
** In other words, return the day of the week according
** to this code:
**
**   0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday
*/
static int daysAfterSunday(DateTime *pDate){
  assert( pDate->validJD );
  return (int)((pDate->iJD+129600000)/86400000) % 7;
}

/*
**    strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
**
** Return a string described by FORMAT.  Conversions as follows:
**
**   %d  day of month
**   %d  day of month  01-31
**   %e  day of month  1-31
**   %f  ** fractional seconds  SS.SSS
**   %F  ISO date.  YYYY-MM-DD
**   %G  ISO year corresponding to %V 0000-9999.
**   %g  2-digit ISO year corresponding to %V 00-99
**   %H  hour 00-24
**   %k  hour  0-24  (leading zero converted to space)
**   %I  hour 01-12
**   %j  day of year 000-366
**   %j  day of year 001-366
**   %J  ** julian day number
**   %l  hour  1-12  (leading zero converted to space)
**   %m  month 01-12
**   %M  minute 00-59
**   %p  "am" or "pm"
**   %P  "AM" or "PM"
**   %R  time as HH:MM
**   %s  seconds since 1970-01-01
**   %S  seconds 00-59
**   %T  time as HH:MM:SS
**   %u  day of week 1-7  Monday==1, Sunday==7
**   %w  day of week 0-6  Sunday==0
**   %W  week of year 00-53
**   %w  day of week 0-6  Sunday==0, Monday==1
**   %U  week of year 00-53  (First Sunday is start of week 01)
**   %V  week of year 01-53  (First week containing Thursday is week 01)
**   %W  week of year 00-53  (First Monday is start of week 01)
**   %Y  year 0000-9999
**   %%  %
*/
static void strftimeFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
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
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







-
+








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














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


-
+







    cf = zFmt[i];
    switch( cf ){
      case 'd':  /* Fall thru */
      case 'e': {
        sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
        break;
      }
      case 'f': {
      case 'f': {  /* Fractional seconds.  (Non-standard) */
        double s = x.s;
        if( s>59.999 ) s = 59.999;
        sqlite3_str_appendf(&sRes, "%06.3f", s);
        break;
      }
      case 'F': {
        sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
        break;
      }
      case 'G': /* Fall thru */
      case 'g': {
        DateTime y = x;
        assert( y.validJD );
        /* Move y so that it is the Thursday in the same week as x */
        y.iJD += (3 - daysAfterMonday(&x))*86400000;
        y.validYMD = 0;
        computeYMD(&y);
        if( cf=='g' ){
          sqlite3_str_appendf(&sRes, "%02d", y.Y%100);
        }else{
          sqlite3_str_appendf(&sRes, "%04d", y.Y);
        }
        break;
      }
      case 'H':
      case 'k': {
        sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h);
        break;
      }
      case 'I': /* Fall thru */
      case 'l': {
        int h = x.h;
        if( h>12 ) h -= 12;
        if( h==0 ) h = 12;
        sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
        break;
      }
      case 'W': /* Fall thru */
      case 'j': {
      case 'j': {  /* Day of year.  Jan01==1, Jan02==2, and so forth */
        int nDay;             /* Number of days since 1st day of year */
        DateTime y = x;
        y.validJD = 0;
        y.M = 1;
        y.D = 1;
        computeJD(&y);
        nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
        if( cf=='W' ){
          int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
          wd = (int)(((x.iJD+43200000)/86400000)%7);
          sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
        }else{
          sqlite3_str_appendf(&sRes,"%03d",nDay+1);
        sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1);
        }
        break;
      }
      case 'J': {
      case 'J': {  /* Julian day number.  (Non-standard) */
        sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
        break;
      }
      case 'm': {
        sqlite3_str_appendf(&sRes,"%02d",x.M);
        break;
      }
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371



1372
1373
1374




















1375
1376
1377
1378
1379
1380
1381
1508
1509
1510
1511
1512
1513
1514



1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547







-
-
-
+
+
+



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







        sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
        break;
      }
      case 'T': {
        sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
        break;
      }
      case 'u': /* Fall thru */
      case 'w': {
        char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
      case 'u':    /* Day of week.  1 to 7.  Monday==1, Sunday==7 */
      case 'w': {  /* Day of week.  0 to 6.  Sunday==0, Monday==1 */
        char c = (char)daysAfterSunday(&x) + '0';
        if( c=='0' && cf=='u' ) c = '7';
        sqlite3_str_appendchar(&sRes, 1, c);
        break;
      }
      case 'U': {  /* Week num. 00-53. First Sun of the year is week 01 */
        sqlite3_str_appendf(&sRes,"%02d",
              (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7);
        break;
      }
      case 'V': {  /* Week num. 01-53. First week with a Thur is week 01 */
        DateTime y = x;
        /* Adjust y so that is the Thursday in the same week as x */
        assert( y.validJD );
        y.iJD += (3 - daysAfterMonday(&x))*86400000;
        y.validYMD = 0;
        computeYMD(&y);
        sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1);
        break;
      }
      case 'W': {  /* Week num. 00-53. First Mon of the year is week 01 */
        sqlite3_str_appendf(&sRes,"%02d",
           (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7);
        break;
      }
      case 'Y': {
        sqlite3_str_appendf(&sRes,"%04d",x.Y);
        break;
      }
      case '%': {
        sqlite3_str_appendchar(&sRes, 1, '%');
1515
1516
1517
1518
1519
1520
1521
1522

1523
1524
1525
1526
1527
1528
1529
1530
1531
1681
1682
1683
1684
1685
1686
1687

1688


1689
1690
1691
1692
1693
1694
1695







-
+
-
-







      }
      d2.validJD = 0;
      computeJD(&d2);
    }
    d1.iJD = d2.iJD - d1.iJD;
    d1.iJD += (u64)1486995408 * (u64)100000;
  }
  d1.validYMD = 0;
  clearYMD_HMS_TZ(&d1);
  d1.validHMS = 0;
  d1.validTZ = 0;
  computeYMD_HMS(&d1);
  sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
  sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
       sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
  sqlite3ResultStrAccum(context, &sRes);
}

1585
1586
1587
1588
1589
1590
1591






























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



1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
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







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
















+
+
+











#endif
  if( pTm ){
    strftime(zBuf, 20, zFormat, &sNow);
    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
  }
}
#endif

#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG)
/*
**   datedebug(...)
**
** This routine returns JSON that describes the internal DateTime object.
** Used for debugging and testing only.  Subject to change.
*/
static void datedebugFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  DateTime x;
  if( isDate(context, argc, argv, &x)==0 ){
    char *zJson;
    zJson = sqlite3_mprintf(
      "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d,"
      "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d,"
      "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d,"
      "isUtc:%d,isLocal:%d}",
      x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz,
      x.s, x.validJD, x.validYMD, x.validHMS,
      x.nFloor, x.rawS, x.isError, x.useSubsec,
      x.isUtc, x.isLocal);
    sqlite3_result_text(context, zJson, -1, sqlite3_free);
  }
}
#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */


/*
** This function registered all of the above C functions as SQL
** functions.  This should be the only routine in this file with
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(void){
  static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
    PURE_DATE(julianday,        -1, 0, 0, juliandayFunc ),
    PURE_DATE(unixepoch,        -1, 0, 0, unixepochFunc ),
    PURE_DATE(date,             -1, 0, 0, dateFunc      ),
    PURE_DATE(time,             -1, 0, 0, timeFunc      ),
    PURE_DATE(datetime,         -1, 0, 0, datetimeFunc  ),
    PURE_DATE(strftime,         -1, 0, 0, strftimeFunc  ),
    PURE_DATE(timediff,          2, 0, 0, timediffFunc  ),
#ifdef SQLITE_DEBUG
    PURE_DATE(datedebug,        -1, 0, 0, datedebugFunc ),
#endif
    DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
    DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
    DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),
#else
    STR_FUNCTION(current_time,      0, "%H:%M:%S",          0, currentTimeFunc),
    STR_FUNCTION(current_date,      0, "%Y-%m-%d",          0, currentTimeFunc),
    STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
  };
  sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
}
Changes to src/expr.c.
214
215
216
217
218
219
220
221
222

223


224
225
226
227
228
229
230
214
215
216
217
218
219
220


221
222
223
224
225
226
227
228
229
230
231







-
-
+

+
+







Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
  while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){
    if( ExprHasProperty(pExpr, EP_Unlikely) ){
      assert( ExprUseXList(pExpr) );
      assert( pExpr->x.pList->nExpr>0 );
      assert( pExpr->op==TK_FUNCTION );
      pExpr = pExpr->x.pList->a[0].pExpr;
    }else{
      assert( pExpr->op==TK_COLLATE );
    }else if( pExpr->op==TK_COLLATE ){
      pExpr = pExpr->pLeft;
    }else{
      break;
    }
  }  
  return pExpr;
}

/*
** Return the collation sequence for the expression pExpr. If
910
911
912
913
914
915
916
917
918
919
920




921

922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937

938
939
940
941
942
943
944
911
912
913
914
915
916
917




918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938

939
940
941
942
943
944
945
946







-
-
-
-
+
+
+
+

+















-
+







**
** If dequote is true, then the token (if it exists) is dequoted.
** If dequote is false, no dequoting is performed.  The deQuote
** parameter is ignored if pToken is NULL or if the token does not
** appear to be quoted.  If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
**
** Special case:  If op==TK_INTEGER and pToken points to a string that
** can be translated into a 32-bit integer, then the token is not
** stored in u.zToken.  Instead, the integer values is written
** into u.iValue and the EP_IntValue flag is set.  No extra storage
** Special case (tag-20240227-a):  If op==TK_INTEGER and pToken points to
** a string that can be translated into a 32-bit integer, then the token is
** not stored in u.zToken.  Instead, the integer values is written
** into u.iValue and the EP_IntValue flag is set. No extra storage
** is allocated to hold the integer text and the dequote flag is ignored.
** See also tag-20240227-b.
*/
Expr *sqlite3ExprAlloc(
  sqlite3 *db,            /* Handle for sqlite3DbMallocRawNN() */
  int op,                 /* Expression opcode */
  const Token *pToken,    /* Token argument.  Might be NULL */
  int dequote             /* True to dequote */
){
  Expr *pNew;
  int nExtra = 0;
  int iValue = 0;

  assert( db!=0 );
  if( pToken ){
    if( op!=TK_INTEGER || pToken->z==0
          || sqlite3GetInt32(pToken->z, &iValue)==0 ){
      nExtra = pToken->n+1;
      nExtra = pToken->n+1;  /* tag-20240227-a */
      assert( iValue>=0 );
    }
  }
  pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
  if( pNew ){
    memset(pNew, 0, sizeof(Expr));
    pNew->op = (u8)op;
1219
1220
1221
1222
1223
1224
1225
1226

1227
1228
1229
1230
1231
1232
1233
1234
1235
1221
1222
1223
1224
1225
1226
1227

1228


1229
1230
1231
1232
1233
1234
1235







-
+
-
-







    return;
  }
  assert( pExpr->op==TK_FUNCTION );
  assert( pExpr->pLeft==0 );
  assert( ExprUseXList(pExpr) );
  if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){
    /* Ignore ORDER BY on zero-argument aggregates */
    sqlite3ParserAddCleanup(pParse,
    sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy);
        (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
        pOrderBy);
    return;
  }
  if( IsWindowFunc(pExpr) ){
    sqlite3ExprOrderByAggregateError(pParse, pExpr);
    sqlite3ExprListDelete(db, pOrderBy);
    return;
  }
1402
1403
1404
1405
1406
1407
1408



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







+
+
+







  if( !ExprHasProperty(p, EP_Static) ){
    sqlite3DbNNFreeNN(db, p);
  }
}
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
  if( p ) sqlite3ExprDeleteNN(db, p);
}
void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){
  if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p);
}

/*
** Clear both elements of an OnOrUsing object
*/
void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
  if( p==0 ){
    /* Nothing to clear */
1427
1428
1429
1430
1431
1432
1433
1434

1435
1436
1437
1438
1439
1440
1441
1442
1443
1430
1431
1432
1433
1434
1435
1436

1437


1438
1439
1440
1441
1442
1443
1444







-
+
-
-







**
** The pExpr might be deleted immediately on an OOM error.
**
** The deferred delete is (currently) implemented by adding the
** pExpr to the pParse->pConstExpr list with a register number of 0.
*/
void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
  sqlite3ParserAddCleanup(pParse,
  sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr);
    (void(*)(sqlite3*,void*))sqlite3ExprDelete,
    pExpr);
}

/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
** expression.
*/
void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){
  if( p ){
1865
1866
1867
1868
1869
1870
1871

1872
1873
1874
1875
1876
1877
1878
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880







+







    pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
    pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
    pNewItem->fg = pOldItem->fg;
    pNewItem->iCursor = pOldItem->iCursor;
    pNewItem->addrFillSub = pOldItem->addrFillSub;
    pNewItem->regReturn = pOldItem->regReturn;
    pNewItem->regResult = pOldItem->regResult;
    if( pNewItem->fg.isIndexedBy ){
      pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
    }
    pNewItem->u2 = pOldItem->u2;
    if( pNewItem->fg.isCte ){
      pNewItem->u2.pCteUse->nUse++;
    }
2235
2236
2237
2238
2239
2240
2241



2242
2243
2244
2245
2246
2247
2248
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253







+
+
+







    pItem++;
  }while( --i>0 );
  sqlite3DbNNFreeNN(db, pList);
}
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
  if( pList ) exprListDeleteNN(db, pList);
}
void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){
  if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList);
}

/*
** Return the bitwise-OR of all Expr.flags fields in the given
** ExprList.
*/
u32 sqlite3ExprListFlags(const ExprList *pList){
  int i;
2338
2339
2340
2341
2342
2343
2344
















































2345
2346
2347
2348
2349
2350
2351
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404







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







    }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){
      pExpr = pExpr->op==TK_AND ? pLeft : pRight;
    }
  }
  return pExpr;
}

/*
** pExpr is a TK_FUNCTION node.  Try to determine whether or not the
** function is a constant function.  A function is constant if all of
** the following are true:
**
**    (1)  It is a scalar function (not an aggregate or window function)
**    (2)  It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
**         property.
**    (3)  All of its arguments are constants
**
** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
** It makes no changes to pWalker->eCode if pExpr is constant.  In
** every case, it returns WRC_Abort.
**
** Called as a service subroutine from exprNodeIsConstant().
*/
static SQLITE_NOINLINE int exprNodeIsConstantFunction(
  Walker *pWalker,
  Expr *pExpr
){
  int n;             /* Number of arguments */
  ExprList *pList;   /* List of arguments */
  FuncDef *pDef;     /* The function */
  sqlite3 *db;       /* The database */

  assert( pExpr->op==TK_FUNCTION );
  if( ExprHasProperty(pExpr, EP_TokenOnly)
   || (pList = pExpr->x.pList)==0
  ){;
    n = 0;
  }else{
    n = pList->nExpr;
    sqlite3WalkExprList(pWalker, pList);
    if( pWalker->eCode==0 ) return WRC_Abort;
  }
  db = pWalker->pParse->db;
  pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
  if( pDef==0
   || pDef->xFinalize!=0
   || (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
   || ExprHasProperty(pExpr, EP_WinFunc)
  ){
    pWalker->eCode = 0;
    return WRC_Abort;
  }
  return WRC_Continue;
}


/*
** These routines are Walker callbacks used to check expressions to
** see if they are "constant" for some definition of constant.  The
** Walker.eCode value determines the type of "constant" we are looking
** for.
**
2366
2367
2368
2369
2370
2371
2372

2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391


2392
2393
2394
2395
2396
2397
2398
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454







+



















+
+







** an error for new statements, but is silently converted
** to NULL for existing schemas.  This allows sqlite_schema tables that
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
  assert( pWalker->eCode>0 );

  /* If pWalker->eCode is 2 then any term of the expression that comes from
  ** the ON or USING clauses of an outer join disqualifies the expression
  ** from being considered constant. */
  if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_OuterON) ){
    pWalker->eCode = 0;
    return WRC_Abort;
  }

  switch( pExpr->op ){
    /* Consider functions to be constant if all their arguments are constant
    ** and either pWalker->eCode==4 or 5 or the function has the
    ** SQLITE_FUNC_CONST flag. */
    case TK_FUNCTION:
      if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc))
       && !ExprHasProperty(pExpr, EP_WinFunc)
      ){
        if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
        return WRC_Continue;
      }else if( pWalker->pParse ){
        return exprNodeIsConstantFunction(pWalker, pExpr);
      }else{
        pWalker->eCode = 0;
        return WRC_Abort;
      }
    case TK_ID:
      /* Convert "true" or "false" in a DEFAULT clause into the
      ** appropriate TK_TRUEFALSE operator */
2437
2438
2439
2440
2441
2442
2443
2444

2445
2446

2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463






2464
2465
2466


2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483


2484
2485
2486
2487
2488
2489
2490
2491
2492
2493

2494
2495
2496
2497
2498
2499
2500
2493
2494
2495
2496
2497
2498
2499

2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527


2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544


2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555

2556
2557
2558
2559
2560
2561
2562
2563







-
+


+

















+
+
+
+
+
+

-
-
+
+















-
-
+
+









-
+







      /* no break */ deliberate_fall_through
    default:
      testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
      testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
      return WRC_Continue;
  }
}
static int exprIsConst(Expr *p, int initFlag, int iCur){
static int exprIsConst(Parse *pParse, Expr *p, int initFlag, int iCur){
  Walker w;
  w.eCode = initFlag;
  w.pParse = pParse;
  w.xExprCallback = exprNodeIsConstant;
  w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
  w.xSelectCallback2 = sqlite3SelectWalkAssert2;
#endif
  w.u.iCur = iCur;
  sqlite3WalkExpr(&w, p);
  return w.eCode;
}

/*
** Walk an expression tree.  Return non-zero if the expression is constant
** and 0 if it involves variables or function calls.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
**
** The pParse parameter may be NULL.  But if it is NULL, there is no way
** to determine if function calls are constant or not, and hence all
** function calls will be considered to be non-constant.  If pParse is
** not NULL, then a function call might be constant, depending on the
** function and on its parameters.
*/
int sqlite3ExprIsConstant(Expr *p){
  return exprIsConst(p, 1, 0);
int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
  return exprIsConst(pParse, p, 1, 0);
}

/*
** Walk an expression tree.  Return non-zero if
**
**   (1) the expression is constant, and
**   (2) the expression does originate in the ON or USING clause
**       of a LEFT JOIN, and
**   (3) the expression does not contain any EP_FixedCol TK_COLUMN
**       operands created by the constant propagation optimization.
**
** When this routine returns true, it indicates that the expression
** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up.  See sqlite3ExprCodeRunJustOnce().
*/
int sqlite3ExprIsConstantNotJoin(Expr *p){
  return exprIsConst(p, 2, 0);
static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
  return exprIsConst(pParse, p, 2, 0);
}

/*
** Walk an expression tree.  Return non-zero if the expression is constant
** for any single row of the table with cursor iCur.  In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
*/
int sqlite3ExprIsTableConstant(Expr *p, int iCur){
  return exprIsConst(p, 3, iCur);
  return exprIsConst(0, p, 3, iCur);
}

/*
** Check pExpr to see if it is an constraint on the single data source
** pSrc = &pSrcList->a[iSrc].  In other words, check to see if pExpr
** constrains pSrc but does not depend on any other tables or data
** sources anywhere else in the query.  Return true (non-zero) if pExpr
2643
2644
2645
2646
2647
2648
2649
2650

2651
2652
2653
2654
2655
2656
2657
2706
2707
2708
2709
2710
2711
2712

2713
2714
2715
2716
2717
2718
2719
2720







-
+







**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
*/
int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
  assert( isInit==0 || isInit==1 );
  return exprIsConst(p, 4+isInit, 0);
  return exprIsConst(0, p, 4+isInit, 0);
}

#ifdef SQLITE_ENABLE_CURSOR_HINTS
/*
** Walk an expression tree.  Return 1 if the expression contains a
** subquery of some kind.  Return 0 if there are no subqueries.
*/
2734
2735
2736
2737
2738
2739
2740
2741

2742
2743

2744
2745
2746
2747
2748
2749
2750
2797
2798
2799
2800
2801
2802
2803

2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814







-
+


+







    case TK_STRING:
    case TK_FLOAT:
    case TK_BLOB:
      return 0;
    case TK_COLUMN:
      assert( ExprUseYTab(p) );
      return ExprHasProperty(p, EP_CanBeNull) ||
             p->y.pTab==0 ||  /* Reference to column of index on expression */
             NEVER(p->y.pTab==0) ||  /* Reference to column of index on expr */
             (p->iColumn>=0
              && p->y.pTab->aCol!=0 /* Possible due to prior error */
              && ALWAYS(p->iColumn<p->y.pTab->nCol)
              && p->y.pTab->aCol[p->iColumn].notNull==0);
    default:
      return 1;
  }
}

/*
2887
2888
2889
2890
2891
2892
2893
2894

2895
2896
2897
2898
2899
2900

2901
2902
2903
2904
2905
2906
2907
2951
2952
2953
2954
2955
2956
2957

2958
2959
2960
2961
2962
2963

2964
2965
2966
2967
2968
2969
2970
2971







-
+





-
+









#ifndef SQLITE_OMIT_SUBQUERY
/*
** The argument is an IN operator with a list (not a subquery) on the
** right-hand side.  Return TRUE if that list is constant.
*/
static int sqlite3InRhsIsConstant(Expr *pIn){
static int sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){
  Expr *pLHS;
  int res;
  assert( !ExprHasProperty(pIn, EP_xIsSelect) );
  pLHS = pIn->pLeft;
  pIn->pLeft = 0;
  res = sqlite3ExprIsConstant(pIn);
  res = sqlite3ExprIsConstant(pParse, pIn);
  pIn->pLeft = pLHS;
  return res;
}
#endif

/*
** This function is used by the implementation of the IN (...) operator.
3162
3163
3164
3165
3166
3167
3168
3169

3170
3171
3172
3173
3174
3175
3176
3226
3227
3228
3229
3230
3231
3232

3233
3234
3235
3236
3237
3238
3239
3240







-
+







  ** and the RHS is not constant or has two or fewer terms,
  ** then it is not worth creating an ephemeral table to evaluate
  ** the IN operator so return IN_INDEX_NOOP.
  */
  if( eType==0
   && (inFlags & IN_INDEX_NOOP_OK)
   && ExprUseXList(pX)
   && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
   && (!sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2)
  ){
    pParse->nTab--;  /* Back out the allocation of the unused cursor */
    iTab = -1;       /* Cursor is not allocated */
    eType = IN_INDEX_NOOP;
  }

  if( eType==0 ){
3445
3446
3447
3448
3449
3450
3451
3452

3453
3454
3455
3456
3457
3458
3459
3509
3510
3511
3512
3513
3514
3515

3516
3517
3518
3519
3520
3521
3522
3523







-
+







      Expr *pE2 = pItem->pExpr;

      /* If the expression is not constant then we will need to
      ** disable the test that was generated above that makes sure
      ** this code only executes once.  Because for a non-constant
      ** expression we need to rerun this code each time.
      */
      if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
      if( addrOnce && !sqlite3ExprIsConstant(pParse, pE2) ){
        sqlite3VdbeChangeToNoop(v, addrOnce-1);
        sqlite3VdbeChangeToNoop(v, addrOnce);
        ExprClearProperty(pExpr, EP_Subrtn);
        addrOnce = 0;
      }

      /* Evaluate the expression and insert it into the temp table */
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4673
4674
4675
4676
4677
4678
4679






4680
4681
4682
4683
4684
4685
4686







-
-
-
-
-
-







    }
#endif
    case TK_VARIABLE: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      assert( pExpr->u.zToken!=0 );
      assert( pExpr->u.zToken[0]!=0 );
      sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
      if( pExpr->u.zToken[1]!=0 ){
        const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
        assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) );
        pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
        sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
      }
      return target;
    }
    case TK_REGISTER: {
      return pExpr->iTable;
    }
#ifndef SQLITE_OMIT_CAST
    case TK_CAST: {
4788
4789
4790
4791
4792
4793
4794
4795



4796
4797
4798
4799
4800
4801
4802
4846
4847
4848
4849
4850
4851
4852

4853
4854
4855
4856
4857
4858
4859
4860
4861
4862







-
+
+
+








#ifndef SQLITE_OMIT_WINDOWFUNC
      if( ExprHasProperty(pExpr, EP_WinFunc) ){
        return pExpr->y.pWin->regResult;
      }
#endif

      if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
      if( ConstFactorOk(pParse)
       && sqlite3ExprIsConstantNotJoin(pParse,pExpr)
      ){
        /* SQL functions can be expensive. So try to avoid running them
        ** multiple times if we know they always give the same result */
        return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
      }
      assert( !ExprHasProperty(pExpr, EP_TokenOnly) );
      assert( ExprUseXList(pExpr) );
      pFarg = pExpr->x.pList;
4819
4820
4821
4822
4823
4824
4825
4826

4827
4828
4829
4830
4831
4832
4833
4879
4880
4881
4882
4883
4884
4885

4886
4887
4888
4889
4890
4891
4892
4893







-
+







        return exprCodeInlineFunction(pParse, pFarg,
             SQLITE_PTR_TO_INT(pDef->pUserData), target);
      }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){
        sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
      }

      for(i=0; i<nFarg; i++){
        if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
        if( i<32 && sqlite3ExprIsConstant(pParse, pFarg->a[i].pExpr) ){
          testcase( i==31 );
          constMask |= MASKBIT32(i);
        }
        if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
          pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
        }
      }
5286
5287
5288
5289
5290
5291
5292
5293

5294
5295
5296
5297
5298
5299
5300
5346
5347
5348
5349
5350
5351
5352

5353
5354
5355
5356
5357
5358
5359
5360







-
+







*/
int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
  int r2;
  pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
  if( ConstFactorOk(pParse)
   && ALWAYS(pExpr!=0)
   && pExpr->op!=TK_REGISTER
   && sqlite3ExprIsConstantNotJoin(pExpr)
   && sqlite3ExprIsConstantNotJoin(pParse, pExpr)
  ){
    *pReg  = 0;
    r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
  }else{
    int r1 = sqlite3GetTempReg(pParse);
    r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    if( r2==r1 ){
5318
5319
5320
5321
5322
5323
5324


5325
5326


5327
5328
5329
5330
5331
5332
5333
5378
5379
5380
5381
5382
5383
5384
5385
5386


5387
5388
5389
5390
5391
5392
5393
5394
5395







+
+
-
-
+
+







  assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
  assert( target>0 && target<=pParse->nMem );
  assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
  if( pParse->pVdbe==0 ) return;
  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
  if( inReg!=target ){
    u8 op;
    Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr);
    testcase( pX!=pExpr );
    if( ALWAYS(pExpr)
     && (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER)
    if( ALWAYS(pX)
     && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER)
    ){
      op = OP_Copy;
    }else{
      op = OP_SCopy;
    }
    sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
  }
5348
5349
5350
5351
5352
5353
5354
5355

5356
5357
5358
5359
5360
5361
5362
5410
5411
5412
5413
5414
5415
5416

5417
5418
5419
5420
5421
5422
5423
5424







-
+







/*
** Generate code that will evaluate expression pExpr and store the
** results in register target.  The results are guaranteed to appear
** in register target.  If the expression is constant, then this routine
** might choose to code the expression at initialization time.
*/
void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
  if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
  if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){
    sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
  }else{
    sqlite3ExprCodeCopy(pParse, pExpr, target);
  }
}

/*
5407
5408
5409
5410
5411
5412
5413
5414

5415
5416
5417
5418
5419
5420
5421
5469
5470
5471
5472
5473
5474
5475

5476
5477
5478
5479
5480
5481
5482
5483







-
+







      if( flags & SQLITE_ECEL_OMITREF ){
        i--;
        n--;
      }else{
        sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
      }
    }else if( (flags & SQLITE_ECEL_FACTOR)!=0
           && sqlite3ExprIsConstantNotJoin(pExpr)
           && sqlite3ExprIsConstantNotJoin(pParse,pExpr)
    ){
      sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
    }else{
      int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
      if( inReg!=target+i ){
        VdbeOp *pOp;
        if( copyOp==OP_Copy
6039
6040
6041
6042
6043
6044
6045
6046
6047


6048
6049
6050
6051
6052
6053
6054
6101
6102
6103
6104
6105
6106
6107


6108
6109
6110
6111
6112
6113
6114
6115
6116







-
-
+
+








/*
** Like sqlite3ExprCompare() except COLLATE operators at the top-level
** are ignored.
*/
int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){
  return sqlite3ExprCompare(0,
             sqlite3ExprSkipCollateAndLikely(pA),
             sqlite3ExprSkipCollateAndLikely(pB),
             sqlite3ExprSkipCollate(pA),
             sqlite3ExprSkipCollate(pB),
             iTab);
}

/*
** Return non-zero if Expr p can only be true if pNN is not NULL.
**
** Or if seenNot is true, return non-zero if Expr p can only be
6765
6766
6767
6768
6769
6770
6771

6772
6773
6774
6775
6776
6777
6778

6779
6780
6781
6782
6783
6784
6785
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840

6841
6842
6843
6844
6845
6846
6847
6848







+






-
+







        } /* end loop over pSrcList */
      }
      return WRC_Continue;
    }
    case TK_AGG_FUNCTION: {
      if( (pNC->ncFlags & NC_InAggFunc)==0
       && pWalker->walkerDepth==pExpr->op2
       && pExpr->pAggInfo==0
      ){
        /* Check to see if pExpr is a duplicate of another aggregate
        ** function that is already in the pAggInfo structure
        */
        struct AggInfo_func *pItem = pAggInfo->aFunc;
        for(i=0; i<pAggInfo->nFunc; i++, pItem++){
          if( pItem->pFExpr==pExpr ) break;
          if( NEVER(pItem->pFExpr==pExpr) ) break;
          if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
            break;
          }
        }
        if( i>=pAggInfo->nFunc ){
          /* pExpr is original.  Make a new entry in pAggInfo->aFunc[]
          */
6814
6815
6816
6817
6818
6819
6820


6821
6822
6823
6824
6825
6826
6827
6877
6878
6879
6880
6881
6882
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892







+
+







                               pExpr->x.pList->a[0].pExpr,0)==0
              ){
                pItem->bOBPayload = 0;
                pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct);
              }else{
                pItem->bOBPayload = 1;
              }
              pItem->bUseSubtype =
                    (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0;
            }else{
              pItem->iOBTab = -1;
            }
            if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){
              pItem->iDistinct = pParse->nTab++;
            }else{
              pItem->iDistinct = -1;
Changes to src/func.c.
1097
1098
1099
1100
1101
1102
1103
1104

1105
1106
1107
1108
1109
1110

1111
1112
1113
1114
1115
1116
1117
1097
1098
1099
1100
1101
1102
1103

1104
1105
1106
1107
1108
1109

1110
1111
1112
1113
1114
1115
1116
1117







-
+





-
+







  assert( pStr!=0 && pStr->nChar==0 );

  switch( sqlite3_value_type(pValue) ){
    case SQLITE_FLOAT: {
      double r1, r2;
      const char *zVal;
      r1 = sqlite3_value_double(pValue);
      sqlite3_str_appendf(pStr, "%!.15g", r1);
      sqlite3_str_appendf(pStr, "%!0.15g", r1);
      zVal = sqlite3_str_value(pStr);
      if( zVal ){
        sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
        if( r1!=r2 ){
          sqlite3_str_reset(pStr);
          sqlite3_str_appendf(pStr, "%!.20e", r1);
          sqlite3_str_appendf(pStr, "%!0.20e", r1);
        }
      }
      break;
    }
    case SQLITE_INTEGER: {
      sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue));
      break;
1405
1406
1407
1408
1409
1410
1411
1412

1413
1414
1415
1416
1417
1418
1419
1405
1406
1407
1408
1409
1410
1411

1412
1413
1414
1415
1416
1417
1418
1419







-
+







  if( zPattern==0 ){
    assert( sqlite3_value_type(argv[1])==SQLITE_NULL
            || sqlite3_context_db_handle(context)->mallocFailed );
    return;
  }
  if( zPattern[0]==0 ){
    assert( sqlite3_value_type(argv[1])!=SQLITE_NULL );
    sqlite3_result_value(context, argv[0]);
    sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT);
    return;
  }
  nPattern = sqlite3_value_bytes(argv[1]);
  assert( zPattern==sqlite3_value_text(argv[1]) );  /* No encoding change */
  zRep = sqlite3_value_text(argv[2]);
  if( zRep==0 ) return;
  nRep = sqlite3_value_bytes(argv[2]);
Changes to src/global.c.
240
241
242
243
244
245
246



247
248
249
250
251
252
253
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256







+
+
+







   1,                         /* bCoreMutex */
   SQLITE_THREADSAFE==1,      /* bFullMutex */
   SQLITE_USE_URI,            /* bOpenUri */
   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
   0,                         /* bSmallMalloc */
   1,                         /* bExtraSchemaChecks */
   sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
#ifdef SQLITE_DEBUG
   0,                         /* bJsonSelfcheck */
#endif
   0x7ffffffe,                /* mxStrlen */
   0,                         /* neverCorrupt */
   SQLITE_DEFAULT_LOOKASIDE,  /* szLookaside, nLookaside */
   SQLITE_STMTJRNL_SPILL,     /* nStmtSpill */
   {0,0,0,0,0,0,0,0},         /* m */
   {0,0,0,0,0,0,0,0,0},       /* mutex */
   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
282
283
284
285
286
287
288



289
290
291
292
293
294
295
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301







+
+
+







#endif
#ifndef SQLITE_OMIT_DESERIALIZE
   SQLITE_MEMDB_DEFAULT_MAXSIZE,   /* mxMemdbSize */
#endif
#ifndef SQLITE_UNTESTABLE
   0,                         /* xTestCallback */
#endif
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
   0,                         /* mNoVisibleRowid.  0 == allow rowid-in-view */
#endif
   0,                         /* bLocaltimeFault */
   0,                         /* xAltLocaltime */
   0x7ffffffe,                /* iOnceResetThreshold */
   SQLITE_DEFAULT_SORTERREF_SIZE,   /* szSorterRef */
   0,                         /* iPrngSeed */
#ifdef SQLITE_DEBUG
   {0,0,0,0,0,0},             /* aTune */
Changes to src/insert.c.
573
574
575
576
577
578
579



























































































































































































580
581
582
583
584
585
586
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
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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







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







** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
** above are all no-ops
*/
# define autoIncBegin(A,B,C) (0)
# define autoIncStep(A,B,C)
#endif /* SQLITE_OMIT_AUTOINCREMENT */

/*
** If argument pVal is a Select object returned by an sqlite3MultiValues()
** that was able to use the co-routine optimization, finish coding the
** co-routine.
*/
void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
  if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
    SrcItem *pItem = &pVal->pSrc->a[0];
    sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
    sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
  }
}

/*
** Return true if all expressions in the expression-list passed as the
** only argument are constant.
*/
static int exprListIsConstant(Parse *pParse, ExprList *pRow){
  int ii;
  for(ii=0; ii<pRow->nExpr; ii++){
    if( 0==sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0;
  }
  return 1;
}

/*
** Return true if all expressions in the expression-list passed as the
** only argument are both constant and have no affinity.
*/
static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){
  int ii;
  if( exprListIsConstant(pParse,pRow)==0 ) return 0;
  for(ii=0; ii<pRow->nExpr; ii++){
    assert( pRow->a[ii].pExpr->affExpr==0 );
    if( 0!=sqlite3ExprAffinity(pRow->a[ii].pExpr) ) return 0;
  }
  return 1;

}

/*
** This function is called by the parser for the second and subsequent
** rows of a multi-row VALUES clause. Argument pLeft is the part of
** the VALUES clause already parsed, argument pRow is the vector of values
** for the new row. The Select object returned represents the complete
** VALUES clause, including the new row.
**
** There are two ways in which this may be achieved - by incremental 
** coding of a co-routine (the "co-routine" method) or by returning a
** Select object equivalent to the following (the "UNION ALL" method):
**
**        "pLeft UNION ALL SELECT pRow"
**
** If the VALUES clause contains a lot of rows, this compound Select
** object may consume a lot of memory.
**
** When the co-routine method is used, each row that will be returned
** by the VALUES clause is coded into part of a co-routine as it is 
** passed to this function. The returned Select object is equivalent to:
**
**     SELECT * FROM (
**       Select object to read co-routine
**     )
**
** The co-routine method is used in most cases. Exceptions are:
**
**    a) If the current statement has a WITH clause. This is to avoid
**       statements like:
**
**            WITH cte AS ( VALUES('x'), ('y') ... )
**            SELECT * FROM cte AS a, cte AS b;
**
**       This will not work, as the co-routine uses a hard-coded register
**       for its OP_Yield instructions, and so it is not possible for two
**       cursors to iterate through it concurrently.
**
**    b) The schema is currently being parsed (i.e. the VALUES clause is part 
**       of a schema item like a VIEW or TRIGGER). In this case there is no VM
**       being generated when parsing is taking place, and so generating 
**       a co-routine is not possible.
**
**    c) There are non-constant expressions in the VALUES clause (e.g.
**       the VALUES clause is part of a correlated sub-query).
**
**    d) One or more of the values in the first row of the VALUES clause
**       has an affinity (i.e. is a CAST expression). This causes problems
**       because the complex rules SQLite uses (see function 
**       sqlite3SubqueryColumnTypes() in select.c) to determine the effective
**       affinity of such a column for all rows require access to all values in
**       the column simultaneously. 
*/
Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){

  if( pParse->bHasWith                   /* condition (a) above */
   || pParse->db->init.busy              /* condition (b) above */
   || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */
   || (pLeft->pSrc->nSrc==0 &&
       exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */
   || IN_SPECIAL_PARSE
  ){
    /* The co-routine method cannot be used. Fall back to UNION ALL. */
    Select *pSelect = 0;
    int f = SF_Values | SF_MultiValue;
    if( pLeft->pSrc->nSrc ){
      sqlite3MultiValuesEnd(pParse, pLeft);
      f = SF_Values;
    }else if( pLeft->pPrior ){
      /* In this case set the SF_MultiValue flag only if it was set on pLeft */
      f = (f & pLeft->selFlags);
    }
    pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
    pLeft->selFlags &= ~SF_MultiValue;
    if( pSelect ){
      pSelect->op = TK_ALL;
      pSelect->pPrior = pLeft;
      pLeft = pSelect;
    }
  }else{
    SrcItem *p = 0;               /* SrcItem that reads from co-routine */

    if( pLeft->pSrc->nSrc==0 ){
      /* Co-routine has not yet been started and the special Select object
      ** that accesses the co-routine has not yet been created. This block 
      ** does both those things. */
      Vdbe *v = sqlite3GetVdbe(pParse);
      Select *pRet = sqlite3SelectNew(pParse, 0, 0, 0, 0, 0, 0, 0, 0);

      /* Ensure the database schema has been read. This is to ensure we have
      ** the correct text encoding.  */
      if( (pParse->db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ){
        sqlite3ReadSchema(pParse);
      }

      if( pRet ){
        SelectDest dest;
        pRet->pSrc->nSrc = 1;
        pRet->pPrior = pLeft->pPrior;
        pRet->op = pLeft->op;
        pLeft->pPrior = 0;
        pLeft->op = TK_SELECT;
        assert( pLeft->pNext==0 );
        assert( pRet->pNext==0 );
        p = &pRet->pSrc->a[0];
        p->pSelect = pLeft;
        p->fg.viaCoroutine = 1;
        p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
        p->regReturn = ++pParse->nMem;
        p->iCursor = -1;
        p->u1.nRow = 2;
        sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
        sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);

        /* Allocate registers for the output of the co-routine. Do so so
        ** that there are two unused registers immediately before those
        ** used by the co-routine. This allows the code in sqlite3Insert()
        ** to use these registers directly, instead of copying the output
        ** of the co-routine to a separate array for processing.  */
        dest.iSdst = pParse->nMem + 3; 
        dest.nSdst = pLeft->pEList->nExpr;
        pParse->nMem += 2 + dest.nSdst;

        pLeft->selFlags |= SF_MultiValue;
        sqlite3Select(pParse, pLeft, &dest);
        p->regResult = dest.iSdst;
        assert( pParse->nErr || dest.iSdst>0 );
        pLeft = pRet;
      }
    }else{
      p = &pLeft->pSrc->a[0];
      assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
      p->u1.nRow++;
    }
  
    if( pParse->nErr==0 ){
      assert( p!=0 );
      if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
        sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
      }else{
        sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
        sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
      }
    }
    sqlite3ExprListDelete(pParse->db, pRow);
  }

  return pLeft;
}

/* Forward declaration */
static int xferOptimization(
  Parse *pParse,        /* Parser context */
  Table *pDest,         /* The table we are inserting into */
  Select *pSelect,      /* A SELECT statement to use as the data source */
  int onError,          /* How to handle constraint errors */
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
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







-
-


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







  ** is coming from a SELECT statement, then generate a co-routine that
  ** produces a single row of the SELECT on each invocation.  The
  ** co-routine is the common header to the 3rd and 4th templates.
  */
  if( pSelect ){
    /* Data is coming from a SELECT or from a multi-row VALUES clause.
    ** Generate a co-routine to run the SELECT. */
    int regYield;       /* Register holding co-routine entry-point */
    int addrTop;        /* Top of the co-routine */
    int rc;             /* Result code */

    if( pSelect->pSrc->nSrc==1 
     && pSelect->pSrc->a[0].fg.viaCoroutine 
     && pSelect->pPrior==0
    ){
      SrcItem *pItem = &pSelect->pSrc->a[0];
      dest.iSDParm = pItem->regReturn;
      regFromSelect = pItem->regResult;
      nColumn = pItem->pSelect->pEList->nExpr;
      ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
      if( bIdListInOrder && nColumn==pTab->nCol ){
        regData = regFromSelect;
        regRowid = regData - 1;
        regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
      }
    }else{
      int addrTop;        /* Top of the co-routine */
    regYield = ++pParse->nMem;
    addrTop = sqlite3VdbeCurrentAddr(v) + 1;
    sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
    sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
    dest.iSdst = bIdListInOrder ? regData : 0;
    dest.nSdst = pTab->nCol;
    rc = sqlite3Select(pParse, pSelect, &dest);
    regFromSelect = dest.iSdst;
    assert( db->pParse==pParse );
    if( rc || pParse->nErr ) goto insert_cleanup;
    assert( db->mallocFailed==0 );
    sqlite3VdbeEndCoroutine(v, regYield);
    sqlite3VdbeJumpHere(v, addrTop - 1);                       /* label B: */
    assert( pSelect->pEList );
    nColumn = pSelect->pEList->nExpr;
      int regYield = ++pParse->nMem;
      addrTop = sqlite3VdbeCurrentAddr(v) + 1;
      sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
      dest.iSdst = bIdListInOrder ? regData : 0;
      dest.nSdst = pTab->nCol;
      rc = sqlite3Select(pParse, pSelect, &dest);
      regFromSelect = dest.iSdst;
      assert( db->pParse==pParse );
      if( rc || pParse->nErr ) goto insert_cleanup;
      assert( db->mallocFailed==0 );
      sqlite3VdbeEndCoroutine(v, regYield);
      sqlite3VdbeJumpHere(v, addrTop - 1);                       /* label B: */
      assert( pSelect->pEList );
      nColumn = pSelect->pEList->nExpr;
    }

    /* Set useTempTable to TRUE if the result of the SELECT statement
    ** should be written into a temporary table (template 4).  Set to
    ** FALSE if each output row of the SELECT can be written directly into
    ** the destination table (template 3).
    **
    ** A temp table must be used if the table being updated is also one
1082
1083
1084
1085
1086
1087
1088
1089

1090
1091
1092
1093
1094
1095
1096
1284
1285
1286
1287
1288
1289
1290

1291
1292
1293
1294
1295
1296
1297
1298







-
+







    pNx = pUpsert;
    do{
      pNx->pUpsertSrc = pTabList;
      pNx->regData = regData;
      pNx->iDataCur = iDataCur;
      pNx->iIdxCur = iIdxCur;
      if( pNx->pUpsertTarget ){
        if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
        if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){
          goto insert_cleanup;
        }
      }
      pNx = pNx->pNextUpsert;
    }while( pNx!=0 );
  }
#endif
Changes to src/json.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
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












-
+




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




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



-
+




















-
+


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







/*
** 2015-08-12
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This SQLite JSON functions.
** SQLite JSON functions.
**
** This file began as an extension in ext/misc/json1.c in 2015.  That
** extension proved so useful that it has now been moved into the core.
**
** For the time being, all JSON is stored as pure text.  (We might add
** a JSONB type in the future which stores a binary encoding of JSON in
** a BLOB, but there is no support for JSONB in the current implementation.
** This implementation parses JSON text at 250 MB/s, so it is hard to see
** how JSONB might improve on that.)
** The original design stored all JSON as pure text, canonical RFC-8259.
** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16).
** All generated JSON text still conforms strictly to RFC-8259, but text
** with JSON-5 extensions is accepted as input.
**
** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
** accept BLOB values that have JSON encoded using a binary representation
** called "JSONB".  The name JSONB comes from PostgreSQL, however the on-disk
** format SQLite JSONB is completely different and incompatible with
** PostgreSQL JSONB.
**
** Decoding and interpreting JSONB is still O(N) where N is the size of
** the input, the same as text JSON.  However, the constant of proportionality
** for JSONB is much smaller due to faster parsing.  The size of each
** element in JSONB is encoded in its header, so there is no need to search
** for delimiters using persnickety syntax rules.  JSONB seems to be about
** 3x faster than text JSON as a result.  JSONB is also tends to be slightly
** smaller than text JSON, by 5% or 10%, but there are corner cases where
** JSONB can be slightly larger.  So you are not far mistaken to say that
** a JSONB blob is the same size as the equivalent RFC-8259 text.
**
**
** THE JSONB ENCODING:
**
** Every JSON element is encoded in JSONB as a header and a payload.
** The header is between 1 and 9 bytes in size.  The payload is zero
** or more bytes.
**
** The lower 4 bits of the first byte of the header determines the
** element type:
**
**    0:   NULL
**    1:   TRUE
**    2:   FALSE
**    3:   INT        -- RFC-8259 integer literal
**    4:   INT5       -- JSON5 integer literal
**    5:   FLOAT      -- RFC-8259 floating point literal
**    6:   FLOAT5     -- JSON5 floating point literal
**    7:   TEXT       -- Text literal acceptable to both SQL and JSON
**    8:   TEXTJ      -- Text containing RFC-8259 escapes
**    9:   TEXT5      -- Text containing JSON5 and/or RFC-8259 escapes
**   10:   TEXTRAW    -- Text containing unescaped syntax characters
**   11:   ARRAY
**   12:   OBJECT
**
** The other three possible values (13-15) are reserved for future
** enhancements.
**
** The upper 4 bits of the first byte determine the size of the header
** and sometimes also the size of the payload.  If X is the first byte
** of the element and if X>>4 is between 0 and 11, then the payload
** will be that many bytes in size and the header is exactly one byte
** in size.  Other four values for X>>4 (12-15) indicate that the header
** is more than one byte in size and that the payload size is determined
** by the remainder of the header, interpreted as a unsigned big-endian
** integer.
**
**   Value of X>>4         Size integer        Total header size
**   -------------     --------------------    -----------------
**        12           1 byte (0-255)                2
**        13           2 byte (0-65535)              3
**        14           4 byte (0-4294967295)         5
**        15           8 byte (0-1.8e19)             9
**
** The payload size need not be expressed in its minimal form.  For example,
** if the payload size is 10, the size can be expressed in any of 5 different
** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
** a single byte of 0x0a.  The shorter forms are preferred, of course, but
** sometimes when generating JSONB, the payload size is not known in advance
** and it is convenient to reserve sufficient header space to cover the
** largest possible payload size and then come back later and patch up
** the size when it becomes known, resulting in a non-minimal encoding.
**
** The value (X>>4)==15 is not actually used in the current implementation
** (as SQLite is currently unable handle BLOBs larger than about 2GB)
** but is included in the design to allow for future enhancements.
**
** The payload follows the header.  NULL, TRUE, and FALSE have no payload and
** their payload size must always be zero.  The payload for INT, INT5,
** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text.  Note that the
** "..." or '...' delimiters are omitted from the various text encodings.
** The payload for ARRAY and OBJECT is a list of additional elements that
** are the content for the array or object.  The payload for an OBJECT
** must be an even number of elements.  The first element of each pair is
** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW.
**
** A valid JSONB blob consists of a single element, as described above.
** Usually this will be an ARRAY or OBJECT element which has many more
** elements as its content.  But the overall blob is just a single element.
**
** Input validation for JSONB blobs simply checks that the element type
** code is between 0 and 12 and that the total size of the element
** (header plus payload) is the same as the size of the BLOB.  If those
** checks are true, the BLOB is assumed to be JSONB and processing continues.
** Errors are only raised if some other miscoding is discovered during
** processing.
**
** Additional information can be found in the doc/jsonb.md file of the
** canonical SQLite source tree.
*/
#ifndef SQLITE_OMIT_JSON
#include "sqliteInt.h"

/* JSONB element types
*/
#define JSONB_NULL     0   /* "null" */
#define JSONB_TRUE     1   /* "true" */
#define JSONB_FALSE    2   /* "false" */
#define JSONB_INT      3   /* integer acceptable to JSON and SQL */
#define JSONB_INT5     4   /* integer in 0x000 notation */
#define JSONB_FLOAT    5   /* float acceptable to JSON and SQL */
#define JSONB_FLOAT5   6   /* float with JSON5 extensions */
#define JSONB_TEXT     7   /* Text compatible with both JSON and SQL */
#define JSONB_TEXTJ    8   /* Text with JSON escapes */
#define JSONB_TEXT5    9   /* Text with JSON-5 escape */
#define JSONB_TEXTRAW 10   /* SQL text that needs escaping for JSON */
#define JSONB_ARRAY   11   /* An array */
#define JSONB_OBJECT  12   /* An object */

/* Human-readable names for the JSONB values.  The index for each
** string must correspond to the JSONB_* integer above.
*/
static const char * const jsonbType[] = {
  "null", "true", "false", "integer", "integer", 
  "real", "real", "text",  "text",    "text",
  "text", "array", "object", "", "", "", ""
};

/*
** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function, resulting in a 7% overall performance
** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
** increase for the text-JSON parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/
static const char jsonIsSpace[] = {
  0, 0, 0, 0, 0, 0, 0, 0,  0, 1, 1, 0, 0, 1, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,

  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
};
#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])

/*
** The set of all space characters recognized by jsonIsspace().
** Useful as the second argument to strspn().
*/
static const char jsonSpaces[] = "\011\012\015\040";

/*
** Characters that are special to JSON.  Control charaters,
** '"' and '\\'.
** Characters that are special to JSON.  Control characters,
** '"' and '\\' and '\''.  Actually, '\'' is not special to
** canonical JSON, but it is special in JSON-5, so we include
** it in the set of special characters.
*/
static const char jsonIsOk[256] = {
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 0, 1, 1, 1, 1, 0,  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86


87


























88





89
90
91
92




93
94
95
96
97
98
99
100

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

113
114
115
116
117
118



119
120
121
122
123
124
125



126
127
128
129
130
131
132
133
134
135
136


137
138
139
140
141


142
143
144
145



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

170
171
172
173



174
175
176
177
178
179




180
181
182
183
184
185
186
187
188
189
190



191
192
193
194
195
196
197
198
199








200
201
202
203
204
205
206
207
208




209
210
211
212



213
214






215
216
217
218
219
220
221

222




223






224





























































































































225
226
227
228


229
230

231
232
233
234
235
236
237
238
239

240
241
242


243
244
245
246
247
248

249
250

251
252
253
254
255
256
257
258




259
260
261
262
263
264

265
266
267
268

269
270
271

272
273
274
275
276
277
278
279
280
281


282
283
284
285
286
287
288
289
290
291

292
293
294
295
296
297

298
299
300
301
302
303
304

305
306
307
308
309
310
311
312
313

314
315
316
317
318
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334
335

336
337
338
339
340
341
342
343
344
345








346



347
348
349
350
351

352
353
354
355
356
357
358

359
360

361
362
363
364
365
366
367
368
369
370
371
372
373
374


































375
376
377


378



379
380
381
382





383
384
385
386
387
388












































389
390

391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
408
409
410


411
412

413
414
415
416
417
418

419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489

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

557
558

559
560
561
562
563
564
565
199
200
201
202
203
204
205







206


207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

256
257
258
259









260






261
262
263





264

265
266
267
268
269
270








271
272
273




274
275




276
277
278
279





















280

281

282


283
284
285
286





287
288
289
290
291










292
293
294
295
296







297
298
299
300
301
302
303
304
305
306
307
308
309




310
311
312
313




314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

473
474
475

476
477
478
479
480
481
482
483
484

485
486


487
488
489
490
491
492
493

494
495

496
497
498
499
500




501
502
503
504
505
506
507
508
509

510
511
512
513

514
515
516

517
518
519
520
521
522
523
524
525


526
527
528
529
530
531
532
533
534
535
536

537
538
539
540
541
542

543
544
545
546
547
548
549

550
551
552
553
554
555
556
557
558

559
560
561
562
563
564
565

566
567
568
569

570
571
572
573
574
575
576
577
578
579

580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665


666
667
668
669
670
671





672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715


716
717
718
719
720
721

722














723
724


725






726
727
728
729
730
731
732

































































733



































































734
735

736
737
738
739
740
741
742
743







-
-
-
-
-
-
-

-
-
+
+

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




+
+
+
+







-
+



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

-
+
+
+



-
-
-
-
-
-
-
-
+
+

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

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

-
+
-

-
-
+
+
+

-
-
-
-
-
+
+
+
+

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


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





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


+
+
+
+
+
+







+
-
+
+
+
+

+
+
+
+
+
+

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



-
+
+

-
+








-
+

-
-
+
+





-
+

-
+




-
-
-
-
+
+
+
+





-
+



-
+


-
+








-
-
+
+









-
+





-
+






-
+








-
+






-




-
+









-
+










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




-
+

-
-
-
-
-
-
+
-
-
+

-












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

-
-
+
+

+
+
+


-
-
+
+
+
+
+

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





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






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

-
+







  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1
};


#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
#  define VVA(X)
#else
#  define VVA(X) X
#endif

/* Objects */
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
typedef struct JsonCache JsonCache;
typedef struct JsonString JsonString;
typedef struct JsonParse JsonParse;

/*
** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
*/
#define JSON_CACHE_ID    (-429938)  /* Cache entry */
#define JSON_CACHE_SIZE  4          /* Max number of cache entries */

/*
** jsonUnescapeOneChar() returns this invalid code point if it encounters
** a syntax error.
*/
#define JSON_INVALID_CHAR 0x99999

/* A cache mapping JSON text into JSONB blobs.
**
** Each cache entry is a JsonParse object with the following restrictions:
**
**    *   The bReadOnly flag must be set
**
**    *   The aBlob[] array must be owned by the JsonParse object.  In other
**        words, nBlobAlloc must be non-zero.
**
**    *   eEdit and delta must be zero.
**
**    *   zJson must be an RCStr.  In other words bJsonIsRCStr must be true.
*/
typedef struct JsonCleanup JsonCleanup;
struct JsonCache {
  sqlite3 *db;                    /* Database connection */
  int nUsed;                      /* Number of active entries in the cache */
  JsonParse *a[JSON_CACHE_SIZE];  /* One line for each cache entry */
};

/* An instance of this object represents a JSON string
** under construction.  Really, this is a generic string accumulator
** that can be and is used to create strings other than JSON.
**
** If the generated string is longer than will fit into the zSpace[] buffer,
** then it will be an RCStr string.  This aids with caching of large
** JSON strings.
*/
struct JsonString {
  sqlite3_context *pCtx;   /* Function context - put error messages here */
  char *zBuf;              /* Append JSON content here */
  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
  u64 nUsed;               /* Bytes of zBuf[] currently used */
  u8 bStatic;              /* True if zBuf is static space */
  u8 bErr;                 /* True if an error has been encountered */
  u8 eErr;                 /* True if an error has been encountered */
  char zSpace[100];        /* Initial static space */
};

/* A deferred cleanup task.  A list of JsonCleanup objects might be
** run when the JsonParse object is destroyed.
*/
struct JsonCleanup {
  JsonCleanup *pJCNext;    /* Next in a list */
  void (*xOp)(void*);      /* Routine to run */
  void *pArg;              /* Argument to xOp() */
};

/* Allowed values for JsonString.eErr */
/* JSON type values
*/
#define JSON_SUBST    0    /* Special edit node.  Uses u.iPrev */
#define JSON_NULL     1
#define JSON_TRUE     2
#define JSON_FALSE    3
#define JSTRING_OOM         0x01   /* Out of memory */
#define JSTRING_MALFORMED   0x02   /* Malformed JSONB */
#define JSTRING_ERR         0x04   /* Error already sent to sqlite3_result */
#define JSON_INT      4
#define JSON_REAL     5
#define JSON_STRING   6
#define JSON_ARRAY    7
#define JSON_OBJECT   8

/* The "subtype" set for JSON values */
/* The "subtype" set for text JSON values passed through using
** sqlite3_result_subtype() and sqlite3_value_subtype().
*/
#define JSON_SUBTYPE  74    /* Ascii for "J" */

/*
** Names of the various JSON types:
*/
static const char * const jsonType[] = {
  "subst",
  "null", "true", "false", "integer", "real", "text", "array", "object"
};

/* Bit values for the JsonNode.jnFlag field
** Bit values for the flags passed into various SQL function implementations
** via the sqlite3_user_data() value.
*/
#define JNODE_RAW     0x01  /* Content is raw, not JSON encoded */
#define JNODE_ESCAPE  0x02  /* Content is text with \ escapes */
#define JNODE_REMOVE  0x04  /* Do not output */
#define JNODE_REPLACE 0x08  /* Target of a JSON_SUBST node */
#define JSON_JSON      0x01        /* Result is always JSON */
#define JSON_SQL       0x02        /* Result is always SQL */
#define JNODE_APPEND  0x10  /* More ARRAY/OBJECT entries at u.iAppend */
#define JNODE_LABEL   0x20  /* Is a label of an object */
#define JNODE_JSON5   0x40  /* Node contains JSON5 enhancements */

#define JSON_ABPATH    0x03        /* Allow abbreviated JSON path specs */
#define JSON_ISSET     0x04        /* json_set(), not json_insert() */
#define JSON_BLOB      0x08        /* Use the BLOB output format */

/* A single node of parsed JSON.  An array of these nodes describes
** a parse of JSON + edits.
**
** Use the json_parse() SQL function (available when compiled with
** -DSQLITE_DEBUG) to see a dump of complete JsonParse objects, including
** a complete listing and decoding of the array of JsonNodes.
*/
struct JsonNode {
  u8 eType;              /* One of the JSON_ type values */
  u8 jnFlags;            /* JNODE flags */
  u8 eU;                 /* Which union element to use */
  u32 n;                 /* Bytes of content for INT, REAL or STRING
                         ** Number of sub-nodes for ARRAY and OBJECT
                         ** Node that SUBST applies to */
  union {
    const char *zJContent; /* 1: Content for INT, REAL, and STRING */
    u32 iAppend;           /* 2: More terms for ARRAY and OBJECT */
    u32 iKey;              /* 3: Key for ARRAY objects in json_tree() */
    u32 iPrev;             /* 4: Previous SUBST node, or 0 */
  } u;
};


/* A parsed JSON value.  Lifecycle:
/* A parsed and possibly edited JSON string.  Lifecycle:
**
**   1.  JSON comes in and is parsed into an array aNode[].  The original
**       JSON text is stored in zJson.
**   1.  JSON comes in and is parsed into a JSONB value in aBlob.  The
**       original text is stored in zJson.  This step is skipped if the
**       input is JSONB instead of text JSON.
**
**   2.  Zero or more changes are made (via json_remove() or json_replace()
**       or similar) to the aNode[] array.
**
**   3.  A new, edited and mimified JSON string is generated from aNode
**       and stored in zAlt.  The JsonParse object always owns zAlt.
**   2.  The aBlob[] array is searched using the JSON path notation, if needed.
**       
**   3.  Zero or more changes are made to aBlob[] (via json_remove() or
**       json_replace() or json_patch() or similar).
**
** Step 1 always happens.  Step 2 and 3 may or may not happen, depending
** on the operation.
**
** aNode[].u.zJContent entries typically point into zJson.  Hence zJson
** must remain valid for the lifespan of the parse.  For edits,
** aNode[].u.zJContent might point to malloced space other than zJson.
** Entries in pClup are responsible for freeing that extra malloced space.
**
** When walking the parse tree in aNode[], edits are ignored if useMod is
** false.
**   4.  New JSON text is generated from the aBlob[] for output.  This step
**       is skipped if the function is one of the jsonb_* functions that
**       returns JSONB instead of text JSON.
*/
struct JsonParse {
  u32 nNode;         /* Number of slots of aNode[] used */
  u32 nAlloc;        /* Number of slots of aNode[] allocated */
  JsonNode *aNode;   /* Array of nodes containing the parse */
  char *zJson;       /* Original JSON string (before edits) */
  char *zAlt;        /* Revised and/or mimified JSON */
  u32 *aUp;          /* Index of parent of each node */
  JsonCleanup *pClup;/* Cleanup operations prior to freeing this object */
  u8 *aBlob;         /* JSONB representation of JSON value */
  u32 nBlob;         /* Bytes of aBlob[] actually used */
  u32 nBlobAlloc;    /* Bytes allocated to aBlob[].  0 if aBlob is external */
  char *zJson;       /* Json text used for parsing */
  sqlite3 *db;       /* The database connection to which this object belongs */
  int nJson;         /* Length of the zJson string in bytes */
  u32 nJPRef;        /* Number of references to this object */
  u32 iErr;          /* Error location in zJson[] */
  u16 iDepth;        /* Nesting depth */
  u8 nErr;           /* Number of errors seen */
  u8 oom;            /* Set to true if out of memory */
  u8 bJsonIsRCStr;   /* True if zJson is an RCStr */
  u8 hasNonstd;      /* True if input uses non-standard features like JSON5 */
  u8 useMod;         /* Actually use the edits contain inside aNode */
  u8 hasMod;         /* aNode contains edits from the original zJson */
  u32 nJPRef;        /* Number of references to this object */
  int nJson;         /* Length of the zJson string in bytes */
  u8 bReadOnly;      /* Do not modify. */
  /* Search and edit information.  See jsonLookupStep() */
  u8 eEdit;          /* Edit operation to apply */
  int delta;         /* Size change due to the edit */
  int nAlt;          /* Length of alternative JSON string zAlt, in bytes */
  u32 iErr;          /* Error location in zJson[] */
  u32 iSubst;        /* Last JSON_SUBST entry in aNode[] */
  u32 iHold;         /* Age of this entry in the cache for LRU replacement */
  u32 nIns;          /* Number of bytes to insert */
  u32 iLabel;        /* Location of label if search landed on an object value */
  u8 *aIns;          /* Content to be inserted */
};

/* Allowed values for JsonParse.eEdit */
#define JEDIT_DEL   1   /* Delete if exists */
#define JEDIT_REPL  2   /* Overwrite if exists */
#define JEDIT_INS   3   /* Insert if not exists */
#define JEDIT_SET   4   /* Insert or overwrite */

/*
** Maximum nesting depth of JSON for this implementation.
**
** This limit is needed to avoid a stack overflow in the recursive
** descent parser.  A depth of 1000 is far deeper than any sane JSON
** should go.  Historical note: This limit was 2000 prior to version 3.42.0
*/
#ifndef SQLITE_JSON_MAX_DEPTH
#define JSON_MAX_DEPTH  1000
# define JSON_MAX_DEPTH  1000
#else
# define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH
#endif

/*
** Allowed values for the flgs argument to jsonParseFuncArg();
*/
#define JSON_EDITABLE  0x01   /* Generate a writable JsonParse object */
#define JSON_KEEPERROR 0x02   /* Return non-NULL even if there is an error */

/**************************************************************************
** Forward references
**************************************************************************/
static void jsonReturnStringAsBlob(JsonString*);
static int jsonFuncArgMightBeBinary(sqlite3_value *pJson);
static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
static void jsonReturnParse(sqlite3_context*,JsonParse*);
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
static void jsonParseFree(JsonParse*);
static u32 jsonbPayloadSize(const JsonParse*, u32, u32*);
static u32 jsonUnescapeOneChar(const char*, u32, u32*);

/**************************************************************************
** Utility routines for dealing with JsonCache objects
**************************************************************************/

/*
** Free a JsonCache object.
*/
static void jsonCacheDelete(JsonCache *p){
  int i;
  for(i=0; i<p->nUsed; i++){
    jsonParseFree(p->a[i]);
  }
  sqlite3DbFree(p->db, p);
}
static void jsonCacheDeleteGeneric(void *p){
  jsonCacheDelete((JsonCache*)p);
}

/*
** Insert a new entry into the cache.  If the cache is full, expel
** the least recently used entry.  Return SQLITE_OK on success or a
** result code otherwise.
**
** Cache entries are stored in age order, oldest first.
*/
static int jsonCacheInsert(
  sqlite3_context *ctx,   /* The SQL statement context holding the cache */
  JsonParse *pParse       /* The parse object to be added to the cache */
){
  JsonCache *p;

  assert( pParse->zJson!=0 );
  assert( pParse->bJsonIsRCStr );
  assert( pParse->delta==0 );
  p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
  if( p==0 ){
    sqlite3 *db = sqlite3_context_db_handle(ctx);
    p = sqlite3DbMallocZero(db, sizeof(*p));
    if( p==0 ) return SQLITE_NOMEM;
    p->db = db;
    sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric);
    p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
    if( p==0 ) return SQLITE_NOMEM;
  }
  if( p->nUsed >= JSON_CACHE_SIZE ){
    jsonParseFree(p->a[0]);
    memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0]));
    p->nUsed = JSON_CACHE_SIZE-1;
  }
  assert( pParse->nBlobAlloc>0 );
  pParse->eEdit = 0;
  pParse->nJPRef++;
  pParse->bReadOnly = 1;
  p->a[p->nUsed] = pParse;
  p->nUsed++;
  return SQLITE_OK;
}

/*
** Search for a cached translation the json text supplied by pArg.  Return
** the JsonParse object if found.  Return NULL if not found.
**
** When a match if found, the matching entry is moved to become the
** most-recently used entry if it isn't so already.
**
** The JsonParse object returned still belongs to the Cache and might
** be deleted at any moment.  If the caller whants the JsonParse to
** linger, it needs to increment the nPJRef reference counter.
*/
static JsonParse *jsonCacheSearch(
  sqlite3_context *ctx,    /* The SQL statement context holding the cache */
  sqlite3_value *pArg      /* Function argument containing SQL text */
){
  JsonCache *p;
  int i;
  const char *zJson;
  int nJson;

  if( sqlite3_value_type(pArg)!=SQLITE_TEXT ){
    return 0;
  }
  zJson = (const char*)sqlite3_value_text(pArg);
  if( zJson==0 ) return 0;
  nJson = sqlite3_value_bytes(pArg);

  p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
  if( p==0 ){
    return 0;
  }
  for(i=0; i<p->nUsed; i++){
    if( p->a[i]->zJson==zJson ) break;
  }
  if( i>=p->nUsed ){
    for(i=0; i<p->nUsed; i++){
      if( p->a[i]->nJson!=nJson ) continue;
      if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break;
    }
  }
  if( i<p->nUsed ){
    if( i<p->nUsed-1 ){
      /* Make the matching entry the most recently used entry */
      JsonParse *tmp = p->a[i];
      memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp));
      p->a[p->nUsed-1] = tmp;
      i = p->nUsed - 1;
    }
    assert( p->a[i]->delta==0 );
    return p->a[i];
  }else{
    return 0;
  }
}

/**************************************************************************
** Utility routines for dealing with JsonString objects
**************************************************************************/

/* Set the JsonString object to an empty string
/* Turn uninitialized bulk memory into a valid JsonString object
** holding a zero-length string.
*/
static void jsonZero(JsonString *p){
static void jsonStringZero(JsonString *p){
  p->zBuf = p->zSpace;
  p->nAlloc = sizeof(p->zSpace);
  p->nUsed = 0;
  p->bStatic = 1;
}

/* Initialize the JsonString object
*/
static void jsonInit(JsonString *p, sqlite3_context *pCtx){
static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){
  p->pCtx = pCtx;
  p->bErr = 0;
  jsonZero(p);
  p->eErr = 0;
  jsonStringZero(p);
}

/* Free all allocated memory and reset the JsonString object back to its
** initial state.
*/
static void jsonReset(JsonString *p){
static void jsonStringReset(JsonString *p){
  if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf);
  jsonZero(p);
  jsonStringZero(p);
}

/* Report an out-of-memory (OOM) condition
*/
static void jsonOom(JsonString *p){
  p->bErr = 1;
  sqlite3_result_error_nomem(p->pCtx);
  jsonReset(p);
static void jsonStringOom(JsonString *p){
  p->eErr |= JSTRING_OOM;
  if( p->pCtx ) sqlite3_result_error_nomem(p->pCtx);
  jsonStringReset(p);
}

/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
** Return zero on success.  Return non-zero on an OOM error
*/
static int jsonGrow(JsonString *p, u32 N){
static int jsonStringGrow(JsonString *p, u32 N){
  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
  char *zNew;
  if( p->bStatic ){
    if( p->bErr ) return 1;
    if( p->eErr ) return 1;
    zNew = sqlite3RCStrNew(nTotal);
    if( zNew==0 ){
      jsonOom(p);
      jsonStringOom(p);
      return SQLITE_NOMEM;
    }
    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
    p->zBuf = zNew;
    p->bStatic = 0;
  }else{
    p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal);
    if( p->zBuf==0 ){
      p->bErr = 1;
      jsonZero(p);
      p->eErr |= JSTRING_OOM;
      jsonStringZero(p);
      return SQLITE_NOMEM;
    }
  }
  p->nAlloc = nTotal;
  return SQLITE_OK;
}

/* Append N bytes from zIn onto the end of the JsonString string.
*/
static SQLITE_NOINLINE void jsonAppendExpand(
static SQLITE_NOINLINE void jsonStringExpandAndAppend(
  JsonString *p,
  const char *zIn,
  u32 N
){
  assert( N>0 );
  if( jsonGrow(p,N) ) return;
  if( jsonStringGrow(p,N) ) return;
  memcpy(p->zBuf+p->nUsed, zIn, N);
  p->nUsed += N;
}
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
  if( N==0 ) return;
  if( N+p->nUsed >= p->nAlloc ){
    jsonAppendExpand(p,zIn,N);
    jsonStringExpandAndAppend(p,zIn,N);
  }else{
    memcpy(p->zBuf+p->nUsed, zIn, N);
    p->nUsed += N;
  }
}
static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
  assert( N>0 );
  if( N+p->nUsed >= p->nAlloc ){
    jsonAppendExpand(p,zIn,N);
    jsonStringExpandAndAppend(p,zIn,N);
  }else{
    memcpy(p->zBuf+p->nUsed, zIn, N);
    p->nUsed += N;
  }
}


/* Append formatted text (not to exceed N bytes) to the JsonString.
*/
static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
  va_list ap;
  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
  if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return;
  va_start(ap, zFormat);
  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
  va_end(ap);
  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
}

/* Append a single character
*/
static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
  if( jsonGrow(p,1) ) return;
  if( jsonStringGrow(p,1) ) return;
  p->zBuf[p->nUsed++] = c;
}
static void jsonAppendChar(JsonString *p, char c){
  if( p->nUsed>=p->nAlloc ){
    jsonAppendCharExpand(p,c);
  }else{
    p->zBuf[p->nUsed++] = c;
  }
}

/* Remove a single character from the end of the string
*/
static void jsonStringTrimOneChar(JsonString *p){
  if( p->eErr==0 ){
    assert( p->nUsed>0 );
    p->nUsed--;
  }
}
/* Try to force the string to be a zero-terminated RCStr string.


/* Make sure there is a zero terminator on p->zBuf[]
**
** Return true on success.  Return false if an OOM prevents this
** from happening.
*/
static int jsonForceRCStr(JsonString *p){
static int jsonStringTerminate(JsonString *p){
  jsonAppendChar(p, 0);
  if( p->bErr ) return 0;
  p->nUsed--;
  if( p->bStatic==0 ) return 1;
  p->nAlloc = 0;
  p->nUsed++;
  jsonGrow(p, p->nUsed);
  jsonStringTrimOneChar(p);
  p->nUsed--;
  return p->bStatic==0;
  return p->eErr==0;
}


/* Append a comma separator to the output buffer, if the previous
** character is not '[' or '{'.
*/
static void jsonAppendSeparator(JsonString *p){
  char c;
  if( p->nUsed==0 ) return;
  c = p->zBuf[p->nUsed-1];
  if( c=='[' || c=='{' ) return;
  jsonAppendChar(p, ',');
}

/* c is a control character.  Append the canonical JSON representation
** of that control character to p.
**
** This routine assumes that the output buffer has already been enlarged
** sufficiently to hold the worst-case encoding plus a nul terminator.
*/
static void jsonAppendControlChar(JsonString *p, u8 c){
  static const char aSpecial[] = {
     0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0,   0,   0, 0, 0
  };
  assert( sizeof(aSpecial)==32 );
  assert( aSpecial['\b']=='b' );
  assert( aSpecial['\f']=='f' );
  assert( aSpecial['\n']=='n' );
  assert( aSpecial['\r']=='r' );
  assert( aSpecial['\t']=='t' );
  assert( c>=0 && c<sizeof(aSpecial) );
  assert( p->nUsed+7 <= p->nAlloc );
  if( aSpecial[c] ){
    p->zBuf[p->nUsed] = '\\';
    p->zBuf[p->nUsed+1] = aSpecial[c];
    p->nUsed += 2;
  }else{
    p->zBuf[p->nUsed] = '\\';
    p->zBuf[p->nUsed+1] = 'u';
    p->zBuf[p->nUsed+2] = '0';
    p->zBuf[p->nUsed+3] = '0';
    p->zBuf[p->nUsed+4] = "0123456789abcdef"[c>>4];
    p->zBuf[p->nUsed+5] = "0123456789abcdef"[c&0xf];
    p->nUsed += 6;
  }
}

/* Append the N-byte string in zIn to the end of the JsonString string
** under construction.  Enclose the string in "..." and escape
** any double-quotes or backslash characters contained within the
** under construction.  Enclose the string in double-quotes ("...") and
** escape any double-quotes or backslash characters contained within the
** string.
**
** This routine is a high-runner.  There is a measurable performance
** increase associated with unwinding the jsonIsOk[] loop.
*/
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
  u32 i;
  if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return;
  u32 k;
  u8 c;
  const u8 *z = (const u8*)zIn;
  if( z==0 ) return;
  if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return;
  p->zBuf[p->nUsed++] = '"';
  for(i=0; i<N; i++){
    unsigned char c = ((unsigned const char*)zIn)[i];
    if( jsonIsOk[c] ){
      p->zBuf[p->nUsed++] = c;
    }else if( c=='"' || c=='\\' ){
  while( 1 /*exit-by-break*/ ){
    k = 0;
    /* The following while() is the 4-way unwound equivalent of
    **
    **     while( k<N && jsonIsOk[z[k]] ){ k++; }
    */
    while( 1 /* Exit by break */ ){
      if( k+3>=N ){
        while( k<N && jsonIsOk[z[k]] ){ k++; }
        break;
      }
      if( !jsonIsOk[z[k]] ){
        break;
      }
      if( !jsonIsOk[z[k+1]] ){
        k += 1;
        break;
      }
      if( !jsonIsOk[z[k+2]] ){
        k += 2;
        break;
      }
      if( !jsonIsOk[z[k+3]] ){
        k += 3;
        break;
      }else{
        k += 4;
      }
    }
    if( k>=N ){
      if( k>0 ){
        memcpy(&p->zBuf[p->nUsed], z, k);
        p->nUsed += k;
      }
      break;
    }
    if( k>0 ){
      memcpy(&p->zBuf[p->nUsed], z, k);
      p->nUsed += k;
      z += k;
      N -= k;
    }
    c = z[0];
    if( c=='"' || c=='\\' ){
      json_simple_escape:
      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
      if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return;
      p->zBuf[p->nUsed++] = '\\';
      p->zBuf[p->nUsed++] = c;
    }else if( c=='\'' ){
      p->zBuf[p->nUsed++] = c;
    }else{
      static const char aSpecial[] = {
      if( (p->nUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return;
         0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0,   0,   0, 0, 0
      };
      assert( sizeof(aSpecial)==32 );
      assert( aSpecial['\b']=='b' );
      assert( aSpecial['\f']=='f' );
      assert( aSpecial['\n']=='n' );
      assert( aSpecial['\r']=='r' );
      assert( aSpecial['\t']=='t' );
      assert( c>=0 && c<sizeof(aSpecial) );
      if( aSpecial[c] ){
        c = aSpecial[c];
        goto json_simple_escape;
      }
      jsonAppendControlChar(p, c);
    }
      if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
      p->zBuf[p->nUsed++] = '\\';
    z++;
      p->zBuf[p->nUsed++] = 'u';
      p->zBuf[p->nUsed++] = '0';
      p->zBuf[p->nUsed++] = '0';
      p->zBuf[p->nUsed++] = "0123456789abcdef"[c>>4];
      p->zBuf[p->nUsed++] = "0123456789abcdef"[c&0xf];
    }
    N--;
  }
  p->zBuf[p->nUsed++] = '"';
  assert( p->nUsed<p->nAlloc );
}

/*
** The zIn[0..N] string is a JSON5 string literal.  Append to p a translation
** of the string literal that standard JSON and that omits all JSON5
** features.
*/
static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
  u32 i;
  jsonAppendChar(p, '"');
  zIn++;
  N -= 2;
  while( N>0 ){
    for(i=0; i<N && zIn[i]!='\\' && zIn[i]!='"'; i++){}
    if( i>0 ){
      jsonAppendRawNZ(p, zIn, i);
      zIn += i;
      N -= i;
      if( N==0 ) break;
    }
    if( zIn[0]=='"' ){
      jsonAppendRawNZ(p, "\\\"", 2);
      zIn++;
      N--;
      continue;
    }
    assert( zIn[0]=='\\' );
    switch( (u8)zIn[1] ){
      case '\'':
        jsonAppendChar(p, '\'');
        break;
      case 'v':
        jsonAppendRawNZ(p, "\\u0009", 6);
        break;
      case 'x':
        jsonAppendRawNZ(p, "\\u00", 4);
        jsonAppendRawNZ(p, &zIn[2], 2);
        zIn += 2;
        N -= 2;
        break;
      case '0':
        jsonAppendRawNZ(p, "\\u0000", 6);
        break;
      case '\r':
        if( zIn[2]=='\n' ){
          zIn++;
          N--;
        }
        break;
      case '\n':
        break;
      case 0xe2:
        assert( N>=4 );
        assert( 0x80==(u8)zIn[2] );
        assert( 0xa8==(u8)zIn[3] || 0xa9==(u8)zIn[3] );
        zIn += 2;
        N -= 2;
        break;
      default:
        jsonAppendRawNZ(p, zIn, 2);
        break;
    }
    zIn += 2;
    N -= 2;
  }
  jsonAppendChar(p, '"');
}

** Append an sqlite3_value (such as a function parameter) to the JSON
/*
** The zIn[0..N] string is a JSON5 integer literal.  Append to p a translation
** of the string literal that standard JSON and that omits all JSON5
** features.
*/
static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
  if( zIn[0]=='+' ){
    zIn++;
    N--;
  }else if( zIn[0]=='-' ){
    jsonAppendChar(p, '-');
    zIn++;
    N--;
  }
  if( zIn[0]=='0' && (zIn[1]=='x' || zIn[1]=='X') ){
    sqlite3_int64 i = 0;
    int rc = sqlite3DecOrHexToI64(zIn, &i);
    if( rc<=1 ){
      jsonPrintf(100,p,"%lld",i);
    }else{
      assert( rc==2 );
      jsonAppendRawNZ(p, "9.0e999", 7);
    }
    return;
  }
  assert( N>0 );
  jsonAppendRawNZ(p, zIn, N);
}

/*
** The zIn[0..N] string is a JSON5 real literal.  Append to p a translation
** of the string literal that standard JSON and that omits all JSON5
** features.
*/
static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
  u32 i;
  if( zIn[0]=='+' ){
    zIn++;
    N--;
  }else if( zIn[0]=='-' ){
    jsonAppendChar(p, '-');
    zIn++;
    N--;
  }
  if( zIn[0]=='.' ){
    jsonAppendChar(p, '0');
  }
  for(i=0; i<N; i++){
    if( zIn[i]=='.' && (i+1==N || !sqlite3Isdigit(zIn[i+1])) ){
      i++;
      jsonAppendRaw(p, zIn, i);
      zIn += i;
      N -= i;
      jsonAppendChar(p, '0');
      break;
    }
  }
  if( N>0 ){
    jsonAppendRawNZ(p, zIn, N);
  }
}



/*
** Append a function parameter value to the JSON string under
** construction.
** string under construction in p.
*/
static void jsonAppendValue(
static void jsonAppendSqlValue(
  JsonString *p,                 /* Append to this JSON string */
  sqlite3_value *pValue          /* Value to append */
){
  switch( sqlite3_value_type(pValue) ){
    case SQLITE_NULL: {
      jsonAppendRawNZ(p, "null", 4);
      break;
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
661
662

663
664
665
666
667





668
669
670
671
672
673


674
675
676
677
678
679

680
681
682
683
684
685
686
687








688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
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
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
881





882
883
884
885
886
887
888
889
890
891
892
893
894
895




896
897
898
899
900
901
902




















































































































































































































































































903
904
905
906
907
908
909







+
+
+
+
+
+
-
+

-
-
+
+






-
-
+
+

-
+
+
+
+
+

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


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


-
-
-
+
+
+
+

+
+

-
+



-
+


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





-
-
-
-
-
-

-
-
-
-
-
-
-
-
-
-



+


-
-
-
+
+
+
+
+




-
-
+
+
-
-
-
-


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



-
-
+
+
+


-
-
-
-
-
+
+
+
+
+









-
-
-
-







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







        jsonAppendRaw(p, z, n);
      }else{
        jsonAppendString(p, z, n);
      }
      break;
    }
    default: {
      if( jsonFuncArgMightBeBinary(pValue) ){
        JsonParse px;
        memset(&px, 0, sizeof(px));
        px.aBlob = (u8*)sqlite3_value_blob(pValue);
        px.nBlob = sqlite3_value_bytes(pValue);
        jsonTranslateBlobToText(&px, 0, p);
      if( p->bErr==0 ){
      }else if( p->eErr==0 ){
        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
        p->bErr = 2;
        jsonReset(p);
        p->eErr = JSTRING_ERR;
        jsonStringReset(p);
      }
      break;
    }
  }
}


/* Make the JSON in p the result of the SQL function.
/* Make the text in p (which is probably a generated JSON text string)
** the result of the SQL function.
**
** The JSON string is reset.
** The JsonString is reset.
**
** If pParse and ctx are both non-NULL, then the SQL string in p is
** loaded into the zJson field of the pParse object as a RCStr and the
** pParse is added to the cache.
*/
static void jsonResult(JsonString *p){
  if( p->bErr==0 ){
    if( p->bStatic ){
static void jsonReturnString(
  JsonString *p,            /* String to return */
  JsonParse *pParse,        /* JSONB source or NULL */
  sqlite3_context *ctx      /* Where to cache */
){
  assert( (pParse!=0)==(ctx!=0) );
  assert( ctx==0 || ctx==p->pCtx );
  if( p->eErr==0 ){
    int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx));
    if( flags & JSON_BLOB ){
      jsonReturnStringAsBlob(p);
    }else if( p->bStatic ){
      sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
                            SQLITE_TRANSIENT, SQLITE_UTF8);
    }else if( jsonForceRCStr(p) ){
      sqlite3RCStrRef(p->zBuf);
      sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
    }else if( jsonStringTerminate(p) ){
      if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
        int rc;
        pParse->zJson = sqlite3RCStrRef(p->zBuf);
        pParse->nJson = p->nUsed;
        pParse->bJsonIsRCStr = 1;
        rc = jsonCacheInsert(ctx, pParse);
        if( rc==SQLITE_NOMEM ){
          sqlite3_result_error_nomem(ctx);
          jsonStringReset(p);
          return;
        }
      }
      sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed,
                            sqlite3RCStrUnref,
                            SQLITE_UTF8);
    }
  }
  if( p->bErr==1 ){
    }else{
      sqlite3_result_error_nomem(p->pCtx);
    }
  }else if( p->eErr & JSTRING_OOM ){
    sqlite3_result_error_nomem(p->pCtx);
  }else if( p->eErr & JSTRING_MALFORMED ){
    sqlite3_result_error(p->pCtx, "malformed JSON", -1);
  }
  jsonReset(p);
  jsonStringReset(p);
}

/**************************************************************************
** Utility routines for dealing with JsonNode and JsonParse objects
** Utility routines for dealing with JsonParse objects
**************************************************************************/

/*
** Return the number of consecutive JsonNode slots need to represent
** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
** OBJECT types, the number might be larger.
**
** Appended elements are not counted.  The value returned is the number
** by which the JsonNode counter should increment in order to go to the
** next peer value.
*/
static u32 jsonNodeSize(JsonNode *pNode){
  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
}

/*
** Reclaim all memory allocated by a JsonParse object.  But do not
** delete the JsonParse object itself.
*/
static void jsonParseReset(JsonParse *pParse){
  while( pParse->pClup ){
    JsonCleanup *pTask = pParse->pClup;
    pParse->pClup = pTask->pJCNext;
    pTask->xOp(pTask->pArg);
    sqlite3_free(pTask);
  }
  assert( pParse->nJPRef<=1 );
  if( pParse->aNode ){
    sqlite3_free(pParse->aNode);
    pParse->aNode = 0;
  }
  pParse->nNode = 0;
  pParse->nAlloc = 0;
  if( pParse->aUp ){
    sqlite3_free(pParse->aUp);
    pParse->aUp = 0;
  }
  if( pParse->bJsonIsRCStr ){
    sqlite3RCStrUnref(pParse->zJson);
    pParse->zJson = 0;
    pParse->nJson = 0;
    pParse->bJsonIsRCStr = 0;
  }
  if( pParse->zAlt ){
    sqlite3RCStrUnref(pParse->zAlt);
    pParse->zAlt = 0;
  if( pParse->nBlobAlloc ){
    sqlite3DbFree(pParse->db, pParse->aBlob);
    pParse->aBlob = 0;
    pParse->nBlob = 0;
    pParse->nBlobAlloc = 0;
  }
}

/*
** Free a JsonParse object that was obtained from sqlite3_malloc().
**
** Decrement the reference count on the JsonParse object.  When the
** count reaches zero, free the object.
** Note that destroying JsonParse might call sqlite3RCStrUnref() to
** destroy the zJson value.  The RCStr object might recursively invoke
** JsonParse to destroy this pParse object again.  Take care to ensure
** that this recursive destructor sequence terminates harmlessly.
*/
static void jsonParseFree(JsonParse *pParse){
  if( pParse ){
  if( pParse->nJPRef>1 ){
    pParse->nJPRef--;
  }else{
    jsonParseReset(pParse);
    sqlite3_free(pParse);
  }
}

    if( pParse->nJPRef>1 ){
      pParse->nJPRef--;
    }else{
      jsonParseReset(pParse);
      sqlite3DbFree(pParse->db, pParse);
    }
  }
}
/*
** Add a cleanup task to the JsonParse object.
**
** If an OOM occurs, the cleanup operation happens immediately
** and this function returns SQLITE_NOMEM.
*/
static int jsonParseAddCleanup(
  JsonParse *pParse,          /* Add the cleanup task to this parser */
  void(*xOp)(void*),          /* The cleanup task */
  void *pArg                  /* Argument to the cleanup */
){
  JsonCleanup *pTask = sqlite3_malloc64( sizeof(*pTask) );
  if( pTask==0 ){
    pParse->oom = 1;
    xOp(pArg);
    return SQLITE_ERROR;
  }
  pTask->pJCNext = pParse->pClup;
  pParse->pClup = pTask;
  pTask->xOp = xOp;
  pTask->pArg = pArg;
  return SQLITE_OK;
}

/*
** Convert the JsonNode pNode into a pure JSON string and
** append to pOut.  Subsubstructure is also included.  Return
** the number of JsonNode objects that are encoded.
*/
static void jsonRenderNode(
  JsonParse *pParse,             /* the complete parse of the JSON */
  JsonNode *pNode,               /* The node to render */
  JsonString *pOut               /* Write JSON here */
){
  assert( pNode!=0 );
  while( (pNode->jnFlags & JNODE_REPLACE)!=0 && pParse->useMod ){
    u32 idx = (u32)(pNode - pParse->aNode);
    u32 i = pParse->iSubst;
    while( 1 /*exit-by-break*/ ){
      assert( i<pParse->nNode );
      assert( pParse->aNode[i].eType==JSON_SUBST );
      assert( pParse->aNode[i].eU==4 );
      assert( pParse->aNode[i].u.iPrev<i );
      if( pParse->aNode[i].n==idx ){
        pNode = &pParse->aNode[i+1];
        break;
      }
      i = pParse->aNode[i].u.iPrev;
    }
  }
  switch( pNode->eType ){
    default: {
      assert( pNode->eType==JSON_NULL );
      jsonAppendRawNZ(pOut, "null", 4);
      break;
    }
    case JSON_TRUE: {
      jsonAppendRawNZ(pOut, "true", 4);
      break;
    }
    case JSON_FALSE: {
      jsonAppendRawNZ(pOut, "false", 5);
      break;
    }
    case JSON_STRING: {
      assert( pNode->eU==1 );
      if( pNode->jnFlags & JNODE_RAW ){
        if( pNode->jnFlags & JNODE_LABEL ){
          jsonAppendChar(pOut, '"');
          jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
          jsonAppendChar(pOut, '"');
        }else{
          jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
        }
      }else if( pNode->jnFlags & JNODE_JSON5 ){
        jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
      }else{
        assert( pNode->n>0 );
        jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
      }
      break;
    }
    case JSON_REAL: {
      assert( pNode->eU==1 );
      if( pNode->jnFlags & JNODE_JSON5 ){
        jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
      }else{
        assert( pNode->n>0 );
        jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
      }

      break;
    }
    case JSON_INT: {
      assert( pNode->eU==1 );
      if( pNode->jnFlags & JNODE_JSON5 ){
        jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
      }else{
        assert( pNode->n>0 );
        jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
      }
      break;
    }
    case JSON_ARRAY: {
      u32 j = 1;
      jsonAppendChar(pOut, '[');
      for(;;){
        while( j<=pNode->n ){
          if( (pNode[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
            jsonAppendSeparator(pOut);
            jsonRenderNode(pParse, &pNode[j], pOut);
          }
          j += jsonNodeSize(&pNode[j]);
        }
        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
        if( pParse->useMod==0 ) break;
        assert( pNode->eU==2 );
        pNode = &pParse->aNode[pNode->u.iAppend];
        j = 1;
      }
      jsonAppendChar(pOut, ']');
      break;
    }
    case JSON_OBJECT: {
      u32 j = 1;
      jsonAppendChar(pOut, '{');
      for(;;){
        while( j<=pNode->n ){
          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
            jsonAppendSeparator(pOut);
            jsonRenderNode(pParse, &pNode[j], pOut);
            jsonAppendChar(pOut, ':');
            jsonRenderNode(pParse, &pNode[j+1], pOut);
          }
          j += 1 + jsonNodeSize(&pNode[j+1]);
        }
        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
        if( pParse->useMod==0 ) break;
        assert( pNode->eU==2 );
        pNode = &pParse->aNode[pNode->u.iAppend];
        j = 1;
      }
      jsonAppendChar(pOut, '}');
      break;
    }
  }
}

/**************************************************************************
/*
** Return a JsonNode and all its descendants as a JSON string.
*/
static void jsonReturnJson(
  JsonParse *pParse,          /* The complete JSON */
  JsonNode *pNode,            /* Node to return */
  sqlite3_context *pCtx,      /* Return value for this function */
  int bGenerateAlt,           /* Also store the rendered text in zAlt */
  int omitSubtype             /* Do not call sqlite3_result_subtype() */
){
  JsonString s;
  if( pParse->oom ){
** Utility routines for the JSON text parser
    sqlite3_result_error_nomem(pCtx);
    return;
  }
  if( pParse->nErr==0 ){
    jsonInit(&s, pCtx);
    jsonRenderNode(pParse, pNode, &s);
    if( bGenerateAlt && pParse->zAlt==0 && jsonForceRCStr(&s) ){
      pParse->zAlt = sqlite3RCStrRef(s.zBuf);
      pParse->nAlt = s.nUsed;
    }
    jsonResult(&s);
    if( !omitSubtype ) sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
  }
}
**************************************************************************/

/*
** Translate a single byte of Hex into an integer.
** This routine only works if h really is a valid hexadecimal
** character:  0..9a..fA..F
** This routine only gives a correct answer if h really is a valid hexadecimal
** character:  0..9a..fA..F.  But unlike sqlite3HexToInt(), it does not
** assert() if the digit is not hex.
*/
static u8 jsonHexToInt(int h){
  assert( (h>='0' && h<='9') ||  (h>='a' && h<='f') ||  (h>='A' && h<='F') );
#ifdef SQLITE_EBCDIC
  h += 9*(1&~(h>>4));
#else
  h += 9*(1&(h>>6));
#ifdef SQLITE_ASCII
  h += 9*(1&(h>>6));
#endif
#ifdef SQLITE_EBCDIC
  h += 9*(1&~(h>>4));
#endif
  return (u8)(h & 0xf);
}

/*
** Convert a 4-byte hex string into an integer
*/
static u32 jsonHexToInt4(const char *z){
  u32 v;
  assert( sqlite3Isxdigit(z[0]) );
  assert( sqlite3Isxdigit(z[1]) );
  assert( sqlite3Isxdigit(z[2]) );
  assert( sqlite3Isxdigit(z[3]) );
  v = (jsonHexToInt(z[0])<<12)
    + (jsonHexToInt(z[1])<<8)
    + (jsonHexToInt(z[2])<<4)
    + jsonHexToInt(z[3]);
  return v;
}

/*
** Make the JsonNode the return value of the function.
*/
static void jsonReturn(
  JsonParse *pParse,          /* Complete JSON parse tree */
  JsonNode *pNode,            /* Node to return */
  sqlite3_context *pCtx,      /* Return value for this function */
  int omitSubtype             /* Do not call sqlite3_result_subtype() */
){
  switch( pNode->eType ){
    default: {
      assert( pNode->eType==JSON_NULL );
      sqlite3_result_null(pCtx);
      break;
    }
    case JSON_TRUE: {
      sqlite3_result_int(pCtx, 1);
      break;
    }
    case JSON_FALSE: {
      sqlite3_result_int(pCtx, 0);
      break;
    }
    case JSON_INT: {
      sqlite3_int64 i = 0;
      int rc;
      int bNeg = 0;
      const char *z;

      assert( pNode->eU==1 );
      z = pNode->u.zJContent;
      if( z[0]=='-' ){ z++; bNeg = 1; }
      else if( z[0]=='+' ){ z++; }
      rc = sqlite3DecOrHexToI64(z, &i);
      if( rc<=1 ){
        sqlite3_result_int64(pCtx, bNeg ? -i : i);
      }else if( rc==3 && bNeg ){
        sqlite3_result_int64(pCtx, SMALLEST_INT64);
      }else{
        goto to_double;
      }
      break;
    }
    case JSON_REAL: {
      double r;
      const char *z;
      assert( pNode->eU==1 );
    to_double:
      z = pNode->u.zJContent;
      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
      sqlite3_result_double(pCtx, r);
      break;
    }
    case JSON_STRING: {
      if( pNode->jnFlags & JNODE_RAW ){
        assert( pNode->eU==1 );
        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
                            SQLITE_TRANSIENT);
      }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
        /* JSON formatted without any backslash-escapes */
        assert( pNode->eU==1 );
        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
                            SQLITE_TRANSIENT);
      }else{
        /* Translate JSON formatted string into raw text */
        u32 i;
        u32 n = pNode->n;
        const char *z;
        char *zOut;
        u32 j;
        u32 nOut = n;
        assert( pNode->eU==1 );
        z = pNode->u.zJContent;
        zOut = sqlite3_malloc( nOut+1 );
        if( zOut==0 ){
          sqlite3_result_error_nomem(pCtx);
          break;
        }
        for(i=1, j=0; i<n-1; i++){
          char c = z[i];
          if( c=='\\' ){
            c = z[++i];
            if( c=='u' ){
              u32 v = jsonHexToInt4(z+i+1);
              i += 4;
              if( v==0 ) break;
              if( v<=0x7f ){
                zOut[j++] = (char)v;
              }else if( v<=0x7ff ){
                zOut[j++] = (char)(0xc0 | (v>>6));
                zOut[j++] = 0x80 | (v&0x3f);
              }else{
                u32 vlo;
                if( (v&0xfc00)==0xd800
                  && i<n-6
                  && z[i+1]=='\\'
                  && z[i+2]=='u'
                  && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
                ){
                  /* We have a surrogate pair */
                  v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
                  i += 6;
                  zOut[j++] = 0xf0 | (v>>18);
                  zOut[j++] = 0x80 | ((v>>12)&0x3f);
                  zOut[j++] = 0x80 | ((v>>6)&0x3f);
                  zOut[j++] = 0x80 | (v&0x3f);
                }else{
                  zOut[j++] = 0xe0 | (v>>12);
                  zOut[j++] = 0x80 | ((v>>6)&0x3f);
                  zOut[j++] = 0x80 | (v&0x3f);
                }
              }
              continue;
            }else if( c=='b' ){
              c = '\b';
            }else if( c=='f' ){
              c = '\f';
            }else if( c=='n' ){
              c = '\n';
            }else if( c=='r' ){
              c = '\r';
            }else if( c=='t' ){
              c = '\t';
            }else if( c=='v' ){
              c = '\v';
            }else if( c=='\'' || c=='"' || c=='/' || c=='\\' ){
              /* pass through unchanged */
            }else if( c=='0' ){
              c = 0;
            }else if( c=='x' ){
              c = (jsonHexToInt(z[i+1])<<4) | jsonHexToInt(z[i+2]);
              i += 2;
            }else if( c=='\r' && z[i+1]=='\n' ){
              i++;
              continue;
            }else if( 0xe2==(u8)c ){
              assert( 0x80==(u8)z[i+1] );
              assert( 0xa8==(u8)z[i+2] || 0xa9==(u8)z[i+2] );
              i += 2;
              continue;
            }else{
              continue;
            }
          } /* end if( c=='\\' ) */
          zOut[j++] = c;
        } /* end for() */
        zOut[j] = 0;
        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
      }
      break;
    }
    case JSON_ARRAY:
    case JSON_OBJECT: {
      jsonReturnJson(pParse, pNode, pCtx, 0, omitSubtype);
      break;
    }
  }
}

/* Forward reference */
static int jsonParseAddNode(JsonParse*,u32,u32,const char*);

/*
** A macro to hint to the compiler that a function should not be
** inlined.
*/
#if defined(__GNUC__)
#  define JSON_NOINLINE  __attribute__((noinline))
#elif defined(_MSC_VER) && _MSC_VER>=1310
#  define JSON_NOINLINE  __declspec(noinline)
#else
#  define JSON_NOINLINE
#endif


/*
** Add a single node to pParse->aNode after first expanding the
** size of the aNode array.  Return the index of the new node.
**
** If an OOM error occurs, set pParse->oom and return -1.
*/
static JSON_NOINLINE int jsonParseAddNodeExpand(
  JsonParse *pParse,        /* Append the node to this object */
  u32 eType,                /* Node type */
  u32 n,                    /* Content size or sub-node count */
  const char *zContent      /* Content */
){
  u32 nNew;
  JsonNode *pNew;
  assert( pParse->nNode>=pParse->nAlloc );
  if( pParse->oom ) return -1;
  nNew = pParse->nAlloc*2 + 10;
  pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
  if( pNew==0 ){
    pParse->oom = 1;
    return -1;
  }
  pParse->nAlloc = sqlite3_msize(pNew)/sizeof(JsonNode);
  pParse->aNode = pNew;
  assert( pParse->nNode<pParse->nAlloc );
  return jsonParseAddNode(pParse, eType, n, zContent);
}

/*
** Create a new JsonNode instance based on the arguments and append that
** instance to the JsonParse.  Return the index in pParse->aNode[] of the
** new node, or -1 if a memory allocation fails.
*/
static int jsonParseAddNode(
  JsonParse *pParse,        /* Append the node to this object */
  u32 eType,                /* Node type */
  u32 n,                    /* Content size or sub-node count */
  const char *zContent      /* Content */
){
  JsonNode *p;
  assert( pParse->aNode!=0 || pParse->nNode>=pParse->nAlloc );
  if( pParse->nNode>=pParse->nAlloc ){
    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
  }
  assert( pParse->aNode!=0 );
  p = &pParse->aNode[pParse->nNode];
  assert( p!=0 );
  p->eType = (u8)(eType & 0xff);
  p->jnFlags = (u8)(eType >> 8);
  VVA( p->eU = zContent ? 1 : 0 );
  p->n = n;
  p->u.zJContent = zContent;
  return pParse->nNode++;
}

/*
** Add an array of new nodes to the current pParse->aNode array.
** Return the index of the first node added.
**
** If an OOM error occurs, set pParse->oom.
*/
static void jsonParseAddNodeArray(
  JsonParse *pParse,        /* Append the node to this object */
  JsonNode *aNode,          /* Array of nodes to add */
  u32 nNode                 /* Number of elements in aNew */
){
  assert( aNode!=0 );
  assert( nNode>=1 );
  if( pParse->nNode + nNode > pParse->nAlloc ){
    u32 nNew = pParse->nNode + nNode;
    JsonNode *aNew = sqlite3_realloc64(pParse->aNode, nNew*sizeof(JsonNode));
    if( aNew==0 ){
      pParse->oom = 1;
      return;
    }
    pParse->nAlloc = sqlite3_msize(aNew)/sizeof(JsonNode);
    pParse->aNode = aNew;
  }
  memcpy(&pParse->aNode[pParse->nNode], aNode, nNode*sizeof(JsonNode));
  pParse->nNode += nNode;
}

/*
** Add a new JSON_SUBST node.  The node immediately following
** this new node will be the substitute content for iNode.
*/
static int jsonParseAddSubstNode(
  JsonParse *pParse,       /* Add the JSON_SUBST here */
  u32 iNode                /* References this node */
){
  int idx = jsonParseAddNode(pParse, JSON_SUBST, iNode, 0);
  if( pParse->oom ) return -1;
  pParse->aNode[iNode].jnFlags |= JNODE_REPLACE;
  pParse->aNode[idx].eU = 4;
  pParse->aNode[idx].u.iPrev = pParse->iSubst;
  pParse->iSubst = idx;
  pParse->hasMod = 1;
  pParse->useMod = 1;
  return idx;
}

/*
** Return true if z[] begins with 2 (or more) hexadecimal digits
*/
static int jsonIs2Hex(const char *z){
  return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]);
}

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
1492
1493
1494
1495

1496
1497
1498
1499
1500

1501
1502
1503

1504
1505
1506
1507

1508
1509
1510
1511












1512
1513
1514
1515
1516
1517
1518
1519
1520

1521
1522
1523
1524
1525

1526
1527
1528
1529

1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541














1542
1543
1544
1545
1546

1547
1548
1549
1550
1551
1552
1553
1554

1555
1556
1557
1558
1559
1560
1561

1562
1563

1564
1565
1566
1567
1568

1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587

1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599

1600
1601

1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618

1619
1620

1621
1622
1623
1624
1625
1626

1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638

1639
1640
1641
1642
1643
1644

1645
1646
1647
1648
1649
1650

1651
1652
1653
1654

1655
1656
1657
1658
1659
1660
1661

1662
1663
1664
1665
1666
1667
1668
1669
1670
1671

1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689

1690
1691
1692
1693
1694
1695




1696

1697
1698
1699
1700
1701
1702
1703
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
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496


1497
1498
1499
1500
1501
1502

1503
1504
1505





1506
1507
1508
1509
1510
1511

1512
1513
1514

1515
1516

1517
1518
1519
1520
1521
1522
1523

1524

1525
1526
1527
1528
1529
1530


1531
1532
1533
1534
1535
1536

1537
1538
1539
1540
1541


1542
1543
1544
1545
1546

1547
1548
1549
1550
1551

1552
1553
1554
1555
1556
1557
1558
1559
1560


1561
1562
1563
1564
1565

1566
1567
1568
1569


1570
1571
1572
1573
1574
1575
1576
1577

1578
1579
1580
1581
1582
1583
1584
1585

1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596


1597
1598
1599
1600
1601
1602
1603
1604

1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617

1618
1619
1620
1621
1622
1623
1624
1625


1626
1627
1628
1629
1630
1631
1632

1633

1634
1635
1636
1637

1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649


1650
1651
1652
1653
1654
1655
1656
1657

1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670

1671
1672
1673
1674
1675

1676
1677
1678

1679
1680
1681
1682

1683
1684
1685


1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705

1706
1707
1708
1709
1710

1711
1712
1713
1714

1715
1716
1717
1718
1719
1720
1721






1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739

1740
1741
1742
1743
1744
1745
1746
1747

1748
1749
1750
1751
1752
1753
1754

1755
1756

1757
1758
1759
1760
1761

1762
1763

1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779

1780
1781

1782
1783
1784
1785
1786
1787
1788
1789
1790

1791
1792

1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
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







-
-
-
-
-
+
+
+
+
+


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

-
-
+
+
+
+

+
-
+


-
-
-
-
-
+
+
+
+
+

-
+


-
+

-
+





+
-
+
-




+

-
-
+
+

+


-
+



+
-
-
+
+



-
+



+
-
+








-
-
+
+



-




-
-
+
+
+





-
+







-
+










-
-
+
+






-
+












-
+





+
+
-
-
+
+
+




-

-
+



-
+











-
-
+
+






-
+












-
+




-
+


-
+



-
+


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








-
+




-
+



-
+






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




-
+







-
+






-
+

-
+




-
+

-
















-
+

-









-
+

-
+
















-
+

-
+





-
+











-
+






+





-
+



-
+






-
+









-
+

















-
+






+
+
+
+
-
+







  char c2;
  char n;
  char eType;
  char nRepl;
  char *zMatch;
  char *zRepl;
} aNanInfName[] = {
  { 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" },
  { 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" },
  { 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" },
  { 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" },
  { 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" },
  { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" },
  { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" },
  { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" },
  { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" },
  { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" },
};


/*
** Report the wrong number of arguments for json_insert(), json_replace()
** or json_set().
*/
static void jsonWrongNumArgs(
  sqlite3_context *pCtx,
  const char *zFuncName
){
  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
                               zFuncName);
  sqlite3_result_error(pCtx, zMsg, -1);
  sqlite3_free(zMsg);
}

/****************************************************************************
** Utility routines for dealing with the binary BLOB representation of JSON
****************************************************************************/

/*
** Expand pParse->aBlob so that it holds at least N bytes.
**
** Return the number of errors.
*/
static int jsonBlobExpand(JsonParse *pParse, u32 N){
  u8 *aNew;
  u32 t;
  assert( N>pParse->nBlobAlloc );
  if( pParse->nBlobAlloc==0 ){
    t = 100;
  }else{
    t = pParse->nBlobAlloc*2;
  }
  if( t<N ) t = N+100;
  aNew = sqlite3DbRealloc(pParse->db, pParse->aBlob, t);
  if( aNew==0 ){ pParse->oom = 1; return 1; }
  pParse->aBlob = aNew;
  pParse->nBlobAlloc = t;
  return 0;
}

/*
** If pParse->aBlob is not previously editable (because it is taken
** from sqlite3_value_blob(), as indicated by the fact that
** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable
** by making a copy into space obtained from malloc.
**
** Return true on success.  Return false on OOM.
*/
static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){
  u8 *aOld;
  u32 nSize;
  assert( !pParse->bReadOnly );
  if( pParse->oom ) return 0;
  if( pParse->nBlobAlloc>0 ) return 1;
  aOld = pParse->aBlob;
  nSize = pParse->nBlob + nExtra;
  pParse->aBlob = 0;
  if( jsonBlobExpand(pParse, nSize) ){
    return 0;
  }
  assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra );
  memcpy(pParse->aBlob, aOld, pParse->nBlob);
  return 1;
}

/* Expand pParse->aBlob and append one bytes.
*/
static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte(
  JsonParse *pParse,
  u8 c
){
  jsonBlobExpand(pParse, pParse->nBlob+1);
  if( pParse->oom==0 ){
    assert( pParse->nBlob+1<=pParse->nBlobAlloc );
    pParse->aBlob[pParse->nBlob++] = c;
  }
}

/* Append a single character.
*/
static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){
  if( pParse->nBlob >= pParse->nBlobAlloc ){
    jsonBlobExpandAndAppendOneByte(pParse, c);
  }else{
    pParse->aBlob[pParse->nBlob++] = c;
  }
}

/* Slow version of jsonBlobAppendNode() that first resizes the
** pParse->aBlob structure.
*/
static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*);
static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode(
  JsonParse *pParse,
  u8 eType,
  u32 szPayload,
  const void *aPayload
){
  if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return;
  jsonBlobAppendNode(pParse, eType, szPayload, aPayload);
}


/* Append an node type byte together with the payload size and
** possibly also the payload.
**
** If aPayload is not NULL, then it is a pointer to the payload which
** is also appended.  If aPayload is NULL, the pParse->aBlob[] array
** is resized (if necessary) so that it is big enough to hold the
** payload, but the payload is not appended and pParse->nBlob is left
** pointing to where the first byte of payload will eventually be.
*/
static void jsonBlobAppendNode(
  JsonParse *pParse,          /* The JsonParse object under construction */
  u8 eType,                   /* Node type.  One of JSONB_* */
  u32 szPayload,              /* Number of bytes of payload */
  const void *aPayload        /* The payload.  Might be NULL */
){
  u8 *a;
  if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){
    jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload);
    return;
  }
  assert( pParse->aBlob!=0 );
  a = &pParse->aBlob[pParse->nBlob];
  if( szPayload<=11 ){
    a[0] = eType | (szPayload<<4);
    pParse->nBlob += 1;
  }else if( szPayload<=0xff ){
    a[0] = eType | 0xc0;
    a[1] = szPayload & 0xff;
    pParse->nBlob += 2;
  }else if( szPayload<=0xffff ){
    a[0] = eType | 0xd0;
    a[1] = (szPayload >> 8) & 0xff;
    a[2] = szPayload & 0xff;
    pParse->nBlob += 3;
  }else{
    a[0] = eType | 0xe0;
    a[1] = (szPayload >> 24) & 0xff;
    a[2] = (szPayload >> 16) & 0xff;
    a[3] = (szPayload >> 8) & 0xff;
    a[4] = szPayload & 0xff;
    pParse->nBlob += 5;
  }
  if( aPayload ){
    pParse->nBlob += szPayload;
    memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload);
  }
}

/* Change the payload size for the node at index i to be szPayload.
*/
static int jsonBlobChangePayloadSize(
  JsonParse *pParse,
  u32 i,
  u32 szPayload
){
  u8 *a;
  u8 szType;
  u8 nExtra;
  u8 nNeeded;
  int delta;
  if( pParse->oom ) return 0;
  a = &pParse->aBlob[i];
  szType = a[0]>>4;
  if( szType<=11 ){
    nExtra = 0;
  }else if( szType==12 ){
    nExtra = 1;
  }else if( szType==13 ){
    nExtra = 2;
  }else{
    nExtra = 4;
  }
  if( szPayload<=11 ){
    nNeeded = 0;
  }else if( szPayload<=0xff ){
    nNeeded = 1;
  }else if( szPayload<=0xffff ){
    nNeeded = 2;
  }else{
    nNeeded = 4;
  }
  delta = nNeeded - nExtra;
  if( delta ){
    u32 newSize = pParse->nBlob + delta;
    if( delta>0 ){
      if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){
        return 0;  /* OOM error.  Error state recorded in pParse->oom. */
      }
      a = &pParse->aBlob[i];
      memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1));
    }else{
      memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta));
    }
    pParse->nBlob = newSize;
  }
  if( nNeeded==0 ){
    a[0] = (a[0] & 0x0f) | (szPayload<<4);
  }else if( nNeeded==1 ){
    a[0] = (a[0] & 0x0f) | 0xc0;
    a[1] = szPayload & 0xff;
  }else if( nNeeded==2 ){
    a[0] = (a[0] & 0x0f) | 0xd0;
    a[1] = (szPayload >> 8) & 0xff;
    a[2] = szPayload & 0xff;
  }else{
    a[0] = (a[0] & 0x0f) | 0xe0;
    a[1] = (szPayload >> 24) & 0xff;
    a[2] = (szPayload >> 16) & 0xff;
    a[3] = (szPayload >> 8) & 0xff;
    a[4] = szPayload & 0xff;
  }
  return delta;
}

/*
** If z[0] is 'u' and is followed by exactly 4 hexadecimal character,
** then set *pOp to JSONB_TEXTJ and return true.  If not, do not make
** any changes to *pOp and return false.
*/
static int jsonIs4HexB(const char *z, int *pOp){
  if( z[0]!='u' ) return 0;
  if( !jsonIs4Hex(&z[1]) ) return 0;
  *pOp = JSONB_TEXTJ;
  return 1;
}

/*
** Check a single element of the JSONB in pParse for validity.
**
** The element to be checked starts at offset i and must end at on the
** last byte before iEnd.
**
** Return 0 if everything is correct.  Return the 1-based byte offset of the
** error if a problem is detected.  (In other words, if the error is at offset
** 0, return 1).
*/
static u32 jsonbValidityCheck(
  const JsonParse *pParse,    /* Input JSONB.  Only aBlob and nBlob are used */
  u32 i,                      /* Start of element as pParse->aBlob[i] */
  u32 iEnd,                   /* One more than the last byte of the element */
  u32 iDepth                  /* Current nesting depth */
){
  u32 n, sz, j, k;
  const u8 *z;
  u8 x;
  if( iDepth>JSON_MAX_DEPTH ) return i+1;
  sz = 0;
  n = jsonbPayloadSize(pParse, i, &sz);
  if( NEVER(n==0) ) return i+1;          /* Checked by caller */
  if( NEVER(i+n+sz!=iEnd) ) return i+1;  /* Checked by caller */
  z = pParse->aBlob;
  x = z[i] & 0x0f;
  switch( x ){
    case JSONB_NULL:
    case JSONB_TRUE:
    case JSONB_FALSE: {
      return n+sz==1 ? 0 : i+1;
    }
    case JSONB_INT: {
      if( sz<1 ) return i+1;
      j = i+n;
      if( z[j]=='-' ){
        j++;
        if( sz<2 ) return i+1;
      }
      k = i+n+sz;
      while( j<k ){
        if( sqlite3Isdigit(z[j]) ){
          j++;
        }else{
          return j+1;
        }
      }
      return 0;
    }
    case JSONB_INT5: {
      if( sz<3 ) return i+1;
      j = i+n;
      if( z[j]=='-' ){
        if( sz<4 ) return i+1;
        j++;
      }
      if( z[j]!='0' ) return i+1;
      if( z[j+1]!='x' && z[j+1]!='X' ) return j+2;
      j += 2;
      k = i+n+sz;
      while( j<k ){
        if( sqlite3Isxdigit(z[j]) ){
          j++;
        }else{
          return j+1;
        }
      }
      return 0;
    }
    case JSONB_FLOAT:
    case JSONB_FLOAT5: {
      u8 seen = 0;   /* 0: initial.  1: '.' seen  2: 'e' seen */
      if( sz<2 ) return i+1;
      j = i+n;
      k = j+sz;
      if( z[j]=='-' ){
        j++;
        if( sz<3 ) return i+1;
      }
      if( z[j]=='.' ){
        if( x==JSONB_FLOAT ) return j+1;
        if( !sqlite3Isdigit(z[j+1]) ) return j+1;
        j += 2;
        seen = 1;
      }else if( z[j]=='0' && x==JSONB_FLOAT ){
        if( j+3>k ) return j+1;
        if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1;
        j++;
      }
      for(; j<k; j++){
        if( sqlite3Isdigit(z[j]) ) continue;
        if( z[j]=='.' ){
          if( seen>0 ) return j+1;
          if( x==JSONB_FLOAT && (j==k-1 || !sqlite3Isdigit(z[j+1])) ){
            return j+1;
          }
          seen = 1;
          continue;
        }
        if( z[j]=='e' || z[j]=='E' ){
          if( seen==2 ) return j+1;
          if( j==k-1 ) return j+1;
          if( z[j+1]=='+' || z[j+1]=='-' ){
            j++;
            if( j==k-1 ) return j+1;
          }
          seen = 2;
          continue;
        }
        return j+1;
      }
      if( seen==0 ) return i+1;
      return 0;
    }
    case JSONB_TEXT: {
      j = i+n;
      k = j+sz;
      while( j<k ){
        if( !jsonIsOk[z[j]] && z[j]!='\'' ) return j+1;
        j++;
      }
      return 0;
    }
    case JSONB_TEXTJ:
    case JSONB_TEXT5: {
      j = i+n;
      k = j+sz;
      while( j<k ){
        if( !jsonIsOk[z[j]] && z[j]!='\'' ){
          if( z[j]=='"' ){
            if( x==JSONB_TEXTJ ) return j+1;
          }else if( z[j]<=0x1f ){
            /* Control characters in JSON5 string literals are ok */
            if( x==JSONB_TEXTJ ) return j+1;
          }else if( NEVER(z[j]!='\\') || j+1>=k ){
            return j+1;
          }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){
            j++;
          }else if( z[j+1]=='u' ){
            if( j+5>=k ) return j+1;
            if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1;
            j++;
          }else if( x!=JSONB_TEXT5 ){
            return j+1;
          }else{
            u32 c = 0;
            u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c);
            if( c==JSON_INVALID_CHAR ) return j+1;
            j += szC - 1;
          }
        }
        j++;
      }
      return 0;
    }
    case JSONB_TEXTRAW: {
      return 0;
    }
    case JSONB_ARRAY: {
      u32 sub;
      j = i+n;
      k = j+sz;
      while( j<k ){
        sz = 0;
        n = jsonbPayloadSize(pParse, j, &sz);
        if( n==0 ) return j+1;
        if( j+n+sz>k ) return j+1;
        sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
        if( sub ) return sub;
        j += n + sz;
      }
      assert( j==k );
      return 0;
    }
    case JSONB_OBJECT: {
      u32 cnt = 0;
      u32 sub;
      j = i+n;
      k = j+sz;
      while( j<k ){
        sz = 0;
        n = jsonbPayloadSize(pParse, j, &sz);
        if( n==0 ) return j+1;
        if( j+n+sz>k ) return j+1;
        if( (cnt & 1)==0 ){
          x = z[j] & 0x0f;
          if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return j+1;
        }
        sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
        if( sub ) return sub;
        cnt++;
        j += n + sz;
      }
      assert( j==k );
      if( (cnt & 1)!=0 ) return j+1;
      return 0;
    }
    default: {
      return i+1;
    }
  }
}

/*
** Parse a single JSON value which begins at pParse->zJson[i].  Return the
** index of the first character past the end of the value parsed.
** Translate a single element of JSON text at pParse->zJson[i] into
** its equivalent binary JSONB representation.  Append the translation into
** pParse->aBlob[] beginning at pParse->nBlob.  The size of
** pParse->aBlob[] is increased as necessary.
**
** Return the index of the first character past the end of the element parsed,
** Special return values:
** or one of the following special result codes:
**
**      0    End of input
**     -1    Syntax error
**     -2    '}' seen
**     -3    ']' seen
**     -4    ',' seen
**     -5    ':' seen
**     -1    Syntax error or OOM
**     -2    '}' seen   \
**     -3    ']' seen    \___  For these returns, pParse->iErr is set to
**     -4    ',' seen    /     the index in zJson[] of the seen character
**     -5    ':' seen   /
*/
static int jsonParseValue(JsonParse *pParse, u32 i){
static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){
  char c;
  u32 j;
  int iThis;
  u32 iThis, iStart;
  int x;
  JsonNode *pNode;
  u8 t;
  const char *z = pParse->zJson;
json_parse_restart:
  switch( (u8)z[i] ){
  case '{': {
    /* Parse object */
    iThis = pParse->nBlob;
    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
    jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0);
    if( iThis<0 ) return -1;
    if( ++pParse->iDepth > JSON_MAX_DEPTH ){
      pParse->iErr = i;
      return -1;
    }
    iStart = pParse->nBlob;
    for(j=i+1;;j++){
      u32 nNode = pParse->nNode;
      x = jsonParseValue(pParse, j);
      u32 iBlob = pParse->nBlob;
      x = jsonTranslateTextToBlob(pParse, j);
      if( x<=0 ){
        int op;
        if( x==(-2) ){
          j = pParse->iErr;
          if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
          if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1;
          break;
        }
        j += json5Whitespace(&z[j]);
        op = JSONB_TEXT;
        if( sqlite3JsonId1(z[j])
         || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2]))
        if( sqlite3JsonId1(z[j]) 
         || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op))
        ){
          int k = j+1;
          while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
            || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2]))
            || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op))
          ){
            k++;
          }
          assert( iBlob==pParse->nBlob );
          jsonParseAddNode(pParse, JSON_STRING | (JNODE_RAW<<8), k-j, &z[j]);
          jsonBlobAppendNode(pParse, op, k-j, &z[j]);
          pParse->hasNonstd = 1;
          x = k;
        }else{
          if( x!=-1 ) pParse->iErr = j;
          return -1;
        }
      }
      if( pParse->oom ) return -1;
      pNode = &pParse->aNode[nNode];
      if( pNode->eType!=JSON_STRING ){
      t = pParse->aBlob[iBlob] & 0x0f;
      if( t<JSONB_TEXT || t>JSONB_TEXTRAW ){
        pParse->iErr = j;
        return -1;
      }
      pNode->jnFlags |= JNODE_LABEL;
      j = x;
      if( z[j]==':' ){
        j++;
      }else{
        if( fast_isspace(z[j]) ){
          do{ j++; }while( fast_isspace(z[j]) );
        if( jsonIsspace(z[j]) ){
          /* strspn() is not helpful here */
          do{ j++; }while( jsonIsspace(z[j]) );
          if( z[j]==':' ){
            j++;
            goto parse_object_value;
          }
        }
        x = jsonParseValue(pParse, j);
        x = jsonTranslateTextToBlob(pParse, j);
        if( x!=(-5) ){
          if( x!=(-1) ) pParse->iErr = j;
          return -1;
        }
        j = pParse->iErr+1;
      }
    parse_object_value:
      x = jsonParseValue(pParse, j);
      x = jsonTranslateTextToBlob(pParse, j);
      if( x<=0 ){
        if( x!=(-1) ) pParse->iErr = j;
        return -1;
      }
      j = x;
      if( z[j]==',' ){
        continue;
      }else if( z[j]=='}' ){
        break;
      }else{
        if( fast_isspace(z[j]) ){
          do{ j++; }while( fast_isspace(z[j]) );
        if( jsonIsspace(z[j]) ){
          j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
          if( z[j]==',' ){
            continue;
          }else if( z[j]=='}' ){
            break;
          }
        }
        x = jsonParseValue(pParse, j);
        x = jsonTranslateTextToBlob(pParse, j);
        if( x==(-4) ){
          j = pParse->iErr;
          continue;
        }
        if( x==(-2) ){
          j = pParse->iErr;
          break;
        }
      }
      pParse->iErr = j;
      return -1;
    }
    pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
    jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
    pParse->iDepth--;
    return j+1;
  }
  case '[': {
    /* Parse array */
    iThis = pParse->nBlob;
    assert( i<=(u32)pParse->nJson );
    iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
    if( iThis<0 ) return -1;
    jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
    iStart = pParse->nBlob;
    if( pParse->oom ) return -1;
    if( ++pParse->iDepth > JSON_MAX_DEPTH ){
      pParse->iErr = i;
      return -1;
    }
    memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
    for(j=i+1;;j++){
      x = jsonParseValue(pParse, j);
      x = jsonTranslateTextToBlob(pParse, j);
      if( x<=0 ){
        if( x==(-3) ){
          j = pParse->iErr;
          if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
          if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1;
          break;
        }
        if( x!=(-1) ) pParse->iErr = j;
        return -1;
      }
      j = x;
      if( z[j]==',' ){
        continue;
      }else if( z[j]==']' ){
        break;
      }else{
        if( fast_isspace(z[j]) ){
          do{ j++; }while( fast_isspace(z[j]) );
        if( jsonIsspace(z[j]) ){
          j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
          if( z[j]==',' ){
            continue;
          }else if( z[j]==']' ){
            break;
          }
        }
        x = jsonParseValue(pParse, j);
        x = jsonTranslateTextToBlob(pParse, j);
        if( x==(-4) ){
          j = pParse->iErr;
          continue;
        }
        if( x==(-3) ){
          j = pParse->iErr;
          break;
        }
      }
      pParse->iErr = j;
      return -1;
    }
    pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
    jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
    pParse->iDepth--;
    return j+1;
  }
  case '\'': {
    u8 jnFlags;
    u8 opcode;
    char cDelim;
    pParse->hasNonstd = 1;
    jnFlags = JNODE_JSON5;
    opcode = JSONB_TEXT;
    goto parse_string;
  case '"':
    /* Parse string */
    jnFlags = 0;
    opcode = JSONB_TEXT;
  parse_string:
    cDelim = z[i];
    for(j=i+1; 1; j++){
      if( jsonIsOk[(unsigned char)z[j]] ) continue;
    j = i+1;
    while( 1 /*exit-by-break*/ ){
      if( jsonIsOk[(u8)z[j]] ){
        if( !jsonIsOk[(u8)z[j+1]] ){
          j += 1;
        }else if( !jsonIsOk[(u8)z[j+2]] ){
          j += 2;
        }else{
          j += 3;
          continue;
        }
      }
      c = z[j];
      if( c==cDelim ){
        break;
      }else if( c=='\\' ){
        c = z[++j];
        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
           || c=='n' || c=='r' || c=='t'
           || (c=='u' && jsonIs4Hex(&z[j+1])) ){
          jnFlags |= JNODE_ESCAPE;
          if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
        }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
           || (0xe2==(u8)c && 0x80==(u8)z[j+1]
                && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
           || (c=='x' && jsonIs2Hex(&z[j+1])) ){
          jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
          opcode = JSONB_TEXT5;
          pParse->hasNonstd = 1;
        }else if( c=='\r' ){
          if( z[j+1]=='\n' ) j++;
          jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
          opcode = JSONB_TEXT5;
          pParse->hasNonstd = 1;
        }else{
          pParse->iErr = j;
          return -1;
        }
      }else if( c<=0x1f ){
        /* Control characters are not allowed in strings */
        pParse->iErr = j;
        return -1;
      }
    }
    jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]);
        if( c==0 ){
          pParse->iErr = j;
          return -1;
        }
        /* Control characters are not allowed in canonical JSON string
        ** literals, but are allowed in JSON5 string literals. */
        opcode = JSONB_TEXT5;
        pParse->hasNonstd = 1;
      }else if( c=='"' ){
        opcode = JSONB_TEXT5;
      }
      j++;
    }
    jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]);
    return j+1;
  }
  case 't': {
    if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
      jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
      jsonBlobAppendOneByte(pParse, JSONB_TRUE);
      return i+4;
    }
    pParse->iErr = i;
    return -1;
  }
  case 'f': {
    if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
      jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
      jsonBlobAppendOneByte(pParse, JSONB_FALSE);
      return i+5;
    }
    pParse->iErr = i;
    return -1;
  }
  case '+': {
    u8 seenDP, seenE, jnFlags;
    u8 seenE;
    pParse->hasNonstd = 1;
    jnFlags = JNODE_JSON5;
    t = 0x00;            /* Bit 0x01:  JSON5.   Bit 0x02:  FLOAT */
    goto parse_number;
  case '.':
    if( sqlite3Isdigit(z[i+1]) ){
      pParse->hasNonstd = 1;
      jnFlags = JNODE_JSON5;
      t = 0x03;          /* Bit 0x01:  JSON5.   Bit 0x02:  FLOAT */
      seenE = 0;
      seenDP = JSON_REAL;
      goto parse_number_2;
    }
    pParse->iErr = i;
    return -1;
  case '-':
  case '0':
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9':
    /* Parse number */
    jnFlags = 0;
    t = 0x00;            /* Bit 0x01:  JSON5.   Bit 0x02:  FLOAT */
  parse_number:
    seenDP = JSON_INT;
    seenE = 0;
    assert( '-' < '0' );
    assert( '+' < '0' );
    assert( '.' < '0' );
    c = z[i];

    if( c<='0' ){
      if( c=='0' ){
        if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
          assert( seenDP==JSON_INT );
          assert( t==0x00 );
          pParse->hasNonstd = 1;
          jnFlags |= JNODE_JSON5;
          t = 0x01;
          for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
          goto parse_number_finish;
        }else if( sqlite3Isdigit(z[i+1]) ){
          pParse->iErr = i+1;
          return -1;
        }
      }else{
        if( !sqlite3Isdigit(z[i+1]) ){
          /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
          ** that case.  SQLite also allows these in any case and it allows
          ** "+inf" and "-inf". */
          if( (z[i+1]=='I' || z[i+1]=='i')
           && sqlite3StrNICmp(&z[i+1], "inf",3)==0
          ){
            pParse->hasNonstd = 1;
            if( z[i]=='-' ){
              jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999");
              jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
            }else{
              jsonParseAddNode(pParse, JSON_REAL, 7, "9.0e999");
              jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
            }
            return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
          }
          if( z[i+1]=='.' ){
            pParse->hasNonstd = 1;
            jnFlags |= JNODE_JSON5;
            t |= 0x01;
            goto parse_number_2;
          }
          pParse->iErr = i;
          return -1;
        }
        if( z[i+1]=='0' ){
          if( sqlite3Isdigit(z[i+2]) ){
            pParse->iErr = i+1;
            return -1;
          }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
            pParse->hasNonstd = 1;
            jnFlags |= JNODE_JSON5;
            t |= 0x01;
            for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
            goto parse_number_finish;
          }
        }
      }
    }

  parse_number_2:
    for(j=i+1;; j++){
      c = z[j];
      if( sqlite3Isdigit(c) ) continue;
      if( c=='.' ){
        if( seenDP==JSON_REAL ){
        if( (t & 0x02)!=0 ){
          pParse->iErr = j;
          return -1;
        }
        seenDP = JSON_REAL;
        t |= 0x02;
        continue;
      }
      if( c=='e' || c=='E' ){
        if( z[j-1]<'0' ){
          if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
            pParse->hasNonstd = 1;
            jnFlags |= JNODE_JSON5;
            t |= 0x01;
          }else{
            pParse->iErr = j;
            return -1;
          }
        }
        if( seenE ){
          pParse->iErr = j;
          return -1;
        }
        seenDP = JSON_REAL;
        t |= 0x02;
        seenE = 1;
        c = z[j+1];
        if( c=='+' || c=='-' ){
          j++;
          c = z[j+1];
        }
        if( c<'0' || c>'9' ){
          pParse->iErr = j;
          return -1;
        }
        continue;
      }
      break;
    }
    if( z[j-1]<'0' ){
      if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
        pParse->hasNonstd = 1;
        jnFlags |= JNODE_JSON5;
        t |= 0x01;
      }else{
        pParse->iErr = j;
        return -1;
      }
    }
  parse_number_finish:
    assert( JSONB_INT+0x01==JSONB_INT5 );
    assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 );
    assert( JSONB_INT+0x02==JSONB_FLOAT );
    if( z[i]=='+' ) i++;
    jsonParseAddNode(pParse, seenDP | (jnFlags<<8), j - i, &z[i]);
    jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]);
    return j;
  }
  case '}': {
    pParse->iErr = i;
    return -2;  /* End of {...} */
  }
  case ']': {
1715
1716
1717
1718
1719
1720
1721
1722

1723
1724
1725
1726
1727
1728
1729
1730
1731
1912
1913
1914
1915
1916
1917
1918

1919


1920
1921
1922
1923
1924
1925
1926







-
+
-
-







  case 0: {
    return 0;   /* End of file */
  }
  case 0x09:
  case 0x0a:
  case 0x0d:
  case 0x20: {
    do{
    i += 1 + (u32)strspn(&z[i+1], jsonSpaces);
      i++;
    }while( fast_isspace(z[i]) );
    goto json_parse_restart;
  }
  case 0x0b:
  case 0x0c:
  case '/':
  case 0xc2:
  case 0xe1:
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
1854
1855
1856
1857



















































1858
1859
























1860
1861
1862
1863




























1864
1865

1866
1867
1868
1869
1870





1871
1872
1873
1874






1875
1876
1877
1878









1879
1880
1881




1882
1883


1884
1885
1886
1887




1888
1889
1890



1891
1892
1893
1894




1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905





















































































1906
1907
1908
1909
1910
1911
1912
1913
1914
















































1915
1916

1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
















1928
1929
1930
1931
1932
1933
1934
1935

















1936
1937
1938



1939
1940


1941
1942
1943
1944
1945





































1946
1947
1948





1949
1950
1951
1952




1953
1954
1955
1956
1957
1958












1959
1960
1961
1962
1963
1964
1965
1966

1967
1968
1969
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
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026






















































2027
2028
2029


2030
2031
2032




2033
2034
2035
2036


2037
2038




2039
2040
2041
2042
2043






2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054



















































2055

2056

2057
2058
2059
2060
2061
2062
2063
2064
2065
2066

2067
2068

2069
2070
2071
2072
2073
2074
2075

2076
2077



2078

2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089






























2090
2091
2092






2093
2094
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








































































2133
2134
2135
2136
2137
2138













2139
2140
2141
2142
2143
2144
2145


2146
2147
2148
2149
2150
2151









































2152
2153
2154


2155

2156
2157

2158
2159
2160
2161
2162






2163
2164

2165
2166
2167



2168
2169


2170
2171
2172
2173
2174
2175
2176





2177












2178
2179
2180
2181







2182
2183
2184
2185
2186
2187
2188
2189






























2190



2191






2192
2193
2194
2195
2196
2197
2198
2199



















































2200
2201
2202






2203
2204


2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218









































2219
2220
2221
2222
2223
2224
2225
2226



2227

2228
2229
2230
2231
2232
2233
2234


















2235
2236

2237

2238

2239
2240
2241
2242
2243
2244

2245
2246
2247
2248




2249


2250
2251
2252
2253
2254
2255













2256
2257
2258
2259
2260
2261
2262










2263
2264
2265
2266
2267

2268
2269
2270
2271

























2272
































































2273
2274
2275
2276









2277
2278
2279
2280
2281
2282
2283
2284
2285
2286















2287
2288
2289
2290




















2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309






















































































2310
2311
2312
2313
2314
2315
2316

2317


2318
2319

2320
2321





2322


2323
2324
2325
2326
2327
2328
2329
2330





























2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345


























2346
2347
2348
2349









































2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372


2373
2374
2375
2376
2377
2378
2379
2380

2381
2382
2383



2384
2385
2386
2387

2388
2389
2390
2391
2392
2393
2394
2395
2396
2397

2398
2399
2400




2401
2402
2403
2404
2405
2406
2407


2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421

2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436



2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453

2454
2455
2456
2457

2458
2459
2460

2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478

2479
2480

2481
2482

2483
2484
2485
2486




2487












2488
2489

2490
2491
2492


2493
2494

2495
2496
2497
2498
2499
2500


2501
2502
2503
2504
2505
2506







2507
2508
2509







2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
1934
1935
1936
1937
1938
1939
1940

1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957


1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
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
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032


2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047

2048
2049
2050
2051
2052

2053



2054
2055
2056
2057






2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071

2072





2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085


2086
2087
2088
2089
2090
2091
2092
2093
2094
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
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176


2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200




2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228


2229





2230
2231
2232
2233
2234




2235
2236
2237
2238
2239
2240




2241
2242
2243
2244
2245
2246
2247
2248
2249



2250
2251
2252
2253


2254
2255




2256
2257
2258
2259



2260
2261
2262




2263
2264
2265
2266











2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351









2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399


2400











2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416








2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434


2435
2436
2437
2438
2439
2440
2441





2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478



2479
2480
2481
2482
2483
2484



2485
2486
2487
2488






2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500








2501




2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524


2525
2526
2527
2528
2529
2530

2531

2532
2533





2534

2535
2536
2537


2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574










2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648













2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716

2717


2718




2719






2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774


2775
2776



2777
2778
2779
2780




2781
2782


2783
2784
2785
2786





2787
2788
2789
2790
2791
2792











2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845

2846
2847
2848
2849
2850
2851
2852
2853
2854


2855
2856
2857
2858
2859
2860
2861
2862
2863


2864
2865
2866
2867
2868
2869

2870











2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900



2901
2902
2903
2904
2905
2906







2907
2908
2909
2910







2911
2912
2913
2914
2915
2916
2917
2918
2919
2920





2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934






2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954













2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026






3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039







3040
3041






3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083


3084
3085
3086
3087
3088

3089





3090
3091
3092
3093
3094
3095


3096



3097
3098
3099


3100
3101




3102


3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120




3121
3122
3123
3124
3125
3126
3127








3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157

3158
3159
3160
3161
3162
3163
3164
3165
3166
3167








3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218



3219
3220
3221
3222
3223
3224


3225
3226














3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270


3271
3272
3273
3274
3275
3276

3277

3278





3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296


3297
3298
3299

3300




3301

3302




3303
3304
3305
3306
3307
3308
3309






3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322







3323
3324
3325
3326
3327
3328
3329
3330
3331
3332





3333




3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423




3424
3425
3426
3427
3428
3429
3430
3431
3432










3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447




3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467



















3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561

3562
3563
3564

3565


3566
3567
3568
3569
3570
3571
3572
3573








3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602















3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628




3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
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
3680
3681
3682
3683
3684
3685
3686
3687


3688
3689
3690
3691



3692










3693



3694
3695
3696
3697







3698
3699





3700
3701
3702
3703
3704
3705
3706
3707

3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720



3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739

3740
3741
3742
3743

3744
3745
3746

3747
3748
3749

3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763

3764
3765

3766
3767

3768
3769

3770
3771
3772
3773
3774
3775

3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788

3789
3790


3791
3792
3793

3794






3795
3796






3797
3798
3799
3800
3801
3802
3803



3804
3805
3806
3807
3808
3809
3810








3811
3812
3813
3814
3815
3816
3817







-
+



+












-
-
+
+
+
+
+








+









-
+





-
+


+

+
+
+
+
-
+



+




















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

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

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

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

+
+
+

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

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

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

-
-
+
+
+


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

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

+
+
+
-
+
-
+

-
-
-
-
-
+
-



-
-
+
+
+
+
+
+
+
+

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

-
+
-
-
+
-
-
-
-

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

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

+
-
+








-
-
+


+





-
-
+


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


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

-
-
+
+

+

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

-
-
+
+
+
+
+

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

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



-
-



+
+
+
-
+
-

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

+
-
+
-
-
-
-

-
+
-
-
-
-
+
+
+
+

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

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







+
-
+
+

-
+
-
-
+
+
+
+
+

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



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




-
-
+
+
-







+

-
-
+
+
+

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








-
+












-
-
-
+
+
+
















-
+



-
+


-
+


-














-
+

-
+

-
+

-


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

-
+

-
-
+
+

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







      goto json_parse_restart;
    }
    pParse->iErr = i;
    return -1;
  }
  case 'n': {
    if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
      jsonParseAddNode(pParse, JSON_NULL, 0, 0);
      jsonBlobAppendOneByte(pParse, JSONB_NULL);
      return i+4;
    }
    /* fall-through into the default case that checks for NaN */
    /* no break */ deliberate_fall_through
  }
  default: {
    u32 k;
    int nn;
    c = z[i];
    for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
      if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
      nn = aNanInfName[k].n;
      if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
        continue;
      }
      if( sqlite3Isalnum(z[i+nn]) ) continue;
      jsonParseAddNode(pParse, aNanInfName[k].eType,
          aNanInfName[k].nRepl, aNanInfName[k].zRepl);
      if( aNanInfName[k].eType==JSONB_FLOAT ){
        jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
      }else{
        jsonBlobAppendOneByte(pParse, JSONB_NULL);
      }
      pParse->hasNonstd = 1;
      return i + nn;
    }
    pParse->iErr = i;
    return -1;  /* Syntax error */
  }
  } /* End switch(z[i]) */
}


/*
** Parse a complete JSON string.  Return 0 on success or non-zero if there
** are any errors.  If an error occurs, free all memory held by pParse,
** but not pParse itself.
**
** pParse must be initialized to an empty parse object prior to calling
** this routine.
*/
static int jsonParse(
static int jsonConvertTextToBlob(
  JsonParse *pParse,           /* Initialize and fill this JsonParse object */
  sqlite3_context *pCtx        /* Report errors here */
){
  int i;
  const char *zJson = pParse->zJson;
  i = jsonParseValue(pParse, 0);
  i = jsonTranslateTextToBlob(pParse, 0);
  if( pParse->oom ) i = -1;
  if( i>0 ){
#ifdef SQLITE_DEBUG
    assert( pParse->iDepth==0 );
    if( sqlite3Config.bJsonSelfcheck ){
      assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 );
    }   
#endif
    while( fast_isspace(zJson[i]) ) i++;
    while( jsonIsspace(zJson[i]) ) i++;
    if( zJson[i] ){
      i += json5Whitespace(&zJson[i]);
      if( zJson[i] ){
        if( pCtx ) sqlite3_result_error(pCtx, "malformed JSON", -1);
        jsonParseReset(pParse);
        return 1;
      }
      pParse->hasNonstd = 1;
    }
  }
  if( i<=0 ){
    if( pCtx!=0 ){
      if( pParse->oom ){
        sqlite3_result_error_nomem(pCtx);
      }else{
        sqlite3_result_error(pCtx, "malformed JSON", -1);
      }
    }
    jsonParseReset(pParse);
    return 1;
  }
  return 0;
}

/*
** The input string pStr is a well-formed JSON text string.  Convert
** this into the JSONB format and make it the return value of the
** SQL function.
*/
static void jsonReturnStringAsBlob(JsonString *pStr){
  JsonParse px;
  memset(&px, 0, sizeof(px));
  jsonStringTerminate(pStr);
  if( pStr->eErr ){
    sqlite3_result_error_nomem(pStr->pCtx);
    return;

/* Mark node i of pParse as being a child of iParent.  Call recursively
  }
  px.zJson = pStr->zBuf;
  px.nJson = pStr->nUsed;
  px.db = sqlite3_context_db_handle(pStr->pCtx);
  (void)jsonTranslateTextToBlob(&px, 0);
  if( px.oom ){
    sqlite3DbFree(px.db, px.aBlob);
    sqlite3_result_error_nomem(pStr->pCtx);
  }else{
    assert( px.nBlobAlloc>0 );
    assert( !px.bReadOnly );
    sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, SQLITE_DYNAMIC);
  }
}

** to fill in all the descendants of node i.
/* The byte at index i is a node type-code.  This routine
** determines the payload size for that node and writes that
** payload size in to *pSz.  It returns the offset from i to the
** beginning of the payload.  Return 0 on error.
*/
static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
  JsonNode *pNode = &pParse->aNode[i];
  u32 j;
  pParse->aUp[i] = iParent;
  u8 x;
  u32 sz;
  u32 n;
  if( NEVER(i>pParse->nBlob) ){
  switch( pNode->eType ){
    case JSON_ARRAY: {
      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
        jsonParseFillInParentage(pParse, i+j, i);
      }
      break;
    *pSz = 0;
    return 0;
  }
  x = pParse->aBlob[i]>>4;
  if( x<=11 ){
    sz = x;
    n = 1;
  }else if( x==12 ){
    if( i+1>=pParse->nBlob ){
      *pSz = 0;
      return 0;
    }
    sz = pParse->aBlob[i+1];
    n = 2;
    case JSON_OBJECT: {
  }else if( x==13 ){
      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
        pParse->aUp[i+j] = i;
        jsonParseFillInParentage(pParse, i+j+1, i);
      }
      break;
    if( i+2>=pParse->nBlob ){
      *pSz = 0;
      return 0;
    }
    sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2];
    n = 3;
  }else if( x==14 ){
    if( i+4>=pParse->nBlob ){
      *pSz = 0;
      return 0;
    }
    sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) +
         (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4];
    default: {
      break;
    n = 5;
  }else{
    if( i+8>=pParse->nBlob
     || pParse->aBlob[i+1]!=0
     || pParse->aBlob[i+2]!=0
     || pParse->aBlob[i+3]!=0
     || pParse->aBlob[i+4]!=0
    ){
      *pSz = 0;
      return 0;
    }
    sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
         (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8];
    n = 9;
  }
  if( (i64)i+sz+n > pParse->nBlob
   && (i64)i+sz+n > pParse->nBlob-pParse->delta
  ){
    sz = 0;
    n = 0;
}

  }
  *pSz = sz;
  return n;
}


/*
** Compute the parentage of all nodes in a completed parse.
** Translate the binary JSONB representation of JSON beginning at
** pParse->aBlob[i] into a JSON text string.  Append the JSON
** text onto the end of pOut.  Return the index in pParse->aBlob[]
** of the first byte past the end of the element that is translated.
**
** If an error is detected in the BLOB input, the pOut->eErr flag
** might get set to JSTRING_MALFORMED.  But not all BLOB input errors
** are detected.  So a malformed JSONB input might either result
** in an error, or in incorrect JSON.
**
** The pOut->eErr JSTRING_OOM flag is set on a OOM.
*/
static u32 jsonTranslateBlobToText(
static int jsonParseFindParents(JsonParse *pParse){
  u32 *aUp;
  assert( pParse->aUp==0 );
  aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
  if( aUp==0 ){
    pParse->oom = 1;
    return SQLITE_NOMEM;
  }
  jsonParseFillInParentage(pParse, 0, 0);
  return SQLITE_OK;
}

  const JsonParse *pParse,       /* the complete parse of the JSON */
  u32 i,                         /* Start rendering at this index */
  JsonString *pOut               /* Write JSON here */
){
  u32 sz, n, j, iEnd;

  n = jsonbPayloadSize(pParse, i, &sz);
  if( n==0 ){
    pOut->eErr |= JSTRING_MALFORMED;
    return pParse->nBlob+1;
  }
  switch( pParse->aBlob[i] & 0x0f ){
    case JSONB_NULL: {
      jsonAppendRawNZ(pOut, "null", 4);
      return i+1;
    }
    case JSONB_TRUE: {
      jsonAppendRawNZ(pOut, "true", 4);
      return i+1;
    }
    case JSONB_FALSE: {
      jsonAppendRawNZ(pOut, "false", 5);
      return i+1;
    }
    case JSONB_INT:
    case JSONB_FLOAT: {
      if( sz==0 ) goto malformed_jsonb;
      jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
      break;
    }
    case JSONB_INT5: {  /* Integer literal in hexadecimal notation */
      u32 k = 2;
      sqlite3_uint64 u = 0;
      const char *zIn = (const char*)&pParse->aBlob[i+n];
      int bOverflow = 0;
      if( sz==0 ) goto malformed_jsonb;
      if( zIn[0]=='-' ){
        jsonAppendChar(pOut, '-');
        k++;
      }else if( zIn[0]=='+' ){
        k++;
      }
      for(; k<sz; k++){
        if( !sqlite3Isxdigit(zIn[k]) ){
          pOut->eErr |= JSTRING_MALFORMED;
          break;
        }else if( (u>>60)!=0 ){
          bOverflow = 1;
        }else{
          u = u*16 + sqlite3HexToInt(zIn[k]);
        }
/*
** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
      }
      jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u);
      break;
    }
    case JSONB_FLOAT5: { /* Float literal missing digits beside "." */
      u32 k = 0;
      const char *zIn = (const char*)&pParse->aBlob[i+n];
      if( sz==0 ) goto malformed_jsonb;
      if( zIn[0]=='-' ){
        jsonAppendChar(pOut, '-');
        k++;
      }
      if( zIn[k]=='.' ){
        jsonAppendChar(pOut, '0');
      }
      for(; k<sz; k++){
        jsonAppendChar(pOut, zIn[k]);
        if( zIn[k]=='.' && (k+1==sz || !sqlite3Isdigit(zIn[k+1])) ){
          jsonAppendChar(pOut, '0');
        }
      }
      break;
    }
    case JSONB_TEXT:
*/
#define JSON_CACHE_ID  (-429938)  /* First cache entry */
#define JSON_CACHE_SZ  4          /* Max number of cache entries */

    case JSONB_TEXTJ: {
      jsonAppendChar(pOut, '"');
      jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
      jsonAppendChar(pOut, '"');
      break;
    }
    case JSONB_TEXT5: {
      const char *zIn;
      u32 k;
      u32 sz2 = sz;
      zIn = (const char*)&pParse->aBlob[i+n];
      jsonAppendChar(pOut, '"');
      while( sz2>0 ){
        for(k=0; k<sz2 && (jsonIsOk[(u8)zIn[k]] || zIn[k]=='\''); k++){}
        if( k>0 ){
          jsonAppendRawNZ(pOut, zIn, k);
          if( k>=sz2 ){
            break;
          }
          zIn += k;
          sz2 -= k;
        }
        if( zIn[0]=='"' ){
          jsonAppendRawNZ(pOut, "\\\"", 2);
          zIn++;
          sz2--;
          continue;
        }
/*
** Obtain a complete parse of the JSON found in the pJson argument
        if( zIn[0]<=0x1f ){
**
** Use the sqlite3_get_auxdata() cache to find a preexisting parse
** if it is available.  If the cache is not available or if it
** is no longer valid, parse the JSON again and return the new parse.
** Also register the new parse so that it will be available for
          if( pOut->nUsed+7>pOut->nAlloc && jsonStringGrow(pOut,7) ) break;
          jsonAppendControlChar(pOut, zIn[0]);
          zIn++;
          sz2--;
          continue;
** future sqlite3_get_auxdata() calls.
**
** If an error occurs and pErrCtx!=0 then report the error on pErrCtx
** and return NULL.
        }
        assert( zIn[0]=='\\' );
        assert( sz2>=1 );
        if( sz2<2 ){
          pOut->eErr |= JSTRING_MALFORMED;
          break;
**
** The returned pointer (if it is not NULL) is owned by the cache in
** most cases, not the caller.  The caller does NOT need to invoke
** jsonParseFree(), in most cases.
        }
        switch( (u8)zIn[1] ){
          case '\'':
            jsonAppendChar(pOut, '\'');
            break;
          case 'v':
            jsonAppendRawNZ(pOut, "\\u0009", 6);
            break;
          case 'x':
**
** Except, if an error occurs and pErrCtx==0 then return the JsonParse
** object with JsonParse.nErr non-zero and the caller will own the JsonParse
            if( sz2<4 ){
              pOut->eErr |= JSTRING_MALFORMED;
              sz2 = 2;
              break;
** object.  In that case, it will be the responsibility of the caller to
** invoke jsonParseFree().  To summarize:
            }
            jsonAppendRawNZ(pOut, "\\u00", 4);
**
**   pErrCtx!=0 || p->nErr==0      ==>   Return value p is owned by the
**                                       cache.  Call does not need to
**                                       free it.
            jsonAppendRawNZ(pOut, &zIn[2], 2);
            zIn += 2;
            sz2 -= 2;
            break;
**
**   pErrCtx==0 && p->nErr!=0      ==>   Return value is owned by the caller
**                                       and so the caller must free it.
          case '0':
            jsonAppendRawNZ(pOut, "\\u0000", 6);
            break;
*/
static JsonParse *jsonParseCached(
  sqlite3_context *pCtx,         /* Context to use for cache search */
  sqlite3_value *pJson,          /* Function param containing JSON text */
          case '\r':
            if( sz2>2 && zIn[2]=='\n' ){
              zIn++;
              sz2--;
  sqlite3_context *pErrCtx,      /* Write parse errors here if not NULL */
  int bUnedited                  /* No prior edits allowed */
){
  char *zJson = (char*)sqlite3_value_text(pJson);
  int nJson = sqlite3_value_bytes(pJson);
  JsonParse *p;
  JsonParse *pMatch = 0;
  int iKey;
  int iMinKey = 0;
  u32 iMinHold = 0xffffffff;
  u32 iMaxHold = 0;
            }
            break;
          case '\n':
            break;
          case 0xe2:
            /* '\' followed by either U+2028 or U+2029 is ignored as
            ** whitespace.  Not that in UTF8, U+2028 is 0xe2 0x80 0x29.
            ** U+2029 is the same except for the last byte */
            if( sz2<4
             || 0x80!=(u8)zIn[2]
             || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3])
            ){
              pOut->eErr |= JSTRING_MALFORMED;
              sz2 = 2;
              break;
            }
            zIn += 2;
            sz2 -= 2;
            break;
          default:
            jsonAppendRawNZ(pOut, zIn, 2);
            break;
        }
        assert( sz2>=2 );
        zIn += 2;
        sz2 -= 2;
      }
      jsonAppendChar(pOut, '"');
      break;
    }
    case JSONB_TEXTRAW: {
      jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz);
      break;
    }
    case JSONB_ARRAY: {
      jsonAppendChar(pOut, '[');
      j = i+n;
      iEnd = j+sz;
      while( j<iEnd && pOut->eErr==0 ){
        j = jsonTranslateBlobToText(pParse, j, pOut);
        jsonAppendChar(pOut, ',');
      }
      if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
      if( sz>0 ) jsonStringTrimOneChar(pOut);
      jsonAppendChar(pOut, ']');
      break;
    }
    case JSONB_OBJECT: {
      int x = 0;
      jsonAppendChar(pOut, '{');
      j = i+n;
      iEnd = j+sz;
      while( j<iEnd && pOut->eErr==0 ){
        j = jsonTranslateBlobToText(pParse, j, pOut);
        jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
      }
      if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
      if( sz>0 ) jsonStringTrimOneChar(pOut);
      jsonAppendChar(pOut, '}');
      break;
    }

    default: {
      malformed_jsonb:
      pOut->eErr |= JSTRING_MALFORMED;
      break;
    }
  }
  return i+n+sz;
}

/* Context for recursion of json_pretty()
*/
typedef struct JsonPretty JsonPretty;
struct JsonPretty {
  JsonParse *pParse;        /* The BLOB being rendered */
  JsonString *pOut;         /* Generate pretty output into this string */
  const char *zIndent;      /* Use this text for indentation */
  u32 szIndent;             /* Bytes in zIndent[] */
  u32 nIndent;              /* Current level of indentation */
};

/* Append indentation to the pretty JSON under construction */
static void jsonPrettyIndent(JsonPretty *pPretty){
  u32 jj;
  int bJsonRCStr;

  if( zJson==0 ) return 0;
  for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
    p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
    if( p==0 ){
      iMinKey = iKey;
      break;
    }
  for(jj=0; jj<pPretty->nIndent; jj++){
    jsonAppendRaw(pPretty->pOut, pPretty->zIndent, pPretty->szIndent);
  }
}

/*
** Translate the binary JSONB representation of JSON beginning at
** pParse->aBlob[i] into a JSON text string.  Append the JSON
** text onto the end of pOut.  Return the index in pParse->aBlob[]
** of the first byte past the end of the element that is translated.
**
** This is a variant of jsonTranslateBlobToText() that "pretty-prints"
** the output.  Extra whitespace is inserted to make the JSON easier
** for humans to read.
**
** If an error is detected in the BLOB input, the pOut->eErr flag
** might get set to JSTRING_MALFORMED.  But not all BLOB input errors
** are detected.  So a malformed JSONB input might either result
** in an error, or in incorrect JSON.
**
** The pOut->eErr JSTRING_OOM flag is set on a OOM.
*/
static u32 jsonTranslateBlobToPrettyText(
  JsonPretty *pPretty,       /* Pretty-printing context */
  u32 i                      /* Start rendering at this index */
){
  u32 sz, n, j, iEnd;
  const JsonParse *pParse = pPretty->pParse;
  JsonString *pOut = pPretty->pOut;
  n = jsonbPayloadSize(pParse, i, &sz);
  if( n==0 ){
    pOut->eErr |= JSTRING_MALFORMED;
    return pParse->nBlob+1;
  }
  switch( pParse->aBlob[i] & 0x0f ){
    case JSONB_ARRAY: {
      j = i+n;
      iEnd = j+sz;
      jsonAppendChar(pOut, '[');
      if( j<iEnd ){
        jsonAppendChar(pOut, '\n');
        pPretty->nIndent++;
        while( pOut->eErr==0 ){
          jsonPrettyIndent(pPretty);
          j = jsonTranslateBlobToPrettyText(pPretty, j);
          if( j>=iEnd ) break;
          jsonAppendRawNZ(pOut, ",\n", 2);
        }
    if( pMatch==0
     && p->nJson==nJson
        jsonAppendChar(pOut, '\n');
     && (p->hasMod==0 || bUnedited==0)
     && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0)
    ){
      p->nErr = 0;
      p->useMod = 0;
      pMatch = p;
    }else
    if( pMatch==0
     && p->zAlt!=0
     && bUnedited==0
     && p->nAlt==nJson
        pPretty->nIndent--;
        jsonPrettyIndent(pPretty);
      }
      jsonAppendChar(pOut, ']');
      i = iEnd;
      break;
    }
    case JSONB_OBJECT: {
      j = i+n;
      iEnd = j+sz;
      jsonAppendChar(pOut, '{');
      if( j<iEnd ){
        jsonAppendChar(pOut, '\n');
        pPretty->nIndent++;
        while( pOut->eErr==0 ){
          jsonPrettyIndent(pPretty);
     && memcmp(p->zAlt, zJson, nJson)==0
    ){
      p->nErr = 0;
      p->useMod = 1;
      pMatch = p;
    }else if( p->iHold<iMinHold ){
      iMinHold = p->iHold;
      iMinKey = iKey;
          j = jsonTranslateBlobToText(pParse, j, pOut);
          if( j>iEnd ){
            pOut->eErr |= JSTRING_MALFORMED;
            break;
          }
          jsonAppendRawNZ(pOut, ": ", 2);
          j = jsonTranslateBlobToPrettyText(pPretty, j);
          if( j>=iEnd ) break;
          jsonAppendRawNZ(pOut, ",\n", 2);
        }
        jsonAppendChar(pOut, '\n');
        pPretty->nIndent--;
        jsonPrettyIndent(pPretty);
      }
      jsonAppendChar(pOut, '}');
      i = iEnd;
      break;
    }
    if( p->iHold>iMaxHold ){
      iMaxHold = p->iHold;
    default: {
      i = jsonTranslateBlobToText(pParse, i, pOut);
      break;
    }
  }
  return i;
}
  if( pMatch ){
    /* The input JSON text was found in the cache.  Use the preexisting
    ** parse of this JSON */
    pMatch->nErr = 0;
    pMatch->iHold = iMaxHold+1;


/* Return true if the input pJson
**
** For performance reasons, this routine does not do a detailed check of the
** input BLOB to ensure that it is well-formed.  Hence, false positives are
** possible.  False negatives should never occur, however.
*/
static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){
  u32 sz, n;
  const u8 *aBlob;
  int nBlob;
  JsonParse s;
  if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0;
  aBlob = sqlite3_value_blob(pJson);
  nBlob = sqlite3_value_bytes(pJson);
  if( nBlob<1 ) return 0;
  if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0;
  memset(&s, 0, sizeof(s));
  s.aBlob = (u8*)aBlob;
  s.nBlob = nBlob;
  n = jsonbPayloadSize(&s, 0, &sz);
  if( n==0 ) return 0;
  if( sz+n!=(u32)nBlob ) return 0;
  if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0;
  return sz+n==(u32)nBlob;
}

/*
** Given that a JSONB_ARRAY object starts at offset i, return
** the number of entries in that array.
*/
static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){
  u32 n, sz, i, iEnd;
  u32 k = 0;
  n = jsonbPayloadSize(pParse, iRoot, &sz);
  iEnd = iRoot+n+sz;
    assert( pMatch->nJPRef>0 ); /* pMatch is owned by the cache */
    return pMatch;
  }
  for(i=iRoot+n; n>0 && i<iEnd; i+=sz+n, k++){
    n = jsonbPayloadSize(pParse, i, &sz);
  }
  return k;
}

  /* The input JSON was not found anywhere in the cache.  We will need
  ** to parse it ourselves and generate a new JsonParse object.
  */
/*
** Edit the payload size of the element at iRoot by the amount in
** pParse->delta.
*/
  bJsonRCStr = sqlite3ValueIsOfClass(pJson,sqlite3RCStrUnref);
  p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) );
  if( p==0 ){
    sqlite3_result_error_nomem(pCtx);
    return 0;
  }
static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
  u32 sz = 0;
  u32 nBlob;
  assert( pParse->delta!=0 );
  assert( pParse->nBlobAlloc >= pParse->nBlob );
  nBlob = pParse->nBlob;
  pParse->nBlob = pParse->nBlobAlloc;
  (void)jsonbPayloadSize(pParse, iRoot, &sz);
  pParse->nBlob = nBlob;
  sz += pParse->delta;
  pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz);
}
  memset(p, 0, sizeof(*p));
  if( bJsonRCStr ){
    p->zJson = sqlite3RCStrRef(zJson);
    p->bJsonIsRCStr = 1;
  }else{
    p->zJson = (char*)&p[1];
    memcpy(p->zJson, zJson, nJson+1);
  }

  p->nJPRef = 1;
  if( jsonParse(p, pErrCtx) ){
    if( pErrCtx==0 ){
      p->nErr = 1;
/*
** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
** content beginning at iDel, and replacing them with nIns bytes of
** content given by aIns.
**
** nDel may be zero, in which case no bytes are removed.  But iDel is
** still important as new bytes will be insert beginning at iDel.
**
** aIns may be zero, in which case space is created to hold nIns bytes
** beginning at iDel, but that space is uninitialized.
**
** Set pParse->oom if an OOM occurs.
*/
static void jsonBlobEdit(
  JsonParse *pParse,     /* The JSONB to be modified is in pParse->aBlob */
  u32 iDel,              /* First byte to be removed */
  u32 nDel,              /* Number of bytes to remove */
  const u8 *aIns,        /* Content to insert */
  u32 nIns               /* Bytes of content to insert */
){
  i64 d = (i64)nIns - (i64)nDel;
  if( d!=0 ){
    if( pParse->nBlob + d > pParse->nBlobAlloc ){
      assert( p->nJPRef==1 ); /* Caller will own the new JsonParse object p */
      return p;
      jsonBlobExpand(pParse, pParse->nBlob+d);
      if( pParse->oom ) return;
    }
    memmove(&pParse->aBlob[iDel+nIns],
            &pParse->aBlob[iDel+nDel],
            pParse->nBlob - (iDel+nDel));
    jsonParseFree(p);
    pParse->nBlob += d;
    return 0;
    pParse->delta += d;
  }
  p->nJson = nJson;
  p->iHold = iMaxHold+1;
  /* Transfer ownership of the new JsonParse to the cache */
  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
                      (void(*)(void*))jsonParseFree);
  if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
}

/*
** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
** a match.
** Return the number of escaped newlines to be ignored.
** An escaped newline is a one of the following byte sequences:
**
**    0x5c 0x0a
**    0x5c 0x0d
**    0x5c 0x0d 0x0a
**    0x5c 0xe2 0x80 0xa8
**    0x5c 0xe2 0x80 0xa9
*/
static u32 jsonBytesToBypass(const char *z, u32 n){
  u32 i = 0;
  while( i+1<n ){
    if( z[i]!='\\' ) return i;
    if( z[i+1]=='\n' ){
      i += 2;
      continue;
    }
    if( z[i+1]=='\r' ){
      if( i+2<n && z[i+2]=='\n' ){
        i += 3;
      }else{
        i += 2;
      }
      continue;
    }
    if( 0xe2==(u8)z[i+1]
     && i+3<n
     && 0x80==(u8)z[i+2]
     && (0xa8==(u8)z[i+3] || 0xa9==(u8)z[i+3])
    ){
      i += 4;
      continue;
    }
    break;
  }
  return i;
}
static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){
  assert( pNode->eU==1 );
  if( pNode->jnFlags & JNODE_RAW ){
    if( pNode->n!=nKey ) return 0;
    return strncmp(pNode->u.zJContent, zKey, nKey)==0;
  }else{
    if( pNode->n!=nKey+2 ) return 0;
    return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
  }
}

/*
** Input z[0..n] defines JSON escape sequence including the leading '\\'.
** Decode that escape sequence into a single character.  Write that
** character into *piOut.  Return the number of bytes in the escape sequence.
**
** If there is a syntax error of some kind (for example too few characters
** after the '\\' to complete the encoding) then *piOut is set to
** JSON_INVALID_CHAR.
*/
static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){
  assert( n>0 );
  assert( z[0]=='\\' );
  if( n<2 ){
    *piOut = JSON_INVALID_CHAR;
    return n;
  }
  switch( (u8)z[1] ){
    case 'u': {
      u32 v, vlo;
      if( n<6 ){
        *piOut = JSON_INVALID_CHAR;
        return n;
      }
      v = jsonHexToInt4(&z[2]);
      if( (v & 0xfc00)==0xd800
       && n>=12
       && z[6]=='\\'
       && z[7]=='u'
       && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00
      ){
        *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
        return 12;
      }else{
        *piOut = v;
        return 6;
      }
    }
    case 'b': {   *piOut = '\b';  return 2; }
    case 'f': {   *piOut = '\f';  return 2; }
    case 'n': {   *piOut = '\n';  return 2; }
    case 'r': {   *piOut = '\r';  return 2; }
    case 't': {   *piOut = '\t';  return 2; }
    case 'v': {   *piOut = '\v';  return 2; }
    case '0': {   *piOut = 0;     return 2; }
    case '\'':
    case '"':
    case '/':
    case '\\':{   *piOut = z[1];  return 2; }
    case 'x': {
      if( n<4 ){
        *piOut = JSON_INVALID_CHAR;
        return n;
      }
      *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]);
      return 4;
    }
    case 0xe2:
    case '\r':
    case '\n': {
      u32 nSkip = jsonBytesToBypass(z, n);
      if( nSkip==0 ){
        *piOut = JSON_INVALID_CHAR;
        return n;
      }else if( nSkip==n ){
        *piOut = 0;
        return n;
      }else if( z[nSkip]=='\\' ){
        return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut);
      }else{
        int sz = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut);
        return nSkip + sz;
      }
    }
static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){
  if( p1->jnFlags & JNODE_RAW ){
    return jsonLabelCompare(p2, p1->u.zJContent, p1->n);
  }else if( p2->jnFlags & JNODE_RAW ){
    return jsonLabelCompare(p1, p2->u.zJContent, p2->n);
  }else{
    return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0;
  }
}

/* forward declaration */
static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);

    default: {
      *piOut = JSON_INVALID_CHAR;
      return 2;
    }
  }
}


/*
** Compare two object labels.  Return 1 if they are equal and
** 0 if they differ.
**
** In this version, we know that one or the other or both of the
** two comparands contains an escape sequence.
*/
static SQLITE_NOINLINE int jsonLabelCompareEscaped(
  const char *zLeft,          /* The left label */
  u32 nLeft,                  /* Size of the left label in bytes */
  int rawLeft,                /* True if zLeft contains no escapes */
  const char *zRight,         /* The right label */
  u32 nRight,                 /* Size of the right label in bytes */
  int rawRight                /* True if zRight is escape-free */
){
  u32 cLeft, cRight;
  assert( rawLeft==0 || rawRight==0 );
  while( 1 /*exit-by-return*/ ){
    if( nLeft==0 ){
      cLeft = 0;
    }else if( rawLeft || zLeft[0]!='\\' ){
      cLeft = ((u8*)zLeft)[0];
      if( cLeft>=0xc0 ){
        int sz = sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft);
        zLeft += sz;
        nLeft -= sz;
      }else{
        zLeft++;
        nLeft--;
      }
    }else{
      u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft);
      zLeft += n;
      assert( n<=nLeft );
      nLeft -= n;
    }
    if( nRight==0 ){
      cRight = 0;
    }else if( rawRight || zRight[0]!='\\' ){
      cRight = ((u8*)zRight)[0];
      if( cRight>=0xc0 ){
        int sz = sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight);
        zRight += sz;
        nRight -= sz;
      }else{
        zRight++;
        nRight--;
      }
    }else{
      u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight);
      zRight += n;
      assert( n<=nRight );
      nRight -= n;
    }
    if( cLeft!=cRight ) return 0;
    if( cLeft==0 ) return 1;
  }
}

/*
** Search along zPath to find the node specified.  Return a pointer
** Compare two object labels.  Return 1 if they are equal and
** to that node, or NULL if zPath is malformed or if there is no such
** node.
** 0 if they differ.  Return -1 if an OOM occurs.
**
** If pApnd!=0, then try to append new nodes to complete zPath if it is
** possible to do so and if no existing node corresponds to zPath.  If
** new nodes are appended *pApnd is set to 1.
*/
static JsonNode *jsonLookupStep(
  JsonParse *pParse,      /* The JSON to search */
  u32 iRoot,              /* Begin the search at this node */
  const char *zPath,      /* The path to search */
  int *pApnd,             /* Append nodes to complete path if not NULL */
  const char **pzErr      /* Make *pzErr point to any syntax error in zPath */
static int jsonLabelCompare(
  const char *zLeft,          /* The left label */
  u32 nLeft,                  /* Size of the left label in bytes */
  int rawLeft,                /* True if zLeft contains no escapes */
  const char *zRight,         /* The right label */
  u32 nRight,                 /* Size of the right label in bytes */
  int rawRight                /* True if zRight is escape-free */
){
  if( rawLeft && rawRight ){
    /* Simpliest case:  Neither label contains escapes.  A simple
    ** memcmp() is sufficient. */
    if( nLeft!=nRight ) return 0;
    return memcmp(zLeft, zRight, nLeft)==0;
  }else{
    return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft,
                                   zRight, nRight, rawRight);
  }
}

/*
** Error returns from jsonLookupStep()
*/
#define JSON_LOOKUP_ERROR      0xffffffff
#define JSON_LOOKUP_NOTFOUND   0xfffffffe
#define JSON_LOOKUP_PATHERROR  0xfffffffd
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)

/* Forward declaration */
static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);


/* This helper routine for jsonLookupStep() populates pIns with
** binary data that is to be inserted into pParse.
**
** In the common case, pIns just points to pParse->aIns and pParse->nIns.
** But if the zPath of the original edit operation includes path elements
** that go deeper, additional substructure must be created.
**
** For example:
**
**     json_insert('{}', '$.a.b.c', 123);
**
** The search stops at '$.a'  But additional substructure must be
** created for the ".b.c" part of the patch so that the final result
** is:  {"a":{"b":{"c"::123}}}.  This routine populates pIns with
** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
**
** The caller is responsible for resetting pIns when it has finished
** using the substructure.
*/
static u32 jsonCreateEditSubstructure(
  JsonParse *pParse,  /* The original JSONB that is being edited */
  JsonParse *pIns,    /* Populate this with the blob data to insert */
  const char *zTail   /* Tail of the path that determins substructure */
){
  u32 i, j, nKey;
  const char *zKey;
  static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
  int rc;
  JsonNode *pRoot;
  if( pParse->oom ) return 0;
  pRoot = &pParse->aNode[iRoot];
  memset(pIns, 0, sizeof(*pIns));
  pIns->db = pParse->db;
  if( zTail[0]==0 ){
    /* No substructure.  Just insert what is given in pParse. */
  if( pRoot->jnFlags & (JNODE_REPLACE|JNODE_REMOVE) && pParse->useMod ){
    while( (pRoot->jnFlags & JNODE_REPLACE)!=0 ){
      u32 idx = (u32)(pRoot - pParse->aNode);
      i = pParse->iSubst;
    pIns->aBlob = pParse->aIns;
    pIns->nBlob = pParse->nIns;
      while( 1 /*exit-by-break*/ ){
        assert( i<pParse->nNode );
    rc = 0;
  }else{
    /* Construct the binary substructure */
    pIns->nBlob = 1;
        assert( pParse->aNode[i].eType==JSON_SUBST );
        assert( pParse->aNode[i].eU==4 );
        assert( pParse->aNode[i].u.iPrev<i );
        if( pParse->aNode[i].n==idx ){
          pRoot = &pParse->aNode[i+1];
    pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.'];
    pIns->eEdit = pParse->eEdit;
    pIns->nIns = pParse->nIns;
    pIns->aIns = pParse->aIns;
    rc = jsonLookupStep(pIns, 0, zTail, 0);
    pParse->oom |= pIns->oom;
          iRoot = i+1;
          break;
        }
        i = pParse->aNode[i].u.iPrev;
      }
    }
    if( pRoot->jnFlags & JNODE_REMOVE ){
      return 0;
    }
  }
  if( zPath[0]==0 ) return pRoot;
  }
  return rc;  /* Error code only */
}

/*
** Search along zPath to find the Json element specified.  Return an
** index into pParse->aBlob[] for the start of that element's value.
**
** If the value found by this routine is the value half of label/value pair
** within an object, then set pPath->iLabel to the start of the corresponding
** label, before returning.
**
** Return one of the JSON_LOOKUP error codes if problems are seen.
**
** This routine will also modify the blob.  If pParse->eEdit is one of
** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
** made to the selected value.  If an edit is performed, then the return
** value does not necessarily point to the select element.  If an edit
** is performed, the return value is only useful for detecting error
** conditions.
*/
static u32 jsonLookupStep(
  JsonParse *pParse,      /* The JSON to search */
  u32 iRoot,              /* Begin the search at this element of aBlob[] */
  const char *zPath,      /* The path to search */
  u32 iLabel              /* Label if iRoot is a value of in an object */
){
  u32 i, j, k, nKey, sz, n, iEnd, rc;
  const char *zKey;
  u8 x;

  if( zPath[0]==0 ){
    if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){
      n = jsonbPayloadSize(pParse, iRoot, &sz);
      sz += n;
      if( pParse->eEdit==JEDIT_DEL ){
        if( iLabel>0 ){
          sz += iRoot - iLabel;
          iRoot = iLabel;
        }
        jsonBlobEdit(pParse, iRoot, sz, 0, 0);
      }else if( pParse->eEdit==JEDIT_INS ){
        /* Already exists, so json_insert() is a no-op */
      }else{
        /* json_set() or json_replace() */
        jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns);
      }
    }
    pParse->iLabel = iLabel;
    return iRoot;
  }
  if( zPath[0]=='.' ){
    int rawKey = 1;
    if( pRoot->eType!=JSON_OBJECT ) return 0;
    x = pParse->aBlob[iRoot];
    zPath++;
    if( zPath[0]=='"' ){
      zKey = zPath + 1;
      for(i=1; zPath[i] && zPath[i]!='"'; i++){}
      nKey = i-1;
      if( zPath[i] ){
        i++;
      }else{
        *pzErr = zPath;
        return 0;
        return JSON_LOOKUP_PATHERROR;
      }
      testcase( nKey==0 );
      rawKey = memchr(zKey, '\\', nKey)==0;
    }else{
      zKey = zPath;
      for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
      nKey = i;
      if( nKey==0 ){
        *pzErr = zPath;
        return 0;
        return JSON_LOOKUP_PATHERROR;
      }
    }
    if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND;
    n = jsonbPayloadSize(pParse, iRoot, &sz);
    j = iRoot + n;  /* j is the index of a label */
    j = 1;
    iEnd = j+sz;
    for(;;){
      while( j<=pRoot->n ){
        if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
          return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
        }
        j++;
        j += jsonNodeSize(&pRoot[j]);
      }
      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
      if( pParse->useMod==0 ) break;
      assert( pRoot->eU==2 );
    while( j<iEnd ){
      int rawLabel;
      const char *zLabel;
      x = pParse->aBlob[j] & 0x0f;
      if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return JSON_LOOKUP_ERROR;
      n = jsonbPayloadSize(pParse, j, &sz);
      if( n==0 ) return JSON_LOOKUP_ERROR;
      k = j+n;  /* k is the index of the label text */
      if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR;
      zLabel = (const char*)&pParse->aBlob[k];
      rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW;
      if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){
        u32 v = k+sz;  /* v is the index of the value */
        if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
        n = jsonbPayloadSize(pParse, v, &sz);
        if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
        assert( j>0 );
        rc = jsonLookupStep(pParse, v, &zPath[i], j);
        if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
        return rc;
      }
      j = k+sz;
      if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
      n = jsonbPayloadSize(pParse, j, &sz);
      if( n==0 ) return JSON_LOOKUP_ERROR;
      j += n+sz;
    }
    if( j>iEnd ) return JSON_LOOKUP_ERROR;
    if( pParse->eEdit>=JEDIT_INS ){
      u32 nIns;          /* Total bytes to insert (label+value) */
      iRoot = pRoot->u.iAppend;
      pRoot = &pParse->aNode[iRoot];
      j = 1;
      JsonParse v;       /* BLOB encoding of the value to be inserted */
      JsonParse ix;      /* Header of the label to be inserted */
      testcase( pParse->eEdit==JEDIT_INS );
      testcase( pParse->eEdit==JEDIT_SET );
      memset(&ix, 0, sizeof(ix));
      ix.db = pParse->db;
    }
    if( pApnd ){
      u32 iStart, iLabel;
      JsonNode *pNode;
      assert( pParse->useMod );
      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
      iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
      jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0);
      pParse->oom |= ix.oom;
      rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]);
      if( !JSON_LOOKUP_ISERROR(rc)
      zPath += i;
      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
      if( pParse->oom ) return 0;
      if( pNode ){
        pRoot = &pParse->aNode[iRoot];
        assert( pRoot->eU==0 );
        pRoot->u.iAppend = iStart;
       && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob)
      ){
        assert( !pParse->oom );
        nIns = ix.nBlob + nKey + v.nBlob;
        jsonBlobEdit(pParse, j, 0, 0, nIns);
        if( !pParse->oom ){
          assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */
          assert( ix.aBlob!=0 );      /* Because pPasre->oom!=0 */
          memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob);
          k = j + ix.nBlob;
        pRoot->jnFlags |= JNODE_APPEND;
        VVA( pRoot->eU = 2 );
        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
      }
      return pNode;
          memcpy(&pParse->aBlob[k], zKey, nKey);
          k += nKey;
          memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob);
          if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot);
        }
      }
      jsonParseReset(&v);
      jsonParseReset(&ix);
      return rc;
    }
  }else if( zPath[0]=='[' ){
    x = pParse->aBlob[iRoot] & 0x0f;
    if( x!=JSONB_ARRAY )  return JSON_LOOKUP_NOTFOUND;
    n = jsonbPayloadSize(pParse, iRoot, &sz);
    i = 0;
    j = 1;
    while( sqlite3Isdigit(zPath[j]) ){
      i = i*10 + zPath[j] - '0';
      j++;
    }
    k = 0;
    i = 1;
    while( sqlite3Isdigit(zPath[i]) ){
      k = k*10 + zPath[i] - '0';
      i++;
    }
    if( i<2 || zPath[i]!=']' ){
      if( zPath[1]=='#' ){
        k = jsonbArrayCount(pParse, iRoot);
        i = 2;
        if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
          unsigned int nn = 0;
          i = 3;
          do{
            nn = nn*10 + zPath[i] - '0';
            i++;
          }while( sqlite3Isdigit(zPath[i]) );
          if( nn>k ) return JSON_LOOKUP_NOTFOUND;
          k -= nn;
        }
    if( j<2 || zPath[j]!=']' ){
      if( zPath[1]=='#' ){
        JsonNode *pBase = pRoot;
        int iBase = iRoot;
        if( pRoot->eType!=JSON_ARRAY ) return 0;
        for(;;){
          while( j<=pBase->n ){
            if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++;
            j += jsonNodeSize(&pBase[j]);
          }
          if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
          if( pParse->useMod==0 ) break;
          assert( pBase->eU==2 );
        if( zPath[i]!=']' ){
          return JSON_LOOKUP_PATHERROR;
        }
      }else{
        return JSON_LOOKUP_PATHERROR;
      }
    }
    j = iRoot+n;
    iEnd = j+sz;
    while( j<iEnd ){
      if( k==0 ){
        rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
        if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
        return rc;
      }
      k--;
      n = jsonbPayloadSize(pParse, j, &sz);
      if( n==0 ) return JSON_LOOKUP_ERROR;
      j += n+sz;
    }
    if( j>iEnd ) return JSON_LOOKUP_ERROR;
    if( k>0 ) return JSON_LOOKUP_NOTFOUND;
    if( pParse->eEdit>=JEDIT_INS ){
      JsonParse v;
      testcase( pParse->eEdit==JEDIT_INS );
      testcase( pParse->eEdit==JEDIT_SET );
      rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
      if( !JSON_LOOKUP_ISERROR(rc)
       && jsonBlobMakeEditable(pParse, v.nBlob)
      ){
        assert( !pParse->oom );
        jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob);
      }
      jsonParseReset(&v);
      if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
      return rc;
    }
  }else{
    return JSON_LOOKUP_PATHERROR; 
  }
  return JSON_LOOKUP_NOTFOUND;
}

/*
** Convert a JSON BLOB into text and make that text the return value
** of an SQL function.
*/
static void jsonReturnTextJsonFromBlob(
  sqlite3_context *ctx,
  const u8 *aBlob,
  u32 nBlob
){
  JsonParse x;
  JsonString s;

  if( NEVER(aBlob==0) ) return;
  memset(&x, 0, sizeof(x));
  x.aBlob = (u8*)aBlob;
  x.nBlob = nBlob;
  jsonStringInit(&s, ctx);
  jsonTranslateBlobToText(&x, 0, &s);
  jsonReturnString(&s, 0, 0);
}


/*
** Return the value of the BLOB node at index i.
**
** If the value is a primitive, return it as an SQL value.
** If the value is an array or object, return it as either
** JSON text or the BLOB encoding, depending on the JSON_B flag
** on the userdata.
          iBase = pBase->u.iAppend;
          pBase = &pParse->aNode[iBase];
          j = 1;
        }
        j = 2;
        if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
*/
static void jsonReturnFromBlob(
  JsonParse *pParse,          /* Complete JSON parse tree */
  u32 i,                      /* Index of the node */
  sqlite3_context *pCtx,      /* Return value for this function */
  int textOnly                /* return text JSON.  Disregard user-data */
){
  u32 n, sz;
  int rc;
  sqlite3 *db = sqlite3_context_db_handle(pCtx);

  n = jsonbPayloadSize(pParse, i, &sz);
  if( n==0 ){
          unsigned int x = 0;
          j = 3;
          do{
            x = x*10 + zPath[j] - '0';
            j++;
          }while( sqlite3Isdigit(zPath[j]) );
          if( x>i ) return 0;
    sqlite3_result_error(pCtx, "malformed JSON", -1);
    return;
          i -= x;
        }
        if( zPath[j]!=']' ){
          *pzErr = zPath;
          return 0;
        }
  }
  switch( pParse->aBlob[i] & 0x0f ){
    case JSONB_NULL: {
      if( sz ) goto returnfromblob_malformed;
      sqlite3_result_null(pCtx);
      break;
    }
    case JSONB_TRUE: {
      if( sz ) goto returnfromblob_malformed;
      sqlite3_result_int(pCtx, 1);
      break;
    }
    case JSONB_FALSE: {
      if( sz ) goto returnfromblob_malformed;
      sqlite3_result_int(pCtx, 0);
      break;
    }
    case JSONB_INT5:
    case JSONB_INT: {
      sqlite3_int64 iRes = 0;
      char *z;
      int bNeg = 0;
      char x;
      if( sz==0 ) goto returnfromblob_malformed;
      x = (char)pParse->aBlob[i+n];
      if( x=='-' ){
        if( sz<2 ) goto returnfromblob_malformed;
        n++;
        sz--;
        bNeg = 1;
      }
      z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
      if( z==0 ) goto returnfromblob_oom;
      rc = sqlite3DecOrHexToI64(z, &iRes);
      sqlite3DbFree(db, z);
      if( rc==0 ){
        sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes);
      }else if( rc==3 && bNeg ){
        sqlite3_result_int64(pCtx, SMALLEST_INT64);
      }else if( rc==1 ){
        goto returnfromblob_malformed;
      }else{
        *pzErr = zPath;
        return 0;
        if( bNeg ){ n--; sz++; }
        goto to_double;
      }
      break;
    }
    if( pRoot->eType!=JSON_ARRAY ) return 0;
    case JSONB_FLOAT5:
    zPath += j + 1;
    j = 1;
    for(;;){
      while( j<=pRoot->n
         && (i>0 || ((pRoot[j].jnFlags & JNODE_REMOVE)!=0 && pParse->useMod))
    case JSONB_FLOAT: {
      double r;
      char *z;
      if( sz==0 ) goto returnfromblob_malformed;
    to_double:
      z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
      ){
        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--;
      if( z==0 ) goto returnfromblob_oom;
        j += jsonNodeSize(&pRoot[j]);
      }
      if( i==0 && j<=pRoot->n ) break;
      rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
      sqlite3DbFree(db, z);
      if( rc<=0 ) goto returnfromblob_malformed;
      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
      if( pParse->useMod==0 ) break;
      sqlite3_result_double(pCtx, r);
      break;
      assert( pRoot->eU==2 );
      iRoot = pRoot->u.iAppend;
      pRoot = &pParse->aNode[iRoot];
      j = 1;
    }
    if( j<=pRoot->n ){
      return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
    case JSONB_TEXTRAW:
    case JSONB_TEXT: {
      sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz,
                          SQLITE_TRANSIENT);
      break;
    }
    case JSONB_TEXT5:
    case JSONB_TEXTJ: {
      /* Translate JSON formatted string into raw text */
      u32 iIn, iOut;
      const char *z;
      char *zOut;
      u32 nOut = sz;
      z = (const char*)&pParse->aBlob[i+n];
      zOut = sqlite3DbMallocRaw(db, nOut+1);
      if( zOut==0 ) goto returnfromblob_oom;
      for(iIn=iOut=0; iIn<sz; iIn++){
        char c = z[iIn];
    if( i==0 && pApnd ){
      u32 iStart;
      JsonNode *pNode;
      assert( pParse->useMod );
        if( c=='\\' ){
          u32 v;
          u32 szEscape = jsonUnescapeOneChar(&z[iIn], sz-iIn, &v);
          if( v<=0x7f ){
            zOut[iOut++] = (char)v;
          }else if( v<=0x7ff ){
            assert( szEscape>=2 );
      iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
      if( pParse->oom ) return 0;
      if( pNode ){
        pRoot = &pParse->aNode[iRoot];
        assert( pRoot->eU==0 );
        pRoot->u.iAppend = iStart;
        pRoot->jnFlags |= JNODE_APPEND;
            zOut[iOut++] = (char)(0xc0 | (v>>6));
            zOut[iOut++] = 0x80 | (v&0x3f);
          }else if( v<0x10000 ){
            assert( szEscape>=3 );
            zOut[iOut++] = 0xe0 | (v>>12);
            zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
            zOut[iOut++] = 0x80 | (v&0x3f);
          }else if( v==JSON_INVALID_CHAR ){
            /* Silently ignore illegal unicode */
          }else{
            assert( szEscape>=4 );
            zOut[iOut++] = 0xf0 | (v>>18);
            zOut[iOut++] = 0x80 | ((v>>12)&0x3f);
            zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
            zOut[iOut++] = 0x80 | (v&0x3f);
          }
          iIn += szEscape - 1;
        }else{
          zOut[iOut++] = c;
        }
      } /* end for() */
      assert( iOut<=nOut );
      zOut[iOut] = 0;
      sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC);
      break;
    }
    case JSONB_ARRAY:
    case JSONB_OBJECT: {
      int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx));
      if( flags & JSON_BLOB ){
        VVA( pRoot->eU = 2 );
        sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
      }else{
        jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n);
      }
      break;
    }
    default: {
      goto returnfromblob_malformed;
    }
  }
      return pNode;
    }
  }else{
    *pzErr = zPath;
  }
  return 0;
}

  return;

returnfromblob_oom:
  sqlite3_result_error_nomem(pCtx);
  return;

returnfromblob_malformed:
  sqlite3_result_error(pCtx, "malformed JSON", -1);
  return;
}

/*
** pArg is a function argument that might be an SQL value or a JSON
** value.  Figure out what it is and encode it as a JSONB blob.
** Return the results in pParse.
**
** pParse is uninitialized upon entry.  This routine will handle the
** initialization of pParse.  The result will be contained in
** pParse->aBlob and pParse->nBlob.  pParse->aBlob might be dynamically
** allocated (if pParse->nBlobAlloc is greater than zero) in which case
** the caller is responsible for freeing the space allocated to pParse->aBlob
** when it has finished with it.  Or pParse->aBlob might be a static string
** or a value obtained from sqlite3_value_blob(pArg).
**
** If the argument is a BLOB that is clearly not a JSONB, then this
** function might set an error message in ctx and return non-zero.
** It might also set an error message and return non-zero on an OOM error.
*/
static int jsonFunctionArgToBlob(
  sqlite3_context *ctx,
  sqlite3_value *pArg,
  JsonParse *pParse
){
  int eType = sqlite3_value_type(pArg);
  static u8 aNull[] = { 0x00 };
  memset(pParse, 0, sizeof(pParse[0]));
  pParse->db = sqlite3_context_db_handle(ctx);
  switch( eType ){
    default: {
      pParse->aBlob = aNull;
      pParse->nBlob = 1;
      return 0;
    }
    case SQLITE_BLOB: {
      if( jsonFuncArgMightBeBinary(pArg) ){
        pParse->aBlob = (u8*)sqlite3_value_blob(pArg);
        pParse->nBlob = sqlite3_value_bytes(pArg);
      }else{
        sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1);
        return 1;
      }
/*
** Append content to pParse that will complete zPath.  Return a pointer
** to the inserted node, or return NULL if the append fails.
      break;
    }
    case SQLITE_TEXT: {
      const char *zJson = (const char*)sqlite3_value_text(pArg);
      int nJson = sqlite3_value_bytes(pArg);
      if( zJson==0 ) return 1;
*/
static JsonNode *jsonLookupAppend(
      if( sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){
        pParse->zJson = (char*)zJson;
  JsonParse *pParse,     /* Append content to the JSON parse */
  const char *zPath,     /* Description of content to append */
  int *pApnd,            /* Set this flag to 1 */
  const char **pzErr     /* Make this point to any syntax error */
){
  *pApnd = 1;
  if( zPath[0]==0 ){
    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
    return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
  }
  if( zPath[0]=='.' ){
    jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
  }else if( strncmp(zPath,"[0]",3)==0 ){
    jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
        pParse->nJson = nJson;
        if( jsonConvertTextToBlob(pParse, ctx) ){
          sqlite3_result_error(ctx, "malformed JSON", -1);
          sqlite3DbFree(pParse->db, pParse->aBlob);
          memset(pParse, 0, sizeof(pParse[0]));
          return 1;
        }
      }else{
        jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson);
      }
      break;
    }
    case SQLITE_FLOAT: {
      double r = sqlite3_value_double(pArg);
      if( NEVER(sqlite3IsNaN(r)) ){
        jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0);
      }else{
        int n = sqlite3_value_bytes(pArg);
        const char *z = (const char*)sqlite3_value_text(pArg);
        if( z==0 ) return 1;
        if( z[0]=='I' ){
          jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
        }else if( z[0]=='-' && z[1]=='I' ){
          jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
        }else{
          jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z);
        }
      }
      break;
    }
    case SQLITE_INTEGER: {
      int n = sqlite3_value_bytes(pArg);
      const char *z = (const char*)sqlite3_value_text(pArg);
      if( z==0 ) return 1;
      jsonBlobAppendNode(pParse, JSONB_INT, n, z);
      break;
    }
  }
  if( pParse->oom ){
    sqlite3_result_error_nomem(ctx);
    return 1;
  }else{
    return 0;
  }
  if( pParse->oom ) return 0;
  return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
}

/*
** Generate a bad path error.
**
** If ctx is not NULL then push the error message into ctx and return NULL.
** Return the text of a syntax error message on a JSON path.  Space is
** If ctx is NULL, then return the text of the error message.
** obtained from sqlite3_malloc().
*/
static char *jsonPathSyntaxError(const char *zErr){
  return sqlite3_mprintf("JSON path error near '%q'", zErr);
}

/*
static char *jsonBadPathError(
  sqlite3_context *ctx,     /* The function call containing the error */
  const char *zPath         /* The path with the problem */
){
  char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
  if( ctx==0 ) return zMsg;
  if( zMsg ){
    sqlite3_result_error(ctx, zMsg, -1);
    sqlite3_free(zMsg);
  }else{
    sqlite3_result_error_nomem(ctx);
  }
  return 0;
}

/* argv[0] is a BLOB that seems likely to be a JSONB.  Subsequent
** arguments come in parse where each pair contains a JSON path and
** content to insert or set at that patch.  Do the updates
** Do a node lookup using zPath.  Return a pointer to the node on success.
** Return NULL if not found or if there is an error.
** and return the result.
**
** The specific operation is determined by eEdit, which can be one
** On an error, write an error message into pCtx and increment the
** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET.
** pParse->nErr counter.
**
** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
** nodes are appended.
*/
static JsonNode *jsonLookup(
static void jsonInsertIntoBlob(
  JsonParse *pParse,      /* The JSON to search */
  const char *zPath,      /* The path to search */
  int *pApnd,             /* Append nodes to complete path if not NULL */
  sqlite3_context *pCtx   /* Report errors here, if not NULL */
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv,
  int eEdit                /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */
){
  int i;
  u32 rc = 0;
  const char *zErr = 0;
  JsonNode *pNode = 0;
  char *zMsg;

  if( zPath==0 ) return 0;
  if( zPath[0]!='$' ){
  const char *zPath = 0;
  int flgs;
  JsonParse *p;
  JsonParse ax;

  assert( (argc&1)==1 );
  flgs = argc==1 ? 0 : JSON_EDITABLE;
  p = jsonParseFuncArg(ctx, argv[0], flgs);
  if( p==0 ) return;
  for(i=1; i<argc-1; i+=2){
    if( sqlite3_value_type(argv[i])==SQLITE_NULL ) continue;
    zPath = (const char*)sqlite3_value_text(argv[i]);
    if( zPath==0 ){
    zErr = zPath;
    goto lookup_err;
  }
  zPath++;
  pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
  if( zErr==0 ) return pNode;

      sqlite3_result_error_nomem(ctx);
      jsonParseFree(p);
      return;
    }
    if( zPath[0]!='$' ) goto jsonInsertIntoBlob_patherror;
    if( jsonFunctionArgToBlob(ctx, argv[i+1], &ax) ){
      jsonParseReset(&ax);
      jsonParseFree(p);
      return;
    }
lookup_err:
  pParse->nErr++;
  assert( zErr!=0 && pCtx!=0 );
  zMsg = jsonPathSyntaxError(zErr);
  if( zMsg ){
    if( zPath[1]==0 ){
    sqlite3_result_error(pCtx, zMsg, -1);
    sqlite3_free(zMsg);
  }else{
    sqlite3_result_error_nomem(pCtx);
      if( eEdit==JEDIT_REPL || eEdit==JEDIT_SET ){
        jsonBlobEdit(p, 0, p->nBlob, ax.aBlob, ax.nBlob);
      }
      rc = 0;
   }else{
      p->eEdit = eEdit;
      p->nIns = ax.nBlob;
      p->aIns = ax.aBlob;
      p->delta = 0;
      rc = jsonLookupStep(p, 0, zPath+1, 0);
    }
    jsonParseReset(&ax);
    if( rc==JSON_LOOKUP_NOTFOUND ) continue;
    if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror;
  }
  jsonReturnParse(ctx, p);
  jsonParseFree(p);
  return;

jsonInsertIntoBlob_patherror:
  jsonParseFree(p);
  if( rc==JSON_LOOKUP_ERROR ){
    sqlite3_result_error(ctx, "malformed JSON", -1);
  }else{
    jsonBadPathError(ctx, zPath);
  }
  return;
}

/*
** If pArg is a blob that seems like a JSONB blob, then initialize
** p to point to that JSONB and return TRUE.  If pArg does not seem like
** a JSONB blob, then return FALSE;
**
** This routine is only called if it is already known that pArg is a
** blob.  The only open question is whether or not the blob appears
** to be a JSONB blob.
*/
static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){
  u32 n, sz = 0;
  p->aBlob = (u8*)sqlite3_value_blob(pArg);
  p->nBlob = (u32)sqlite3_value_bytes(pArg);
  if( p->nBlob==0 ){
    p->aBlob = 0;
    return 0;
  }
  if( NEVER(p->aBlob==0) ){
    return 0;
  }
  if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT
   && (n = jsonbPayloadSize(p, 0, &sz))>0
   && sz+n==p->nBlob
   && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0)
  ){
    return 1;
  }
  p->aBlob = 0;
  p->nBlob = 0;
  return 0;
}

/*
** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob,
** from the SQL function argument pArg.  Return a pointer to the new
** JsonParse object.
**
** Ownership of the new JsonParse object is passed to the caller.  The
** caller should invoke jsonParseFree() on the return value when it
** has finished using it.
**
** If any errors are detected, an appropriate error messages is set
** using sqlite3_result_error() or the equivalent and this routine
** returns NULL.  This routine also returns NULL if the pArg argument
** is an SQL NULL value, but no error message is set in that case.  This
** is so that SQL functions that are given NULL arguments will return
** a NULL value.
*/
static JsonParse *jsonParseFuncArg(
  sqlite3_context *ctx,
  sqlite3_value *pArg,
  u32 flgs
){
  int eType;                   /* Datatype of pArg */
  JsonParse *p = 0;            /* Value to be returned */
  JsonParse *pFromCache = 0;   /* Value taken from cache */
  sqlite3 *db;                 /* The database connection */
  
  assert( ctx!=0 );
  eType = sqlite3_value_type(pArg);
  if( eType==SQLITE_NULL ){
  return 0;
}


    return 0;
  }
  pFromCache = jsonCacheSearch(ctx, pArg);
  if( pFromCache ){
    pFromCache->nJPRef++;
    if( (flgs & JSON_EDITABLE)==0 ){
      return pFromCache;
    }
  }
/*
** Report the wrong number of arguments for json_insert(), json_replace()
** or json_set().
*/
static void jsonWrongNumArgs(
  sqlite3_context *pCtx,
  const char *zFuncName
){
  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
                               zFuncName);
  db = sqlite3_context_db_handle(ctx);
rebuild_from_cache:
  p = sqlite3DbMallocZero(db, sizeof(*p));
  if( p==0 ) goto json_pfa_oom;
  memset(p, 0, sizeof(*p));
  p->db = db;
  p->nJPRef = 1;
  if( pFromCache!=0 ){
    u32 nBlob = pFromCache->nBlob;
    p->aBlob = sqlite3DbMallocRaw(db, nBlob);
    if( p->aBlob==0 ) goto json_pfa_oom;
    memcpy(p->aBlob, pFromCache->aBlob, nBlob);
    p->nBlobAlloc = p->nBlob = nBlob;
    p->hasNonstd = pFromCache->hasNonstd;
    jsonParseFree(pFromCache);
  sqlite3_result_error(pCtx, zMsg, -1);
  sqlite3_free(zMsg);
}

    return p;
  }
  if( eType==SQLITE_BLOB ){
    if( jsonArgIsJsonb(pArg,p) ){
      if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){
        goto json_pfa_oom;
      }
      return p;
    }
    /* If the blob is not valid JSONB, fall through into trying to cast
    ** the blob into text which is then interpreted as JSON.  (tag-20240123-a)
    **
    ** This goes against all historical documentation about how the SQLite
    ** JSON functions were suppose to work.  From the beginning, blob was
    ** reserved for expansion and a blob value should have raised an error.
    ** But it did not, due to a bug.  And many applications came to depend
    ** upon this buggy behavior, espeically when using the CLI and reading
    ** JSON text using readfile(), which returns a blob.  For this reason
    ** we will continue to support the bug moving forward.
    ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
/*
** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
*/
static void jsonRemoveAllNulls(JsonNode *pNode){
  int i, n;
  assert( pNode->eType==JSON_OBJECT );
  n = pNode->n;
  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
    switch( pNode[i].eType ){
      case JSON_NULL:
        pNode[i].jnFlags |= JNODE_REMOVE;
        break;
      case JSON_OBJECT:
        jsonRemoveAllNulls(&pNode[i]);
        break;
    }
  }
}

    */
  }
  p->zJson = (char*)sqlite3_value_text(pArg);
  p->nJson = sqlite3_value_bytes(pArg);
  if( db->mallocFailed ) goto json_pfa_oom;
  if( p->nJson==0 ) goto json_pfa_malformed;
  assert( p->zJson!=0 );
  if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
    if( flgs & JSON_KEEPERROR ){
      p->nErr = 1;
      return p;
    }else{
      jsonParseFree(p);
      return 0;
    }
  }else{
    int isRCStr = sqlite3ValueIsOfClass(pArg, sqlite3RCStrUnref);
    int rc;
    if( !isRCStr ){
      char *zNew = sqlite3RCStrNew( p->nJson );
      if( zNew==0 ) goto json_pfa_oom;
      memcpy(zNew, p->zJson, p->nJson);
      p->zJson = zNew;
      p->zJson[p->nJson] = 0;
    }else{
      sqlite3RCStrRef(p->zJson);
    }
    p->bJsonIsRCStr = 1;
    rc = jsonCacheInsert(ctx, p);
    if( rc==SQLITE_NOMEM ) goto json_pfa_oom;
    if( flgs & JSON_EDITABLE ){
      pFromCache = p;
      p = 0;
      goto rebuild_from_cache;
    }
  }
  return p;

json_pfa_malformed:
  if( flgs & JSON_KEEPERROR ){
    p->nErr = 1;
    return p;
  }else{
    jsonParseFree(p);
    sqlite3_result_error(ctx, "malformed JSON", -1);
    return 0;
  }

json_pfa_oom:
  jsonParseFree(pFromCache);
  jsonParseFree(p);
  sqlite3_result_error_nomem(ctx);
  return 0;
}

/*
** Make the return value of a JSON function either the raw JSONB blob
** or make it JSON text, depending on whether the JSON_BLOB flag is
** set on the function.
*/
static void jsonReturnParse(
  sqlite3_context *ctx,
  JsonParse *p
){
  int flgs;
  if( p->oom ){
    sqlite3_result_error_nomem(ctx);
    return;
  }
  flgs = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
  if( flgs & JSON_BLOB ){
    if( p->nBlobAlloc>0 && !p->bReadOnly ){
      sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC);
      p->nBlobAlloc = 0;
    }else{
      sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT);
    }
  }else{
    JsonString s;
    jsonStringInit(&s, ctx);
    p->delta = 0;
    jsonTranslateBlobToText(p, 0, &s);
    jsonReturnString(&s, p, ctx);
    sqlite3_result_subtype(ctx, JSON_SUBTYPE);
  }
}

/****************************************************************************
** SQL functions used for testing and debugging
****************************************************************************/

#if SQLITE_DEBUG
/*
** Decode JSONB bytes in aBlob[] starting at iStart through but not 
** Print N node entries.
** including iEnd.  Indent the
** content by nIndent spaces.
*/
static void jsonDebugPrintNodeEntries(
static void jsonDebugPrintBlob(
  JsonNode *aNode,  /* First node entry to print */
  int N             /* Number of node entries to print */
  JsonParse *pParse, /* JSON content */
  u32 iStart,        /* Start rendering here */
  u32 iEnd,          /* Do not render this byte or any byte after this one */
  int nIndent,       /* Indent by this many spaces */
  sqlite3_str *pOut  /* Generate output into this sqlite3_str object */
){
  while( iStart<iEnd ){
    u32 i, n, nn, sz = 0;
  int i;
  for(i=0; i<N; i++){
    const char *zType;
    if( aNode[i].jnFlags & JNODE_LABEL ){
      zType = "label";
    }else{
      zType = jsonType[aNode[i].eType];
    }
    int showContent = 1;
    u8 x = pParse->aBlob[iStart] & 0x0f;
    u32 savedNBlob = pParse->nBlob;
    sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, "");
    if( pParse->nBlobAlloc>pParse->nBlob ){
      pParse->nBlob = pParse->nBlobAlloc;
    }
    nn = n = jsonbPayloadSize(pParse, iStart, &sz);
    if( nn==0 ) nn = 1;
    if( sz>0 && x<JSONB_ARRAY ){
      nn += sz;
    }
    for(i=0; i<nn; i++){
      sqlite3_str_appendf(pOut, " %02x", pParse->aBlob[iStart+i]);
    }
    if( n==0 ){
      sqlite3_str_appendf(pOut, "   ERROR invalid node size\n");
      iStart = n==0 ? iStart+1 : iEnd;
      continue;
    }
    pParse->nBlob = savedNBlob;
    if( iStart+n+sz>iEnd ){
      iEnd = iStart+n+sz;
      if( iEnd>pParse->nBlob ){
        if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){
          iEnd = pParse->nBlobAlloc;
        }else{
          iEnd = pParse->nBlob;
        }
    printf("node %4u: %-7s n=%-5d", i, zType, aNode[i].n);
    if( (aNode[i].jnFlags & ~JNODE_LABEL)!=0 ){
      u8 f = aNode[i].jnFlags;
      if( f & JNODE_RAW )     printf(" RAW");
      if( f & JNODE_ESCAPE )  printf(" ESCAPE");
      if( f & JNODE_REMOVE )  printf(" REMOVE");
      if( f & JNODE_REPLACE ) printf(" REPLACE");
      if( f & JNODE_APPEND )  printf(" APPEND");
      if( f & JNODE_JSON5 )   printf(" JSON5");
    }
    switch( aNode[i].eU ){
      case 1:  printf(" zJContent=[%.*s]\n",
                      aNode[i].n, aNode[i].u.zJContent);           break;
      case 2:  printf(" iAppend=%u\n", aNode[i].u.iAppend);        break;
      case 3:  printf(" iKey=%u\n", aNode[i].u.iKey);              break;
      }
    }
    sqlite3_str_appendall(pOut,"  <-- ");
    switch( x ){
      case JSONB_NULL:     sqlite3_str_appendall(pOut,"null"); break;
      case JSONB_TRUE:     sqlite3_str_appendall(pOut,"true"); break;
      case JSONB_FALSE:    sqlite3_str_appendall(pOut,"false"); break;
      case JSONB_INT:      sqlite3_str_appendall(pOut,"int"); break;
      case JSONB_INT5:     sqlite3_str_appendall(pOut,"int5"); break;
      case JSONB_FLOAT:    sqlite3_str_appendall(pOut,"float"); break;
      case JSONB_FLOAT5:   sqlite3_str_appendall(pOut,"float5"); break;
      case JSONB_TEXT:     sqlite3_str_appendall(pOut,"text"); break;
      case JSONB_TEXTJ:    sqlite3_str_appendall(pOut,"textj"); break;
      case JSONB_TEXT5:    sqlite3_str_appendall(pOut,"text5"); break;
      case JSONB_TEXTRAW:  sqlite3_str_appendall(pOut,"textraw"); break;
      case JSONB_ARRAY: {
        sqlite3_str_appendf(pOut,"array, %u bytes\n", sz);
        jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
        showContent = 0;
        break;
      }
      case JSONB_OBJECT: {
        sqlite3_str_appendf(pOut, "object, %u bytes\n", sz);
        jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
        showContent = 0;
        break;
      case 4:  printf(" iPrev=%u\n", aNode[i].u.iPrev);            break;
      default: printf("\n");
    }
  }
      }
      default: {
        sqlite3_str_appendall(pOut, "ERROR: unknown node type\n");
        showContent = 0;
        break;
      }
    }
    if( showContent ){
      if( sz==0 && x<=JSONB_FALSE ){
        sqlite3_str_append(pOut, "\n", 1);
      }else{
        u32 j;
        sqlite3_str_appendall(pOut, ": \"");
        for(j=iStart+n; j<iStart+n+sz; j++){
          u8 c = pParse->aBlob[j];
          if( c<0x20 || c>=0x7f ) c = '.';
          sqlite3_str_append(pOut, (char*)&c, 1);
        }
        sqlite3_str_append(pOut, "\"\n", 2);
      }
    }
    iStart += n + sz;
  }
}
static void jsonShowParse(JsonParse *pParse){
  sqlite3_str out;
  char zBuf[1000];
  if( pParse==0 ){
    printf("NULL pointer\n");
    return;
  }else{
    printf("nBlobAlloc = %u\n", pParse->nBlobAlloc);
    printf("nBlob = %u\n", pParse->nBlob);
    printf("delta = %d\n", pParse->delta);
    if( pParse->nBlob==0 ) return;
    printf("content (bytes 0..%u):\n", pParse->nBlob-1);
  }
  sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000);
  jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out);
  printf("%s", sqlite3_str_value(&out));
  sqlite3_str_reset(&out);
}
#endif /* SQLITE_DEBUG */


#if 0  /* 1 for debugging.  0 normally.  Requires -DSQLITE_DEBUG too */
static void jsonDebugPrintParse(JsonParse *p){
  jsonDebugPrintNodeEntries(p->aNode, p->nNode);
}
static void jsonDebugPrintNode(JsonNode *pNode){
  jsonDebugPrintNodeEntries(pNode, jsonNodeSize(pNode));
}
#else
   /* The usual case */
# define jsonDebugPrintNode(X)
# define jsonDebugPrintParse(X)
#endif

#ifdef SQLITE_DEBUG
/*
** SQL function:   json_parse(JSON)
**
** Parse JSON using jsonParseCached().  Then print a dump of that
** parse on standard output.  Return the mimified JSON result, just
** Parse JSON using jsonParseFuncArg().  Return text that is a
** human-readable dump of the binary JSONB for the input parameter.
** like the json() function.
*/
static void jsonParseFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *p;        /* The parse */
  sqlite3_str out;

  assert( argc==1 );
  p = jsonParseCached(ctx, argv[0], ctx, 0);
  assert( argc>=1 );
  sqlite3StrAccumInit(&out, 0, 0, 0, 1000000);
  p = jsonParseFuncArg(ctx, argv[0], 0);
  if( p==0 ) return;
  printf("nNode     = %u\n", p->nNode);
  printf("nAlloc    = %u\n", p->nAlloc);
  printf("nJson     = %d\n", p->nJson);
  if( argc==1 ){
  printf("nAlt      = %d\n", p->nAlt);
  printf("nErr      = %u\n", p->nErr);
  printf("oom       = %u\n", p->oom);
  printf("hasNonstd = %u\n", p->hasNonstd);
  printf("useMod    = %u\n", p->useMod);
  printf("hasMod    = %u\n", p->hasMod);
  printf("nJPRef    = %u\n", p->nJPRef);
  printf("iSubst    = %u\n", p->iSubst);
  printf("iHold     = %u\n", p->iHold);
  jsonDebugPrintNodeEntries(p->aNode, p->nNode);
    jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out);
  jsonReturnJson(p, p->aNode, ctx, 1, 0);
}

    sqlite3_result_text64(ctx,out.zText,out.nChar,SQLITE_TRANSIENT,SQLITE_UTF8);
  }else{
    jsonShowParse(p);
  }
/*
** The json_test1(JSON) function return true (1) if the input is JSON
** text generated by another json function.  It returns (0) if the input
** is not known to be JSON.
*/
static void jsonTest1Func(
  sqlite3_context *ctx,
  jsonParseFree(p);
  sqlite3_str_reset(&out);
  int argc,
  sqlite3_value **argv
){
  UNUSED_PARAMETER(argc);
  sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
}
#endif /* SQLITE_DEBUG */

/****************************************************************************
** Scalar SQL function implementations
****************************************************************************/

/*
** Implementation of the json_QUOTE(VALUE) function.  Return a JSON value
** Implementation of the json_quote(VALUE) function.  Return a JSON value
** corresponding to the SQL value input.  Mostly this means putting
** double-quotes around strings and returning the unquoted string "null"
** when given a NULL input.
*/
static void jsonQuoteFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonString jx;
  UNUSED_PARAMETER(argc);

  jsonInit(&jx, ctx);
  jsonAppendValue(&jx, argv[0]);
  jsonResult(&jx);
  jsonStringInit(&jx, ctx);
  jsonAppendSqlValue(&jx, argv[0]);
  jsonReturnString(&jx, 0, 0);
  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}

/*
** Implementation of the json_array(VALUE,...) function.  Return a JSON
** array that contains all values given in arguments.  Or if any argument
** is a BLOB, throw an error.
*/
static void jsonArrayFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  int i;
  JsonString jx;

  jsonInit(&jx, ctx);
  jsonStringInit(&jx, ctx);
  jsonAppendChar(&jx, '[');
  for(i=0; i<argc; i++){
    jsonAppendSeparator(&jx);
    jsonAppendValue(&jx, argv[i]);
    jsonAppendSqlValue(&jx, argv[i]);
  }
  jsonAppendChar(&jx, ']');
  jsonResult(&jx);
  jsonReturnString(&jx, 0, 0);
  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}


/*
** json_array_length(JSON)
** json_array_length(JSON, PATH)
**
** Return the number of elements in the top-level JSON array.
** Return 0 if the input is not a well-formed JSON array.
*/
static void jsonArrayLengthFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *p;          /* The parse */
  sqlite3_int64 n = 0;
  sqlite3_int64 cnt = 0;
  u32 i;
  JsonNode *pNode;
  u8 eErr = 0;

  p = jsonParseCached(ctx, argv[0], ctx, 0);
  p = jsonParseFuncArg(ctx, argv[0], 0);
  if( p==0 ) return;
  assert( p->nNode );
  if( argc==2 ){
    const char *zPath = (const char*)sqlite3_value_text(argv[1]);
    if( zPath==0 ){
      jsonParseFree(p);
      return;
    }
    pNode = jsonLookup(p, zPath, 0, ctx);
    i = jsonLookupStep(p, 0, zPath[0]=='$' ? zPath+1 : "@", 0);
    if( JSON_LOOKUP_ISERROR(i) ){
      if( i==JSON_LOOKUP_NOTFOUND ){
        /* no-op */
      }else if( i==JSON_LOOKUP_PATHERROR ){
        jsonBadPathError(ctx, zPath);
      }else{
        sqlite3_result_error(ctx, "malformed JSON", -1);
      }
      eErr = 1;
      i = 0;
    }
  }else{
    pNode = p->aNode;
    i = 0;
  }
  if( pNode==0 ){
    return;
  if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){
    cnt = jsonbArrayCount(p, i);
  }
  if( pNode->eType==JSON_ARRAY ){
  if( !eErr ) sqlite3_result_int64(ctx, cnt);
    while( 1 /*exit-by-break*/ ){
      i = 1;
      while( i<=pNode->n ){
        if( (pNode[i].jnFlags & JNODE_REMOVE)==0 ) n++;
        i += jsonNodeSize(&pNode[i]);
      }
  jsonParseFree(p);
}
      if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
      if( p->useMod==0 ) break;
      assert( pNode->eU==2 );
      pNode = &p->aNode[pNode->u.iAppend];
    }
  }

/* True if the string is all digits */
static int jsonAllDigits(const char *z, int n){
  int i;
  for(i=0; i<n && sqlite3Isdigit(z[i]); i++){}
  return i==n;
}
  sqlite3_result_int64(ctx, n);
}


/* True if the string is all alphanumerics and underscores */
static int jsonAllAlphanum(const char *z, int n){
  int i;
  for(i=0; i<n && (sqlite3Isalnum(z[i]) || z[i]=='_'); i++){}
  return i==n;
}
/*
** Bit values for the flags passed into jsonExtractFunc() or
** jsonSetFunc() via the user-data value.
*/
#define JSON_JSON      0x01        /* Result is always JSON */
#define JSON_SQL       0x02        /* Result is always SQL */
#define JSON_ABPATH    0x03        /* Allow abbreviated JSON path specs */
#define JSON_ISSET     0x04        /* json_set(), not json_insert() */

/*
** json_extract(JSON, PATH, ...)
** "->"(JSON,PATH)
** "->>"(JSON,PATH)
**
** Return the element described by PATH.  Return NULL if that PATH element
2537
2538
2539
2540
2541
2542
2543
2544

2545
2546
2547
2548



2549
2550
2551

2552


2553




2554
2555
2556
2557








2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
































2583


2584




2585
2586
2587
2588
2589
2590









2591
2592
2593






2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612















2613
2614


2615
2616
2617












2618

2619












































2620
2621
2622
2623
2624





2625



2626
2627
2628
2629











2630
2631
2632











2633
2634
2635
2636
2637







2638
2639



2640
2641
2642
2643
2644
2645
2646

2647
2648
2649



2650
2651
2652
2653
2654


2655
2656

2657
2658
2659


2660
2661
2662
2663
2664
2665
2666

























2667
2668
2669
2670
2671
2672
2673
2674
2675

















2676
2677
2678



































2679
2680
2681
2682
2683
2684
2685
2686















2687

2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701



2702
2703

2704
2705


2706
2707
2708
2709


2710
2711
2712

2713
2714
2715
2716




2717
2718
2719
2720






2721
2722
2723
2724
2725
2726
2727
3830
3831
3832
3833
3834
3835
3836

3837




3838
3839
3840
3841
3842

3843
3844
3845
3846

3847
3848
3849
3850
3851



3852
3853
3854
3855
3856
3857
3858
3859

























3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894

3895
3896
3897
3898
3899





3900
3901
3902
3903
3904
3905
3906
3907
3908



3909
3910
3911
3912
3913
3914



















3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933



3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947

3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992




3993
3994
3995
3996
3997
3998
3999
4000
4001




4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012



4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023





4024
4025
4026
4027
4028
4029
4030


4031
4032
4033







4034



4035
4036
4037





4038
4039


4040



4041
4042







4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067









4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084



4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119








4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147



4148
4149
4150
4151
4152
4153


4154
4155




4156
4157



4158




4159
4160
4161
4162




4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175







-
+
-
-
-
-
+
+
+


-
+

+
+
-
+
+
+
+

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

+
+
-
+
+
+
+

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


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

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

-
-
-
-
+
+
+
+
+

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

+











-
-
-
+
+
+


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







** compatibility with PG.
*/
static void jsonExtractFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *p;          /* The parse */
  JsonParse *p = 0;      /* The parse */
  JsonNode *pNode;
  const char *zPath;
  int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
  JsonString jx;
  int flags;             /* Flags associated with the function */
  int i;                 /* Loop counter */
  JsonString jx;         /* String for array result */

  if( argc<2 ) return;
  p = jsonParseCached(ctx, argv[0], ctx, 0);
  p = jsonParseFuncArg(ctx, argv[0], 0);
  if( p==0 ) return;
  flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
  jsonStringInit(&jx, ctx);
  if( argc==2 ){
  if( argc>2 ){
    jsonAppendChar(&jx, '[');
  }
  for(i=1; i<argc; i++){
    /* With a single PATH argument */
    zPath = (const char*)sqlite3_value_text(argv[1]);
    if( zPath==0 ) return;
    if( flags & JSON_ABPATH ){
    const char *zPath = (const char*)sqlite3_value_text(argv[i]);
    int nPath;
    u32 j;
    if( zPath==0 ) goto json_extract_error;
    nPath = sqlite3Strlen30(zPath);
    if( zPath[0]=='$' ){
      j = jsonLookupStep(p, 0, zPath+1, 0);
    }else if( (flags & JSON_ABPATH) ){
      if( zPath[0]!='$' || (zPath[1]!='.' && zPath[1]!='[' && zPath[1]!=0) ){
        /* The -> and ->> operators accept abbreviated PATH arguments.  This
        ** is mostly for compatibility with PostgreSQL, but also for
        ** convenience.
        **
        **     NUMBER   ==>  $[NUMBER]     // PG compatible
        **     LABEL    ==>  $.LABEL       // PG compatible
        **     [NUMBER] ==>  $[NUMBER]     // Not PG.  Purely for convenience
        */
        jsonInit(&jx, ctx);
        if( sqlite3Isdigit(zPath[0]) ){
          jsonAppendRawNZ(&jx, "$[", 2);
          jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
          jsonAppendRawNZ(&jx, "]", 2);
        }else{
          jsonAppendRawNZ(&jx, "$.", 1 + (zPath[0]!='['));
          jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
          jsonAppendChar(&jx, 0);
        }
        pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
        jsonReset(&jx);
      }else{
        pNode = jsonLookup(p, zPath, 0, ctx);
      }
      if( pNode ){
      /* The -> and ->> operators accept abbreviated PATH arguments.  This
      ** is mostly for compatibility with PostgreSQL, but also for
      ** convenience.
      **
      **     NUMBER   ==>  $[NUMBER]     // PG compatible
      **     LABEL    ==>  $.LABEL       // PG compatible
      **     [NUMBER] ==>  $[NUMBER]     // Not PG.  Purely for convenience
      */
      jsonStringInit(&jx, ctx);
      if( jsonAllDigits(zPath, nPath) ){
        jsonAppendRawNZ(&jx, "[", 1);
        jsonAppendRaw(&jx, zPath, nPath);
        jsonAppendRawNZ(&jx, "]", 2);
      }else if( jsonAllAlphanum(zPath, nPath) ){
        jsonAppendRawNZ(&jx, ".", 1);
        jsonAppendRaw(&jx, zPath, nPath);
      }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){
        jsonAppendRaw(&jx, zPath, nPath);
      }else{
        jsonAppendRawNZ(&jx, ".\"", 2);
        jsonAppendRaw(&jx, zPath, nPath);
        jsonAppendRawNZ(&jx, "\"", 1);
      }
      jsonStringTerminate(&jx);
      j = jsonLookupStep(p, 0, jx.zBuf, 0);
      jsonStringReset(&jx);
    }else{
      jsonBadPathError(ctx, zPath);
      goto json_extract_error;
    }
    if( j<p->nBlob ){
      if( argc==2 ){
        if( flags & JSON_JSON ){
          jsonStringInit(&jx, ctx);
          jsonTranslateBlobToText(p, j, &jx);
          jsonReturnJson(p, pNode, ctx, 0, 0);
          jsonReturnString(&jx, 0, 0);
          jsonStringReset(&jx);
          assert( (flags & JSON_BLOB)==0 );
          sqlite3_result_subtype(ctx, JSON_SUBTYPE);
        }else{
          jsonReturn(p, pNode, ctx, 1);
        }
      }
    }else{
      pNode = jsonLookup(p, zPath, 0, ctx);
          jsonReturnFromBlob(p, j, ctx, 0);
          if( (flags & (JSON_SQL|JSON_BLOB))==0
           && (p->aBlob[j]&0x0f)>=JSONB_ARRAY
          ){
            sqlite3_result_subtype(ctx, JSON_SUBTYPE);
          }
        }
      }else{
        jsonAppendSeparator(&jx);
      if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx, 0);
    }
  }else{
        jsonTranslateBlobToText(p, j, &jx);
      }
    }else if( j==JSON_LOOKUP_NOTFOUND ){
      if( argc==2 ){
        goto json_extract_error;  /* Return NULL if not found */
      }else{
    /* Two or more PATH arguments results in a JSON array with each
    ** element of the array being the value selected by one of the PATHs */
    int i;
    jsonInit(&jx, ctx);
    jsonAppendChar(&jx, '[');
    for(i=1; i<argc; i++){
      zPath = (const char*)sqlite3_value_text(argv[i]);
      pNode = jsonLookup(p, zPath, 0, ctx);
      if( p->nErr ) break;
      jsonAppendSeparator(&jx);
      if( pNode ){
        jsonRenderNode(p, pNode, &jx);
      }else{
        jsonAppendRawNZ(&jx, "null", 4);
      }
    }
    if( i==argc ){
      jsonAppendChar(&jx, ']');
      jsonResult(&jx);
        jsonAppendSeparator(&jx);
        jsonAppendRawNZ(&jx, "null", 4);
      }
    }else if( j==JSON_LOOKUP_ERROR ){
      sqlite3_result_error(ctx, "malformed JSON", -1);
      goto json_extract_error;
    }else{
      jsonBadPathError(ctx, zPath);
      goto json_extract_error;
    }
  }
  if( argc>2 ){
    jsonAppendChar(&jx, ']');
    jsonReturnString(&jx, 0, 0);
    if( (flags & JSON_BLOB)==0 ){
      sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    }
  }
json_extract_error:
    jsonReset(&jx);
  }
}
  jsonStringReset(&jx);
  jsonParseFree(p);
  return;
}

/*
** Return codes for jsonMergePatch()
*/
#define JSON_MERGE_OK          0     /* Success */
#define JSON_MERGE_BADTARGET   1     /* Malformed TARGET blob */
#define JSON_MERGE_BADPATCH    2     /* Malformed PATCH blob */
#define JSON_MERGE_OOM         3     /* Out-of-memory condition */

/*
/* This is the RFC 7396 MergePatch algorithm.
** RFC-7396 MergePatch for two JSONB blobs.
**
** pTarget is the target. pPatch is the patch.  The target is updated
** in place.  The patch is read-only.
**
** The original RFC-7396 algorithm is this:
**
**   define MergePatch(Target, Patch):
**     if Patch is an Object:
**       if Target is not an Object:
**         Target = {} # Ignore the contents and set it to an empty Object
**     for each Name/Value pair in Patch:
**         if Value is null:
**           if Name exists in Target:
**             remove the Name/Value pair from Target
**         else:
**           Target[Name] = MergePatch(Target[Name], Value)
**       return Target
**     else:
**       return Patch
**
** Here is an equivalent algorithm restructured to show the actual
** implementation:
**
** 01   define MergePatch(Target, Patch):
** 02      if Patch is not an Object:
** 03         return Patch
** 04      else: // if Patch is an Object
** 05         if Target is not an Object:
** 06            Target = {}
** 07      for each Name/Value pair in Patch:
** 08         if Name exists in Target:
** 09            if Value is null:
** 10               remove the Name/Value pair from Target
** 11            else
** 12               Target[name] = MergePatch(Target[Name], Value)
** 13         else if Value is not NULL:
** 14            if Value is not an Object:
** 15               Target[name] = Value
** 16            else:
** 17               Target[name] = MergePatch('{}',value)
** 18      return Target
**  |
**  ^---- Line numbers referenced in comments in the implementation
*/
static JsonNode *jsonMergePatch(
  JsonParse *pParse,   /* The JSON parser that contains the TARGET */
  u32 iTarget,         /* Node of the TARGET in pParse */
  JsonNode *pPatch     /* The PATCH */
static int jsonMergePatch(
  JsonParse *pTarget,      /* The JSON parser that contains the TARGET */
  u32 iTarget,             /* Index of TARGET in pTarget->aBlob[] */
  const JsonParse *pPatch, /* The PATCH */
  u32 iPatch               /* Index of PATCH in pPatch->aBlob[] */
){
  u8 x;             /* Type of a single node */
  u32 n, sz=0;      /* Return values from jsonbPayloadSize() */
  u32 iTCursor;     /* Cursor position while scanning the target object */
  u32 i, j;
  u32 iRoot;
  JsonNode *pTarget;
  if( pPatch->eType!=JSON_OBJECT ){
  u32 iTStart;      /* First label in the target object */
  u32 iTEndBE;      /* Original first byte past end of target, before edit */
  u32 iTEnd;        /* Current first byte past end of target */
  u8 eTLabel;       /* Node type of the target label */
  u32 iTLabel = 0;  /* Index of the label */
  u32 nTLabel = 0;  /* Header size in bytes for the target label */
  u32 szTLabel = 0; /* Size of the target label payload */
  u32 iTValue = 0;  /* Index of the target value */
  u32 nTValue = 0;  /* Header size of the target value */
  u32 szTValue = 0; /* Payload size for the target value */

    return pPatch;
  }
  assert( iTarget<pParse->nNode );
  u32 iPCursor;     /* Cursor position while scanning the patch */
  u32 iPEnd;        /* First byte past the end of the patch */
  u8 ePLabel;       /* Node type of the patch label */
  u32 iPLabel;      /* Start of patch label */
  u32 nPLabel;      /* Size of header on the patch label */
  u32 szPLabel;     /* Payload size of the patch label */
  u32 iPValue;      /* Start of patch value */
  u32 nPValue;      /* Header size for the patch value */
  u32 szPValue;     /* Payload size of the patch value */

  assert( iTarget>=0 && iTarget<pTarget->nBlob );
  pTarget = &pParse->aNode[iTarget];
  assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
  if( pTarget->eType!=JSON_OBJECT ){
    jsonRemoveAllNulls(pPatch);
    return pPatch;
  assert( iPatch>=0 && iPatch<pPatch->nBlob );
  x = pPatch->aBlob[iPatch] & 0x0f;
  if( x!=JSONB_OBJECT ){  /* Algorithm line 02 */
    u32 szPatch;        /* Total size of the patch, header+payload */
    u32 szTarget;       /* Total size of the target, header+payload */
    n = jsonbPayloadSize(pPatch, iPatch, &sz);
    szPatch = n+sz;
  }
  iRoot = iTarget;
    sz = 0;
    n = jsonbPayloadSize(pTarget, iTarget, &sz);
    szTarget = n+sz;
  for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
    u32 nKey;
    const char *zKey;
    assert( pPatch[i].eType==JSON_STRING );
    assert( pPatch[i].jnFlags & JNODE_LABEL );
    assert( pPatch[i].eU==1 );
    nKey = pPatch[i].n;
    jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch);
    zKey = pPatch[i].u.zJContent;
    for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
      assert( pTarget[j].eType==JSON_STRING );
    return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK;  /* Line 03 */
  }
  x = pTarget->aBlob[iTarget] & 0x0f;
      assert( pTarget[j].jnFlags & JNODE_LABEL );
      if( jsonSameLabel(&pPatch[i], &pTarget[j]) ){
        if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ) break;
        if( pPatch[i+1].eType==JSON_NULL ){
          pTarget[j+1].jnFlags |= JNODE_REMOVE;
  if( x!=JSONB_OBJECT ){  /* Algorithm line 05 */
    n = jsonbPayloadSize(pTarget, iTarget, &sz);
        }else{
          JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
    jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0);
          if( pNew==0 ) return 0;
          if( pNew!=&pParse->aNode[iTarget+j+1] ){
            jsonParseAddSubstNode(pParse, iTarget+j+1);
    x = pTarget->aBlob[iTarget];
    pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT;
            jsonParseAddNodeArray(pParse, pNew, jsonNodeSize(pNew));
          }
          pTarget = &pParse->aNode[iTarget];
        }
        break;
      }
    }
  }
  n = jsonbPayloadSize(pPatch, iPatch, &sz);
  if( NEVER(n==0) ) return JSON_MERGE_BADPATCH;
  iPCursor = iPatch+n;
  iPEnd = iPCursor+sz;
  n = jsonbPayloadSize(pTarget, iTarget, &sz);
  if( NEVER(n==0) ) return JSON_MERGE_BADTARGET;
  iTStart = iTarget+n;
  iTEndBE = iTStart+sz;

  while( iPCursor<iPEnd ){  /* Algorithm line 07 */
    iPLabel = iPCursor;
    ePLabel = pPatch->aBlob[iPCursor] & 0x0f;
    if( ePLabel<JSONB_TEXT || ePLabel>JSONB_TEXTRAW ){
      return JSON_MERGE_BADPATCH;
    }
    nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel);
    if( nPLabel==0 ) return JSON_MERGE_BADPATCH;
    iPValue = iPCursor + nPLabel + szPLabel;
    if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH;
    nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue);
    if( nPValue==0 ) return JSON_MERGE_BADPATCH;
    iPCursor = iPValue + nPValue + szPValue;
    if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH;

    if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
      int iStart;
      JsonNode *pApnd;
      u32 nApnd;
      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
      jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
      pApnd = &pPatch[i+1];
      if( pApnd->eType==JSON_OBJECT ) jsonRemoveAllNulls(pApnd);
      nApnd = jsonNodeSize(pApnd);
    iTCursor = iTStart;
    iTEnd = iTEndBE + pTarget->delta;
    while( iTCursor<iTEnd ){
      int isEqual;   /* true if the patch and target labels match */
      iTLabel = iTCursor;
      eTLabel = pTarget->aBlob[iTCursor] & 0x0f;
      if( eTLabel<JSONB_TEXT || eTLabel>JSONB_TEXTRAW ){
        return JSON_MERGE_BADTARGET;
      }
      nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel);
      if( nTLabel==0 ) return JSON_MERGE_BADTARGET;
      iTValue = iTLabel + nTLabel + szTLabel;
      if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET;
      nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue);
      if( nTValue==0 ) return JSON_MERGE_BADTARGET;
      if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET;
      isEqual = jsonLabelCompare(
      jsonParseAddNodeArray(pParse, pApnd, jsonNodeSize(pApnd));
      if( pParse->oom ) return 0;
      pParse->aNode[iStart].n = 1+nApnd;
                   (const char*)&pPatch->aBlob[iPLabel+nPLabel],
                   szPLabel,
                   (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW),
                   (const char*)&pTarget->aBlob[iTLabel+nTLabel],
                   szTLabel,
                   (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW));
      if( isEqual ) break;
      iTCursor = iTValue + nTValue + szTValue;
    }
    x = pPatch->aBlob[iPValue] & 0x0f;
    if( iTCursor<iTEnd ){
      /* A match was found.  Algorithm line 08 */
      if( x==0 ){
        /* Patch value is NULL.  Algorithm line 09 */
        jsonBlobEdit(pTarget, iTLabel, nTLabel+szTLabel+nTValue+szTValue, 0,0);
        /*  vvvvvv----- No OOM on a delete-only edit */
        if( NEVER(pTarget->oom) ) return JSON_MERGE_OOM;
      }else{
        /* Algorithm line 12 */
        int rc, savedDelta = pTarget->delta;
        pTarget->delta = 0;
        rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
        if( rc ) return rc;
        pTarget->delta += savedDelta;
      }        
    }else if( x>0 ){  /* Algorithm line 13 */
      /* No match and patch value is not NULL */
      u32 szNew = szPLabel+nPLabel;
      if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){  /* Line 14 */
        jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew);
        if( pTarget->oom ) return JSON_MERGE_OOM;
        memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
        memcpy(&pTarget->aBlob[iTEnd+szNew], 
               &pPatch->aBlob[iPValue], szPValue+nPValue);
      }else{
      pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
      pParse->aNode[iRoot].u.iAppend = iStart;
      VVA( pParse->aNode[iRoot].eU = 2 );
      iRoot = iStart;
      pTarget = &pParse->aNode[iTarget];
    }
  }
  return pTarget;
        int rc, savedDelta;
        jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1);
        if( pTarget->oom ) return JSON_MERGE_OOM;
        memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
        pTarget->aBlob[iTEnd+szNew] = 0x00;
        savedDelta = pTarget->delta;
        pTarget->delta = 0;
        rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
        if( rc ) return rc;
        pTarget->delta += savedDelta;
      }
    }
  }
  if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget);
  return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK;
}


/*
** Implementation of the json_mergepatch(JSON1,JSON2) function.  Return a JSON
** object that is the result of running the RFC 7396 MergePatch() algorithm
** on the two arguments.
*/
static void jsonPatchFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *pX;     /* The JSON that is being patched */
  JsonParse *pY;     /* The patch */
  JsonNode *pResult;   /* The result of the merge */
  JsonParse *pTarget;    /* The TARGET */
  JsonParse *pPatch;     /* The PATCH */
  int rc;                /* Result code */

  UNUSED_PARAMETER(argc);
  assert( argc==2 );
  pX = jsonParseCached(ctx, argv[0], ctx, 1);
  if( pX==0 ) return;
  pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE);
  if( pTarget==0 ) return;
  assert( pX->hasMod==0 );
  pX->hasMod = 1;
  pY = jsonParseCached(ctx, argv[1], ctx, 1);
  if( pY==0 ) return;
  pPatch = jsonParseFuncArg(ctx, argv[1], 0);
  if( pPatch ){
  pX->useMod = 1;
  pY->useMod = 1;
  pResult = jsonMergePatch(pX, 0, pY->aNode);
    rc = jsonMergePatch(pTarget, 0, pPatch, 0);
  assert( pResult!=0 || pX->oom );
  if( pResult && pX->oom==0 ){
    jsonDebugPrintParse(pX);
    jsonDebugPrintNode(pResult);
    if( rc==JSON_MERGE_OK ){
      jsonReturnParse(ctx, pTarget);
    }else if( rc==JSON_MERGE_OOM ){
      sqlite3_result_error_nomem(ctx);
    jsonReturnJson(pX, pResult, ctx, 0, 0);
  }else{
    sqlite3_result_error_nomem(ctx);
  }
    }else{
      sqlite3_result_error(ctx, "malformed JSON", -1);
    }
    jsonParseFree(pPatch);
  }
  jsonParseFree(pTarget);
}


/*
** Implementation of the json_object(NAME,VALUE,...) function.  Return a JSON
** object that contains all name/value given in arguments.  Or if any name
** is not a string or if any value is a BLOB, throw an error.
2737
2738
2739
2740
2741
2742
2743
2744

2745
2746
2747
2748
2749

2750
2751
2752
2753
2754

2755
2756
2757

2758
2759
2760

2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776

2777
2778
2779



2780
2781
2782
2783
2784



2785
2786

2787
2788

2789
2790
2791
2792
2793
2794
2795
2796
2797
2798






2799
2800
2801


2802
2803
2804
2805
2806
2807
2808

2809
2810
2811
2812


2813
2814
2815
2816
2817
2818

2819
2820
2821
2822
2823
2824


2825
2826
2827
2828
2829

2830
2831
2832
2833
2834
2835
2836
2837
2838
2839

2840
2841
2842
2843

2844
2845

2846
2847
2848
2849
2850
2851
2852


2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864


2865
2866
2867
2868

2869
2870
2871
2872
2873



2874
2875
2876
2877
2878

2879
2880
2881


2882
2883
2884

2885
2886
2887

2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913

2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949

2950
2951
2952
2953
2954


2955
2956
2957
2958
2959
2960
2961

2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998


2999
3000

3001
3002
3003





3004
3005
3006













3007




3008
3009





























3010



3011
3012
3013
3014

3015











3016
3017









































3018
3019
3020
3021
3022
3023
3024


3025
3026











3027
3028
3029


3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040















































3041
3042
3043
3044
3045
3046

3047
3048
3049
3050
3051
3052


3053
3054

3055
3056
3057


3058
3059

3060
3061
3062
3063
3064
3065

3066
3067
3068
3069
3070
3071
3072
3073
3074
3075

3076



3077

3078

3079
3080
3081
3082
3083
3084
3085












3086
3087


3088
3089
3090
3091
3092











3093
3094
3095
3096




3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116

3117
3118
3119
3120
3121
3122

3123
3124
3125
3126
3127
3128

3129
3130

3131
3132
3133











3134
3135
3136
3137
3138
3139
3140
3141

3142
3143
3144
3145
3146
3147
3148
4185
4186
4187
4188
4189
4190
4191

4192
4193
4194
4195
4196

4197
4198
4199
4200
4201

4202
4203
4204

4205
4206
4207

4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223

4224



4225
4226
4227
4228
4229



4230
4231
4232
4233

4234


4235




4236





4237
4238
4239
4240
4241
4242



4243
4244







4245




4246
4247






4248






4249
4250





4251










4252




4253


4254







4255
4256












4257
4258




4259





4260
4261
4262





4263



4264
4265



4266



4267


4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280





4281
4282
4283
4284
4285

4286















4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306

4307





4308
4309
4310
4311
4312
4313
4314
4315

4316




















4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331


4332
4333
4334

4335
4336
4337
4338
4339
4340
4341
4342
4343



4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361


4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411


4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461


4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473


4474
4475
4476










4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528

4529



4530


4531
4532


4533
4534


4535
4536


4537






4538




4539
4540
4541
4542
4543
4544
4545

4546
4547
4548
4549
4550

4551







4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563


4564
4565





4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576




4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599

4600
4601
4602
4603
4604
4605

4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616



4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634

4635
4636
4637
4638
4639
4640
4641
4642







-
+




-
+




-
+


-
+


-
+















-
+
-
-
-
+
+
+


-
-
-
+
+
+

-
+
-
-
+
-
-
-
-

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













-
-
-
-
-





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




















-
+
-
-
-
-
-
+
+






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















-
-
+
+

-
+



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

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

+
+
+




+

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







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

-
-
+
+

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





-
+
-
-
-

-
-
+
+
-
-
+

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






+
-
+
+
+

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



















-
+





-
+






+


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







-
+







  u32 n;

  if( argc&1 ){
    sqlite3_result_error(ctx, "json_object() requires an even number "
                                  "of arguments", -1);
    return;
  }
  jsonInit(&jx, ctx);
  jsonStringInit(&jx, ctx);
  jsonAppendChar(&jx, '{');
  for(i=0; i<argc; i+=2){
    if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
      sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
      jsonReset(&jx);
      jsonStringReset(&jx);
      return;
    }
    jsonAppendSeparator(&jx);
    z = (const char*)sqlite3_value_text(argv[i]);
    n = (u32)sqlite3_value_bytes(argv[i]);
    n = sqlite3_value_bytes(argv[i]);
    jsonAppendString(&jx, z, n);
    jsonAppendChar(&jx, ':');
    jsonAppendValue(&jx, argv[i+1]);
    jsonAppendSqlValue(&jx, argv[i+1]);
  }
  jsonAppendChar(&jx, '}');
  jsonResult(&jx);
  jsonReturnString(&jx, 0, 0);
  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}


/*
** json_remove(JSON, PATH, ...)
**
** Remove the named elements from JSON and return the result.  malformed
** JSON or PATH arguments result in an error.
*/
static void jsonRemoveFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *pParse;          /* The parse */
  JsonParse *p;          /* The parse */
  JsonNode *pNode;
  const char *zPath;
  u32 i;
  const char *zPath = 0; /* Path of element to be removed */
  int i;                 /* Loop counter */
  u32 rc;                /* Subroutine return code */

  if( argc<1 ) return;
  pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
  if( pParse==0 ) return;
  for(i=1; i<(u32)argc; i++){
  p = jsonParseFuncArg(ctx, argv[0], argc>1 ? JSON_EDITABLE : 0);
  if( p==0 ) return;
  for(i=1; i<argc; i++){
    zPath = (const char*)sqlite3_value_text(argv[i]);
    if( zPath==0 ) goto remove_done;
    if( zPath==0 ){
    pNode = jsonLookup(pParse, zPath, 0, ctx);
    if( pParse->nErr ) goto remove_done;
      goto json_remove_done;
    if( pNode ){
      pNode->jnFlags |= JNODE_REMOVE;
      pParse->hasMod = 1;
      pParse->useMod = 1;
    }
  }
  if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){
    jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0);
  }
remove_done:
    if( zPath[0]!='$' ){
      goto json_remove_patherror;
    }
    if( zPath[1]==0 ){
      /* json_remove(j,'$') returns NULL */
      goto json_remove_done;
  jsonDebugPrintParse(p);
}

    }
    p->eEdit = JEDIT_DEL;
/*
** Substitute the value at iNode with the pValue parameter.
*/
static void jsonReplaceNode(
  sqlite3_context *pCtx,
  JsonParse *p,
  int iNode,
    p->delta = 0;
  sqlite3_value *pValue
){
  int idx = jsonParseAddSubstNode(p, iNode);
  if( idx<=0 ){
    rc = jsonLookupStep(p, 0, zPath+1, 0);
    if( JSON_LOOKUP_ISERROR(rc) ){
    assert( p->oom );
    return;
  }
  switch( sqlite3_value_type(pValue) ){
    case SQLITE_NULL: {
      jsonParseAddNode(p, JSON_NULL, 0, 0);
      if( rc==JSON_LOOKUP_NOTFOUND ){
      break;
    }
    case SQLITE_FLOAT: {
      char *z = sqlite3_mprintf("%!0.15g", sqlite3_value_double(pValue));
      int n;
      if( z==0 ){
        continue;  /* No-op */
      }else if( rc==JSON_LOOKUP_PATHERROR ){
        p->oom = 1;
        break;
      }
      n = sqlite3Strlen30(z);
      jsonParseAddNode(p, JSON_REAL, n, z);
        jsonBadPathError(ctx, zPath);
      jsonParseAddCleanup(p, sqlite3_free, z);
      break;
    }
    case SQLITE_INTEGER: {
      char *z = sqlite3_mprintf("%lld", sqlite3_value_int64(pValue));
      int n;
      if( z==0 ){
        p->oom = 1;
        break;
      }
      }else{
      n = sqlite3Strlen30(z);
      jsonParseAddNode(p, JSON_INT, n, z);
      jsonParseAddCleanup(p, sqlite3_free, z);

        sqlite3_result_error(ctx, "malformed JSON", -1);
      break;
    }
      }
    case SQLITE_TEXT: {
      const char *z = (const char*)sqlite3_value_text(pValue);
      u32 n = (u32)sqlite3_value_bytes(pValue);
      if( z==0 ){
         p->oom = 1;
         break;
      }
      goto json_remove_done;
    }
      if( sqlite3_value_subtype(pValue)!=JSON_SUBTYPE ){
        char *zCopy = sqlite3_malloc64( n+1 );
        int k;
        if( zCopy ){
          memcpy(zCopy, z, n);
          zCopy[n] = 0;
          jsonParseAddCleanup(p, sqlite3_free, zCopy);
        }else{
          p->oom = 1;
          sqlite3_result_error_nomem(pCtx);
        }
        k = jsonParseAddNode(p, JSON_STRING, n, zCopy);
  }
  jsonReturnParse(ctx, p);
        assert( k>0 || p->oom );
        if( p->oom==0 ) p->aNode[k].jnFlags |= JNODE_RAW;
      }else{
        JsonParse *pPatch = jsonParseCached(pCtx, pValue, pCtx, 1);
  jsonParseFree(p);
        if( pPatch==0 ){
          p->oom = 1;
          break;
        }
        jsonParseAddNodeArray(p, pPatch->aNode, pPatch->nNode);
  return;

json_remove_patherror:
        /* The nodes copied out of pPatch and into p likely contain
        ** u.zJContent pointers into pPatch->zJson.  So preserve the
        ** content of pPatch until p is destroyed. */
        assert( pPatch->nJPRef>=1 );
        pPatch->nJPRef++;
  jsonBadPathError(ctx, zPath);
        jsonParseAddCleanup(p, (void(*)(void*))jsonParseFree, pPatch);
      }
      break;

json_remove_done:
    }
    default: {
      jsonParseAddNode(p, JSON_NULL, 0, 0);
  jsonParseFree(p);
      sqlite3_result_error(pCtx, "JSON cannot hold BLOB values", -1);
      p->nErr++;
      break;
  return;
    }
  }
}

/*
** json_replace(JSON, PATH, VALUE, ...)
**
** Replace the value at PATH with VALUE.  If PATH does not already exist,
** this routine is a no-op.  If JSON or PATH is malformed, throw an error.
*/
static void jsonReplaceFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *pParse;          /* The parse */
  JsonNode *pNode;
  const char *zPath;
  u32 i;

  if( argc<1 ) return;
  if( (argc&1)==0 ) {
    jsonWrongNumArgs(ctx, "replace");
    return;
  }
  pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
  jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL);
  if( pParse==0 ) return;
  pParse->nJPRef++;
  for(i=1; i<(u32)argc; i+=2){
    zPath = (const char*)sqlite3_value_text(argv[i]);
    pParse->useMod = 1;
    pNode = jsonLookup(pParse, zPath, 0, ctx);
    if( pParse->nErr ) goto replace_err;
    if( pNode ){
      jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
    }
  }
  jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0);
replace_err:
  jsonDebugPrintParse(pParse);
  jsonParseFree(pParse);
}


/*
** json_set(JSON, PATH, VALUE, ...)
**
** Set the value at PATH to VALUE.  Create the PATH if it does not already
** exist.  Overwrite existing values that do exist.
** If JSON or PATH is malformed, throw an error.
**
** json_insert(JSON, PATH, VALUE, ...)
**
** Create PATH and initialize it to VALUE.  If PATH already exists, this
** routine is a no-op.  If JSON or PATH is malformed, throw an error.
*/
static void jsonSetFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *pParse;       /* The parse */

  JsonNode *pNode;
  const char *zPath;
  u32 i;
  int bApnd;
  int bIsSet = sqlite3_user_data(ctx)!=0;
  int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
  int bIsSet = (flags&JSON_ISSET)!=0;

  if( argc<1 ) return;
  if( (argc&1)==0 ) {
    jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
    return;
  }
  pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
  jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS);
  if( pParse==0 ) return;
  pParse->nJPRef++;
  for(i=1; i<(u32)argc; i+=2){
    zPath = (const char*)sqlite3_value_text(argv[i]);
    bApnd = 0;
    pParse->useMod = 1;
    pNode = jsonLookup(pParse, zPath, &bApnd, ctx);
    if( pParse->oom ){
      sqlite3_result_error_nomem(ctx);
      goto jsonSetDone;
    }else if( pParse->nErr ){
      goto jsonSetDone;
    }else if( pNode && (bApnd || bIsSet) ){
      jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
    }
  }
  jsonDebugPrintParse(pParse);
  jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0);
jsonSetDone:
  jsonParseFree(pParse);
}

/*
** json_type(JSON)
** json_type(JSON, PATH)
**
** Return the top-level "type" of a JSON string.  json_type() raises an
** error if either the JSON or PATH inputs are not well-formed.
*/
static void jsonTypeFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *p;          /* The parse */
  const char *zPath;
  JsonNode *pNode;
  const char *zPath = 0;
  u32 i;

  p = jsonParseCached(ctx, argv[0], ctx, 0);
  p = jsonParseFuncArg(ctx, argv[0], 0);
  if( p==0 ) return;
  if( argc==2 ){
    zPath = (const char*)sqlite3_value_text(argv[1]);
    if( zPath==0 ) goto json_type_done;
    if( zPath[0]!='$' ){
      jsonBadPathError(ctx, zPath);
      goto json_type_done;
    }
    pNode = jsonLookup(p, zPath, 0, ctx);
  }else{
    pNode = p->aNode;
    i = jsonLookupStep(p, 0, zPath+1, 0);
    if( JSON_LOOKUP_ISERROR(i) ){
      if( i==JSON_LOOKUP_NOTFOUND ){
        /* no-op */
      }else if( i==JSON_LOOKUP_PATHERROR ){
        jsonBadPathError(ctx, zPath);
      }else{
        sqlite3_result_error(ctx, "malformed JSON", -1);
      }
      goto json_type_done;
    }
  }else{
    i = 0;
  }
  sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC);
json_type_done:
  jsonParseFree(p);
}
  if( pNode ){
    sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);

/*
** json_pretty(JSON)
** json_pretty(JSON, INDENT)
**
** Return text that is a pretty-printed rendering of the input JSON.
** If the argument is not valid JSON, return NULL.
**
** The INDENT argument is text that is used for indentation.  If omitted,
** it defaults to four spaces (the same as PostgreSQL).
*/
static void jsonPrettyFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonString s;          /* The output string */
  JsonPretty x;          /* Pretty printing context */

  memset(&x, 0, sizeof(x));
  x.pParse = jsonParseFuncArg(ctx, argv[0], 0);
  if( x.pParse==0 ) return;
  x.pOut = &s;
  jsonStringInit(&s, ctx);
  if( argc==1 || (x.zIndent = (const char*)sqlite3_value_text(argv[1]))==0 ){
    x.zIndent = "    ";
    x.szIndent = 4;
  }else{
    x.szIndent = (u32)strlen(x.zIndent);
  }
  jsonTranslateBlobToPrettyText(&x, 0);
  jsonReturnString(&s, 0, 0);
  jsonParseFree(x.pParse);
}

/*
** json_valid(JSON)
** json_valid(JSON, FLAGS)
**
** Check the JSON argument to see if it is well-formed.  The FLAGS argument
** encodes the various constraints on what is meant by "well-formed":
**
**     0x01      Canonical RFC-8259 JSON text
**     0x02      JSON text with optional JSON-5 extensions
**     0x04      Superficially appears to be JSONB
**     0x08      Strictly well-formed JSONB
**
** If the FLAGS argument is omitted, it defaults to 1.  Useful values for
** FLAGS include:
**
** Return 1 if JSON is a well-formed canonical JSON string according
** to RFC-7159. Return 0 otherwise.
**    1          Strict canonical JSON text
**    2          JSON text perhaps with JSON-5 extensions
**    4          Superficially appears to be JSONB
**    5          Canonical JSON text or superficial JSONB
**    6          JSON-5 text or superficial JSONB
**    8          Strict JSONB
**    9          Canonical JSON text or strict JSONB
**    10         JSON-5 text or strict JSONB
**
** Other flag combinations are redundant.  For example, every canonical
** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3
** are the same.  Similarly, any input that passes a strict JSONB validation
** will also pass the superficial validation so 12 through 15 are the same
** as 8 through 11 respectively.
**
** This routine runs in linear time to validate text and when doing strict
** JSONB validation.  Superficial JSONB validation is constant time,
** assuming the BLOB is already in memory.  The performance advantage
** of superficial JSONB validation is why that option is provided.
** Application developers can choose to do fast superficial validation or
** slower strict validation, according to their specific needs.
**
** Only the lower four bits of the FLAGS argument are currently used.
** Higher bits are reserved for future expansion.   To facilitate
** compatibility, the current implementation raises an error if any bit
** in FLAGS is set other than the lower four bits.
**
** The original circa 2015 implementation of the JSON routines in
** SQLite only supported canonical RFC-8259 JSON text and the json_valid()
** function only accepted one argument.  That is why the default value
** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only
** recognize canonical RFC-8259 JSON text as valid.  The extra FLAGS
** argument was added when the JSON routines were extended to support
** JSON5-like extensions and binary JSONB stored in BLOBs.
**
** Return Values:
**
**   *   Raise an error if FLAGS is outside the range of 1 to 15.
**   *   Return NULL if the input is NULL
**   *   Return 1 if the input is well-formed.
**   *   Return 0 if the input is not well-formed.
*/
static void jsonValidFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonParse *p;          /* The parse */
  u8 flags = 1;
  u8 res = 0;
  UNUSED_PARAMETER(argc);
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
  if( argc==2 ){
    i64 f = sqlite3_value_int64(argv[1]);
    if( f<1 || f>15 ){
      sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be"
                                " between 1 and 15", -1);
      return;
    }
    flags = f & 0x0f;
  }
  switch( sqlite3_value_type(argv[0]) ){
    case SQLITE_NULL: {
#ifdef SQLITE_LEGACY_JSON_VALID
    /* Incorrect legacy behavior was to return FALSE for a NULL input */
    sqlite3_result_int(ctx, 0);
      /* Incorrect legacy behavior was to return FALSE for a NULL input */
      sqlite3_result_int(ctx, 0);
#endif
    return;
  }
  p = jsonParseCached(ctx, argv[0], 0, 0);
  if( p==0 || p->oom ){
    sqlite3_result_error_nomem(ctx);
    sqlite3_free(p);
  }else{
    sqlite3_result_int(ctx, p->nErr==0 && (p->hasNonstd==0 || p->useMod));
    if( p->nErr ) jsonParseFree(p);
  }
      return;
    }
    case SQLITE_BLOB: {
      if( jsonFuncArgMightBeBinary(argv[0]) ){
        if( flags & 0x04 ){
          /* Superficial checking only - accomplished by the
          ** jsonFuncArgMightBeBinary() call above. */
          res = 1;
        }else if( flags & 0x08 ){
          /* Strict checking.  Check by translating BLOB->TEXT->BLOB.  If
          ** no errors occur, call that a "strict check". */
          JsonParse px;
          u32 iErr;
          memset(&px, 0, sizeof(px));
          px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
          px.nBlob = sqlite3_value_bytes(argv[0]);
          iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
          res = iErr==0;
        }
        break;
      }
      /* Fall through into interpreting the input as text.  See note
      ** above at tag-20240123-a. */
      /* no break */ deliberate_fall_through
    }
    default: {
      JsonParse px;
      if( (flags & 0x3)==0 ) break;
      memset(&px, 0, sizeof(px));
     
      p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR);
      if( p ){
        if( p->oom ){
          sqlite3_result_error_nomem(ctx);
        }else if( p->nErr ){
          /* no-op */
        }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){
          res = 1;
        }
        jsonParseFree(p);
      }else{
        sqlite3_result_error_nomem(ctx);
      }
      break;
    }
  }
  sqlite3_result_int(ctx, res);
}

/*
** json_error_position(JSON)
**
** If the argument is not an interpretable JSON string, then return the 1-based
** If the argument is NULL, return NULL
** character position at which the parser first recognized that the input
** was in error.  The left-most character is 1.  If the string is valid
** JSON, then return 0.
**
** Note that json_valid() is only true for strictly conforming canonical JSON.
** But this routine returns zero if the input contains extension.  Thus:
** If the argument is BLOB, do a full validity check and return non-zero
** if the check fails.  The return value is the approximate 1-based offset
**
** (1) If the input X is strictly conforming canonical JSON:
** to the byte of the element that contains the first error.
**
**         json_valid(X) returns true
**         json_error_position(X) returns 0
** Otherwise interpret the argument is TEXT (even if it is numeric) and
** return the 1-based character position for where the parser first recognized
**
** (2) If the input X is JSON but it includes extension (such as JSON5) that
** that the input was not valid JSON, or return 0 if the input text looks
**     are not part of RFC-8259:
**
**         json_valid(X) returns false
**         json_error_position(X) return 0
**
** (3) If the input X cannot be interpreted as JSON even taking extensions
** ok.  JSON-5 extensions are accepted.
**     into account:
**
**         json_valid(X) return false
**         json_error_position(X) returns 1 or more
*/
static void jsonErrorFunc(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  i64 iErrPos = 0;       /* Error position to be returned */
  JsonParse *p;          /* The parse */
  JsonParse s;

  assert( argc==1 );
  UNUSED_PARAMETER(argc);
  memset(&s, 0, sizeof(s));
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  s.db = sqlite3_context_db_handle(ctx);
  p = jsonParseCached(ctx, argv[0], 0, 0);
  if( p==0 || p->oom ){
    sqlite3_result_error_nomem(ctx);
    sqlite3_free(p);
  }else if( p->nErr==0 ){
    sqlite3_result_int(ctx, 0);
  }else{
  if( jsonFuncArgMightBeBinary(argv[0]) ){
    s.aBlob = (u8*)sqlite3_value_blob(argv[0]);
    s.nBlob = sqlite3_value_bytes(argv[0]);
    iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1);
  }else{
    s.zJson = (char*)sqlite3_value_text(argv[0]);
    if( s.zJson==0 ) return;  /* NULL input or OOM */
    s.nJson = sqlite3_value_bytes(argv[0]);
    if( jsonConvertTextToBlob(&s,0) ){
      if( s.oom ){
        iErrPos = -1;
      }else{
    int n = 1;
    u32 i;
        /* Convert byte-offset s.iErr into a character offset */
        u32 k;
    const char *z = (const char*)sqlite3_value_text(argv[0]);
    for(i=0; i<p->iErr && ALWAYS(z[i]); i++){
      if( (z[i]&0xc0)!=0x80 ) n++;
    }
    sqlite3_result_int(ctx, n);
        assert( s.zJson!=0 );  /* Because s.oom is false */
        for(k=0; k<s.iErr && ALWAYS(s.zJson[k]); k++){
          if( (s.zJson[k] & 0xc0)!=0x80 ) iErrPos++;
        }
        iErrPos++;
      }
    }
  }
  jsonParseReset(&s);
  if( iErrPos<0 ){
    sqlite3_result_error_nomem(ctx);
    jsonParseFree(p);
  }
}

  }else{
    sqlite3_result_int64(ctx, iErrPos);
  }
}

/****************************************************************************
** Aggregate SQL function implementations
****************************************************************************/
/*
** json_group_array(VALUE)
**
** Return a JSON array composed of all values in the aggregate.
*/
static void jsonArrayStep(
  sqlite3_context *ctx,
  int argc,
  sqlite3_value **argv
){
  JsonString *pStr;
  UNUSED_PARAMETER(argc);
  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
  if( pStr ){
    if( pStr->zBuf==0 ){
      jsonInit(pStr, ctx);
      jsonStringInit(pStr, ctx);
      jsonAppendChar(pStr, '[');
    }else if( pStr->nUsed>1 ){
      jsonAppendChar(pStr, ',');
    }
    pStr->pCtx = ctx;
    jsonAppendValue(pStr, argv[0]);
    jsonAppendSqlValue(pStr, argv[0]);
  }
}
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
  JsonString *pStr;
  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
  if( pStr ){
    int flags;
    pStr->pCtx = ctx;
    jsonAppendChar(pStr, ']');
    flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
    if( pStr->bErr ){
      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
      assert( pStr->bStatic );
    if( pStr->eErr ){
      jsonReturnString(pStr, 0, 0);
      return;
    }else if( flags & JSON_BLOB ){
      jsonReturnStringAsBlob(pStr);
      if( isFinal ){
        if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf);
      }else{
        jsonStringTrimOneChar(pStr);
      }
      return;
    }else if( isFinal ){
      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
                          pStr->bStatic ? SQLITE_TRANSIENT :
                              sqlite3RCStrUnref);
      pStr->bStatic = 1;
    }else{
      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
      pStr->nUsed--;
      jsonStringTrimOneChar(pStr);
    }
  }else{
    sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
  }
  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonArrayValue(sqlite3_context *ctx){
3215
3216
3217
3218
3219
3220
3221
3222

3223
3224
3225
3226
3227
3228
3229

3230
3231
3232

3233
3234
3235
3236
3237
3238

3239


3240
3241
3242











3243
3244
3245
3246
3247
3248
3249
3250

3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269









3270
3271
3272
3273
3274
3275

3276

3277

3278
3279
3280





3281
3282






3283
3284
3285
3286
3287
3288
3289
3290
3291
3292

3293
3294
3295
3296
3297
3298
3299
4709
4710
4711
4712
4713
4714
4715

4716
4717
4718
4719
4720
4721
4722

4723
4724
4725

4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736



4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754

4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787


4788
4789
4790

4791
4792


4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814

4815
4816
4817
4818
4819
4820
4821
4822







-
+






-
+


-
+






+

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







-
+



















+
+
+
+
+
+
+
+
+




-
-
+

+
-
+

-
-
+
+
+
+
+


+
+
+
+
+
+









-
+







  JsonString *pStr;
  const char *z;
  u32 n;
  UNUSED_PARAMETER(argc);
  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
  if( pStr ){
    if( pStr->zBuf==0 ){
      jsonInit(pStr, ctx);
      jsonStringInit(pStr, ctx);
      jsonAppendChar(pStr, '{');
    }else if( pStr->nUsed>1 ){
      jsonAppendChar(pStr, ',');
    }
    pStr->pCtx = ctx;
    z = (const char*)sqlite3_value_text(argv[0]);
    n = (u32)sqlite3_value_bytes(argv[0]);
    n = sqlite3Strlen30(z);
    jsonAppendString(pStr, z, n);
    jsonAppendChar(pStr, ':');
    jsonAppendValue(pStr, argv[1]);
    jsonAppendSqlValue(pStr, argv[1]);
  }
}
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
  JsonString *pStr;
  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
  if( pStr ){
    int flags;
    jsonAppendChar(pStr, '}');
    pStr->pCtx = ctx;
    flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
    if( pStr->bErr ){
      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
      assert( pStr->bStatic );
    if( pStr->eErr ){
      jsonReturnString(pStr, 0, 0);
      return;
    }else if( flags & JSON_BLOB ){
      jsonReturnStringAsBlob(pStr);
      if( isFinal ){
        if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf);
      }else{
        jsonStringTrimOneChar(pStr);
      }
      return;
    }else if( isFinal ){
      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
                          pStr->bStatic ? SQLITE_TRANSIENT :
                          sqlite3RCStrUnref);
      pStr->bStatic = 1;
    }else{
      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
      pStr->nUsed--;
      jsonStringTrimOneChar(pStr);
    }
  }else{
    sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
  }
  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonObjectValue(sqlite3_context *ctx){
  jsonObjectCompute(ctx, 0);
}
static void jsonObjectFinal(sqlite3_context *ctx){
  jsonObjectCompute(ctx, 1);
}



#ifndef SQLITE_OMIT_VIRTUALTABLE
/****************************************************************************
** The json_each virtual table
****************************************************************************/
typedef struct JsonParent JsonParent;
struct JsonParent {
  u32 iHead;                 /* Start of object or array */
  u32 iValue;                /* Start of the value */
  u32 iEnd;                  /* First byte past the end */
  u32 nPath;                 /* Length of path */
  i64 iKey;                  /* Key for JSONB_ARRAY */
};

typedef struct JsonEachCursor JsonEachCursor;
struct JsonEachCursor {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  u32 iRowid;                /* The rowid */
  u32 iBegin;                /* The first node of the scan */
  u32 i;                     /* Index in sParse.aNode[] of current row */
  u32 i;                     /* Index in sParse.aBlob[] of current row */
  u32 iEnd;                  /* EOF when i equals or exceeds this value */
  u32 nRoot;                 /* Size of the root path in bytes */
  u8 eType;                  /* Type of top-level element */
  u8 eType;                  /* Type of the container for element i */
  u8 bRecursive;             /* True for json_tree().  False for json_each() */
  char *zJson;               /* Input JSON */
  char *zRoot;               /* Path by which to filter zJson */
  u32 nParent;               /* Current nesting depth */
  u32 nParentAlloc;          /* Space allocated for aParent[] */
  JsonParent *aParent;       /* Parent elements of i */
  sqlite3 *db;               /* Database connection */
  JsonString path;           /* Current path */
  JsonParse sParse;          /* Parse of the input JSON */
};
typedef struct JsonEachConnection JsonEachConnection;
struct JsonEachConnection {
  sqlite3_vtab base;         /* Base class - must be first */
  sqlite3 *db;               /* Database connection */
};


/* Constructor for the json_each virtual table */
static int jsonEachConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  sqlite3_vtab *pNew;
  JsonEachConnection *pNew;
  int rc;

/* Column numbers */
#define JEACH_KEY     0
#define JEACH_VALUE   1
#define JEACH_TYPE    2
#define JEACH_ATOM    3
3311
3312
3313
3314
3315
3316
3317

3318

3319
3320
3321

3322
3323
3324
3325
3326
3327

3328

3329
3330
3331
3332
3333

3334
3335
3336
3337

3338
3339


3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358


3359
3360



3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371


3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390




















3391
3392
3393
3394
3395
3396
3397
3398
3399
3400

















3401
3402
3403


3404

3405
3406
3407
3408

3409
3410

3411
3412
3413
3414
3415

3416
3417
3418
3419
3420


3421
3422




3423
3424


















3425
3426
3427
3428
3429
3430

3431
3432
3433


3434
3435
3436
3437
3438
3439





3440
3441
3442
3443
3444
3445


3446
3447
3448




3449




3450

3451
3452
3453








3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466

3467
3468
3469
3470
3471
3472
3473
3474
3475





3476
3477
3478
3479




























3480
3481
3482
3483
3484
3485
3486

3487
3488
3489
3490

3491
3492
3493
3494
3495





3496
3497
3498
3499
3500








3501
3502

3503






3504

3505
3506
3507
3508
3509
3510





3511
3512
3513
3514
3515



3516
3517
3518
3519
3520
3521




3522
3523
3524
3525

3526
3527
3528
3529
3530
3531


3532
3533
3534
3535
3536
3537
3538
3539
3540
3541

3542
3543
3544

3545
3546
3547
3548



3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562





3563
3564
3565
3566
3567
3568
3569
3570

3571
3572
3573



3574
3575



3576
3577
3578
3579
3580
3581
3582
4834
4835
4836
4837
4838
4839
4840
4841

4842
4843

4844
4845
4846
4847
4848
4849
4850
4851
4852

4853
4854
4855
4856
4857
4858
4859
4860
4861
4862

4863
4864

4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883

4884
4885
4886
4887
4888
4889
4890
4891
4892
4893


4894
4895
4896
4897
4898
4899

4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911









4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931










4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953

4954




4955


4956





4957





4958
4959


4960
4961
4962
4963


4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981






4982



4983
4984






4985
4986
4987
4988
4989






4990
4991


4992
4993
4994
4995
4996
4997
4998
4999
5000
5001

5002



5003
5004
5005
5006
5007
5008
5009
5010













5011








5012
5013
5014
5015
5016
5017




5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051

5052
5053
5054


5055
5056




5057
5058
5059
5060
5061





5062
5063
5064
5065
5066
5067
5068
5069
5070

5071
5072
5073
5074
5075
5076
5077
5078

5079
5080
5081
5082
5083


5084
5085
5086
5087
5088
5089
5090
5091


5092
5093
5094
5095
5096
5097



5098
5099
5100
5101
5102
5103
5104

5105

5106
5107
5108


5109
5110
5111
5112
5113
5114






5115



5116




5117
5118
5119




5120
5121
5122







5123
5124
5125
5126
5127




5128



5129
5130
5131
5132
5133
5134
5135


5136
5137
5138
5139
5140
5141
5142
5143
5144
5145







+
-
+

-

+






+
-
+





+



-
+

-
+
+

















-

+
+


+
+
+


-
-






-
+
+










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



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

+
+
+
+

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

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






-
+


-
-
+

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

-
+

+
+
+
+
+
+
-
+




-
-
+
+
+
+
+



-
-
+
+
+



-
-
-
+
+
+
+



-
+
-



-
-
+
+




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



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

-
-
-
+



+
+
+
-
-
+
+
+







  UNUSED_PARAMETER(argv);
  UNUSED_PARAMETER(argc);
  UNUSED_PARAMETER(pAux);
  rc = sqlite3_declare_vtab(db,
     "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
                    "json HIDDEN,root HIDDEN)");
  if( rc==SQLITE_OK ){
    pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew));
    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
    *ppVtab = (sqlite3_vtab*)pNew;
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));
    sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
    pNew->db = db;
  }
  return rc;
}

/* destructor for json_each virtual table */
static int jsonEachDisconnect(sqlite3_vtab *pVtab){
  JsonEachConnection *p = (JsonEachConnection*)pVtab;
  sqlite3_free(pVtab);
  sqlite3DbFree(p->db, pVtab);
  return SQLITE_OK;
}

/* constructor for a JsonEachCursor object for json_each(). */
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
  JsonEachConnection *pVtab = (JsonEachConnection*)p;
  JsonEachCursor *pCur;

  UNUSED_PARAMETER(p);
  pCur = sqlite3_malloc( sizeof(*pCur) );
  pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur));
  if( pCur==0 ) return SQLITE_NOMEM;
  memset(pCur, 0, sizeof(*pCur));
  pCur->db = pVtab->db;
  jsonStringZero(&pCur->path);
  *ppCursor = &pCur->base;
  return SQLITE_OK;
}

/* constructor for a JsonEachCursor object for json_tree(). */
static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
  int rc = jsonEachOpenEach(p, ppCursor);
  if( rc==SQLITE_OK ){
    JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
    pCur->bRecursive = 1;
  }
  return rc;
}

/* Reset a JsonEachCursor back to its original state.  Free any memory
** held. */
static void jsonEachCursorReset(JsonEachCursor *p){
  sqlite3_free(p->zRoot);
  jsonParseReset(&p->sParse);
  jsonStringReset(&p->path);
  sqlite3DbFree(p->db, p->aParent);
  p->iRowid = 0;
  p->i = 0;
  p->aParent = 0;
  p->nParent = 0;
  p->nParentAlloc = 0;
  p->iEnd = 0;
  p->eType = 0;
  p->zJson = 0;
  p->zRoot = 0;
}

/* Destructor for a jsonEachCursor object */
static int jsonEachClose(sqlite3_vtab_cursor *cur){
  JsonEachCursor *p = (JsonEachCursor*)cur;
  jsonEachCursorReset(p);
  sqlite3_free(cur);
  
  sqlite3DbFree(p->db, cur);
  return SQLITE_OK;
}

/* Return TRUE if the jsonEachCursor object has been advanced off the end
** of the JSON object */
static int jsonEachEof(sqlite3_vtab_cursor *cur){
  JsonEachCursor *p = (JsonEachCursor*)cur;
  return p->i >= p->iEnd;
}

/* Advance the cursor to the next element for json_tree() */
static int jsonEachNext(sqlite3_vtab_cursor *cur){
  JsonEachCursor *p = (JsonEachCursor*)cur;
  if( p->bRecursive ){
    if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
    p->i++;
    p->iRowid++;
    if( p->i<p->iEnd ){
      u32 iUp = p->sParse.aUp[p->i];
/*
** If the cursor is currently pointing at the label of a object entry,
** then return the index of the value.  For all other cases, return the
** current pointer position, which is the value.
*/
static int jsonSkipLabel(JsonEachCursor *p){
  if( p->eType==JSONB_OBJECT ){
    u32 sz = 0;
    u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz);
    return p->i + n + sz;
  }else{
    return p->i;
  }
}

/*
** Append the path name for the current element.
*/
static void jsonAppendPathName(JsonEachCursor *p){
  assert( p->nParent>0 );
      JsonNode *pUp = &p->sParse.aNode[iUp];
      p->eType = pUp->eType;
      if( pUp->eType==JSON_ARRAY ){
        assert( pUp->eU==0 || pUp->eU==3 );
        testcase( pUp->eU==3 );
        VVA( pUp->eU = 3 );
        if( iUp==p->i-1 ){
          pUp->u.iKey = 0;
        }else{
          pUp->u.iKey++;
  assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT );
  if( p->eType==JSONB_ARRAY ){
    jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey);
  }else{
    u32 n, sz = 0, k, i;
    const char *z;
    int needQuote = 0;
    n = jsonbPayloadSize(&p->sParse, p->i, &sz);
    k = p->i + n;
    z = (const char*)&p->sParse.aBlob[k];
    if( sz==0 || !sqlite3Isalpha(z[0]) ){
      needQuote = 1;
    }else{
      for(i=0; i<sz; i++){
        if( !sqlite3Isalnum(z[i]) ){
          needQuote = 1;
          break;
        }
      }
    }
    if( needQuote ){
      jsonPrintf(sz+4,&p->path,".\"%.*s\"", sz, z);
  }else{
    }else{
    switch( p->eType ){
      case JSON_ARRAY: {
        p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
        p->iRowid++;
      jsonPrintf(sz+2,&p->path,".%.*s", sz, z);
        break;
      }
    }
      case JSON_OBJECT: {
        p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
        p->iRowid++;
        break;
      }
  }
      default: {
        p->i = p->iEnd;
        break;
      }
    }
}

  }
  return SQLITE_OK;
/* Advance the cursor to the next element for json_tree() */
static int jsonEachNext(sqlite3_vtab_cursor *cur){
  JsonEachCursor *p = (JsonEachCursor*)cur;
  int rc = SQLITE_OK;
}

  if( p->bRecursive ){
    u8 x;
    u8 levelChange = 0;
    u32 n, sz = 0;
    u32 i = jsonSkipLabel(p);
    x = p->sParse.aBlob[i] & 0x0f;
    n = jsonbPayloadSize(&p->sParse, i, &sz);
    if( x==JSONB_OBJECT || x==JSONB_ARRAY ){
      JsonParent *pParent;
      if( p->nParent>=p->nParentAlloc ){
        JsonParent *pNew;
        u64 nNew;
        nNew = p->nParentAlloc*2 + 3;
        pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew);
        if( pNew==0 ) return SQLITE_NOMEM;
        p->nParentAlloc = (u32)nNew;
        p->aParent = pNew;
      }
/* Append an object label to the JSON Path being constructed
** in pStr.
*/
static void jsonAppendObjectPathElement(
  JsonString *pStr,
  JsonNode *pNode
      levelChange = 1;
){
  int jj, nn;
  const char *z;
      pParent = &p->aParent[p->nParent];
      pParent->iHead = p->i;
  assert( pNode->eType==JSON_STRING );
  assert( pNode->jnFlags & JNODE_LABEL );
  assert( pNode->eU==1 );
  z = pNode->u.zJContent;
  nn = pNode->n;
  if( (pNode->jnFlags & JNODE_RAW)==0 ){
      pParent->iValue = i;
      pParent->iEnd = i + n + sz;
      pParent->iKey = -1;
      pParent->nPath = (u32)p->path.nUsed;
      if( p->eType && p->nParent ){
    assert( nn>=2 );
    assert( z[0]=='"' || z[0]=='\'' );
    assert( z[nn-1]=='"' || z[0]=='\'' );
    if( nn>2 && sqlite3Isalpha(z[1]) ){
      for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
      if( jj==nn-1 ){
        jsonAppendPathName(p);
        if( p->path.eErr ) rc = SQLITE_NOMEM;
        z++;
        nn -= 2;
      }
      p->nParent++;
      p->i = i + n;
    }else{
      p->i = i + n + sz;
    }
    while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){
      p->nParent--;
      p->path.nUsed = p->aParent[p->nParent].nPath;
      levelChange = 1;
  }
    }
  jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
}

    if( levelChange ){
      if( p->nParent>0 ){
        JsonParent *pParent = &p->aParent[p->nParent-1];
        u32 iVal = pParent->iValue;
        p->eType = p->sParse.aBlob[iVal] & 0x0f;
      }else{
        p->eType = 0;
      }
/* Append the name of the path for element i to pStr
*/
static void jsonEachComputePath(
  JsonEachCursor *p,       /* The cursor */
  JsonString *pStr,        /* Write the path here */
  u32 i                    /* Path to this element */
){
  JsonNode *pNode, *pUp;
  u32 iUp;
  if( i==0 ){
    jsonAppendChar(pStr, '$');
    return;
  }
    }
  iUp = p->sParse.aUp[i];
  jsonEachComputePath(p, pStr, iUp);
  pNode = &p->sParse.aNode[i];
  pUp = &p->sParse.aNode[iUp];
  if( pUp->eType==JSON_ARRAY ){
    assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
    testcase( pUp->eU==0 );
    jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
  }else{
    u32 n, sz = 0;
    u32 i = jsonSkipLabel(p);
    n = jsonbPayloadSize(&p->sParse, i, &sz);
    p->i = i + n + sz;
  }
    assert( pUp->eType==JSON_OBJECT );
    if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
    jsonAppendObjectPathElement(pStr, pNode);
  }
  if( p->eType==JSONB_ARRAY && p->nParent ){
    p->aParent[p->nParent-1].iKey++;
  }
  p->iRowid++;
  return rc;
}

/* Length of the path for rowid==0 in bRecursive mode.
*/
static int jsonEachPathLength(JsonEachCursor *p){
  u32 n = p->path.nUsed;
  char *z = p->path.zBuf;
  if( p->iRowid==0 && p->bRecursive && n>=2 ){
    while( n>1 ){
      n--;
      if( z[n]=='[' || z[n]=='.' ){
        u32 x, sz = 0;
        char cSaved = z[n];
        z[n] = 0;
        assert( p->sParse.eEdit==0 );
        x = jsonLookupStep(&p->sParse, 0, z+1, 0);
        z[n] = cSaved;
        if( JSON_LOOKUP_ISERROR(x) ) continue;
        if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break;
      }
    }
  }
  return n;
}

/* Return the value of a column */
static int jsonEachColumn(
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
  int iColumn                 /* Which column to return */
){
  JsonEachCursor *p = (JsonEachCursor*)cur;
  JsonNode *pThis = &p->sParse.aNode[p->i];
  switch( i ){
  switch( iColumn ){
    case JEACH_KEY: {
      if( p->i==0 ) break;
      if( p->eType==JSON_OBJECT ){
        jsonReturn(&p->sParse, pThis, ctx, 0);
      }else if( p->eType==JSON_ARRAY ){
      if( p->nParent==0 ){
        u32 n, j;
        if( p->nRoot==1 ) break;
        j = jsonEachPathLength(p);
        n = p->nRoot - j;
        u32 iKey;
        if( p->bRecursive ){
          if( p->iRowid==0 ) break;
          assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
          iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
        if( n==0 ){
          break;
        }else if( p->path.zBuf[j]=='[' ){
          i64 x;
          sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8);
          sqlite3_result_int64(ctx, x);
        }else if( p->path.zBuf[j+1]=='"' ){
          sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT);
        }else{
          iKey = p->iRowid;
          sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT);
        }
        break;
      }
      if( p->eType==JSONB_OBJECT ){
        jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
      }else{
        assert( p->eType==JSONB_ARRAY );
        sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
        sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
      }
      break;
    }
    case JEACH_VALUE: {
      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
      jsonReturn(&p->sParse, pThis, ctx, 0);
      u32 i = jsonSkipLabel(p);
      jsonReturnFromBlob(&p->sParse, i, ctx, 1);
      if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
        sqlite3_result_subtype(ctx, JSON_SUBTYPE);
      }
      break;
    }
    case JEACH_TYPE: {
      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
      sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
      u32 i = jsonSkipLabel(p);
      u8 eType = p->sParse.aBlob[i] & 0x0f;
      sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
      break;
    }
    case JEACH_ATOM: {
      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
      if( pThis->eType>=JSON_ARRAY ) break;
      jsonReturn(&p->sParse, pThis, ctx, 0);
      u32 i = jsonSkipLabel(p);
      if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){
        jsonReturnFromBlob(&p->sParse, i, ctx, 1);
      }
      break;
    }
    case JEACH_ID: {
      sqlite3_result_int64(ctx,
      sqlite3_result_int64(ctx, (sqlite3_int64)p->i);
         (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
      break;
    }
    case JEACH_PARENT: {
      if( p->i>p->iBegin && p->bRecursive ){
        sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
      if( p->nParent>0 && p->bRecursive ){
        sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
      }
      break;
    }
    case JEACH_FULLKEY: {
      JsonString x;
      jsonInit(&x, ctx);
      if( p->bRecursive ){
        jsonEachComputePath(p, &x, p->i);
      }else{
        if( p->zRoot ){
      u64 nBase = p->path.nUsed;
          jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
        }else{
          jsonAppendChar(&x, '$');
      if( p->nParent ) jsonAppendPathName(p);
        }
        if( p->eType==JSON_ARRAY ){
          jsonPrintf(30, &x, "[%d]", p->iRowid);
        }else if( p->eType==JSON_OBJECT ){
      sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
                            SQLITE_TRANSIENT, SQLITE_UTF8);
      p->path.nUsed = nBase;
          jsonAppendObjectPathElement(&x, pThis);
        }
      }
      jsonResult(&x);
      break;
    }
    case JEACH_PATH: {
      if( p->bRecursive ){
        JsonString x;
        jsonInit(&x, ctx);
        jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
        jsonResult(&x);
        break;
      }
      u32 n = jsonEachPathLength(p);
      sqlite3_result_text64(ctx, p->path.zBuf, n,
                            SQLITE_TRANSIENT, SQLITE_UTF8);
      break;
    }
      /* For json_each() path and root are the same so fall through
      ** into the root case */
      /* no break */ deliberate_fall_through
    }
    default: {
      const char *zRoot = p->zRoot;
      if( zRoot==0 ) zRoot = "$";
      sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
      sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC);
      break;
    }
    case JEACH_JSON: {
      if( p->sParse.zJson==0 ){
        sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
                            SQLITE_TRANSIENT);
      assert( i==JEACH_JSON );
      sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
      }else{
        sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT);
      }
      break;
    }
  }
  return SQLITE_OK;
}

/* Return the current rowid value */
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668

3669
3670
3671
3672
3673
3674
3675
3676
3677


3678
3679


3680

3681

3682
3683
3684
3685




3686
3687
3688

3689
3690

3691
3692
3693
3694
3695



3696
3697
3698
3699
3700
3701
3702



3703
3704
3705


3706
3707
3708
3709
3710
3711
3712
3713
3714



















3715
3716
3717

3718
3719
3720
3721
3722



3723
3724
3725




3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745






























3746
3747
3748
3749
3750
3751
3752
5222
5223
5224
5225
5226
5227
5228

5229

5230
5231
5232
5233
5234
5235


5236
5237
5238
5239


5240
5241
5242
5243

5244




5245
5246
5247
5248



5249


5250





5251
5252
5253







5254
5255
5256



5257
5258









5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277

5278

5279
5280
5281


5282
5283
5284
5285



5286
5287
5288
5289




















5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326







-

-
+





-
-


+
+
-
-
+
+

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

-
+


-
-

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







/* Start a search on a new JSON string */
static int jsonEachFilter(
  sqlite3_vtab_cursor *cur,
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  JsonEachCursor *p = (JsonEachCursor*)cur;
  const char *z;
  const char *zRoot = 0;
  sqlite3_int64 n;
  u32 i, n, sz;

  UNUSED_PARAMETER(idxStr);
  UNUSED_PARAMETER(argc);
  jsonEachCursorReset(p);
  if( idxNum==0 ) return SQLITE_OK;
  z = (const char*)sqlite3_value_text(argv[0]);
  if( z==0 ) return SQLITE_OK;
  memset(&p->sParse, 0, sizeof(p->sParse));
  p->sParse.nJPRef = 1;
  p->sParse.db = p->db;
  if( jsonFuncArgMightBeBinary(argv[0]) ){
  if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){
    p->sParse.zJson = sqlite3RCStrRef((char*)z);
    p->sParse.nBlob = sqlite3_value_bytes(argv[0]);
    p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]);
  }else{
    p->sParse.zJson = (char*)sqlite3_value_text(argv[0]);
    n = sqlite3_value_bytes(argv[0]);
    p->sParse.nJson = sqlite3_value_bytes(argv[0]);
    p->sParse.zJson = sqlite3RCStrNew( n+1 );
    if( p->sParse.zJson==0 ) return SQLITE_NOMEM;
    memcpy(p->sParse.zJson, z, (size_t)n+1);
  }
    if( p->sParse.zJson==0 ){
      p->i = p->iEnd = 0;
      return SQLITE_OK;
    }      
  p->sParse.bJsonIsRCStr = 1;
  p->zJson = p->sParse.zJson;
  if( jsonParse(&p->sParse, 0) ){
    if( jsonConvertTextToBlob(&p->sParse, 0) ){
    int rc = SQLITE_NOMEM;
    if( p->sParse.oom==0 ){
      if( p->sParse.oom ){
      sqlite3_free(cur->pVtab->zErrMsg);
      cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
      if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
    }
    jsonEachCursorReset(p);
        return SQLITE_NOMEM;
      }
      goto json_each_malformed_input;
    return rc;
  }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
    jsonEachCursorReset(p);
    return SQLITE_NOMEM;
  }else{
    JsonNode *pNode = 0;
    if( idxNum==3 ){
    }
  }
  if( idxNum==3 ){
      const char *zErr = 0;
      zRoot = (const char*)sqlite3_value_text(argv[1]);
      if( zRoot==0 ) return SQLITE_OK;
    zRoot = (const char*)sqlite3_value_text(argv[1]);
    if( zRoot==0 ) return SQLITE_OK;
      n = sqlite3_value_bytes(argv[1]);
      p->zRoot = sqlite3_malloc64( n+1 );
      if( p->zRoot==0 ) return SQLITE_NOMEM;
      memcpy(p->zRoot, zRoot, (size_t)n+1);
      if( zRoot[0]!='$' ){
        zErr = zRoot;
      }else{
        pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
      }
    if( zRoot[0]!='$' ){
      sqlite3_free(cur->pVtab->zErrMsg);
      cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
      jsonEachCursorReset(p);
      return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
    }
    p->nRoot = sqlite3Strlen30(zRoot);
    if( zRoot[1]==0 ){
      i = p->i = 0;
      p->eType = 0;
    }else{
      i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0);
      if( JSON_LOOKUP_ISERROR(i) ){
        if( i==JSON_LOOKUP_NOTFOUND ){
          p->i = 0;
          p->eType = 0;
          p->iEnd = 0;
          return SQLITE_OK;
        }
      if( zErr ){
        sqlite3_free(cur->pVtab->zErrMsg);
        cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
        cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
        jsonEachCursorReset(p);
        return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
      }else if( pNode==0 ){
        return SQLITE_OK;
      }
      if( p->sParse.iLabel ){
        p->i = p->sParse.iLabel;
        p->eType = JSONB_OBJECT;
    }else{
      pNode = p->sParse.aNode;
    }
      }else{
        p->i = i;
        p->eType = JSONB_ARRAY;
      }
    p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
    p->eType = pNode->eType;
    if( p->eType>=JSON_ARRAY ){
      assert( pNode->eU==0 );
      VVA( pNode->eU = 3 );
      pNode->u.iKey = 0;
      p->iEnd = p->i + pNode->n + 1;
      if( p->bRecursive ){
        p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
        if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
          p->i--;
        }
      }else{
        p->i++;
      }
    }else{
      p->iEnd = p->i+1;
    }
  }
  return SQLITE_OK;
    }
    jsonAppendRaw(&p->path, zRoot, p->nRoot);
  }else{
    i = p->i = 0;
    p->eType = 0;
    p->nRoot = 1;
    jsonAppendRaw(&p->path, "$", 1);
  }
  p->nParent = 0;
  n = jsonbPayloadSize(&p->sParse, i, &sz);
  p->iEnd = i+n+sz;
  if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){
    p->i = i + n;
    p->eType = p->sParse.aBlob[i] & 0x0f;
    p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent));
    if( p->aParent==0 ) return SQLITE_NOMEM;
    p->nParent = 1;
    p->nParentAlloc = 1;
    p->aParent[0].iKey = 0;
    p->aParent[0].iEnd = p->iEnd;
    p->aParent[0].iHead = p->i;
    p->aParent[0].iValue = i;
  }
  return SQLITE_OK;

json_each_malformed_input:
  sqlite3_free(cur->pVtab->zErrMsg);
  cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
  jsonEachCursorReset(p);
  return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}

/* The methods of the json_each virtual table */
static sqlite3_module jsonEachModule = {
  0,                         /* iVersion */
  0,                         /* xCreate */
  jsonEachConnect,           /* xConnect */
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819






3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
































3841
3842
3843
3844
3845
3846



3847



3848
3849
3850
3851
3852
3853
3854
5381
5382
5383
5384
5385
5386
5387






5388
5389
5390
5391
5392
5393





















5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425

5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444







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





+
+
+

+
+
+








/*
** Register JSON functions.
*/
void sqlite3RegisterJsonFunctions(void){
#ifndef SQLITE_OMIT_JSON
  static FuncDef aJsonFunc[] = {
    /*                     calls sqlite3_result_subtype()                    */
    /*                                  |                                    */
    /*              Uses cache ______   |   __ calls sqlite3_value_subtype() */
    /*                               |  |  |                                 */
    /*          Num args _________   |  |  |   ___ Flags                     */
    /*                            |  |  |  |  |                              */
    /*   sqlite3_result_subtype() ----,  ,--- sqlite3_value_subtype()       */
    /*                                |  |                                  */
    /*             Uses cache ------, |  | ,---- Returns JSONB              */
    /*                              | |  | |                                */
    /*     Number of arguments ---, | |  | | ,--- Flags                     */
    /*                            | | |  | | |                              */
    /*                            |  |  |  |  |                              */
    JFUNCTION(json,               1, 1, 1, 0, 0,          jsonRemoveFunc),
    JFUNCTION(json_array,        -1, 0, 1, 1, 0,          jsonArrayFunc),
    JFUNCTION(json_array_length,  1, 1, 0, 0, 0,          jsonArrayLengthFunc),
    JFUNCTION(json_array_length,  2, 1, 0, 0, 0,          jsonArrayLengthFunc),
    JFUNCTION(json_error_position,1, 1, 0, 0, 0,          jsonErrorFunc),
    JFUNCTION(json_extract,      -1, 1, 1, 0, 0,          jsonExtractFunc),
    JFUNCTION(->,                 2, 1, 1, 0, JSON_JSON,  jsonExtractFunc),
    JFUNCTION(->>,                2, 1, 0, 0, JSON_SQL,   jsonExtractFunc),
    JFUNCTION(json_insert,       -1, 1, 1, 1, 0,          jsonSetFunc),
    JFUNCTION(json_object,       -1, 0, 1, 1, 0,          jsonObjectFunc),
    JFUNCTION(json_patch,         2, 1, 1, 0, 0,          jsonPatchFunc),
    JFUNCTION(json_quote,         1, 0, 1, 1, 0,          jsonQuoteFunc),
    JFUNCTION(json_remove,       -1, 1, 1, 0, 0,          jsonRemoveFunc),
    JFUNCTION(json_replace,      -1, 1, 1, 1, 0,          jsonReplaceFunc),
    JFUNCTION(json_set,          -1, 1, 1, 1, JSON_ISSET, jsonSetFunc),
    JFUNCTION(json_type,          1, 1, 0, 0, 0,          jsonTypeFunc),
    JFUNCTION(json_type,          2, 1, 0, 0, 0,          jsonTypeFunc),
    JFUNCTION(json_valid,         1, 1, 0, 0, 0,          jsonValidFunc),
#ifdef SQLITE_DEBUG
    JFUNCTION(json_parse,         1, 1, 1, 0, 0,          jsonParseFunc),
    JFUNCTION(json,               1,1,1, 0,0,0,          jsonRemoveFunc),
    JFUNCTION(jsonb,              1,1,0, 0,1,0,          jsonRemoveFunc),
    JFUNCTION(json_array,        -1,0,1, 1,0,0,          jsonArrayFunc),
    JFUNCTION(jsonb_array,       -1,0,1, 1,1,0,          jsonArrayFunc),
    JFUNCTION(json_array_length,  1,1,0, 0,0,0,          jsonArrayLengthFunc),
    JFUNCTION(json_array_length,  2,1,0, 0,0,0,          jsonArrayLengthFunc),
    JFUNCTION(json_error_position,1,1,0, 0,0,0,          jsonErrorFunc),
    JFUNCTION(json_extract,      -1,1,1, 0,0,0,          jsonExtractFunc),
    JFUNCTION(jsonb_extract,     -1,1,0, 0,1,0,          jsonExtractFunc),
    JFUNCTION(->,                 2,1,1, 0,0,JSON_JSON,  jsonExtractFunc),
    JFUNCTION(->>,                2,1,0, 0,0,JSON_SQL,   jsonExtractFunc),
    JFUNCTION(json_insert,       -1,1,1, 1,0,0,          jsonSetFunc),
    JFUNCTION(jsonb_insert,      -1,1,0, 1,1,0,          jsonSetFunc),
    JFUNCTION(json_object,       -1,0,1, 1,0,0,          jsonObjectFunc),
    JFUNCTION(jsonb_object,      -1,0,1, 1,1,0,          jsonObjectFunc),
    JFUNCTION(json_patch,         2,1,1, 0,0,0,          jsonPatchFunc),
    JFUNCTION(jsonb_patch,        2,1,0, 0,1,0,          jsonPatchFunc),
    JFUNCTION(json_pretty,        1,1,0, 0,0,0,          jsonPrettyFunc),
    JFUNCTION(json_pretty,        2,1,0, 0,0,0,          jsonPrettyFunc),
    JFUNCTION(json_quote,         1,0,1, 1,0,0,          jsonQuoteFunc),
    JFUNCTION(json_remove,       -1,1,1, 0,0,0,          jsonRemoveFunc),
    JFUNCTION(jsonb_remove,      -1,1,0, 0,1,0,          jsonRemoveFunc),
    JFUNCTION(json_replace,      -1,1,1, 1,0,0,          jsonReplaceFunc),
    JFUNCTION(jsonb_replace,     -1,1,0, 1,1,0,          jsonReplaceFunc),
    JFUNCTION(json_set,          -1,1,1, 1,0,JSON_ISSET, jsonSetFunc),
    JFUNCTION(jsonb_set,         -1,1,0, 1,1,JSON_ISSET, jsonSetFunc),
    JFUNCTION(json_type,          1,1,0, 0,0,0,          jsonTypeFunc),
    JFUNCTION(json_type,          2,1,0, 0,0,0,          jsonTypeFunc),
    JFUNCTION(json_valid,         1,1,0, 0,0,0,          jsonValidFunc),
    JFUNCTION(json_valid,         2,1,0, 0,0,0,          jsonValidFunc),
#if SQLITE_DEBUG
    JFUNCTION(json_parse,         1,1,0, 0,0,0,          jsonParseFunc),
    JFUNCTION(json_test1,         1, 1, 0, 1, 0,          jsonTest1Func),
#endif
    WAGGREGATE(json_group_array,  1, 0, 0,
       jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
       SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
       SQLITE_DETERMINISTIC),
    WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0,
       jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
       SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
    WAGGREGATE(json_group_object, 2, 0, 0,
       jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
       SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
    WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0,
       jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
       SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
       SQLITE_DETERMINISTIC)
  };
  sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
#endif
}
Changes to src/main.c.
4400
4401
4402
4403
4404
4405
4406

































4407
4408
4409
4410
4411
4412
4413
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446







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







        typedef int(*sqlite3LocaltimeType)(const void*,void*);
        sqlite3GlobalConfig.xAltLocaltime = va_arg(ap, sqlite3LocaltimeType);
      }else{
        sqlite3GlobalConfig.xAltLocaltime = 0;
      }
      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_ROWID_IN_VIEW, int *pVal);
    **
    ** Query or set the sqlite3Config.mNoVisibleRowid flag.  Cases:
    **
    **    *pVal==1      Allow ROWID in VIEWs
    **    *pVal==0      Disallow ROWID in VIEWs
    **    *pVal<0       No change
    **
    ** In every case *pVal is written with 1 if ROWID is allowd in VIEWs and
    ** 0 if not.  Changes to the setting only occur if SQLite is compiled
    ** with -DSQLITE_ALLOW_ROWID_IN_VIEW (hereafter: "SARIV").  With the
    ** "SARIV" compile-time option the default value for this setting is 1.
    ** Otherwise this setting defaults to 0.  This setting may only be changed
    ** if SQLite is compiled with "SARIV".  Hence, in the normal case when
    ** SQLite is compiled without "SARIV", this test-control is a no-op
    ** that always leaves *pVal set to 0.
    **
    ** IMPORTANT:  If you change this setting while a database connection
    ** is option, it is very important to run "PRAGMA writable_schema=RESET"
    ** afterwards in order to reparse all VIEW definitions in the schema.
    */
    case SQLITE_TESTCTRL_ROWID_IN_VIEW: {
      int *pVal = va_arg(ap, int*);
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
      if( *pVal==0 ) sqlite3Config.mNoVisibleRowid = TF_NoVisibleRowid;
      if( *pVal==1 ) sqlite3Config.mNoVisibleRowid = 0;
      *pVal = (sqlite3Config.mNoVisibleRowid==0);
#else
      *pVal = 0;
#endif
      break;
    }

    /*   sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*);
    **
    ** Toggle the ability to use internal functions on or off for
    ** the database connection given in the argument.
    */
    case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
4655
4656
4657
4658
4659
4660
4661






















4662
4663
4664
4665
4666
4667
4668
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723







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







        *piValue = Tuning(-id);
      }else{
        rc = SQLITE_NOTFOUND;
      }
      break;
    }
#endif

    /* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff);
    **
    ** Activate or deactivate validation of JSONB that is generated from
    ** text.  Off by default, as the validation is slow.  Validation is
    ** only available if compiled using SQLITE_DEBUG.
    **
    ** If onOff is initially 1, then turn it on.  If onOff is initially
    ** off, turn it off.  If onOff is initially -1, then change onOff
    ** to be the current setting.
    */
    case SQLITE_TESTCTRL_JSON_SELFCHECK: {
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
      int *pOnOff = va_arg(ap, int*);
      if( *pOnOff<0 ){
        *pOnOff = sqlite3Config.bJsonSelfcheck;
      }else{
        sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
      }
#endif
      break;
    }
  }
  va_end(ap);
#endif /* SQLITE_UNTESTABLE */
  return rc;
}

/*
Changes to src/malloc.c.
217
218
219
220
221
222
223


















224
225
226
227
228
229
230
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







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







static void sqlite3MallocAlarm(int nByte){
  if( mem0.alarmThreshold<=0 ) return;
  sqlite3_mutex_leave(mem0.mutex);
  sqlite3_release_memory(nByte);
  sqlite3_mutex_enter(mem0.mutex);
}

#ifdef SQLITE_DEBUG
/*
** This routine is called whenever an out-of-memory condition is seen,
** It's only purpose to to serve as a breakpoint for gdb or similar
** code debuggers when working on out-of-memory conditions, for example
** caused by PRAGMA hard_heap_limit=N.
*/
static SQLITE_NOINLINE void test_oom_breakpoint(u64 n){
  static u64 nOomFault = 0;
  nOomFault += n;
  /* The assert() is never reached in a human lifetime.  It  is here mostly
  ** to prevent code optimizers from optimizing out this function. */
  assert( (nOomFault>>32) < 0xffffffff );
}
#else
# define test_oom_breakpoint(X)   /* No-op for production builds */
#endif

/*
** Do a memory allocation with statistics and alarms.  Assume the
** lock is already held.
*/
static void mallocWithAlarm(int n, void **pp){
  void *p;
  int nFull;
243
244
245
246
247
248
249

250
251
252
253
254
255
256
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275







+







    sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    if( nUsed >= mem0.alarmThreshold - nFull ){
      AtomicStore(&mem0.nearlyFull, 1);
      sqlite3MallocAlarm(nFull);
      if( mem0.hardLimit ){
        nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
        if( nUsed >= mem0.hardLimit - nFull ){
          test_oom_breakpoint(1);
          *pp = 0;
          return;
        }
      }
    }else{
      AtomicStore(&mem0.nearlyFull, 0);
    }
531
532
533
534
535
536
537

538
539
540
541
542
543
544
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564







+







    sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    nDiff = nNew - nOld;
    if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >= 
          mem0.alarmThreshold-nDiff ){
      sqlite3MallocAlarm(nDiff);
      if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
        sqlite3_mutex_leave(mem0.mutex);
        test_oom_breakpoint(1);
        return 0;
      }
    }
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
    if( pNew==0 && mem0.alarmThreshold>0 ){
      sqlite3MallocAlarm((int)nBytes);
Changes to src/memdb.c.
795
796
797
798
799
800
801








802
803
804
805
806
807
808
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816







+
+
+
+
+
+
+
+







  sqlite3_free(zSql);
  if( rc ) return 0;
  rc = sqlite3_step(pStmt);
  if( rc!=SQLITE_ROW ){
    pOut = 0;
  }else{
    sz = sqlite3_column_int64(pStmt, 0)*szPage;
    if( sz==0 ){
      sqlite3_reset(pStmt);
      sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0);
      rc = sqlite3_step(pStmt);
      if( rc==SQLITE_ROW ){
        sz = sqlite3_column_int64(pStmt, 0)*szPage;
      }
    }
    if( piSize ) *piSize = sz;
    if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
      pOut = 0;
    }else{
      pOut = sqlite3_malloc64( sz );
      if( pOut ){
        int nPage = sqlite3_column_int(pStmt, 0);
Changes to src/os_unix.c.
1291
1292
1293
1294
1295
1296
1297



1298
1299


1300
1301
1302
1303
1304
1305
1306
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301

1302
1303
1304
1305
1306
1307
1308
1309
1310







+
+
+

-
+
+







  ** Otherwise, assume that the system provides the POSIX version of
  ** strerror_r(), which always writes an error message into aErr[].
  **
  ** If the code incorrectly assumes that it is the POSIX version that is
  ** available, the error message will often be an empty string. Not a
  ** huge problem. Incorrectly concluding that the GNU version is available
  ** could lead to a segfault though.
  **
  ** Forum post 3f13857fa4062301 reports that the Android SDK may use
  ** int-type return, depending on its version.
  */
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
#if (defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)) \
  && !defined(ANDROID) && !defined(__ANDROID__)
  zErr =
# endif
  strerror_r(iErrno, aErr, sizeof(aErr)-1);

#elif SQLITE_THREADSAFE
  /* This is a threadsafe build, but strerror_r() is not available. */
  zErr = "";
4050
4051
4052
4053
4054
4055
4056

4057





4058
4059
4060
4061
4062
4063
4064
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074







+

+
+
+
+
+







    case SQLITE_FCNTL_HAS_MOVED: {
      *(int*)pArg = fileHasMoved(pFile);
      return SQLITE_OK;
    }
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    case SQLITE_FCNTL_LOCK_TIMEOUT: {
      int iOld = pFile->iBusyTimeout;
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
      pFile->iBusyTimeout = *(int*)pArg;
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
      pFile->iBusyTimeout = !!(*(int*)pArg);
#else
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
#endif
      *(int*)pArg = iOld;
      return SQLITE_OK;
    }
#endif
#if SQLITE_MAX_MMAP_SIZE>0
    case SQLITE_FCNTL_MMAP_SIZE: {
      i64 newLimit = *(i64*)pArg;
4303
4304
4305
4306
4307
4308
4309



















4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322



4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356


4357
4358
4359
4360
4361
4362
4363







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













+
+
+


-
-







**
**      hShm
**      zFilename
**
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
**
** aLock[SQLITE_SHM_NLOCK]:
**   This array records the various locks held by clients on each of the
**   SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no
**   locks are held by the process on this slot. If it is set to -1, then
**   some client holds an EXCLUSIVE lock on the locking slot. If the aLock[]
**   value is set to a positive value, then it is the number of shared 
**   locks currently held on the slot.
**
** aMutex[SQLITE_SHM_NLOCK]:
**   Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex 
**   pShmMutex is used to protect the aLock[] array and the right to
**   call fcntl() on unixShmNode.hShm to obtain or release locks.
**
**   If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array
**   of mutexes - one for each locking slot. To read or write locking
**   slot aLock[iSlot], the caller must hold the corresponding mutex
**   aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a
**   lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held.
*/
struct unixShmNode {
  unixInodeInfo *pInode;     /* unixInodeInfo that owns this SHM node */
  sqlite3_mutex *pShmMutex;  /* Mutex to access this object */
  char *zFilename;           /* Name of the mmapped file */
  int hShm;                  /* Open file descriptor */
  int szRegion;              /* Size of shared-memory regions */
  u16 nRegion;               /* Size of array apRegion */
  u8 isReadonly;             /* True if read-only */
  u8 isUnlocked;             /* True if no DMS lock held */
  char **apRegion;           /* Array of mapped shared-memory regions */
  int nRef;                  /* Number of unixShm objects pointing to this */
  unixShm *pFirst;           /* All unixShm objects pointing to this */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
#endif
  int aLock[SQLITE_SHM_NLOCK];  /* # shared locks on slot, -1==excl lock */
#ifdef SQLITE_DEBUG
  u8 exclMask;               /* Mask of exclusive locks held */
  u8 sharedMask;             /* Mask of shared locks held */
  u8 nextShmId;              /* Next available unixShm.id value */
#endif
};

/*
** Structure used internally by this VFS to record the state of an
** open shared memory connection.
4402
4403
4404
4405
4406
4407
4408
4409
4410









4411
4412












4413
4414
4415
4416
4417
4418

4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429

4430
4431
4432
4433
4434
4435
4436
4437

4438
4439
4440
4441
4442
4443
4444

4445
4446
4447
4448

4449
4450
4451
4452
4453

4454
4455
4456
4457
4458
4459

4460
4461

4462
4463
4464

4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4432
4433
4434
4435
4436
4437
4438

4439
4440
4441
4442
4443
4444
4445
4446
4447
4448


4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477

4478
4479
4480
4481
4482
4483
4484
4485

4486
4487

4488

4489
4490

4491


4492

4493


4494
4495

4496


4497
4498
4499

4500
4501

4502
4503
4504

4505
4506



4507
4508
4509
4510
4511
4512
4513







-

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






+










-
+







-
+

-

-


-
+
-
-

-
+
-
-


-
+
-
-



-
+

-
+


-
+

-
-
-







  int ofst,              /* First byte of the locking range */
  int n                  /* Number of bytes to lock */
){
  unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */
  struct flock f;        /* The posix advisory locking structure */
  int rc = SQLITE_OK;    /* Result code form fcntl() */

  /* Access to the unixShmNode object is serialized by the caller */
  pShmNode = pFile->pInode->pShmNode;

  /* Assert that the parameters are within expected range and that the
  ** correct mutex or mutexes are held. */
  assert( pShmNode->nRef>=0 );
  assert( (ofst==UNIX_SHM_DMS && n==1)
       || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK))
  );
  if( ofst==UNIX_SHM_DMS ){
    assert( pShmNode->nRef>0 || unixMutexHeld() );
  assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
  assert( pShmNode->nRef>0 || unixMutexHeld() );
    assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
  }else{
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    int ii;
    for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){
      assert( sqlite3_mutex_held(pShmNode->aMutex[ii]) );
    }
#else
    assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
    assert( pShmNode->nRef>0 );
#endif
  }

  /* Shared locks never span more than one byte */
  assert( n==1 || lockType!=F_RDLCK );

  /* Locks are within range */
  assert( n>=1 && n<=SQLITE_SHM_NLOCK );
  assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );

  if( pShmNode->hShm>=0 ){
    int res;
    /* Initialize the locking parameters */
    f.l_type = lockType;
    f.l_whence = SEEK_SET;
    f.l_start = ofst;
    f.l_len = n;
    res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
    if( res==-1 ){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1
      rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
#else
      rc = SQLITE_BUSY;
#endif
    }
  }

  /* Update the global lock state and do debug tracing */
  /* Do debug tracing */
#ifdef SQLITE_DEBUG
  { u16 mask;
  OSTRACE(("SHM-LOCK "));
  mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
  if( rc==SQLITE_OK ){
    if( lockType==F_UNLCK ){
      OSTRACE(("unlock %d ok", ofst));
      OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1));
      pShmNode->exclMask &= ~mask;
      pShmNode->sharedMask &= ~mask;
    }else if( lockType==F_RDLCK ){
      OSTRACE(("read-lock %d ok", ofst));
      OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1));
      pShmNode->exclMask &= ~mask;
      pShmNode->sharedMask |= mask;
    }else{
      assert( lockType==F_WRLCK );
      OSTRACE(("write-lock %d ok", ofst));
      OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1));
      pShmNode->exclMask |= mask;
      pShmNode->sharedMask &= ~mask;
    }
  }else{
    if( lockType==F_UNLCK ){
      OSTRACE(("unlock %d failed", ofst));
      OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1));
    }else if( lockType==F_RDLCK ){
      OSTRACE(("read-lock failed"));
      OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1));
    }else{
      assert( lockType==F_WRLCK );
      OSTRACE(("write-lock %d failed", ofst));
      OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1));
    }
  }
  OSTRACE((" - afterwards %03x,%03x\n",
           pShmNode->sharedMask, pShmNode->exclMask));
  }
#endif

  return rc;      
}

/*
4499
4500
4501
4502
4503
4504
4505





4506
4507
4508
4509
4510
4511
4512
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555







+
+
+
+
+







  unixShmNode *p = pFd->pInode->pShmNode;
  assert( unixMutexHeld() );
  if( p && ALWAYS(p->nRef==0) ){
    int nShmPerMap = unixShmRegionPerMap();
    int i;
    assert( p->pInode==pFd->pInode );
    sqlite3_mutex_free(p->pShmMutex);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    for(i=0; i<SQLITE_SHM_NLOCK; i++){
      sqlite3_mutex_free(p->aMutex[i]);
    }
#endif
    for(i=0; i<p->nRegion; i+=nShmPerMap){
      if( p->hShm>=0 ){
        osMunmap(p->apRegion[i], p->szRegion);
      }else{
        sqlite3_free(p->apRegion[i]);
      }
    }
4558
4559
4560
4561
4562
4563
4564










4565



4566
4567
4568
4569
4570
4571
4572
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628







+
+
+
+
+
+
+
+
+
+

+
+
+







  if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) {
    rc = SQLITE_IOERR_LOCK;
  }else if( lock.l_type==F_UNLCK ){
    if( pShmNode->isReadonly ){
      pShmNode->isUnlocked = 1;
      rc = SQLITE_READONLY_CANTINIT;
    }else{
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
      /* Do not use a blocking lock here. If the lock cannot be obtained
      ** immediately, it means some other connection is truncating the
      ** *-shm file. And after it has done so, it will not release its
      ** lock, but only downgrade it to a shared lock. So no point in
      ** blocking here. The call below to obtain the shared DMS lock may 
      ** use a blocking lock. */
      int iSaveTimeout = pDbFd->iBusyTimeout;
      pDbFd->iBusyTimeout = 0;
#endif
      rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
      pDbFd->iBusyTimeout = iSaveTimeout;
#endif
      /* The first connection to attach must truncate the -shm file.  We
      ** truncate to 3 bytes (an arbitrary small number, less than the
      ** -shm header size) rather than 0 as a system debugging aid, to
      ** help detect if a -shm file truncation is legitimate or is the work
      ** or a rogue process. */
      if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){
        rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename);
4679
4680
4681
4682
4683
4684
4685












4686
4687
4688
4689
4690
4691
4692
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760







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







    pShmNode->pInode = pDbFd->pInode;
    if( sqlite3GlobalConfig.bCoreMutex ){
      pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
      if( pShmNode->pShmMutex==0 ){
        rc = SQLITE_NOMEM_BKPT;
        goto shm_open_err;
      }
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
      {
        int ii;
        for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
          pShmNode->aMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
          if( pShmNode->aMutex[ii]==0 ){
            rc = SQLITE_NOMEM_BKPT;
            goto shm_open_err;
          }
        }
      }
#endif
    }

    if( pInode->bProcessLock==0 ){
      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
        pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
      }
4900
4901
4902
4903
4904
4905
4906



4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926

4927
4928
4929
4930
4931
4932
4933

4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948

4949
4950
4951
4952
4953
4954
4955
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979

4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003

5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018

5019
5020
5021
5022
5023
5024
5025
5026







+
+
+


-

















+






-
+














-
+







** held by each client. Return true if it does, or false otherwise. This
** is to be used in an assert(). e.g.
**
**     assert( assertLockingArrayOk(pShmNode) );
*/
#ifdef SQLITE_DEBUG
static int assertLockingArrayOk(unixShmNode *pShmNode){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  return 1;
#else
  unixShm *pX;
  int aLock[SQLITE_SHM_NLOCK];
  assert( sqlite3_mutex_held(pShmNode->pShmMutex) );

  memset(aLock, 0, sizeof(aLock));
  for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
    int i;
    for(i=0; i<SQLITE_SHM_NLOCK; i++){
      if( pX->exclMask & (1<<i) ){
        assert( aLock[i]==0 );
        aLock[i] = -1;
      }else if( pX->sharedMask & (1<<i) ){
        assert( aLock[i]>=0 );
        aLock[i]++;
      }
    }
  }

  assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
  return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
#endif
}
#endif

/*
** Change the lock state for a shared-memory segment.
**
** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
** Note that the relationship between SHARED and EXCLUSIVE locks is a little
** different here than in posix.  In xShmLock(), one can go from unlocked
** to shared and back or from unlocked to exclusive and back.  But one may
** not go from shared to exclusive or from exclusive to shared.
*/
static int unixShmLock(
  sqlite3_file *fd,          /* Database file holding the shared memory */
  int ofst,                  /* First lock to acquire or release */
  int n,                     /* Number of locks to acquire or release */
  int flags                  /* What to do with the lock */
){
  unixFile *pDbFd = (unixFile*)fd;      /* Connection holding shared memory */
  unixShm *p;                           /* The shared memory being locked */
  unixShmNode *pShmNode;                /* The underlying file iNode */
  int rc = SQLITE_OK;                   /* Result code */
  u16 mask;                             /* Mask of locks to take or release */
  u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */
  int *aLock;

  p = pDbFd->pShm;
  if( p==0 ) return SQLITE_IOERR_SHMLOCK;
  pShmNode = p->pShmNode;
  if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
  aLock = pShmNode->aLock;
4976
4977
4978
4979
4980
4981
4982


4983
4984
4985
4986
4987
4988







4989
4990










4991
4992
4993
4994
4995






































4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
























5010
5011

5012
5013
5014
5015
5016
5017
5018

5019
5020
5021
5022
5023





5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040






















5041
5042

5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054











5055
5056
5057
5058
5059
5060
5061
5062
5063
5064





















5065
5066
5067
5068
5069
5070
5071
5047
5048
5049
5050
5051
5052
5053
5054
5055






5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074





5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112














5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136


5137







5138





5139
5140
5141
5142
5143

















5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165


5166












5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177










5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205







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


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







  ** In other words, if this is a blocking lock, none of the locks that
  ** occur later in the above list than the lock being obtained may be
  ** held.
  **
  ** It is not permitted to block on the RECOVER lock.
  */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  {
    u16 lockMask = (p->exclMask|p->sharedMask);
  assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
         (ofst!=2)                                   /* not RECOVER */
      && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
      && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
      && (ofst<3  || (p->exclMask|p->sharedMask)<(1<<ofst))
  ));
    assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
          (ofst!=2)                                   /* not RECOVER */
       && (ofst!=1 || lockMask==0 || lockMask==2)
       && (ofst!=0 || lockMask<3)
       && (ofst<3  || lockMask<(1<<ofst))
    ));
  }
#endif

  /* Check if there is any work to do. There are three cases:
  **
  **    a) An unlock operation where there are locks to unlock,
  **    b) An shared lock where the requested lock is not already held
  **    c) An exclusive lock where the requested lock is not already held
  **
  ** The SQLite core never requests an exclusive lock that it already holds.
  ** This is assert()ed below.
  */
  assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK) 
  mask = (1<<(ofst+n)) - (1<<ofst);
  assert( n>1 || mask==(1<<ofst) );
  sqlite3_mutex_enter(pShmNode->pShmMutex);
  assert( assertLockingArrayOk(pShmNode) );
  if( flags & SQLITE_SHM_UNLOCK ){
       || 0==(p->exclMask & mask) 
  );
  if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
   || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
   || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
  ){

    /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if
    ** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any
    ** other thread is holding this mutex, then it is either holding or about
    ** to hold a lock exclusive to the one being requested, and we may
    ** therefore return SQLITE_BUSY to the caller.
    **
    ** Doing this prevents some deadlock scenarios. For example, thread 1 may
    ** be a checkpointer blocked waiting on the WRITER lock. And thread 2
    ** may be a normal SQL client upgrading to a write transaction. In this
    ** case thread 2 does a non-blocking request for the WRITER lock. But -
    ** if it were to use sqlite3_mutex_enter() then it would effectively
    ** become a (doomed) blocking request, as thread 2 would block until thread
    ** 1 obtained WRITER and released the mutex. Since thread 2 already holds
    ** a lock on a read-locking slot at this point, this breaks the
    ** anti-deadlock rules (see above).  */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    int iMutex;
    for(iMutex=ofst; iMutex<ofst+n; iMutex++){
      if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){
        rc = sqlite3_mutex_try(pShmNode->aMutex[iMutex]);
        if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes;
      }else{
        sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
      }
    }
#else
    sqlite3_mutex_enter(pShmNode->pShmMutex);
#endif

    if( ALWAYS(rc==SQLITE_OK) ){
      if( flags & SQLITE_SHM_UNLOCK ){
    if( (p->exclMask|p->sharedMask) & mask ){
      int ii;
      int bUnlock = 1;

      for(ii=ofst; ii<ofst+n; ii++){
        if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
          bUnlock = 0;
        }
      }

      if( bUnlock ){
        rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
        if( rc==SQLITE_OK ){
          memset(&aLock[ofst], 0, sizeof(int)*n);
        /* Case (a) - unlock.  */
        int bUnlock = 1;
        assert( (p->exclMask & p->sharedMask)==0 );
        assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
        assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
  
        /* If this is a SHARED lock being unlocked, it is possible that other
        ** clients within this process are holding the same SHARED lock. In
        ** this case, set bUnlock to 0 so that the posix lock is not removed
        ** from the file-descriptor below.  */
        if( flags & SQLITE_SHM_SHARED ){
          assert( n==1 );
          assert( aLock[ofst]>=1 );
          if( aLock[ofst]>1 ){
            bUnlock = 0;
            aLock[ofst]--;
            p->sharedMask &= ~mask;
          }
        }
  
        if( bUnlock ){
          rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
          if( rc==SQLITE_OK ){
            memset(&aLock[ofst], 0, sizeof(int)*n);
        }
      }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
            p->sharedMask &= ~mask;
        assert( n==1 && aLock[ofst]>1 );
        aLock[ofst]--;
      }

      /* Undo the local locks */
      if( rc==SQLITE_OK ){
        p->exclMask &= ~mask;
            p->exclMask &= ~mask;
        p->sharedMask &= ~mask;
      }
    }
  }else if( flags & SQLITE_SHM_SHARED ){
    assert( n==1 );
          }
        }
      }else if( flags & SQLITE_SHM_SHARED ){
        /* Case (b) - a shared lock.  */
  
    assert( (p->exclMask & (1<<ofst))==0 );
    if( (p->sharedMask & mask)==0 ){
      if( aLock[ofst]<0 ){
        rc = SQLITE_BUSY;
      }else if( aLock[ofst]==0 ){
        rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
      }

      /* Get the local shared locks */
      if( rc==SQLITE_OK ){
        p->sharedMask |= mask;
        aLock[ofst]++;
      }
    }
  }else{
    /* Make sure no sibling connections hold locks that will block this
    ** lock.  If any do, return SQLITE_BUSY right away.  */
        if( aLock[ofst]<0 ){
          /* An exclusive lock is held by some other connection. BUSY. */ 
          rc = SQLITE_BUSY;
        }else if( aLock[ofst]==0 ){
          rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
        }
  
        /* Get the local shared locks */
        if( rc==SQLITE_OK ){
          p->sharedMask |= mask;
          aLock[ofst]++;
        }
      }else{
        /* Case (c) - an exclusive lock.  */
        int ii;
  
        assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
        assert( (p->sharedMask & mask)==0 );
        assert( (p->exclMask & mask)==0 );
  
        /* Make sure no sibling connections hold locks that will block this
        ** lock.  If any do, return SQLITE_BUSY right away.  */
    int ii;
    for(ii=ofst; ii<ofst+n; ii++){
        for(ii=ofst; ii<ofst+n; ii++){
      assert( (p->sharedMask & mask)==0 );
      if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
        rc = SQLITE_BUSY;
        break;
      }
    }

    /* Get the exclusive locks at the system level. Then if successful
    ** also update the in-memory values. */
    if( rc==SQLITE_OK ){
      rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
      if( rc==SQLITE_OK ){
          if( aLock[ii] ){
            rc = SQLITE_BUSY;
            break;
          }
        }
  
        /* Get the exclusive locks at the system level. Then if successful
        ** also update the in-memory values. */
        if( rc==SQLITE_OK ){
          rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
          if( rc==SQLITE_OK ){
        assert( (p->sharedMask & mask)==0 );
        p->exclMask |= mask;
        for(ii=ofst; ii<ofst+n; ii++){
          aLock[ii] = -1;
        }
      }
    }
  }
  assert( assertLockingArrayOk(pShmNode) );
  sqlite3_mutex_leave(pShmNode->pShmMutex);
            p->exclMask |= mask;
            for(ii=ofst; ii<ofst+n; ii++){
              aLock[ii] = -1;
            }
          }
        }
      }
      assert( assertLockingArrayOk(pShmNode) );
    }

    /* Drop the mutexes acquired above. */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  leave_shmnode_mutexes:
    for(iMutex--; iMutex>=ofst; iMutex--){
      sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
    }
#else
    sqlite3_mutex_leave(pShmNode->pShmMutex);
#endif
  }

  OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
           p->id, osGetpid(0), p->sharedMask, p->exclMask));
  return rc;
}

/*
** Implement a memory barrier or memory fence on shared memory.
5307
5308
5309
5310
5311
5312
5313





5314
5315
5316
5317
5318

5319
5320
5321
5322
5323
5324
5325
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456

5457
5458
5459
5460
5461
5462
5463
5464







+
+
+
+
+




-
+







#if SQLITE_MAX_MMAP_SIZE>0
  unixFile *pFd = (unixFile *)fd;   /* The underlying database file */
#endif
  *pp = 0;

#if SQLITE_MAX_MMAP_SIZE>0
  if( pFd->mmapSizeMax>0 ){
    /* Ensure that there is always at least a 256 byte buffer of addressable
    ** memory following the returned page. If the database is corrupt,
    ** SQLite may overread the page slightly (in practice only a few bytes,
    ** but 256 is safe, round, number).  */
    const int nEofBuffer = 256;
    if( pFd->pMapRegion==0 ){
      int rc = unixMapfile(pFd, -1);
      if( rc!=SQLITE_OK ) return rc;
    }
    if( pFd->mmapSize >= iOff+nAmt ){
    if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
      *pp = &((u8 *)pFd->pMapRegion)[iOff];
      pFd->nFetchOut++;
    }
  }
#endif
  return SQLITE_OK;
}
Changes to src/os_win.c.
4517
4518
4519
4520
4521
4522
4523





4524
4525
4526
4527
4528
4529
4530
4531
4532

4533
4534
4535
4536
4537
4538
4539
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536

4537
4538
4539
4540
4541
4542
4543
4544







+
+
+
+
+








-
+







  *pp = 0;

  OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
           osGetCurrentProcessId(), fd, iOff, nAmt, pp));

#if SQLITE_MAX_MMAP_SIZE>0
  if( pFd->mmapSizeMax>0 ){
    /* Ensure that there is always at least a 256 byte buffer of addressable
    ** memory following the returned page. If the database is corrupt,
    ** SQLite may overread the page slightly (in practice only a few bytes,
    ** but 256 is safe, round, number).  */
    const int nEofBuffer = 256;
    if( pFd->pMapRegion==0 ){
      int rc = winMapfile(pFd, -1);
      if( rc!=SQLITE_OK ){
        OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",
                 osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
        return rc;
      }
    }
    if( pFd->mmapSize >= iOff+nAmt ){
    if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
      assert( pFd->pMapRegion!=0 );
      *pp = &((u8 *)pFd->pMapRegion)[iOff];
      pFd->nFetchOut++;
    }
  }
#endif

Changes to src/pager.c.
684
685
686
687
688
689
690
691

692
693
694
695
696
697
698
684
685
686
687
688
689
690

691
692
693
694
695
696
697
698







-
+







  Pgno lckPgno;               /* Page number for the locking page */
  i64 pageSize;               /* Number of bytes in a page */
  i64 journalSizeLimit;       /* Size limit for persistent journal files */
  char *zFilename;            /* Name of the database file */
  char *zJournal;             /* Name of the journal file */
  int (*xBusyHandler)(void*); /* Function to call when busy */
  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
  int aStat[4];               /* Total cache hits, misses, writes, spills */
  u32 aStat[4];               /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
  int nRead;                  /* Database pages read */
#endif
  void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
  int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
  char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
  PCache *pPCache;            /* Pointer to page cache object */
814
815
816
817
818
819
820
821
822
823


824
825
826
827
828
829
830
814
815
816
817
818
819
820



821
822
823
824
825
826
827
828
829







-
-
-
+
+







*/
int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
  if( pPager->fd->pMethods==0 ) return 0;
  if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
#ifndef SQLITE_OMIT_WAL
  if( pPager->pWal ){
    u32 iRead = 0;
    int rc;
    rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    return (rc==SQLITE_OK && iRead==0);
    (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    return iRead==0;
  }
#endif
  return 1;
}
#endif

#ifndef SQLITE_OMIT_WAL
6828
6829
6830
6831
6832
6833
6834
6835
6836


6837
6838
6839

6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855

6856
6857
6858
6859
6860
6861
6862
6827
6828
6829
6830
6831
6832
6833


6834
6835
6836
6837

6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853

6854
6855
6856
6857
6858
6859
6860
6861







-
-
+
+


-
+















-
+







  static int a[11];
  a[0] = sqlite3PcacheRefCount(pPager->pPCache);
  a[1] = sqlite3PcachePagecount(pPager->pPCache);
  a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
  a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
  a[4] = pPager->eState;
  a[5] = pPager->errCode;
  a[6] = pPager->aStat[PAGER_STAT_HIT];
  a[7] = pPager->aStat[PAGER_STAT_MISS];
  a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff;
  a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff;
  a[8] = 0;  /* Used to be pPager->nOvfl */
  a[9] = pPager->nRead;
  a[10] = pPager->aStat[PAGER_STAT_WRITE];
  a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff;
  return a;
}
#endif

/*
** Parameter eStat must be one of SQLITE_DBSTATUS_CACHE_HIT, _MISS, _WRITE,
** or _WRITE+1.  The SQLITE_DBSTATUS_CACHE_WRITE+1 case is a translation
** of SQLITE_DBSTATUS_CACHE_SPILL.  The _SPILL case is not contiguous because
** it was added later.
**
** Before returning, *pnVal is incremented by the
** current cache hit or miss count, according to the value of eStat. If the
** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
*/
void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){

  assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
       || eStat==SQLITE_DBSTATUS_CACHE_MISS
       || eStat==SQLITE_DBSTATUS_CACHE_WRITE
       || eStat==SQLITE_DBSTATUS_CACHE_WRITE+1
  );

7788
7789
7790
7791
7792
7793
7794
7795

7796
7797
7798
7799
7800
7801
7787
7788
7789
7790
7791
7792
7793

7794
7795
7796
7797
7798
7799
7800







-
+






*/
int sqlite3PagerWalFramesize(Pager *pPager){
  assert( pPager->eState>=PAGER_READER );
  return sqlite3WalFramesize(pPager->pWal);
}
#endif

#ifdef SQLITE_USE_SEH
#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
int sqlite3PagerWalSystemErrno(Pager *pPager){
  return sqlite3WalSystemErrno(pPager->pWal);
}
#endif

#endif /* SQLITE_OMIT_DISKIO */
Changes to src/pager.h.
212
213
214
215
216
217
218
219

220
221
222
223
224
225
226
212
213
214
215
216
217
218

219
220
221
222
223
224
225
226







-
+







const char *sqlite3PagerFilename(const Pager*, int);
sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
sqlite3_file *sqlite3PagerJrnlFile(Pager*);
const char *sqlite3PagerJournalname(Pager*);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerCacheStat(Pager *, int, int, u64*);
void sqlite3PagerClearCache(Pager*);
int sqlite3SectorSize(sqlite3_file *);

/* Functions used to truncate the database file. */
void sqlite3PagerTruncateImage(Pager*,Pgno);

void sqlite3PagerRekey(DbPage*, Pgno, u16);
Changes to src/parse.y.
16
17
18
19
20
21
22




23
24
25
26
27
28
29
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







+
+
+
+







** file that specifies the input grammar and actions to take while parsing.
** That input file is processed by Lemon to generate a C-language 
** implementation of a parser for the given grammar.  You might be reading
** this comment as part of the translated C-code.  Edits should be made
** to the original parse.y sources.
*/
}

// Function used to enlarge the parser stack, if needed
%realloc parserStackRealloc
%free    sqlite3_free

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
//
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
45
46
47
48
49
50
51

52
53
54
55
56
57
58
59







-
+







  if( TOKEN.z[0] ){
    sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
  }else{
    sqlite3ErrorMsg(pParse, "incomplete input");
  }
}
%stack_overflow {
  sqlite3ErrorMsg(pParse, "parser stack overflow");
  sqlite3OomFault(pParse->db);
}

// The name of the generated procedure that implements the parser
// is as follows:
%name sqlite3Parser

// The following text is included near the beginning of the C source
543
544
545
546
547
548
549








550
551
552
553
554
555

556
557
558
559
560
561
562
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







+
+
+
+
+
+
+
+






+







      pSelect->pWith = pWith;
      parserDoubleLinkSelect(pParse, pSelect);
    }else{
      sqlite3WithDelete(pParse->db, pWith);
    }
    return pSelect;
  }

  /* Memory allocator for parser stack resizing.  This is a thin wrapper around
  ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate
  ** testing.
  */
  static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){
    return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize);
  }
}

%ifndef SQLITE_OMIT_CTE
select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);}
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X).
                                              {A = attachWithToSelect(pParse,X,W);}

%endif /* SQLITE_OMIT_CTE */
select(A) ::= selectnowith(A). {
  Select *p = A;
  if( p ){
    parserDoubleLinkSelect(pParse, p);
  }
}
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
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







-
-
+
+

+




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







  }else{
    sqlite3WindowListDelete(pParse->db, R);
  }
}
%endif


oneselect(A) ::= values(A).

// Single row VALUES clause.
//
%type values {Select*}
oneselect(A) ::= values(A).
%destructor values {sqlite3SelectDelete(pParse->db, $$);}
values(A) ::= VALUES LP nexprlist(X) RP. {
  A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0);
}

// Multiple row VALUES clause.
//
%type mvalues {Select*}
oneselect(A) ::= mvalues(A). {
  sqlite3MultiValuesEnd(pParse, A);
}
%destructor mvalues {sqlite3SelectDelete(pParse->db, $$);}
values(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
mvalues(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
  Select *pRight, *pLeft = A;
  pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0);
  if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
  A = sqlite3MultiValues(pParse, A, Y);
  if( pRight ){
    pRight->op = TK_ALL;
    pRight->pPrior = pLeft;
    A = pRight;
  }else{
    A = pLeft;
  }
}
mvalues(A) ::= mvalues(A) COMMA LP nexprlist(Y) RP. {
  A = sqlite3MultiValues(pParse, A, Y);
}

// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
// present and false (0) if it is not.
//
%type distinct {int}
distinct(A) ::= DISTINCT.   {A = SF_Distinct;}
1305
1306
1307
1308
1309
1310
1311
1312

1313
1314
1315
1316
1317
1318
1319
1321
1322
1323
1324
1325
1326
1327

1328
1329
1330
1331
1332
1333
1334
1335







-
+







      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, A);
      A = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false");
      if( A ) sqlite3ExprIdToTrueFalse(A);
    }else{
      Expr *pRHS = Y->a[0].pExpr;
      if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){
      if( Y->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && A->op!=TK_VECTOR ){
        Y->a[0].pExpr = 0;
        sqlite3ExprListDelete(pParse->db, Y);
        pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
        A = sqlite3PExpr(pParse, TK_EQ, A, pRHS);
      }else if( Y->nExpr==1 && pRHS->op==TK_SELECT ){
        A = sqlite3PExpr(pParse, TK_IN, A, 0);
        sqlite3PExprAddSelect(pParse, A, pRHS->x.pSelect);
1745
1746
1747
1748
1749
1750
1751
1752

1753
1754

1755
1756
1757
1758
1759
1760
1761
1761
1762
1763
1764
1765
1766
1767

1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778







-
+


+







with ::= WITH wqlist(W).              { sqlite3WithPush(pParse, W, 1); }
with ::= WITH RECURSIVE wqlist(W).    { sqlite3WithPush(pParse, W, 1); }

%type wqas {u8}
wqas(A)   ::= AS.                  {A = M10d_Any;}
wqas(A)   ::= AS MATERIALIZED.     {A = M10d_Yes;}
wqas(A)   ::= AS NOT MATERIALIZED. {A = M10d_No;}
wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. {
wqitem(A) ::= withnm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. {
  A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/
}
withnm(A) ::= nm(A). {pParse->bHasWith = 1;}
wqlist(A) ::= wqitem(X). {
  A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
}
wqlist(A) ::= wqlist(A) COMMA wqitem(X). {
  A = sqlite3WithAdd(pParse, A, X);
}
%endif  SQLITE_OMIT_CTE
1919
1920
1921
1922
1923
1924
1925






1926
1927
1928
1929
1930
1931
1932
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955







+
+
+
+
+
+







  VECTOR          /* Vector */
  SELECT_COLUMN   /* Choose a single column from a multi-column SELECT */
  IF_NULL_ROW     /* the if-null-row operator */
  ASTERISK        /* The "*" in count(*) and similar */
  SPAN            /* The span operator */
  ERROR           /* An expression containing an error */
.

term(A) ::= QNUMBER(X). {
  A=tokenExpr(pParse,@X,X);
  sqlite3DequoteNumber(pParse, A);
}

/* There must be no more than 255 tokens defined above.  If this grammar
** is extended with new rules and tokens, they must either be so few in
** number that TK_SPAN is no more than 255, or else the new tokens must
** appear after this line.
*/
%include {
#if TK_SPAN>255
Changes to src/pragma.c.
26
27
28
29
30
31
32




























33
34
35
36
37
38
39
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







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







** that includes the PragType_XXXX macro definitions and the aPragmaName[]
** object.  This ensures that the aPragmaName[] table is arranged in
** lexicographical order to facility a binary search of the pragma name.
** Do not edit pragma.h directly.  Edit and rerun the script in at
** ../tool/mkpragmatab.tcl. */
#include "pragma.h"

/*
** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands
** will be run with an analysis_limit set to the lessor of the value of
** the following macro or to the actual analysis_limit if it is non-zero,
** in order to prevent PRAGMA optimize from running for too long.
**
** The value of 2000 is chosen emperically so that the worst-case run-time
** for PRAGMA optimize does not exceed 100 milliseconds against a variety
** of test databases on a RaspberryPI-4 compiled using -Os and without
** -DSQLITE_DEBUG.  Of course, your mileage may vary.  For the purpose of
** this paragraph, "worst-case" means that ANALYZE ends up being
** run on every table in the database.  The worst case typically only
** happens if PRAGMA optimize is run on a database file for which ANALYZE
** has not been previously run and the 0x10000 flag is included so that
** all tables are analyzed.  The usual case for PRAGMA optimize is that
** no ANALYZE commands will be run at all, or if any ANALYZE happens it
** will be against a single table, so that expected timing for PRAGMA
** optimize on a PI-4 is more like 1 millisecond or less with the 0x10000
** flag or less than 100 microseconds without the 0x10000 flag.
**
** An analysis limit of 2000 is almost always sufficient for the query
** planner to fully characterize an index.  The additional accuracy from
** a larger analysis is not usually helpful.
*/
#ifndef SQLITE_DEFAULT_OPTIMIZE_LIMIT
# define SQLITE_DEFAULT_OPTIMIZE_LIMIT 2000
#endif

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or
** unrecognized string argument.  The FULL and EXTRA option is disallowed
** if the omitFull parameter it 1.
**
** Note that the values returned are one less that the values that
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1716
1717
1718
1719
1720
1721
1722

1723
1724
1725
1726
1727
1728
1729







-








    /* Do an integrity check on each database file */
    for(i=0; i<db->nDb; i++){
      HashElem *x;     /* For looping over tables in the schema */
      Hash *pTbls;     /* Set of all tables in the schema */
      int *aRoot;      /* Array of root page numbers of all btrees */
      int cnt = 0;     /* Number of entries in aRoot[] */
      int mxIdx = 0;   /* Maximum number of indexes for any table */

      if( OMIT_TEMPDB && i==1 ) continue;
      if( iDb>=0 && i!=iDb ) continue;

      sqlite3CodeVerifySchema(pParse, i);
      pParse->okConstFactor = 0;  /* tag-20230327-1 */

1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737

1738
1739
1740
1741

1742
1743
1744
1745
1746
1747
1748
1749






























1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765

1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
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







-



















-
+



-
+








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















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







      for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);  /* Current table */
        Index *pIdx;                      /* An index on pTab */
        int nIdx;                         /* Number of indexes on pTab */
        if( pObjTab && pObjTab!=pTab ) continue;
        if( HasRowid(pTab) ) cnt++;
        for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
        if( nIdx>mxIdx ) mxIdx = nIdx;
      }
      if( cnt==0 ) continue;
      if( pObjTab ) cnt++;
      aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
      if( aRoot==0 ) break;
      cnt = 0;
      if( pObjTab ) aRoot[++cnt] = 0;
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx;
        if( pObjTab && pObjTab!=pTab ) continue;
        if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          aRoot[++cnt] = pIdx->tnum;
        }
      }
      aRoot[0] = cnt;

      /* Make sure sufficient number of registers have been allocated */
      sqlite3TouchRegister(pParse, 8+mxIdx);
      sqlite3TouchRegister(pParse, 8+cnt);
      sqlite3ClearTempRegCache(pParse);

      /* Do the b-tree integrity checks */
      sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
      sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
      sqlite3VdbeChangeP5(v, (u8)i);
      addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
      sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
         P4_DYNAMIC);
      sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
      integrityCheckResultRow(v);
      sqlite3VdbeJumpHere(v, addr);

      /* Check that the indexes all have the right number of rows */
      cnt = pObjTab ? 1 : 0;
      sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        int iTab = 0;
        Table *pTab = sqliteHashData(x);
        Index *pIdx;
        if( pObjTab && pObjTab!=pTab ) continue;
        if( HasRowid(pTab) ){
          iTab = cnt++;
        }else{
          iTab = cnt;
          for(pIdx=pTab->pIndex; ALWAYS(pIdx); pIdx=pIdx->pNext){
            if( IsPrimaryKeyIndex(pIdx) ) break;
            iTab++;
          }
        }
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          if( pIdx->pPartIdxWhere==0 ){
            addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab);
            VdbeCoverageNeverNull(v);
            sqlite3VdbeLoadString(v, 4, pIdx->zName);
            sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
            integrityCheckResultRow(v);
            sqlite3VdbeJumpHere(v, addr);
          }
          cnt++;
        }
      }

      /* Make sure all the indices are constructed correctly.
      */
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx, *pPk;
        Index *pPrior = 0;      /* Previous index */
        int loopTop;
        int iDataCur, iIdxCur;
        int r1 = -1;
        int bStrict;            /* True for a STRICT table */
        int r2;                 /* Previous key for WITHOUT ROWID tables */
        int mxCol;              /* Maximum non-virtual column number */

        if( pObjTab && pObjTab!=pTab ) continue;
        if( !IsOrdinaryTable(pTab) ){
        if( !IsOrdinaryTable(pTab) ) continue;
#ifndef SQLITE_OMIT_VIRTUALTABLE
          sqlite3_vtab *pVTab;
          int a1;
          if( !IsVirtual(pTab) ) continue;
          if( pTab->nCol<=0 ){
            const char *zMod = pTab->u.vtab.azArg[0];
            if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
          }
          sqlite3ViewGetColumnNames(pParse, pTab);
          if( pTab->u.vtab.p==0 ) continue;
          pVTab = pTab->u.vtab.p->pVtab;
          if( NEVER(pVTab==0) ) continue;
          if( NEVER(pVTab->pModule==0) ) continue;
          if( pVTab->pModule->iVersion<4 ) continue;
          if( pVTab->pModule->xIntegrity==0 ) continue;
          sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
          sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
          a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
          integrityCheckResultRow(v);
          sqlite3VdbeJumpHere(v, a1);
#endif
          continue;
        }
        if( isQuick || HasRowid(pTab) ){
          pPk = 0;
          r2 = 0;
        }else{
          pPk = sqlite3PrimaryKeyIndex(pTab);
          r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol);
          sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
1916
1917
1918
1919
1920
1921
1922

1923
1924
1925
1926
1927
1928
1929
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963







+







            }else{
              sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
              /* OP_IsType does not detect NaN values in the database file
              ** which should be treated as a NULL.  So if the header type
              ** is REAL, we have to load the actual data using OP_Column
              ** to reliably determine if the value is a NULL. */
              sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
              sqlite3ColumnDefault(v, pTab, j, 3);
              jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
              VdbeCoverage(v);
            }           
            zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
                                pCol->zCnName);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
            if( doTypeCheck ){
2089
2090
2091
2092
2093
2094
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
2123
2124
2125
2126
2127
2128
2129
2130







2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160






2161
2162
2163
2164
2165
2166




2167
2168
2169
2170
2171
2172
2173







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







            }
            sqlite3VdbeJumpHere(v, jmp4);
            sqlite3ResolvePartIdxLabel(pParse, jmp3);
          }
        }
        sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
        sqlite3VdbeJumpHere(v, loopTop-1);
        if( pPk ){
        if( !isQuick ){
          sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
          for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
            if( pPk==pIdx ) continue;
            sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
            addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
            sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
          assert( !isQuick );
          sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
        }
      }

#ifndef SQLITE_OMIT_VIRTUALTABLE
      /* Second pass to invoke the xIntegrity method on all virtual
      ** tables.
      */
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        sqlite3_vtab *pVTab;
        int a1;
        if( pObjTab && pObjTab!=pTab ) continue;
        if( IsOrdinaryTable(pTab) ) continue;
        if( !IsVirtual(pTab) ) continue;
        if( pTab->nCol<=0 ){
          const char *zMod = pTab->u.vtab.azArg[0];
          if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
        }
        sqlite3ViewGetColumnNames(pParse, pTab);
        if( pTab->u.vtab.p==0 ) continue;
        pVTab = pTab->u.vtab.p->pVtab;
        if( NEVER(pVTab==0) ) continue;
        if( NEVER(pVTab->pModule==0) ) continue;
        if( pVTab->pModule->iVersion<4 ) continue;
        if( pVTab->pModule->xIntegrity==0 ) continue;
        sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
        pTab->nTabRef++;
        sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
            sqlite3VdbeLoadString(v, 4, pIdx->zName);
            sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
            integrityCheckResultRow(v);
            sqlite3VdbeJumpHere(v, addr);
          }
          if( pPk ){
        a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
        integrityCheckResultRow(v);
        sqlite3VdbeJumpHere(v, a1);
        continue;
      }
#endif
            sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
          }
        }
      }
    }
    {
      static const int iLn = VDBE_OFFSET_LINENO(2);
      static const VdbeOpList endCode[] = {
        { OP_AddImm,      1, 0,        0},    /* 0 */
        { OP_IfNotZero,   1, 4,        0},    /* 1 */
        { OP_String8,     0, 3,        0},    /* 2 */
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378



2379
2380
2381


2382
2383
2384
2385
2386








2387
2388
2389



2390
2391
2392
2393




2394
2395

2396
2397
2398
2399
2400
2401
2402

2403








2404
2405
2406



2407

2408
2409
2410






2411
2412
2413



2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424




2425
2426
2427
2428
2429
2430
2431








2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443





2444
2445
2446






2447

2448
2449
2450
2451
2452
2453
2454
2455
2456








































2457
2458
2459
2460
2461
2462
2463
2464
2465
2466


2467
2468
2469
2470















2471
2472
2473
2474
2475
2476
2477
2423
2424
2425
2426
2427
2428
2429



2430
2431
2432
2433


2434
2435
2436




2437
2438
2439
2440
2441
2442
2443
2444
2445


2446
2447
2448
2449



2450
2451
2452
2453


2454
2455
2456
2457
2458
2459
2460

2461
2462
2463
2464
2465
2466
2467
2468
2469
2470



2471
2472
2473
2474
2475



2476
2477
2478
2479
2480
2481
2482
2483

2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524




2525
2526
2527
2528
2529
2530


2531
2532
2533
2534
2535
2536
2537
2538
2539








2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588

2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616







-
-
-
+
+
+

-
-
+
+

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

-
-
+
+
+

-
-
-
+
+
+
+
-
-
+






-
+

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

+
-
-
-
+
+
+
+
+
+


-
+
+
+











+
+
+
+







+
+
+
+
+
+
+
+








-
-
-
-
+
+
+
+
+

-
-
+
+
+
+
+
+

+

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









-
+
+




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







  **
  ** The details of optimizations performed by this pragma are expected
  ** to change and improve over time.  Applications should anticipate that
  ** this pragma will perform new optimizations in future releases.
  **
  ** The optional argument is a bitmask of optimizations to perform:
  **
  **    0x0001    Debugging mode.  Do not actually perform any optimizations
  **              but instead return one line of text for each optimization
  **              that would have been done.  Off by default.
  **    0x00001    Debugging mode.  Do not actually perform any optimizations
  **               but instead return one line of text for each optimization
  **               that would have been done.  Off by default.
  **
  **    0x0002    Run ANALYZE on tables that might benefit.  On by default.
  **              See below for additional information.
  **    0x00002    Run ANALYZE on tables that might benefit.  On by default.
  **               See below for additional information.
  **
  **    0x0004    (Not yet implemented) Record usage and performance
  **              information from the current session in the
  **              database file so that it will be available to "optimize"
  **              pragmas run by future database connections.
  **    0x00010    Run all ANALYZE operations using an analysis_limit that
  **               is the lessor of the current analysis_limit and the
  **               SQLITE_DEFAULT_OPTIMIZE_LIMIT compile-time option.
  **               The default value of SQLITE_DEFAULT_OPTIMIZE_LIMIT is
  **               currently (2024-02-19) set to 2000, which is such that
  **               the worst case run-time for PRAGMA optimize on a 100MB
  **               database will usually be less than 100 milliseconds on
  **               a RaspberryPI-4 class machine.  On by default.
  **
  **    0x0008    (Not yet implemented) Create indexes that might have
  **              been helpful to recent queries
  **    0x10000    Look at tables to see if they need to be reanalyzed
  **               due to growth or shrinkage even if they have not been
  **               queried during the current connection.  Off by default.
  **
  ** The default MASK is and always shall be 0xfffe.  0xfffe means perform all
  ** of the optimizations listed above except Debug Mode, including new
  ** optimizations that have not yet been invented.  If new optimizations are
  ** The default MASK is and always shall be 0x0fffe.  In the current
  ** implementation, the default mask only covers the 0x00002 optimization,
  ** though additional optimizations that are covered by 0x0fffe might be
  ** added in the future.  Optimizations that are off by default and must
  ** ever added that should be off by default, those off-by-default
  ** optimizations will have bitmasks of 0x10000 or larger.
  ** be explicitly requested have masks of 0x10000 or greater.
  **
  ** DETERMINATION OF WHEN TO RUN ANALYZE
  **
  ** In the current implementation, a table is analyzed if only if all of
  ** the following are true:
  **
  ** (1) MASK bit 0x02 is set.
  ** (1) MASK bit 0x00002 is set.
  **
  ** (2) The table is an ordinary table, not a virtual table or view.
  **
  ** (3) The table name does not begin with "sqlite_".
  **
  ** (4) One or more of the following is true:
  **      (4a) The 0x10000 MASK bit is set.
  **      (4b) One or more indexes on the table lacks an entry
  **           in the sqlite_stat1 table.
  ** (2) The query planner used sqlite_stat1-style statistics for one or
  **     more indexes of the table at some point during the lifetime of
  **     the current connection.
  **      (4c) The query planner used sqlite_stat1-style statistics for one
  **           or more indexes of the table at some point during the lifetime
  **           of the current connection.
  **
  ** (5) One or more of the following is true:
  ** (3) One or more indexes of the table are currently unanalyzed OR
  **     the number of rows in the table has increased by 25 times or more
  **     since the last time ANALYZE was run.
  **      (5a) One or more indexes on the table lacks an entry
  **           in the sqlite_stat1 table.  (Same as 4a)
  **      (5b) The number of rows in the table has increased or decreased by
  **           10-fold.  In other words, the current size of the table is
  **           10 times larger than the size in sqlite_stat1 or else the
  **           current size is less than 1/10th the size in sqlite_stat1.
  **
  ** The rules for when tables are analyzed are likely to change in
  ** future releases.
  ** future releases.  Future versions of SQLite might accept a string
  ** literal argument to this pragma that contains a mnemonic description
  ** of the options rather than a bitmap.
  */
  case PragTyp_OPTIMIZE: {
    int iDbLast;           /* Loop termination point for the schema loop */
    int iTabCur;           /* Cursor for a table whose size needs checking */
    HashElem *k;           /* Loop over tables of a schema */
    Schema *pSchema;       /* The current schema */
    Table *pTab;           /* A table in the schema */
    Index *pIdx;           /* An index of the table */
    LogEst szThreshold;    /* Size threshold above which reanalysis needed */
    char *zSubSql;         /* SQL statement for the OP_SqlExec opcode */
    u32 opMask;            /* Mask of operations to perform */
    int nLimit;            /* Analysis limit to use */
    int nCheck = 0;        /* Number of tables to be optimized */
    int nBtree = 0;        /* Number of btrees to scan */
    int nIndex;            /* Number of indexes on the current table */

    if( zRight ){
      opMask = (u32)sqlite3Atoi(zRight);
      if( (opMask & 0x02)==0 ) break;
    }else{
      opMask = 0xfffe;
    }
    if( (opMask & 0x10)==0 ){
      nLimit = 0;
    }else if( db->nAnalysisLimit>0
           && db->nAnalysisLimit<SQLITE_DEFAULT_OPTIMIZE_LIMIT ){
      nLimit = 0;
    }else{
      nLimit = SQLITE_DEFAULT_OPTIMIZE_LIMIT;
    }
    iTabCur = pParse->nTab++;
    for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
      if( iDb==1 ) continue;
      sqlite3CodeVerifySchema(pParse, iDb);
      pSchema = db->aDb[iDb].pSchema;
      for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
        pTab = (Table*)sqliteHashData(k);

        /* If table pTab has not been used in a way that would benefit from
        ** having analysis statistics during the current session, then skip it.
        ** This also has the effect of skipping virtual tables and views */
        if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
        /* This only works for ordinary tables */
        if( !IsOrdinaryTable(pTab) ) continue;

        /* Do not scan system tables */
        if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue;

        /* Reanalyze if the table is 25 times larger than the last analysis */
        szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
        /* Find the size of the table as last recorded in sqlite_stat1.
        ** If any index is unanalyzed, then the threshold is -1 to
        ** indicate a new, unanalyzed index
        */
        szThreshold = pTab->nRowLogEst;
        nIndex = 0;
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          nIndex++;
          if( !pIdx->hasStat1 ){
            szThreshold = 0; /* Always analyze if any index lacks statistics */
            break;
          }
        }
        if( szThreshold ){
          sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
          sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
                         sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
            szThreshold = -1; /* Always analyze if any index lacks statistics */
          }
        }

        /* If table pTab has not been used in a way that would benefit from
        ** having analysis statistics during the current session, then skip it,
        ** unless the 0x10000 MASK bit is set. */
        if( (pTab->tabFlags & TF_MaybeReanalyze)!=0 ){
          /* Check for size change if stat1 has been used for a query */
        }else if( opMask & 0x10000 ){
          /* Check for size change if 0x10000 is set */
        }else if( pTab->pIndex!=0 && szThreshold<0 ){
          /* Do analysis if unanalyzed indexes exists */
        }else{
          /* Otherwise, we can skip this table */
          continue;
        }

        nCheck++;
        if( nCheck==2 ){
          /* If ANALYZE might be invoked two or more times, hold a write
          ** transaction for efficiency */
          sqlite3BeginWriteOperation(pParse, 0, iDb);
        }
        nBtree += nIndex+1;

        /* Reanalyze if the table is 10 times larger or smaller than
        ** the last analysis.  Unconditional reanalysis if there are
        ** unanalyzed indexes. */
        sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
        if( szThreshold>=0 ){
          const LogEst iRange = 33;   /* 10x size change */
          sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur,
                         sqlite3VdbeCurrentAddr(v)+2+(opMask&1),
                         szThreshold>=iRange ? szThreshold-iRange : -1,
                         szThreshold+iRange);
          VdbeCoverage(v);
        }else{
          sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur,
                         sqlite3VdbeCurrentAddr(v)+2+(opMask&1));
          VdbeCoverage(v);
        }
        zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
                                 db->aDb[iDb].zDbSName, pTab->zName);
        if( opMask & 0x01 ){
          int r1 = sqlite3GetTempReg(pParse);
          sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
          sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
        }else{
          sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
          sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0,
                            zSubSql, P4_DYNAMIC);
        }
      }
    }
    sqlite3VdbeAddOp0(v, OP_Expire);

    /* In a schema with a large number of tables and indexes, scale back
    ** the analysis_limit to avoid excess run-time in the worst case.
    */
    if( !db->mallocFailed && nLimit>0 && nBtree>100 ){
      int iAddr, iEnd;
      VdbeOp *aOp;
      nLimit = 100*nLimit/nBtree;
      if( nLimit<100 ) nLimit = 100;
      aOp = sqlite3VdbeGetOp(v, 0);
      iEnd = sqlite3VdbeCurrentAddr(v);
      for(iAddr=0; iAddr<iEnd; iAddr++){
        if( aOp[iAddr].opcode==OP_SqlExec ) aOp[iAddr].p2 = nLimit;
      }
    }
    break;
  }

  /*
  **   PRAGMA busy_timeout
  **   PRAGMA busy_timeout = N
  **
Changes to src/prepare.c.
864
865
866
867
868
869
870

871
872
873
874
875
876
877
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878







+







  }while( (rc==SQLITE_ERROR_RETRY && (cnt++)<SQLITE_MAX_PREPARE_RETRY)
       || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
  sqlite3BtreeLeaveAll(db);
  rc = sqlite3ApiExit(db, rc);
  assert( (rc&db->errMask)==rc );
  db->busyHandler.nBusy = 0;
  sqlite3_mutex_leave(db->mutex);
  assert( rc==SQLITE_OK || (*ppStmt)==0 );
  return rc;
}


/*
** Rerun the compilation of a statement after a schema change.
**
Changes to src/printf.c.
494
495
496
497
498
499
500

501
502
503
504
505
506
507
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508







+







        if( precision>SQLITE_FP_PRECISION_LIMIT ){
          precision = SQLITE_FP_PRECISION_LIMIT;
        }
#endif
        if( xtype==etFLOAT ){
          iRound = -precision;
        }else if( xtype==etGENERIC ){
          if( precision==0 ) precision = 1;
          iRound = precision;
        }else{
          iRound = precision+1;
        }
        sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16);
        if( s.isSpecial ){
          if( s.isSpecial==2 ){
529
530
531
532
533
534
535
536
537
538
539
540
541
542


543
544
545
546
547
548
549
530
531
532
533
534
535
536

537
538
539
540
541
542
543
544
545
546
547
548
549
550
551







-






+
+







        if( s.sign=='-' ){
          prefix = '-';
        }else{
          prefix = flag_prefix;
        }

        exp = s.iDP-1;
        if( xtype==etGENERIC && precision>0 ) precision--;

        /*
        ** If the field type is etGENERIC, then convert to either etEXP
        ** or etFLOAT, as appropriate.
        */
        if( xtype==etGENERIC ){
          assert( precision>0 );
          precision--;
          flag_rtz = !flag_alternateform;
          if( exp<-4 || exp>precision ){
            xtype = etEXP;
          }else{
            precision = precision - exp;
            xtype = etFLOAT;
          }
854
855
856
857
858
859
860




861
862
863
864
865
866
867
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873







+
+
+
+







        }else if( pItem->zAlias ){
          sqlite3_str_appendall(pAccum, pItem->zAlias);
        }else{
          Select *pSel = pItem->pSelect;
          assert( pSel!=0 );
          if( pSel->selFlags & SF_NestedFrom ){
            sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
          }else if( pSel->selFlags & SF_MultiValue ){
            assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
            sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
                                pItem->u1.nRow);
          }else{
            sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
          }
        }
        length = width = 0;
        break;
      }
1365
1366
1367
1368
1369
1370
1371
1372

1373
1374
1375
1376
1377
1378
1379
1371
1372
1373
1374
1375
1376
1377

1378
1379
1380
1381
1382
1383
1384
1385







-
+







  va_start(ap,zFormat);
  sqlite3_str_vappendf(p, zFormat, ap);
  va_end(ap);
}


/*****************************************************************************
** Reference counted string storage
** Reference counted string/blob storage
*****************************************************************************/

/*
** Increase the reference count of the string by one.
**
** The input parameter is returned.
*/
Changes to src/resolve.c.
75
76
77
78
79
80
81


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







+
+







  Expr *pOrig;           /* The iCol-th column of the result set */
  Expr *pDup;            /* Copy of pOrig */
  sqlite3 *db;           /* The database connection */

  assert( iCol>=0 && iCol<pEList->nExpr );
  pOrig = pEList->a[iCol].pExpr;
  assert( pOrig!=0 );
  assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
  if( pExpr->pAggInfo ) return;
  db = pParse->db;
  pDup = sqlite3ExprDup(db, pOrig, 0);
  if( db->mallocFailed ){
    sqlite3ExprDelete(db, pDup);
    pDup = 0;
  }else{
    Expr temp;
178
179
180
181
182
183
184

185
186
187
188
189
190
191
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194







+







  int n;
  Table *pExTab;

  n = pExpr->iColumn;
  assert( ExprUseYTab(pExpr) );
  pExTab = pExpr->y.pTab;
  assert( pExTab!=0 );
  assert( n < pExTab->nCol );
  if( (pExTab->tabFlags & TF_HasGenerated)!=0
   && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
  ){
    testcase( pExTab->nCol==BMS-1 );
    testcase( pExTab->nCol==BMS );
    return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
  }else{
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
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







-
+
















+







** If the name cannot be resolved unambiguously, leave an error message
** in pParse and return WRC_Abort.  Return WRC_Prune on success.
*/
static int lookupName(
  Parse *pParse,       /* The parsing context */
  const char *zDb,     /* Name of the database containing table, or NULL */
  const char *zTab,    /* Name of table containing column, or NULL */
  const char *zCol,    /* Name of the column. */
  const Expr *pRight,  /* Name of the column. */
  NameContext *pNC,    /* The name context used to resolve the name */
  Expr *pExpr          /* Make this EXPR node point to the selected column */
){
  int i, j;                         /* Loop counters */
  int cnt = 0;                      /* Number of matching column names */
  int cntTab = 0;                   /* Number of potential "rowid" matches */
  int nSubquery = 0;                /* How many levels of subquery */
  sqlite3 *db = pParse->db;         /* The database connection */
  SrcItem *pItem;                   /* Use for looping over pSrcList items */
  SrcItem *pMatch = 0;              /* The matching pSrcList item */
  NameContext *pTopNC = pNC;        /* First namecontext in the list */
  Schema *pSchema = 0;              /* Schema of the expression */
  int eNewExprOp = TK_COLUMN;       /* New value for pExpr->op on success */
  Table *pTab = 0;                  /* Table holding the row */
  Column *pCol;                     /* A column of pTab */
  ExprList *pFJMatch = 0;           /* Matches for FULL JOIN .. USING */
  const char *zCol = pRight->u.zToken;

  assert( pNC );     /* the name context cannot be NULL. */
  assert( zCol );    /* The Z in X.Y.Z cannot be NULL */
  assert( zDb==0 || zTab!=0 );
  assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );

  /* Initialize the node to no-match */
748
749
750
751
752
753
754




755
756
757
758
759
760

761
762
763
764
765
766
767
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







+
+
+
+






+







      }
    }
    zErr = cnt==0 ? "no such column" : "ambiguous column name";
    if( zDb ){
      sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
    }else if( zTab ){
      sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol);
    }else if( cnt==0 && ExprHasProperty(pRight,EP_DblQuoted) ){
      sqlite3ErrorMsg(pParse, "%s: \"%s\" - should this be a"
                              " string literal in single-quotes?",
                              zErr, zCol);
    }else{
      sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
    }
    sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
    pParse->checkSchema = 1;
    pTopNC->nNcErr++;
    eNewExprOp = TK_NULL;
  }
  assert( pFJMatch==0 );

  /* Remove all substructure from pExpr */
  if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
    sqlite3ExprDelete(db, pExpr->pLeft);
    pExpr->pLeft = 0;
780
781
782
783
784
785
786
787

788
789
790
791
792
793
794
789
790
791
792
793
794
795

796
797
798
799
800
801
802
803







-
+







  ** if the mask contains extra set bits.  However, it is important to
  ** avoid setting bits beyond the maximum column number of the table.
  ** (See ticket [b92e5e8ec2cdbaa1]).
  **
  ** If a generated column is referenced, set bits for every column
  ** of the table.
  */
  if( pExpr->iColumn>=0 && pMatch!=0 ){
  if( pExpr->iColumn>=0 && cnt==1 && pMatch!=0 ){
    pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
  }

  pExpr->op = eNewExprOp;
lookupname_end:
  if( cnt==1 ){
    assert( pNC!=0 );
958
959
960
961
962
963
964













965
966
967
968
969
970
971
972
973
974

975
976
977
978
979
980
























981
982
983
984
985
986





987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010

1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036

1037
1038
1039
1040
1041
1042
1043
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997






998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021






1022
1023
1024
1025
1026

1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039

1040
1041
1042
1043
1044
1045
1046
1047

1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066

1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
1080







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










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













-








-
+


















-






-
+







    ** "NOT NULL strength reduction optimization".
    **
    ** If this optimization occurs, also restore the NameContext ref-counts
    ** to the state they where in before the "column" LHS expression was
    ** resolved.  This prevents "column" from being counted as having been
    ** referenced, which might prevent a SELECT from being erroneously
    ** marked as correlated.
    **
    ** 2024-03-28: Beware of aggregates.  A bare column of aggregated table
    ** can still evaluate to NULL even though it is marked as NOT NULL.
    ** Example:
    **
    **       CREATE TABLE t1(a INT NOT NULL);
    **       SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1;
    **
    ** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized
    ** here because at the time this case is hit, we do not yet know whether
    ** or not t1 is being aggregated.  We have to assume the worst and omit
    ** the optimization.  The only time it is safe to apply this optimization
    ** is within the WHERE clause.
    */
    case TK_NOTNULL:
    case TK_ISNULL: {
      int anRef[8];
      NameContext *p;
      int i;
      for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
        anRef[i] = p->nRef;
      }
      sqlite3WalkExpr(pWalker, pExpr->pLeft);
      if( IN_RENAME_OBJECT ) return WRC_Prune;
      if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
        testcase( ExprHasProperty(pExpr, EP_OuterON) );
        assert( !ExprHasProperty(pExpr, EP_IntValue) );
        pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
        pExpr->flags |= EP_IntValue;
        pExpr->op = TK_INTEGER;
      if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
        /* The expression can be NULL.  So the optimization does not apply */
        return WRC_Prune;
      }

      for(i=0, p=pNC; p; p=p->pNext, i++){
        if( (p->ncFlags & NC_Where)==0 ){
          return WRC_Prune;  /* Not in a WHERE clause.  Unsafe to optimize. */
        }
      }
      testcase( ExprHasProperty(pExpr, EP_OuterON) );
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
#if TREETRACE_ENABLED
      if( sqlite3TreeTrace & 0x80000 ){
        sqlite3DebugPrintf(
           "NOT NULL strength reduction converts the following to %d:\n",
           pExpr->op==TK_NOTNULL
        );
        sqlite3ShowExpr(pExpr);
      }
#endif /* TREETRACE_ENABLED */
      pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
      pExpr->flags |= EP_IntValue;
      pExpr->op = TK_INTEGER;

        for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
          p->nRef = anRef[i];
        }
        sqlite3ExprDelete(pParse->db, pExpr->pLeft);
        pExpr->pLeft = 0;
      for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
        p->nRef = anRef[i];
      }
      sqlite3ExprDelete(pParse->db, pExpr->pLeft);
      pExpr->pLeft = 0;
      }
      return WRC_Prune;
    }

    /* A column name:                    ID
    ** Or table name and column name:    ID.ID
    ** Or a database, table and column:  ID.ID.ID
    **
    ** The TK_ID and TK_OUT cases are combined so that there will only
    ** be one call to lookupName().  Then the compiler will in-line
    ** lookupName() for a size reduction and performance increase.
    */
    case TK_ID:
    case TK_DOT: {
      const char *zColumn;
      const char *zTable;
      const char *zDb;
      Expr *pRight;

      if( pExpr->op==TK_ID ){
        zDb = 0;
        zTable = 0;
        assert( !ExprHasProperty(pExpr, EP_IntValue) );
        zColumn = pExpr->u.zToken;
        pRight = pExpr;
      }else{
        Expr *pLeft = pExpr->pLeft;
        testcase( pNC->ncFlags & NC_IdxExpr );
        testcase( pNC->ncFlags & NC_GenCol );
        sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator",
                               NC_IdxExpr|NC_GenCol, 0, pExpr);
        pRight = pExpr->pRight;
        if( pRight->op==TK_ID ){
          zDb = 0;
        }else{
          assert( pRight->op==TK_DOT );
          assert( !ExprHasProperty(pRight, EP_IntValue) );
          zDb = pLeft->u.zToken;
          pLeft = pRight->pLeft;
          pRight = pRight->pRight;
        }
        assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) );
        zTable = pLeft->u.zToken;
        zColumn = pRight->u.zToken;
        assert( ExprUseYTab(pExpr) );
        if( IN_RENAME_OBJECT ){
          sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
          sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft);
        }
      }
      return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
      return lookupName(pParse, zDb, zTable, pRight, pNC, pExpr);
    }

    /* Resolve function names
    */
    case TK_FUNCTION: {
      ExprList *pList = pExpr->x.pList;    /* The argument list */
      int n = pList ? pList->nExpr : 0;    /* Number of arguments */
1245
1246
1247
1248
1249
1250
1251
1252

1253
1254
1255
1256

1257
1258
1259
1260
1261
1262
1263
1282
1283
1284
1285
1286
1287
1288

1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301







-
+




+







            sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
          }
#endif
          pNC2 = pNC;
          while( pNC2
              && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
          ){
            pExpr->op2++;
            pExpr->op2 += (1 + pNC2->nNestedSelect);
            pNC2 = pNC2->pNext;
          }
          assert( pDef!=0 || IN_RENAME_OBJECT );
          if( pNC2 && pDef ){
            pExpr->op2 += pNC2->nNestedSelect;
            assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
            assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
            testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
            testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 );
            pNC2->ncFlags |= NC_HasAgg
              | ((pDef->funcFlags^SQLITE_FUNC_ANYORDER)
                  & (SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER));
1808
1809
1810
1811
1812
1813
1814

1815
1816
1817
1818
1819
1820
1821
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860







+







      assert( pSub->pPrior && pSub->pOrderBy==0 );
      pSub->pOrderBy = p->pOrderBy;
      p->pOrderBy = 0;
    }
 
    /* Recursively resolve names in all subqueries in the FROM clause
    */
    if( pOuterNC ) pOuterNC->nNestedSelect++;
    for(i=0; i<p->pSrc->nSrc; i++){
      SrcItem *pItem = &p->pSrc->a[i];
      if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
        int nRef = pOuterNC ? pOuterNC->nRef : 0;
        const char *zSavedContext = pParse->zAuthContext;

        if( pItem->zName ) pParse->zAuthContext = pItem->zName;
1831
1832
1833
1834
1835
1836
1837



1838
1839
1840
1841
1842
1843
1844
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886







+
+
+







        ** the refcount on all contexts between the current one and the
        ** context containing the column when it resolves a name. */
        if( pOuterNC ){
          assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef );
          pItem->fg.isCorrelated = (pOuterNC->nRef>nRef);
        }
      }
    }
    if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){
      pOuterNC->nNestedSelect--;
    }
 
    /* Set up the local name-context to pass to sqlite3ResolveExprNames() to
    ** resolve the result-set expression list.
    */
    sNC.ncFlags = NC_AllowAgg|NC_AllowWin;
    sNC.pSrcList = p->pSrc;
1875
1876
1877
1878
1879
1880
1881

1882

1883
1884
1885
1886
1887
1888
1889
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933







+

+







    if( p->pHaving ){
      if( (p->selFlags & SF_Aggregate)==0 ){
        sqlite3ErrorMsg(pParse, "HAVING clause on a non-aggregate query");
        return WRC_Abort;
      }
      if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
    }
    sNC.ncFlags |= NC_Where;
    if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
    sNC.ncFlags &= ~NC_Where;

    /* Resolve names in table-valued-function arguments */
    for(i=0; i<p->pSrc->nSrc; i++){
      SrcItem *pItem = &p->pSrc->a[i];
      if( pItem->fg.isTabFunc
       && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
      ){
Changes to src/select.c.
180
181
182
183
184
185
186



187
188
189
190
191
192
193
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196







+
+
+








/*
** Delete the given Select structure and all of its substructures.
*/
void sqlite3SelectDelete(sqlite3 *db, Select *p){
  if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){
  if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1);
}

/*
** Return a pointer to the right-most SELECT statement in a compound.
*/
static Select *findRightmost(Select *p){
  while( p->pNext ) p = p->pNext;
  return p;
1946
1947
1948
1949
1950
1951
1952
1953
1954

1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1949
1950
1951
1952
1953
1954
1955


1956



1957
1958
1959
1960
1961
1962
1963







-
-
+
-
-
-







      assert( pTab && ExprUseYTab(pExpr) && pExpr->y.pTab==pTab );
      if( pS ){
        /* The "table" is actually a sub-select or a view in the FROM clause
        ** of the SELECT statement. Return the declaration type and origin
        ** data for the result-set column of the sub-select.
        */
        if( iCol<pS->pEList->nExpr
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
         && iCol>=0
         && (!ViewCanHaveRowid || iCol>=0)
#else
         && ALWAYS(iCol>=0)
#endif
        ){
          /* If iCol is less than zero, then the expression requests the
          ** rowid of the sub-select or view. This expression is legal (see
          ** test case misc2.2.2) - it always evaluates to NULL.
          */
          NameContext sNC;
          Expr *p = pS->pEList->a[iCol].pExpr;
2315
2316
2317
2318
2319
2320
2321

2322

2323
2324
2325
2326
2327
2328
2329
2314
2315
2316
2317
2318
2319
2320
2321

2322
2323
2324
2325
2326
2327
2328
2329







+
-
+







  CollSeq *pColl;
  int i,j;
  Expr *p;
  struct ExprList_item *a;
  NameContext sNC;

  assert( pSelect!=0 );
  testcase( (pSelect->selFlags & SF_Resolved)==0 );
  assert( (pSelect->selFlags & SF_Resolved)!=0 );
  assert( (pSelect->selFlags & SF_Resolved)!=0 || IN_RENAME_OBJECT );
  assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
  assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
  if( db->mallocFailed || IN_RENAME_OBJECT ) return;
  while( pSelect->pPrior ) pSelect = pSelect->pPrior;
  a = pSelect->pEList->a;
  memset(&sNC, 0, sizeof(sNC));
  sNC.pSrcList = pSelect->pSrc;
3199
3200
3201
3202
3203
3204
3205
3206

3207
3208
3209
3210
3211
3212
3213
3214
3215
3199
3200
3201
3202
3203
3204
3205

3206


3207
3208
3209
3210
3211
3212
3213







-
+
-
-







    sqlite3KeyInfoUnref(pKeyInfo);
  }

multi_select_end:
  pDest->iSdst = dest.iSdst;
  pDest->nSdst = dest.nSdst;
  if( pDelete ){
    sqlite3ParserAddCleanup(pParse,
    sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
        (void(*)(sqlite3*,void*))sqlite3SelectDelete,
        pDelete);
  }
  return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */

/*
** Error message for when two or more terms of a compound select have different
3752
3753
3754
3755
3756
3757
3758
3759

3760
3761
3762
3763
3764
3765
3766
3767
3750
3751
3752
3753
3754
3755
3756

3757

3758
3759
3760
3761
3762
3763
3764







-
+
-







  /* Jump to the this point in order to terminate the query.
  */
  sqlite3VdbeResolveLabel(v, labelEnd);

  /* Make arrangements to free the 2nd and subsequent arms of the compound
  ** after the parse has finished */
  if( pSplit->pPrior ){
    sqlite3ParserAddCleanup(pParse,
    sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior);
       (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
  }
  pSplit->pPrior = pPrior;
  pPrior->pNext = pSplit;
  sqlite3ExprListDelete(db, pPrior->pOrderBy);
  pPrior->pOrderBy = 0;

  /*** TBD:  Insert subroutine calls to close cursors on incomplete
4574
4575
4576
4577
4578
4579
4580
4581

4582
4583
4584
4585
4586
4587
4588
4589
4590
4571
4572
4573
4574
4575
4576
4577

4578


4579
4580
4581
4582
4583
4584
4585







-
+
-
-







  **
  ** pSubitem->pTab is always non-NULL by test restrictions and tests above.
  */
  if( ALWAYS(pSubitem->pTab!=0) ){
    Table *pTabToDel = pSubitem->pTab;
    if( pTabToDel->nTabRef==1 ){
      Parse *pToplevel = sqlite3ParseToplevel(pParse);
      sqlite3ParserAddCleanup(pToplevel,
      sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
         (void(*)(sqlite3*,void*))sqlite3DeleteTable,
         pTabToDel);
      testcase( pToplevel->earlyCleanup );
    }else{
      pTabToDel->nTabRef--;
    }
    pSubitem->pTab = 0;
  }

4773
4774
4775
4776
4777
4778
4779
4780

4781
4782
4783
4784
4785
4786
4787
4768
4769
4770
4771
4772
4773
4774

4775
4776
4777
4778
4779
4780
4781
4782







-
+







  WhereConst *pConst,  /* The WhereConst into which we are inserting */
  Expr *pColumn,       /* The COLUMN part of the constraint */
  Expr *pValue,        /* The VALUE part of the constraint */
  Expr *pExpr          /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */
){
  int i;
  assert( pColumn->op==TK_COLUMN );
  assert( sqlite3ExprIsConstant(pValue) );
  assert( sqlite3ExprIsConstant(pConst->pParse, pValue) );

  if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
  if( sqlite3ExprAffinity(pValue)!=0 ) return;
  if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){
    return;
  }

4831
4832
4833
4834
4835
4836
4837
4838

4839
4840
4841

4842
4843
4844
4845
4846
4847
4848
4826
4827
4828
4829
4830
4831
4832

4833
4834
4835

4836
4837
4838
4839
4840
4841
4842
4843







-
+


-
+







    return;
  }
  if( pExpr->op!=TK_EQ ) return;
  pRight = pExpr->pRight;
  pLeft = pExpr->pLeft;
  assert( pRight!=0 );
  assert( pLeft!=0 );
  if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){
  if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pLeft) ){
    constInsert(pConst,pRight,pLeft,pExpr);
  }
  if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){
  if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pRight) ){
    constInsert(pConst,pLeft,pRight,pExpr);
  }
}

/*
** This is a helper function for Walker callback propagateConstantExprRewrite().
**
5623
5624
5625
5626
5627
5628
5629
5630

5631
5632
5633
5634
5635
5636
5637
5638
5618
5619
5620
5621
5622
5623
5624

5625

5626
5627
5628
5629
5630
5631
5632







-
+
-







**
** If bFree is true, do not continue to use the pWith pointer after
** calling this routine,  Instead, use only the return value.
*/
With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
  if( pWith ){
    if( bFree ){
      pWith = (With*)sqlite3ParserAddCleanup(pParse,
      pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric,
                      (void(*)(sqlite3*,void*))sqlite3WithDelete,
                      pWith);
      if( pWith==0 ) return 0;
    }
    if( pParse->nErr==0 ){
      assert( pParse->pWith!=pWith );
      pWith->pOuter = pParse->pWith;
      pParse->pWith = pWith;
5872
5873
5874
5875
5876
5877
5878
5879


5880
5881
5882
5883
5884
5885
5886
5866
5867
5868
5869
5870
5871
5872

5873
5874
5875
5876
5877
5878
5879
5880
5881







-
+
+







  sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
  pTab->iPKey = -1;
  pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
  /* The usual case - do not allow ROWID on a subquery */
  pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
#else
  pTab->tabFlags |= TF_Ephemeral;  /* Legacy compatibility mode */
  /* Legacy compatibility mode */
  pTab->tabFlags |= TF_Ephemeral | sqlite3Config.mNoVisibleRowid;
#endif
  return pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
}


/*
** Check the N SrcItem objects to the right of pBase.  (N might be zero!)
6140
6141
6142
6143
6144
6145
6146
6147

6148
6149
6150
6151
6152
6153
6154
6135
6136
6137
6138
6139
6140
6141

6142
6143
6144
6145
6146
6147
6148
6149







-
+







          if( db->mallocFailed ) break;
          assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
          if( pFrom->fg.isNestedFrom ){
            assert( pFrom->pSelect!=0 );
            pNestedFrom = pFrom->pSelect->pEList;
            assert( pNestedFrom!=0 );
            assert( pNestedFrom->nExpr==pTab->nCol );
            assert( VisibleRowid(pTab)==0 );
            assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
          }else{
            if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
              continue;
            }
            pNestedFrom = 0;
            iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
            zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
6172
6173
6174
6175
6176
6177
6178
6179







6180
6181
6182
6183
6184
6185
6186
6167
6168
6169
6170
6171
6172
6173

6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187







-
+
+
+
+
+
+
+







                pX->fg.bUsingTerm = 1;
              }
            }
          }else{
            pUsing = 0;
          }

          nAdd = pTab->nCol + (VisibleRowid(pTab) && (selFlags&SF_NestedFrom));
          nAdd = pTab->nCol;
          if( VisibleRowid(pTab)
           && !ViewCanHaveRowid
           && (selFlags & SF_NestedFrom)!=0
          ){
            nAdd++;
          }
          for(j=0; j<nAdd; j++){
            const char *zName; 
            struct ExprList_item *pX; /* Newly added ExprList term */

            if( j==pTab->nCol ){
              zName = sqlite3RowidAlias(pTab);
              if( zName==0 ) continue;
6442
6443
6444
6445
6446
6447
6448


6449
6450
6451
6452
6453
6454
6455
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458







+
+








#if TREETRACE_ENABLED
/*
** Display all information about an AggInfo object
*/
static void printAggInfo(AggInfo *pAggInfo){
  int ii;
  sqlite3DebugPrintf("AggInfo %d/%p:\n",
     pAggInfo->selId, pAggInfo);
  for(ii=0; ii<pAggInfo->nColumn; ii++){
    struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
    sqlite3DebugPrintf(
       "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d"
       " iSorterColumn=%d %s\n",
       ii, pCol->pTab ? pCol->pTab->zName : "NULL",
       pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii,
6657
6658
6659
6660
6661
6662
6663

6664
6665
6666
6667
6668
6669
6670
6671
6672



6673
6674
6675
6676
6677
6678
6679
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







+









+
+
+







    if( pFunc->iOBTab>=0 ){
      ExprList *pOBList;
      KeyInfo *pKeyInfo;
      int nExtra = 0;
      assert( pFunc->pFExpr->pLeft!=0 );
      assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
      assert( ExprUseXList(pFunc->pFExpr->pLeft) );
      assert( pFunc->pFunc!=0 );
      pOBList = pFunc->pFExpr->pLeft->x.pList;
      if( !pFunc->bOBUnique ){
        nExtra++;  /* One extra column for the OP_Sequence */
      }
      if( pFunc->bOBPayload ){
        /* extra columns for the function arguments */
        assert( ExprUseXList(pFunc->pFExpr) );
        nExtra += pFunc->pFExpr->x.pList->nExpr;
      }
      if( pFunc->bUseSubtype ){
        nExtra += pFunc->pFExpr->x.pList->nExpr;
      }
      pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
      if( !pFunc->bOBUnique && pParse->nErr==0 ){
        pKeyInfo->nKeyField++;
      }
      sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
            pFunc->iOBTab, pOBList->nExpr+nExtra, 0,
            (char*)pKeyInfo, P4_KEYINFO);
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
6723
6724









6725
6726
6727
6728
6729
6730
6731
6699
6700
6701
6702
6703
6704
6705



6706
6707
6708
6709
6710
6711
6712
6713
6714

6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748







-
-
-
+
+
+






-
+
+
















+
+
+
+
+
+
+
+
+







  int i;
  struct AggInfo_func *pF;
  for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
    ExprList *pList;
    assert( ExprUseXList(pF->pFExpr) );
    pList = pF->pFExpr->x.pList;
    if( pF->iOBTab>=0 ){
      /* For an ORDER BY aggregate, calls to OP_AggStep where deferred and
      ** all content was stored in emphermal table pF->iOBTab.  Extract that
      ** content now (in ORDER BY order) and make all calls to OP_AggStep
      /* For an ORDER BY aggregate, calls to OP_AggStep were deferred.  Inputs
      ** were stored in emphermal table pF->iOBTab.  Here, we extract those
      ** inputs (in ORDER BY order) and make all calls to OP_AggStep
      ** before doing the OP_AggFinal call. */
      int iTop;        /* Start of loop for extracting columns */
      int nArg;        /* Number of columns to extract */
      int nKey;        /* Key columns to be skipped */
      int regAgg;      /* Extract into this array */
      int j;           /* Loop counter */
      
     
      assert( pF->pFunc!=0 );
      nArg = pList->nExpr;
      regAgg = sqlite3GetTempRange(pParse, nArg);

      if( pF->bOBPayload==0 ){
        nKey = 0;
      }else{
        assert( pF->pFExpr->pLeft!=0 );
        assert( ExprUseXList(pF->pFExpr->pLeft) );
        assert( pF->pFExpr->pLeft->x.pList!=0 );
        nKey = pF->pFExpr->pLeft->x.pList->nExpr;
        if( ALWAYS(!pF->bOBUnique) ) nKey++;
      }
      iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v);
      for(j=nArg-1; j>=0; j--){
        sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
      }
      if( pF->bUseSubtype ){
        int regSubtype = sqlite3GetTempReg(pParse);
        int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0);
        for(j=nArg-1; j>=0; j--){
          sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype);
          sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j);
        }
        sqlite3ReleaseTempReg(pParse, regSubtype);
      }
      sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
      sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
      sqlite3VdbeChangeP5(v, (u8)nArg);
      sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v);
      sqlite3VdbeJumpHere(v, iTop);
      sqlite3ReleaseTempRange(pParse, regAgg, nArg);
    }
6772
6773
6774
6775
6776
6777
6778

6779
6780
6781
6782
6783
6784
6785
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803







+







    int addrNext = 0;
    int regAgg;
    int regAggSz = 0;
    int regDistinct = 0;
    ExprList *pList;
    assert( ExprUseXList(pF->pFExpr) );
    assert( !IsWindowFunc(pF->pFExpr) );
    assert( pF->pFunc!=0 );
    pList = pF->pFExpr->x.pList;
    if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
      Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
      if( pAggInfo->nAccumulator
       && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
       && regAcc
      ){
6815
6816
6817
6818
6819
6820
6821



6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834








6835
6836
6837
6838
6839
6840
6841
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870







+
+
+













+
+
+
+
+
+
+
+







      assert( pOBList->nExpr>0 );
      regAggSz = pOBList->nExpr;
      if( !pF->bOBUnique ){
        regAggSz++;   /* One register for OP_Sequence */
      }
      if( pF->bOBPayload ){
        regAggSz += nArg;
      }
      if( pF->bUseSubtype ){
        regAggSz += nArg;
      }
      regAggSz++;  /* One extra register to hold result of MakeRecord */
      regAgg = sqlite3GetTempRange(pParse, regAggSz);
      regDistinct = regAgg;
      sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP);
      jj = pOBList->nExpr;
      if( !pF->bOBUnique ){
        sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj);
        jj++;
      }
      if( pF->bOBPayload ){
        regDistinct = regAgg+jj;
        sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
        jj += nArg;
      }
      if( pF->bUseSubtype ){
        int kk;
        int regBase = pF->bOBPayload ? regDistinct : regAgg;
        for(kk=0; kk<nArg; kk++, jj++){
          sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj);
        }
      }
    }else if( pList ){
      nArg = pList->nExpr;
      regAgg = sqlite3GetTempRange(pParse, nArg);
      regDistinct = regAgg;
      sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
    }else{
7032
7033
7034
7035
7036
7037
7038
7039


7040
7041
7042
7043
7044
7045
7046
7061
7062
7063
7064
7065
7066
7067

7068
7069
7070
7071
7072
7073
7074
7075
7076







-
+
+







  }
  return 0;
}

/*
** Deallocate a single AggInfo object
*/
static void agginfoFree(sqlite3 *db, AggInfo *p){
static void agginfoFree(sqlite3 *db, void *pArg){
  AggInfo *p = (AggInfo*)pArg;
  sqlite3DbFree(db, p->aCol);
  sqlite3DbFree(db, p->aFunc);
  sqlite3DbFreeNN(db, p);
}

/*
** Attempt to transform a query of the form
7106
7107
7108
7109
7110
7111
7112
7113

7114
7115
7116
7117
7118
7119
7120
7136
7137
7138
7139
7140
7141
7142

7143
7144
7145
7146
7147
7148
7149
7150







-
+







    Expr *pTerm;
    pPrior = pSub->pPrior;
    pSub->pPrior = 0;
    pSub->pNext = 0;
    pSub->selFlags |= SF_Aggregate;
    pSub->selFlags &= ~SF_Compound;
    pSub->nSelectRow = 0;
    sqlite3ExprListDelete(db, pSub->pEList);
    sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList);
    pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
    pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
    pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    sqlite3PExprAddSelect(pParse, pTerm, pSub);
    if( pExpr==0 ){
      pExpr = pTerm;
    }else{
7286
7287
7288
7289
7290
7291
7292
7293

7294
7295

7296
7297
7298
7299
7300
7301
7302
7316
7317
7318
7319
7320
7321
7322

7323


7324
7325
7326
7327
7328
7329
7330
7331







-
+
-
-
+







    if( p->pOrderBy ){
#if TREETRACE_ENABLED
      TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n"));
      if( sqlite3TreeTrace & 0x800 ){
        sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
      }
#endif   
      sqlite3ParserAddCleanup(pParse,
      sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
        (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
        p->pOrderBy);
                              p->pOrderBy);
      testcase( pParse->earlyCleanup );
      p->pOrderBy = 0;
    }
    p->selFlags &= ~SF_Distinct;
    p->selFlags |= SF_NoopOrderBy;
  }
  sqlite3SelectPrep(pParse, p, 0);
7480
7481
7482
7483
7484
7485
7486
7487

7488
7489

7490
7491
7492
7493
7494
7495
7496
7509
7510
7511
7512
7513
7514
7515

7516


7517
7518
7519
7520
7521
7522
7523
7524







-
+
-
-
+







     && pSub->pLimit==0                           /* Condition (1) */
     && (pSub->selFlags & SF_OrderByReqd)==0      /* Condition (2) */
     && (p->selFlags & SF_OrderByReqd)==0         /* Condition (3) and (4) */
     && OptimizationEnabled(db, SQLITE_OmitOrderBy)
    ){
      TREETRACE(0x800,pParse,p,
                ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
      sqlite3ParserAddCleanup(pParse,
      sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
         (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
         pSub->pOrderBy);
                              pSub->pOrderBy);
      pSub->pOrderBy = 0;
    }

    /* If the outer query contains a "complex" result set (that is,
    ** if the result set of the outer query uses functions or subqueries)
    ** and if the subquery contains an ORDER BY clause and if
    ** it will be implemented as a co-routine, then do not flatten.  This
7607
7608
7609
7610
7611
7612
7613
7614

7615
7616
7617
7618
7619
7620
7621
7635
7636
7637
7638
7639
7640
7641

7642
7643
7644
7645
7646
7647
7648
7649







-
+







      sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
    }

#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    /* Generate code for all sub-queries in the FROM clause
    */
    pSub = pItem->pSelect;
    if( pSub==0 ) continue;
    if( pSub==0 || pItem->addrFillSub!=0 ) continue;

    /* The code for a subquery should only be generated once. */
    assert( pItem->addrFillSub==0 );

    /* Increment Parse.nHeight by the height of the largest expression
    ** tree referred to by this, the parent select. The child select
    ** may contain expression trees of at most
8011
8012
8013
8014
8015
8016
8017
8018

8019
8020
8021
8022
8023
8024
8025
8026
8039
8040
8041
8042
8043
8044
8045

8046

8047
8048
8049
8050
8051
8052
8053







-
+
-








    /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
    ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
    ** SELECT statement.
    */
    pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
    if( pAggInfo ){
      sqlite3ParserAddCleanup(pParse,
      sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo);
          (void(*)(sqlite3*,void*))agginfoFree, pAggInfo);
      testcase( pParse->earlyCleanup );
    }
    if( db->mallocFailed ){
      goto select_end;
    }
    pAggInfo->selId = p->selId;
#ifdef SQLITE_DEBUG
8520
8521
8522
8523
8524
8525
8526






8527
8528
8529
8530
8531
8532
8533
8547
8548
8549
8550
8551
8552
8553
8554
8555
8556
8557
8558
8559
8560
8561
8562
8563
8564
8565
8566







+
+
+
+
+
+







  */
select_end:
  assert( db->mallocFailed==0 || db->mallocFailed==1 );
  assert( db->mallocFailed==0 || pParse->nErr!=0 );
  sqlite3ExprListDelete(db, pMinMaxOrderBy);
#ifdef SQLITE_DEBUG
  if( pAggInfo && !db->mallocFailed ){
#if TREETRACE_ENABLED
    if( sqlite3TreeTrace & 0x20 ){
      TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
      printAggInfo(pAggInfo);
    }
#endif
    for(i=0; i<pAggInfo->nColumn; i++){
      Expr *pExpr = pAggInfo->aCol[i].pCExpr;
      if( pExpr==0 ) continue;
      assert( pExpr->pAggInfo==pAggInfo );
      assert( pExpr->iAgg==i );
    }
    for(i=0; i<pAggInfo->nFunc; i++){
Changes to src/shell.c.in.
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
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







+
















+
+
+








+


+
+
+
+
+
-
+
+

+

-

-
+







# define SQLITE_CIO_NO_TRANSLATE
# define SQLITE_CIO_NO_SETMODE
#endif
INCLUDE ../ext/consio/console_io.h
INCLUDE ../ext/consio/console_io.c

#ifndef SQLITE_SHELL_FIDDLE

/* From here onward, fgets() is redirected to the console_io library. */
# define fgets(b,n,f) fGetsUtf8(b,n,f)
/*
 * Define macros for emitting output text in various ways:
 *  sputz(s, z)      => emit 0-terminated string z to given stream s
 *  sputf(s, f, ...) => emit varargs per format f to given stream s
 *  oputz(z)         => emit 0-terminated string z to default stream
 *  oputf(f, ...)    => emit varargs per format f to default stream
 *  eputz(z)         => emit 0-terminated string z to error stream
 *  eputf(f, ...)    => emit varargs per format f to error stream
 *  oputb(b, n)      => emit char buffer b[0..n-1] to default stream
 *
 * Note that the default stream is whatever has been last set via:
 *   setOutputStream(FILE *pf)
 * This is normally the stream that CLI normal output goes to.
 * For the stand-alone CLI, it is stdout with no .output redirect.
 *
 * The ?putz(z) forms are required for the Fiddle builds for string literal
 * output, in aid of enforcing format string to argument correspondence.
 */
# define sputz(s,z) fPutsUtf8(z,s)
# define sputf fPrintfUtf8
# define oputz(z) oPutsUtf8(z)
# define oputf oPrintfUtf8
# define eputz(z) ePutsUtf8(z)
# define eputf ePrintfUtf8
# define oputb(buf,na) oPutbUtf8(buf,na)

#else
/* For Fiddle, all console handling and emit redirection is omitted. */
/* These next 3 macros are for emitting formatted output. When complaints
 * from the WASM build are issued for non-formatted output, (when a mere
 * string literal is to be emitted, the ?putz(z) forms should be used.
 * (This permits compile-time checking of format string / argument mismatch.)
 */
# define sputz(fp,z) fputs(z,fp)
# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
/* These next 3 macros are for emitting simple string literals. */
# define oputz(z) fputs(z,stdout)
# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
# define eputz(z) fputs(z,stderr)
# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
# define sputz(fp,z) fputs(z,fp)
# define oputb(buf,na) fwrite(buf,1,na,stdout)
#endif

/* True if the timer is enabled */
static int enableTimer = 0;

/* A version of strcmp() that works with NULL values */
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
365
366
367
368
369
370
371

372
373
374
375
376
377
378
379







-
+







** Print the timing results.
*/
static void endTimer(void){
  if( enableTimer ){
    sqlite3_int64 iEnd = timeOfDay();
    struct rusage sEnd;
    getrusage(RUSAGE_SELF, &sEnd);
    oputf("Run Time: real %.3f user %f sys %f\n",
    sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
          (iEnd - iBegin)*0.001,
          timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
          timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
  }
}

#define BEGIN_TIMER beginTimer()
433
434
435
436
437
438
439
440

441
442
443
444
445
446
447
444
445
446
447
448
449
450

451
452
453
454
455
456
457
458







-
+







** Print the timing results.
*/
static void endTimer(void){
  if( enableTimer && getProcessTimesAddr){
    FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
    sqlite3_int64 ftWallEnd = timeOfDay();
    getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
    oputf("Run Time: real %.3f user %f sys %f\n",
    sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
          (ftWallEnd - ftWallBegin)*0.001,
          timeDiff(&ftUserBegin, &ftUserEnd),
          timeDiff(&ftKernelBegin, &ftKernelEnd));
  }
}

#define BEGIN_TIMER beginTimer()
473
474
475
476
477
478
479
480
481
482



483
484
485
486
487
488
489
484
485
486
487
488
489
490



491
492
493
494
495
496
497
498
499
500







-
-
-
+
+
+







/*
** Treat stdin as an interactive input if the following variable
** is true.  Otherwise, assume stdin is connected to a file or pipe.
*/
static int stdin_is_interactive = 1;

/*
** On Windows systems we have to know if standard output is a console
** in order to translate UTF-8 into MBCS.  The following variable is
** true if translation is required.
** On Windows systems we need to know if standard output is a console
** in order to show that UTF-16 translation is done in the sign-on
** banner. The following variable is true if it is the console.
*/
static int stdout_is_console = 1;

/*
** The following is the open SQLite database.  We make a pointer
** to this database a static variable so that it can be accessed
** by the SIGINT handler to interrupt database processing.
730
731
732
733
734
735
736
737

738
739
740
741
742
743
744

745
746
747
748
749
750
751
741
742
743
744
745
746
747

748
749
750
751
752
753
754

755
756
757
758
759
760
761
762







-
+






-
+







/*
** Return open FILE * if zFile exists, can be opened for read
** and is an ordinary file or a character stream source.
** Otherwise return 0.
*/
static FILE * openChrSource(const char *zFile){
#if defined(_WIN32) || defined(WIN32)
  struct _stat x = {0};
  struct __stat64 x = {0};
# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
  /* On Windows, open first, then check the stream nature. This order
  ** is necessary because _stat() and sibs, when checking a named pipe,
  ** effectively break the pipe as its supplier sees it. */
  FILE *rv = fopen(zFile, "rb");
  if( rv==0 ) return 0;
  if( _fstat(_fileno(rv), &x) != 0
  if( _fstat64(_fileno(rv), &x) != 0
      || !STAT_CHR_SRC(x.st_mode)){
    fclose(rv);
    rv = 0;
  }
  return rv;
#else
  struct stat x = {0};
1206
1207
1208
1209
1210
1211
1212



1213
1214
1215
1216
1217
1218
1219
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233







+
+
+







#endif
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
#endif
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c

INCLUDE ../ext/intck/sqlite3intck.h
INCLUDE ../ext/intck/sqlite3intck.c

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
#define SQLITE_SHELL_HAVE_RECOVER 1
#else
#define SQLITE_SHELL_HAVE_RECOVER 0
#endif
#if SQLITE_SHELL_HAVE_RECOVER
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







+







  u8 scanstatsOn;        /* True to display scan stats before each finalize */
  u8 openMode;           /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
  u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
  u8 nEqpLevel;          /* Depth of the EQP output graph */
  u8 eTraceType;         /* SHELL_TRACE_* value for type of trace */
  u8 bSafeMode;          /* True to prohibit unsafe operations */
  u8 bSafeModePersist;   /* The long-term value of bSafeMode */
  u8 eRestoreState;      /* See comments above doAutoDetectRestore() */
  ColModeOpts cmOpts;    /* Option values affecting columnar mode output */
  unsigned statsOn;      /* True to display memory stats before each finalize */
  unsigned mEqpLines;    /* Mask of vertical lines in the EQP output graph */
  int inputNesting;      /* Track nesting level of .read and other redirects */
  int outCount;          /* Revert to stdout when reaching zero */
  int cnt;               /* Number of records displayed so far */
  int lineno;            /* Line number of last line read from in */
3757
3758
3759
3760
3761
3762
3763

3764
3765
3766
3767
3768
3769
3770
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786







+







  int bw = p->cmOpts.bWordWrap;
  const char *zEmpty = "";
  const char *zShowNull = p->nullValue;

  rc = sqlite3_step(pStmt);
  if( rc!=SQLITE_ROW ) return;
  nColumn = sqlite3_column_count(pStmt);
  if( nColumn==0 ) goto columnar_end;
  nAlloc = nColumn*4;
  if( nAlloc<=0 ) nAlloc = 1;
  azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
  shell_check_oom(azData);
  azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
  shell_check_oom(azNextLine);
  memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3858
3859
3860
3861
3862
3863
3864

3865
3866
3867
3868
3869
3870
3871







-







    z = azData[i];
    if( z==0 ) z = (char*)zEmpty;
    n = strlenChar(z);
    j = i%nColumn;
    if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
  }
  if( seenInterrupt ) goto columnar_end;
  if( nColumn==0 ) goto columnar_end;
  switch( p->cMode ){
    case MODE_Column: {
      colSep = "  ";
      rowSep = "\n";
      if( p->showHeader ){
        for(i=0; i<nColumn; i++){
          w = p->actualWidth[i];
4725
4726
4727
4728
4729
4730
4731

4732
4733
4734
4735
4736
4737
4738
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754







+







#endif
#ifndef SQLITE_OMIT_TEST_CONTROL
  ",imposter INDEX TABLE    Create imposter table TABLE on index INDEX",
#endif
  ".indexes ?TABLE?         Show names of indexes",
  "                           If TABLE is specified, only show indexes for",
  "                           tables matching TABLE using the LIKE operator.",
  ".intck ?STEPS_PER_UNLOCK?  Run an incremental integrity check on the db",
#ifdef SQLITE_ENABLE_IOTRACE
  ",iotrace FILE            Enable I/O diagnostic logging to FILE",
#endif
  ".limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT",
  ".lint OPTIONS            Report potential schema issues.",
  "     Options:",
  "        fkey-indexes     Find missing foreign key indexes",
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336

5337
5338
5339
5340
5341
5342
5343
5329
5330
5331
5332
5333
5334
5335

5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359







-
















+







      case SHELL_OPEN_UNSPEC:
      case SHELL_OPEN_NORMAL: {
        sqlite3_open_v2(zDbFilename, &p->db,
           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
        break;
      }
    }
    globalDb = p->db;
    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
      eputf("Error: unable to open database \"%s\": %s\n",
            zDbFilename, sqlite3_errmsg(p->db));
      if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
        exit(1);
      }
      sqlite3_close(p->db);
      sqlite3_open(":memory:", &p->db);
      if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
        eputz("Also: unable to open substitute in-memory database.\n");
        exit(1);
      }else{
        eputf("Notice: using substitute in-memory database instead of \"%s\"\n",
              zDbFilename);
      }
    }
    globalDb = p->db;
    sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);

    /* Reflect the use or absence of --unsafe-testing invocation. */
    {
      int testmode_on = ShellHasFlag(p,SHFLG_TestingMode);
      sqlite3_db_config(p->db, SQLITE_DBCONFIG_TRUSTED_SCHEMA, testmode_on,0);
      sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, !testmode_on,0);
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756

6757
6758
6759
6760
6761
6762
6763
6741
6742
6743
6744
6745
6746
6747

6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765




6766

6767
6768
6769
6770
6771
6772
6773
6774







-


















-
-
-
-

-
+







 usage:
  eputf("Usage %s sub-command ?switches...?\n", azArg[0]);
  eputz("Where sub-commands are:\n");
  eputz("    fkey-indexes\n");
  return SQLITE_ERROR;
}

#if !defined SQLITE_OMIT_VIRTUALTABLE
static void shellPrepare(
  sqlite3 *db,
  int *pRc,
  const char *zSql,
  sqlite3_stmt **ppStmt
){
  *ppStmt = 0;
  if( *pRc==SQLITE_OK ){
    int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
    if( rc!=SQLITE_OK ){
      eputf("sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
      *pRc = rc;
    }
  }
}

/*
** Create a prepared statement using printf-style arguments for the SQL.
**
** This routine is could be marked "static".  But it is not always used,
** depending on compile-time options.  By omitting the "static", we avoid
** nuisance compiler warnings about "defined but not used".
*/
void shellPreparePrintf(
static void shellPreparePrintf(
  sqlite3 *db,
  int *pRc,
  sqlite3_stmt **ppStmt,
  const char *zFmt,
  ...
){
  *ppStmt = 0;
6772
6773
6774
6775
6776
6777
6778

6779

6780
6781
6782
6783
6784
6785

6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800

6801
6802
6803
6804
6805
6806
6807
6783
6784
6785
6786
6787
6788
6789
6790

6791




6792

6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816







+
-
+
-
-
-
-

-
+















+







    }else{
      shellPrepare(db, pRc, z, ppStmt);
      sqlite3_free(z);
    }
  }
}

/* 
/* Finalize the prepared statement created using shellPreparePrintf().
** Finalize the prepared statement created using shellPreparePrintf().
**
** This routine is could be marked "static".  But it is not always used,
** depending on compile-time options.  By omitting the "static", we avoid
** nuisance compiler warnings about "defined but not used".
*/
void shellFinalize(
static void shellFinalize(
  int *pRc,
  sqlite3_stmt *pStmt
){
  if( pStmt ){
    sqlite3 *db = sqlite3_db_handle(pStmt);
    int rc = sqlite3_finalize(pStmt);
    if( *pRc==SQLITE_OK ){
      if( rc!=SQLITE_OK ){
        eputf("SQL error: %s\n", sqlite3_errmsg(db));
      }
      *pRc = rc;
    }
  }
}

#if !defined SQLITE_OMIT_VIRTUALTABLE
/* Reset the prepared statement created using shellPreparePrintf().
**
** This routine is could be marked "static".  But it is not always used,
** depending on compile-time options.  By omitting the "static", we avoid
** nuisance compiler warnings about "defined but not used".
*/
void shellReset(
7641
7642
7643
7644
7645
7646
7647


































7648
7649
7650
7651
7652
7653
7654
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697







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







    eputf("sql error: %s (%d)\n", zErr, errCode);
  }
  rc = sqlite3_recover_finish(p);
  return rc;
}
#endif /* SQLITE_SHELL_HAVE_RECOVER */

/*
** Implementation of ".intck STEPS_PER_UNLOCK" command.
*/
static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
  sqlite3_intck *p = 0;
  int rc = SQLITE_OK;

  rc = sqlite3_intck_open(pState->db, "main", &p);
  if( rc==SQLITE_OK ){
    i64 nStep = 0;
    i64 nError = 0;
    const char *zErr = 0;
    while( SQLITE_OK==sqlite3_intck_step(p) ){
      const char *zMsg = sqlite3_intck_message(p);
      if( zMsg ){
        oputf("%s\n", zMsg);
        nError++;
      }
      nStep++;
      if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){
        sqlite3_intck_unlock(p);
      }
    }
    rc = sqlite3_intck_error(p, &zErr);
    if( zErr ){
      eputf("%s\n", zErr);
    }
    sqlite3_intck_close(p);

    oputf("%lld steps, %lld errors\n", nStep, nError);
  }

  return rc;
}

/*
 * zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
 * zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE,
 *   close db and set it to 0, and return the columns spec, to later
 *   be sqlite3_free()'ed by the caller.
 * The return is 0 when either:
7859
7860
7861
7862
7863
7864
7865
























































7866
7867
7868
7869
7870
7871
7872
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971







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







    }
    sqlite3_finalize(pStmt);
    sqlite3_close(*pDb);
    *pDb = 0;
    return zColsSpec;
  }
}

/*
** Check if the sqlite_schema table contains one or more virtual tables. If
** parameter zLike is not NULL, then it is an SQL expression that the
** sqlite_schema row must also match. If one or more such rows are found,
** print the following warning to the output:
**
** WARNING: Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled
*/
static int outputDumpWarning(ShellState *p, const char *zLike){
  int rc = SQLITE_OK;
  sqlite3_stmt *pStmt = 0;
  shellPreparePrintf(p->db, &rc, &pStmt,
    "SELECT 1 FROM sqlite_schema o WHERE "
    "sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true"
  );
  if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
    oputz("/* WARNING: "
          "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n"
    );
  }
  shellFinalize(&rc, pStmt);
  return rc;
}

/*
** Fault-Simulator state and logic.
*/
static struct {
  int iId;           /* ID that triggers a simulated fault.  -1 means "any" */
  int iErr;          /* The error code to return on a fault */
  int iCnt;          /* Trigger the fault only if iCnt is already zero */
  int iInterval;     /* Reset iCnt to this value after each fault */
  int eVerbose;      /* When to print output */
} faultsim_state = {-1, 0, 0, 0, 0};

/*
** This is the fault-sim callback
*/
static int faultsim_callback(int iArg){
  if( faultsim_state.iId>0 && faultsim_state.iId!=iArg ){
    return SQLITE_OK;
  }
  if( faultsim_state.iCnt>0 ){
    faultsim_state.iCnt--;
    if( faultsim_state.eVerbose>=2 ){
      oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
    }
    return SQLITE_OK;
  }
  if( faultsim_state.eVerbose>=1 ){
    oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
  }
  faultsim_state.iCnt = faultsim_state.iInterval;
  return faultsim_state.iErr;
}

/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
8322
8323
8324
8325
8326
8327
8328

8329
8330
8331
8332
8333
8334
8335
8421
8422
8423
8424
8425
8426
8427
8428
8429
8430
8431
8432
8433
8434
8435







+







          zLike = zExpr;
        }
      }
    }

    open_db(p, 0);

    outputDumpWarning(p, zLike);
    if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
      /* When playing back a "dump", the content might appear in an order
      ** which causes immediate foreign key constraints to be violated.
      ** So disable foreign-key constraint enforcement to prevent problems. */
      oputz("PRAGMA foreign_keys=OFF;\n");
      oputz("BEGIN TRANSACTION;\n");
    }
8350
8351
8352
8353
8354
8355
8356
8357


8358
8359
8360
8361
8362
8363
8364
8450
8451
8452
8453
8454
8455
8456

8457
8458
8459
8460
8461
8462
8463
8464
8465







-
+
+







    );
    run_schema_dump_query(p,zSql);
    sqlite3_free(zSql);
    if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
      zSql = sqlite3_mprintf(
        "SELECT sql FROM sqlite_schema AS o "
        "WHERE (%s) AND sql NOT NULL"
        "  AND type IN ('index','trigger','view')",
        "  AND type IN ('index','trigger','view') "
        "ORDER BY type COLLATE NOCASE DESC",
        zLike
      );
      run_table_dump_query(p, zSql);
      sqlite3_free(zSql);
    }
    sqlite3_free(zLike);
    if( p->writableSchema ){
8673
8674
8675
8676
8677
8678
8679
8680

8681
8682
8683
8684

8685
8686
8687
8688

8689
8690
8691
8692
8693
8694
8695
8696
8774
8775
8776
8777
8778
8779
8780

8781
8782
8783
8784

8785
8786
8787
8788

8789

8790
8791
8792
8793
8794
8795
8796







-
+



-
+



-
+
-







      showHelp(p->out, 0);
    }
  }else

#ifndef SQLITE_SHELL_FIDDLE
  if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){
    char *zTable = 0;           /* Insert data into this table */
    char *zSchema = 0;          /* within this schema (may default to "main") */
    char *zSchema = 0;          /* Schema of zTable */
    char *zFile = 0;            /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */
    i64 nByte;                  /* Number of bytes in an SQL string */
    int i, j;                   /* Loop counters */
    int needCommit;             /* True to COMMIT or ROLLBACK at end */
    int nSep;                   /* Number of bytes in p->colSeparator[] */
    char *zSql;                 /* An SQL statement */
    char *zSql = 0;             /* An SQL statement */
    char *zFullTabName;         /* Table name with schema if applicable */
    ImportCtx sCtx;             /* Reader context */
    char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
    int eVerbose = 0;           /* Larger for more console output */
    int nSkip = 0;              /* Initial lines to skip */
    int useOutputMode = 1;      /* Use output mode to determine separators */
    char *zCreate = 0;          /* CREATE TABLE statement text */

8816
8817
8818
8819
8820
8821
8822
8823
8824
8825
8826
8827
8828
8829
8830
8831
8832
8833
8834
8835
8836


8837
8838
8839
8840


8841
8842
8843
8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
8859
8860
8861
8862
8863




8864
8865
8866
8867


8868
8869
8870



8871









8872
8873


8874
8875
8876
8877
8878
8879



8880
8881
8882





8883
8884
8885
8886
8887
8888
8889
8890

8891





8892
8893
8894
8895
8896
8897
8898
8899
8900
8901
8902


8903
8904
8905
8906



8907
8908
8909
8910
8911
8912
8913
8914
8915
8916
8916
8917
8918
8919
8920
8921
8922












8923

8924
8925
8926
8927
8928

8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944




8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961

8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974


8975
8976


8977
8978
8979

8980
8981
8982
8983


8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994
8995
8996
8997

8998
8999
9000
9001
9002
9003
9004
9005
9006
9007
9008
9009
9010
9011
9012
9013
9014
9015
9016
9017
9018

9019
9020
9021
9022


9023
9024
9025
9026
9027
9028
9029







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

-
+
+



-
+
+














-
-
-
-





+
+
+
+




+
+


-
+
+
+

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



-
+
+
+

-
-
+
+
+
+
+








+
-
+
+
+
+
+











+
+



-
+
+
+

-
-







      import_cleanup(&sCtx);
      shell_out_of_memory();
    }
    /* Below, resources must be freed before exit. */
    while( (nSkip--)>0 ){
      while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
    }
    if( zSchema!=0 ){
      zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);
    }else{
      zFullTabName = sqlite3_mprintf("\"%w\"", zTable);
    }
    zSql = sqlite3_mprintf("SELECT * FROM %s", zFullTabName);
    if( zSql==0 || zFullTabName==0 ){
      import_cleanup(&sCtx);
      shell_out_of_memory();
    }
    nByte = strlen30(zSql);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    import_append_char(&sCtx, 0);    /* To ensure sCtx.z is allocated */
    if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
    if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){
      /* Table does not exist.  Create it. */
      sqlite3 *dbCols = 0;
      char *zRenames = 0;
      char *zColDefs;
      zCreate = sqlite3_mprintf("CREATE TABLE %s", zFullTabName);
      zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"", 
                    zSchema ? zSchema : "main", zTable);
      while( xRead(&sCtx) ){
        zAutoColumn(sCtx.z, &dbCols, 0);
        if( sCtx.cTerm!=sCtx.cColSep ) break;
      }
      zColDefs = zAutoColumn(0, &dbCols, &zRenames);
      if( zRenames!=0 ){
        sputf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
              "Columns renamed during .import %s due to duplicates:\n"
              "%s\n", sCtx.zFile, zRenames);
        sqlite3_free(zRenames);
      }
      assert(dbCols==0);
      if( zColDefs==0 ){
        eputf("%s: empty file\n", sCtx.zFile);
      import_fail:
        sqlite3_free(zCreate);
        sqlite3_free(zSql);
        sqlite3_free(zFullTabName);
        import_cleanup(&sCtx);
        rc = 1;
        goto meta_command_exit;
      }
      zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
      if( zCreate==0 ){
        import_cleanup(&sCtx);
        shell_out_of_memory();
      }
      if( eVerbose>=1 ){
        oputf("%s\n", zCreate);
      }
      rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
      sqlite3_free(zCreate);
      zCreate = 0;
      if( rc ){
        eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
        goto import_fail;
        import_cleanup(&sCtx);
        rc = 1;
        goto meta_command_exit;
      }
    }
    zSql = sqlite3_mprintf("SELECT count(*) FROM pragma_table_info(%Q,%Q);",
                           zTable, zSchema);
    if( zSql==0 ){
      import_cleanup(&sCtx);
      shell_out_of_memory();
    }
    nByte = strlen(zSql);    
    rc =  sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
      sqlite3_free(zCreate);
      zCreate = 0;
    sqlite3_free(zSql);
    zSql = 0;
      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    }
    if( rc ){
      if (pStmt) sqlite3_finalize(pStmt);
      eputf("Error: %s\n", sqlite3_errmsg(p->db));
      goto import_fail;
      import_cleanup(&sCtx);
      rc = 1;
      goto meta_command_exit;
    }
    sqlite3_free(zSql);
    nCol = sqlite3_column_count(pStmt);
    if( sqlite3_step(pStmt)==SQLITE_ROW ){
      nCol = sqlite3_column_int(pStmt, 0);
    }else{
      nCol = 0;
    }
    sqlite3_finalize(pStmt);
    pStmt = 0;
    if( nCol==0 ) return 0; /* no columns, no error */
    zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
    if( zSql==0 ){
      import_cleanup(&sCtx);
      shell_out_of_memory();
    }
    if( zSchema ){
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zFullTabName);
      sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?", 
                       zSchema, zTable);
    }else{
      sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
    }
    j = strlen30(zSql);
    for(i=1; i<nCol; i++){
      zSql[j++] = ',';
      zSql[j++] = '?';
    }
    zSql[j++] = ')';
    zSql[j] = 0;
    if( eVerbose>=2 ){
      oputf("Insert using: %s\n", zSql);
    }
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    zSql = 0;
    if( rc ){
      eputf("Error: %s\n", sqlite3_errmsg(p->db));
      if (pStmt) sqlite3_finalize(pStmt);
      goto import_fail;
      import_cleanup(&sCtx);
      rc = 1;
      goto meta_command_exit;
    }
    sqlite3_free(zSql);
    sqlite3_free(zFullTabName);
    needCommit = sqlite3_get_autocommit(p->db);
    if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
    do{
      int startLine = sCtx.nLine;
      for(i=0; i<nCol; i++){
        char *z = xRead(&sCtx);
        /*
9072
9073
9074
9075
9076
9077
9078















9079
9080
9081
9082
9083
9084
9085
9185
9186
9187
9188
9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213







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







    }else{
      eputf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
      rc = 1;
    }
    sqlite3_free(zSql);
  }else
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */

  if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){
    i64 iArg = 0;
    if( nArg==2 ){
      iArg = integerValue(azArg[1]);
      if( iArg==0 ) iArg = -1;
    }
    if( (nArg!=1 && nArg!=2) || iArg<0 ){
      eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    rc = intckDatabaseCmd(p, iArg);
  }else

#ifdef SQLITE_ENABLE_IOTRACE
  if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){
    SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
    if( iotrace && iotrace!=stdout ) fclose(iotrace);
    iotrace = 0;
    if( nArg<2 ){
10071
10072
10073
10074
10075
10076
10077
10078

10079
10080
10081
10082
10083
10084
10085
10086
10199
10200
10201
10202
10203
10204
10205

10206

10207
10208
10209
10210
10211
10212
10213







-
+
-







        }
        if( rc ){
          sputf(stdout, "Error: error code %d\n", rc);
          rc = 0;
        }
        if( pChng
          && fwrite(pChng, szChng, 1, out)!=1 ){
          eputf("ERROR: Failed to write entire %d-byte output\n",
          eputf("ERROR: Failed to write entire %d-byte output\n", szChng);
                szChng);
        }
        sqlite3_free(pChng);
        fclose(out);
      }
    }else

    /* .session close
10747
10748
10749
10750
10751
10752
10753
10754

10755
10756
10757

10758
10759
10760
10761
10762
10763
10764
10765
10766
10767

10768
10769
10770
10771
10772
10773
10774
10874
10875
10876
10877
10878
10879
10880

10881
10882
10883
10884
10885
10886
10887
10888
10889
10890
10891
10892
10893
10894
10895
10896
10897
10898
10899
10900
10901
10902
10903







-
+



+










+







    } aCtrl[] = {
    {"always",             SQLITE_TESTCTRL_ALWAYS, 1,     "BOOLEAN"         },
    {"assert",             SQLITE_TESTCTRL_ASSERT, 1,     "BOOLEAN"         },
  /*{"benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, ""        },*/
  /*{"bitvec_test",        SQLITE_TESTCTRL_BITVEC_TEST, 1,  ""              },*/
    {"byteorder",          SQLITE_TESTCTRL_BYTEORDER, 0,  ""                },
    {"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN"  },
  /*{"fault_install",      SQLITE_TESTCTRL_FAULT_INSTALL, 1,""              },*/
    {"fault_install",      SQLITE_TESTCTRL_FAULT_INSTALL, 1,"args..."       },
    {"fk_no_action",       SQLITE_TESTCTRL_FK_NO_ACTION, 0, "BOOLEAN"       },
    {"imposter",         SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
    {"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,""          },
    {"json_selfcheck",     SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN"      },
    {"localtime_fault",    SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN"      },
    {"never_corrupt",      SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN"       },
    {"optimizations",      SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK"   },
#ifdef YYCOVERAGE
    {"parser_coverage",    SQLITE_TESTCTRL_PARSER_COVERAGE,0,""             },
#endif
    {"pending_byte",       SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET  "       },
    {"prng_restore",       SQLITE_TESTCTRL_PRNG_RESTORE,0, ""               },
    {"prng_save",          SQLITE_TESTCTRL_PRNG_SAVE,   0, ""               },
    {"prng_seed",          SQLITE_TESTCTRL_PRNG_SEED,   0, "SEED ?db?"      },
    {"rowid_in_view",      SQLITE_TESTCTRL_ROWID_IN_VIEW,0,"?BOOLEAN?"      },
    {"seek_count",         SQLITE_TESTCTRL_SEEK_COUNT,  0, ""               },
    {"sorter_mmap",        SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX"           },
    {"tune",               SQLITE_TESTCTRL_TUNE,        1, "ID VALUE"       },
    {"uselongdouble",  SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"},
    };
    int testctrl = -1;
    int iCtrl = -1;
10935
10936
10937
10938
10939
10940
10941














10942
10943
10944
10945
10946
10947
10948
11064
11065
11066
11067
11068
11069
11070
11071
11072
11073
11074
11075
11076
11077
11078
11079
11080
11081
11082
11083
11084
11085
11086
11087
11088
11089
11090
11091







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







          if( nArg==2 ){
            sqlite3_test_control(testctrl, p->out);
            isOk = 3;
          }
          break;
        }
#endif
       case SQLITE_TESTCTRL_ROWID_IN_VIEW: {
          rc2 = -1;
          if( nArg>=3 ){
            if( !ShellHasFlag(p,SHFLG_TestingMode) ){
              eputz("The --unsafe-testing option is required to change "
                    "this setting\n");
            }else{
              rc2 = booleanValue(azArg[2]);
            }
          }
          sqlite3_test_control(testctrl, &rc2);
          isOk = 1;
          break;
       }
#ifdef SQLITE_DEBUG
        case SQLITE_TESTCTRL_TUNE: {
          if( nArg==4 ){
            int id = (int)integerValue(azArg[2]);
            int val = (int)integerValue(azArg[3]);
            sqlite3_test_control(testctrl, id, &val);
            isOk = 3;
10969
10970
10971
10972
10973
10974
10975




































































10976
10977
10978
10979
10980
10981
10982
11112
11113
11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124
11125
11126
11127
11128
11129
11130
11131
11132
11133
11134
11135
11136
11137
11138
11139
11140
11141
11142
11143
11144
11145
11146
11147
11148
11149
11150
11151
11152
11153
11154
11155
11156
11157
11158
11159
11160
11161
11162
11163
11164
11165
11166
11167
11168
11169
11170
11171
11172
11173
11174
11175
11176
11177
11178
11179
11180
11181
11182
11183
11184
11185
11186
11187
11188
11189
11190
11191
11192
11193







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







        case SQLITE_TESTCTRL_SORTER_MMAP:
          if( nArg==3 ){
            int opt = (unsigned int)integerValue(azArg[2]);
            rc2 = sqlite3_test_control(testctrl, p->db, opt);
            isOk = 3;
          }
          break;
        case SQLITE_TESTCTRL_JSON_SELFCHECK:
          if( nArg==2 ){
            rc2 = -1;
            isOk = 1;
          }else{
            rc2 = booleanValue(azArg[2]);
            isOk = 3;
          }
          sqlite3_test_control(testctrl, &rc2);
          break;
        case SQLITE_TESTCTRL_FAULT_INSTALL: {
          int kk;
          int bShowHelp = nArg<=2;
          isOk = 3;
          for(kk=2; kk<nArg; kk++){
            const char *z = azArg[kk];
            if( z[0]=='-' && z[1]=='-' ) z++;
            if( cli_strcmp(z,"off")==0 ){
              sqlite3_test_control(testctrl, 0);
            }else if( cli_strcmp(z,"on")==0 ){
              faultsim_state.iCnt = faultsim_state.iInterval;
              if( faultsim_state.iErr==0 ) faultsim_state.iErr = 1;
              sqlite3_test_control(testctrl, faultsim_callback);
            }else if( cli_strcmp(z,"reset")==0 ){
              faultsim_state.iCnt = faultsim_state.iInterval;
            }else if( cli_strcmp(z,"status")==0 ){
              oputf("faultsim.iId:       %d\n", faultsim_state.iId);
              oputf("faultsim.iErr:      %d\n", faultsim_state.iErr);
              oputf("faultsim.iCnt:      %d\n", faultsim_state.iCnt);
              oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
              oputf("faultsim.eVerbose:  %d\n", faultsim_state.eVerbose);
            }else if( cli_strcmp(z,"-v")==0 ){
              if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
            }else if( cli_strcmp(z,"-q")==0 ){
              if( faultsim_state.eVerbose>0 ) faultsim_state.eVerbose--;
            }else if( cli_strcmp(z,"-id")==0 && kk+1<nArg ){
              faultsim_state.iId = atoi(azArg[++kk]);
            }else if( cli_strcmp(z,"-errcode")==0 && kk+1<nArg ){
              faultsim_state.iErr = atoi(azArg[++kk]);
            }else if( cli_strcmp(z,"-interval")==0 && kk+1<nArg ){
              faultsim_state.iInterval = atoi(azArg[++kk]);
            }else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
              bShowHelp = 1;
            }else{
              eputf("Unrecognized fault_install argument: \"%s\"\n",
                  azArg[kk]);
              rc = 1;
              bShowHelp = 1;
              break;
            }
          }
          if( bShowHelp ){
            oputz(
               "Usage: .testctrl fault_install ARGS\n"
               "Possible arguments:\n"
               "   off               Disable faultsim\n"
               "   on                Activate faultsim\n"
               "   reset             Reset the trigger counter\n"
               "   status            Show current status\n"
               "   -v                Increase verbosity\n"
               "   -q                Decrease verbosity\n"
               "   --errcode N       When triggered, return N as error code\n"
               "   --id ID           Trigger only for the ID specified\n"
               "   --interval N      Trigger only after every N-th call\n"
            );
          }
          break;
        }
      }
    }
    if( isOk==0 && iCtrl>=0 ){
      oputf("Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
      rc = 1;
    }else if( isOk==1 ){
      oputf("%d\n", rc2);
11374
11375
11376
11377
11378
11379
11380


















































































11381
11382
11383
11384
11385
11386
11387
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
11599
11600
11601
11602
11603
11604
11605
11606
11607
11608
11609
11610
11611
11612
11613
11614
11615
11616
11617
11618
11619
11620
11621
11622
11623
11624
11625
11626
11627
11628
11629
11630
11631
11632
11633
11634
11635
11636
11637
11638
11639
11640
11641
11642
11643
11644
11645
11646
11647
11648
11649
11650
11651
11652
11653
11654
11655
11656
11657
11658
11659
11660
11661
11662
11663
11664
11665
11666
11667
11668
11669
11670
11671
11672
11673
11674
11675
11676
11677
11678
11679
11680







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







  if( zSql==0 ) return 1;
  zSql[nSql] = ';';
  zSql[nSql+1] = 0;
  rc = sqlite3_complete(zSql);
  zSql[nSql] = 0;
  return rc;
}

/*
** This function is called after processing each line of SQL in the
** runOneSqlLine() function. Its purpose is to detect scenarios where
** defensive mode should be automatically turned off. Specifically, when
**
**   1. The first line of input is "PRAGMA foreign_keys=OFF;",
**   2. The second line of input is "BEGIN TRANSACTION;",
**   3. The database is empty, and
**   4. The shell is not running in --safe mode.
** 
** The implementation uses the ShellState.eRestoreState to maintain state:
**
**    0: Have not seen any SQL.
**    1: Have seen "PRAGMA foreign_keys=OFF;".
**    2-6: Currently running .dump transaction. If the "2" bit is set,
**         disable DEFENSIVE when done. If "4" is set, disable DQS_DDL.
**    7: Nothing left to do. This function becomes a no-op.
*/
static int doAutoDetectRestore(ShellState *p, const char *zSql){
  int rc = SQLITE_OK;

  if( p->eRestoreState<7 ){
    switch( p->eRestoreState ){
      case 0: {
        const char *zExpect = "PRAGMA foreign_keys=OFF;";
        assert( strlen(zExpect)==24 );
        if( p->bSafeMode==0 && memcmp(zSql, zExpect, 25)==0 ){
          p->eRestoreState = 1;
        }else{
          p->eRestoreState = 7;
        }
        break;
      };
  
      case 1: {
        int bIsDump = 0;
        const char *zExpect = "BEGIN TRANSACTION;";
        assert( strlen(zExpect)==18 );
        if( memcmp(zSql, zExpect, 19)==0 ){
          /* Now check if the database is empty. */
          const char *zQuery = "SELECT 1 FROM sqlite_schema LIMIT 1";
          sqlite3_stmt *pStmt = 0;
  
          bIsDump = 1;
          shellPrepare(p->db, &rc, zQuery, &pStmt);
          if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
            bIsDump = 0;
          }
          shellFinalize(&rc, pStmt);
        }
        if( bIsDump && rc==SQLITE_OK ){
          int bDefense = 0;
          int bDqsDdl = 0;
          sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &bDefense);
          sqlite3_db_config(p->db, SQLITE_DBCONFIG_DQS_DDL, -1, &bDqsDdl);
          sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
          sqlite3_db_config(p->db, SQLITE_DBCONFIG_DQS_DDL, 1, 0);
          p->eRestoreState = (bDefense ? 2 : 0) + (bDqsDdl ? 4 : 0);
        }else{
          p->eRestoreState = 7;
        }
        break;
      }
  
      default: {
        if( sqlite3_get_autocommit(p->db) ){
          if( (p->eRestoreState & 2) ){
            sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 1, 0);
          }
          if( (p->eRestoreState & 4) ){
            sqlite3_db_config(p->db, SQLITE_DBCONFIG_DQS_DDL, 0, 0);
          }
          p->eRestoreState = 7;
        }
        break;
      }
    }
  }

  return rc;
}

/*
** Run a single line of SQL.  Return the number of errors.
*/
static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
  int rc;
  char *zErrMsg = 0;
11422
11423
11424
11425
11426
11427
11428


11429
11430
11431
11432
11433
11434
11435
11715
11716
11717
11718
11719
11720
11721
11722
11723
11724
11725
11726
11727
11728
11729
11730







+
+







  }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
    char zLineBuf[2000];
    sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
            "changes: %lld   total_changes: %lld",
            sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
    oputf("%s\n", zLineBuf);
  }

  if( doAutoDetectRestore(p, zSql) ) return 1;
  return 0;
}

static void echo_group_input(ShellState *p, const char *zDo){
  if( ShellHasFlag(p, SHFLG_Echo) ) oputf("%s\n", zDo);
}

11806
11807
11808
11809
11810
11811
11812
11813

11814
11815
11816
11817
11818
11819
11820
12101
12102
12103
12104
12105
12106
12107

12108
12109
12110
12111
12112
12113
12114
12115







-
+







       "FILENAME is the name of an SQLite database. A new database is created\n"
       "if the file does not previously exist. Defaults to :memory:.\n", Argv0);
  if( showDetail ){
    eputf("OPTIONS include:\n%s", zOptions);
  }else{
    eputz("Use the -help option for additional information\n");
  }
  exit(1);
  exit(0);
}

/*
** Internal check:  Verify that the SQLite is uninitialized.  Print a
** error message if it is initialized.
*/
static void verify_uninitialized(void){
11855
11856
11857
11858
11859
11860
11861
11862

11863
11864
11865
11866
11867
11868
11869

11870
11871
11872
11873
11874
11875
11876
11877
11878
11879

11880
11881
11882
11883
11884
11885
11886
11887
12150
12151
12152
12153
12154
12155
12156

12157
12158
12159
12160
12161
12162
12163

12164
12165
12166
12167
12168
12169
12170
12171
12172
12173

12174

12175
12176
12177
12178
12179
12180
12181







-
+






-
+









-
+
-







  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
  CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
  GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
  SetConsoleTextAttribute(out,
         FOREGROUND_RED|FOREGROUND_INTENSITY
  );
#endif
  oputf("%s", zText);
  sputz(stdout, zText);
#if !SQLITE_OS_WINRT
  SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
#endif
}
#else
static void printBold(const char *zText){
  oputf("\033[1m%s\033[0m", zText);
  sputf(stdout, "\033[1m%s\033[0m", zText);
}
#endif

/*
** Get the argument to an --option.  Throw an error and die if no argument
** is available.
*/
static char *cmdline_option_value(int argc, char **argv, int i){
  if( i==argc ){
    eputf("%s: Error: missing argument to %s\n",
    eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
          argv[0], argv[argc-1]);
    exit(1);
  }
  return argv[i];
}

static void sayAbnormalExit(void){
  if( seenInterrupt ) eputz("Program interrupted.\n");
11965
11966
11967
11968
11969
11970
11971
11972

11973
11974
11975
11976
11977
11978
11979
12259
12260
12261
12262
12263
12264
12265

12266
12267
12268
12269
12270
12271
12272
12273







-
+







  }
#endif
  /* Register a valid signal handler early, before much else is done. */
#ifdef SIGINT
  signal(SIGINT, interrupt_handler);
#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
  if( !SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE) ){
    eputf("No ^C handler.\n");
    eputz("No ^C handler.\n");
  }
#endif

#if USE_SYSTEM_SQLITE+0!=1
  if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
    eputf("SQLite header and source version mismatch\n%s\n%s\n",
          sqlite3_sourceid(), SQLITE_SOURCE_ID);
12057
12058
12059
12060
12061
12062
12063
12064
12065
12066
12067
12068
12069
12070
12071
12072
12073
12074
12351
12352
12353
12354
12355
12356
12357




12358
12359
12360
12361
12362
12363
12364







-
-
-
-







     || cli_strcmp(z,"-newline")==0
     || cli_strcmp(z,"-cmd")==0
    ){
      (void)cmdline_option_value(argc, argv, ++i);
    }else if( cli_strcmp(z,"-init")==0 ){
      zInitFile = cmdline_option_value(argc, argv, ++i);
    }else if( cli_strcmp(z,"-interactive")==0 ){
      /* Need to check for interactive override here to so that it can
      ** affect console setup (for Windows only) and testing thereof.
      */
      stdin_is_interactive = 1;
    }else if( cli_strcmp(z,"-batch")==0 ){
      /* Need to check for batch mode here to so we can avoid printing
      ** informational messages (like from process_sqliterc) before
      ** we do the actual processing of arguments later in a second pass.
      */
      stdin_is_interactive = 0;
    }else if( cli_strcmp(z,"-utf8")==0 ){
12330
12331
12332
12333
12334
12335
12336
12337
12338


12339
12340
12341




12342
12343
12344
12345
12346
12347
12348
12620
12621
12622
12623
12624
12625
12626


12627
12628
12629
12630

12631
12632
12633
12634
12635
12636
12637
12638
12639
12640
12641







-
-
+
+


-
+
+
+
+







      ** prior to sending the SQL into SQLite.  Useful for injecting
      ** crazy bytes in the middle of SQL statements for testing and debugging.
      */
      ShellSetFlag(&data, SHFLG_Backslash);
    }else if( cli_strcmp(z,"-bail")==0 ){
      /* No-op.  The bail_on_error flag should already be set. */
    }else if( cli_strcmp(z,"-version")==0 ){
      oputf("%s %s (%d-bit)\n", sqlite3_libversion(), sqlite3_sourceid(),
            8*(int)sizeof(char*));
      sputf(stdout, "%s %s (%d-bit)\n",
            sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
      return 0;
    }else if( cli_strcmp(z,"-interactive")==0 ){
      /* already handled */
      /* Need to check for interactive override here to so that it can
      ** affect console setup (for Windows only) and testing thereof.
      */
      stdin_is_interactive = 1;
    }else if( cli_strcmp(z,"-batch")==0 ){
      /* already handled */
    }else if( cli_strcmp(z,"-utf8")==0 ){
      /* already handled */
    }else if( cli_strcmp(z,"-no-utf8")==0 ){
      /* already handled */
    }else if( cli_strcmp(z,"-heap")==0 ){
12457
12458
12459
12460
12461
12462
12463
12464
12465
12466
12467
12468




12469
12470
12471

12472
12473

12474
12475

12476
12477

12478
12479
12480
12481
12482
12483
12484
12750
12751
12752
12753
12754
12755
12756

12757



12758
12759
12760
12761

12762

12763
12764

12765
12766

12767
12768

12769
12770
12771
12772
12773
12774
12775
12776







-

-
-
-
+
+
+
+
-

-
+

-
+

-
+

-
+







    }
  }else{
    /* Run commands received from standard input
    */
    if( stdin_is_interactive ){
      char *zHome;
      char *zHistory;
      const char *zCharset = "";
      int nHistory;
#if SHELL_CON_TRANSLATE==1
      zCharset = " (UTF-16 console I/O)";
#elif SHELL_CON_TRANSLATE==2
#if CIO_WIN_WC_XLATE
# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
#else
# define SHELL_CIO_CHAR_SET ""
      zCharset = " (MBCS console I/O)";
#endif
      oputf("SQLite version %s %.19s%s\n" /*extra-version-info*/
      sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
            "Enter \".help\" for usage hints.\n",
            sqlite3_libversion(), sqlite3_sourceid(), zCharset);
            sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
      if( warnInmemoryDb ){
        oputz("Connected to a ");
        sputz(stdout, "Connected to a ");
        printBold("transient in-memory database");
        oputz(".\nUse \".open FILENAME\" to reopen on a"
        sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
              " persistent database.\n");
      }
      zHistory = getenv("SQLITE_HISTORY");
      if( zHistory ){
        zHistory = strdup(zHistory);
      }else if( (zHome = find_home_dir(0))!=0 ){
        nHistory = strlen30(zHome) + 20;
12503
12504
12505
12506
12507
12508
12509





12510
12511
12512
12513
12514
12515
12516
12795
12796
12797
12798
12799
12800
12801
12802
12803
12804
12805
12806
12807
12808
12809
12810
12811
12812
12813







+
+
+
+
+







      data.in = stdin;
      rc = process_input(&data);
    }
  }
#ifndef SQLITE_SHELL_FIDDLE
  /* In WASM mode we have to leave the db state in place so that
  ** client code can "push" SQL into it after this call returns. */
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( data.expert.pExpert ){
    expertFinish(&data, 1, 0);
  }
#endif
  free(azCmd);
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data, -1);
    close_db(data.db);
  }
  for(i=0; i<ArraySize(data.aAuxDb); i++){
12569
12570
12571
12572
12573
12574
12575
12576

12577
12578
12579
12580
12581
12582
12583
12866
12867
12868
12869
12870
12871
12872

12873
12874
12875
12876
12877
12878
12879
12880







-
+







                         SQLITE_FCNTL_VFS_POINTER, &pVfs);
  }
  return pVfs;
}

/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_db_arg(sqlite3 *arg){
    printf("fiddle_db_arg(%p)\n", (const void*)arg);
    oputf("fiddle_db_arg(%p)\n", (const void*)arg);
    return arg;
}

/*
** Intended to be called via a SharedWorker() while a separate
** SharedWorker() (which manages the wasm module) is performing work
** which should be interrupted. Unfortunately, SharedWorker is not
12595
12596
12597
12598
12599
12600
12601
12602


12603
12604
12605









12606
12607


12608
12609
12610
12611
12612
12613
12614
12892
12893
12894
12895
12896
12897
12898

12899
12900
12901
12902
12903
12904
12905
12906
12907
12908
12909
12910
12911
12912


12913
12914
12915
12916
12917
12918
12919
12920
12921







-
+
+



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







    return globalDb
      ? sqlite3_db_filename(globalDb, zDbName ? zDbName : "main")
      : NULL;
}

/*
** Completely wipes out the contents of the currently-opened database
** but leaves its storage intact for reuse.
** but leaves its storage intact for reuse. If any transactions are
** active, they are forcibly rolled back.
*/
void fiddle_reset_db(void){
  if( globalDb ){
    int rc;
    while( sqlite3_txn_state(globalDb,0)>0 ){
      /*
      ** Resolve problem reported in
      ** https://sqlite.org/forum/forumpost/0b41a25d65
      */
      oputz("Rolling back in-progress transaction.\n");
      sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0);
    }
    int rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
    if( 0==rc ) rc = sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
    rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
    if( 0==rc ) sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
    sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
  }
}

/*
** Uses the current database's VFS xRead to stream the db file's
** contents out to the given callback. The callback gets a single
Changes to src/sqlite.h.in.
416
417
418
419
420
421
422


423
424
425
426
427
428
429
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431







+
+







** <ul>
** <li> The application must ensure that the 1st parameter to sqlite3_exec()
**      is a valid and open [database connection].
** <li> The application must not close the [database connection] specified by
**      the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
**      the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not dereference the arrays or string pointers
**       passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
int sqlite3_exec(
  sqlite3*,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 1st argument to callback */
758
759
760
761
762
763
764
765

766
767
768
769

770
771
772
773
774
775
776
760
761
762
763
764
765
766

767
768
769
770

771
772
773
774
775
776
777
778







-
+



-
+







** <li> [SQLITE_LOCK_SHARED],
** <li> [SQLITE_LOCK_RESERVED],
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
** xLock() upgrades the database file lock.  In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE.  If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE.
*  If the lock is already at or below the requested lock state, then the call
** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
** PENDING, or EXCLUSIVE lock on the file.  It returns true
** if such a lock exists and false otherwise.
**
** The xFileControl() method is a generic interface that allows custom
3950
3951
3952
3953
3954
3955
3956
3957


3958
3959
3960
3961
3962
3963
3964
3965



3966
3967
3968
3969
3970
3971
3972
3952
3953
3954
3955
3956
3957
3958

3959
3960
3961
3962
3963
3964
3965
3966


3967
3968
3969
3970
3971
3972
3973
3974
3975
3976







-
+
+






-
-
+
+
+







** <li> sqlite3_extended_errcode()
** <li> sqlite3_errmsg()
** <li> sqlite3_errmsg16()
** <li> sqlite3_error_offset()
** </ul>
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
** text that describes the error, as either UTF-8 or UTF-16 respectively.
** text that describes the error, as either UTF-8 or UTF-16 respectively,
** or NULL if no error message is available.
** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
** ^The sqlite3_errstr() interface returns the English-language text
** that describes the [result code], as UTF-8.
** ^The sqlite3_errstr(E) interface returns the English-language text
** that describes the [result code] E, as UTF-8, or NULL if E is not an
** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
** ^If the most recent error references a specific token in the input
** SQL, the sqlite3_error_offset() interface returns the byte offset
** of the start of that token.  ^The byte offset returned by
** sqlite3_error_offset() assumes that the input SQL is UTF8.
8033
8034
8035
8036
8037
8038
8039
8040
8041
8042





8043
8044
8045
8046
8047
8048
8049
8037
8038
8039
8040
8041
8042
8043



8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055







-
-
-
+
+
+
+
+







** In such cases, the
** mutex must be exited an equal number of times before another thread
** can enter.)^  If the same thread tries to enter any mutex other
** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined.
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try().  On those systems, sqlite3_mutex_try()
** will always return SQLITE_BUSY. The SQLite core only ever uses
** sqlite3_mutex_try() as an optimization so this is acceptable
** behavior.)^
** will always return SQLITE_BUSY. In most cases the SQLite core only uses
** sqlite3_mutex_try() as an optimization, so this is acceptable
** behavior. The exceptions are unix builds that set the 
** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
** sqlite3_mutex_try() is required.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread.   The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
8294
8295
8296
8297
8298
8299
8300

8301
8302

8303
8304
8305
8306
8307
8308
8309
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317







+


+







#define SQLITE_TESTCTRL_BITVEC_TEST              8
#define SQLITE_TESTCTRL_FAULT_INSTALL            9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS     10
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14  /* NOT USED */
#define SQLITE_TESTCTRL_JSON_SELFCHECK          14
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
#define SQLITE_TESTCTRL_ROWID_IN_VIEW           16
#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
#define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
#define SQLITE_TESTCTRL_NEVER_CORRUPT           20
#define SQLITE_TESTCTRL_VDBE_COVERAGE           21
Changes to src/sqliteInt.h.
323
324
325
326
327
328
329













330
331
332
333
334
335
336
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







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







** SEH support if the -DSQLITE_OMIT_SEH option is given.
*/
#if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH)
# define SQLITE_USE_SEH 1
#else
# undef SQLITE_USE_SEH
#endif

/*
** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly
** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0
*/
#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1
  /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */
# undef SQLITE_DIRECT_OVERFLOW_READ
#else
  /* In all other cases, enable */
# define SQLITE_DIRECT_OVERFLOW_READ 1
#endif


/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
** threadsafe.  1 means the library is serialized which is the highest
** level of threadsafety.  2 means the library is multithreaded - multiple
** threads can use SQLite as long as no two threads try to use the same
591
592
593
594
595
596
597


598
599
600
601
602
603
604
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619







+
+








/*
** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE
*/
#if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE)
# define SQLITE_OMIT_ALTERTABLE
#endif

#define SQLITE_DIGIT_SEPARATOR '_'

/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits.  This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
*/
#define IS_BIG_INT(X)  (((X)&~(i64)0xffffffff)!=0)
869
870
871
872
873
874
875
876

877
878
879
880
881
882
883
884
885
886
887
888
889
890

891
892
893
894
895
896
897
898







-
+







** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
*/
#ifndef SQLITE_PTRSIZE
# if defined(__SIZEOF_POINTER__)
#   define SQLITE_PTRSIZE __SIZEOF_POINTER__
# elif defined(i386)     || defined(__i386__)   || defined(_M_IX86) ||    \
       defined(_M_ARM)   || defined(__arm__)    || defined(__x86)   ||    \
      (defined(__APPLE__) && defined(__POWERPC__)) ||                     \
      (defined(__APPLE__) && defined(__ppc__)) ||                         \
      (defined(__TOS_AIX__) && !defined(__64BIT__))
#   define SQLITE_PTRSIZE 4
# else
#   define SQLITE_PTRSIZE 8
# endif
#endif

1106
1107
1108
1109
1110
1111
1112

1113
1114
1115
1116
1117
1118
1119
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135







+







**   0x00001000     LEFT JOIN simplifies to JOIN
**   0x00002000     Constant propagation
**   0x00004000     Push-down optimization
**   0x00008000     After all FROM-clause analysis
**   0x00010000     Beginning of DELETE/INSERT/UPDATE processing
**   0x00020000     Transform DISTINCT into GROUP BY
**   0x00040000     SELECT tree dump after all code has been generated
**   0x00080000     NOT NULL strength reduction
*/

/*
** Macros for "wheretrace"
*/
extern u32 sqlite3WhereTrace;
#if defined(SQLITE_DEBUG) \
1579
1580
1581
1582
1583
1584
1585




1586
1587
1588
1589
1590
1591
1592
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612







+
+
+
+







*/
#define SQLITE_FUNC_HASH_SZ 23
struct FuncDefHash {
  FuncDef *a[SQLITE_FUNC_HASH_SZ];       /* Hash table for functions */
};
#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)

#if defined(SQLITE_USER_AUTHENTICATION)
# warning  "The SQLITE_USER_AUTHENTICATION extension is deprecated. \
 See ext/userauth/user-auth.txt for details."
#endif
#ifdef SQLITE_USER_AUTHENTICATION
/*
** Information held in the "sqlite3" database connection object and used
** to manage user authentication.
*/
typedef struct sqlite3_userauth sqlite3_userauth;
struct sqlite3_userauth {
2110
2111
2112
2113
2114
2115
2116
2117

2118
2119
2120
2121

2122
2123
2124
2125
2126
2127
2128
2130
2131
2132
2133
2134
2135
2136

2137
2138
2139
2140

2141
2142
2143
2144
2145
2146
2147
2148







-
+



-
+







   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
  {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
  {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
   xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, iArg, xFunc) \
#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \
  {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\
   SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\
   ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \
   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
   SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
  {nArg, SQLITE_FUNC_BUILTIN|\
   SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
   SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
#define TEST_FUNC(zName, nArg, iArg, mFlags) \
  {nArg, SQLITE_FUNC_BUILTIN|\
         SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
2455
2456
2457
2458
2459
2460
2461
2462

2463
2464
2465
2466
2467
2468
2469
2470
2475
2476
2477
2478
2479
2480
2481

2482

2483
2484
2485
2486
2487
2488
2489







-
+
-







#define TF_HasPrimaryKey  0x00000004 /* Table has a primary key */
#define TF_Autoincrement  0x00000008 /* Integer primary key is autoincrement */
#define TF_HasStat1       0x00000010 /* nRowLogEst set from sqlite_stat1 */
#define TF_HasVirtual     0x00000020 /* Has one or more VIRTUAL columns */
#define TF_HasStored      0x00000040 /* Has one or more STORED columns */
#define TF_HasGenerated   0x00000060 /* Combo: HasVirtual + HasStored */
#define TF_WithoutRowid   0x00000080 /* No rowid.  PRIMARY KEY is the key */
#define TF_StatsUsed      0x00000100 /* Query planner decisions affected by
#define TF_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */
                                     ** Index.aiRowLogEst[] values */
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
#define TF_OOOHidden      0x00000400 /* Out-of-Order hidden columns */
#define TF_HasNotNull     0x00000800 /* Contains NOT NULL constraints */
#define TF_Shadow         0x00001000 /* True for a shadow table */
#define TF_HasStat4       0x00002000 /* STAT4 info available for this table */
#define TF_Ephemeral      0x00004000 /* An ephemeral table */
#define TF_Eponymous      0x00008000 /* An eponymous virtual table */
2511
2512
2513
2514
2515
2516
2517









2518
2519
2520
2521
2522
2523
2524
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552







+
+
+
+
+
+
+
+
+







#  define IsOrdinaryHiddenColumn(X) 0
#endif


/* Does the table have a rowid */
#define HasRowid(X)     (((X)->tabFlags & TF_WithoutRowid)==0)
#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)

/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is
** available.  By default, this macro is false
*/
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
# define ViewCanHaveRowid     0
#else
# define ViewCanHaveRowid     (sqlite3Config.mNoVisibleRowid==0)
#endif

/*
** Each foreign key constraint is an instance of the following structure.
**
** A foreign key is associated with two tables.  The "from" table is
** the table that contains the REFERENCES clause that creates the foreign
** key.  The "to" table is the table that is named in the REFERENCES clause.
2749
2750
2751
2752
2753
2754
2755

2756
2757
2758
2759
2760
2761
2762
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791







+







  unsigned idxType:2;      /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
  unsigned bUnordered:1;   /* Use this index for == or IN queries only */
  unsigned uniqNotNull:1;  /* True if UNIQUE and NOT NULL for all columns */
  unsigned isResized:1;    /* True if resizeIndexObject() has been called */
  unsigned isCovering:1;   /* True if this is a covering index */
  unsigned noSkipScan:1;   /* Do not try to use skip-scan if true */
  unsigned hasStat1:1;     /* aiRowLogEst values come from sqlite_stat1 */
  unsigned bLowQual:1;     /* sqlite_stat1 says this is a low-quality index */
  unsigned bNoQuery:1;     /* Do not use this index to optimize queries */
  unsigned bAscKeyBug:1;   /* True if the bba7b69f9849b5bf bug applies */
  unsigned bHasVCol:1;     /* Index references one or more VIRTUAL columns */
  unsigned bHasExpr:1;     /* Index contains an expression, either a literal
                           ** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
  int nSample;             /* Number of elements in aSample[] */
2862
2863
2864
2865
2866
2867
2868

2869
2870
2871
2872
2873
2874
2875
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905







+







    Expr *pFExpr;            /* Expression encoding the function */
    FuncDef *pFunc;          /* The aggregate function implementation */
    int iDistinct;           /* Ephemeral table used to enforce DISTINCT */
    int iDistAddr;           /* Address of OP_OpenEphemeral */
    int iOBTab;              /* Ephemeral table to implement ORDER BY */
    u8 bOBPayload;           /* iOBTab has payload columns separate from key */
    u8 bOBUnique;            /* Enforce uniqueness on iOBTab keys */
    u8 bUseSubtype;          /* Transfer subtype info through sorter */
  } *aFunc;
  int nFunc;              /* Number of entries in aFunc[] */
  u32 selId;              /* Select to which this AggInfo belongs */
#ifdef SQLITE_DEBUG
  Select *pSelect;        /* SELECT statement that this AggInfo supports */
#endif
};
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255






3256
3257
3258
3259
3260
3261
3262
3275
3276
3277
3278
3279
3280
3281




3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294







-
-
-
-
+
+
+
+
+
+







** jointype expresses the join between the table and the previous table.
**
** In the colUsed field, the high-order bit (bit 63) is set if the table
** contains more than 63 columns and the 64-th or later column is used.
**
** Union member validity:
**
**    u1.zIndexedBy          fg.isIndexedBy && !fg.isTabFunc
**    u1.pFuncArg            fg.isTabFunc   && !fg.isIndexedBy
**    u2.pIBIndex            fg.isIndexedBy && !fg.isCte
**    u2.pCteUse             fg.isCte       && !fg.isIndexedBy
**    u1.zIndexedBy      fg.isIndexedBy && !fg.isTabFunc
**    u1.pFuncArg        fg.isTabFunc   && !fg.isIndexedBy
**    u1.nRow            !fg.isTabFunc  && !fg.isIndexedBy
**
**    u2.pIBIndex        fg.isIndexedBy && !fg.isCte
**    u2.pCteUse         fg.isCte       && !fg.isIndexedBy
*/
struct SrcItem {
  Schema *pSchema;  /* Schema to which this item is fixed */
  char *zDatabase;  /* Name of database holding this table */
  char *zName;      /* Name of the table */
  char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
  Table *pTab;      /* An SQL table corresponding to zName */
3286
3287
3288
3289
3290
3291
3292

3293
3294
3295
3296
3297
3298
3299
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332







+







    Expr *pOn;        /* fg.isUsing==0 =>  The ON clause of a join */
    IdList *pUsing;   /* fg.isUsing==1 =>  The USING clause of a join */
  } u3;
  Bitmask colUsed;  /* Bit N set if column N used. Details above for N>62 */
  union {
    char *zIndexedBy;    /* Identifier from "INDEXED BY <zIndex>" clause */
    ExprList *pFuncArg;  /* Arguments to table-valued-function */
    u32 nRow;            /* Number of rows in a VALUES clause */
  } u1;
  union {
    Index *pIBIndex;  /* Index structure corresponding to u1.zIndexedBy */
    CteUse *pCteUse;  /* CTE Usage info when fg.isCte is true */
  } u2;
};

3395
3396
3397
3398
3399
3400
3401

3402
3403
3404
3405
3406
3407
3408
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442







+







    Upsert *pUpsert;     /* ON CONFLICT clause information from an upsert */
    int iBaseReg;        /* For TK_REGISTER when parsing RETURNING */
  } uNC;
  NameContext *pNext;  /* Next outer name context.  NULL for outermost */
  int nRef;            /* Number of names resolved by this context */
  int nNcErr;          /* Number of errors encountered while resolving names */
  int ncFlags;         /* Zero or more NC_* flags defined below */
  u32 nNestedSelect;   /* Number of nested selects using this NC */
  Select *pWinSelect;  /* SELECT statement for any window functions */
};

/*
** Allowed values for the NameContext, ncFlags field.
**
** Value constraints (all checked via assert()):
3428
3429
3430
3431
3432
3433
3434

3435
3436
3437
3438
3439
3440
3441
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476







+







#define NC_Complex   0x002000 /* True if a function or subquery seen */
#define NC_AllowWin  0x004000 /* Window functions are allowed here */
#define NC_HasWin    0x008000 /* One or more window functions seen */
#define NC_IsDDL     0x010000 /* Resolving names in a CREATE statement */
#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
#define NC_FromDDL   0x040000 /* SQL text comes from sqlite_schema */
#define NC_NoSelect  0x080000 /* Do not descend into sub-selects */
#define NC_Where     0x100000 /* Processing WHERE clause of a SELECT */
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */

/*
** An instance of the following object describes a single ON CONFLICT
** clause in an upsert.
**
** The pUpsertTarget field is only set if the ON CONFLICT clause includes
3451
3452
3453
3454
3455
3456
3457

3458
3459
3460
3461
3462
3463
3464
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500







+







struct Upsert {
  ExprList *pUpsertTarget;  /* Optional description of conflict target */
  Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */
  ExprList *pUpsertSet;     /* The SET clause from an ON CONFLICT UPDATE */
  Expr *pUpsertWhere;       /* WHERE clause for the ON CONFLICT UPDATE */
  Upsert *pNextUpsert;      /* Next ON CONFLICT clause in the list */
  u8 isDoUpdate;            /* True for DO UPDATE.  False for DO NOTHING */
  u8 isDup;                 /* True if 2nd or later with same pUpsertIdx */
  /* Above this point is the parse tree for the ON CONFLICT clauses.
  ** The next group of fields stores intermediate data. */
  void *pToFree;            /* Free memory when deleting the Upsert object */
  /* All fields above are owned by the Upsert object and must be freed
  ** when the Upsert is destroyed.  The fields below are used to transfer
  ** information from the INSERT processing down into the UPDATE processing
  ** while generating code.  The fields below are owned by the INSERT
3784
3785
3786
3787
3788
3789
3790

3791
3792
3793
3794
3795
3796
3797
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834







+







  u8 isMultiWrite;     /* True if statement may modify/insert multiple rows */
  u8 mayAbort;         /* True if statement may throw an ABORT exception */
  u8 hasCompound;      /* Need to invoke convertCompoundSelectToSubquery() */
  u8 okConstFactor;    /* OK to factor out constants */
  u8 disableLookaside; /* Number of times lookaside has been disabled */
  u8 prepFlags;        /* SQLITE_PREPARE_* flags */
  u8 withinRJSubrtn;   /* Nesting level for RIGHT JOIN body subroutines */
  u8 bHasWith;         /* True if statement contains WITH */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
  u8 earlyCleanup;     /* OOM inside sqlite3ParserAddCleanup() */
#endif
#ifdef SQLITE_DEBUG
  u8 ifNotExists;      /* Might be true if IF NOT EXISTS.  Assert()s only */
#endif
  int nRangeReg;       /* Size of the temporary register block */
4111
4112
4113
4114
4115
4116
4117



4118
4119
4120
4121
4122
4123
4124
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164







+
+
+







**       when the reference count reaches zero.
**
**   2.  Use sqlite3RCStrUnref() to free an RCStr string rather than
**       sqlite3_free()
**
**   3.  Make a (read-only) copy of a read-only RCStr string using
**       sqlite3RCStrRef().
**
** "String" is in the name, but an RCStr object can also be used to hold
** binary data.
*/
struct RCStr {
  u64 nRCRef;            /* Number of references */
  /* Total structure size should be a multiple of 8 bytes for alignment */
};

/*
4169
4170
4171
4172
4173
4174
4175



4176
4177
4178
4179
4180
4181
4182
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225







+
+
+







  u8 bCoreMutex;                    /* True to enable core mutexing */
  u8 bFullMutex;                    /* True to enable full mutexing */
  u8 bOpenUri;                      /* True to interpret filenames as URIs */
  u8 bUseCis;                       /* Use covering indices for full-scans */
  u8 bSmallMalloc;                  /* Avoid large memory allocations if true */
  u8 bExtraSchemaChecks;            /* Verify type,name,tbl_name in schema */
  u8 bUseLongDouble;                /* Make use of long double */
#ifdef SQLITE_DEBUG
  u8 bJsonSelfcheck;                /* Double-check JSON parsing */
#endif
  int mxStrlen;                     /* Maximum string length */
  int neverCorrupt;                 /* Database is always well-formed */
  int szLookaside;                  /* Default lookaside buffer size */
  int nLookaside;                   /* Default lookaside buffer count */
  int nStmtSpill;                   /* Stmt-journal spill-to-disk threshold */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */
  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
4216
4217
4218
4219
4220
4221
4222





4223
4224
4225
4226
4227
4228
4229
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277







+
+
+
+
+







#endif
#ifndef SQLITE_OMIT_DESERIALIZE
  sqlite3_int64 mxMemdbSize;        /* Default max memdb size */
#endif
#ifndef SQLITE_UNTESTABLE
  int (*xTestCallback)(int);        /* Invoked by sqlite3FaultSim() */
#endif
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
  u32 mNoVisibleRowid;              /* TF_NoVisibleRowid if the ROWID_IN_VIEW
                                    ** feature is disabled.  0 if rowids can
                                    ** occur in views. */
#endif
  int bLocaltimeFault;              /* True to fail localtime() calls */
  int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */
  int iOnceResetThreshold;          /* When to reset OP_Once counters */
  u32 szSorterRef;                  /* Min size in bytes to use sorter-refs */
  unsigned int iPrngSeed;           /* Alternative fixed seed for the PRNG */
  /* vvvv--- must be last ---vvv */
#ifdef SQLITE_DEBUG
4451
4452
4453
4454
4455
4456
4457



4458
4459
4460
4461
4462
4463
4464
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515







+
+
+







  int iArgCol;            /* Offset of first argument for this function */
  int regOne;             /* Register containing constant value 1 */
  int regStartRowid;
  int regEndRowid;
  u8 bExprArgs;           /* Defer evaluation of window function arguments
                          ** due to the SQLITE_SUBTYPE flag */
};

Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow);
void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal);

#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3WindowDelete(sqlite3*, Window*);
void sqlite3WindowUnlinkFromSelect(Window*);
void sqlite3WindowListDelete(sqlite3 *db, Window *p);
Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
void sqlite3WindowAttach(Parse*, Expr*, Window*);
4766
4767
4768
4769
4770
4771
4772

4773
4774
4775
4776
4777
4778
4779
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831







+







void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ProgressCheck(Parse*);
void sqlite3ErrorMsg(Parse*, const char*, ...);
int sqlite3ErrorToParser(sqlite3*,int);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
void sqlite3DequoteToken(Token*);
void sqlite3DequoteNumber(Parse*, Expr*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);
void sqlite3ReleaseTempReg(Parse*,int);
int sqlite3GetTempRange(Parse*,int);
4795
4796
4797
4798
4799
4800
4801

4802
4803
4804
4805
4806
4807
4808
4809
4810

4811
4812
4813
4814
4815
4816
4817
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871







+









+







Expr *sqlite3ExprSimplifiedAndOr(Expr*);
Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*);
void sqlite3ExprOrderByAggregateError(Parse*,Expr*);
void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
void sqlite3ExprDelete(sqlite3*, Expr*);
void sqlite3ExprDeleteGeneric(sqlite3*,void*);
void sqlite3ExprDeferredDelete(Parse*, Expr*);
void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
Select *sqlite3ExprListToValues(Parse*, int, ExprList*);
void sqlite3ExprListSetSortOrder(ExprList*,int,int);
void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
void sqlite3ExprListDeleteGeneric(sqlite3*,void*);
u32 sqlite3ExprListFlags(const ExprList*);
int sqlite3IndexHasDuplicateRootPage(Index*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
int sqlite3InitOne(sqlite3*, int, char**, u32);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
#ifndef SQLITE_OMIT_VIRTUALTABLE
4894
4895
4896
4897
4898
4899
4900

4901
4902
4903
4904
4905
4906
4907
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962







+








#if SQLITE_MAX_ATTACHED>30
  int sqlite3DbMaskAllZero(yDbMask);
#endif
void sqlite3DropTable(Parse*, SrcList*, int, int);
void sqlite3CodeDropTable(Parse*, Table*, int, int);
void sqlite3DeleteTable(sqlite3*, Table*);
void sqlite3DeleteTableGeneric(sqlite3*, void*);
void sqlite3FreeIndex(sqlite3*, Index*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
  void sqlite3AutoincrementBegin(Parse *pParse);
  void sqlite3AutoincrementEnd(Parse *pParse);
#else
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
4930
4931
4932
4933
4934
4935
4936

4937
4938
4939
4940
4941
4942
4943
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999







+







void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
                          Expr*, int, int, u8);
void sqlite3DropIndex(Parse*, SrcList*, int);
int sqlite3Select(Parse*, Select*, SelectDest*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
                         Expr*,ExprList*,u32,Expr*);
void sqlite3SelectDelete(sqlite3*, Select*);
void sqlite3SelectDeleteGeneric(sqlite3*,void*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
#endif
void sqlite3CodeChangeCount(Vdbe*,int,const char*);
5015
5016
5017
5018
5019
5020
5021
5022

5023
5024
5025
5026
5027
5028
5029
5030
5071
5072
5073
5074
5075
5076
5077

5078

5079
5080
5081
5082
5083
5084
5085







-
+
-







void sqlite3EndTransaction(Parse*,int);
void sqlite3Savepoint(Parse*, int, Token*);
void sqlite3CloseSavepoints(sqlite3 *);
void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
u32 sqlite3IsTrueOrFalse(const char*);
int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*);
int sqlite3ExprIsConstant(Expr*);
int sqlite3ExprIsConstant(Parse*,Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int);
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
int sqlite3ExprContainsSubquery(Expr*);
#endif
5156
5157
5158
5159
5160
5161
5162

5163
5164
5165
5166
5167
5168
5169
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225







+







int sqlite3GetUInt32(const char*, u32*);
int sqlite3Atoi(const char*);
#ifndef SQLITE_OMIT_UTF16
int sqlite3Utf16ByteLen(const void *pData, int nChar);
#endif
int sqlite3Utf8CharLen(const char *pData, int nByte);
u32 sqlite3Utf8Read(const u8**);
int sqlite3Utf8ReadLimited(const u8*, int, u32*);
LogEst sqlite3LogEst(u64);
LogEst sqlite3LogEstAdd(LogEst,LogEst);
LogEst sqlite3LogEstFromDouble(double);
u64 sqlite3LogEstToInt(LogEst);
VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
const char *sqlite3VListNumToName(VList*,int);
int sqlite3VListNameToNum(VList*,const char*,int);
5502
5503
5504
5505
5506
5507
5508

5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521

5522
5523
5524
5525
5526
5527
5528
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577

5578
5579
5580
5581
5582
5583
5584
5585







+












-
+







  int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
#endif
#ifndef SQLITE_OMIT_CTE
  Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
  void sqlite3CteDelete(sqlite3*,Cte*);
  With *sqlite3WithAdd(Parse*,With*,Cte*);
  void sqlite3WithDelete(sqlite3*,With*);
  void sqlite3WithDeleteGeneric(sqlite3*,void*);
  With *sqlite3WithPush(Parse*, With*, u8);
#else
# define sqlite3CteNew(P,T,E,S)   ((void*)0)
# define sqlite3CteDelete(D,C)
# define sqlite3CteWithAdd(P,W,C) ((void*)0)
# define sqlite3WithDelete(x,y)
# define sqlite3WithPush(x,y,z) ((void*)0)
#endif
#ifndef SQLITE_OMIT_UPSERT
  Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
  void sqlite3UpsertDelete(sqlite3*,Upsert*);
  Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
  int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
  int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*);
  void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
  Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
  int sqlite3UpsertNextIsIPK(Upsert*);
#else
#define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0)
#define sqlite3UpsertDelete(x,y)
#define sqlite3UpsertDup(x,y)         ((Upsert*)0)
Changes to src/sqliteLimit.h.
183
184
185
186
187
188
189
190

191
192
193
194
195
196
197
183
184
185
186
187
188
189

190
191
192
193
194
195
196
197







-
+







** Maximum number of pages in one database file.
**
** This is really just the default value for the max_page_count pragma.
** This value can be lowered (or raised) at run-time using that the
** max_page_count macro.
*/
#ifndef SQLITE_MAX_PAGE_COUNT
# define SQLITE_MAX_PAGE_COUNT 1073741823
# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */
#endif

/*
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
** operator.
*/
#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
Changes to src/status.c.
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
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







-
+












-
+







    case SQLITE_DBSTATUS_CACHE_SPILL:
      op = SQLITE_DBSTATUS_CACHE_WRITE+1;
      /* no break */ deliberate_fall_through
    case SQLITE_DBSTATUS_CACHE_HIT:
    case SQLITE_DBSTATUS_CACHE_MISS:
    case SQLITE_DBSTATUS_CACHE_WRITE:{
      int i;
      int nRet = 0;
      u64 nRet = 0;
      assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
      assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );

      for(i=0; i<db->nDb; i++){
        if( db->aDb[i].pBt ){
          Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
          sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
        }
      }
      *pHighwater = 0; /* IMP: R-42420-56072 */
                       /* IMP: R-54100-20147 */
                       /* IMP: R-29431-39229 */
      *pCurrent = nRet;
      *pCurrent = (int)nRet & 0x7fffffff;
      break;
    }

    /* Set *pCurrent to non-zero if there are unresolved deferred foreign
    ** key constraints.  Set *pCurrent to zero if all foreign key constraints
    ** have been satisfied.  The *pHighwater is always set to zero.
    */
Changes to src/test1.c.
986
987
988
989
990
991
992

































993
994
995
996
997
998
999
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032







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







  int argc,  
  sqlite3_value **argv
){
  sqlite3_int64 v = sqlite3_value_int64(argv[0]);
  sqlite3_result_int64(context, v);
  sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, context);
}

/*
** These SQL functions attempt to return a value (their first argument)
** that has been modified to have multiple datatypes.  For example both
** TEXT and INTEGER.
*/
static void addTextTypeFunction(
  sqlite3_context *context, 
  int argc,  
  sqlite3_value **argv
){
  (void)sqlite3_value_text(argv[0]);
  (void)argc;
  sqlite3_result_value(context, argv[0]);
}
static void addIntTypeFunction(
  sqlite3_context *context, 
  int argc,  
  sqlite3_value **argv
){
  (void)sqlite3_value_int64(argv[0]);
  (void)argc;
  sqlite3_result_value(context, argv[0]);
}
static void addRealTypeFunction(
  sqlite3_context *context, 
  int argc,  
  sqlite3_value **argv
){
  (void)sqlite3_value_double(argv[0]);
  (void)argc;
  sqlite3_result_value(context, argv[0]);
}

/*
** SQL function:  strtod(X)
**
** Use the C-library strtod() function to convert string X into a double.
** Used for comparing the accuracy of SQLite's internal text-to-float conversion
** routines against the C-library.
1098
1099
1100
1101
1102
1103
1104
















1105
1106
1107
1108
1109
1110
1111
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







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







  /* The intreal() function converts its argument to an integer and returns
  ** it as a MEM_IntReal.
  */
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "intreal", 1, SQLITE_UTF8,
          0, intrealFunction, 0, 0);
  }

  /* The add_text_type(), add_int_type(), and add_real_type() functions
  ** attempt to return a value that has multiple datatypes.
  */
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "add_text_type", 1, SQLITE_UTF8,
          0, addTextTypeFunction, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "add_int_type", 1, SQLITE_UTF8,
          0, addIntTypeFunction, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "add_real_type", 1, SQLITE_UTF8,
          0, addRealTypeFunction, 0, 0);
  }

  /* Functions strtod() and dtostr() work as in the shell.  These routines
  ** use the standard C library to convert between floating point and
  ** text.  This is used to compare SQLite's internal conversion routines
  ** against the standard library conversion routines.
  **
  ** Both routines copy/pasted from the shell.c.in implementation
8116
8117
8118
8119
8120
8121
8122

8123
8124
8125
8126
8127
8128
8129
8165
8166
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179







+







  extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*);
#endif
  extern int sqlite3_qpvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_randomjson_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
8148
8149
8150
8151
8152
8153
8154

8155
8156
8157
8158
8159
8160
8161
8198
8199
8200
8201
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212







+







    { "ieee754",               sqlite3_ieee_init                 },
    { "nextchar",              sqlite3_nextchar_init             },
    { "percentile",            sqlite3_percentile_init           },
#ifndef SQLITE_OMIT_VIRTUALTABLE
    { "prefixes",              sqlite3_prefixes_init             },
#endif
    { "qpvtab",                sqlite3_qpvtab_init               },
    { "randomjson",            sqlite3_randomjson_init           },
    { "regexp",                sqlite3_regexp_init               },
    { "remember",              sqlite3_remember_init             },
    { "series",                sqlite3_series_init               },
    { "spellfix",              sqlite3_spellfix_init             },
    { "totype",                sqlite3_totype_init               },
    { "unionvtab",             sqlite3_unionvtab_init            },
    { "wholenumber",           sqlite3_wholenumber_init          },
Changes to src/test_func.c.
690
691
692
693
694
695
696
697


698
699
700
701
702
703
704
690
691
692
693
694
695
696

697
698
699
700
701
702
703
704
705







-
+
+







    { "test_isolation",        2, SQLITE_UTF8, test_isolation},
    { "test_counter",          1, SQLITE_UTF8, counterFunc},
    { "real2hex",              1, SQLITE_UTF8, real2hex},
    { "test_decode",           1, SQLITE_UTF8, test_decode},
    { "test_extract",          2, SQLITE_UTF8, test_extract},
    { "test_zeroblob",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob},
    { "test_getsubtype",       1, SQLITE_UTF8, test_getsubtype},
    { "test_setsubtype",       2, SQLITE_UTF8, test_setsubtype},
    { "test_setsubtype",       2, SQLITE_UTF8|SQLITE_RESULT_SUBTYPE,
                                               test_setsubtype},
    { "test_frombind",        -1, SQLITE_UTF8, test_frombind},
  };
  int i;

  for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
    sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
        aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0);
Changes to src/test_tclsh.c.
104
105
106
107
108
109
110

111
112
113
114
115
116
117
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118







+







#ifdef SQLITE_ENABLE_ZIPVFS
  extern int Zipvfs_Init(Tcl_Interp*);
#endif
  extern int TestExpert_Init(Tcl_Interp*);
  extern int Sqlitetest_window_Init(Tcl_Interp *);
  extern int Sqlitetestvdbecov_Init(Tcl_Interp *);
  extern int TestRecover_Init(Tcl_Interp*);
  extern int Sqlitetestintck_Init(Tcl_Interp*);

  Tcl_CmdInfo cmdInfo;

  /* Since the primary use case for this binary is testing of SQLite,
  ** be sure to generate core files if we crash */
#if defined(unix)
  { struct rlimit x;
171
172
173
174
175
176
177

178
179
180
181
182
183
184
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186







+







#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
  Sqlitetestfts3_Init(interp);
#endif
  TestExpert_Init(interp);
  Sqlitetest_window_Init(interp);
  Sqlitetestvdbecov_Init(interp);
  TestRecover_Init(interp);
  Sqlitetestintck_Init(interp);

  Tcl_CreateObjCommand(
      interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
  );
  return 0;
}

Changes to src/tokenize.c.
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
433
434
435
436
437
438
439
440



441
442
443
444
445
446
447
448
449
450
451
452

453
454
455
456
457
458
459
460
461














462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498







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

+
+
-
+
+
+
+
+
+
+
+

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

+







      testcase( z[0]=='0' );  testcase( z[0]=='1' );  testcase( z[0]=='2' );
      testcase( z[0]=='3' );  testcase( z[0]=='4' );  testcase( z[0]=='5' );
      testcase( z[0]=='6' );  testcase( z[0]=='7' );  testcase( z[0]=='8' );
      testcase( z[0]=='9' );  testcase( z[0]=='.' );
      *tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
      if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
        for(i=3; 1; i++){
        for(i=3; sqlite3Isxdigit(z[i]); i++){}
        return i;
      }
          if( sqlite3Isxdigit(z[i])==0 ){
            if( z[i]==SQLITE_DIGIT_SEPARATOR ){
              *tokenType = TK_QNUMBER;
            }else{
              break;
            }
          }
        }
      }else
#endif
        {
        for(i=0; 1; i++){
      for(i=0; sqlite3Isdigit(z[i]); i++){}
          if( sqlite3Isdigit(z[i])==0 ){
            if( z[i]==SQLITE_DIGIT_SEPARATOR ){
              *tokenType = TK_QNUMBER;
            }else{
              break;
            }
          }
        }
#ifndef SQLITE_OMIT_FLOATING_POINT
      if( z[i]=='.' ){
        i++;
        while( sqlite3Isdigit(z[i]) ){ i++; }
        *tokenType = TK_FLOAT;
      }
      if( (z[i]=='e' || z[i]=='E') &&
           ( sqlite3Isdigit(z[i+1]) 
            || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
           )
      ){
        i += 2;
        while( sqlite3Isdigit(z[i]) ){ i++; }
        *tokenType = TK_FLOAT;
      }
        if( z[i]=='.' ){
          if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
          for(i++; 1; i++){
            if( sqlite3Isdigit(z[i])==0 ){
              if( z[i]==SQLITE_DIGIT_SEPARATOR ){
                *tokenType = TK_QNUMBER;
              }else{
                break;
              }
            }
          }
        }
        if( (z[i]=='e' || z[i]=='E') &&
             ( sqlite3Isdigit(z[i+1]) 
              || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
             )
        ){
          if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
          for(i+=2; 1; i++){
            if( sqlite3Isdigit(z[i])==0 ){
              if( z[i]==SQLITE_DIGIT_SEPARATOR ){
                *tokenType = TK_QNUMBER;
              }else{
                break;
              }
            }
          }
        }
#endif
      }
      while( IdChar(z[i]) ){
        *tokenType = TK_ILLEGAL;
        i++;
      }
      return i;
    }
    case CC_QUOTE2: {
618
619
620
621
622
623
624

625
626
627
628



629
630
631
632
633
634
635
649
650
651
652
653
654
655
656
657
658
659

660
661
662
663
664
665
666
667
668
669







+



-
+
+
+







      pParse->nErr++;
      break;
    }
#ifndef SQLITE_OMIT_WINDOWFUNC
    if( tokenType>=TK_WINDOW ){
      assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
           || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW 
           || tokenType==TK_QNUMBER
      );
#else
    if( tokenType>=TK_SPACE ){
      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL 
           || tokenType==TK_QNUMBER 
      );
#endif /* SQLITE_OMIT_WINDOWFUNC */
      if( AtomicLoad(&db->u1.isInterrupted) ){
        pParse->rc = SQLITE_INTERRUPT;
        pParse->nErr++;
        break;
      }
      if( tokenType==TK_SPACE ){
654
655
656
657
658
659
660
661

662
663
664
665
666
667
668
688
689
690
691
692
693
694

695
696
697
698
699
700
701
702







-
+







      }else if( tokenType==TK_OVER ){
        assert( n==4 );
        tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed);
      }else if( tokenType==TK_FILTER ){
        assert( n==6 );
        tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
      }else{
      }else if( tokenType!=TK_QNUMBER ){
        Token x;
        x.z = zSql;
        x.n = n;
        sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x);
        break;
      }
    }
Changes to src/treeview.c.
777
778
779
780
781
782
783
784

785
786
787
788
789
790
791
777
778
779
780
781
782
783

784
785
786
787
788
789
790
791







-
+







    case TK_BETWEEN: {
      const Expr *pX, *pY, *pZ;
      pX = pExpr->pLeft;
      assert( ExprUseXList(pExpr) );
      assert( pExpr->x.pList->nExpr==2 );
      pY = pExpr->x.pList->a[0].pExpr;
      pZ = pExpr->x.pList->a[1].pExpr;
      sqlite3TreeViewLine(pView, "BETWEEN");
      sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs);
      sqlite3TreeViewExpr(pView, pX, 1);
      sqlite3TreeViewExpr(pView, pY, 1);
      sqlite3TreeViewExpr(pView, pZ, 0);
      break;
    }
    case TK_TRIGGER: {
      /* If the opcode is TK_TRIGGER, then the expression is a reference
Changes to src/upsert.c.
86
87
88
89
90
91
92
93


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

93
94
95
96
97
98
99
100
101







-
+
+







**
** Return SQLITE_OK if everything works, or an error code is something
** is wrong.
*/
int sqlite3UpsertAnalyzeTarget(
  Parse *pParse,     /* The parsing context */
  SrcList *pTabList, /* Table into which we are inserting */
  Upsert *pUpsert    /* The ON CONFLICT clauses */
  Upsert *pUpsert,   /* The ON CONFLICT clauses */
  Upsert *pAll       /* Complete list of all ON CONFLICT clauses */
){
  Table *pTab;            /* That table into which we are inserting */
  int rc;                 /* Result code */
  int iCursor;            /* Cursor used by pTab */
  Index *pIdx;            /* One of the indexes of pTab */
  ExprList *pTarget;      /* The conflict-target clause */
  Expr *pTerm;            /* One term of the conflict-target clause */
189
190
191
192
193
194
195








196
197
198
199
200
201
202
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211







+
+
+
+
+
+
+
+







      }
      if( ii<nn ){
        /* Column ii of the index did not match any term of the conflict target.
        ** Continue the search with the next index. */
        continue;
      }
      pUpsert->pUpsertIdx = pIdx;
      if( sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){
        /* Really this should be an error.  The isDup ON CONFLICT clause will
        ** never fire.  But this problem was not discovered until three years
        ** after multi-CONFLICT upsert was added, and so we silently ignore
        ** the problem to prevent breaking applications that might actually
        ** have redundant ON CONFLICT clauses. */
        pUpsert->isDup = 1;
      }
      break;
    }
    if( pUpsert->pUpsertIdx==0 ){
      char zWhich[16];
      if( nClause==0 && pUpsert->pNextUpsert==0 ){
        zWhich[0] = 0;
      }else{
215
216
217
218
219
220
221

222
223
224






225
226
227
228
229
230
231
224
225
226
227
228
229
230
231



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







+
-
-
-
+
+
+
+
+
+







** conflict target, or if pUpsert is followed by another ON CONFLICT
** clause that targets the INTEGER PRIMARY KEY.
*/
int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
  Upsert *pNext;
  if( NEVER(pUpsert==0) ) return 0;
  pNext = pUpsert->pNextUpsert;
  while( 1 /*exit-by-return*/ ){
  if( pNext==0 ) return 1;
  if( pNext->pUpsertTarget==0 ) return 1;
  if( pNext->pUpsertIdx==0 ) return 1;
    if( pNext==0 ) return 1;
    if( pNext->pUpsertTarget==0 ) return 1;
    if( pNext->pUpsertIdx==0 ) return 1;
    if( !pNext->isDup ) return 0;
    pNext = pNext->pNextUpsert;
  }
  return 0;
}

/*
** Given the list of ON CONFLICT clauses described by pUpsert, and
** a particular index pIdx, return a pointer to the particular ON CONFLICT
** clause that applies to the index.  Or, if the index is not subject to
Changes to src/utf.c.
160
161
162
163
164
165
166



























167





168
169
170
171
172
173
174
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







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







    if( c<0x80
        || (c&0xFFFFF800)==0xD800
        || (c&0xFFFFFFFE)==0xFFFE ){  c = 0xFFFD; }
  }
  return c;
}

/*
** Read a single UTF8 character out of buffer z[], but reading no
** more than n characters from the buffer.  z[] is not zero-terminated.
**
** Return the number of bytes used to construct the character.
**
** Invalid UTF8 might generate a strange result.  No effort is made
** to detect invalid UTF8.
**
** At most 4 bytes will be read out of z[].  The return value will always
** be between 1 and 4.
*/
int sqlite3Utf8ReadLimited(
  const u8 *z,
  int n,
  u32 *piOut
){
  u32 c;
  int i = 1;
  assert( n>0 );
  c = z[0];
  if( c>=0xc0 ){
    c = sqlite3Utf8Trans1[c-0xc0];
    if( n>4 ) n = 4;
    while( i<n && (z[i] & 0xc0)==0x80 ){
      c = (c<<6) + (0x3f & z[i]);
      i++;

    }
  }
  *piOut = c;
  return i;
}


/*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
*/ 
/* #define TRANSLATE_TRACE 1 */
Changes to src/util.c.
137
138
139
140
141
142
143
144

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

144
145
146
147
148
149
150
151







-
+








/*
** Load the sqlite3.iSysErrno field if that is an appropriate thing
** to do based on the SQLite error code in rc.
*/
void sqlite3SystemError(sqlite3 *db, int rc){
  if( rc==SQLITE_IOERR_NOMEM ) return;
#ifdef SQLITE_USE_SEH
#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
  if( rc==SQLITE_IOERR_IN_PAGE ){
    int ii;
    int iErr;
    sqlite3BtreeEnterAll(db);
    for(ii=0; ii<db->nDb; ii++){
      if( db->aDb[ii].pBt ){
        iErr = sqlite3PagerWalSystemErrno(sqlite3BtreePager(db->aDb[ii].pBt));
306
307
308
309
310
311
312






































313
314
315
316
317
318
319
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







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







}
void sqlite3DequoteExpr(Expr *p){
  assert( !ExprHasProperty(p, EP_IntValue) );
  assert( sqlite3Isquote(p->u.zToken[0]) );
  p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted;
  sqlite3Dequote(p->u.zToken);
}

/*
** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken
** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those
** that contain '_' characters that must be removed before further processing.
*/
void sqlite3DequoteNumber(Parse *pParse, Expr *p){
  assert( p!=0 || pParse->db->mallocFailed );
  if( p ){
    const char *pIn = p->u.zToken;
    char *pOut = p->u.zToken;
    int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X'));
    int iValue;
    assert( p->op==TK_QNUMBER );
    p->op = TK_INTEGER;
    do {
      if( *pIn!=SQLITE_DIGIT_SEPARATOR ){
        *pOut++ = *pIn;
        if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT;
      }else{
        if( (bHex==0 && (!sqlite3Isdigit(pIn[-1]) || !sqlite3Isdigit(pIn[1])))
         || (bHex==1 && (!sqlite3Isxdigit(pIn[-1]) || !sqlite3Isxdigit(pIn[1])))
        ){
          sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken);
        }
      }
    }while( *pIn++ );
    if( bHex ) p->op = TK_INTEGER;

    /* tag-20240227-a: If after dequoting, the number is an integer that
    ** fits in 32 bits, then it must be converted into EP_IntValue.  Other
    ** parts of the code expect this.  See also tag-20240227-b. */
    if( p->op==TK_INTEGER && sqlite3GetInt32(p->u.zToken, &iValue) ){
      p->u.iValue = iValue;
      p->flags |= EP_IntValue;
    }
  }
}

/*
** If the input token p is quoted, try to adjust the token to remove
** the quotes.  This is not always possible:
**
**     "abc"     ->   abc
**     "ab""cd"  ->   (not possible because of the interior "")
623
624
625
626
627
628
629



630
631
632
633
634
635
636
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677







+
+
+







      *pResult = (double)r;
    }
  }else{
    double rr[2];
    u64 s2;
    rr[0] = (double)s;
    s2 = (u64)rr[0];
#if defined(_MSC_VER) && _MSC_VER<1700
    if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
#endif
    rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
    if( e>0 ){
      while( e>=100  ){
        e -= 100;
        dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
      }
      while( e>=10   ){
1065
1066
1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
1106
1107
1108
1109
1110
1111
1112

1113
1114
1115
1116
1117
1118
1119
1120







-
+







  assert( v>0 );
  while( v ){  p->zBuf[i--] = (v%10) + '0'; v /= 10; }
  assert( i>=0 && i<sizeof(p->zBuf)-1 );
  p->n = sizeof(p->zBuf) - 1 - i;
  assert( p->n>0 );
  assert( p->n<sizeof(p->zBuf) );
  p->iDP = p->n + exp;
  if( iRound<0 ){
  if( iRound<=0 ){
    iRound = p->iDP - iRound;
    if( iRound==0 && p->zBuf[i+1]>='5' ){
      iRound = 1;
      p->zBuf[i--] = '0';
      p->n++;
      p->iDP++;
    }
Changes to src/vdbe.c.
128
129
130
131
132
133
134
135

136
137
138
139

140
141
142
143
144
145
146
128
129
130
131
132
133
134

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







-
+




+







** Other useful labels for breakpoints include:
**   test_addop_breakpoint(pc,pOp)
**   sqlite3CorruptError(lineno)
**   sqlite3MisuseError(lineno)
**   sqlite3CantopenError(lineno)
*/
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
  static int n = 0;
  static u64 n = 0;
  (void)pc;
  (void)pOp;
  (void)v;
  n++;
  if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */
}
#endif

/*
** Invoke the VDBE coverage callback, if that callback is defined.  This
** feature is used for test suite validation only and does not appear an
** production builds.
1124
1125
1126
1127
1128
1129
1130
1131

1132
1133
1134
1135
1136
1137
1138
1125
1126
1127
1128
1129
1130
1131

1132
1133
1134
1135
1136
1137
1138
1139







-
+







**
** If P2!=0 then the coroutine implementation immediately follows
** this opcode.  So jump over the coroutine implementation to
** address P2.
**
** See also: EndCoroutine
*/
case OP_InitCoroutine: {     /* jump */
case OP_InitCoroutine: {     /* jump0 */
  assert( pOp->p1>0 &&  pOp->p1<=(p->nMem+1 - p->nCursor) );
  assert( pOp->p2>=0 && pOp->p2<p->nOp );
  assert( pOp->p3>=0 && pOp->p3<p->nOp );
  pOut = &aMem[pOp->p1];
  assert( !VdbeMemDynamic(pOut) );
  pOut->u.i = pOp->p3 - 1;
  pOut->flags = MEM_Int;
1177
1178
1179
1180
1181
1182
1183
1184

1185
1186
1187
1188
1189
1190
1191
1178
1179
1180
1181
1182
1183
1184

1185
1186
1187
1188
1189
1190
1191
1192







-
+







** Yield or Return then continue to the next instruction.  But if
** the coroutine launched by this instruction ends with
** EndCoroutine, then jump to P2 rather than continuing with the
** next instruction.
**
** See also: InitCoroutine
*/
case OP_Yield: {            /* in1, jump */
case OP_Yield: {            /* in1, jump0 */
  int pcDest;
  pIn1 = &aMem[pOp->p1];
  assert( VdbeMemDynamic(pIn1)==0 );
  pIn1->flags = MEM_Int;
  pcDest = (int)pIn1->u.i;
  pIn1->u.i = (int)(pOp - aOp);
  REGISTER_TRACE(pOp->p1, pIn1);
1507
1508
1509
1510
1511
1512
1513
1514
1515


1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1508
1509
1510
1511
1512
1513
1514


1515
1516
1517
1518



1519
1520
1521
1522
1523

1524
1525
1526
1527
1528
1529
1530







-
-
+
+


-
-
-





-







    sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
  }
  pOut->enc = encoding;
  UPDATE_MAX_BLOBSIZE(pOut);
  break;
}

/* Opcode: Variable P1 P2 * P4 *
** Synopsis: r[P2]=parameter(P1,P4)
/* Opcode: Variable P1 P2 * * *
** Synopsis: r[P2]=parameter(P1)
**
** Transfer the values of bound parameter P1 into register P2
**
** If the parameter is named, then its name appears in P4.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
case OP_Variable: {            /* out2 */
  Mem *pVar;       /* Value being transferred */

  assert( pOp->p1>0 && pOp->p1<=p->nVar );
  assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) );
  pVar = &p->aVar[pOp->p1 - 1];
  if( sqlite3VdbeMemTooBig(pVar) ){
    goto too_big;
  }
  pOut = &aMem[pOp->p2];
  if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
  memcpy(pOut, pVar, MEMCELLSIZE);
2029
2030
2031
2032
2033
2034
2035
2036

2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047

2048
2049
2050
2051
2052
2053
2054
2026
2027
2028
2029
2030
2031
2032

2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043

2044
2045
2046
2047
2048
2049
2050
2051







-
+










-
+







**
** To force any register to be an integer, just add 0.
*/
case OP_AddImm: {            /* in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  sqlite3VdbeMemIntegerify(pIn1);
  pIn1->u.i += pOp->p2;
  *(u64*)&pIn1->u.i += (u64)pOp->p2;
  break;
}

/* Opcode: MustBeInt P1 P2 * * *
**
** Force the value in register P1 to be an integer.  If the value
** in P1 is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
case OP_MustBeInt: {            /* jump, in1 */
case OP_MustBeInt: {            /* jump0, in1 */
  pIn1 = &aMem[pOp->p1];
  if( (pIn1->flags & MEM_Int)==0 ){
    applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
    if( (pIn1->flags & MEM_Int)==0 ){
      VdbeBranchTaken(1, 2);
      if( pOp->p2==0 ){
        rc = SQLITE_MISMATCH;
2081
2082
2083
2084
2085
2086
2087
2088

2089
2090
2091
2092
2093
2094
2095
2078
2079
2080
2081
2082
2083
2084

2085
2086
2087
2088
2089
2090
2091
2092







-
+







    sqlite3VdbeMemRealify(pIn1);
    REGISTER_TRACE(pOp->p1, pIn1);
  }
  break;
}
#endif

#ifndef SQLITE_OMIT_CAST
#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
/* Opcode: Cast P1 P2 * * *
** Synopsis: affinity(r[P1])
**
** Force the value in register P1 to be the type defined by P2.
**
** <ul>
** <li> P2=='A' &rarr; BLOB
2296
2297
2298
2299
2300
2301
2302


2303

2304
2305
2306
2307
2308
2309
2310
2311


2312

2313
2314
2315
2316
2317
2318
2319
2293
2294
2295
2296
2297
2298
2299
2300
2301

2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312

2313
2314
2315
2316
2317
2318
2319
2320







+
+
-
+








+
+
-
+







          flags3 = pIn3->flags;
        }
        if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
          applyNumericAffinity(pIn3,0);
        }
      }
    }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
      if( (flags1 & MEM_Str)!=0 ){
        pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
      if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
      }else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
        testcase( pIn1->flags & MEM_Int );
        testcase( pIn1->flags & MEM_Real );
        testcase( pIn1->flags & MEM_IntReal );
        sqlite3VdbeMemStringify(pIn1, encoding, 1);
        testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
        flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
        if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
      }
      if( (flags3 & MEM_Str)!=0 ){
        pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
      if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
      }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
        testcase( pIn3->flags & MEM_Int );
        testcase( pIn3->flags & MEM_Real );
        testcase( pIn3->flags & MEM_IntReal );
        sqlite3VdbeMemStringify(pIn3, encoding, 1);
        testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
        flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
      }
3649
3650
3651
3652
3653
3654
3655

3656
3657

3658

3659

3660

3661
3662
3663
3664
3665
3666
3667
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673







+


+

+

+

+







          v = pRec->u.i;
        }
        len = sqlite3SmallTypeSizes[serial_type];
        assert( len>=1 && len<=8 && len!=5 && len!=7 );
        switch( len ){
          default: zPayload[7] = (u8)(v&0xff); v >>= 8;
                   zPayload[6] = (u8)(v&0xff); v >>= 8;
                   /* no break */ deliberate_fall_through
          case 6:  zPayload[5] = (u8)(v&0xff); v >>= 8;
                   zPayload[4] = (u8)(v&0xff); v >>= 8;
                   /* no break */ deliberate_fall_through
          case 4:  zPayload[3] = (u8)(v&0xff); v >>= 8;
                   /* no break */ deliberate_fall_through
          case 3:  zPayload[2] = (u8)(v&0xff); v >>= 8;
                   /* no break */ deliberate_fall_through
          case 2:  zPayload[1] = (u8)(v&0xff); v >>= 8;
                   /* no break */ deliberate_fall_through
          case 1:  zPayload[0] = (u8)(v&0xff);
        }
        zPayload += len;
      }
    }else if( serial_type<0x80 ){
      *(zHdr++) = serial_type;
      if( serial_type>=14 && pRec->n>0 ){
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725




4726
4727
4728
4729
4730
4731
4732
4721
4722
4723
4724
4725
4726
4727




4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738







-
-
-
-
+
+
+
+







** The IdxGE opcode will be skipped if this opcode succeeds, but the
** IdxGE opcode will be used on subsequent loop iterations.  The
** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
** is an equality search.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLT:         /* jump, in3, group, ncycle */
case OP_SeekLE:         /* jump, in3, group, ncycle */
case OP_SeekGE:         /* jump, in3, group, ncycle */
case OP_SeekGT: {       /* jump, in3, group, ncycle */
case OP_SeekLT:         /* jump0, in3, group, ncycle */
case OP_SeekLE:         /* jump0, in3, group, ncycle */
case OP_SeekGE:         /* jump0, in3, group, ncycle */
case OP_SeekGT: {       /* jump0, in3, group, ncycle */
  int res;           /* Comparison result */
  int oc;            /* Opcode */
  VdbeCursor *pC;    /* The cursor to seek */
  UnpackedRecord r;  /* The key to seek for */
  int nField;        /* Number of columns or fields in the key */
  i64 iKey;          /* The rowid we are to seek to */
  int eqOnly;        /* Only interested in == results */
5385
5386
5387
5388
5389
5390
5391
5392

5393
5394
5395
5396
5397
5398
5399
5391
5392
5393
5394
5395
5396
5397

5398
5399
5400
5401
5402
5403
5404
5405







-
+







**
** This opcode leaves the cursor in a state where it cannot be advanced
** in either direction.  In other words, the Next and Prev opcodes will
** not work following this opcode.
**
** See also: Found, NotFound, NoConflict, SeekRowid
*/
case OP_SeekRowid: {        /* jump, in3, ncycle */
case OP_SeekRowid: {        /* jump0, in3, ncycle */
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;
  u64 iKey;

  pIn3 = &aMem[pOp->p3];
  testcase( pIn3->flags & MEM_Int );
6144
6145
6146
6147
6148
6149
6150
6151

6152
6153
6154
6155
6156
6157
6158
6150
6151
6152
6153
6154
6155
6156

6157
6158
6159
6160
6161
6162
6163
6164







-
+







** to the following instruction.
**
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning.  In other words, the cursor is
** configured to use Prev, not Next.
*/
case OP_SeekEnd:             /* ncycle */
case OP_Last: {              /* jump, ncycle */
case OP_Last: {              /* jump0, ncycle */
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
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
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
6221
6222
6223
6224
6225
6226
6227
6228







-
+

-
-
+
+
+
+

-
+






+
+
+






-
+
+
+

+
-
+

+







  if( pOp->p2>0 ){
    VdbeBranchTaken(res!=0,2);
    if( res ) goto jump_to_p2;
  }
  break;
}

/* Opcode: IfSmaller P1 P2 P3 * *
/* Opcode: IfSizeBetween P1 P2 P3 P4 *
**
** Estimate the number of rows in the table P1.  Jump to P2 if that
** estimate is less than approximately 2**(0.1*P3).
** Let N be the approximate number of rows in the table or index
** with cursor P1 and let X be 10*log2(N) if N is positive or -1
** if N is zero. Thus X will be within the range of -1 to 640, inclusive
** Jump to P2 if X is in between P3 and P4, inclusive.
*/
case OP_IfSmaller: {        /* jump */
case OP_IfSizeBetween: {        /* jump */
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;
  i64 sz;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p4type==P4_INT32 );
  assert( pOp->p3>=-1 && pOp->p3<=640 );
  assert( pOp->p4.i>=-1 && pOp->p4.i<=640 );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pCrsr = pC->uc.pCursor;
  assert( pCrsr );
  rc = sqlite3BtreeFirst(pCrsr, &res);
  if( rc ) goto abort_due_to_error;
  if( res==0 ){
  if( res!=0 ){
    sz = -1;  /* -Infinity encoding */
  }else{
    sz = sqlite3BtreeRowCountEst(pCrsr);
    assert( sz>0 );
    if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
    sz = sqlite3LogEst((u64)sz);
  }
  res = sz>=pOp->p3 && sz<=pOp->p4.i;
  VdbeBranchTaken(res!=0,2);
  if( res ) goto jump_to_p2;
  break;
}


/* Opcode: SorterSort P1 P2 * * *
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







-
+







** If P2 is zero, that is an assertion that the P1 table is never
** empty and hence the jump will never be taken.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end.  In other words, the cursor is
** configured to use Next, not Prev.
*/
case OP_Rewind: {        /* jump, ncycle */
case OP_Rewind: {        /* jump0, ncycle */
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p5==0 );
  assert( pOp->p2>=0 && pOp->p2<p->nOp );
6899
6900
6901
6902
6903
6904
6905
6906

6907
6908



6909
6910






6911
6912
6913
6914
6915
6916
6917

6918
6919
6920
6921
6922
6923
6924
6925

6926

6927
6928
6929
6930
6931



6932
6933
6934
6935
6936
6937

6938
6939
6940
6941
6942
6943
6944
6914
6915
6916
6917
6918
6919
6920

6921
6922
6923
6924
6925
6926


6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949

6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972







-
+


+
+
+
-
-
+
+
+
+
+
+







+








+
-
+





+
+
+






+







  assert( pDb->pBt!=0 );
  rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3);
  if( rc ) goto abort_due_to_error;
  pOut->u.i = pgno;
  break;
}

/* Opcode: SqlExec * * * P4 *
/* Opcode: SqlExec P1 P2 * P4 *
**
** Run the SQL statement or statements specified in the P4 string.
**
** The P1 parameter is a bitmask of options:
**
** Disable Auth and Trace callbacks while those statements are running if
** P1 is true.
**    0x0001     Disable Auth and Trace callbacks while the statements
**               in P4 are running.
**
**    0x0002     Set db->nAnalysisLimit to P2 while the statements in
**               P4 are running.
**
*/
case OP_SqlExec: {
  char *zErr;
#ifndef SQLITE_OMIT_AUTHORIZATION
  sqlite3_xauth xAuth;
#endif
  u8 mTrace;
  int savedAnalysisLimit;

  sqlite3VdbeIncrWriteCounter(p, 0);
  db->nSqlExec++;
  zErr = 0;
#ifndef SQLITE_OMIT_AUTHORIZATION
  xAuth = db->xAuth;
#endif
  mTrace = db->mTrace;
  savedAnalysisLimit = db->nAnalysisLimit;
  if( pOp->p1 ){
  if( pOp->p1 & 0x0001 ){
#ifndef SQLITE_OMIT_AUTHORIZATION
    db->xAuth = 0;
#endif
    db->mTrace = 0;
  }
  if( pOp->p1 & 0x0002 ){
    db->nAnalysisLimit = pOp->p2;
  }
  rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
  db->nSqlExec--;
#ifndef SQLITE_OMIT_AUTHORIZATION
  db->xAuth = xAuth;
#endif
  db->mTrace = mTrace;
  db->nAnalysisLimit = savedAnalysisLimit;
  if( zErr || rc ){
    sqlite3VdbeError(p, "%s", zErr);
    sqlite3_free(zErr);
    if( rc==SQLITE_NOMEM ) goto no_mem;
    goto abort_due_to_error;
  }
  break;
7082
7083
7084
7085
7086
7087
7088
7089
7090


7091
7092
7093


7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112

7113
7114
7115

7116
7117
7118


7119
7120
7121

7122
7123
7124
7125


7126
7127
7128
7129
7130
7131
7132
7110
7111
7112
7113
7114
7115
7116


7117
7118
7119


7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146


7147
7148
7149
7150

7151
7152
7153


7154
7155
7156
7157
7158
7159
7160
7161
7162







-
-
+
+

-
-
+
+



















+



+

-
-
+
+


-
+


-
-
+
+







}


#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/* Opcode: IntegrityCk P1 P2 P3 P4 P5
**
** Do an analysis of the currently open database.  Store in
** register P1 the text of an error message describing any problems.
** If no problems are found, store a NULL in register P1.
** register (P1+1) the text of an error message describing any problems.
** If no problems are found, store a NULL in register (P1+1).
**
** The register P3 contains one less than the maximum number of allowed errors.
** At most reg(P3) errors will be reported.
** The register (P1) contains one less than the maximum number of allowed
** errors.  At most reg(P1) errors will be reported.
** In other words, the analysis stops as soon as reg(P1) errors are
** seen.  Reg(P1) is updated with the number of errors remaining.
**
** The root page numbers of all tables in the database are integers
** stored in P4_INTARRAY argument.
**
** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
**
** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
  int nRoot;      /* Number of tables to check.  (Number of root pages.) */
  Pgno *aRoot;    /* Array of rootpage numbers for tables to be checked */
  int nErr;       /* Number of errors reported */
  char *z;        /* Text of the error report */
  Mem *pnErr;     /* Register keeping track of errors remaining */

  assert( p->bIsReader );
  assert( pOp->p4type==P4_INTARRAY );
  nRoot = pOp->p2;
  aRoot = pOp->p4.ai;
  assert( nRoot>0 );
  assert( aRoot!=0 );
  assert( aRoot[0]==(Pgno)nRoot );
  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  pnErr = &aMem[pOp->p3];
  assert( pOp->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) );
  pnErr = &aMem[pOp->p1];
  assert( (pnErr->flags & MEM_Int)!=0 );
  assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
  pIn1 = &aMem[pOp->p1];
  pIn1 = &aMem[pOp->p1+1];
  assert( pOp->p5<db->nDb );
  assert( DbMaskTest(p->btreeMask, pOp->p5) );
  rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
                                 (int)pnErr->u.i+1, &nErr, &z);
  rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], 
      &aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z);
  sqlite3VdbeMemSetNull(pIn1);
  if( nErr==0 ){
    assert( z==0 );
  }else if( rc ){
    sqlite3_free(z);
    goto abort_due_to_error;
  }else{
7245
7246
7247
7248
7249
7250
7251
7252



7253
7254
7255
7256
7257
7258
7259
7260

7261
7262
7263
7264
7265
7266
7267
7275
7276
7277
7278
7279
7280
7281

7282
7283
7284
7285
7286
7287
7288
7289
7290
7291

7292
7293
7294
7295
7296
7297
7298
7299







-
+
+
+







-
+







/* Opcode: Program P1 P2 P3 P4 P5
**
** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
**
** P1 contains the address of the memory cell that contains the first memory
** cell in an array of values used as arguments to the sub-program. P2
** contains the address to jump to if the sub-program throws an IGNORE
** exception using the RAISE() function. Register P3 contains the address
** exception using the RAISE() function. P2 might be zero, if there is
** no possibility that an IGNORE exception will be raised.
** Register P3 contains the address
** of a memory cell in this (the parent) VM that is used to allocate the
** memory required by the sub-vdbe at runtime.
**
** P4 is a pointer to the VM containing the trigger program.
**
** If P5 is non-zero, then recursive program invocation is enabled.
*/
case OP_Program: {        /* jump */
case OP_Program: {        /* jump0 */
  int nMem;               /* Number of memory registers for sub-program */
  int nByte;              /* Bytes of runtime space required for sub-program */
  Mem *pRt;               /* Register to allocate runtime space */
  Mem *pMem;              /* Used to iterate through memory cells */
  Mem *pEnd;              /* Last memory cell in new array */
  VdbeFrame *pFrame;      /* New vdbe frame to execute in */
  SubProgram *pProgram;   /* Sub-program to execute */
8175
8176
8177
8178
8179
8180
8181
8182

8183
8184

8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195
8196
8197
8198
8199
8200
8201
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212
8213

8214
8215
8216
8217
8218
8219
8220
8221
8222
8223
8224
8225

8226
8227
8228
8229
8230

8231
8232
8233
8234
8235
8236
8237







-
+


+








-





-







  Table *pTab;
  sqlite3_vtab *pVtab;
  const sqlite3_module *pModule;
  char *zErr = 0;

  pOut = &aMem[pOp->p2];
  sqlite3VdbeMemSetNull(pOut);  /* Innocent until proven guilty */
  assert( pOp->p4type==P4_TABLE );
  assert( pOp->p4type==P4_TABLEREF );
  pTab = pOp->p4.pTab;
  assert( pTab!=0 );
  assert( pTab->nTabRef>0 );
  assert( IsVirtual(pTab) );
  if( pTab->u.vtab.p==0 ) break;
  pVtab = pTab->u.vtab.p->pVtab;
  assert( pVtab!=0 );
  pModule = pVtab->pModule;
  assert( pModule!=0 );
  assert( pModule->iVersion>=4 );
  assert( pModule->xIntegrity!=0 );
  pTab->nTabRef++;
  sqlite3VtabLock(pTab->u.vtab.p);
  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
                           pOp->p3, &zErr);
  sqlite3VtabUnlock(pTab->u.vtab.p);
  sqlite3DeleteTable(db, pTab);
  if( rc ){
    sqlite3_free(zErr);
    goto abort_due_to_error;
  }
  if( zErr ){
    sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlite3_free);
  }
8317
8318
8319
8320
8321
8322
8323

8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340



8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
8364
8365
8366
8367
8368
8369
8370
8371
8372
8373
8374
8375
8376
8377
8378
8379
8380
8381
8382







+

















+
+
+







** unused by OP_VColumn.
*/
case OP_VColumn: {           /* ncycle */
  sqlite3_vtab *pVtab;
  const sqlite3_module *pModule;
  Mem *pDest;
  sqlite3_context sContext;
  FuncDef nullFunc;

  VdbeCursor *pCur = p->apCsr[pOp->p1];
  assert( pCur!=0 );
  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);
  if( pCur->nullRow ){
    sqlite3VdbeMemSetNull(pDest);
    break;
  }
  assert( pCur->eCurType==CURTYPE_VTAB );
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;
  assert( pModule->xColumn );
  memset(&sContext, 0, sizeof(sContext));
  sContext.pOut = pDest;
  sContext.enc = encoding;
  nullFunc.pUserData = 0;
  nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE;
  sContext.pFunc = &nullFunc;
  assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
  if( pOp->p5 & OPFLAG_NOCHNG ){
    sqlite3VdbeMemSetNull(pDest);
    pDest->flags = MEM_Null|MEM_Zero;
    pDest->u.nZero = 0;
  }else{
    MemSetTypeFlag(pDest, MEM_Null);
8665
8666
8667
8668
8669
8670
8671




































8672
8673
8674
8675
8676
8677
8678
8700
8701
8702
8703
8704
8705
8706
8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
8722
8723
8724
8725
8726
8727
8728
8729
8730
8731
8732
8733
8734
8735
8736
8737
8738
8739
8740
8741
8742
8743
8744
8745
8746
8747
8748
8749







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







** Clear the subtype from register P1.
*/
case OP_ClrSubtype: {   /* in1 */
  pIn1 = &aMem[pOp->p1];
  pIn1->flags &= ~MEM_Subtype;
  break;
}

/* Opcode: GetSubtype P1 P2 * * *
** Synopsis:  r[P2] = r[P1].subtype
**
** Extract the subtype value from register P1 and write that subtype
** into register P2.  If P1 has no subtype, then P1 gets a NULL.
*/
case OP_GetSubtype: {   /* in1 out2 */
  pIn1 = &aMem[pOp->p1];
  pOut = &aMem[pOp->p2];
  if( pIn1->flags & MEM_Subtype ){
    sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype);
  }else{
    sqlite3VdbeMemSetNull(pOut);
  }
  break;
}

/* Opcode: SetSubtype P1 P2 * * *
** Synopsis:  r[P2].subtype = r[P1]
**
** Set the subtype value of register P2 to the integer from register P1.
** If P1 is NULL, clear the subtype from p2.
*/
case OP_SetSubtype: {   /* in1 out2 */
  pIn1 = &aMem[pOp->p1];
  pOut = &aMem[pOp->p2];
  if( pIn1->flags & MEM_Null ){
    pOut->flags &= ~MEM_Subtype;
  }else{
    assert( pIn1->flags & MEM_Int );
    pOut->flags |= MEM_Subtype;
    pOut->eSubtype = (u8)(pIn1->u.i & 0xff);
  }
  break;
}

/* Opcode: FilterAdd P1 * P3 P4 *
** Synopsis: filter(P1) += key(P3@P4)
**
** Compute a hash on the P4 registers starting with r[P3] and
** add that hash to the bloom filter contained in r[P1].
*/
8763
8764
8765
8766
8767
8768
8769
8770

8771
8772
8773
8774
8775
8776
8777
8834
8835
8836
8837
8838
8839
8840

8841
8842
8843
8844
8845
8846
8847
8848







-
+







** Increment the value of P1 so that OP_Once opcodes will jump the
** first time they are evaluated for this run.
**
** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
** error is encountered.
*/
case OP_Trace:
case OP_Init: {          /* jump */
case OP_Init: {          /* jump0 */
  int i;
#ifndef SQLITE_OMIT_TRACE
  char *zTrace;
#endif

  /* If the P4 argument is not NULL, then it must be an SQL comment string.
  ** The "--" string is broken up to prevent false-positives with srcck1.c.
Changes to src/vdbe.h.
122
123
124
125
126
127
128

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







+







#define P4_EXPR       (-9) /* P4 is a pointer to an Expr tree */
#define P4_MEM        (-10) /* P4 is a pointer to a Mem*    structure */
#define P4_VTAB       (-11) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_REAL       (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64      (-13) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY   (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX    (-15) /* P4 is a pointer to an sqlite3_context object */
#define P4_TABLEREF   (-16) /* Like P4_TABLE, but reference counted */

/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
#define P5_ConstraintUnique  2
#define P5_ConstraintCheck   3
#define P5_ConstraintFK      4

290
291
292
293
294
295
296


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







+
+







UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);

typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);

void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
int sqlite3VdbeHasSubProgram(Vdbe*);

void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val);

int sqlite3NotPureFunc(sqlite3_context*);
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
int sqlite3VdbeBytecodeVtabInit(sqlite3*);
#endif

/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
Changes to src/vdbeapi.c.
148
149
150
151
152
153
154
155









156
157
158
159
160
161
162
148
149
150
151
152
153
154

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







-
+
+
+
+
+
+
+
+
+







** Set all the parameters in the compiled SQL statement to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
  int i;
  int rc = SQLITE_OK;
  Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE
  sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
  sqlite3_mutex *mutex;
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
  if( pStmt==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
#if SQLITE_THREADSAFE
  mutex = p->db->mutex;
#endif
  sqlite3_mutex_enter(mutex);
  for(i=0; i<p->nVar; i++){
    sqlite3VdbeMemRelease(&p->aVar[i]);
    p->aVar[i].flags = MEM_Null;
  }
  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
938
939
940
941
942
943
944
945

946
947
948
949
950
951
952
953
954
946
947
948
949
950
951
952

953
954

955
956
957
958
959
960
961







-
+

-







/*
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
*/
void *sqlite3_user_data(sqlite3_context *p){
#ifdef SQLITE_ENABLE_API_ARMOR
  if( p==0 ) return 0;
#else
#endif
  assert( p && p->pFunc );
#endif
  return p->pFunc->pUserData;
}

/*
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
**
Changes to src/vdbeaux.c.
207
208
209
210
211
212
213
214

215
216
217

218
219
220
221
222
223
224
207
208
209
210
211
212
213

214
215
216
217
218
219
220
221
222
223
224
225







-
+



+







** Other useful labels for breakpoints include:
**   test_trace_breakpoint(pc,pOp)
**   sqlite3CorruptError(lineno)
**   sqlite3MisuseError(lineno)
**   sqlite3CantopenError(lineno)
*/
static void test_addop_breakpoint(int pc, Op *pOp){
  static int n = 0;
  static u64 n = 0;
  (void)pc;
  (void)pOp;
  n++;
  if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */
}
#endif

/*
** Slow paths for sqlite3VdbeAddOp3() and sqlite3VdbeAddOp4Int() for the
** unusual case when we need to increase the size of the Vdbe.aOp[] array
** before adding the new opcode.
934
935
936
937
938
939
940









941
942
943
944
945
946
947
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957







+
+
+
+
+
+
+
+
+







            ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
            ** have non-negative values for P2. */
            assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
            assert( ADDR(pOp->p2)<-pParse->nLabel );
            assert( aLabel!=0 );  /* True because of tag-20230419-1 */
            pOp->p2 = aLabel[ADDR(pOp->p2)];
          }

          /* OPFLG_JUMP opcodes never have P2==0, though OPFLG_JUMP0 opcodes
          ** might */
          assert( pOp->p2>0 
                  || (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP0)!=0 );

          /* Jumps never go off the end of the bytecode array */
          assert( pOp->p2<p->nOp
                  || (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)==0 );
          break;
        }
      }
      /* The mkopcodeh.tcl script has so arranged things that the only
      ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
      ** have non-negative values for P2. */
      assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
1395
1396
1397
1398
1399
1400
1401




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







+
+
+
+







      }
      break;
    }
    case P4_VTAB : {
      if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
      break;
    }
    case P4_TABLEREF: {
      if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4);
      break;
    }
  }
}

/*
** Free the space allocated for aOp and any p4 values allocated for the
** opcodes contained within. If aOp is not NULL it is assumed to contain
** nOp entries.
1522
1523
1524
1525
1526
1527
1528
1529

1530
1531
1532
1533
1534
1535
1536
1536
1537
1538
1539
1540
1541
1542

1543
1544
1545
1546
1547
1548
1549
1550







-
+







static void SQLITE_NOINLINE vdbeChangeP4Full(
  Vdbe *p,
  Op *pOp,
  const char *zP4,
  int n
){
  if( pOp->p4type ){
    freeP4(p->db, pOp->p4type, pOp->p4.p);
    assert( pOp->p4type > P4_FREE_IF_LE );
    pOp->p4type = 0;
    pOp->p4.p = 0;
  }
  if( n<0 ){
    sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n);
  }else{
    if( n==0 ) n = sqlite3Strlen30(zP4);
4050
4051
4052
4053
4054
4055
4056

















4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094







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







    assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
#endif
    assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
    swapMixedEndianFloat(x);
    memcpy(&pMem->u.r, &x, sizeof(x));
    pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
  }
}
static int serialGet7(
  const unsigned char *buf,     /* Buffer to deserialize from */
  Mem *pMem                     /* Memory cell to write value into */
){
  u64 x = FOUR_BYTE_UINT(buf);
  u32 y = FOUR_BYTE_UINT(buf+4);
  x = (x<<32) + y;
  assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
  swapMixedEndianFloat(x);
  memcpy(&pMem->u.r, &x, sizeof(x));
  if( IsNaN(x) ){
    pMem->flags = MEM_Null;
    return 1;
  }
  pMem->flags = MEM_Real;
  return 0;
}
void sqlite3VdbeSerialGet(
  const unsigned char *buf,     /* Buffer to deserialize from */
  u32 serial_type,              /* Serial type to deserialize */
  Mem *pMem                     /* Memory cell to write value into */
){
  switch( serial_type ){
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507




4508
4509
4510
4511
4512
4513
4514
4521
4522
4523
4524
4525
4526
4527

4528
4529
4530
4531
4532





4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543







-





-
-
-
-
-
+
+
+
+







    LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
    testcase( x<r );
    testcase( x>r );
    testcase( x==r );
    return (x<r) ? -1 : (x>r);
  }else{
    i64 y;
    double s;
    if( r<-9223372036854775808.0 ) return +1;
    if( r>=9223372036854775808.0 ) return -1;
    y = (i64)r;
    if( i<y ) return -1;
    if( i>y ) return +1;
    s = (double)i;
    testcase( doubleLt(s,r) );
    testcase( doubleLt(r,s) );
    testcase( doubleEq(r,s) );
    return (s<r) ? -1 : (s>r);
    testcase( doubleLt(((double)i),r) );
    testcase( doubleLt(r,((double)i)) );
    testcase( doubleEq(r,((double)i)) );
    return (((double)i)<r) ? -1 : (((double)i)>r);
  }
}

/*
** Compare the values contained by the two memory cells, returning
** negative, zero or positive if pMem1 is less than, equal to, or greater
** than pMem2. Sorting order is NULL's first, followed by numbers (integers
4730
4731
4732
4733
4734
4735
4736
4737

4738
4739
4740
4741
4742
4743
4744
4759
4760
4761
4762
4763
4764
4765

4766
4767
4768
4769
4770
4771
4772
4773







-
+







      serial_type = aKey1[idx1];
      testcase( serial_type==12 );
      if( serial_type>=10 ){
        rc = serial_type==10 ? -1 : +1;
      }else if( serial_type==0 ){
        rc = -1;
      }else if( serial_type==7 ){
        sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
        serialGet7(&aKey1[d1], &mem1);
        rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
      }else{
        i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
        i64 rhs = pRhs->u.i;
        if( lhs<rhs ){
          rc = -1;
        }else if( lhs>rhs ){
4755
4756
4757
4758
4759
4760
4761
4762
4763


4764

4765
4766
4767


4768
4769

4770
4771
4772
4773
4774
4775
4776
4784
4785
4786
4787
4788
4789
4790

4791
4792
4793

4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809







-

+
+
-
+



+
+


+







        ** numbers). Types 10 and 11 are currently "reserved for future
        ** use", so it doesn't really matter what the results of comparing
        ** them to numeric values are.  */
        rc = serial_type==10 ? -1 : +1;
      }else if( serial_type==0 ){
        rc = -1;
      }else{
        sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
        if( serial_type==7 ){
          if( serialGet7(&aKey1[d1], &mem1) ){
            rc = -1;  /* mem1 is a NaN */
          if( mem1.u.r<pRhs->u.r ){
          }else if( mem1.u.r<pRhs->u.r ){
            rc = -1;
          }else if( mem1.u.r>pRhs->u.r ){
            rc = +1;
          }else{
            assert( rc==0 );
          }
        }else{
          sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
          rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
        }
      }
    }

    /* RHS is a string */
    else if( pRhs->flags & MEM_Str ){
4832
4833
4834
4835
4836
4837
4838
4839








4840
4841
4842
4843
4844
4845
4846
4865
4866
4867
4868
4869
4870
4871

4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886







-
+
+
+
+
+
+
+
+







        }
      }
    }

    /* RHS is null */
    else{
      serial_type = aKey1[idx1];
      rc = (serial_type!=0 && serial_type!=10);
      if( serial_type==0
       || serial_type==10
       || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
      ){
        assert( rc==0 );
      }else{
        rc = 1;
      }
    }

    if( rc!=0 ){
      int sortFlags = pPKey2->pKeyInfo->aSortFlags[i];
      if( sortFlags ){
        if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0
         || ((sortFlags & KEYINFO_ORDER_DESC)
Changes to src/vdbemem.c.
938
939
940
941
942
943
944







945
946
947
948
949
950
951
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958







+
+
+
+
+
+
+







  if( VdbeMemDynamic(pMem) ){
    vdbeReleaseAndSetInt64(pMem, val);
  }else{
    pMem->u.i = val;
    pMem->flags = MEM_Int;
  }
}

/*
** Set the iIdx'th entry of array aMem[] to contain integer value val.
*/
void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val){
  sqlite3VdbeMemSetInt64(&aMem[iIdx], val);
}

/* A no-op destructor */
void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }

/*
** Set the value stored in *pMem should already be a NULL.
** Also store a pointer to go with it.
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641














1642
1643
1644
1645
1646
1647
1648
1649




1650
1651
1652
1653
1654
1655
















1656
1657
1658
1659
1660
1661
1662
1634
1635
1636
1637
1638
1639
1640








1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666






1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689







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








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







      sqlite3VdbeMemCast(*ppVal, aff, enc);
      sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
    }
    return rc;
  }

  /* Handle negative integers in a single step.  This is needed in the
  ** case when the value is -9223372036854775808.
  */
  if( op==TK_UMINUS
   && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
    pExpr = pExpr->pLeft;
    op = pExpr->op;
    negInt = -1;
    zNeg = "-";
  ** case when the value is -9223372036854775808. Except - do not do this
  ** for hexadecimal literals.  */
  if( op==TK_UMINUS ){
    Expr *pLeft = pExpr->pLeft;
    if( (pLeft->op==TK_INTEGER || pLeft->op==TK_FLOAT) ){
      if( ExprHasProperty(pLeft, EP_IntValue)
       || pLeft->u.zToken[0]!='0' || (pLeft->u.zToken[1] & ~0x20)!='X'
      ){
        pExpr = pLeft;
        op = pExpr->op;
        negInt = -1;
        zNeg = "-";
      }
    }
  }

  if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
    pVal = valueNew(db, pCtx);
    if( pVal==0 ) goto no_mem;
    if( ExprHasProperty(pExpr, EP_IntValue) ){
      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
    }else{
      i64 iVal;
      if( op==TK_INTEGER && 0==sqlite3DecOrHexToI64(pExpr->u.zToken, &iVal) ){
        sqlite3VdbeMemSetInt64(pVal, iVal*negInt);
      }else{
      zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
      if( zVal==0 ) goto no_mem;
      sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
    }
    if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){
      sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
        zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
        if( zVal==0 ) goto no_mem;
        sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
      }
    }
    if( affinity==SQLITE_AFF_BLOB ){
      if( op==TK_FLOAT ){
        assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) );
        sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8);
        pVal->flags = MEM_Real;
      }else if( op==TK_INTEGER ){
        /* This case is required by -9223372036854775808 and other strings
        ** that look like integers but cannot be handled by the
        ** sqlite3DecOrHexToI64() call above.  */
        sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
      }
    }else{
      sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
    }
    assert( (pVal->flags & MEM_IntReal)==0 );
    if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){
      testcase( pVal->flags & MEM_Int );
      testcase( pVal->flags & MEM_Real );
Changes to src/vtab.c.
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
311
312
313
314
315
316
317

318
319
320
321
322
323
324







-







  VTable *p = db->pDisconnect;

  assert( sqlite3BtreeHoldsAllMutexes(db) );
  assert( sqlite3_mutex_held(db->mutex) );

  if( p ){
    db->pDisconnect = 0;
    sqlite3ExpirePreparedStatements(db, 0);
    do {
      VTable *pNext = p->pNext;
      sqlite3VtabUnlock(p);
      p = pNext;
    }while( p );
  }
}
608
609
610
611
612
613
614


615
616
617
618
619
620
621
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622







+
+







  sCtx.pTab = pTab;
  sCtx.pVTable = pVTable;
  sCtx.pPrior = db->pVtabCtx;
  sCtx.bDeclared = 0;
  db->pVtabCtx = &sCtx;
  pTab->nTabRef++;
  rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
  assert( pTab!=0 );
  assert( pTab->nTabRef>1 || rc!=SQLITE_OK );
  sqlite3DeleteTable(db, pTab);
  db->pVtabCtx = sCtx.pPrior;
  if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
  assert( sCtx.pTab==pTab );

  if( SQLITE_OK!=rc ){
    if( zErr==0 ){
630
631
632
633
634
635
636
637

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

638
639
640
641
642
643
644
645







-
+







    ** the sqlite3_vtab object if successful.  */
    memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
    pVTable->pVtab->pModule = pMod->pModule;
    pMod->nRefModule++;
    pVTable->nRef = 1;
    if( sCtx.bDeclared==0 ){
      const char *zFormat = "vtable constructor did not declare schema: %s";
      *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
      *pzErr = sqlite3MPrintf(db, zFormat, zModuleName);
      sqlite3VtabUnlock(pVTable);
      rc = SQLITE_ERROR;
    }else{
      int iCol;
      u16 oooHidden = 0;
      /* If everything went according to plan, link the new VTable structure
      ** into the linked list headed by pTab->u.vtab.p. Then loop through the
Changes to src/wal.c.
2000
2001
2002
2003
2004
2005
2006













2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022

2023
2024
2025
2026
2027
2028
2029
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030





2031
2032
2033
2034
2035
2036
2037
2038







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











-
-
-
-
-
+







    p = 0;
  }
  *pp = p;
  return rc;
}

#ifdef SQLITE_ENABLE_SETLK_TIMEOUT


/*
** Attempt to enable blocking locks that block for nMs ms. Return 1 if 
** blocking locks are successfully enabled, or 0 otherwise.
*/
static int walEnableBlockingMs(Wal *pWal, int nMs){
  int rc = sqlite3OsFileControl(
      pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs
  );
  return (rc==SQLITE_OK);
}

/*
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
** they are supported by the VFS, and (b) the database handle is configured
** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
** or 0 otherwise.
*/
static int walEnableBlocking(Wal *pWal){
  int res = 0;
  if( pWal->db ){
    int tmout = pWal->db->busyTimeout;
    if( tmout ){
      int rc;
      rc = sqlite3OsFileControl(
          pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
      );
      res = (rc==SQLITE_OK);
      res = walEnableBlockingMs(pWal, tmout);
    }
  }
  return res;
}

/*
** Disable blocking locks.
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084

2085
2086
2087
2088
2089
2090
2091
2073
2074
2075
2076
2077
2078
2079










2080
2081
2082

2083
2084
2085
2086
2087
2088
2089
2090







-
-
-
-
-
-
-
-
-
-



-
+







/*
** Set the database handle used to determine if blocking locks are required.
*/
void sqlite3WalDb(Wal *pWal, sqlite3 *db){
  pWal->db = db;
}

/*
** Take an exclusive WRITE lock. Blocking if so configured.
*/
static int walLockWriter(Wal *pWal){
  int rc;
  walEnableBlocking(pWal);
  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
  walDisableBlocking(pWal);
  return rc;
}
#else
# define walEnableBlocking(x) 0
# define walDisableBlocking(x)
# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
# define walEnableBlockingMs(pWal, ms) 0
# define sqlite3WalDb(pWal, db)
#endif   /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */


/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
2678
2679
2680
2681
2682
2683
2684
2685



2686
2687
2688
2689
2690
2691
2692
2693


2694
2695
2696
2697
2698
2699
2700
2677
2678
2679
2680
2681
2682
2683

2684
2685
2686
2687
2688
2689
2690
2691
2692
2693

2694
2695
2696
2697
2698
2699
2700
2701
2702







-
+
+
+







-
+
+







    if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
      if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
        walUnlockShared(pWal, WAL_WRITE_LOCK);
        rc = SQLITE_READONLY_RECOVERY;
      }
    }else{
      int bWriteLock = pWal->writeLock;
      if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
      if( bWriteLock 
       || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) 
      ){
        pWal->writeLock = 1;
        if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
          badHdr = walIndexTryHdr(pWal, pChanged);
          if( badHdr ){
            /* If the wal-index header is still malformed even while holding
            ** a WRITE lock, it can only mean that the header is corrupted and
            ** needs to be reconstructed.  So run recovery to do exactly that.
            */
            ** Disable blocking locks first.  */
            walDisableBlocking(pWal);
            rc = walIndexRecover(pWal);
            *pChanged = 1;
          }
        }
        if( bWriteLock==0 ){
          pWal->writeLock = 0;
          walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
2896
2897
2898
2899
2900
2901
2902































2903
2904
2905
2906
2907
2908
2909
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942







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







    pWal->bShmUnreliable = 0;
    sqlite3WalEndReadTransaction(pWal);
    *pChanged = 1;
  }
  return rc;
}

/*
** The final argument passed to walTryBeginRead() is of type (int*). The
** caller should invoke walTryBeginRead as follows:
**
**   int cnt = 0;
**   do {
**     rc = walTryBeginRead(..., &cnt);
**   }while( rc==WAL_RETRY );
**
** The final value of "cnt" is of no use to the caller. It is used by
** the implementation of walTryBeginRead() as follows:
**
**   + Each time walTryBeginRead() is called, it is incremented. Once
**     it reaches WAL_RETRY_PROTOCOL_LIMIT - indicating that walTryBeginRead()
**     has many times been invoked and failed with WAL_RETRY - walTryBeginRead()
**     returns SQLITE_PROTOCOL.
**
**   + If SQLITE_ENABLE_SETLK_TIMEOUT is defined and walTryBeginRead() failed
**     because a blocking lock timed out (SQLITE_BUSY_TIMEOUT from the OS
**     layer), the WAL_RETRY_BLOCKED_MASK bit is set in "cnt". In this case
**     the next invocation of walTryBeginRead() may omit an expected call to 
**     sqlite3OsSleep(). There has already been a delay when the previous call
**     waited on a lock.
*/
#define WAL_RETRY_PROTOCOL_LIMIT 100
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
# define WAL_RETRY_BLOCKED_MASK    0x10000000
#else
# define WAL_RETRY_BLOCKED_MASK    0
#endif

/*
** Attempt to start a read transaction.  This might fail due to a race or
** other transient condition.  When that happens, it returns WAL_RETRY to
** indicate to the caller that it is safe to retry immediately.
**
** On success return SQLITE_OK.  On a permanent failure (such an
** I/O error or an SQLITE_BUSY because another process is running
2946
2947
2948
2949
2950
2951
2952
2953

2954
2955
2956
2957
2958
2959



2960
2961
2962
2963
2964
2965
2966
2979
2980
2981
2982
2983
2984
2985

2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002







-
+






+
+
+







** This routine uses the nBackfill and aReadMark[] fields of the header
** to select a particular WAL_READ_LOCK() that strives to let the
** checkpoint process do as much work as possible.  This routine might
** update values of the aReadMark[] array in the header, but if it does
** so it takes care to hold an exclusive lock on the corresponding
** WAL_READ_LOCK() while changing values.
*/
static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
  volatile WalCkptInfo *pInfo;    /* Checkpoint information in wal-index */
  u32 mxReadMark;                 /* Largest aReadMark[] value */
  int mxI;                        /* Index of largest aReadMark[] value */
  int i;                          /* Loop counter */
  int rc = SQLITE_OK;             /* Return code  */
  u32 mxFrame;                    /* Wal frame to lock to */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  int nBlockTmout = 0;
#endif

  assert( pWal->readLock<0 );     /* Not currently locked */

  /* useWal may only be set for read/write connections */
  assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 );

  /* Take steps to avoid spinning forever if there is a protocol error.
2976
2977
2978
2979
2980
2981
2982

2983

2984

2985

2986
2987
2988
2989


















2990

2991
2992
2993
2994
2995
2996
2997







2998
2999
3000
3001
3002
3003
3004
3012
3013
3014
3015
3016
3017
3018
3019

3020
3021
3022

3023
3024
3025
3026

3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067







+
-
+

+
-
+



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

+







+
+
+
+
+
+
+







  ** After 5 RETRYs, we begin calling sqlite3OsSleep().  The first few
  ** calls to sqlite3OsSleep() have a delay of 1 microsecond.  Really this
  ** is more of a scheduler yield than an actual delay.  But on the 10th
  ** an subsequent retries, the delays start becoming longer and longer,
  ** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
  ** The total delay time before giving up is less than 10 seconds.
  */
  (*pCnt)++;
  if( cnt>5 ){
  if( *pCnt>5 ){
    int nDelay = 1;                      /* Pause time in microseconds */
    int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK);
    if( cnt>100 ){
    if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){
      VVA_ONLY( pWal->lockError = 1; )
      return SQLITE_PROTOCOL;
    }
    if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
    if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor
    ** to block for locks for approximately nDelay us. This affects three
    ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if
    ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the
    ** first attempted read fails, and (c) the shared lock taken on the 
    ** read-mark.  
    **
    ** If the previous call failed due to an SQLITE_BUSY_TIMEOUT error,
    ** then sleep for the minimum of 1us. The previous call already provided 
    ** an extra delay while it was blocking on the lock.
    */
    nBlockTmout = (nDelay+998) / 1000;
    if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){
      if( *pCnt & WAL_RETRY_BLOCKED_MASK ) nDelay = 1;
    }
#endif
    sqlite3OsSleep(pWal->pVfs, nDelay);
    *pCnt &= ~WAL_RETRY_BLOCKED_MASK;
  }

  if( !useWal ){
    assert( rc==SQLITE_OK );
    if( pWal->bShmUnreliable==0 ){
      rc = walIndexReadHdr(pWal, pChanged);
    }
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    walDisableBlocking(pWal);
    if( rc==SQLITE_BUSY_TIMEOUT ){
      rc = SQLITE_BUSY;
      *pCnt |= WAL_RETRY_BLOCKED_MASK;
    }
#endif
    if( rc==SQLITE_BUSY ){
      /* If there is not a recovery running in another thread or process
      ** then convert BUSY errors to WAL_RETRY.  If recovery is known to
      ** be running, convert BUSY to BUSY_RECOVERY.  There is a race here
      ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
      ** would be technically correct.  But the race is benign since with
      ** WAL_RETRY this routine will be called again and will probably be
3105
3106
3107
3108
3109
3110
3111

3112

3113








3114

3115
3116
3117
3118
3119
3120
3121
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186

3187
3188
3189
3190
3191
3192
3193
3194







+

+

+
+
+
+
+
+
+
+
-
+







    }
  }
  if( mxI==0 ){
    assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
    return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
  }

  (void)walEnableBlockingMs(pWal, nBlockTmout);
  rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
  walDisableBlocking(pWal);
  if( rc ){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
    if( rc==SQLITE_BUSY_TIMEOUT ){
      *pCnt |= WAL_RETRY_BLOCKED_MASK;
    }
#else
    assert( rc!=SQLITE_BUSY_TIMEOUT );
#endif
    assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
    return rc==SQLITE_BUSY ? WAL_RETRY : rc;
    return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc;
  }
  /* Now that the read-lock has been obtained, check that neither the
  ** value in the aReadMark[] array or the contents of the wal-index
  ** header have changed.
  **
  ** It is necessary to check that the wal-index header did not change
  ** between the time it was read and when the shared-lock was obtained
3295
3296
3297
3298
3299
3300
3301
3302

3303
3304
3305
3306
3307
3308
3309
3368
3369
3370
3371
3372
3373
3374

3375
3376
3377
3378
3379
3380
3381
3382







-
+







      return rc;
    }
    ckptLock = 1;
  }
#endif

  do{
    rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
    rc = walTryBeginRead(pWal, pChanged, 0, &cnt);
  }while( rc==WAL_RETRY );
  testcase( (rc&0xff)==SQLITE_BUSY );
  testcase( (rc&0xff)==SQLITE_IOERR );
  testcase( rc==SQLITE_PROTOCOL );
  testcase( rc==SQLITE_OK );

#ifdef SQLITE_ENABLE_SNAPSHOT
3476
3477
3478
3479
3480
3481
3482

3483
3484
3485
3486
3487
3488
3489
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563







+







    while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
      u32 iFrame = iH + sLoc.iZero;
      if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
        assert( iFrame>iRead || CORRUPT_DB );
        iRead = iFrame;
      }
      if( (nCollide--)==0 ){
        *piRead = 0;
        return SQLITE_CORRUPT_BKPT;
      }
      iKey = walNextHash(iKey);
    }
    if( iRead ) break;
  }

3779
3780
3781
3782
3783
3784
3785
3786

3787
3788
3789
3790
3791
3792
3793
3853
3854
3855
3856
3857
3858
3859

3860
3861
3862
3863
3864
3865
3866
3867







-
+







      }
    }
    walUnlockShared(pWal, WAL_READ_LOCK(0));
    pWal->readLock = -1;
    cnt = 0;
    do{
      int notUsed;
      rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
      rc = walTryBeginRead(pWal, &notUsed, 1, &cnt);
    }while( rc==WAL_RETRY );
    assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
    testcase( (rc&0xff)==SQLITE_IOERR );
    testcase( rc==SQLITE_PROTOCOL );
    testcase( rc==SQLITE_OK );
  }
  return rc;
4200
4201
4202
4203
4204
4205
4206
4207

4208
4209
4210

4211
4212
4213
4214
4215
4216
4217
4274
4275
4276
4277
4278
4279
4280

4281

4282

4283
4284
4285
4286
4287
4288
4289
4290







-
+
-

-
+







  /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
  ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
  assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );

  if( pWal->readOnly ) return SQLITE_READONLY;
  WALTRACE(("WAL%p: checkpoint begins\n", pWal));

  /* Enable blocking locks, if possible. If blocking locks are successfully
  /* Enable blocking locks, if possible. */
  ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
  sqlite3WalDb(pWal, db);
  (void)walEnableBlocking(pWal);
  if( xBusy2 ) (void)walEnableBlocking(pWal);

  /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
  ** "checkpoint" lock on the database file.
  ** EVIDENCE-OF: R-10421-19736 If any other process is running a
  ** checkpoint operation at the same time, the lock cannot be obtained and
  ** SQLITE_BUSY is returned.
  ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
4244
4245
4246
4247
4248
4249
4250





4251
4252
4253

4254
4255
4256
4257
4258
4259
4260
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330

4331
4332
4333
4334
4335
4336
4337
4338







+
+
+
+
+


-
+







    }
  }


  /* Read the wal-index header. */
  SEH_TRY {
    if( rc==SQLITE_OK ){
      /* For a passive checkpoint, do not re-enable blocking locks after
      ** reading the wal-index header. A passive checkpoint should not block 
      ** or invoke the busy handler. The only lock such a checkpoint may 
      ** attempt to obtain is a lock on a read-slot, and it should give up
      ** immediately and do a partial checkpoint if it cannot obtain it. */
      walDisableBlocking(pWal);
      rc = walIndexReadHdr(pWal, &isChanged);
      (void)walEnableBlocking(pWal);
      if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal);
      if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
        sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
      }
    }
  
    /* Copy data from the log to the database file. */
    if( rc==SQLITE_OK ){
Changes to src/where.c.
674
675
676
677
678
679
680





681
682
683
684
685
686





687
688
689
690
691
692
693
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703







+
+
+
+
+






+
+
+
+
+







  Vdbe *v = pParse->pVdbe;
  VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
  int iEnd = sqlite3VdbeCurrentAddr(v);
  if( pParse->db->mallocFailed ) return;
  for(; iStart<iEnd; iStart++, pOp++){
    if( pOp->p1!=iTabCur ) continue;
    if( pOp->opcode==OP_Column ){
#ifdef SQLITE_DEBUG
      if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
        printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart);
      }
#endif
      pOp->opcode = OP_Copy;
      pOp->p1 = pOp->p2 + iRegister;
      pOp->p2 = pOp->p3;
      pOp->p3 = 0;
      pOp->p5 = 2;  /* Cause the MEM_Subtype flag to be cleared */
    }else if( pOp->opcode==OP_Rowid ){
#ifdef SQLITE_DEBUG
      if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
        printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart);
      }
#endif
      pOp->opcode = OP_Sequence;
      pOp->p1 = iAutoidxCur;
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
      if( iAutoidxCur==0 ){
        pOp->opcode = OP_Null;
        pOp->p3 = 0;
      }
1315
1316
1317
1318
1319
1320
1321
1322

1323
1324
1325
1326
1327
1328
1329
1325
1326
1327
1328
1329
1330
1331

1332
1333
1334
1335
1336
1337
1338
1339







-
+







  if( pOrderBy ){
    int n = pOrderBy->nExpr;
    for(i=0; i<n; i++){
      Expr *pExpr = pOrderBy->a[i].pExpr;
      Expr *pE2;

      /* Skip over constant terms in the ORDER BY clause */
      if( sqlite3ExprIsConstant(pExpr) ){
      if( sqlite3ExprIsConstant(0, pExpr) ){
        continue;
      }

      /* Virtual tables are unable to deal with NULLS FIRST */
      if( pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) break;

      /* First case - a direct column references without a COLLATE operator */
1427
1428
1429
1430
1431
1432
1433
1434

1435
1436
1437
1438
1439
1440
1441
1437
1438
1439
1440
1441
1442
1443

1444
1445
1446
1447
1448
1449
1450
1451







-
+








    j++;
  }
  assert( j==nTerm );
  pIdxInfo->nConstraint = j;
  for(i=j=0; i<nOrderBy; i++){
    Expr *pExpr = pOrderBy->a[i].pExpr;
    if( sqlite3ExprIsConstant(pExpr) ) continue;
    if( sqlite3ExprIsConstant(0, pExpr) ) continue;
    assert( pExpr->op==TK_COLUMN
         || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
              && pExpr->iColumn==pExpr->pLeft->iColumn) );
    pIdxOrderBy[j].iColumn = pExpr->iColumn;
    pIdxOrderBy[j].desc = pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC;
    j++;
  }
2006
2007
2008
2009
2010
2011
2012
2013


2014
2015
2016
2017
2018
2019
2020
2016
2017
2018
2019
2020
2021
2022

2023
2024
2025
2026
2027
2028
2029
2030
2031







-
+
+







      if( rc==SQLITE_OK ){
        if( iUpper>iLower ){
          nNew = sqlite3LogEst(iUpper - iLower);
          /* TUNING:  If both iUpper and iLower are derived from the same
          ** sample, then assume they are 4x more selective.  This brings
          ** the estimated selectivity more in line with what it would be
          ** if estimated without the use of STAT4 tables. */
          if( iLwrIdx==iUprIdx ) nNew -= 20;  assert( 20==sqlite3LogEst(4) );
          if( iLwrIdx==iUprIdx ){ nNew -= 20; }
          assert( 20==sqlite3LogEst(4) );
        }else{
          nNew = 10;        assert( 10==sqlite3LogEst(2) );
        }
        if( nNew<nOut ){
          nOut = nNew;
        }
        WHERETRACE(0x20, ("STAT4 range scan: %u..%u  est=%d\n",
2230
2231
2232
2233
2234
2235
2236












2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247















2248
2249
2250
2251
2252
2253
2254
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260










2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282







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

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







  }
}
#endif

#ifdef WHERETRACE_ENABLED
/*
** Print a WhereLoop object for debugging purposes
**
** Format example:
**
**     .--- Position in WHERE clause           rSetup, rRun, nOut ---.
**     |                                                             |
**     |  .--- selfMask                       nTerm ------.          |
**     |  |                                               |          |
**     |  |   .-- prereq    Idx          wsFlags----.     |          |
**     |  |   |             Name                    |     |          |
**     |  |   |           __|__        nEq ---.  ___|__   |        __|__
**     | / \ / \         /     \              | /      \ / \      /     \
**     1.002.001         t2.t2xy              2 f 010241 N 2 cost 0,56,31
*/
void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
  WhereInfo *pWInfo = pWC->pWInfo;
  int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
  SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
  Table *pTab = pItem->pTab;
  Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
  sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
                     p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
  sqlite3DebugPrintf(" %12s",
                     pItem->zAlias ? pItem->zAlias : pTab->zName);
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
  if( pWC ){
    WhereInfo *pWInfo = pWC->pWInfo;
    int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
    SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
    Table *pTab = pItem->pTab;
    Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
    sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
                       p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
    sqlite3DebugPrintf(" %12s",
                       pItem->zAlias ? pItem->zAlias : pTab->zName);
  }else{
    sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
         p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
  }
  if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
    const char *zName;
    if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
      if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){
        int i = sqlite3Strlen30(zName) - 1;
        while( zName[i]!='_' ) i--;
        zName += i;
2276
2277
2278
2279
2280
2281
2282









2283
2284
2285
2286
2287
2288
2289
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326







+
+
+
+
+
+
+
+
+







  sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
  if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){
    int i;
    for(i=0; i<p->nLTerm; i++){
      sqlite3WhereTermPrint(p->aLTerm[i], i);
    }
  }
}
void sqlite3ShowWhereLoop(const WhereLoop *p){
  if( p ) sqlite3WhereLoopPrint(p, 0);
}
void sqlite3ShowWhereLoopList(const WhereLoop *p){
  while( p ){
    sqlite3ShowWhereLoop(p);
    p = p->pNextLoop;
  }
}
#endif

/*
** Convert bulk memory into a valid WhereLoop that can be passed
** to whereLoopClear harmlessly.
*/
2389
2390
2391
2392
2393
2394
2395
2396




2397












2398
2399
2400
2401
2402
2403






2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418









2419
2420

2421
2422
2423

2424
2425
2426
2427
2428
2429

2430
2431
2432
2433

2434
2435

2436
2437
2438
2439
2440
2441
2442
2426
2427
2428
2429
2430
2431
2432

2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449






2450
2451
2452
2453
2454
2455









2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471

2472
2473


2474
2475
2476
2477
2478
2479

2480
2481
2482
2483

2484
2485

2486
2487
2488
2489
2490
2491
2492
2493







-
+
+
+
+

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






+
+
+
+
+
+
+
+
+

-
+

-
-
+





-
+



-
+

-
+







    sqlite3DbNNFreeNN(db, pWInfo->pMemToFree);
    pWInfo->pMemToFree = pNext;
  }
  sqlite3DbNNFreeNN(db, pWInfo);
}

/*
** Return TRUE if all of the following are true:
** Return TRUE if X is a proper subset of Y but is of equal or less cost.
** In other words, return true if all constraints of X are also part of Y
** and Y has additional constraints that might speed the search that X lacks
** but the cost of running X is not more than the cost of running Y.
**
** In other words, return true if the cost relationwship between X and Y
** is inverted and needs to be adjusted.
**
** Case 1:
**
**   (1a)  X and Y use the same index.
**   (1b)  X has fewer == terms than Y
**   (1c)  Neither X nor Y use skip-scan
**   (1d)  X does not have a a greater cost than Y
**
** Case 2:
**
**   (1)  X has the same or lower cost, or returns the same or fewer rows,
**        than Y.
**   (2)  X uses fewer WHERE clause terms than Y
**   (3)  Every WHERE clause term used by X is also used by Y
**   (4)  X skips at least as many columns as Y
**   (5)  If X is a covering index, than Y is too
**   (2a)  X has the same or lower cost, or returns the same or fewer rows,
**         than Y.
**   (2b)  X uses fewer WHERE clause terms than Y
**   (2c)  Every WHERE clause term used by X is also used by Y
**   (2d)  X skips at least as many columns as Y
**   (2e)  If X is a covering index, than Y is too
**
** Conditions (2) and (3) mean that X is a "proper subset" of Y.
** If X is a proper subset of Y then Y is a better choice and ought
** to have a lower cost.  This routine returns TRUE when that cost
** relationship is inverted and needs to be adjusted.  Constraint (4)
** was added because if X uses skip-scan less than Y it still might
** deserve a lower cost even if it is a proper subset of Y.  Constraint (5)
** was added because a covering index probably deserves to have a lower cost
** than a non-covering index even if it is a proper subset.
*/
static int whereLoopCheaperProperSubset(
  const WhereLoop *pX,       /* First WhereLoop to compare */
  const WhereLoop *pY        /* Compare against this WhereLoop */
){
  int i, j;
  if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */
  assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 );
  assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 );
  if( pX->u.btree.nEq < pY->u.btree.nEq                  /* (1b) */
   && pX->u.btree.pIndex==pY->u.btree.pIndex             /* (1a) */
   && pX->nSkip==0 && pY->nSkip==0                       /* (1c) */
  ){
    return 1;  /* Case 1 is true */
  }
  if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
    return 0; /* X is not a subset of Y */
    return 0;                                            /* (2b) */
  }
  if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
  if( pY->nSkip > pX->nSkip ) return 0;
  if( pY->nSkip > pX->nSkip ) return 0;                  /* (2d) */
  for(i=pX->nLTerm-1; i>=0; i--){
    if( pX->aLTerm[i]==0 ) continue;
    for(j=pY->nLTerm-1; j>=0; j--){
      if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
    }
    if( j<0 ) return 0;  /* X not a subset of Y since term X[i] not used by Y */
    if( j<0 ) return 0;                                  /* (2c) */
  }
  if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
   && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
    return 0;  /* Constraint (5) */
    return 0;                                            /* (2e) */
  }
  return 1;  /* All conditions meet */
  return 1;  /* Case 2 is true */
}

/*
** Try to adjust the cost and number of output rows of WhereLoop pTemplate
** upwards or downwards so that:
**
**   (1) pTemplate costs less than any other WhereLoops that are a proper
2918
2919
2920
2921
2922
2923
2924

2925





2926
2927
2928
2929
2930
2931
2932
2969
2970
2971
2972
2973
2974
2975
2976

2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988







+
-
+
+
+
+
+







  assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
  if( pNew->wsFlags & WHERE_BTM_LIMIT ){
    opMask = WO_LT|WO_LE;
  }else{
    assert( pNew->u.btree.nBtm==0 );
    opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
  }
  if( pProbe->bUnordered || pProbe->bLowQual ){
  if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
    if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
    if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ 
      opMask &= ~(WO_EQ|WO_IN|WO_IS);
    }
  }

  assert( pNew->u.btree.nEq<pProbe->nColumn );
  assert( pNew->u.btree.nEq<pProbe->nKeyCol
       || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY );

  saved_nEq = pNew->u.btree.nEq;
  saved_nBtm = pNew->u.btree.nBtm;
3304
3305
3306
3307
3308
3309
3310

3311


3312
3313
3314
3315
3316
3317
3318
3360
3361
3362
3363
3364
3365
3366
3367

3368
3369
3370
3371
3372
3373
3374
3375
3376







+
-
+
+







  int ii, jj;

  if( pIndex->bUnordered ) return 0;
  if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
  for(ii=0; ii<pOB->nExpr; ii++){
    Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
    if( NEVER(pExpr==0) ) continue;
    if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) 
    if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
     && pExpr->iTable==iCursor 
    ){
      if( pExpr->iColumn<0 ) return 1;
      for(jj=0; jj<pIndex->nKeyCol; jj++){
        if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
      }
    }else if( (aColExpr = pIndex->aColExpr)!=0 ){
      for(jj=0; jj<pIndex->nKeyCol; jj++){
        if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
3561
3562
3563
3564
3565
3566
3567
3568

3569
3570
3571
3572
3573
3574
3575
3619
3620
3621
3622
3623
3624
3625

3626
3627
3628
3629
3630
3631
3632
3633







-
+








  if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
    Expr *pLeft = pPart->pLeft;
    Expr *pRight = pPart->pRight;
    u8 aff;

    if( pLeft->op!=TK_COLUMN ) return;
    if( !sqlite3ExprIsConstant(pRight) ) return;
    if( !sqlite3ExprIsConstant(0, pRight) ) return;
    if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
    if( pLeft->iColumn<0 ) return;
    aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
    if( aff>=SQLITE_AFF_TEXT ){
      if( pItem ){
        sqlite3 *db = pParse->db;
        IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocRaw(db, sizeof(*p));
3910
3911
3912
3913
3914
3915
3916
3917

3918
3919
3920
3921
3922
3923
3924
3968
3969
3970
3971
3972
3973
3974

3975
3976
3977
3978
3979
3980
3981
3982







-
+







    pBuilder->bldFlags1 = 0;
    rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
    if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){
      /* If a non-unique index is used, or if a prefix of the key for
      ** unique index is used (making the index functionally non-unique)
      ** then the sqlite_stat1 data becomes important for scoring the
      ** plan */
      pTab->tabFlags |= TF_StatsUsed;
      pTab->tabFlags |= TF_MaybeReanalyze;
    }
#ifdef SQLITE_ENABLE_STAT4
    sqlite3Stat4ProbeFree(pBuilder->pRec);
    pBuilder->nRecValid = 0;
    pBuilder->pRec = 0;
#endif
  }
4935
4936
4937
4938
4939
4940
4941
4942

4943
4944
4945
4946
4947
4948
4949
4993
4994
4995
4996
4997
4998
4999

5000
5001
5002
5003
5004
5005
5006
5007







-
+







      orderDistinctMask |= pLoop->maskSelf;
      for(i=0; i<nOrderBy; i++){
        Expr *p;
        Bitmask mTerm;
        if( MASKBIT(i) & obSat ) continue;
        p = pOrderBy->a[i].pExpr;
        mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
        if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue;
        if( mTerm==0 && !sqlite3ExprIsConstant(0,p) ) continue;
        if( (mTerm&~orderDistinctMask)==0 ){
          obSat |= MASKBIT(i);
        }
      }
    }
  } /* End the loop over all WhereLoops from outer-most down to inner-most */
  if( obSat==obDone ) return (i8)nOrderBy;
5404
5405
5406
5407
5408
5409
5410

5411

5412
5413

5414
5415
5416
5417
5418
5419
5420
5421
5462
5463
5464
5465
5466
5467
5468
5469

5470


5471

5472
5473
5474
5475
5476
5477
5478







+
-
+
-
-
+
-







  pWInfo->bOrderedInnerLoop = 0;
  if( pWInfo->pOrderBy ){
    pWInfo->nOBSat = pFrom->isOrdered;
    if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
      if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
        pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
      }
      /* vvv--- See check-in [12ad822d9b827777] on 2023-03-16 ---vvv */
      if( pWInfo->pSelect->pOrderBy
      assert( pWInfo->pSelect->pOrderBy==0
       && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){
        pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr;
           || pWInfo->nOBSat <= pWInfo->pSelect->pOrderBy->nExpr );
      }
    }else{
      pWInfo->revMask = pFrom->revLoop;
      if( pWInfo->nOBSat<=0 ){
        pWInfo->nOBSat = 0;
        if( nLoop>0 ){
          u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags;
          if( (wsFlags & WHERE_ONEROW)==0
5746
5747
5748
5749
5750
5751
5752
5753

5754
5755
5756
5757
5758
5759
5760
5803
5804
5805
5806
5807
5808
5809

5810
5811
5812
5813
5814
5815
5816
5817







-
+







  assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
  for(i=0; i<pWInfo->nLevel; i++){
    WhereLoop *pLoop = pWInfo->a[i].pWLoop;
    const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
    SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
    Table *pTab = pItem->pTab;
    if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
    pTab->tabFlags |= TF_StatsUsed;
    pTab->tabFlags |= TF_MaybeReanalyze;
    if( i>=1
     && (pLoop->wsFlags & reqFlags)==reqFlags
     /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
     && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0)
    ){
      if( nSearch > pTab->nRowLogEst ){
        testcase( pItem->fg.jointype & JT_LEFT );
5805
5806
5807
5808
5809
5810
5811
5812

5813
5814
5815
5816
5817
5818
5819
5862
5863
5864
5865
5866
5867
5868

5869
5870
5871
5872
5873
5874
5875
5876







-
+







      bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
    }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
      pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
      bMaybeNullRow = 0;
    }else{
      continue;
    }
    if( sqlite3ExprIsConstant(pExpr) ) continue;
    if( sqlite3ExprIsConstant(0,pExpr) ) continue;
    if( pExpr->op==TK_FUNCTION ){
      /* Functions that might set a subtype should not be replaced by the
      ** value taken from an expression index since the index omits the
      ** subtype.  https://sqlite.org/forum/forumpost/68d284c86b082c3e */
      int n;
      FuncDef *pDef;
      sqlite3 *db = pParse->db;
5998
5999
6000
6001
6002
6003
6004
6005




6006
6007
6008
6009
6010
6011
6012
6055
6056
6057
6058
6059
6060
6061

6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072







-
+
+
+
+








  /* Variable initialization */
  db = pParse->db;
  memset(&sWLB, 0, sizeof(sWLB));

  /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
  testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
  if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
  if( pOrderBy && pOrderBy->nExpr>=BMS ){
    pOrderBy = 0;
    wctrlFlags &= ~WHERE_WANT_DISTINCT;
  }

  /* The number of tables in the FROM clause is limited by the number of
  ** bits in a Bitmask
  */
  testcase( pTabList->nSrc==BMS );
  if( pTabList->nSrc>BMS ){
    sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
6023
6024
6025
6026
6027
6028
6029
6030




6031
6032
6033
6034
6035
6036
6037
6083
6084
6085
6086
6087
6088
6089

6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100







-
+
+
+
+







  /* Allocate and initialize the WhereInfo structure that will become the
  ** return value. A single allocation is used to store the WhereInfo
  ** struct, the contents of WhereInfo.a[], the WhereClause structure
  ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte
  ** field (type Bitmask) it must be aligned on an 8-byte boundary on
  ** some architectures. Hence the ROUND8() below.
  */
  nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
  nByteWInfo = ROUND8P(sizeof(WhereInfo));
  if( nTabList>1 ){
    nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
  }
  pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
  if( db->mallocFailed ){
    sqlite3DbFree(db, pWInfo);
    pWInfo = 0;
    goto whereBeginError;
  }
  pWInfo->pParse = pParse;
6077
6078
6079
6080
6081
6082
6083



6084


6085
6086
6087
6088
6089
6090
6091
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149

6150
6151
6152
6153
6154
6155
6156
6157
6158







+
+
+
-
+
+







  if( nTabList==0 ){
    if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
    if( (wctrlFlags & WHERE_WANT_DISTINCT)!=0
     && OptimizationEnabled(db, SQLITE_DistinctOpt)
    ){
      pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    }
    if( ALWAYS(pWInfo->pSelect)
     && (pWInfo->pSelect->selFlags & SF_MultiValue)==0
    ){
    ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
      ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
    }
  }else{
    /* Assign a bit from the bitmask to every term in the FROM clause.
    **
    ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    **
    ** The rule of the previous sentence ensures that if X is the bitmask for
    ** a table T, then X-1 is the bitmask for all other tables to the left of T.
6585
6586
6587
6588
6589
6590
6591





6592
6593
6594
6595
6596
6597
6598
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670







+
+
+
+
+








  /* Jump here if malloc fails */
whereBeginError:
  if( pWInfo ){
    pParse->nQueryLoop = pWInfo->savedNQueryLoop;
    whereInfoFree(db, pWInfo);
  }
#ifdef WHERETRACE_ENABLED
  /* Prevent harmless compiler warnings about debugging routines
  ** being declared but never used */
  sqlite3ShowWhereLoopList(0);
#endif /* WHERETRACE_ENABLED */
  return 0;
}

/*
** Part of sqlite3WhereEnd() will rewrite opcodes to reference the
** index rather than the main table.  In SQLITE_DEBUG mode, we want
** to trace those changes if PRAGMA vdbe_addoptrace=on.  This routine
6824
6825
6826
6827
6828
6829
6830

6831
6832
6833
6834
6835
6836
6837
6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910







+








    /* For a co-routine, change all OP_Column references to the table of
    ** the co-routine into OP_Copy of result contained in a register.
    ** OP_Rowid becomes OP_Null.
    */
    if( pTabItem->fg.viaCoroutine ){
      testcase( pParse->db->mallocFailed );
      assert( pTabItem->regResult>=0 );
      translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
                            pTabItem->regResult, 0);
      continue;
    }

    /* If this scan uses an index, make VDBE code substitutions to read data
    ** from the index instead of from the table where possible.  In some cases
Changes to src/whereInt.h.
498
499
500
501
502
503
504
505

506
507
508
509
510
511
512
498
499
500
501
502
503
504

505
506
507
508
509
510
511
512







-
+







**
** where.c:
*/
Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
void sqlite3WhereClausePrint(WhereClause *pWC);
void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC);
#endif
WhereTerm *sqlite3WhereFindTerm(
  WhereClause *pWC,     /* The WHERE clause to be searched */
  int iCur,             /* Cursor number of LHS */
  int iColumn,          /* Column number of LHS */
  Bitmask notReady,     /* RHS must not overlap with this mask */
  u32 op,               /* Mask of WO_xx values describing operator */
Changes to src/whereexpr.c.
985
986
987
988
989
990
991
992

993
994
995
996
997
998
999
985
986
987
988
989
990
991

992
993
994
995
996
997
998
999







-
+







    iCur = pFrom->a[j].iCursor;
    for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      if( pIdx->aColExpr==0 ) continue;
      for(i=0; i<pIdx->nKeyCol; i++){
        if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
        assert( pIdx->bHasExpr );
        if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
          && pExpr->op!=TK_STRING
         && !sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr)
        ){
          aiCurCol[0] = iCur;
          aiCurCol[1] = XN_EXPR;
          return 1;
        }
      }
    }
Changes to src/window.c.
1160
1161
1162
1163
1164
1165
1166
1167

1168
1169
1170
1171
1172
1173
1174
1160
1161
1162
1163
1164
1165
1166

1167
1168
1169
1170
1171
1172
1173
1174







-
+







** The argument expression is an PRECEDING or FOLLOWING offset.  The
** value should be a non-negative integer.  If the value is not a
** constant, change it to NULL.  The fact that it is then a non-negative
** integer will be caught later.  But it is important not to leave
** variable values in the expression tree.
*/
static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
  if( 0==sqlite3ExprIsConstant(pExpr) ){
  if( 0==sqlite3ExprIsConstant(0,pExpr) ){
    if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr);
    sqlite3ExprDelete(pParse->db, pExpr);
    pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
  }
  return pExpr;
}

Changes to test/aggnested.test.
354
355
356
357
358
359
360


361






362


363

















































































































364
365
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487







+
+

+
+
+
+
+
+

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


do_execsql_test 6.2.2 {
  SELECT ( 
    SELECT c FROM (SELECT t2.b AS c FROM t1) GROUP BY c HAVING t2.b
  )
  FROM t2 GROUP BY 'constant_string';
} {{}}

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

do_execsql_test 7.0 {
  CREATE TABLE invoice (
      id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
      amount DOUBLE PRECISION DEFAULT NULL,
      name VARCHAR(100) DEFAULT NULL
  );

  INSERT INTO invoice (amount, name) VALUES 
      (4.0, 'Michael'), (15.0, 'Bara'), (4.0, 'Michael'), (6.0, 'John');
 
}

do_execsql_test 7.1 {
  SELECT sum(amount), name
    from invoice
  group by name
  having (select v > 6 from (select sum(amount) v) t)
} {
  15.0 Bara
  8.0 Michael
}

do_execsql_test 7.2 {
  SELECT (select 1 from (select sum(amount))) FROM invoice
} {1}

do_execsql_test 8.0 {
  CREATE TABLE t1(x INT);
  INSERT INTO t1 VALUES(100);
  INSERT INTO t1 VALUES(20);
  INSERT INTO t1 VALUES(3);
  SELECT (SELECT y FROM (SELECT sum(x) AS y) AS t2 ) FROM t1;
} {123}

do_execsql_test 8.1 {
  SELECT (
    SELECT y FROM (
      SELECT z AS y FROM (SELECT sum(x) AS z) AS t2 
    ) 
  ) FROM t1;
} {123}

do_execsql_test 8.2 {
  SELECT (
    SELECT a FROM (
      SELECT y AS a FROM (
        SELECT z AS y FROM (SELECT sum(x) AS z) AS t2 
      ) 
    )
  ) FROM t1;
} {123}

#-------------------------------------------------------------------------
# dbsqlfuzz 04408efc51ae46897c4c122b407412045ed221b4
#
reset_db

do_execsql_test 9.1 {
  WITH out(i, j, k) AS ( 
      VALUES(1234, 5678, 9012) 
  )
  SELECT (
    SELECT (
      SELECT min(abc) = ( SELECT ( SELECT 1234 fROM (SELECT abc) ) ) 
      FROM (
        SELECT sum( out.i ) + ( SELECT sum( out.i ) ) AS abc FROM (SELECT out.j)
      )
    ) 
  ) FROM out;
} {0}

do_execsql_test 9.2 {
  CREATE TABLE t1(a);
  CREATE TABLE t2(b);
  INSERT INTO t1 VALUES(1), (2), (3);
  INSERT INTO t2 VALUES(4), (5), (6);

  SELECT ( 
    SELECT min(y) + (SELECT x) FROM (
      SELECT sum(a) AS x, b AS y FROM t2
    )
  )
  FROM t1;
} {10}

do_execsql_test 9.3 {
  SELECT ( 
    SELECT min(y) + (SELECT (SELECT x)) FROM (
      SELECT sum(a) AS x, b AS y FROM t2
    )
  )
  FROM t1;
} {10}

do_execsql_test 9.4 {
  SELECT (
    SELECT (SELECT x) FROM (
      SELECT sum(a) AS x, b AS y FROM t2
      ) GROUP BY y
    )
  FROM t1;
} {6}

do_execsql_test 9.5 {
  SELECT (
    SELECT (SELECT (SELECT x)) FROM (
      SELECT sum(a) AS x, b AS y FROM t2
      ) GROUP BY y
    )
  FROM t1;
} {6}

# 2023-12-16
# New test case for check-in [4470f657d2069972] from 2023-11-02
# https://bugs.chromium.org/p/chromium/issues/detail?id=1511689
#
do_execsql_test 10.1 {
  DROP TABLE IF EXISTS t0;
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t0(c1, c2);  INSERT INTO t0 VALUES(1,2);
  CREATE TABLE t1(c3, c4);  INSERT INTO t1 VALUES(3,4);
  SELECT * FROM t0 WHERE EXISTS (SELECT 1 FROM t1 GROUP BY c3 HAVING ( SELECT count(*) FROM (SELECT 1 UNION ALL SELECT sum(DISTINCT c1) ) ) ) BETWEEN 1 AND 1;
} {1 2}

finish_test
Changes to test/aggorderby.test.
113
114
115
116
117
118
119








































120
121
122
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







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



  WITH c(x,y,z) AS (VALUES('a',4,5),('b',3,6),('b',2,7),('c',1,8))
  SELECT group_concat(DISTINCT x ORDER BY y, z) FROM c;
} {c,b,a}
do_execsql_test aggorderby-8.2 {
  WITH c(x,y) AS (VALUES(1,1),(2,2),(3,3),(3,4),(3,5),(3,6))
  SELECT sum(DISTINCT x ORDER BY y) FROM c;
} 6

# Subtype information is transfered through the sorter for aggregates
# that make use of subtype info.
#
do_execsql_test aggorderby-9.0 {
  WITH c(x,y) AS (VALUES
    ('{a:3}', 3),
    ('[1,1]', 1),
    ('[4,4]', 4),
    ('{x:2}', 2))
  SELECT json_group_array(json(x) ORDER BY y) FROM c;
} {{[[1,1],{"x":2},{"a":3},[4,4]]}}
do_execsql_test aggorderby-9.1 {
  WITH c(x,y) AS (VALUES
    ('[4,4]', 4),
    ('{a:3}', 3),
    ('[4,4]', 4),
    ('[1,1]', 1),
    ('[4,4]', 4),
    ('{x:2}', 2))
  SELECT json_group_array(DISTINCT json(x) ORDER BY y) FROM c;
} {{[[1,1],{"x":2},{"a":3},[4,4]]}}
do_execsql_test aggorderby-9.2 {
  WITH c(x,y) AS (VALUES
    ('{a:3}', 3),
    ('[1,1]', 1),
    ('[4,4]', 4),
    ('{x:2}', 2))
  SELECT json_group_array(json(x) ORDER BY json(x)) FROM c;
} {{[[1,1],[4,4],{"a":3},{"x":2}]}}
do_execsql_test aggorderby-9.3 {
  WITH c(x,y) AS (VALUES
    ('[4,4]', 4),
    ('{a:3}', 3),
    ('[4,4]', 4),
    ('[1,1]', 1),
    ('[4,4]', 4),
    ('{x:2}', 2))
  SELECT json_group_array(DISTINCT json(x) ORDER BY json(x)) FROM c;
} {{[[1,1],[4,4],{"a":3},{"x":2}]}}


finish_test
Changes to test/alter.test.
966
967
968
969
970
971
972












973
974
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986







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


    SELECT unknown_function(a ORDER BY (SELECT group_concat(DISTINCT a ORDER BY a) FROM t1)) FROM t1;
  END;
  ALTER TABLE t2 RENAME TO e;
} {}
do_execsql_test alter-21.2 {
  SELECT name, type FROM sqlite_schema ORDER BY name;
} {e table r1 trigger t1 table}
do_execsql_test alter-21.3 {
  DROP TRIGGER r1;
  CREATE TRIGGER r2 AFTER INSERT ON e BEGIN
    SELECT unknown_function(a ORDER BY (SELECT group_concat(a ORDER BY a) FROM (SELECT b FROM t1))) FROM t1;
  END;
  ALTER TABLE e RENAME TO t99;
}
do_execsql_test alter-21.4 {
  SELECT name, type FROM sqlite_schema ORDER BY name;
} {r2 trigger t1 table t99 table}



finish_test
Changes to test/alter2.test.
367
368
369
370
371
372
373
374

375
376
377
378
379
380
381
367
368
369
370
371
372
373

374
375
376
377
378
379
380
381







-
+







} {1 integer 123 text 123 integer}
do_test alter2-7.5 {
  set sql {CREATE TABLE t1(a, b DEFAULT -123.0, c VARCHAR(10) default 5)}
  alter_table t1 $sql 3
  execsql {
    SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;
  }
} {1 integer -123 integer 5 text}
} {1 integer -123.0 real 5 text}

#-----------------------------------------------------------------------
# Test that UPDATE trigger tables work with default values, and that when
# a row is updated the default values are correctly transfered to the 
# new row.
# 
ifcapable trigger {
393
394
395
396
397
398
399
400

401
402
403
404

405
406
407
408
409
410
411
393
394
395
396
397
398
399

400
401
402
403

404
405
406
407
408
409
410
411







-
+



-
+







  } {}
}
do_test alter2-8.2 {
  execsql {
    UPDATE t1 SET c = 10 WHERE a = 1;
    SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;
  }
} {1 integer -123 integer 10 text}
} {1 integer -123.0 real 10 text}
ifcapable trigger {
  do_test alter2-8.3 {
    set ::val
  } {-123 integer 5 text -123 integer 10 text}
  } {-123.0 real 5 text -123.0 real 10 text}
}

#-----------------------------------------------------------------------
# Test that DELETE trigger tables work with default values, and that when
# a row is updated the default values are correctly transfered to the 
# new row.
# 
421
422
423
424
425
426
427
428

429
430
431
432
433
434
435
421
422
423
424
425
426
427

428
429
430
431
432
433
434
435







-
+







    list
  } {}
  do_test alter2-9.2 {
    execsql {
      DELETE FROM t1 WHERE a = 2;
    }
    set ::val
  } {-123 integer 5 text}
  } {-123.0 real 5 text}
}

#-----------------------------------------------------------------------
# Test creating an index on a column added with a default value. 
#
ifcapable bloblit {
  do_test alter2-10.1 {
Changes to test/altertab3.test.
731
732
733
734
735
736
737



























738
739
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







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


  END}
  {CREATE TRIGGER tr2 AFTER DELETE ON "t3" BEGIN
    SELECT z, y FROM (
      SELECT "t3".* FROM "t3"
    );
  END}
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 30.0 {
  CREATE TABLE t1(a, b);
  CREATE VIEW v1 AS 
      SELECT ( VALUES(a), (b) ) FROM (
        SELECT a, b FROM t1
      )
  ;
}

do_execsql_test 30.1 {
  SELECT * FROM v1
}

do_execsql_test 30.1 {
  ALTER TABLE t1 RENAME TO t2;
}
do_execsql_test 30.2 {
  SELECT sql FROM sqlite_schema WHERE type='view'
} {
  {CREATE VIEW v1 AS 
      SELECT ( VALUES(a), (b) ) FROM (
        SELECT a, b FROM "t2"
      )}
}

finish_test
Changes to test/avfs.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2021-03-06
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
# 
# This file implements tests for the appendvfs extension.
#
# Tests performed:
# avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file.
# avfs-1.1. Test that the DB can be read with correct content upon reopen.
# avfs-1.2. Test that an appendvfs DB can be added to a simple text file.
Changes to test/busy.test.
102
103
104
105
106
107
108
109

110
111
112
113
114
115
116
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116







-
+







    SELECT count(*) FROM sqlite_master;
  } db2
} {6}

proc busy_handler {n} { return 1 }
do_test 3.5 {
  catchsql { PRAGMA optimize }
} {0 {}}
} {1 {database is locked}}

do_test 3.6 {
  execsql { COMMIT } db2
  execsql {
    WITH s(i) AS (
      SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
    )
Added test/cksumvfs.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 March 19
#
# 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.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix cksumvfs

sqlite3_register_cksumvfs
db close
sqlite3 db test.db
file_control_reservebytes db 8

set text [db one "SELECT hex(randomblob(5000))"]

do_execsql_test 1.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1, $text);
}

do_execsql_test 1.1 {
  SELECT * FROM t1;
} [list 1 $text]

finish_test
Changes to test/corruptC.test.
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







-
+








  # insert corrupt byte(s)
  hexio_write test.db 2053 [format %02x 0x04]

  sqlite3 db test.db
  catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
Tree 3 page 3: free space corruption}}}
Tree 3 page 3: free space corruption} {wrong # of entries in index t1i1}}}

# test that a corrupt content offset size is handled (seed 5649)
#
# Update 2016-12-27:  As of check-in [0b86fbca66] "In sqlite3BtreeInsert() when
# replacing a re-existing row, try to overwrite the cell directly rather than
# deallocate and reallocate the cell" on 2016-12-09, this test case no longer
# detects the offset size problem during the UPDATE.  We have to run a subsequent
Changes to test/corruptD.test.
109
110
111
112
113
114
115
116

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

116
117
118
119
120
121
122
123







-
+







# containing the offset of the first free block in a page. 
#
do_test corruptD-1.1.1 {
  incr_change_counter
  hexio_write test.db [expr 1024+1] FFFF
  catchsql { PRAGMA quick_check }
} {0 {{*** in database main ***
Tree 2 page 2: free space corruption}}}
Tree 2 page 2: free space corruption} {wrong # of entries in index i1}}}
do_test corruptD-1.1.2 {
  incr_change_counter
  hexio_write test.db [expr 1024+1] [hexio_render_int32 1021]
  catchsql { SELECT * FROM t1 ORDER BY rowid }
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
Changes to test/date.test.
142
143
144
145
146
147
148


149
150
151
152
153
154
155
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157







+
+







datetest 2.46 {datetime('2003-10-22 12:24','70 second')} {2003-10-22 12:25:10}
datetest 2.47 {datetime('2003-10-22 12:24','8.6 seconds')} {2003-10-22 12:24:08}
datetest 2.48 {datetime('2003-10-22 12:24','9.4 second')} {2003-10-22 12:24:09}
datetest 2.49 {datetime('2003-10-22 12:24','0000 second')} {2003-10-22 12:24:00}
datetest 2.50 {datetime('2003-10-22 12:24','0001 second')} {2003-10-22 12:24:01}
datetest 2.51 {datetime('2003-10-22 12:24','nonsense')} NULL

datetest 2.60 {datetime('2023-02-31')} {2023-03-03 00:00:00}

datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31
datetest 3.2.1 {strftime('pre%fpost','2003-10-31 12:34:56.432')} pre56.432post
datetest 3.2.2 {strftime('%f','2003-10-31 12:34:59.9999999')} 59.999
datetest 3.3 {strftime('%H','2003-10-31 12:34:56.432')} 12
datetest 3.4 {strftime('%j','2003-10-31 12:34:56.432')} 304
datetest 3.5 {strftime('%J','2003-10-31 12:34:56.432')} 2452944.024264259
datetest 3.6 {strftime('%m','2003-10-31 12:34:56.432')} 10
203
204
205
206
207
208
209
210
211


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


212
213
214
215
216
217
218
219
220







-
-
+
+







  }
  return $x
}
datetest 3.16 "strftime('[repeat 200 %Y]','2003-10-31')" [repeat 200 2003]
datetest 3.17 "strftime('[repeat 200 abc%m123]','2003-10-31')" \
    [repeat 200 abc10123]

foreach c {a b c g h i n o q r t v x y z
           A B C D E G K L N O Q V Z
foreach c {a b c h i n o q r t v x y z
           A B C D E K L N O Q Z
           0 1 2 3 4 5 6 6 7 9 _} {
  datetest 3.18.$c "strftime('%$c','2003-10-31')" NULL
}
datetest 3.20 {strftime('%e','2023-08-09')} { 9}
datetest 3.21 {strftime('%F %T','2023-08-09 01:23')} {2023-08-09 01:23:00}
datetest 3.22 {strftime('%k','2023-08-09 04:59:59')} { 4}
datetest 3.23 {strftime('%I%P','2023-08-09 11:59:59')} {11am}
256
257
258
259
260
261
262
263

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

265
266
267
268
269
270
271
272







-
+







datetest 5.13 {datetime('1994-04-16 14:00:00Zulu')} NULL
datetest 5.14 {datetime('1994-04-16 14:00:00Z +05:00')} NULL
datetest 5.15 {datetime('1994-04-16 14:00:00 +05:00 Z')} NULL

# localtime->utc and utc->localtime conversions.
#
# Use SQLITE_TESTCTRL_LOCALTIME_FAULT=2 to set an alternative localtime_r()
# implementation that is not locale-dependent.  This testing localtime_r()
# implementation that is not locale-dependent.  The testing localtime_r()
# operates as follows:
#
#     (1)  Localtime is 30 minutes earlier than (west of) UTC on
#          even days (counting from 1970-01-01)
#
#     (2)  Localtime is 30 minutes later than (east of) UTC on odd days.
#
314
315
316
317
318
319
320
































321
322
323
324
325
326
327
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







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








# Modifiers work for dates that are way out of band for localtime_r()
#
local_to_utc 6.21 {1800-10-29 12:00:00} {1800-10-29 12:30:00}
utc_to_local 6.22 {1800-10-29 12:30:00} {1800-10-29 12:00:00}
local_to_utc 6.23 {3000-10-30 12:00:00} {3000-10-30 11:30:00}
utc_to_local 6.24 {3000-10-30 11:30:00} {3000-10-30 12:00:00}

# If the time is specified to be ZULU, or if it has an explicit
# timezone extension, then the time will already be UTC and subsequent
# 'utc' modifiers are no-ops.
#
do_execsql_test date-6.25 {
  SELECT datetime('2000-10-29 12:00Z','utc','utc');
} {{2000-10-29 12:00:00}}
do_execsql_test date-6.26 {
  SELECT datetime('2000-10-29 12:00:00+05:00');
} {{2000-10-29 07:00:00}}
do_execsql_test date-6.27 {
  SELECT datetime('2000-10-29 12:00:00+05:00', 'utc');
} {{2000-10-29 07:00:00}}

# Multiple back-and-forth UTC to LOCAL to UTC...
do_execsql_test date-6.28 {
  SELECT datetime('2000-10-29 12:00:00Z', 'localtime');
} {{2000-10-29 12:30:00}}
do_execsql_test date-6.29 {
  SELECT datetime('2000-10-29 12:00:00Z', 'utc', 'localtime');
} {{2000-10-29 12:30:00}}
do_execsql_test date-6.30 {
  SELECT datetime('2000-10-29 12:00:00Z', 'utc', 'localtime', 'utc');
} {{2000-10-29 12:00:00}}
do_execsql_test date-6.31 {
  SELECT datetime('2000-10-29 12:00:00Z', 'utc','localtime','utc','localtime');
} {{2000-10-29 12:30:00}}
do_execsql_test date-6.32 {
  SELECT datetime('2000-10-29 12:00:00Z', 'localtime','localtime');
} {{2000-10-29 12:30:00}}


# Restore the use of the OS localtime_r() before going on...
sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0

# Date-time functions that contain NULL arguments return a NULL
# result.
#
448
449
450
451
452
453
454



455
456
457
458
459
460
461
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498







+
+
+







datetest 13.24 {julianday(2454832.5,'+1.5 years')} {2455380.0}

datetest 13.30 {date('2000-01-01','+1.5 years')} {2001-07-02}
datetest 13.31 {date('2001-01-01','+1.5 years')} {2002-07-02}
datetest 13.32 {date('2002-01-01','+1.5 years')} {2003-07-02}
datetest 13.33 {date('2002-01-01','-1.5 years')} {2000-07-02}
datetest 13.34 {date('2001-01-01','-1.5 years')} {1999-07-02}
datetest 13.35 {date('2023-02-28')} {2023-02-28}
datetest 13.36 {date('2023-02-29')} {2023-03-01}
datetest 13.37 {date('2023-04-31')} {2023-05-01}

# Test for issues reported by BareFeet (list.sql at tandb.com.au)
# on mailing list on 2008-06-12.
#
# Put a floating point number in the database so that we can manipulate
# raw bits using the hexio interface.
#
564
565
566
567
568
569
570















































571
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







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


# 2023-04 The 'subsecond' (or 'subsec') modifier alters resolutions
# to at least milliseconds. Added for release 3.42.0 .
datetest 18.2 {unixepoch('1970-01-01T00:00:00.1', 'subsec')} {0.1}
datetest 18.3 {unixepoch('1970-01-01T00:00:00.2', 'subsecond')} {0.2}
datetest 18.4 {julianday('-4713-11-24 13:40:48.864', 'subsec')} {0.07001}
datetest 18.5 {typeof(unixepoch('now', 'subsecond'))} {real}

# 2024-03-03 the 'ceiling' and 'floor' operators.
#
datetest 19.1 {date('2000-01-31','floor')} {2000-01-31}
datetest 19.2a {date('2000-02-31','floor')} {2000-02-29}
datetest 19.2b {date('1999-02-31','floor')} {1999-02-28}
datetest 19.2c {date('1900-02-31','floor')} {1900-02-28}
datetest 19.3 {date('2000-03-31','floor')} {2000-03-31}
datetest 19.4 {date('2000-04-31','floor')} {2000-04-30}
datetest 19.5 {date('2000-05-31','floor')} {2000-05-31}
datetest 19.6 {date('2000-06-31','floor')} {2000-06-30}
datetest 19.7 {date('2000-07-31','floor')} {2000-07-31}
datetest 19.8 {date('2000-08-31','floor')} {2000-08-31}
datetest 19.9 {date('2000-09-31','floor')} {2000-09-30}
datetest 19.10 {date('2000-10-31','floor')} {2000-10-31}
datetest 19.11 {date('2000-11-31','floor')} {2000-11-30}
datetest 19.12 {date('2000-12-31','floor')} {2000-12-31}
datetest 19.21 {date('2000-01-31','ceiling')} {2000-01-31}
datetest 19.22a {date('2000-02-31','ceiling')} {2000-03-02}
datetest 19.22b {date('1999-02-31','ceiling')} {1999-03-03}
datetest 19.22c {date('1900-02-31','ceiling')} {1900-03-03}
datetest 19.23 {date('2000-03-31','ceiling')} {2000-03-31}
datetest 19.24 {date('2000-04-31','ceiling')} {2000-05-01}
datetest 19.25 {date('2000-05-31','ceiling')} {2000-05-31}
datetest 19.26 {date('2000-06-31','ceiling')} {2000-07-01}
datetest 19.27 {date('2000-07-31','ceiling')} {2000-07-31}
datetest 19.28 {date('2000-08-31','ceiling')} {2000-08-31}
datetest 19.29 {date('2000-09-31','ceiling')} {2000-10-01}
datetest 19.30 {date('2000-10-31','ceiling')} {2000-10-31}
datetest 19.31 {date('2000-11-31','ceiling')} {2000-12-01}
datetest 19.32 {date('2000-12-31','ceiling')} {2000-12-31}
datetest 19.40 {date('2024-01-31','+1 month','ceiling')} {2024-03-02}
datetest 19.41 {date('2024-01-31','+1 month','floor')} {2024-02-29}
datetest 19.42 {date('2023-01-31','+1 month','ceiling')} {2023-03-03}
datetest 19.43 {date('2023-01-31','+1 month','floor')} {2023-02-28}
datetest 19.44 {date('2024-02-29','+1 year','ceiling')} {2025-03-01}
datetest 19.45 {date('2024-02-29','+1 year','floor')} {2025-02-28}
datetest 19.46 {date('2024-02-29','-110 years','ceiling')} {1914-03-01}
datetest 19.47 {date('2024-02-29','-110 years','floor')} {1914-02-28}
datetest 19.48 {date('2024-02-29','-0110-00-00','floor')} {1914-02-28}
datetest 19.49 {date('2024-02-29','-0110-00-00','ceiling')} {1914-03-01}
datetest 19.50 {date('2000-08-31','+0023-06-00','floor')} {2024-02-29}
datetest 19.51 {date('2000-08-31','+0022-06-00','floor')} {2023-02-28}
datetest 19.52 {date('2000-08-31','+0023-06-00','ceiling')} {2024-03-02}
datetest 19.53 {date('2000-08-31','+0022-06-00','ceiling')} {2023-03-03}


finish_test
Changes to test/date4.test.
20
21
22
23
24
25
26
27

28
29
30
31
32


33
34
35
36
37
38
20
21
22
23
24
25
26

27
28
29
30


31
32
33
34
35
36
37
38







-
+



-
-
+
+






#
ifcapable {!datetime} {
  finish_test
  return
}

if {$tcl_platform(os)=="Linux"} {
  set FMT {%d,%e,%F,%H,%k,%I,%l,%j,%m,%M,%u,%w,%W,%Y,%%,%P,%p}
  set FMT {%d,%e,%F,%H,%k,%I,%l,%j,%m,%M,%u,%w,%W,%Y,%%,%P,%p,%U,%V,%G,%g}
} else {
  set FMT {%d,%e,%F,%H,%I,%j,%p,%R,%u,%w,%W,%%}
}
for {set i 0} {$i<=24854} {incr i} {
  set TS [expr {$i*86401}]
for {set i 0} {$i<=24858} {incr i} {
  set TS [expr {$i*86390}]
  do_execsql_test date4-$i {
    SELECT strftime($::FMT,$::TS,'unixepoch');
  } [list [strftime $FMT $TS]]
}

finish_test
Changes to test/distinctagg.test.
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105







-
+







  3  1  "SELECT count(DISTINCT c) FROM t1"                4
  4  0  "SELECT count(DISTINCT c) FROM t1 WHERE b=3"      3
  5  0  "SELECT count(DISTINCT rowid) FROM t1"           10
  6  0  "SELECT count(DISTINCT a) FROM t1, t2"            5
  7  0  "SELECT count(DISTINCT a) FROM t2, t1"            5
  8  1  "SELECT count(DISTINCT a+b) FROM t1, t2, t2, t2"  6
  9  0  "SELECT count(DISTINCT c) FROM t1 WHERE c=2"      1
 10  1  "SELECT count(DISTINCT t1.rowid) FROM t1, t2"    10
 10  0  "SELECT count(DISTINCT t1.rowid) FROM t1, t2"    10
} {
  do_test 3.$tn.1 {
    set prg [db eval "EXPLAIN $sql"]
    set idx [lsearch $prg OpenEphemeral]
    expr {$idx>=0}
  } $use_eph

144
145
146
147
148
149
150




151
152
153
154
155
156
157
158
159
160



161
162
163
164
165
166
167
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







+
+
+
+










+
+
+







  INSERT INTO t2 VALUES(2, 3, 'x');
  INSERT INTO t2 VALUES(2, 3, 'y');
  INSERT INTO t2 VALUES(2, 3, 'z');

  CREATE TABLE t3(x, y, z);
  INSERT INTO t3 VALUES(1,1,1);
  INSERT INTO t3 VALUES(2,2,2);

  CREATE TABLE t4(a);
  CREATE INDEX t4a ON t4(a);
  INSERT INTO t4 VALUES(1), (2), (2), (3), (1);
}

foreach {tn use_eph sql res} {
  1 0  "SELECT count(DISTINCT c) FROM t1 GROUP BY b"   {2 3 0 1}
  2 1  "SELECT count(DISTINCT a) FROM t1 GROUP BY b"   {2 3 0 1}
  3 1  "SELECT count(DISTINCT a) FROM t1 GROUP BY b+c" {0 1 1 1 1}

  4 0  "SELECT count(DISTINCT f) FROM t2 GROUP BY d, e" {1 2 2 3}
  5 1  "SELECT count(DISTINCT f) FROM t2 GROUP BY d" {2 3}
  6 0  "SELECT count(DISTINCT f) FROM t2 WHERE d IS 1 GROUP BY e" {1 2 2}

  7 0  "SELECT count(DISTINCT a) FROM t1" {4}
  8 0  "SELECT count(DISTINCT a) FROM t4" {3}
} {
  do_test 4.$tn.1 {
    set prg [db eval "EXPLAIN $sql"]
    set idx [lsearch $prg OpenEphemeral]
    expr {$idx>=0}
  } $use_eph

Changes to test/e_reindex.test.
69
70
71
72
73
74
75


76
77
78
79

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

81


82
83
84
85
86
87
88







+
+



-
+
-
-







} {}

db close
sqlite3 db test.db
do_execsql_test e_reindex-1.3 {
  PRAGMA integrity_check;
} [list \
  {wrong # of entries in index i2} \
  {wrong # of entries in index i1} \
  {row 3 missing from index i2} \
  {row 3 missing from index i1} \
  {row 4 missing from index i2} \
  {row 4 missing from index i1} \
  {row 4 missing from index i1} 
  {wrong # of entries in index i2} \
  {wrong # of entries in index i1}
]

do_execsql_test e_reindex-1.4 {
  REINDEX;
  PRAGMA integrity_check;
} {ok}

Changes to test/fts3fault3.test.
45
46
47
48
49
50
51




























52
53
54
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







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



    DELETE FROM t1;
  }
} -test {
  catchsql { COMMIT }
  faultsim_integrity_check
  faultsim_test_result {0 {}}
}

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

do_execsql_test 2.0 {
  BEGIN;
  CREATE VIRTUAL TABLE t1 USING fts3(a);
  WITH s(i) AS (
      SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50
  )
  INSERT INTO t1 SELECT 'abc def ghi jkl mno pqr' FROM s;
  COMMIT;
}

faultsim_save_and_close
do_faultsim_test 2 -faults oom-t* -prep { 
  faultsim_restore_and_reopen
  execsql {
    BEGIN;
      CREATE TABLE x1(a PRIMARY KEY);
  }
} -body {
  execsql {
    PRAGMA integrity_check;
  }
} -test {
  faultsim_test_result {0 ok} $::TMPDBERROR
}


finish_test
Added test/fts3integrity.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023 December 16
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: fts3.test,v 1.2 2008/07/23 18:17:32 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix fts3integrity

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
  finish_test
  return
}
  
do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts3(x);
  INSERT INTO t1 VALUES('first row');
  INSERT INTO t1 VALUES('second row');

  CREATE TABLE t2(x PRIMARY KEY);
  INSERT INTO t2 VALUES('first row');
  INSERT INTO t2 VALUES('second row');
}

sqlite3 db2 test.db

do_execsql_test -db db2 1.1 {
  CREATE TABLE t3(x, y);
}

do_execsql_test 1.2 {
  PRAGMA integrity_check;
} {ok}

finish_test
Changes to test/fts4intck1.test.
49
50
51
52
53
54
55

















56
57
58
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







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



  PRAGMA integrity_check(t2);
} {ok}

proc slang {in} {return $in}
do_execsql_test 2.3 {
  PRAGMA integrity_check(t2);
} {{malformed inverted index for FTS4 table main.t2}}

#-------------------------------------------------------------------------
# Test that integrity-check works on a read-only database.
#
reset_db
do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE x1 USING fts4(a, b);
  INSERT INTO x1 VALUES('one', 'two');
  INSERT INTO x1 VALUES('three', 'four');
}
db close
sqlite3 db test.db -readonly 1

do_execsql_test 3.1 {
  PRAGMA integrity_check;
} {ok}



finish_test
Changes to test/func.test.
781
782
783
784
785
786
787





788
789
790
791
792
793
794
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799







+
+
+
+
+







  sqlite3_bind_blob $::STMT 1 abc 3
  sqlite3_step $::STMT
  sqlite3_finalize $::STMT
  execsql {
    SELECT quote(a), quote(b) FROM tbl2;
  }
} {X'616263' NULL}

# Test the quote function for +Inf and -Inf
do_execsql_test func-16.2 {
  SELECT quote(4.2e+859), quote(-7.8e+904);
} {9.0e+999 -9.0e+999}

# Correctly handle function error messages that include %.  Ticket #1354
#
do_test func-17.1 {
  proc testfunc1 args {error "Error %d with %s percents %p"}
  db function testfunc1 ::testfunc1
  catchsql {
1038
1039
1040
1041
1042
1043
1044



1045
1046
1047
1048
1049
1050
1051
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059







+
+
+







  }
} {{This is the larger-main test string}}
do_test func-21.8 {
  execsql {
    SELECT replace('aaaaaaa', 'a', '0123456789');
  }
} {0123456789012345678901234567890123456789012345678901234567890123456789}
do_execsql_test func-21.9 {
  SELECT typeof(replace(1,'',0));
} {text}

ifcapable tclvar {
  do_test func-21.9 {
    # Attempt to exploit a buffer-overflow that at one time existed 
    # in the REPLACE function. 
    set ::str "[string repeat A 29998]CC[string repeat A 35537]"
    set ::rep [string repeat B 65536]
Changes to test/func4.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

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
-
+










-
+
+
+
+













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







# 2013 March 10
# 2023-03-10
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The focus of
# this file is testing the tointeger() and toreal() functions.
# this file is testing the tointeger() and toreal() functions that are
# part of the "totype.c" extension.  This file does not test the core
# SQLite library.  Failures of tests in this file are related to the
# ext/misc/totype.c extension.
#
# Several of the toreal() tests are disabled on platforms where floating
# point precision is not high enough to represent their constant integer
# expression arguments as double precision floating point values.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set saved_tcl_precision $tcl_precision
set tcl_precision 0
load_static_extension db totype

set highPrecision(1) [expr \
    {[db eval {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}]
set highPrecision(2) [expr \
    {[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]

# highPrecision(3) is only known to be false on i586 with gcc-13 and -O2.
# It is true on the exact same platform with -O0.  Both results seem
# reasonable, so we'll just very the expectation accordingly.
#
set highPrecision(3) [expr \
    {[db eval {SELECT toreal(9007199254740992 + 1);}] eq {{}}}]

if {!$highPrecision(1) || !$highPrecision(2) || !$highPrecision(3)} {
  puts "NOTICE: use_long_double: [use_long_double] \
        highPrecision: $highPrecision(1) $highPrecision(2) $highPrecision(3)"
}

do_execsql_test func4-1.1 {
  SELECT tointeger(NULL);
} {{}}
do_execsql_test func4-1.2 {
  SELECT tointeger('');
} {{}}
88
89
90
91
92
93
94
95

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

112
113
114
115
116
117
118
119







-
+







  SELECT tointeger(-1.79769313486232e308);
} {{}}
do_execsql_test func4-1.22 {
  SELECT tointeger(-1.79769313486232e308 + 1);
} {{}}
do_execsql_test func4-1.23 {
  SELECT tointeger(-9223372036854775808 - 1);
} {-9223372036854775808}
} {{}}
do_execsql_test func4-1.24 {
  SELECT tointeger(-9223372036854775808);
} {-9223372036854775808}
do_execsql_test func4-1.25 {
  SELECT tointeger(-9223372036854775808 + 1);
} {-9223372036854775807}
do_execsql_test func4-1.26 {
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
208
209
210
211
212
213
214


215
216
217
218
219
220
221







-
-







  SELECT tointeger(18446744073709551616);
} {{}}
do_execsql_test func4-1.55 {
  SELECT tointeger(18446744073709551616 + 1);
} {{}}

ifcapable floatingpoint {
  set highPrecision(2) [expr \
      {[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]

  do_execsql_test func4-2.1 {
    SELECT toreal(NULL);
  } {{}}
  do_execsql_test func4-2.2 {
    SELECT toreal('');
  } {{}}
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280

281
282
283
284
285
286
287
280
281
282
283
284
285
286

287
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302







-
+







-
+







    SELECT toreal(-1.79769313486232e308 + 1);
  } {-Inf}
  do_execsql_test func4-2.23 {
    SELECT toreal(-9223372036854775808 - 1);
  } {-9.223372036854776e+18}
  do_execsql_test func4-2.24 {
    SELECT toreal(-9223372036854775808);
  } {-9.223372036854776e+18}
  } {{}}
  if {$highPrecision(2)} {
    do_execsql_test func4-2.25 {
      SELECT toreal(-9223372036854775808 + 1);
    } {{}}
  }
  do_execsql_test func4-2.26 {
    SELECT toreal(-9223372036854775807 - 1);
  } {-9.223372036854776e+18}
  } {{}}
  if {$highPrecision(2)} {
    do_execsql_test func4-2.27 {
      SELECT toreal(-9223372036854775807);
    } {{}}
    do_execsql_test func4-2.28 {
      SELECT toreal(-9223372036854775807 + 1);
    } {{}}
337
338
339
340
341
342
343
344

345
346
347




348
349
350
351
352
353
354
352
353
354
355
356
357
358

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







-
+



+
+
+
+







  } {4503599627370497.0}
  do_execsql_test func4-2.44 {
    SELECT toreal(9007199254740992 - 1);
  } {9007199254740991.0}
  do_execsql_test func4-2.45 {
    SELECT toreal(9007199254740992);
  } {9007199254740992.0}
  if {$highPrecision(2)} {
  if {$highPrecision(3)} {
    do_execsql_test func4-2.46 {
      SELECT toreal(9007199254740992 + 1);
    } {{}}
  } else {
    do_execsql_test func4-2.46 {
      SELECT toreal(9007199254740992 + 1);
    } {9007199254740992.0}
  }
  do_execsql_test func4-2.47 {
    SELECT toreal(9007199254740992 + 2);
  } {9007199254740994.0}
  do_execsql_test func4-2.48 {
    SELECT toreal(tointeger(9223372036854775808) - 1);
  } {{}}
457
458
459
460
461
462
463
464

465
466
467
468
469
470
471
476
477
478
479
480
481
482

483
484
485
486
487
488
489
490







-
+







      INSERT INTO t1 (x) VALUES (1234.00);
    }
  } {0 {}}
  do_test func4-3.18 {
    catchsql {
      INSERT INTO t1 (x) VALUES ('-9223372036854775809');
    }
  } {0 {}}
  } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}}
  if {$highPrecision(1)} {
    do_test func4-3.19 {
      catchsql {
        INSERT INTO t1 (x) VALUES (9223372036854775808);
      }
    } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}}
  }
569
570
571
572
573
574
575
576

577
578
579

580
581
582
583
584
585
586
588
589
590
591
592
593
594

595
596
597

598
599
600
601
602
603
604
605







-
+


-
+







    SELECT tointeger(toreal(0));
  } {0}
  do_execsql_test func4-5.5 {
    SELECT tointeger(toreal(1));
  } {1}
  do_execsql_test func4-5.6 {
    SELECT tointeger(toreal(-9223372036854775808 - 1));
  } {-9223372036854775808}
  } {{}}
  do_execsql_test func4-5.7 {
    SELECT tointeger(toreal(-9223372036854775808));
  } {-9223372036854775808}
  } {{}}
  if {$highPrecision(2)} {
    do_execsql_test func4-5.8 {
      SELECT tointeger(toreal(-9223372036854775808 + 1));
    } {{}}
  }
  do_execsql_test func4-5.9 {
    SELECT tointeger(toreal(-2147483648 - 1));
622
623
624
625
626
627
628
629

630
631
632




633
634
635
636
637
638
639
641
642
643
644
645
646
647

648
649
650
651
652
653
654
655
656
657
658
659
660
661
662







-
+



+
+
+
+







  } {4503599627370497}
  do_execsql_test func4-5.21 {
    SELECT tointeger(toreal(9007199254740992 - 1));
  } {9007199254740991}
  do_execsql_test func4-5.22 {
    SELECT tointeger(toreal(9007199254740992));
  } {9007199254740992}
  if {$highPrecision(2)} {
  if {$highPrecision(3)} {
    do_execsql_test func4-5.23 {
      SELECT tointeger(toreal(9007199254740992 + 1));
    } {{}}
  } else {
    do_execsql_test func4-5.23 {
      SELECT tointeger(toreal(9007199254740992 + 1));
    } {9007199254740992}
  }
  do_execsql_test func4-5.24 {
    SELECT tointeger(toreal(9007199254740992 + 2));
  } {9007199254740994}
  if {$highPrecision(1)} {
    do_execsql_test func4-5.25 {
      SELECT tointeger(toreal(9223372036854775808 - 1));
Changes to test/fuzzcheck.c.
155
156
157
158
159
160
161
162

163
164


165
166
167
168
169
170
171
155
156
157
158
159
160
161

162
163

164
165
166
167
168
169
170
171
172







-
+

-
+
+







  Blob *pFirstSql;                 /* First SQL script */
  unsigned int uRandom;            /* Seed for the SQLite PRNG */
  unsigned int nInvariant;         /* Number of invariant checks run */
  char zTestName[100];             /* Name of current test */
} g;

/*
** Include the external vt02.c module.
** Include the external vt02.c and randomjson.c modules.
*/
extern int sqlite3_vt02_init(sqlite3*,char***,void*);
extern int sqlite3_vt02_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_randomjson_init(sqlite3*,char**,const sqlite3_api_routines*);


/*
** Print an error message and quit.
*/
static void fatalError(const char *zFormat, ...){
  va_list ap;
1263
1264
1265
1266
1267
1268
1269


1270
1271
1272
1273
1274
1275
1276
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279







+
+







    sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, lengthLimit);
  }
  if( depthLimit>0 ){
    sqlite3_limit(cx.db, SQLITE_LIMIT_EXPR_DEPTH, depthLimit);
  }
  sqlite3_limit(cx.db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 100);
  sqlite3_hard_heap_limit64(heapLimit);
  rc = 1;
  sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &rc);

  if( nDb>=20 && aDb[18]==2 && aDb[19]==2 ){
    aDb[18] = aDb[19] = 1;
  }
  rc = sqlite3_deserialize(cx.db, "main", aDb, nDb, nDb,
          SQLITE_DESERIALIZE_RESIZEABLE |
          SQLITE_DESERIALIZE_FREEONCLOSE);
1290
1291
1292
1293
1294
1295
1296



1297
1298
1299
1300
1301
1302
1303
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309







+
+
+








  /* Block debug pragmas and ATTACH/DETACH.  But wait until after
  ** deserialize to do this because deserialize depends on ATTACH */
  sqlite3_set_authorizer(cx.db, block_troublesome_sql, &btsFlags);

  /* Add the vt02 virtual table */
  sqlite3_vt02_init(cx.db, 0, 0);

  /* Add the random_json() and random_json5() functions */
  sqlite3_randomjson_init(cx.db, 0, 0);

  /* Add support for sqlite_dbdata and sqlite_dbptr virtual tables used
  ** by the recovery API */
  sqlite3_dbdata_init(cx.db, 0, 0);

  /* Consistent PRNG seed */
#ifdef SQLITE_TESTCTRL_PRNG_SEED
Changes to test/in4.test.
454
455
456
457
458
459
460
461

462
463
464
465
466
467
468

469
470
471
472
473
474
475
454
455
456
457
458
459
460

461
462
463
464
465
466
467

468
469
470
471
472
473
474
475







-
+






-
+







  ANALYZE sqlite_schema;
  INSERT INTO sqlite_stat1 VALUES('t1','t1abc','10000 5 00 2003 10');
  ANALYZE sqlite_schema;
} {}
do_execsql_test 11.1 {
  SELECT * FROM t1
   WHERE b IN (345, (SELECT 1 FROM t1 
                      WHERE b IN (345 NOT GLOB 510)
                      WHERE b IN (coalesce(1,random()))
                        AND c GLOB 'abc*xyz'))
     AND c BETWEEN 'abc' AND 'xyz';
} {xyz 1 abcdefxyz 99}
do_execsql_test 11.2 {
  EXPLAIN SELECT * FROM t1
   WHERE b IN (345, (SELECT 1 FROM t1 
                      WHERE b IN (345 NOT GLOB 510)
                      WHERE b IN (coalesce(1,random()))
                        AND c GLOB 'abc*xyz'))
     AND c BETWEEN 'abc' AND 'xyz';
} {/ SeekScan /}

# 2021-06-25 ticket 6dcbfd11cf666e21
# Another problem with OP_SeekScan
#
Changes to test/json/README.md.
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
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







+
+
-
+

-
+

-
+



-
+




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

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



-
+

-
+


+
+
+
-
+




-
-
-
-
-
+
+
+
+
-
The files in this subdirectory are used to help measure the performance
of the SQLite JSON functions, especially in relation to handling large
JSON inputs.

# 1.0 Prerequisites

  *   Standard SQLite build environment (SQLite source tree, compiler, make, etc.)

  1.  Valgrind
  *   Valgrind

  2.  Fossil
  *   Fossil (only the "fossil xdiff" command is used by this procedure)

  3.  tclsh
  *   tclsh

# 2.0 Setup

  1.  Run: "`tclsh json-generator.tcl | sqlite3 json100mb.db`" to create
  *   Run: "`tclsh json-generator.tcl | sqlite3 json100mb.db`" to create
      the 100 megabyte test database.  Do this so that the "json100mb.db"
      file lands in the directory from which you will run tests, not in
      the test/json subdirectory of the source tree.

  *   Make a copy of "json100mb.db" into "jsonb100mb.db" - change the prefix
      from "json" to "jsonb".

  *   Bring up jsonb100mb.db in the sqlite3 command-line shell.
      Convert all of the content into JSONB using a commands like this:

>        UPDATE data1 SET x=jsonb(x);
>        VACUUM;

  2.  Build the baseline sqlite3.c file with sqlite3.h and shell.c.
      ("`CFLAGS='-Os -g' make -e clean sqlite3.c`")
  *   Build the baseline sqlite3.c file with sqlite3.h and shell.c.

>        make clean sqlite3.c

  3.  Run "`sh json-speed-check.sh trunk`".   This creates the baseline
      profile in "jout-trunk.txt".
  *   Run "`sh json-speed-check.sh trunk`".   This creates the baseline
      profile in "jout-trunk.txt" for the preformance test using text JSON.

  *   Run "`sh json-speed-check.sh trunk --jsonb`".  This creates the
      baseline profile in "joutb-trunk.txt" for the performance test
      for processing JSONB

  *   (Optional) Verify that the json100mb.db database really does contain
      approximately 100MB of JSON content by running:

>        SELECT sum(length(x)) FROM data1;
>        SELECT * FROM data1 WHERE NOT json_valid(x);

# 3.0 Testing

  1.  Build the sqlite3.c (with sqlite3.h and shell.c) to be tested.
  *   Build the sqlite3.c (with sqlite3.h and shell.c) to be tested.

  2.  Run "`sh json-speed-check.sh x1`".  The profile output will appear
  *   Run "`sh json-speed-check.sh x1`".  The profile output will appear
      in jout-x1.txt.  Substitute any label you want in place of "x1".

  *   Run "`sh json-speed-check.sh x1 --jsonb`".  The profile output will appear
      in joutb-x1.txt.  Substitute any label you want in place of "x1".

  3.  Run the script shown below in the CLI.
  *   Run the script shown below in the CLI.
      Divide 2500 by the real elapse time from this test
      to get an estimate for number of MB/s that the JSON parser is
      able to process.

> ~~~~
.open json100mb.db
.timer on
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<25)
SELECT sum(json_valid(x)) FROM c, data1;
>        .open json100mb.db
>        .timer on
>        WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<25)
>        SELECT sum(json_valid(x)) FROM c, data1;
~~~~
Changes to test/json/json-speed-check.sh.
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
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







+





+














+
+
+
+















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

LEAN_OPTS="$LEAN_OPTS -DSQLITE_MAX_EXPR_DEPTH=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DECLTYPE"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DEPRECATED"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_PROGRESS_CALLBACK"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA"
BASELINE="trunk"
TYPE="json"
doExplain=0
doCachegrind=1
doVdbeProfile=0
doWal=1
doDiff=1
doJsonB=0
while test "$1" != ""; do
  case $1 in
    --nodiff)
	doDiff=0
        ;;
    --lean)
        CC_OPTS="$CC_OPTS $LEAN_OPTS"
        ;;
    --clang)
        CC=clang
        ;;
    --gcc7)
        CC=gcc-7
        ;;
    --jsonb)
        doJsonB=1
        TYPE="jsonb"
        ;;
    -*)
        CC_OPTS="$CC_OPTS $1"
        ;;
    *)
	BASELINE=$1
        ;;
  esac
  shift
done
echo "NAME           = $NAME" | tee summary-$NAME.txt
echo "CC_OPTS        = $CC_OPTS" | tee -a summary-$NAME.txt
rm -f cachegrind.out.* jsonshell
$CC -g -Os -Wall -I. $CC_OPTS ./shell.c ./sqlite3.c -o jsonshell -ldl -lpthread
ls -l jsonshell | tee -a summary-$NAME.txt
home=`echo $0 | sed -e 's,/[^/]*$,,'`
DB=$TYPE''100mb.db
echo ./jsonshell json100mb.db "<$home/json-q1.txt"
valgrind --tool=cachegrind ./jsonshell json100mb.db <$home/json-q1.txt \
      2>&1 | tee -a summary-$NAME.txt
cg_anno.tcl cachegrind.out.* >jout-$NAME.txt
echo '*****************************************************' >>jout-$NAME.txt
sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>jout-$NAME.txt
if test "$NAME" != "$BASELINE"; then
  fossil xdiff --tk -c 20 jout-$BASELINE.txt jout-$NAME.txt
echo ./jsonshell $DB "<$home/$TYPE-q1.txt"
valgrind --tool=cachegrind ./jsonshell json100mb_b.db <$home/$TYPE-q1.txt \
        2>&1 | tee -a summary-$NAME.txt
cg_anno.tcl cachegrind.out.* >$TYPE-$NAME.txt
echo '*****************************************************' >>$TYPE-$NAME.txt
sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>$TYPE-$NAME.txt
if test "$NAME" != "$BASELINE" -a $doDiff -ne 0; then
  fossil xdiff --tk -c 20 $TYPE-$BASELINE.txt $TYPE-$NAME.txt
fi
Added test/json/jsonb-q1.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
.mode qbox
.timer on
.param set $label 'q87'
SELECT rowid, x->>$label FROM data1 WHERE x->>$label IS NOT NULL;

CREATE TEMP TABLE t2(x JSON TEXT);
WITH RECURSIVE
  c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<25000),
  array1(y) AS (
    SELECT json_group_array(
             json_object('x',x,'y',random(),'z',hex(randomblob(50)))
           )
      FROM c
  ),
  c2(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c2 WHERE n<5)
INSERT INTO t2(x)
  SELECT jsonb_object('a',n,'b',n*2,'c',y,'d',3,'e',5,'f',6) FROM array1, c2;
CREATE INDEX t2x1 ON t2(x->>'a');
CREATE INDEX t2x2 ON t2(x->>'b');
CREATE INDEX t2x3 ON t2(x->>'e');
CREATE INDEX t2x4 ON t2(x->>'f');
UPDATE t2 SET x=jsonb_replace(x,'$.f',(x->>'f')+1);
UPDATE t2 SET x=jsonb_set(x,'$.e',(x->>'f')-1);
UPDATE t2 SET x=jsonb_remove(x,'$.d');
Changes to test/json101.test.
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
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







+
+
+











+
+
+
+
+
+
+
+
+
+
+




+
+
+



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






+
+
+




+
+
+



+
+
+



+
+
+



+
+
+

-
-
-
+
+
+
+
+
+







} {[1,{"abc":2.5,"def":null,"ghi":"hello"},99]}
do_execsql_test json101-1.2 {
  SELECT hex(json_array('String "\ Test'));
} {5B22537472696E67205C225C5C2054657374225D}
do_catchsql_test json101-1.3 {
  SELECT json_array(1,printf('%.1000c','x'),x'abcd',3);
} {1 {JSON cannot hold BLOB values}}
do_catchsql_test json101-1.3b {
  SELECT jsonb_array(1,printf('%.1000c','x'),x'abcd',3);
} {1 {JSON cannot hold BLOB values}}
do_execsql_test json101-1.4 {
  SELECT json_array(-9223372036854775808,9223372036854775807,0,1,-1,
                    0.0, 1.0, -1.0, -1e99, +2e100,
                    'one','two','three',
                    4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
                    19, NULL, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                    'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    99);
} {[-9223372036854775808,9223372036854775807,0,1,-1,0.0,1.0,-1.0,-1.0e+99,2.0e+100,"one","two","three",4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,null,21,22,23,24,25,26,27,28,29,30,31,"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ",99]}
do_execsql_test json101-1.4b {
  SELECT json(jsonb_array(-9223372036854775808,9223372036854775807,0,1,-1,
                    0.0, 1.0, -1.0, -1e99, +2e100,
                    'one','two','three',
                    4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
                    19, NULL, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                    'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
                    99));
} {[-9223372036854775808,9223372036854775807,0,1,-1,0.0,1.0,-1.0,-1.0e+99,2.0e+100,"one","two","three",4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,null,21,22,23,24,25,26,27,28,29,30,31,"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ",99]}

do_execsql_test json101-2.1 {
  SELECT json_object('a',1,'b',2.5,'c',null,'d','String Test');
} {{{"a":1,"b":2.5,"c":null,"d":"String Test"}}}
do_execsql_test json101-2.1b {
  SELECT json(jsonb_object('a',1,'b',2.5,'c',null,'d','String Test'));
} {{{"a":1,"b":2.5,"c":null,"d":"String Test"}}}
do_catchsql_test json101-2.2 {
  SELECT json_object('a',printf('%.1000c','x'),2,2.5);
} {1 {json_object() labels must be TEXT}}
do_catchsql_test json101-2.2b {
  SELECT jsonb_object('a',printf('%.1000c','x'),2,2.5);
} {1 {json_object() labels must be TEXT}}
do_execsql_test json101-2.2.2 {
  SELECT json_object('a',json_array('xyx',77,4.5),'x',2.5);
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_execsql_test json101-2.2.2b {
  SELECT json(jsonb_object('a',json_array('xyx',77,4.5),'x',2.5));
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_execsql_test json101-2.2.3 {
  SELECT json_object('a',jsonb_array('xyx',77,4.5),'x',2.5);
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_execsql_test json101-2.2.3b {
  SELECT json(jsonb_object('a',jsonb_array('xyx',77,4.5),'x',2.5));
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_catchsql_test json101-2.3 {
  SELECT json_object('a',1,'b');
} {1 {json_object() requires an even number of arguments}}
do_catchsql_test json101-2.4 {
  SELECT json_object('a',printf('%.1000c','x'),'b',x'abcd');
} {1 {JSON cannot hold BLOB values}}
do_execsql_test json101-2.5 {
  SELECT json_object('a',printf('%.10c','x'),'b',jsonb_array(1,2,3));
} {{{"a":"xxxxxxxxxx","b":[1,2,3]}}}

do_execsql_test json101-3.1 {
  SELECT json_replace('{"a":1,"b":2}','$.a','[3,4,5]');
} {{{"a":"[3,4,5]","b":2}}}
do_execsql_test json101-3.1b {
  SELECT json(jsonb_replace('{"a":1,"b":2}','$.a','[3,4,5]'));
} {{{"a":"[3,4,5]","b":2}}}
do_execsql_test json101-3.2 {
  SELECT json_replace('{"a":1,"b":2}','$.a',json('[3,4,5]'));
} {{{"a":[3,4,5],"b":2}}}
do_execsql_test json101-3.2b {
  SELECT json_replace('{"a":1,"b":2}','$.a',jsonb('[3,4,5]'));
} {{{"a":[3,4,5],"b":2}}}
do_execsql_test json101-3.3 {
  SELECT json_type(json_set('{"a":1,"b":2}','$.b','{"x":3,"y":4}'),'$.b');
} {text}
do_execsql_test json101-3.3b {
  SELECT json_type(jsonb_set('{"a":1,"b":2}','$.b','{"x":3,"y":4}'),'$.b');
} {text}
do_execsql_test json101-3.4 {
  SELECT json_type(json_set('{"a":1,"b":2}','$.b',json('{"x":3,"y":4}')),'$.b');
} {object}
do_execsql_test json101-3.4b {
  SELECT json_type(jsonb_set('{"a":1,"b":2}','$.b',jsonb('{"x":3,"y":4}')),'$.b');
} {object}
ifcapable vtab {
do_execsql_test json101-3.5 {
  SELECT fullkey, atom, '|' FROM json_tree(json_set('{}','$.x',123,'$.x',456));
} {{$} {} | {$.x} 456 |}
  do_execsql_test json101-3.5 {
    SELECT fullkey, atom, '|' FROM json_tree(json_set('{}','$.x',123,'$.x',456));
  } {{$} {} | {$.x} 456 |}
  do_execsql_test json101-3.5b {
    SELECT fullkey, atom, '|' FROM json_tree(jsonb_set('{}','$.x',123,'$.x',456));
  } {{$} {} | {$.x} 456 |}
}

# Per rfc7159, any JSON value is allowed at the top level, and whitespace
# is permitting before and/or after that value.
#
do_execsql_test json101-4.1 {
  CREATE TABLE j1(x);
127
128
129
130
131
132
133







134
135
136
137
138
139
140
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197







+
+
+
+
+
+
+







#
do_execsql_test json101-4.10 {
  SELECT count(*) FROM j1 WHERE json_type(x) IN ('object','array');
  SELECT x FROM j1
   WHERE json_extract(x,'$')<>x
     AND json_type(x) IN ('object','array');
} {4}
do_execsql_test json101-4.10b {
  CREATE TABLE j1b AS SELECT jsonb(x) AS "x" FROM j1;
  SELECT count(*) FROM j1b WHERE json_type(x) IN ('object','array');
  SELECT json(x) FROM j1b
   WHERE json_extract(x,'$')<>json(x)
     AND json_type(x) IN ('object','array');
} {4}

do_execsql_test json101-5.1 {
  CREATE TABLE j2(id INTEGER PRIMARY KEY, json, src);
  INSERT INTO j2(id,json,src)
  VALUES(1,'{
    "firstName": "John",
    "lastName": "Smith",
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
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







+
+
+
-
+




+
+
+











+
+
+
+
+
+







				{ "id": "5002", "type": "Glazed" },
				{ "id": "5003", "type": "Chocolate" },
				{ "id": "5004", "type": "Maple" }
			]
	}
   ]','https://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html');
   SELECT count(*) FROM j2;
   CREATE TABLE j2b(id INTEGER PRIMARY KEY, json, src);
   INSERT INTO J2b(id,json,src) SELECT id, jsonb(json), src FROM j2;
   SELECT count(*) FROM j2b;
} {3}
} {3 3}

do_execsql_test json101-5.2 {
  SELECT id, json_valid(json), json_type(json), '|' FROM j2 ORDER BY id;
} {1 1 object | 2 1 object | 3 1 array |}
do_execsql_test json101-5.2b {
  SELECT id, json_valid(json,5), json_type(json), '|' FROM j2b ORDER BY id;
} {1 1 object | 2 1 object | 3 1 array |}

ifcapable !vtab {
  finish_test
  return
}

# fullkey is always the same as path+key (with appropriate formatting)
#
do_execsql_test json101-5.3 {
  SELECT j2.rowid, jx.rowid, fullkey, path, key
    FROM j2, json_tree(j2.json) AS jx
   WHERE fullkey!=(path || CASE WHEN typeof(key)=='integer' THEN '['||key||']'
                                ELSE '.'||key END);
} {}
do_execsql_test json101-5.3b {
  SELECT j2b.rowid, jx.rowid, fullkey, path, key
    FROM j2b, json_tree(j2b.json) AS jx
   WHERE fullkey!=(path || CASE WHEN typeof(key)=='integer' THEN '['||key||']'
                                ELSE '.'||key END);
} {}
do_execsql_test json101-5.4 {
  SELECT j2.rowid, jx.rowid, fullkey, path, key
    FROM j2, json_each(j2.json) AS jx
   WHERE fullkey!=(path || CASE WHEN typeof(key)=='integer' THEN '['||key||']'
304
305
306
307
308
309
310














311
312
313
314
315
316
317
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400







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







   WHERE jx.value<>jx.atom AND type NOT IN ('array','object');
} {}
do_execsql_test json101-5.8 {
  SELECT j2.rowid, jx.rowid, fullkey, path, key
    FROM j2, json_tree(j2.json) AS jx
   WHERE jx.value<>jx.atom AND type NOT IN ('array','object');
} {}

# 2024-02-16 https://sqlite.org/forum/forumpost/ecb94cd210
# Regression in json_tree()/json_each().  The value column
# should have the "J" subtype if the value is an array or
# object.
#
do_execsql_test json101-5.10 {
  SELECT json_insert('{}','$.a',value) FROM json_tree('[1,2,3]') WHERE atom IS NULL;
} {{{"a":[1,2,3]}}}
#        ^^^^^^^--- In double-quotes, a string literal, prior to bug fix

do_execsql_test json101-5.11 {
  SELECT json_insert('{}','$.a',value) FROM json_tree('"[1,2,3]"');
} {{{"a":"[1,2,3]"}}}

do_execsql_test json101-6.1 {
  SELECT json_valid('{"a":55,"b":72,}');
} {0}
do_execsql_test json101-6.2 {
  SELECT json_error_position('{"a":55,"b":72,}');
} {0}
366
367
368
369
370
371
372







373
374
375
376
377
378
379
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469







+
+
+
+
+
+
+







#
do_execsql_test json101-8.1 {
  DROP TABLE IF EXISTS t8;
  CREATE TABLE t8(a,b);
  INSERT INTO t8(a) VALUES('abc' || char(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) || 'xyz');
  UPDATE t8 SET b=json_array(a);
  SELECT b FROM t8;
} {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}}
do_execsql_test json101-8.1b {
  DROP TABLE IF EXISTS t8;
  CREATE TABLE t8(a,b);
  INSERT INTO t8(a) VALUES('abc' || char(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) || 'xyz');
  UPDATE t8 SET b=jsonb_array(a);
  SELECT json(b) FROM t8;
} {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}}
do_execsql_test json101-8.2 {
  SELECT a=json_extract(b,'$[0]') FROM t8;
} {1}

# 2017-04-12.  Regression reported on the mailing list by Rolf Ade
#
397
398
399
400
401
402
403
404

405
406
407
408
409
410
411
487
488
489
490
491
492
493

494
495
496
497
498
499
500
501







-
+







do_execsql_test json101-9.3 {
  SELECT json_quote(12345);
} {12345}
do_execsql_test json101-9.4 {
  SELECT json_quote(null);
} {"null"}
do_catchsql_test json101-9.5 {
  SELECT json_quote(x'30313233');
  SELECT json_quote(x'3031323334');
} {1 {JSON cannot hold BLOB values}}
do_catchsql_test json101-9.6 {
  SELECT json_quote(123,456)
} {1 {wrong number of arguments to function json_quote()}}
do_catchsql_test json101-9.7 {
  SELECT json_quote()
} {1 {wrong number of arguments to function json_quote()}}
765
766
767
768
769
770
771

772
773




774
775
776
777
778




779
780
781
782
783
784
785
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







+


+
+
+
+





+
+
+
+







               "transliterate":false,
               "add.footnote":false,
               "summary.report":false}
           }
        }
     }');
} {}

do_execsql_test json101-12.110 {
  SELECT json_remove(x, '$.settings.layer2."dis.legomenon".forceDisplay')
    FROM t12;
} {{{"settings":{"layer2":{"hapax.legomenon":{"forceDisplay":true,"transliterate":true,"add.footnote":true,"summary.report":true},"dis.legomenon":{"transliterate":false,"add.footnote":false,"summary.report":true},"tris.legomenon":{"forceDisplay":true,"transliterate":false,"add.footnote":false,"summary.report":false}}}}}}
do_execsql_test json101-12.110b {
  SELECT json_remove(jsonb(x), '$.settings.layer2."dis.legomenon".forceDisplay')
    FROM t12;
} {{{"settings":{"layer2":{"hapax.legomenon":{"forceDisplay":true,"transliterate":true,"add.footnote":true,"summary.report":true},"dis.legomenon":{"transliterate":false,"add.footnote":false,"summary.report":true},"tris.legomenon":{"forceDisplay":true,"transliterate":false,"add.footnote":false,"summary.report":false}}}}}}
do_execsql_test json101-12.120 {
  SELECT json_extract(x, '$.settings.layer2."tris.legomenon"."summary.report"')
    FROM t12;
} {0}
do_execsql_test json101-12.120b {
  SELECT json_extract(jsonb(x), '$.settings.layer2."tris.legomenon"."summary.report"')
    FROM t12;
} {0}

# 2018-01-26
# ticket https://www.sqlite.org/src/tktview/80177f0c226ff54f6ddd41
# Make sure the query planner knows about the arguments to table-valued functions.
#
do_execsql_test json101-13.100 {
836
837
838
839
840
841
842
843

844
845
846

847
848
849

850
851
852

853
854
855
856
857
858
859
935
936
937
938
939
940
941

942
943
944

945
946
947

948
949
950

951
952
953
954
955
956
957
958







-
+


-
+


-
+


-
+







# Make sure the table-valued functions contained within parentheses
# work correctly.
#
# Bug reported via private email. See TH3 for more information.
#
do_execsql_test json101-15.100 {
  SELECT * FROM JSON_EACH('{"a":1, "b":2}');
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
do_execsql_test json101-15.110 {
  SELECT xyz.* FROM JSON_EACH('{"a":1, "b":2}') AS xyz;
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
do_execsql_test json101-15.120 {
  SELECT * FROM (JSON_EACH('{"a":1, "b":2}'));
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
do_execsql_test json101-15.130 {
  SELECT xyz.* FROM (JSON_EACH('{"a":1, "b":2}')) AS xyz;
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}

# 2019-11-10
# Mailing list bug report on the handling of surrogate pairs
# in JSON.
#
do_execsql_test json101-16.10 {
  SELECT length(json_extract('"abc\uD834\uDD1Exyz"','$'));
885
886
887
888
889
890
891
892

893
894
895
896
897
898
899
984
985
986
987
988
989
990

991
992
993
994
995
996
997
998







-
+







  SELECT json_extract('[3,{"a":4,"":[5,{"hi":6},7]},8]', '$[1].""[1].hi');
} {6}
do_execsql_test json101-18.4 {
  SELECT json_extract('[3,{"a":4,"":[5,{"hi":6},7]},8]', '$[1].""[1]."hi"');
} {6}
do_catchsql_test json101-18.5 {
  SELECT json_extract('{"":8}', '$.');
} {1 {JSON path error near ''}}
} {1 {bad JSON path: '$.'}}

# 2022-08-29 https://sqlite.org/forum/forumpost/9b9e4716c0d7bbd1
# This is not a problem specifically with JSON functions.  It is
# a problem with transaction control.  But the json() function makes
# the problem more easily accessible, so it is tested here.
#
do_execsql_test json101-19.1 {
1050
1051
1052
1053
1054
1055
1056


1057
1058























1059
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







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

    FROM (SELECT json_set(json_set('[]','$[#]',0), '$[#]',1) AS j);
} {{[0,1]} 0 1}
do_execsql_test json101-23.2 {
  SELECT j, j->>0, j->>1
    FROM (SELECT json_set('[]','$[#]',0,'$[#]',1) AS j);
} {{[0,1]} 0 1}

# Insert/Set/Replace where the path specifies substructure that
# does not yet exist


#
proc tx x {return [string map [list ( \173 ) \175 ' \042 < \133 > \135] $x]}
foreach {id start path ins set repl} {
  1 {{}}       {$.a.b.c}     ('a':('b':('c':9)))      ('a':('b':('c':9)))      ()
  2 {{a:4}}    {$.a.b.c}     ('a':4)                  ('a':4)                  ('a':4)
  3 {{a:{}}}   {$.a.b.c}     ('a':('b':('c':9)))      ('a':('b':('c':9)))      ('a':())
  4 {[0,1,2]}  {$[3].a[0].b} <0,1,2,('a':<('b':9)>)>  <0,1,2,('a':<('b':9)>)>  <0,1,2>
  5 {[0,1,2]}  {$[1].a[0].b} <0,1,2>                  <0,1,2>                  <0,1,2>
  6 {[0,{},2]} {$[1].a[0].b} <0,('a':<('b':9)>),2>    <0,('a':<('b':9)>),2>    <0,(),2>
  7 {[0,1,2]}  {$[3][0].b}   <0,1,2,<('b':9)>>        <0,1,2,<('b':9)>>        <0,1,2>
  8 {[0,1,2]}  {$[1][0].b}   <0,1,2>                  <0,1,2>                  <0,1,2>
} {
  do_execsql_test json101-24.$id.insert {
    SELECT json_insert($start,$path,9);
  } [list [tx $ins]]
  do_execsql_test json101-24.$id.set {
    SELECT json_set($start,$path,9);
  } [list [tx $set]]
  do_execsql_test json101-24.$id.replace {
    SELECT json_replace($start,$path,9);
  } [list [tx $repl]]
}

finish_test
Changes to test/json102.test.
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
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518

519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542







+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+



+
+
+



+
+
+



+
+
+
+
+
+
+
+
+



+
+
+



+
+
+
+
+
+
+
+
+



+
+
+



+
+
+



+
+
+



+
+
+
+
+
+



-
-
+
+




+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+



+
+
+
+
+
+
+
+
+



+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



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



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



+
+
+



+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
+
+
+



+
+
+



+
+
+



+
+
+



+
+
+



+
+
+



+
+
+



+
+
+



+
+
+



+
+
+



+
+
+









-
+





+




+
+
+
+
+
+








set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test json102-100 {
  SELECT json_object('ex','[52,3.14159]');
} {{{"ex":"[52,3.14159]"}}}
do_execsql_test json102-100b {
  SELECT json(jsonb_object('ex','[52,3.14159]'));
} {{{"ex":"[52,3.14159]"}}}
do_execsql_test json102-110 {
  SELECT json_object('ex',json('[52,3.14159]'));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-110-2 {
  SELECT json(jsonb_object('ex',json('[52,3.14159]')));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-110-3 {
  SELECT json_object('ex',jsonb('[52,3.14159]'));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-110-3 {
  SELECT json(jsonb_object('ex',jsonb('[52,3.14159]')));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120 {
  SELECT json_object('ex',json_array(52,3.14159));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120-2 {
  SELECT json(jsonb_object('ex',json_array(52,3.14159)));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120-3 {
  SELECT json_object('ex',jsonb_array(52,3.14159));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120-4 {
  SELECT json(jsonb_object('ex',jsonb_array(52,3.14159)));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-130 {
  SELECT json(' { "this" : "is", "a": [ "test" ] } ');
} {{{"this":"is","a":["test"]}}}
do_execsql_test json102-130b {
  SELECT json(jsonb(' { "this" : "is", "a": [ "test" ] } '));
} {{{"this":"is","a":["test"]}}}
do_execsql_test json102-140 {
  SELECT json_array(1,2,'3',4);
} {{[1,2,"3",4]}}
do_execsql_test json102-140b {
  SELECT json(jsonb_array(1,2,'3',4));
} {{[1,2,"3",4]}}
do_execsql_test json102-150 {
  SELECT json_array('[1,2]');
} {{["[1,2]"]}}
do_execsql_test json102-150b {
  SELECT json(jsonb_array('[1,2]'));
} {{["[1,2]"]}}
do_execsql_test json102-160 {
  SELECT json_array(json_array(1,2));
} {{[[1,2]]}}
do_execsql_test json102-160-2 {
  SELECT json_array(jsonb_array(1,2));
} {{[[1,2]]}}
do_execsql_test json102-160-3 {
  SELECT json(jsonb_array(json_array(1,2)));
} {{[[1,2]]}}
do_execsql_test json102-160-4 {
  SELECT json(jsonb_array(jsonb_array(1,2)));
} {{[[1,2]]}}
do_execsql_test json102-170 {
  SELECT json_array(1,null,'3','[4,5]','{"six":7.7}');
} {{[1,null,"3","[4,5]","{\"six\":7.7}"]}}
do_execsql_test json102-170b {
  SELECT json(jsonb_array(1,null,'3','[4,5]','{"six":7.7}'));
} {{[1,null,"3","[4,5]","{\"six\":7.7}"]}}
do_execsql_test json102-180 {
  SELECT json_array(1,null,'3',json('[4,5]'),json('{"six":7.7}'));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-180-2 {
  SELECT json_array(1,null,'3',jsonb('[4,5]'),json('{"six":7.7}'));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-180-3 {
  SELECT json(jsonb_array(1,null,'3',json('[4,5]'),json('{"six":7.7}')));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-180-4 {
  SELECT json(jsonb_array(1,null,'3',jsonb('[4,5]'),jsonb('{"six":7.7}')));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-190 {
  SELECT json_array_length('[1,2,3,4]');
} {{4}}
do_execsql_test json102-190b {
  SELECT json_array_length(jsonb('[1,2,3,4]'));
} {{4}}
do_execsql_test json102-191 {
  SELECT json_array_length( json_remove('[1,2,3,4]','$[2]') );
} {{3}}
do_execsql_test json102-191b {
  SELECT json_array_length( jsonb_remove('[1,2,3,4]','$[2]') );
} {{3}}
do_execsql_test json102-200 {
  SELECT json_array_length('[1,2,3,4]', '$');
} {{4}}
do_execsql_test json102-200b {
  SELECT json_array_length(jsonb('[1,2,3,4]'), '$');
} {{4}}
do_execsql_test json102-210 {
  SELECT json_array_length('[1,2,3,4]', '$[2]');
} {{0}}
do_execsql_test json102-210b {
  SELECT json_array_length(jsonb('[1,2,3,4]'), '$[2]');
} {{0}}
do_execsql_test json102-220 {
  SELECT json_array_length('{"one":[1,2,3]}');
} {{0}}
do_execsql_test json102-220 {
  SELECT json_array_length('{"one":[1,2,3]}');
} {{0}}
do_execsql_test json102-230 {
  SELECT json_array_length('{"one":[1,2,3]}', '$.one');
do_execsql_test json102-230b {
  SELECT json_array_length(jsonb('{"one":[1,2,3]}'), '$.one');
} {{3}}
do_execsql_test json102-240 {
  SELECT json_array_length('{"one":[1,2,3]}', '$.two');
} {{}}
do_execsql_test json102-240b {
  SELECT json_array_length(jsonb('{"one":[1,2,3]}'), '$.two');
} {{}}
do_execsql_test json102-250 {
  SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$');
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-250-2 {
  SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$');
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-250-3 {
  SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$'));
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-250-4 {
  SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$'));
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-260 {
  SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c');
} {{[4,5,{"f":7}]}}
do_execsql_test json102-260-2 {
  SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c');
} {{[4,5,{"f":7}]}}
do_execsql_test json102-260-3 {
  SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c'));
} {{[4,5,{"f":7}]}}
do_execsql_test json102-260-4 {
  SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c'));
} {{[4,5,{"f":7}]}}
do_execsql_test json102-270 {
  SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]');
} {{{"f":7}}}
do_execsql_test json102-270-2 {
  SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c[2]');
} {{{"f":7}}}
do_execsql_test json102-270-3 {
  SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c[2]'));
} {{{"f":7}}}
do_execsql_test json102-270-4 {
  SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]'));
} {{{"f":7}}}
do_execsql_test json102-280 {
  SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f');
} {{7}}
do_execsql_test json102-280b {
  SELECT jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f');
} {{7}}
do_execsql_test json102-290 {
  SELECT json_extract('{"a":2,"c":[4,5],"f":7}','$.c','$.a');
} {{[[4,5],2]}}
do_execsql_test json102-290-2 {
  SELECT json_extract(jsonb('{"a":2,"c":[4,5],"f":7}'),'$.c','$.a');
} {{[[4,5],2]}}
do_execsql_test json102-290-3 {
  SELECT json(jsonb_extract('{"a":2,"c":[4,5],"f":7}','$.c','$.a'));
} {{[[4,5],2]}}
do_execsql_test json102-290-4 {
  SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5],"f":7}'),'$.c','$.a'));
} {{[[4,5],2]}}
do_execsql_test json102-300 {
  SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x');
} {{}}
do_execsql_test json102-300b {
  SELECT jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x');
} {{}}
do_execsql_test json102-310 {
  SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x', '$.a');
} {{[null,2]}}
do_execsql_test json102-310-2 {
  SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.x', '$.a');
} {{[null,2]}}
do_execsql_test json102-310-3 {
  SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.x', '$.a'));
} {{[null,2]}}
do_execsql_test json102-310-43 {
  SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x', '$.a'));
} {{[null,2]}}
do_execsql_test json102-320 {
  SELECT json_insert('{"a":2,"c":4}', '$.a', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-320-2 {
  SELECT json_insert(jsonb('{"a":2,"c":4}'), '$.a', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-320-3 {
  SELECT json(jsonb_insert('{"a":2,"c":4}', '$.a', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-320-4 {
  SELECT json(jsonb_insert(jsonb('{"a":2,"c":4}'), '$.a', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-330 {
  SELECT json_insert('{"a":2,"c":4}', '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-330-2 {
  SELECT json_insert(jsonb('{"a":2,"c":4}'), '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-330-3 {
  SELECT json(jsonb_insert('{"a":2,"c":4}', '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-330-4 {
  SELECT json(jsonb_insert(jsonb('{"a":2,"c":4}'), '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-340 {
  SELECT json_replace('{"a":2,"c":4}', '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-340-2 {
  SELECT json_replace(jsonb('{"a":2,"c":4}'), '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-340-3 {
  SELECT json(jsonb_replace('{"a":2,"c":4}', '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-340-4 {
  SELECT json(jsonb_replace(jsonb('{"a":2,"c":4}'), '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-350 {
  SELECT json_replace('{"a":2,"c":4}', '$.e', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-350-2 {
  SELECT json_replace(jsonb('{"a":2,"c":4}'), '$.e', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-350-3 {
  SELECT json(jsonb_replace('{"a":2,"c":4}', '$.e', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-350-4 {
  SELECT json(jsonb_replace(jsonb('{"a":2,"c":4}'), '$.e', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-360 {
  SELECT json_set('{"a":2,"c":4}', '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-360-2 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-360-3 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-360-4 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-370 {
  SELECT json_set('{"a":2,"c":4}', '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-370-2 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-370-3 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-370-4 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-380 {
  SELECT json_set('{"a":2,"c":4}', '$.c', '[97,96]');
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-380-2 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', '[97,96]');
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-380-3 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', '[97,96]'));
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-380-4 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', '[97,96]'));
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-390 {
  SELECT json_set('{"a":2,"c":4}', '$.c', json('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-2 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', json('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-3 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', json('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-4 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', json('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-5 {
  SELECT json_set('{"a":2,"c":4}', '$.c', jsonb('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-6 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-7 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', jsonb('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-8 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400 {
  SELECT json_set('{"a":2,"c":4}', '$.c', json_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-2 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', json_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-3 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', json_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-4 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', json_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-5 {
  SELECT json_set('{"a":2,"c":4}', '$.c', jsonb_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-6 {
  SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-7 {
  SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', jsonb_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-8 {
  SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-410 {
  SELECT json_object('a',2,'c',4);
} {{{"a":2,"c":4}}}
do_execsql_test json102-410b {
  SELECT json(jsonb_object('a',2,'c',4));
} {{{"a":2,"c":4}}}
do_execsql_test json102-420 {
  SELECT json_object('a',2,'c','{e:5}');
} {{{"a":2,"c":"{e:5}"}}}
do_execsql_test json102-420b {
  SELECT json(jsonb_object('a',2,'c','{e:5}'));
} {{{"a":2,"c":"{e:5}"}}}
do_execsql_test json102-430 {
  SELECT json_object('a',2,'c',json_object('e',5));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-430-2 {
  SELECT json(jsonb_object('a',2,'c',json_object('e',5)));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-430-3 {
  SELECT json_object('a',2,'c',jsonb_object('e',5));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-430-4 {
  SELECT json(jsonb_object('a',2,'c',jsonb_object('e',5)));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-440 {
  SELECT json_remove('[0,1,2,3,4]','$[2]');
} {{[0,1,3,4]}}
do_execsql_test json102-440-2 {
  SELECT json_remove(jsonb('[0,1,2,3,4]'),'$[2]');
} {{[0,1,3,4]}}
do_execsql_test json102-440-3 {
  SELECT json(jsonb_remove('[0,1,2,3,4]','$[2]'));
} {{[0,1,3,4]}}
do_execsql_test json102-440-4 {
  SELECT json(jsonb_remove(jsonb('[0,1,2,3,4]'),'$[2]'));
} {{[0,1,3,4]}}
do_execsql_test json102-450 {
  SELECT json_remove('[0,1,2,3,4]','$[2]','$[0]');
} {{[1,3,4]}}
do_execsql_test json102-450-2 {
  SELECT json_remove(jsonb('[0,1,2,3,4]'),'$[2]','$[0]');
} {{[1,3,4]}}
do_execsql_test json102-450-3 {
  SELECT json(jsonb_remove('[0,1,2,3,4]','$[2]','$[0]'));
} {{[1,3,4]}}
do_execsql_test json102-450-4 {
  SELECT json(jsonb_remove(jsonb('[0,1,2,3,4]'),'$[2]','$[0]'));
} {{[1,3,4]}}
do_execsql_test json102-460 {
  SELECT json_remove('[0,1,2,3,4]','$[0]','$[2]');
} {{[1,2,4]}}
do_execsql_test json102-460-2 {
  SELECT json_remove(jsonb('[0,1,2,3,4]'),'$[0]','$[2]');
} {{[1,2,4]}}
do_execsql_test json102-460-3 {
  SELECT json(jsonb_remove('[0,1,2,3,4]','$[0]','$[2]'));
} {{[1,2,4]}}
do_execsql_test json102-460-4 {
  SELECT json(jsonb_remove(jsonb('[0,1,2,3,4]'),'$[0]','$[2]'));
} {{[1,2,4]}}
do_execsql_test json102-470 {
  SELECT json_remove('{"x":25,"y":42}');
} {{{"x":25,"y":42}}}
do_execsql_test json102-470-2 {
  SELECT json_remove(jsonb('{"x":25,"y":42}'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-470-3 {
  SELECT json(jsonb_remove('{"x":25,"y":42}'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-470-4 {
  SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}')));
} {{{"x":25,"y":42}}}
do_execsql_test json102-480 {
  SELECT json_remove('{"x":25,"y":42}','$.z');
} {{{"x":25,"y":42}}}
do_execsql_test json102-480-2 {
  SELECT json_remove(jsonb('{"x":25,"y":42}'),'$.z');
} {{{"x":25,"y":42}}}
do_execsql_test json102-480-3 {
  SELECT json(jsonb_remove('{"x":25,"y":42}','$.z'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-480-4 {
  SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}'),'$.z'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-490 {
  SELECT json_remove('{"x":25,"y":42}','$.y');
} {{{"x":25}}}
do_execsql_test json102-490-2 {
  SELECT json_remove(jsonb('{"x":25,"y":42}'),'$.y');
} {{{"x":25}}}
do_execsql_test json102-490-3 {
  SELECT json(jsonb_remove('{"x":25,"y":42}','$.y'));
} {{{"x":25}}}
do_execsql_test json102-490-4 {
  SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}'),'$.y'));
} {{{"x":25}}}
do_execsql_test json102-500 {
  SELECT json_remove('{"x":25,"y":42}','$');
} {{}}
do_execsql_test json102-500-2 {
  SELECT json_remove(jsonb('{"x":25,"y":42}'),'$');
} {{}}
do_execsql_test json102-500-3 {
  SELECT json(jsonb_remove('{"x":25,"y":42}','$'));
} {{}}
do_execsql_test json102-500-4 {
  SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}'),'$'));
} {{}}
do_execsql_test json102-510 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}');
} {{object}}
do_execsql_test json102-510b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778');
} {{object}}
do_execsql_test json102-520 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$');
} {{object}}
do_execsql_test json102-520b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$');
} {{object}}
do_execsql_test json102-530 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a');
} {{array}}
do_execsql_test json102-530b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a');
} {{array}}
do_execsql_test json102-540 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[0]');
} {{integer}}
do_execsql_test json102-540b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[0]');
} {{integer}}
do_execsql_test json102-550 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[1]');
} {{real}}
do_execsql_test json102-550b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[1]');
} {{real}}
do_execsql_test json102-560 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[2]');
} {{true}}
do_execsql_test json102-560b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[2]');
} {{true}}
do_execsql_test json102-570 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[3]');
} {{false}}
do_execsql_test json102-570b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[3]');
} {{false}}
do_execsql_test json102-580 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[4]');
} {{null}}
do_execsql_test json102-580b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[4]');
} {{null}}
do_execsql_test json102-590 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[5]');
} {{text}}
do_execsql_test json102-590b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[5]');
} {{text}}
do_execsql_test json102-600 {
  SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[6]');
} {{}}
do_execsql_test json102-600b {
  SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[6]');
} {{}}
do_execsql_test json102-610 {
  SELECT json_valid(char(123)||'"x":35'||char(125));
} {{1}}
do_execsql_test json102-620 {
  SELECT json_valid(char(123)||'"x":35');
} {{0}}

ifcapable vtab {
do_execsql_test json102-1000 {
  CREATE TABLE user(name,phone);
  CREATE TABLE user(name,phone,phoneb);
  INSERT INTO user(name,phone) VALUES
     ('Alice','["919-555-2345","804-555-3621"]'),
     ('Bob','["201-555-8872"]'),
     ('Cindy','["704-555-9983"]'),
     ('Dave','["336-555-8421","704-555-4321","803-911-4421"]');
  UPDATE user SET phoneb=jsonb(phone);
  SELECT DISTINCT user.name
    FROM user, json_each(user.phone)
   WHERE json_each.value LIKE '704-%'
   ORDER BY 1;
} {Cindy Dave}
do_execsql_test json102-1000b {
  SELECT DISTINCT user.name
    FROM user, json_each(user.phoneb)
   WHERE json_each.value LIKE '704-%'
   ORDER BY 1;
} {Cindy Dave}

do_execsql_test json102-1010 {
  UPDATE user
     SET phone=json_extract(phone,'$[0]')
   WHERE json_array_length(phone)<2;
  SELECT name, substr(phone,1,5) FROM user ORDER BY name;
249
250
251
252
253
254
255






256
257
258
259
260
261
262
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608







+
+
+
+
+
+







    2 {$.partlist[1].uuid} c690dc14-572e-11e5-95f9-dfc8861fd535]
do_execsql_test json102-1110 {
  SELECT big.rowid, fullkey, value
    FROM big, json_tree(big.json)
   WHERE json_tree.type NOT IN ('object','array')
   ORDER BY +big.rowid, +json_tree.id
} $correct_answer
do_execsql_test json102-1110b {
  SELECT big.rowid, fullkey, value
    FROM big, json_tree(jsonb(big.json))
   WHERE json_tree.type NOT IN ('object','array')
   ORDER BY +big.rowid, +json_tree.id
} $correct_answer
do_execsql_test json102-1120 {
  SELECT big.rowid, fullkey, atom
    FROM big, json_tree(big.json)
   WHERE atom IS NOT NULL
   ORDER BY +big.rowid, +json_tree.id
} $correct_answer

Changes to test/json105.test.
9
10
11
12
13
14
15
16

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

16
17
18
19
20
21
22
23







-
+







#
#***********************************************************************
# This file implements tests for "[#]" extension to json-path
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix json104
set testprefix json105

# This is the example from pages 2 and 3 of RFC-7396
db eval {
  CREATE TABLE t1(j);
  INSERT INTO t1(j) VALUES('{"a":1,"b":[1,[2,3],4],"c":99}');
}
proc json_extract_test {testnum path result} {
92
93
94
95
96
97
98
99

100
101
102

103
104
105

106
107
108

109
110
111

112
113
92
93
94
95
96
97
98

99
100
101

102
103
104

105
106
107

108
109
110

111
112
113







-
+


-
+


-
+


-
+


-
+


json_replace_test 70 {'$.b[1][#-1]','AAA','$.b[#-1]','BBB'} \
     {'{"a":1,"b":[1,[2,"AAA"],"BBB"],"c":99}'}
json_replace_test 80 {'$.b[#-1]','AAA','$.b[#-1]','BBB'} \
     {'{"a":1,"b":[1,[2,3],"BBB"],"c":99}'}

do_catchsql_test json105-6.10 {
  SELECT json_extract(j, '$.b[#-]') FROM t1;
} {1 {JSON path error near '[#-]'}}
} {1 {bad JSON path: '$.b[#-]'}}
do_catchsql_test json105-6.20 {
  SELECT json_extract(j, '$.b[#9]') FROM t1;
} {1 {JSON path error near '[#9]'}}
} {1 {bad JSON path: '$.b[#9]'}}
do_catchsql_test json105-6.30 {
  SELECT json_extract(j, '$.b[#+2]') FROM t1;
} {1 {JSON path error near '[#+2]'}}
} {1 {bad JSON path: '$.b[#+2]'}}
do_catchsql_test json105-6.40 {
  SELECT json_extract(j, '$.b[#-1') FROM t1;
} {1 {JSON path error near '[#-1'}}
} {1 {bad JSON path: '$.b[#-1'}}
do_catchsql_test json105-6.50 {
  SELECT json_extract(j, '$.b[#-1x]') FROM t1;
} {1 {JSON path error near '[#-1x]'}}
} {1 {bad JSON path: '$.b[#-1x]'}}

finish_test
Added test/json106.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023-12-18
#
# 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.
#
#***********************************************************************
# Invariant tests for JSON built around the randomjson extension
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix json106

# These tests require virtual table "json_tree" to run.
ifcapable !vtab { finish_test ; return }

load_static_extension db randomjson
db eval {
  CREATE TEMP TABLE t1(j0,j5,p);
  CREATE TEMP TABLE kv(n,key,val);
}
unset -nocomplain ii
for {set ii 1} {$ii<=5000} {incr ii} {
  do_execsql_test $ii.1 {
    DELETE FROM t1;
    INSERT INTO t1(j0,j5) VALUES(random_json($ii),random_json5($ii));
    SELECT json_valid(j0), json_valid(j5,2) FROM t1;
  } {1 1}
  do_execsql_test $ii.2 {
    SELECT count(*)
      FROM t1, json_tree(j0) AS rt
     WHERE rt.type NOT IN ('object','array')
       AND rt.atom IS NOT (j0 ->> rt.fullkey);
  } 0
  do_execsql_test $ii.3 {
    SELECT count(*)
      FROM t1, json_tree(j5) AS rt
     WHERE rt.type NOT IN ('object','array')
       AND rt.atom IS NOT (j0 ->> rt.fullkey);
  } 0
  do_execsql_test $ii.4 {
    DELETE FROM kv;
    INSERT INTO kv
      SELECT rt.rowid, rt.fullkey, rt.atom
        FROM t1, json_tree(j0) AS rt
       WHERE rt.type NOT IN ('object','array');
  }
  do_execsql_test $ii.5 {
    SELECT count(*)
      FROM t1, kv
     WHERE key NOT LIKE '%]'
       AND json_remove(j5,key)->>key IS NOT NULL
  } 0
  do_execsql_test $ii.6 {
    SELECT count(*)
      FROM t1, kv
     WHERE key NOT LIKE '%]'
       AND json_insert(json_remove(j5,key),key,val)->>key IS NOT val
  } 0
  do_execsql_test $ii.7 {
    UPDATE t1 SET p=json_patch(j0,j5);
    SELECT count(*)
      FROM t1, kv
     WHERE p->>key IS NOT val
  } 0
  do_execsql_test $ii.8 {
    SELECT j0 FROM t1 WHERE json(j0)!=json(json_pretty(j0));
  } {}
  do_execsql_test $ii.9 {
    SELECT j5 FROM t1 WHERE json(j5)!=json(json_pretty(j5));
  } {}
}


finish_test
Added test/json107.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024-01-23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# 
# Legacy JSON bug:  If the input is a BLOB that when cast into TEXT looks
# like valid JSON, then treat it as valid JSON.
#
# The original intent of the JSON functions was to raise an error on any
# BLOB input.  That intent was clearly documented, but the code failed to
# to implement it.  Subsequently, many applications began to depend on the
# incorrect behavior, especially apps that used readfile() to read JSON
# content, since readfile() returns a BLOB.  So we need to support the
# bug moving forward.
#
# The tests in this fail verify that the original buggy behavior is
# preserved.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix json107

if {[db one {PRAGMA encoding}]!="UTF-8"} {
  # These tests only work for a UTF-8 encoding.
  finish_test
  return
}

do_execsql_test 1.1 {
  SELECT json_valid( CAST('{"a":1}' AS BLOB) );
} 1
do_execsql_test 1.1.1 {
  SELECT json_valid( CAST('{"a":1}' AS BLOB), 1);
} 1
do_execsql_test 1.1.2 {
  SELECT json_valid( CAST('{"a":1}' AS BLOB), 2);
} 1
do_execsql_test 1.1.4 {
  SELECT json_valid( CAST('{"a":1}' AS BLOB), 4);
} 0
do_execsql_test 1.1.8 {
  SELECT json_valid( CAST('{"a":1}' AS BLOB), 8);
} 0

do_execsql_test 1.2.1 {
  SELECT CAST('{"a":123}' AS blob) -> 'a';
} 123
do_execsql_test 1.2.2 {
  SELECT CAST('{"a":123}' AS blob) ->> 'a';
} 123
do_execsql_test 1.2.3 {
  SELECT json_extract(CAST('{"a":123}' AS blob), '$.a');
} 123
do_execsql_test 1.3 {
  SELECT json_insert(CAST('{"a":123}' AS blob),'$.b',456);
} {{{"a":123,"b":456}}}
do_execsql_test 1.4 {
  SELECT json_remove(CAST('{"a":123,"b":456}' AS blob),'$.a');
} {{{"b":456}}}
do_execsql_test 1.5 {
  SELECT json_set(CAST('{"a":123,"b":456}' AS blob),'$.a',789);
} {{{"a":789,"b":456}}}
do_execsql_test 1.6 {
  SELECT json_replace(CAST('{"a":123,"b":456}' AS blob),'$.a',789);
} {{{"a":789,"b":456}}}
do_execsql_test 1.7 {
  SELECT json_type(CAST('{"a":123,"b":456}' AS blob));
} object
do_execsql_test 1.8 {
  SELECT json(CAST('{"a":123,"b":456}' AS blob));
} {{{"a":123,"b":456}}}

ifcapable vtab {
  do_execsql_test 2.1 {
    SELECT key, value FROM json_tree( CAST('{"a":123,"b":456}' AS blob) )
      WHERE atom;
  } {a 123 b 456}
} 
finish_test
Added test/json108.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024-03-06
#
# 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.
#
#***********************************************************************
# Invariant tests for JSON built around the randomjson extension
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix json108

# These tests require virtual table "json_tree" to run.
ifcapable !vtab { finish_test ; return }

load_static_extension db randomjson
db eval {
  CREATE TEMP TABLE t1(j0,j5);
  WITH RECURSIVE c(n) AS (VALUES(0) UNION ALL SELECT n+1 FROM c WHERE n<9)
  INSERT INTO t1 SELECT random_json(n), random_json5(n) FROM c;
}

do_execsql_test 1.1 {
  SELECT count(*) FROM t1 WHERE json(j0)==json(json_pretty(j0,NULL));
} 10
do_execsql_test 1.2 {
  SELECT count(*) FROM t1 WHERE json(j0)==json(json_pretty(j0,NULL));
} 10
do_execsql_test 1.3 {
  SELECT count(*) FROM t1 WHERE json(j0)==json(json_pretty(j0,''));
} 10
do_execsql_test 1.4 {
  SELECT count(*) FROM t1 WHERE json(j0)==json(json_pretty(j0,char(9)));
} 10
do_execsql_test 1.5 {
  SELECT count(*) FROM t1 WHERE json(j0)==json(json_pretty(j0,'/*hello*/'));
} 10


finish_test
Changes to test/json501.test.
248
249
250
251
252
253
254
255

256
257
258

259
260
261

262
263
264
265
266
267
268
248
249
250
251
252
253
254

255
256
257

258
259
260

261
262
263
264
265
266
267
268







-
+


-
+


-
+









###############################################################################
#    9) Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.

do_execsql_test 9.1 {
  WITH c(x) AS (VALUES('{x: +Infinity}')) SELECT x->>'x', json(x) FROM c;
} {Inf {{"x":9.0e999}}}
} {Inf {{"x":9e999}}}
do_execsql_test 9.2 {
  WITH c(x) AS (VALUES('{x: -Infinity}')) SELECT x->>'x', json(x) FROM c;
} {-Inf {{"x":-9.0e999}}}
} {-Inf {{"x":-9e999}}}
do_execsql_test 9.3 {
  WITH c(x) AS (VALUES('{x: Infinity}')) SELECT x->>'x', json(x) FROM c;
} {Inf {{"x":9.0e999}}}
} {Inf {{"x":9e999}}}
do_execsql_test 9.4 {
  WITH c(x) AS (VALUES('{x: NaN}')) SELECT x->>'x', json(x) FROM c;
} {{} {{"x":null}}}

###############################################################################
#   10) Numbers may begin with an explicit plus sign.

301
302
303
304
305
306
307
308



























309
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








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

} xyz

# 2023-11-08 forum/forumpost/ddcad3e884
#
do_execsql_test 13.1 {
  SELECT json('{x:''a "b" c''}');
} {{{"x":"a \"b\" c"}}}

# 2024-01-31
# Allow control characters within JSON5 string literals.
#
for {set c 1} {$c<=0x1f} {incr c} {
  do_execsql_test 14.$c.1 {
    SELECT json_valid('"abc' || char($c) || 'xyz"');
  } {0}
  do_execsql_test 14.$c.2 {
    SELECT json_valid('"abc' || char($c) || 'xyz"', 2);
  } {1}
  switch $c {
    8   {set e "\\b"}
    9   {set e "\\t"}
    10  {set e "\\n"}
    12  {set e "\\f"}
    13  {set e "\\r"}
    default {set e [format "\\u00%02x" $c]}
  }
  do_execsql_test 14.$c.3 {
    SELECT json('{label:"abc' || char($c) || 'xyz"}');
  } "{{\"label\":\"abc${e}xyz\"}}"
  do_execsql_test 14.$c.4 {
    SELECT jsonb('{label:"abc' || char($c) || 'xyz"}') -> '$';
  } "{{\"label\":\"abc${e}xyz\"}}"
}


finish_test
Changes to test/json502.test.
32
33
34
35
36
37
38



























39
40
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







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


do_catchsql_test 2.2 {
  SELECT json('{a:null,{"h":[1,[1,2,3]],"j":"abc"}:true}');
} {1 {malformed JSON}}
do_catchsql_test 2.3 {
  SELECT '{a:null,{"h":[1,[1,2,3]],"j":"abc"}:true}'->'$h[#-1]';
} {1 {malformed JSON}}

# Verify that escaped label names are compared correctly.
# 
do_execsql_test 3.1 {
  SELECT '{"a\x62c":123}' ->> 'abc';
} 123
do_execsql_test 3.2 {
  SELECT '{"abc":123}' ->> 'a\x62c';
} 123

db null null
do_execsql_test 3.3 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(x);
  INSERT INTO t1 VALUES(json_insert('{}','$.a\',111,'$."b\\"',222));
  INSERT INTO t1 VALUES(jsonb_insert('{}','$.a\',111,'$."b\\"',222));
  SELECT x->'$.a\', x->'$.a\\', x->'$."a\\"', x->'$."b\\"' FROM t1;
} {111 null 111 222 111 null 111 222}

do_execsql_test 3.4 {
  SELECT json_patch('{"a\x62c":123}','{"ab\x63":456}') ->> 'abc';
} 456

ifcapable vtab {
  do_execsql_test 4.1 {
    SELECT * FROM json_tree('{"\u0017":1}','$."\x17"');
  } {{\x17} 1 integer 1 1 null {$."\x17"} {$}}
}

finish_test
Added test/jsonb01.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2023-11-15
#
# 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 JSONB
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test jsonb01-1.1 {
  CREATE TABLE t1(x JSON BLOB);
  INSERT INTO t1 VALUES(jsonb('{a:5,b:{x:10,y:11},c:[1,2,3,4]}'));
}
foreach {id path res} {
  1 {$.a}    {{{"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
  2 {$.b}    {{{"a":5,"c":[1,2,3,4]}}}
  3 {$.c}    {{{"a":5,"b":{"x":10,"y":11}}}}
  4 {$.d}    {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
  5 {$.b.x}  {{{"a":5,"b":{"y":11},"c":[1,2,3,4]}}}
  6 {$.b.y}  {{{"a":5,"b":{"x":10},"c":[1,2,3,4]}}}
  7 {$.c[0]}  {{{"a":5,"b":{"x":10,"y":11},"c":[2,3,4]}}}
  8 {$.c[1]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,3,4]}}}
  9 {$.c[2]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,4]}}}
 10 {$.c[3]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3]}}}
 11 {$.c[4]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
 12 {$.c[#]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
 13 {$.c[#-1]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3]}}}
 14 {$.c[#-2]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,4]}}}
 15 {$.c[#-3]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,3,4]}}}
 16 {$.c[#-4]}  {{{"a":5,"b":{"x":10,"y":11},"c":[2,3,4]}}}
 17 {$.c[#-5]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
 18 {$.c[#-6]}  {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
} {
  do_execsql_test jsonb01-1.2.$id.1 {
    SELECT json(jsonb_remove(x,$path)) FROM t1;
  } $res
  do_execsql_test jsonb01-1.2.$id.2 {
    SELECT json_remove(x,$path) FROM t1;
  } $res
}

do_catchsql_test jsonb01-2.0 {
  SELECT x'8ce6ffffffff171333' -> '$';
} {1 {malformed JSON}}

finish_test
Added test/literal.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024-01-19
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements tests for SQL literals


set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix literal

proc test_literal {tn lit type val} {
  do_execsql_test $tn.1 "SELECT typeof( $lit ), $lit" [list $type $val]

  ifcapable altertable {
    do_execsql_test $tn.2 "
      DROP TABLE IF EXISTS x1;
      CREATE TABLE x1(a);
      INSERT INTO x1 VALUES(123);
      ALTER TABLE x1 ADD COLUMN b DEFAULT $lit ;
      SELECT typeof(b), b FROM x1;
    " [list $type $val]
  }

  do_execsql_test $tn.3 "
    DROP TABLE IF EXISTS x1;
    CREATE TABLE x1(a DEFAULT $lit);
    INSERT INTO x1 DEFAULT VALUES;
    SELECT typeof(a), a FROM x1;
  " [list $type $val]
}

proc test_literal_error {tn lit unrec} {
  do_catchsql_test $tn "SELECT $lit" "1 {unrecognized token: \"$unrec\"}"
}


test_literal 1.0 45                  integer 45
test_literal 1.1 0xFF                integer 255
test_literal 1.2 0xFFFFFFFF          integer [expr 0xFFFFFFFF]
test_literal 1.3 0x123FFFFFFFF       integer [expr 0x123FFFFFFFF]
test_literal 1.4 -0x123FFFFFFFF      integer [expr -1 * 0x123FFFFFFFF]
test_literal 1.5 0xFFFFFFFFFFFFFFFF  integer -1
test_literal 1.7 0x7FFFFFFFFFFFFFFF  integer  [expr 0x7FFFFFFFFFFFFFFF]
test_literal 1.8 -0x7FFFFFFFFFFFFFFF integer [expr -0x7FFFFFFFFFFFFFFF]
test_literal 1.9 +0x7FFFFFFFFFFFFFFF integer [expr +0x7FFFFFFFFFFFFFFF]
test_literal 1.10 -45                integer -45
test_literal 1.11 '0xFF'             text 0xFF
test_literal 1.12 '-0xFF'            text -0xFF
test_literal 1.13 -'0xFF'            integer 0
test_literal 1.14 -9223372036854775808 integer -9223372036854775808

test_literal 2.1  1e12    real    1000000000000.0
test_literal 2.2  1.0     real    1.0
test_literal 2.3  1e1000  real    Inf
test_literal 2.4  -1e1000  real   -Inf

test_literal 3.1  1_000   integer 1000
test_literal 3.2  1.1_1   real    1.11
test_literal 3.3  1_0.1_1 real    10.11
test_literal 3.4  1e1_000 real    Inf
test_literal 3.5  12_3_456.7_8_9 real 123456.789
test_literal 3.6  9_223_372_036_854_775_807 integer 9223372036854775807
test_literal 3.7  9_223_372_036_854_775_808 real 9.22337203685478e+18
test_literal 3.8  -9_223_372_036_854_775_808 integer -9223372036854775808

foreach {tn lit unrec} {
  0    123a456       123a456
  1    1_            1_
  2    1_.4          1_.4
  3    1e_4          1e_4
  4    1_e4          1_e4
  5    1.4_e4        1.4_e4
  6    1.4e+_4       1.4e
  7    1.4e-_4       1.4e
  8    1.4e4_        1.4e4_
  9    1.4_e4        1.4_e4
  10   1.4e_4        1.4e_4
  11   12__34        12__34
  12   1234_         1234_
  13   12._34        12._34
  14   12_.34        12_.34
  15   12.34_        12.34_
  16   1.0e1_______2 1.0e1_______2 
} {
  test_literal_error 4.$tn $lit $unrec
}

# dbsqlfuzz e3186a9e7826e9cd7f4085aa4452f8696485f9e1
# See tag-20240224-a and -b
#
do_catchsql_test 5.1 {
  SELECT 1 ORDER BY 2_3;
} {1 {1st ORDER BY term out of range - should be between 1 and 1}}

finish_test
Added test/literal2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2018 May 19
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

source [file join [file dirname $argv0] pg_common.tcl]

#=========================================================================


start_test literal2 "2024 Jan 23"

execsql_test  1.0 { SELECT 123_456 }
errorsql_test 1.1 { SELECT 123__456 }

execsql_float_test 2.1 { SELECT 1.0e1_2 }


execsql_test  3.0.0 { SELECT 0xFF_FF }
execsql_test  3.0.1 { SELECT 0xFF_EF }
errorsql_test  3.0.2 { SELECT 0xFF__EF }
# errorsql_test   3.0.3 { SELECT 0x_FFEF }
errorsql_test  3.0.4 { SELECT 0xFFEF_ }

execsql_test  3.1.0 { SELECT 0XFF_FF }
execsql_test  3.1.1 { SELECT 0XFF_EF }
errorsql_test  3.1.2 { SELECT 0XFF__EF }
# errorsql_test   3.1.3 { SELECT 0X_FFEF }
errorsql_test  3.1.4 { SELECT 0XFFEF_ }

finish_test


Added test/literal2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 Jan 23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#

####################################################
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
####################################################

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix literal2

do_execsql_test 1.0 {
  SELECT 123_456
} {123456}

# PG says ERROR:  trailing junk after numeric literal at or near "123_"
do_test 1.1 { catch { execsql {
  SELECT 123__456
} } } 1


do_test 2.1 {
  set myres {}
  foreach r [db eval {SELECT 1.0e1_2}] {
    lappend myres [format %.4f [set r]]
  }
  set res2 {1000000000000.0000}
  set i 0
  foreach r [set myres] r2 [set res2] {
    if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
      error "list element [set i] does not match: got=[set r] expected=[set r2]"
    }
    incr i
  }
  set {} {}
} {}

do_execsql_test 3.0.0 {
  SELECT 0xFF_FF
} {65535}

do_execsql_test 3.0.1 {
  SELECT 0xFF_EF
} {65519}

# PG says ERROR:  trailing junk after numeric literal at or near "0xFF_"
do_test 3.0.2 { catch { execsql {
  SELECT 0xFF__EF
} } } 1

# PG says ERROR:  trailing junk after numeric literal at or near "0xFFEF_"
do_test 3.0.4 { catch { execsql {
  SELECT 0xFFEF_
} } } 1

do_execsql_test 3.1.0 {
  SELECT 0XFF_FF
} {65535}

do_execsql_test 3.1.1 {
  SELECT 0XFF_EF
} {65519}

# PG says ERROR:  trailing junk after numeric literal at or near "0XFF_"
do_test 3.1.2 { catch { execsql {
  SELECT 0XFF__EF
} } } 1

# PG says ERROR:  trailing junk after numeric literal at or near "0XFFEF_"
do_test 3.1.4 { catch { execsql {
  SELECT 0XFFEF_
} } } 1

finish_test
Changes to test/memdb1.test.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
80
81
82
83
84
85
86

87
88
89
90
91
92
93







-







  db deserialize -readonly 1 $db1
  db eval {SELECT * FROM t1}
} {1 2}
do_test 152 {
  catchsql {INSERT INTO t1 VALUES(3,4);}
} {1 {attempt to write a readonly database}}

breakpoint
do_test 160 {
  db deserialize -maxsize 32768 $db1
  db eval {SELECT * FROM t1}
} {1 2}
do_test 161 {
  db eval {INSERT INTO t1 VALUES(3,4); SELECT * FROM t1}
} {1 2 3 4}
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
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







+



















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

    CREATE TABLE t2(x, y);
  } {wal}
  db close
  
  set fd [open test.db]
  fconfigure $fd -translation binary -encoding binary
  set data [read $fd [expr 20*1024]]
  close $fd
  
  sqlite3 db ""
  db deserialize $data
  
  do_execsql_test 810 {
    PRAGMA locking_mode = exclusive;
    SELECT * FROM t1
  } {exclusive 1 2}
  
  do_execsql_test 820 {
    INSERT INTO t1 VALUES(3, 4);
    SELECT * FROM t1;
  } {1 2 3 4}
  
  do_catchsql_test 830 {
    PRAGMA wal_checkpoint;
  } {1 {database disk image is malformed}}
}

# 2024-01-20
# https://sqlite.org/forum/forumpost/498777780e16880a
#
# Make sure a database is initialized before serializing it.
#
reset_db
sqlite3 dbempty :memory:
do_test 900 {
  set len [string length [dbempty serialize]]
  expr {$len>0}
} 1
dbempty close

finish_test
Changes to test/misc1.test.
650
651
652
653
654
655
656
657

658
659
660
661
662
663
664
650
651
652
653
654
655
656

657
658
659
660
661
662
663
664







-
+







# 2015-03-22: NULL pointer dereference after a syntax error
#
do_catchsql_test misc1-21.1 {
  select''like''like''like#0;
} {1 {near "#0": syntax error}}
do_catchsql_test misc1-21.2 {
  VALUES(0,0x0MATCH#0;
} {1 {near ";": syntax error}}
} {1 {unrecognized token: "0x0MATCH"}}

# 2015-04-15
do_execsql_test misc1-22.1 {
  SELECT ''+3 FROM (SELECT ''+5);
} {3}

# 2015-04-19: NULL pointer dereference on a corrupt schema
Changes to test/misc5.test.
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
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







-
-
-
+
+
+

-
+







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

+
-
+







      SELECT * FROM logs 
      LIMIT (SELECT lmt FROM logs_base) ;
    }
  } {1 {no such table: logs_base}}
}

# Overflow the lemon parser stack by providing an overly complex
# expression.  Make sure that the overflow is detected and reported.
#
# This test fails when building with -DYYSTACKDEPTH=0
# expression.  Make sure that the overflow is detected and the
# stack is grown automatically such that the application calling
# SQLite never notices.
#
do_test misc5-7.1 {
do_test misc5-7.1.1 {
  execsql {CREATE TABLE t1(x)}
  set sql "INSERT INTO t1 VALUES("
  set tail ""
  for {set i 0} {$i<200} {incr i} {
    append sql "(1+"
    append tail ")"
  }
  append sql "0$tail); SELECT * FROM t1;"
  catchsql $sql
} {0 200}
do_test misc5-7.1.2 {
  execsql {DELETE FROM t1}
  set sql "INSERT INTO t1 VALUES("
  set tail ""
  for {set i 0} {$i<900} {incr i} {
  append sql 2$tail
    append sql "(1+"
    append tail ")"
  }
  append sql "0$tail); SELECT * FROM t1;"
  catchsql $sql
} {0 900}
} {1 {parser stack overflow}}


# Parser stack overflow is silently ignored when it occurs while parsing the
# schema and PRAGMA writable_schema is turned on.
#
do_test misc5-7.2 {
  sqlite3 db2 :memory:
  sqlite3_db_config db2 DEFENSIVE 0
Changes to test/mmap1.test.
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
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







-
-
+
+




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







      string range [string repeat [set str] [expr [set n]/4]] 1 [set n]
    }
    $dbname func rblob rblob
  }]
}


# For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on
# unix and 9 on windows. The difference is that windows only ever maps
# For cases 1.1 and 1.4, the number of pages read using xRead() is 8 on
# unix and 12 on windows. The difference is that windows only ever maps
# an integer number of OS pages (i.e. creates mappings that are a multiple
# of 4KB in size). Whereas on unix any sized mapping may be created.
#
foreach {t mmap_size nRead c2init} {
  1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0}
  1.2 { PRAGMA mmap_size =    53248 } 150    {PRAGMA mmap_size = 0}
  1.3 { PRAGMA mmap_size =        0 } 344    {PRAGMA mmap_size = 0}
  1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 }
  1.5 { PRAGMA mmap_size =    53248 } 150    {PRAGMA mmap_size = 67108864 }
  1.6 { PRAGMA mmap_size =        0 } 344    {PRAGMA mmap_size = 67108864 }
  1.1 { PRAGMA mmap_size = 67108864 } /8|12/   {PRAGMA mmap_size = 0}
  1.2 { PRAGMA mmap_size =    53248 } /15[34]/ {PRAGMA mmap_size = 0}
  1.3 { PRAGMA mmap_size =        0 } 344      {PRAGMA mmap_size = 0}
  1.4 { PRAGMA mmap_size = 67108864 } /12|8/   {PRAGMA mmap_size = 67108864 }
  1.5 { PRAGMA mmap_size =    53248 } /15[34]/ {PRAGMA mmap_size = 67108864 }
  1.6 { PRAGMA mmap_size =        0 } 344      {PRAGMA mmap_size = 67108864 }
} {

  do_multiclient_test tn {
    sql1 {PRAGMA cache_size=2000}
    sql2 {PRAGMA cache_size=2000}

    sql1 {PRAGMA page_size=1024}
Added test/mmapcorrupt.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 January 23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Test special cases of corrupt database handling in mmap-mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix mmapcorrupt

database_may_be_corrupt

db close
sqlite3_shutdown
sqlite3_config_lookaside 0 0
sqlite3_initialize

reset_db
do_execsql_test 1.0 {
  PRAGMA page_size = 16384;
  CREATE TABLE tn1(a PRIMARY KEY) WITHOUT ROWID;
  CREATE TABLE t0(a PRIMARY KEY) WITHOUT ROWID;
  CREATE TABLE t1(a PRIMARY KEY) WITHOUT ROWID;
  INSERT INTO t1 VALUES('B');
}
db close

set sz [file size test.db]
hexio_write test.db [expr $sz-3] 800380

sqlite3 db test.db
do_execsql_test 2.1 {
  PRAGMA mmap_size = 1000000;
  SELECT sql FROM sqlite_schema LIMIT 1;
  SELECT * FROM t0;
} {1000000 {CREATE TABLE tn1(a PRIMARY KEY) WITHOUT ROWID}}

do_execsql_test 2.2 {
  INSERT INTO t0 SELECT * FROM t1;
}

finish_test

Changes to test/notnull2.test.
55
56
57
58
59
60
61
62

63
64

65
66
67

68
69

70
71
72
73
74
75
76
55
56
57
58
59
60
61

62
63

64
65
66

67
68

69
70
71
72
73
74
75
76







-
+

-
+


-
+

-
+







} 100 {}
do_vmstep_test 1.4.2 {
  SELECT * FROM t2 WHERE 0==( c IS NOT NULL )
} +1000 {}

do_vmstep_test 1.5.1 {
  SELECT count(*) FROM t2 WHERE EXISTS(
    SELECT t2.d IS NULL FROM t1 WHERE t1.a=450
    SELECT 1 FROM t1 WHERE t1.a=450 AND t2.d IS NULL
  )
} 10000 {1000}
} 7000 {0}
do_vmstep_test 1.5.2 {
  SELECT count(*) FROM t2 WHERE EXISTS(
    SELECT t2.c IS NULL FROM t1 WHERE t1.a=450
    SELECT 1 FROM t1 WHERE t1.a=450 AND t2.c IS NULL
  )
} +100000 {1000}
} +8000 {0}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
  CREATE TABLE T1(a INTEGER PRIMARY KEY, b);
  CREATE TABLE T3(k, v);
}
106
107
108
109
110
111
112
113








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








+
+
+
+
+
+
+
+

} {{} 1 / missing {} /}
do_execsql_test 4.1 {
  CREATE TABLE t1(a INT);
  INSERT INTO t1(a) VALUES(1);
  CREATE TABLE t2(b INT);
  SELECT * FROM (SELECT 3 AS c FROM t1) AS t3 LEFT JOIN t2 ON c IS NULL;
} {3 {}}

# 2024-03-08 https://sqlite.org/forum/forumpost/440f2a2f17
#
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a INT NOT NULL);
  SELECT a IS NULL, a IS NOT NULL, count(*) FROM t1;
} {1 0 0}

finish_test
Changes to test/permutations.test.
91
92
93
94
95
96
97

98
99
100
101
102
103
104
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105







+







foreach f [glob -nocomplain            \
    $testdir/../ext/rtree/*.test       \
    $testdir/../ext/fts5/test/*.test   \
    $testdir/../ext/expert/*.test      \
    $testdir/../ext/lsm1/test/*.test   \
    $testdir/../ext/recover/*.test     \
    $testdir/../ext/rbu/*.test         \
    $testdir/../ext/intck/*.test       \
] {
  lappend alltests $f 
}
foreach f [glob -nocomplain $testdir/../ext/session/*.test] { 
  lappend alltests $f 
}
unset f
Changes to test/pragma.test.
368
369
370
371
372
373
374
375

376
377
378

379
380
381
382
383
384

385
386
387
388
389

390
391
392
393
394
395

396
397
398
399
400
401
402
403

404
405
406
407
408
409
410
368
369
370
371
372
373
374

375
376
377

378
379
380
381
382
383

384
385
386
387
388

389
390
391
392
393
394

395
396
397
398
399
400
401
402

403
404
405
406
407
408
409
410







-
+


-
+





-
+




-
+





-
+







-
+







      # make the index appear to be empty.
      #
      set offset [expr {$pgsz*($rootpage-1)}]
      hexio_write test.db $offset 0a00000000040000000000
      db close
      sqlite3 db test.db
      execsql {PRAGMA integrity_check}
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    } {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
    do_test pragma-3.3 {
      execsql {PRAGMA integrity_check=1}
    } {{row 1 missing from index i2}}
    } {{wrong # of entries in index i2}}
    do_test pragma-3.4 {
      execsql {
        ATTACH DATABASE 'test.db' AS t2;
        PRAGMA integrity_check
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    } {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
    do_test pragma-3.5 {
      execsql {
        PRAGMA integrity_check=4
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}}
    } {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    do_catchsql_test pragma-3.6 {
      PRAGMA integrity_check=xyz
    } {1 {no such table: xyz}}
    do_catchsql_test pragma-3.6b {
      PRAGMA integrity_check=t2
    } {0 {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}}
    } {0 {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}}
    do_catchsql_test pragma-3.6c {
      PRAGMA integrity_check=sqlite_schema
    } {0 ok}
    do_test pragma-3.7 {
      execsql {
        PRAGMA integrity_check=0
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    } {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
  
    # Add additional corruption by appending unused pages to the end of
    # the database file testerr.db
    #
    do_test pragma-3.8 {
      execsql {DETACH t2}
      forcedelete testerr.db testerr.db-journal
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
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







-
+


-
+
















-
+







-
+







      execsql {
        ATTACH 'testerr.db' AS t2;
        PRAGMA integrity_check
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
    do_execsql_test pragma-3.9b {
      PRAGMA t2.integrity_check=t2;
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    } {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
    do_execsql_test pragma-3.9c {
      PRAGMA t2.integrity_check=sqlite_schema;
    } {ok}
    do_test pragma-3.10 {
      execsql {
        PRAGMA integrity_check=1
      }
    } {{*** in database t2 ***
Page 4: never used}}
    do_test pragma-3.11 {
      execsql {
        PRAGMA integrity_check=5
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2}}
    do_test pragma-3.12 {
      execsql {
        PRAGMA integrity_check=4
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2}}
    do_test pragma-3.13 {
      execsql {
        PRAGMA integrity_check=3
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
483
484
485
486
487
488
489
490

491
492
493

494
495
496
497
498
499
500
501

502
503
504

505
506
507
508
509
510
511
512

513
514
515
516
517
518
519
520
521
522

523
524
525
526
527
528
529
483
484
485
486
487
488
489

490
491
492

493
494
495
496
497
498
499
500

501
502
503

504
505
506
507
508
509
510
511

512
513
514
515
516
517
518
519
520
521

522
523
524
525
526
527
528
529







-
+


-
+







-
+


-
+







-
+









-
+







      execsql {
        ATTACH 'testerr.db' AS t3;
        PRAGMA integrity_check
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
    do_test pragma-3.16 {
      execsql {
        PRAGMA integrity_check(10)
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2}}
    do_test pragma-3.17 {
      execsql {
        PRAGMA integrity_check=8
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
Page 4: never used
Page 5: never used}}
    do_test pragma-3.18 {
      execsql {
        PRAGMA integrity_check=4
      }
    } {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2}}
  }
  do_test pragma-3.19 {
    catch {db close}
    forcedelete test.db test.db-journal
    sqlite3 db test.db
    db eval {PRAGMA integrity_check}
  } {ok}
552
553
554
555
556
557
558















559
560
561
562
563
564
565
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







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







  } {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}}
  do_execsql_test pragma-3.22 {
    PRAGMA integrity_check(2);
  } {{non-unique entry in index t1a} {NULL value in t1x.a}}
  do_execsql_test pragma-3.23 {
    PRAGMA integrity_check(1);
  } {{non-unique entry in index t1a}}

  # forum post https://sqlite.org/forum/forumpost/ee4f6fa5ab
  do_execsql_test pragma-3.24 {
    DROP TABLE IF EXISTS t1;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES (1);
    ALTER TABLE t1 ADD COLUMN b NOT NULL DEFAULT 0.25;
    SELECT * FROM t1;
    PRAGMA integrity_check(t1);
  } {1 0.25 ok}
  do_execsql_test pragma-3.25 {
    ALTER TABLE t1 ADD COLUMN c CHECK (1);
    SELECT * FROM t1;
    PRAGMA integrity_check(t1);
  } {1 0.25 {} ok}
}

# PRAGMA integrity check (or more specifically the sqlite3BtreeCount()
# interface) used to leave index cursors in an inconsistent state
# which could result in an assertion fault in sqlite3BtreeKey()
# called from saveCursorPosition() if content is removed from the
# index while the integrity_check is still running.  This test verifies
Changes to test/pragma4.test.
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107







-
+







    WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10000)
    INSERT INTO t1(x) SELECT zeroblob(300) FROM c;
    CREATE TABLE t2(y);
    DROP TABLE t1;
  }
  string map {\[ x \] x \173 {} \175 {}} \
    [db eval {EXPLAIN PRAGMA integrity_check}]
} {/ IntegrityCk 2 2 1 x[0-9]+,1x /}
} {/ IntegrityCk 1 2 8 x[0-9]+,1x /}


#--------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
do_execsql_test 4.1.1 {
Added test/pragma6.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 February 27
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements tests for PRAGMAs quick_check and integrity_check.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix pragma6

database_may_be_corrupt

#-------------------------------------------------------------------------
#
do_test 1.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
    .open --hexdb
    | size 12288 pagesize 4096 filename crash-540f4c1eb1e7ac.db
    | page 1 offset 0
    |      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
    |     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 03   .....@  ........
    |     32: 00 bb 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
    |     96: 00 00 00 00 0d 00 00 00 02 0f 7f 00 0f c3 0f 7f   ................
    |   3952: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42   ...............B
    |   3968: 02 06 17 11 11 01 71 74 61 62 6c 65 74 32 74 32   ......qtablet2t2
    |   3984: 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32   .CREATE TABLE t2
    |   4000: 28 61 20 49 4e 54 2c 20 62 20 41 53 20 28 61 2a   (a INT, b AS (a*
    |   4016: 32 29 20 53 54 4f 52 45 44 20 4e 4f 54 20 4e 55   2) STORED NOT NU
    |   4032: 4c 4c 29 3b 01 06 17 11 11 01 63 74 61 62 6c 65   LL);......ctable
    |   4048: 74 31 74 31 02 43 52 45 41 54 45 20 54 41 42 4c   t1t1.CREATE TABL
    |   4064: 45 20 74 31 28 61 20 49 4e 54 2c 20 62 20 41 53   E t1(a INT, b AS
    |   4080: 20 28 61 2a 32 29 20 4e 4f 54 20 4e 55 4c 4c 29    (a*2) NOT NULL)
    | page 2 offset 4096
    |      0: 0d 00 00 00 05 0f e7 00 00 00 00 00 00 00 00 00   ................
    |   4064: 00 00 00 00 00 00 00 00 03 05 02 01 05 03 04 02   ................
    |   4080: 01 04 03 03 02 01 03 03 02 02 01 02 02 01 02 09   ................
    | page 3 offset 8192
    |      0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
    |   4048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 05   ................
    |   4064: 03 01 01 05 0a 05 04 03 01 01 04 08 05 03 03 01   ................
    |   4080: 01 03 06 05 02 03 00 00 00 00 00 00 00 00 00 00   ................
    | end crash-540f4c1eb1e7ac.db
  }]
} {}

do_test 1.1 {
  execsql {
    CREATE TEMP TABLE t2(
        a t1 PRIMARY KEY default 27,
        b default(current_timestamp),
        d TEXT UNIQUE DEFAULT 'ch`arlie',
        c TEXT UNIQUE DEFAULT 084,
        UNIQUE(c,b,b,a,b)
    ) WITHOUT ROWID;
  }
  catchsql { INSERT INTO t1(a) VALUES(zeroblob(40000)) }
  set {} {}
} {}

do_test 1.2 {
  execsql { PRAGMA integrity_check; }
  execsql { PRAGMA quick_check; }
  set {} {}
} {}

finish_test
Changes to test/printf.test.
3828
3829
3830
3831
3832
3833
3834

















3835
3836
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853







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


#
db close
sqlite3 db test.db
sqlite3_db_config_lookaside db 0 0 0
do_execsql_test printf-18.1 {
  SELECT length( format('%,.249f', -5.0e-300) );
} {252}

# 2024-02-16
# https://sqlite.org/forum/info/393708f4a8
#
# The problem introduced by on 2023-07-03 by
# https://sqlite.org/src/info/32befb224b254639
#
do_execsql_test printf-19.1 {
  SELECT format('%0.0f %0.0g %0.0g', 0.9, 0.09, 1.9);
} {{1 0.09 2}}
do_execsql_test printf-19.2 {
  SELECT format('%0.0f %#0.0f',0.0, 0.0);
} {{0 0.}}
do_execsql_test printf-19.3 {
  SELECT format('%,.0f %,.0f',12345e+10, 12345e+11);
} {{123,450,000,000,000 1,234,500,000,000,000}}


finish_test
Changes to test/quote.test.
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
99
100
101
102
103
104
105

106
107
108
109
110
111
112
113







-
+







}
foreach {tn sql errname} {
  1 { CREATE TABLE xyz(a, b, c CHECK (c!="null") ) } null
  2 { CREATE INDEX i2 ON t1(x, y, z||"abc") }        abc
  3 { CREATE INDEX i3 ON t1("w") }                   w
  4 { CREATE INDEX i4 ON t1(x) WHERE z="w" }         w
} {
  do_catchsql_test 2.1.$tn $sql [list 1 "no such column: $errname"]
  do_catchsql_test 2.1.$tn $sql [list 1 "no such column: \"$errname\" - should this be a string literal in single-quotes?"]
}

do_execsql_test 2.2 {
  PRAGMA writable_schema = 1;
  CREATE TABLE xyz(a, b, c CHECK (c!="null") );
  CREATE INDEX i2 ON t1(x, y, z||"abc");
  CREATE INDEX i3 ON t1("w"||"");
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
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







-
+





-
+





-
+












-
+











# ticket 1c24a659e6d7f3a1
ifcapable altertable {
  reset_db
    do_catchsql_test 3.0 {
      CREATE TABLE t1(a,b);
      CREATE INDEX x1 on t1("b");
      ALTER TABLE t1 DROP COLUMN b;
    } {1 {error in index x1 after drop column: no such column: b}}
    } {1 {error in index x1 after drop column: no such column: "b" - should this be a string literal in single-quotes?}}
  do_catchsql_test 3.1 {
    DROP TABLE t1;
    CREATE TABLE t1(a,"b");
    CREATE INDEX x1 on t1("b");
    ALTER TABLE t1 DROP COLUMN b;
  } {1 {error in index x1 after drop column: no such column: b}}
  } {1 {error in index x1 after drop column: no such column: "b" - should this be a string literal in single-quotes?}}
  do_catchsql_test 3.2 {
    DROP TABLE t1;
    CREATE TABLE t1(a,'b');
    CREATE INDEX x1 on t1("b");
    ALTER TABLE t1 DROP COLUMN b;
  } {1 {error in index x1 after drop column: no such column: b}}
  } {1 {error in index x1 after drop column: no such column: "b" - should this be a string literal in single-quotes?}}
  do_catchsql_test 3.3 {
    DROP TABLE t1;
    CREATE TABLE t1(a,"b");
    CREATE INDEX x1 on t1('b');
    ALTER TABLE t1 DROP COLUMN b;
  } {1 {error in index x1 after drop column: no such column: b}}
  do_catchsql_test 3.4 {
    DROP TABLE t1;
    CREATE TABLE t1(a, b, c);
    CREATE INDEX x1 ON t1("a"||"b");
    INSERT INTO t1 VALUES(1,2,3),(1,4,5);
    ALTER TABLE t1 DROP COLUMN b;
  } {1 {error in index x1 after drop column: no such column: b}}
  } {1 {error in index x1 after drop column: no such column: "b" - should this be a string literal in single-quotes?}}
  sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
  do_catchsql_test 3.5 {
    DROP TABLE t1;
    CREATE TABLE t1(a, b, c);
    CREATE INDEX x1 ON t1("a"||"x");
    INSERT INTO t1 VALUES(1,2,3),(1,4,5);
    ALTER TABLE t1 DROP COLUMN b;
  } {0 {}}
}

finish_test
Changes to test/recover.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2019 April 23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# TESTRUNNER: shell
#
# Test the shell tool ".ar" command.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix recover
Deleted test/releasetest_data.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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













































































































































































































































































































































































































































































































































































































































































































































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# 2019 August 01
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements a program that produces scripts (either shell scripts
# or batch files) to implement a particular test that is part of the SQLite
# release testing procedure. For example, to run veryquick.test with a 
# specified set of -D compiler switches.
#
# A "configuration" is a set of options passed to [./configure] and [make]
# to build the SQLite library in a particular fashion. A "platform" is a
# list of tests; most platforms are named after the hardware/OS platform
# that the tests will be run on as part of the release procedure. Each 
# "test" is a combination of a configuration and a makefile target (e.g.
# "fulltest"). The program may be invoked as follows:
#
set USAGE {
$argv0 script ?-msvc? CONFIGURATION TARGET
    Given a configuration and make target, return a bash (or, if -msvc
    is specified, batch) script to execute the test. The first argument
    passed to the script must be a directory containing SQLite source code.

$argv0 configurations
    List available configurations.

$argv0 platforms
    List available platforms.

$argv0 tests ?-nodebug? PLATFORM
    List tests in a specified platform. If the -nodebug switch is 
    specified, synthetic debug/ndebug configurations are omitted. Each
    test is a combination of a configuration and a makefile target.
}

# Omit comments (text between # and \n) in a long multi-line string.
#
proc strip_comments {in} {
  regsub -all {#[^\n]*\n} $in {} out
  return $out
}

array set ::Configs [strip_comments {
  "Default" {
    -O2
    --disable-amalgamation --disable-shared
    --enable-session
    -DSQLITE_ENABLE_RBU
  }
  "All-Debug" {
    --enable-debug --enable-all
  }
  "All-O0" {
    -O0 --enable-all
  }
  "Sanitize" {
    CC=clang -fsanitize=address,undefined
    -DSQLITE_ENABLE_STAT4
    -DCONFIG_SLOWDOWN_FACTOR=5.0
    --enable-debug
    --enable-all
  }
  "Stdcall" {
    -DUSE_STDCALL=1
    -O2
  }
  "Have-Not" {
    # The "Have-Not" configuration sets all possible -UHAVE_feature options
    # in order to verify that the code works even on platforms that lack
    # these support services.
    -DHAVE_FDATASYNC=0
    -DHAVE_GMTIME_R=0
    -DHAVE_ISNAN=0
    -DHAVE_LOCALTIME_R=0
    -DHAVE_LOCALTIME_S=0
    -DHAVE_MALLOC_USABLE_SIZE=0
    -DHAVE_STRCHRNUL=0
    -DHAVE_USLEEP=0
    -DHAVE_UTIME=0
  }
  "Unlock-Notify" {
    -O2
    -DSQLITE_ENABLE_UNLOCK_NOTIFY
    -DSQLITE_THREADSAFE
    -DSQLITE_TCL_DEFAULT_FULLMUTEX=1
  }
  "User-Auth" {
    -O2
    -DSQLITE_USER_AUTHENTICATION=1
  }
  "Secure-Delete" {
    -O2
    -DSQLITE_SECURE_DELETE=1
    -DSQLITE_SOUNDEX=1
  }
  "Update-Delete-Limit" {
    -O2
    -DSQLITE_DEFAULT_FILE_FORMAT=4
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    -DSQLITE_ENABLE_STMT_SCANSTATUS
    -DSQLITE_LIKE_DOESNT_MATCH_BLOBS
    -DSQLITE_ENABLE_CURSOR_HINTS
  }
  "Check-Symbols" {
    -DSQLITE_MEMDEBUG=1
    -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_MEMSYS5=1
    -DSQLITE_ENABLE_MEMSYS3=1
    -DSQLITE_ENABLE_COLUMN_METADATA=1
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    -DSQLITE_SECURE_DELETE=1
    -DSQLITE_SOUNDEX=1
    -DSQLITE_ENABLE_ATOMIC_WRITE=1
    -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
    -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
    -DSQLITE_ENABLE_STAT4
    -DSQLITE_ENABLE_STMT_SCANSTATUS
    --enable-fts5 --enable-session
  }
  "Debug-One" {
    --disable-shared
    -O2 -funsigned-char
    -DSQLITE_DEBUG=1
    -DSQLITE_MEMDEBUG=1
    -DSQLITE_MUTEX_NOOP=1
    -DSQLITE_TCL_DEFAULT_FULLMUTEX=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_MEMSYS5=1
    -DSQLITE_ENABLE_COLUMN_METADATA=1
    -DSQLITE_ENABLE_STAT4
    -DSQLITE_ENABLE_HIDDEN_COLUMNS
    -DSQLITE_MAX_ATTACHED=125
    -DSQLITE_MUTATION_TEST
    --enable-fts5
  }
  "Debug-Two" {
    -DSQLITE_DEFAULT_MEMSTATUS=0
    -DSQLITE_MAX_EXPR_DEPTH=0
    --enable-debug
  }
  "Fast-One" {
    -O6
    -DSQLITE_ENABLE_FTS4=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_STAT4
    -DSQLITE_ENABLE_RBU
    -DSQLITE_MAX_ATTACHED=125
    -DSQLITE_MAX_MMAP_SIZE=12884901888
    -DSQLITE_ENABLE_SORTER_MMAP=1
    -DLONGDOUBLE_TYPE=double
    --enable-session
  }
  "Device-One" {
    -O2
    -DSQLITE_DEBUG=1
    -DSQLITE_DEFAULT_AUTOVACUUM=1
    -DSQLITE_DEFAULT_CACHE_SIZE=64
    -DSQLITE_DEFAULT_PAGE_SIZE=1024
    -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32
    -DSQLITE_DISABLE_LFS=1
    -DSQLITE_ENABLE_ATOMIC_WRITE=1
    -DSQLITE_ENABLE_IOTRACE=1
    -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
    -DSQLITE_MAX_PAGE_SIZE=4096
    -DSQLITE_OMIT_LOAD_EXTENSION=1
    -DSQLITE_OMIT_PROGRESS_CALLBACK=1
    -DSQLITE_OMIT_VIRTUALTABLE=1
    -DSQLITE_ENABLE_HIDDEN_COLUMNS
    -DSQLITE_TEMP_STORE=3
  }
  "Device-Two" {
    -DSQLITE_4_BYTE_ALIGNED_MALLOC=1
    -DSQLITE_DEFAULT_AUTOVACUUM=1
    -DSQLITE_DEFAULT_CACHE_SIZE=1000
    -DSQLITE_DEFAULT_LOCKING_MODE=0
    -DSQLITE_DEFAULT_PAGE_SIZE=1024
    -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000
    -DSQLITE_DISABLE_LFS=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_MAX_COMPOUND_SELECT=50
    -DSQLITE_MAX_PAGE_SIZE=32768
    -DSQLITE_OMIT_TRACE=1
    -DSQLITE_TEMP_STORE=3
    -DSQLITE_THREADSAFE=2
    --enable-fts5 --enable-session
  }
  "Locking-Style" {
    -O2
    -DSQLITE_ENABLE_LOCKING_STYLE=1
  }
  "Apple" {
    -Os
    -DHAVE_GMTIME_R=1
    -DHAVE_ISNAN=1
    -DHAVE_LOCALTIME_R=1
    -DHAVE_PREAD=1
    -DHAVE_PWRITE=1
    -DHAVE_UTIME=1
    -DSQLITE_DEFAULT_CACHE_SIZE=1000
    -DSQLITE_DEFAULT_CKPTFULLFSYNC=1
    -DSQLITE_DEFAULT_MEMSTATUS=1
    -DSQLITE_DEFAULT_PAGE_SIZE=1024
    -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1
    -DSQLITE_ENABLE_API_ARMOR=1
    -DSQLITE_ENABLE_AUTO_PROFILE=1
    -DSQLITE_ENABLE_FLOCKTIMEOUT=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
    -DSQLITE_ENABLE_FTS3_TOKENIZER=1
    -DSQLITE_ENABLE_PERSIST_WAL=1
    -DSQLITE_ENABLE_PURGEABLE_PCACHE=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_SNAPSHOT=1
    # -DSQLITE_ENABLE_SQLLOG=1
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    -DSQLITE_MAX_LENGTH=2147483645
    -DSQLITE_MAX_VARIABLE_NUMBER=500000
    # -DSQLITE_MEMDEBUG=1
    -DSQLITE_NO_SYNC=1
    -DSQLITE_OMIT_AUTORESET=1
    -DSQLITE_OMIT_LOAD_EXTENSION=1
    -DSQLITE_PREFER_PROXY_LOCKING=1
    -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
    -DSQLITE_THREADSAFE=2
    -DSQLITE_USE_URI=1
    -DSQLITE_WRITE_WALFRAME_PREBUFFERED=1
    -DUSE_GUARDED_FD=1
    -DUSE_PREAD=1
    --enable-fts5
  }
  "Extra-Robustness" {
    -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
    -DSQLITE_MAX_ATTACHED=62
  }
  "Devkit" {
    -DSQLITE_DEFAULT_FILE_FORMAT=4
    -DSQLITE_MAX_ATTACHED=30
    -DSQLITE_ENABLE_COLUMN_METADATA
    -DSQLITE_ENABLE_FTS4
    -DSQLITE_ENABLE_FTS5
    -DSQLITE_ENABLE_FTS4_PARENTHESIS
    -DSQLITE_DISABLE_FTS4_DEFERRED
    -DSQLITE_ENABLE_RTREE
    --enable-fts5
  }
  "No-lookaside" {
    -DSQLITE_TEST_REALLOC_STRESS=1
    -DSQLITE_OMIT_LOOKASIDE=1
  }
  "Valgrind" {
    -DSQLITE_ENABLE_STAT4
    -DSQLITE_ENABLE_FTS4
    -DSQLITE_ENABLE_RTREE
    -DSQLITE_ENABLE_HIDDEN_COLUMNS
    -DLONGDOUBLE_TYPE=double
    -DCONFIG_SLOWDOWN_FACTOR=8.0
  }

  "Windows-Memdebug" {
    MEMDEBUG=1
    DEBUG=3
  }
  "Windows-Win32Heap" {
    WIN32HEAP=1
    DEBUG=4
  }

  # The next group of configurations are used only by the
  # Failure-Detection platform.  They are all the same, but we need
  # different names for them all so that they results appear in separate
  # subdirectories.
  #
  Fail0     {-O0}
  Fail2     {-O0}
  Fail3     {-O0}
  Fail4     {-O0}
  FuzzFail1 {-O0}
  FuzzFail2 {-O0}
}]
if {$tcl_platform(os)=="Darwin"} {
  lappend Configs(Apple) -DSQLITE_ENABLE_LOCKING_STYLE=1
}

array set ::Platforms [strip_comments {
  Linux-x86_64 {
    "Check-Symbols*"          "" checksymbols
    "Fast-One"                QUICKTEST_INCLUDE=rbu.test "fuzztest test"
    "Debug-One"               "" "mptest test"
    "Debug-Two"               "" test
    "Have-Not"                "" test
    "Secure-Delete"           "" test
    "Unlock-Notify"           QUICKTEST_INCLUDE=notify2.test test
    "User-Auth"               "" tcltest
    "Update-Delete-Limit"     "" test
    "Extra-Robustness"        "" test
    "Device-Two"              "" "threadtest test"
    "No-lookaside"            "" test
    "Devkit"                  "" test
    "Apple"                   "" test
    "Sanitize*"               "" test
    "Device-One"              "" alltest
    "Default"                 "" "threadtest fuzztest alltest"
    "Valgrind*"               "" valgrindtest
  }
  Linux-i686 {
    "Devkit"                  "" test
    "Have-Not"                "" test
    "Unlock-Notify"           QUICKTEST_INCLUDE=notify2.test test
    "Device-One"              "" test
    "Device-Two"              "" test
    "Default"                 "" "threadtest fuzztest alltest"
  }
  Darwin-i386 {
    "Locking-Style"           "" "mptest test"
    "Have-Not"                "" test
    "Apple"                   "" "threadtest fuzztest alltest"
  }
  Darwin-x86_64 {
    "Locking-Style"           "" "mptest test"
    "Have-Not"                "" test
    "Apple"                   "" "threadtest fuzztest alltest"
  }
  Darwin-arm64 {
    "Locking-Style"           "" "mptest test"
    "Have-Not"                "" test
    "Apple"                   "" "threadtest fuzztest alltest"
  }
  "Windows NT-intel" {
    "Stdcall"                 "" test
    "Have-Not"                "" test
    "Windows-Memdebug*"       "" test
    "Windows-Win32Heap*"      "" test
    "Default"                 "" "mptest fulltestonly"
  }
  "Windows NT-amd64" {
    "Stdcall"                 "" test
    "Have-Not"                "" test
    "Windows-Memdebug*"       "" test
    "Windows-Win32Heap*"      "" test
    "Default"                 "" "mptest fulltestonly"
  }

  # The Failure-Detection platform runs various tests that deliberately
  # fail.  This is used as a test of this script to verify that this script
  # correctly identifies failures.
  #
  Failure-Detection {
    Fail0*     "TEST_FAILURE=0" test
    Sanitize*  "TEST_FAILURE=1" test
    Fail2*     "TEST_FAILURE=2" valgrindtest
    Fail3*     "TEST_FAILURE=3" valgrindtest
    Fail4*     "TEST_FAILURE=4" test
    FuzzFail1* "TEST_FAILURE=5" test
    FuzzFail2* "TEST_FAILURE=5" valgrindtest
  }
}]

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# End of configuration section.
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------

# Configuration verification: Check that each entry in the list of configs
# specified for each platforms exists.
#
foreach {key value} [array get ::Platforms] {
  foreach {v vars t} $value {
    if {[string range $v end end]=="*"} {
      set v [string range $v 0 end-1]
    }
    if {0==[info exists ::Configs($v)]} {
      puts stderr "No such configuration: \"$v\""
      exit -1
    }
  }
}

proc usage {} {
  global argv0
  puts stderr [subst $::USAGE]
  exit 1
}

proc is_prefix {p str min} {
  set n [string length $p]
  if {$n<$min} { return 0 }
  if {[string range $str 0 [expr $n-1]]!=$p} { return 0 }
  return 1
}

proc main_configurations {} {
  foreach k [lsort [array names ::Configs]] {
    puts $k
  }
}

proc main_platforms {} {
  foreach k [lsort [array names ::Platforms]] {
    puts "\"$k\""
  }
}

proc main_script {args} {
  set bMsvc 0
  set nArg [llength $args]
  if {$nArg==3} {
    if {![is_prefix [lindex $args 0] -msvc 2]} usage
    set bMsvc 1
  } elseif {$nArg<2 || $nArg>3} {
    usage
  }
  set config [lindex $args end-1]
  set target [lindex $args end]

  set opts       [list]                         ;# OPTS value
  set cflags     [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value
  set makeOpts   [list]                         ;# Extra args for [make]
  set configOpts [list]                         ;# Extra args for [configure]

  if {$::tcl_platform(platform)=="windows" || $bMsvc} {
    lappend opts -DSQLITE_OS_WIN=1
  } else {
    lappend opts -DSQLITE_OS_UNIX=1
  }

  # Figure out if this is a synthetic ndebug or debug configuration.
  #
  set bRemoveDebug 0
  if {[string match *-ndebug $config]} {
    set bRemoveDebug 1
    set config [string range $config 0 end-7]
  }
  if {[string match *-debug $config]} {
    lappend opts -DSQLITE_DEBUG
    lappend opts -DSQLITE_EXTRA_IFNULLROW
    set config [string range $config 0 end-6]
  }
  regexp {^(.*)-[0-9]+} $config -> config

  # Ensure that the named configuration exists.
  #
  if {![info exists ::Configs($config)]} {
    puts stderr "No such config: $config"
    exit 1
  }

  # Loop through the parameters of the nominated configuration, updating
  # $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as
  # follows:
  #
  #   1. If the parameter begins with a "*", discard it.
  #
  #   2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or
  #      -DSQLITE_DEBUG=1, discard it
  #
  #   3. If the parameter begins with "-D", add it to $opts.
  #
  #   4. If the parameter begins with "--" add it to $configOpts. Unless
  #      this command is preparing a script for MSVC - then add an 
  #      equivalent to $makeOpts or $opts.
  #
  #   5. If the parameter begins with "-" add it to $cflags. If in MSVC
  #      mode and the parameter is an -O<integer> option, instead add
  #      an OPTIMIZATIONS=<integer> switch to $makeOpts.
  #
  #   6. If none of the above apply, add the parameter to $makeOpts
  #
  foreach param $::Configs($config) {
    if {[string range $param 0 0]=="*"} continue

    if {$bRemoveDebug} {
      if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1"
       || $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1"
       || $param=="--enable-debug"
      } {
        continue
      }
    }

    if {[string range $param 0 1]=="-D"} {
      lappend opts $param
      continue
    }

    if {[string range $param 0 1]=="--"} {
      if {$bMsvc} {
        switch -- $param {
          --disable-amalgamation {
            lappend makeOpts USE_AMALGAMATION=0
          }
          --disable-shared {
            lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0
          }
          --enable-fts5 {
            lappend opts -DSQLITE_ENABLE_FTS5
          } 
          --enable-shared {
            lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1
          }
          --enable-session {
            lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK
            lappend opts -DSQLITE_ENABLE_SESSION
          }
          default {
            error "Cannot translate $param for MSVC"
          }
        }
      } else {
        lappend configOpts $param
      }

      continue
    }

    if {[string range $param 0 0]=="-"} {
      if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} {
        lappend makeOpts OPTIMIZATIONS=$level
      } else {
        lappend cflags $param
      }
      continue
    }

    lappend makeOpts $param
  }

  # Some configurations specify -DHAVE_USLEEP=0. For all others, add
  # -DHAVE_USLEEP=1.
  #
  if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} {
    lappend opts -DHAVE_USLEEP=1
  }

  if {$bMsvc==0} {
    puts {set -e}
    puts {}
    puts {if [ "$#" -ne 1 ] ; then}
    puts {  echo "Usage: $0 <sqlite-src-dir>" }
    puts {  exit -1 }
    puts {fi }
    puts {SRCDIR=$1}
    puts {}
    puts "TCL=\"[::tcl::pkgconfig get libdir,install]\""

    puts "\$SRCDIR/configure --with-tcl=\$TCL $configOpts"
    puts {}
    puts {OPTS="      -DSQLITE_NO_SYNC=1"}
    foreach o $opts { 
      puts "OPTS=\"\$OPTS $o\"" 
    }
    puts {}
    puts "CFLAGS=\"$cflags\""
    puts {}
    puts "make $target \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts"
  } else {

    puts {set SRCDIR=%1}
    set makecmd    "nmake /f %SRCDIR%\\Makefile.msc TOP=%SRCDIR% $target "
    append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts"

    puts "set TMP=%CD%"
    puts $makecmd
  }
}

proc main_trscript {args} {
  set bMsvc 0
  set nArg [llength $args]
  if {$nArg==3} {
    if {![is_prefix [lindex $args 0] -msvc 2]} usage
    set bMsvc 1
  } elseif {$nArg<2 || $nArg>3} {
    usage
  }
  set config [lindex $args end-1]
  set srcdir [lindex $args end]

  set opts       [list]                         ;# OPTS value
  set cflags     [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value
  set makeOpts   [list]                         ;# Extra args for [make]
  set configOpts [list]                         ;# Extra args for [configure]

  if {$::tcl_platform(platform)=="windows" || $bMsvc} {
    lappend opts -DSQLITE_OS_WIN=1
  } else {
    lappend opts -DSQLITE_OS_UNIX=1
  }

  # Figure out if this is a synthetic ndebug or debug configuration.
  #
  set bRemoveDebug 0
  if {[string match *-ndebug $config]} {
    set bRemoveDebug 1
    set config [string range $config 0 end-7]
  }
  if {[string match *-debug $config]} {
    lappend opts -DSQLITE_DEBUG
    lappend opts -DSQLITE_EXTRA_IFNULLROW
    set config [string range $config 0 end-6]
  }
  regexp {^(.*)-[0-9]+} $config -> config

  # Ensure that the named configuration exists.
  #
  if {![info exists ::Configs($config)]} {
    puts stderr "No such config: $config"
    exit 1
  }

  # Loop through the parameters of the nominated configuration, updating
  # $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as
  # follows:
  #
  #   1. If the parameter begins with a "*", discard it.
  #
  #   2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or
  #      -DSQLITE_DEBUG=1, discard it
  #
  #   3. If the parameter begins with "-D", add it to $opts.
  #
  #   4. If the parameter begins with "--" add it to $configOpts. Unless
  #      this command is preparing a script for MSVC - then add an 
  #      equivalent to $makeOpts or $opts.
  #
  #   5. If the parameter begins with "-" add it to $cflags. If in MSVC
  #      mode and the parameter is an -O<integer> option, instead add
  #      an OPTIMIZATIONS=<integer> switch to $makeOpts.
  #
  #   6. If none of the above apply, add the parameter to $makeOpts
  #
  foreach param $::Configs($config) {
    if {[string range $param 0 0]=="*"} continue

    if {$bRemoveDebug} {
      if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1"
       || $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1"
       || $param=="--enable-debug"
      } {
        continue
      }
    }

    if {[string range $param 0 1]=="-D"} {
      lappend opts $param
      continue
    }

    if {[string range $param 0 1]=="--"} {
      if {$bMsvc} {
        switch -- $param {
          --disable-amalgamation {
            lappend makeOpts USE_AMALGAMATION=0
          }
          --disable-shared {
            lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0
          }
          --enable-fts5 {
            lappend opts -DSQLITE_ENABLE_FTS5
          } 
          --enable-shared {
            lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1
          }
          --enable-session {
            lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK
            lappend opts -DSQLITE_ENABLE_SESSION
          }
          --enable-all {
          }
          --enable-debug {
            # lappend makeOpts OPTIMIZATIONS=0
            lappend opts -DSQLITE_DEBUG
          }
          default {
            error "Cannot translate $param for MSVC"
          }
        }
      } else {
        lappend configOpts $param
      }

      continue
    }

    if {[string range $param 0 0]=="-"} {
      if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} {
        lappend makeOpts OPTIMIZATIONS=$level
      } else {
        lappend cflags $param
      }
      continue
    }

    lappend makeOpts $param
  }

  # Some configurations specify -DHAVE_USLEEP=0. For all others, add
  # -DHAVE_USLEEP=1.
  #
  if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} {
    lappend opts -DHAVE_USLEEP=1
  }

  if {$bMsvc==0} {
    puts {set -e}
    puts {}
    puts {if [ "$#" -ne 1 ] ; then}
    puts {  echo "Usage: $0 <target>" }
    puts {  exit -1 }
    puts {fi }
    puts "SRCDIR=\"$srcdir\""
    puts {}
    puts "TCL=\"[::tcl::pkgconfig get libdir,install]\""

    puts {if [ ! -f Makefile ] ; then}
    puts "  \$SRCDIR/configure --with-tcl=\$TCL $configOpts"
    puts {fi}
    puts {}
    if {[info exists ::env(OPTS)]} {
      puts "# From environment variable:"
      puts "OPTS=$::env(OPTS)"
      puts ""
    }
    puts {OPTS="$OPTS -DSQLITE_NO_SYNC=1"}
    foreach o $opts { 
      puts "OPTS=\"\$OPTS $o\"" 
    }
    puts {}
    puts "CFLAGS=\"$cflags\""
    puts {}
    puts "make \$1 \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts"
  } else {

    set srcdir [file nativename [file normalize $srcdir]]
    # set srcdir [string map [list "\\" "\\\\"] $srcdir]

    puts {set TARGET=%1}
    set makecmd    "nmake /f $srcdir\\Makefile.msc TOP=\"$srcdir\" %TARGET% "
    append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts"

    puts "set TMP=%CD%"
    puts $makecmd
  }
}

proc main_tests {args} {
  set bNodebug 0
  set nArg [llength $args]
  if {$nArg==2} {
    if {[is_prefix [lindex $args 0] -nodebug 2]} {
      set bNodebug 1
    } elseif {[is_prefix [lindex $args 0] -debug 2]} {
      set bNodebug 0
    } else usage
  } elseif {$nArg==0 || $nArg>2} {
    usage
  }
  set p [lindex $args end]
  if {![info exists ::Platforms($p)]} {
    puts stderr "No such platform: $p"
    exit 1
  }

  set lTest [list]

  foreach {config vars target} $::Platforms($p) {
    if {[string range $config end end]=="*"} {
      set config [string range $config 0 end-1]
    } elseif {$bNodebug==0} {
      set dtarget test
      if {[lsearch $target fuzztest]<0 && [lsearch $target test]<0} {
        set dtarget tcltest
      }
      if {$vars!=""} { set dtarget "$vars $dtarget" }

      if {[string first SQLITE_DEBUG $::Configs($config)]>=0
       || [string first --enable-debug $::Configs($config)]>=0
      } {
        lappend lTest "$config-ndebug \"$dtarget\""
      } else {
        lappend lTest "$config-debug \"$dtarget\""
      }
    }

    if {[llength $target]==1 && ([string match "*TEST_FAILURE*" $vars] || (
        [lsearch $target "valgrindtest"]<0
     && [lsearch $target "alltest"]<0
     && [lsearch $target "fulltestonly"]<0
     && ![string match Sanitize* $config]
    ))} {
      if {$vars!=""} { set target "$vars $target" }
      lappend lTest "$config \"$target\""
    } else {
      set idir -1
      foreach t $target {
        if {$t=="valgrindtest" || $t=="alltest" || $t=="fulltestonly"
         || [string match Sanitize* $config]
        } {
          if {$vars!=""} { set t "$vars $t" }
          for {set ii 1} {$ii<=4} {incr ii} {
            lappend lTest "$config-[incr idir] \"TCLTEST_PART=$ii/4 $t\""
          }
        } else {
          if {$vars!=""} { set t "$vars $t" }
          lappend lTest "$config-[incr idir] \"$t\""
        }
      }
    }
  }

  foreach l $lTest {
    puts $l
  }

}

if {[llength $argv]==0} { usage }
set cmd [lindex $argv 0]
set n [expr [llength $argv]-1]
if {[string match ${cmd}* configurations] && $n==0} {
  main_configurations 
} elseif {[string match ${cmd}* script]} {
  main_script {*}[lrange $argv 1 end]
} elseif {[string match ${cmd}* trscript]} {
  main_trscript {*}[lrange $argv 1 end]
} elseif {[string match ${cmd}* platforms] && $n==0} {
  main_platforms
} elseif {[string match ${cmd}* tests]} {
  main_tests {*}[lrange $argv 1 end]
} else {
  usage
}
Changes to test/shell1.test.
1
2
3
4
5
6
7
8
9
10
11
12
13

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













+







# 2009 Nov 11
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the CLI shell tool.
#
# TESTRUNNER: shell
#

# Test plan:
#
#   shell1-1.*: Basic command line option handling.
#   shell1-2.*: Basic "dot" command token parsing.
#   shell1-3.*: Basic test that "dot" command can be called.
492
493
494
495
496
497
498
499
500



501
502
503






504
505
506
507
508
509
510
493
494
495
496
497
498
499


500
501
502
503


504
505
506
507
508
509
510
511
512
513
514
515
516







-
-
+
+
+

-
-
+
+
+
+
+
+







do_test shell1-3.14.3 {
  # too many arguments
  catchcmd "test.db" ".nullvalue FOO BAD"
} {1 {Usage: .nullvalue STRING}}

# .output FILENAME       Send output to FILENAME
do_test shell1-3.15.1 {
  catchcmd "test.db" ".output"
} {0 {}}
  catchcmd "test.db" ".output
.print x"
} {0 x}
do_test shell1-3.15.2 {
  catchcmd "test.db" ".output FOO"
} {0 {}}
  catchcmd "test.db" ".output FOO
.print x
.output
SELECT readfile('FOO');"
} {0 {x
}}
do_test shell1-3.15.3 {
  # too many arguments
  catchcmd "test.db" ".output FOO BAD"
} {1 {ERROR: extra parameter: "BAD".  Usage:
.output ?FILE?           Send output to FILE or stdout if FILE is omitted
   If FILE begins with '|' then open it as a pipe.
   Options:
Changes to test/shell2.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2009 Nov 11
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool.
#
# $Id: shell2.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
#

# Test plan:
Changes to test/shell3.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2009 Dec 16
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool.
#
# $Id: shell2.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
#

# Test plan:
Changes to test/shell4.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2010 July 28
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool.
# These tests are specific to the .stats command.
#
# 2015-03-19:  Added tests for .trace

# Test plan:
113
114
115
116
117
118
119
120

121
122
123
124
125
126
127
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128







-
+







  catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace --unknown"
} {1 {Unknown option "--unknown" on ".trace"}}
do_test shell4-2.2 {
  catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace off\n.trace off\n"
} {0 {}}
do_test shell4-2.3 {
  catchcmd ":memory:" ".trace stdout\n.dump\n.trace off\n"
} {/^0 {PRAGMA.*}$/}
} {/^0 {SELECT.*}$/}
do_test shell4-2.4 {
  catchcmd ":memory:" ".trace stdout\nCREATE TABLE t1(x);SELECT * FROM t1;"
} {0 {CREATE TABLE t1(x);
SELECT * FROM t1;}}
do_test shell4-2.5 {
  catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace stdout\nSELECT * FROM t1;"
} {0 {SELECT * FROM t1;}}
Changes to test/shell5.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2010 August 4
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool.
# These tests are specific to the .import command.
#
# $Id: shell5.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
#

565
566
567
568
569
570
571
572














573
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588








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

  close $out
  forcedelete test.db
  catchcmd test.db {.import -csv shell5.csv t1
.mode line
SELECT * FROM t1;}
} {0 {    1 = あい
    2 = うえお}}

# 2024-03-11 https://sqlite.org/forum/forumpost/ca014d7358
# Import into a table that contains computed columns.
#
do_test shell5-7.1 {
  set out [open shell5.csv w]
  fconfigure $out -translation lf
  puts $out {aaa|bbb}
  close $out
  forcedelete test.db
  catchcmd :memory: {CREATE TABLE t1(a TEXT, b TEXT, c AS (a||b));
.import shell5.csv t1
SELECT * FROM t1;}
} {0 aaa|bbb|aaabbb}

finish_test
Changes to test/shell6.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2016 December 15
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# Test the shell tool ".lint fkey-indexes" command.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !vtab {finish_test; return}
Changes to test/shell7.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2016 December 17
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# Test the readfile() function built into the shell tool. Specifically,
# that it does not truncate the blob read at the first embedded 0x00
# byte.
#

set testdir [file dirname $argv0]
Changes to test/shell8.test.
1
2
3
4
5
6
7
8
9
10

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










+







# 2017 December 9
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# Test the shell tool ".ar" command.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell8
Added test/shell9.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 Jan 8
#
# 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.
#
#***********************************************************************
# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool. Specifically, 
# testing that it is possible to run a ".dump" script that creates
# virtual tables without explicitly disabling defensive mode.
#
# And, that it can process a ".dump" script that contains strings
# delimited using double-quotes in the schema (DQS_DDL setting).
#

# Test plan:
#
#   shell1-1.*: Basic command line option handling.
#   shell1-2.*: Basic "dot" command token parsing.
#   shell1-3.*: Basic test that "dot" command can be called.
#   shell1-{4-8}.*: Test various "dot" commands's functionality.
#   shell1-9.*: Basic test that "dot" commands and SQL intermix ok.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set CLI [test_cli_invocation]

set ::testprefix shell9

ifcapable !fts5 {
  finish_test
  return
}

#----------------------------------------------------------------------------
# Test cases shell9-1.* verify that scripts output by .dump may be parsed
# by the shell tool without explicitly disabling DEFENSIVE mode, unless
# the shell is in safe mode.
#
do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
  INSERT INTO t1 VALUES('one', 'two', 'three');
}
db close

# Create .dump file in "testdump.txt".
#
set out [open testdump.txt w]
puts $out [lindex [catchcmd test.db .dump] 1]
close $out

# Check testdump.txt can be processed if the initial db is empty.
#
do_test 1.1.1 {
  forcedelete test.db
  catchcmd test.db ".read testdump.txt"
} {0 {}}
sqlite3 db test.db
do_execsql_test 1.1.2 {
  SELECT * FROM t1;
} {one two three}

# Check testdump.txt cannot be processed if the initial db is not empty.
#
reset_db
do_execsql_test 1.2.1 {
  CREATE TABLE t4(hello);
}
db close
do_test 1.2.2 {
  catchcmd test.db ".read testdump.txt"
} {1 {Parse error near line 5: table sqlite_master may not be modified}}

# Check testdump.txt cannot be processed if the db is in safe mode
#
do_test 1.3.1 {
  forcedelete test.db
  catchsafecmd test.db ".read testdump.txt"
} {1 {line 1: cannot run .read in safe mode}}
do_test 1.3.2 {
  set fd [open testdump.txt]
  set script [read $fd]
  close $fd
  forcedelete test.db
  catchsafecmd test.db $script
} {1 {Parse error near line 5: table sqlite_master may not be modified}}
do_test 1.3.3 {
  # Quick check that the above would have worked but for safe mode.
  forcedelete test.db
  catchcmd test.db $script
} {0 {}}

#----------------------------------------------------------------------------
# Test cases shell9-2.* verify that a warning is printed at the top of
# .dump scripts that contain virtual tables.
#
proc contains_warning {text} {
  return [string match "*WARNING: Script requires that*" $text]
}

reset_db
do_execsql_test 2.0.1 {
  CREATE TABLE t1(x);
  CREATE TABLE t2(y);
  INSERT INTO t1 VALUES('one');
  INSERT INTO t2 VALUES('two');
}
do_test 2.0.2 {
  contains_warning [catchcmd test.db .dump]
} 0

do_execsql_test 2.1.1 {
  CREATE virtual TABLE r1 USING fts5(x);
}
do_test 2.1.2 {
  contains_warning [catchcmd test.db .dump]
} 1

do_test 2.2.1 {
  contains_warning [catchcmd test.db ".dump t1"]
} 0
do_test 2.2.2 {
  contains_warning [catchcmd test.db ".dump r1"]
} 1

#-------------------------------------------------------------------------
reset_db
sqlite3_db_config db DQS_DDL 1
do_execsql_test 3.1.0 {
  CREATE TABLE t4(hello, check( hello IS NOT "xyz") );
}
db close

# Create .dump file in "testdump.txt".
#
set out [open testdump.txt w]
puts $out [lindex [catchcmd test.db .dump] 1]
close $out
do_test 3.1.1 {
  forcedelete test.db
  catchcmd test.db ".read testdump.txt"
} {0 {}}

finish_test
Changes to test/snapshot_up.test.
22
23
24
25
26
27
28


29
30
31
32
33
34
35
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37







+
+







# is that each connection opened as part of this permutation executes
# "PRAGMA journal_mode=memory", which fails if the database is in wal mode
# and there are one or more existing connections.
if {[permutation]=="inmemory_journal"} {
  finish_test
  return
}

db timeout 1000

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b, c);
  PRAGMA journal_mode = wal;
  INSERT INTO t1 VALUES(1, 2, 3);
  INSERT INTO t1 VALUES(4, 5, 6);
  INSERT INTO t1 VALUES(7, 8, 9);
Changes to test/speedtest1.c.
2145
2146
2147
2148
2149
2150
2151












































2152
2153
2154
2155
2156
2157
2158
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202







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







  for(i=1; i<=n; i++){
    x1 = swizzle(i, n);
    x2 = swizzle(x1, n);
    speedtest1_numbername(x1, zNum, sizeof(zNum));
    printf("%5d %5d %5d %s\n", i, x1, x2, zNum);
  }
}

/*
** This testset focuses on the speed of parsing numeric literals (integers
** and real numbers). This was added to test the impact of allowing "_"
** characters to appear in numeric SQL literals to make them easier to read. 
** For example, "SELECT 1_000_000;" instead of "SELECT 1000000;".
*/
void testset_parsenumber(void){
  const char *zSql1 = "SELECT 1, 12, 123, 1234, 12345, 123456";
  const char *zSql2 = "SELECT 8227256643844975616, 7932208612563860480, "
                      "2010730661871032832, 9138463067404021760, "
                      "2557616153664746496, 2557616153664746496";
  const char *zSql3 = "SELECT 1.0, 1.2, 1.23, 123.4, 1.2345, 1.23456";
  const char *zSql4 = "SELECT 8.227256643844975616, 7.932208612563860480, "
                      "2.010730661871032832, 9.138463067404021760, "
                      "2.557616153664746496, 2.557616153664746496";

  const int NROW = 100*g.szTest;
  int ii;

  speedtest1_begin_test(100, "parsing small integers");
  for(ii=0; ii<NROW; ii++){
    sqlite3_exec(g.db, zSql1, 0, 0, 0);
  }
  speedtest1_end_test();

  speedtest1_begin_test(110, "parsing large integers");
  for(ii=0; ii<NROW; ii++){
    sqlite3_exec(g.db, zSql2, 0, 0, 0);
  }
  speedtest1_end_test();

  speedtest1_begin_test(200, "parsing small reals");
  for(ii=0; ii<NROW; ii++){
    sqlite3_exec(g.db, zSql3, 0, 0, 0);
  }
  speedtest1_end_test();

  speedtest1_begin_test(210, "parsing large reals");
  for(ii=0; ii<NROW; ii++){
    sqlite3_exec(g.db, zSql4, 0, 0, 0);
  }
  speedtest1_end_test();
}

#ifdef __linux__
#include <sys/types.h>
#include <unistd.h>

/*
** Attempt to display I/O stats on Linux using /proc/PID/io
2553
2554
2555
2556
2557
2558
2559


2560
2561
2562
2563
2564
2565
2566
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612







+
+







      testset_orm();
    }else if( strcmp(zThisTest,"cte")==0 ){
      testset_cte();
    }else if( strcmp(zThisTest,"fp")==0 ){
      testset_fp();
    }else if( strcmp(zThisTest,"trigger")==0 ){
      testset_trigger();
    }else if( strcmp(zThisTest,"parsenumber")==0 ){
      testset_parsenumber();
    }else if( strcmp(zThisTest,"rtree")==0 ){
#ifdef SQLITE_ENABLE_RTREE
      testset_rtree(6, 147);
#else
      fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable "
                  "the R-Tree tests\n");
#endif
Changes to test/sqllimits1.test.
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
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







+











-







    set max $::SQLITE_MAX_EXPR_DEPTH
    set expr "(1 [string repeat {AND 1 } $max])"
    catchsql [subst {
      SELECT $expr
    }]
  } "1 {Expression tree is too large (maximum depth $::SQLITE_MAX_EXPR_DEPTH)}"
  
if 0 {  
  # Attempting to beat the expression depth limit using nested SELECT
  # queries causes a parser stack overflow. 
  do_test sqllimits1-9.2 {
    set max $::SQLITE_MAX_EXPR_DEPTH
    set expr "SELECT 1"
    for {set i 0} {$i <= $max} {incr i} {
      set expr "SELECT ($expr)"
    }
    catchsql [subst { $expr }]
  } "1 {parser stack overflow}"
  
if 0 {  
  do_test sqllimits1-9.3 {
    execsql {
      PRAGMA max_page_count = 1000000;  -- 1 GB
      CREATE TABLE v0(a);
      INSERT INTO v0 VALUES(1);
    }
    db transaction {
918
919
920
921
922
923
924
925

926
927
928
929
930
931
932
918
919
920
921
922
923
924

925
926
927
928
929
930
931
932







-
+







  CREATE TABLE b1(x);
  INSERT INTO b1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11);
} {0 {}}

do_catchsql_test sqllimits1-18.2 {
  INSERT INTO b1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
    UNION VALUES(11);
} {1 {too many terms in compound SELECT}}
} {0 {}}

#-------------------------------------------------------------------------
#
reset_db
ifcapable utf16 {
  do_execsql_test 19.0 {
    PRAGMA encoding = 'utf16';
Changes to test/tester.tcl.
550
551
552
553
554
555
556
557

558
559
560
561
562
563
564
550
551
552
553
554
555
556

557
558
559
560
561
562
563
564







-
+







          lappend leftover [file normalize $a]
        }
      }
    }
  }
  unset -nocomplain a
  set testdir [file normalize $testdir]
  set cmdlinearg(TESTFIXTURE_HOME) [pwd]
  set cmdlinearg(TESTFIXTURE_HOME) [file dirname [info nameofexec]]
  set cmdlinearg(INFO_SCRIPT) [file normalize [info script]]
  set argv0 [file normalize $argv0]
  if {$cmdlinearg(testdir)!=""} {
    file mkdir $cmdlinearg(testdir)
    cd $cmdlinearg(testdir)
  }
  set argv $leftover
879
880
881
882
883
884
885









886
887
888
889
890
891
892
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901







+
+
+
+
+
+
+
+
+







  global CLI
  set out [open cmds.txt w]
  puts $out $cmd
  close $out
  set line "exec $CLI $db < cmds.txt"
  set rc [catch { eval $line } msg]
  list $rc $msg
}
proc catchsafecmd {db {cmd ""}} {
  global CLI
  set out [open cmds.txt w]
  puts $out $cmd
  close $out
  set line "exec $CLI -safe $db < cmds.txt"
  set rc [catch { eval $line } msg]
  list $rc $msg
}

proc catchcmdex {db {cmd ""}} {
  global CLI
  set out [open cmds.txt w]
  fconfigure $out -encoding binary -translation binary
  puts -nonewline $out $cmd
Changes to test/testrunner.tcl.
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
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







+

+



+
+
+

+
+


-
+

+
+
+
+
-
-
+
+
+


-
+
+



















+
+
+
+
+
+







proc usage {} {
  set a0 [file tail $::argv0]

  puts stderr [string trim [subst -nocommands {
Usage: 
    $a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?
    $a0 PERMUTATION FILE
    $a0 help
    $a0 njob ?NJOB?
    $a0 script ?-msvc? CONFIG
    $a0 status

  where SWITCHES are:
    --buildonly
    --dryrun
    --explain
    --jobs NUMBER-OF-JOBS
    --stop-on-coredump
    --stop-on-error
    --zipvfs ZIPVFS-SOURCE-DIR

Interesting values for PERMUTATION are:
Special values for PERMUTATION that work with plain tclsh:

    list      - show all allowed PERMUTATION arguments.
    mdevtest  - tests recommended prior to normal development check-ins.
    release   - full release test with various builds.
    sdevtest  - like mdevtest but using ASAN and UBSAN.
    veryquick - a fast subset of the tcl test scripts. This is the default.
    full      - all tcl test scripts.

Other PERMUTATION arguments must be run using testfixture, not tclsh:

    all       - all tcl test scripts, plus a subset of test scripts rerun
                with various permutations.
    release   - full release test with various builds.
    full      - all tcl test scripts.
    veryquick - a fast subset of the tcl test scripts. This is the default.

If no PATTERN arguments are present, all tests specified by the PERMUTATION
are run. Otherwise, each pattern is interpreted as a glob pattern. Only
those tcl tests for which the final component of the filename matches at
least one specified pattern are run.

If no PATTERN arguments are present, then various fuzztest, threadtest
and other tests are run as part of the "release" permutation. These are
omitted if any PATTERN arguments are specified on the command line.

If a PERMUTATION is specified and is followed by the path to a Tcl script
instead of a list of patterns, then that single Tcl test script is run
with the specified permutation.

The "status" and "njob" commands are designed to be run from the same
directory as a running testrunner.tcl script that is running tests. The
"status" command prints a report describing the current state and progress 
of the tests. The "njob" command may be used to query or modify the number
of sub-processes the test script uses to run tests.

The "script" command outputs the script used to build a configuration.
Add the "-msvc" option for a Windows-compatible script. For a list of
available configurations enter "$a0 script help".

Full documentation here: https://sqlite.org/src/doc/trunk/doc/testrunner.md
  }]]

  exit 1
}
#-------------------------------------------------------------------------

#-------------------------------------------------------------------------
120
121
122
123
124
125
126




127
128
129
130
131
132
133
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156







+
+
+
+







      }
    }
  }
  return $ret
}

proc default_njob {} {
  global env
  if {[info exists env(NJOB)] && $env(NJOB)>=1} {
    return $env(NJOB)
  }
  set nCore [guess_number_of_cores]
  if {$nCore<=2} {
    set nHelper 1
  } else {
    set nHelper [expr int($nCore*0.5)]
  }
  return $nHelper
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
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







+
+
+
+
+







+








+






-
+

+







set TRG(timeout) 10000              ;# Default busy-timeout for testrunner.db 
set TRG(nJob)    [default_njob]     ;# Default number of helper processes
set TRG(patternlist) [list]
set TRG(cmdline) $argv
set TRG(reporttime) 2000
set TRG(fuzztest) 0                 ;# is the fuzztest option present.
set TRG(zipvfs) ""                  ;# -zipvfs option, if any
set TRG(buildonly) 0                ;# True if --buildonly option 
set TRG(dryrun) 0                   ;# True if --dryrun option 
set TRG(explain) 0                  ;# True for the --explain option
set TRG(stopOnError) 0              ;# Stop running at first failure
set TRG(stopOnCore) 0               ;# Stop on a core-dump

switch -nocase -glob -- $tcl_platform(os) {
  *darwin* {
    set TRG(platform)    osx
    set TRG(make)        make.sh
    set TRG(makecmd)     "bash make.sh"
    set TRG(testfixture) testfixture
    set TRG(shell)       sqlite3
    set TRG(run)         run.sh
    set TRG(runcmd)      "bash run.sh"
  }
  *linux* {
    set TRG(platform)    linux
    set TRG(make)        make.sh
    set TRG(makecmd)     "bash make.sh"
    set TRG(testfixture) testfixture
    set TRG(shell)       sqlite3
    set TRG(run)         run.sh
    set TRG(runcmd)      "bash run.sh"
  }
  *win* {
    set TRG(platform)    win
    set TRG(make)        make.bat
    set TRG(makecmd)     make.bat
    set TRG(makecmd)     "call make.bat"
    set TRG(testfixture) testfixture.exe
    set TRG(shell)       sqlite3.exe
    set TRG(run)         run.bat
    set TRG(runcmd)      "run.bat"
  }
  default {
    error "cannot determine platform!"
  }
} 
318
319
320
321
322
323
324








325
326
327
328
329
330
331
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370







+
+
+
+
+
+
+
+







  set res [mydb one { SELECT value FROM config WHERE name='njob' }]
  mydb close
  puts "$res"
  exit
}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
# Check if this is the "help" command:
#
if {[string compare -nocase help [lindex $argv 0]]==0} {
  usage
}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
# Check if this is the "script" command:
#
if {[string compare -nocase script [lindex $argv 0]]==0} {
  if {[llength $argv]!=2 && !([llength $argv]==3&&[lindex $argv 1]=="-msvc")} {
    usage
  }
421
422
423
424
425
426
427
428

429










430
431
432
433
434
435
436
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







-
+

+
+
+
+
+
+
+
+
+
+







  if {[string range $a 0 0]=="-"} {
    if {($n>2 && [string match "$a*" --jobs]) || $a=="-j"} {
      incr ii
      set TRG(nJob) [lindex $argv $ii]
      if {$isLast} { usage }
    } elseif {($n>2 && [string match "$a*" --zipvfs]) || $a=="-z"} {
      incr ii
      set TRG(zipvfs) [lindex $argv $ii]
      set TRG(zipvfs) [file normalize [lindex $argv $ii]]
      if {$isLast} { usage }
    } elseif {($n>2 && [string match "$a*" --buildonly]) || $a=="-b"} {
      set TRG(buildonly) 1
    } elseif {($n>2 && [string match "$a*" --dryrun]) || $a=="-d"} {
      set TRG(dryrun) 1
    } elseif {($n>2 && [string match "$a*" --explain]) || $a=="-e"} {
      set TRG(explain) 1
    } elseif {[string match "$a*" --stop-on-error]} {
      set TRG(stopOnError) 1
    } elseif {[string match "$a*" --stop-on-coredump]} {
      set TRG(stopOnCore) 1
    } else {
      usage
    }
  } else {
    lappend TRG(patternlist) [string map {% *} $a]
  }
}
605
606
607
608
609
610
611









612

613
614
615
616
617
618
619
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669

670
671
672
673
674
675
676
677







+
+
+
+
+
+
+
+
+
-
+







      $state
    )
  }

  trdb last_insert_rowid
}

# Argument $build is either an empty string, or else a list of length 3 
# describing the job to build testfixture. In the usual form:
#
#    {ID DIRNAME DISPLAYNAME}
# 
# e.g    
#
#    {1 /home/user/sqlite/test/testrunner_bld_xyz All-Debug}
# 
proc add_tcl_jobs {build config patternlist} {
proc add_tcl_jobs {build config patternlist {shelldepid ""}} {
  global TRG

  set topdir [file dirname $::testdir]
  set testrunner_tcl [file normalize [info script]]

  if {$build==""} {
    set testfixture [info nameofexec]
654
655
656
657
658
659
660



661
662
663
664
665

666
667
668
669
670
671

672
673
674
675






676
677
678
679
680
681
682


683
684
685
686
687
















688
689
690
691
692
693
694
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







+
+
+




-
+

-



-
+




+
+
+
+
+
+






-
+
+





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







    }

    set lProp [trd_test_script_properties $f]
    set priority 0
    if {[lsearch $lProp slow]>=0} { set priority 2 }
    if {[lsearch $lProp superslow]>=0} { set priority 4 }

    set depid [lindex $build 0]
    if {$shelldepid!="" && [lsearch $lProp shell]>=0} { set depid $shelldepid }

    add_job                            \
        -displaytype tcl               \
        -displayname $displayname      \
        -cmd $cmd                      \
        -depid [lindex $build 0]       \
        -depid $depid                  \
        -priority $priority

  }
}

proc add_build_job {buildname target} {
proc add_build_job {buildname target {postcmd ""} {depid ""}} {
  global TRG

  set dirname "[string tolower [string map {- _} $buildname]]_$target"
  set dirname "testrunner_bld_$dirname"

  set cmd "$TRG(makecmd) $target"
  if {$postcmd!=""} {
    append cmd "\n"
    append cmd $postcmd
  }

  set id [add_job                                \
    -displaytype bld                             \
    -displayname "Build $buildname ($target)"    \
    -dirname $dirname                            \
    -build $buildname                            \
    -cmd  "$TRG(makecmd) $target"                \
    -cmd  $cmd                                   \
    -depid $depid                                \
    -priority 3
  ]

  list $id [file normalize $dirname] $buildname
}

proc add_shell_build_job {buildname dirname depid} {
  global TRG

  if {$TRG(platform)=="win"} {
    set path [string map {/ \\} "$dirname/"]
    set copycmd "xcopy $TRG(shell) $path"
  } else {
    set copycmd "cp $TRG(shell) $dirname/"
  }

  return [
    add_build_job $buildname $TRG(shell) $copycmd $depid
  ]
}


proc add_make_job {bld target} {
  global TRG

  if {$TRG(platform)=="win"} {
    set path [string map {/ \\} [lindex $bld 1]]
    set cmd "xcopy /S $path\\* ."
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
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
886
887
888
889
890
891
892
893
894
895
896
897

898



899
900
901
902
903
904

905


906

907
908
909
910
911
912
913
914
915

916
917
918
919





920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946







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
















+








+
+
-
+
-
-
-

+



+
-
+
-
-
+
-

+



+



-
+


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





+
+
+
+
+
+
+

+







        -displayname "Zipvfs [file tail $s]" \
        -cmd $cmd                            \
        -depid [lindex $bld 0]
  }

  set ::env(SQLITE_TEST_DIR) $::testdir
}

# Used to add jobs for "mdevtest" and "sdevtest".
#
proc add_devtest_jobs {lBld patternlist} {
  global TRG

  foreach b $lBld {
    set bld [add_build_job $b $TRG(testfixture)]
    add_tcl_jobs $bld veryquick $patternlist SHELL
    if {$patternlist==""} {
      add_fuzztest_jobs $b
    }

    if {[trdb one "SELECT EXISTS (SELECT 1 FROM jobs WHERE depid='SHELL')"]} {
      set sbld [add_shell_build_job $b [lindex $bld 1] [lindex $bld 0]]
      set sbldid [lindex $sbld 0]
      trdb eval {
        UPDATE jobs SET depid=$sbldid WHERE depid='SHELL'
      }
    }

  }
}

# Check to ensure that the interpreter is a full-blown "testfixture"
# build and not just a "tclsh".  If this is not the case, issue an
# error message and exit.
#
proc must_be_testfixture {} {
  if {[lsearch [info commands] sqlite3_soft_heap_limit]<0} {
    puts "Use testfixture, not tclsh, for these arguments."
    exit 1
  }
}

proc add_jobs_from_cmdline {patternlist} {
  global TRG

  if {$TRG(zipvfs)!=""} {
    add_zipvfs_jobs
    if {[llength $patternlist]==0} return
  }

  if {[llength $patternlist]==0} {
    set patternlist [list veryquick]
  }

  set first [lindex $patternlist 0]
  switch -- $first {
    all {
      must_be_testfixture
      set patternlist [lrange $patternlist 1 end]
      set clist [trd_all_configs]
      foreach c $clist {
        add_tcl_jobs "" $c $patternlist
      }
    }

    mdevtest {
      set config_set {
        All-O0
      foreach b [list All-O0 All-Debug] {
        All-Debug
        set bld [add_build_job $b $TRG(testfixture)]
        add_tcl_jobs $bld veryquick ""
        add_fuzztest_jobs $b
      }
      add_devtest_jobs $config_set [lrange $patternlist 1 end]
    }

    sdevtest {
      set config_set {
      foreach b [list All-Sanitize All-Debug] {
        All-Sanitize
        set bld [add_build_job $b $TRG(testfixture)]
        add_tcl_jobs $bld veryquick ""
        All-Debug
        add_fuzztest_jobs $b
      }
      add_devtest_jobs $config_set [lrange $patternlist 1 end]
    }

    release {
      set patternlist [lrange $patternlist 1 end]
      foreach b [trd_builds $TRG(platform)] {
        set bld [add_build_job $b $TRG(testfixture)]
        foreach c [trd_configs $TRG(platform) $b] {
          add_tcl_jobs $bld $c ""
          add_tcl_jobs $bld $c $patternlist
        }

        if {$patternlist==""} {
        foreach e [trd_extras $TRG(platform) $b] {
          if {$e=="fuzztest"} {
            add_fuzztest_jobs $b
          } else {
            add_make_job $bld $e
          foreach e [trd_extras $TRG(platform) $b] {
            if {$e=="fuzztest"} {
              add_fuzztest_jobs $b
            } else {
              add_make_job $bld $e
            }
          }
        }
      }
    }

    list {
      set allperm [array names ::testspec]
      lappend allperm all mdevtest sdevtest release list
      puts "Allowed values for the PERMUTATION argument: [lsort $allperm]"
      exit 0
    }

    default {
      must_be_testfixture
      if {[info exists ::testspec($first)]} {
        add_tcl_jobs "" $first [lrange $patternlist 1 end]
      } else {
        add_tcl_jobs "" full $patternlist
      }
    }
  }
829
830
831
832
833
834
835











836
837
838
839
840
841
842
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







+
+
+
+
+
+
+
+
+
+
+







    trdb eval { REPLACE INTO config VALUES('cmdline', $cmdline ); }
    trdb eval { REPLACE INTO config VALUES('start', $tm ); }

    add_jobs_from_cmdline $TRG(patternlist)
  }

}

proc mark_job_as_finished {jobid output state endtm} {
  r_write_db {
    trdb eval {
      UPDATE jobs 
        SET output=$output, state=$state, endtime=$endtm
        WHERE jobid=$jobid;
      UPDATE jobs SET state='ready' WHERE depid=$jobid;
    }
  }
}

proc script_input_ready {fd iJob jobid} {
  global TRG
  global O
  global T

  if {[eof $fd]} {
856
857
858
859
860
861
862








863
864
865
866
867
868
869
870
871
872

873
874
875
876
877
878
879
880
881
882
883
884
885
886
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018


1019







1020
1021
1022
1023
1024
1025
1026







+
+
+
+
+
+
+
+








-
-
+
-
-
-
-
-
-
-







    set rc [catch { close $fd } msg]
    if {$rc} { 
      if {[info exists TRG(reportlength)]} {
        puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
      }
      puts "FAILED: $job(displayname) ($iJob)"
      set state "failed" 
      if {$TRG(stopOnError)} {
        puts "OUTPUT: $O($iJob)"
        exit 1
      }
      if {$TRG(stopOnCore) && [string first {core dumped} $O($iJob)]>0} {
        puts "OUTPUT: $O($iJob)"
        exit 1
      }
    }

    set tm [clock_milliseconds]
    set jobtm [expr {$tm - $job(starttime)}]

    puts $TRG(log) "### $job(displayname) ${jobtm}ms ($state)"
    puts $TRG(log) [string trim $O($iJob)]

    r_write_db {
      set output $O($iJob)
    mark_job_as_finished $jobid $O($iJob) $state $tm
      trdb eval {
        UPDATE jobs 
          SET output=$output, state=$state, endtime=$tm
          WHERE jobid=$jobid;
        UPDATE jobs SET state='ready' WHERE depid=$jobid;
      }
    }

    dirs_freeDir $iJob
    launch_some_jobs
    incr ::wakeup
  } else {
    set rc [catch { gets $fd line } res]
    if {$rc} {
924
925
926
927
928
929
930





















931
932
933
934
935
936
937








938
939
940



941
942
943
944
945
946
947
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







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

-
-
+
+
+







      set script [trd_buildscript $job(build) $srcdir $bWin]
    }
    set fd [open [file join $dir $TRG(make)] w]
    puts $fd $script
    close $fd
  }

  # Add a batch/shell file command to set the directory used for temp
  # files to the test's working directory. Otherwise, tests that use
  # large numbers of temp files (e.g. zipvfs), might generate temp 
  # filename collisions.
  if {$TRG(platform)=="win"} {
    set set_tmp_dir "SET SQLITE_TMPDIR=[file normalize $dir]"
  } else {
    set set_tmp_dir "export SQLITE_TMPDIR=\"[file normalize $dir]\""
  }

  if { $TRG(dryrun) } {

    mark_job_as_finished $job(jobid) "" done 0
    dirs_freeDir $iJob
    if {$job(build)!=""} {
      puts $TRG(log) "(cd $dir ; $job(cmd) )"
    } else {
      puts $TRG(log) "$job(cmd)"
    }

  } else {
  set pwd [pwd]
  cd $dir
  set fd [open $TRG(run) w]
  puts $fd $job(cmd) 
  close $fd
  set fd [open "|$TRG(runcmd) 2>@1" r]
  cd $pwd
    set pwd [pwd]
    cd $dir
    set fd [open $TRG(run) w]
    puts $fd $set_tmp_dir
    puts $fd $job(cmd)
    close $fd
    set fd [open "|$TRG(runcmd) 2>@1" r]
    cd $pwd

  fconfigure $fd -blocking false
  fileevent $fd readable [list script_input_ready $fd $iJob $job(jobid)]
    fconfigure $fd -blocking false
    fileevent $fd readable [list script_input_ready $fd $iJob $job(jobid)]
  }

  return 1
}

proc one_line_report {} {
  global TRG

1031
1032
1033
1034
1035
1036
1037

1038



































1039
1040
1041



1042
1043
1044
1045
1046







1047
1048
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








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



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

-
    }
  }

  puts "\nTest database is $TRG(dbname)"
  puts "Test log is $TRG(logname)"
}

# Handle the --buildonly option, if it was specified.

#
proc handle_buildonly {} {
  global TRG
  if {$TRG(buildonly)} {
    r_write_db {
      trdb eval { DELETE FROM jobs WHERE displaytype!='bld' }
    }
  }
}

# Handle the --explain option.  Provide a human-readable
# explanation of all the tests that are in the trdb database jobs
# table.
#
proc explain_layer {indent depid} {
  global TRG
  if {$TRG(buildonly)} {
    set showtests 0
  } else {
    set showtests 1
  }
  trdb eval {SELECT jobid, displayname, displaytype, dirname
               FROM jobs WHERE depid=$depid ORDER BY displayname} {
    if {$displaytype=="bld"} {
      puts "${indent}$displayname in $dirname"
      explain_layer "${indent}   " $jobid
    } elseif {$showtests} {
      puts "${indent}[lindex $displayname end]"
    }
  }
}
proc explain_tests {} {
  explain_layer "" ""
}

sqlite3 trdb $TRG(dbname)
trdb timeout $TRG(timeout)
set tm [lindex [time { make_new_testset }] 0]
if {$TRG(explain)} {
  explain_tests
} else {
if {$TRG(nJob)>1} {
  puts "splitting work across $TRG(nJob) jobs"
}
puts "built testset in [expr $tm/1000]ms.."
run_testset
  if {$TRG(nJob)>1} {
    puts "splitting work across $TRG(nJob) jobs"
  }
  puts "built testset in [expr $tm/1000]ms.."
  handle_buildonly
  run_testset
}
trdb close
#puts [pwd]
Changes to test/testrunner_data.tcl.
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40







-
+







  set tcltest(linux.Sanitize)             veryquick
  set tcltest(linux.Device-One)           all
  set tcltest(linux.Default)              all_plus_autovacuum_crash
  set tcltest(linux.Valgrind)             valgrind

  set tcltest(osx.Locking-Style)          veryquick
  set tcltest(osx.Have-Not)               veryquick
  set tcltest(osx.Apple)                  all
  set tcltest(osx.Apple)                  all_less_no_mutex_try

  set tcltest(win.Stdcall)                veryquick
  set tcltest(win.Have-Not)               veryquick
  set tcltest(win.Windows-Memdebug)       veryquick
  set tcltest(win.Windows-Win32Heap)      veryquick
  set tcltest(win.Windows-Sanitize)       veryquick
  set tcltest(win.Default)                full
96
97
98
99
100
101
102
103

104
105
106
107

108
109
110

111
112
113
114
115
116
117
96
97
98
99
100
101
102

103
104
105
106

107
108
109
110
111
112
113
114
115
116
117
118







-
+



-
+



+







    --enable-debug --enable-all
  }
  set build(All-O0) {
    -O0 --enable-all
  }
  set build(All-Sanitize) { 
    -DSQLITE_OMIT_LOOKASIDE=1
    --enable-all -fsanitize=address,undefined 
    --enable-all -fsanitize=address,undefined -fno-sanitize-recover=undefined
  }

  set build(Sanitize) {
    CC=clang -fsanitize=address,undefined
    CC=clang -fsanitize=address,undefined -fno-sanitize-recover=undefined
    -DSQLITE_ENABLE_STAT4
    -DSQLITE_OMIT_LOOKASIDE=1
    -DCONFIG_SLOWDOWN_FACTOR=5.0
    -DSQLITE_ENABLE_RBU
    --enable-debug
    --enable-all
  }
  set build(Stdcall) {
    -DUSE_STDCALL=1
    -O2
  }
263
264
265
266
267
268
269

270
271
272
273
274
275
276
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278







+







    -DSQLITE_ENABLE_FLOCKTIMEOUT=1
    -DSQLITE_ENABLE_FTS3=1
    -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
    -DSQLITE_ENABLE_FTS3_TOKENIZER=1
    -DSQLITE_ENABLE_PERSIST_WAL=1
    -DSQLITE_ENABLE_PURGEABLE_PCACHE=1
    -DSQLITE_ENABLE_RTREE=1
    -DSQLITE_ENABLE_SETLK_TIMEOUT=2
    -DSQLITE_ENABLE_SNAPSHOT=1
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    -DSQLITE_MAX_LENGTH=2147483645
    -DSQLITE_MAX_VARIABLE_NUMBER=500000
    -DSQLITE_NO_SYNC=1
    -DSQLITE_OMIT_AUTORESET=1
    -DSQLITE_OMIT_LOAD_EXTENSION=1
362
363
364
365
366
367
368



369
370
371
372
373
374
375
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380







+
+
+








  if {[info exists tcltest($platform.$bld)]} {
    set clist $tcltest($platform.$bld)
    if {$clist=="all"} {
      set clist $all_configs
    } elseif {$clist=="all_plus_autovacuum_crash"} {
      set clist [concat $all_configs autovacuum_crash]
    } elseif {$clist=="all_less_no_mutex_try"} {
      set idx [lsearch $all_configs no_mutex_try]
      set clist [lreplace $all_configs $idx $idx]
    }
  }

  set clist
}

proc trd_extras {platform bld} {
590
591
592
593
594
595
596

597





598
599
600
601
602
603
604
595
596
597
598
599
600
601
602

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







+
-
+
+
+
+
+







# use the MSVC compiler, false otherwise.
#
proc trd_buildscript {config srcdir bMsvc} {
  trd_import

  # Ensure that the named configuration exists.
  if {![info exists build($config)]} {
    if {$config!="help"} {
    error "No such build config: $config"
      puts "No such build config: $config"
    }
    puts "Available configurations: [lsort [array names build]]"
    flush stdout
    exit 1
  }

  # Generate and return the script.
  return [make_script $build($config) $srcdir $bMsvc]
}

# Usage:
629
630
631
632
633
634
635
636
639
640
641
642
643
644
645








-
    }
    set trd_test_script_properties_cache($path) $ret
    close $fd
  }

  set trd_test_script_properties_cache($path)
}

Changes to test/tkt-8454a207b9.test.
45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
45
46
47
48
49
50
51

52
53
54
55
56
57
58
59







-
+







  }
} {0 text}
do_test tkt-8454a207b9.4 {
  db eval {
    ALTER TABLE t1 ADD COLUMN e DEFAULT -123.0;
    SELECT e, typeof(e) FROM t1;
  }
} {-123 integer}
} {-123.0 real}
do_test tkt-8454a207b9.5 {
  db eval {
    ALTER TABLE t1 ADD COLUMN f DEFAULT -123.5;
    SELECT f, typeof(f) FROM t1;
  }
} {-123.5 real}
do_test tkt-8454a207b9.6 {
Changes to test/tkt-bd484a090c.test.
26
27
28
29
30
31
32
33

34
35
36
37
38
26
27
28
29
30
31
32

33
34
35
36
37
38







-
+






sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 1

do_test 2.1 {
  catchsql { SELECT datetime('now', 'localtime') }
} {1 {local time unavailable}}
do_test 2.2 {
  catchsql { SELECT datetime('now', 'utc') }
  catchsql { SELECT datetime('2000-01-01', 'utc') }
} {1 {local time unavailable}}

sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0

finish_test
Changes to test/trace3.test.
128
129
130
131
132
133
134


135
136
137
138
139
140
141
142



















143
144
145
146
147
148
149
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







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







    SELECT a, b FROM t1 ORDER BY a;
  }
  set stmt [lindex [lindex $::stmtlist(record) 0] 0]
  set ns [lindex [lindex $::stmtlist(record) 0] 1]
  list $stmt [expr {$ns >= 0 && $ns <= 9999999}]; # less than 0.010 seconds
} {/^-?\d+ 1$/}
do_test trace3-4.4 {
  set cnt 0
  while {1} {
  set ::stmtlist(record) {}
  db trace_v2 trace_v2_record 2
  execsql {
    SELECT a, b FROM t1 ORDER BY a;
  }
  set stmt [lindex [lindex $::stmtlist(record) 0] 0]
  set ns [lindex [lindex $::stmtlist(record) 0] 1]
  list $stmt [expr {$ns >= 0 && $ns <= 9999999}]; # less than 0.010 seconds
    set ::stmtlist(record) {}
    db trace_v2 trace_v2_record 2
    execsql {
      SELECT a, b FROM t1 ORDER BY a;
    }
    set stmt [lindex [lindex $::stmtlist(record) 0] 0]
    set ns [lindex [lindex $::stmtlist(record) 0] 1]
    if {$ns<0 || $ns>9999999} {  #less than 0.010 seconds
      incr cnt
      if {$cnt>3} {
        set res "time out of bounds.  Expected less than 99999999.  Got $ns"
        break
      }
    } else {
      set res 1
      break
    }
  }
  list $stmt $res
} {/^-?\d+ 1$/}

do_test trace3-5.1 {
  set ::stmtlist(record) {}
  db trace_v2 trace_v2_record row
  execsql {
    SELECT a, b FROM t1 ORDER BY a;
Changes to test/types3.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
8
9
10
11
12
13
14


15
16
17
18
19
20
21







-
-







#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The focus
# of this file is testing the interaction of SQLite manifest types
# with Tcl dual-representations.
#
# $Id: types3.test,v 1.8 2008/04/28 13:02:58 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# A variable with only a string representation comes in as TEXT
do_test types3-1.1 {
  set V {}
91
92
93
94
95
96
97
98




























99
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








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

  set V [db one {SELECT '1234567890123456.0'}]
  tcl_variable_type V
} {}
do_test types3-2.6 {
  set V [db one {SELECT NULL}]
  tcl_variable_type V
} {}

# See https://sqlite.org/forum/forumpost/3776b48e71
#
# On a text-affinity comparison of two values where one of
# the values has both MEM_Str and a numeric type like MEM_Int,
# make sure that only the MEM_Str representation is used.
#
sqlite3_create_function db
do_execsql_test types3-3.1 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(x TEXT PRIMARY KEY);
  INSERT INTO t1 VALUES('1');
  SELECT * FROM t1 WHERE NOT x=upper(1);
} {}
do_execsql_test types3-3.2 {
  SELECT * FROM t1 WHERE NOT x=add_text_type(1);
} {}
do_execsql_test types3-3.3 {
  SELECT * FROM t1 WHERE NOT x=add_int_type('1');
} {}
do_execsql_test types3-3.4 {
  DELETE FROM t1;
  INSERT INTO t1 VALUES(1.25);
  SELECT * FROM t1 WHERE NOT x=add_real_type('1.25');
} {}
do_execsql_test types3-3.5 {
  SELECT * FROM t1 WHERE NOT x=add_text_type(1.25);
} {}

finish_test
Changes to test/unionall.test.
342
343
344
345
346
347
348







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







+
+
+
+
+
+
+







} {}
do_execsql_test 5.10 {
  SELECT *, '+' FROM t1 LEFT JOIN t2 ON (a NOT IN(SELECT v FROM t1, t3 WHERE a=k)=NOT EXISTS(SELECT 1 FROM t1 LEFT JOIN t3 ON (a=k)));
} {0 {} {} {} + 1 one {} {} + 2 two {} {} + 5 five {} {} + 3 three {} {} + 6 six {} {} +}
do_execsql_test 5.20 {
  SELECT *, '+' FROM t1 LEFT JOIN t3 ON (a NOT IN(SELECT v FROM t1 LEFT JOIN t2 ON (a=k))=k);
} {0 {} {} {} + 1 one {} {} + 2 two {} {} + 5 five {} {} + 3 three {} {} + 6 six {} {} +}
ifcapable vtab {
do_catchsql_test 5.30 {
  SELECT * FROM (t1 NATURAL JOIN pragma_table_xinfo('t1_a') NATURAL JOIN t3) t1
                NATURAL JOIN t2 NATURAL JOIN t3
   WHERE rowid ISNULL>0 AND 0%y;
} {1 {no such column: rowid}}
}

reset_db
do_execsql_test 6.0 {
  CREATE TABLE t1(a,b);
  INSERT INTO t1 VALUES(1,2);
  CREATE TABLE t2(a,b);
  INSERT INTO t2 VALUES(3,4);
Changes to test/upsert5.test.
403
404
405
406
407
408
409










































410
411
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453







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



do_catchsql_test 2.1 {
  INSERT INTO t2(a,b,c,e,d) VALUES(1,2,3,4,5)
      ON CONFLICT(c) DO UPDATE SET b=''
      ON CONFLICT((SELECT t2 FROM nosuchtable)) DO NOTHING;

} {1 {no such table: nosuchtable}}

# 2024-03-08 https://sqlite.org/forum/forumpost/919c6579c8
# A redundant ON CONFLICT clause in an upsert can lead to
# index corruption.
#
reset_db
do_execsql_test 3.0 {
  CREATE TABLE t1(aa INTEGER PRIMARY KEY, bb INT);
  INSERT INTO t1 VALUES(11,22);
  CREATE UNIQUE INDEX t1bb ON t1(bb);
  REPLACE INTO t1 VALUES(11,33)
    ON CONFLICT(bb) DO UPDATE SET aa = 44
    ON CONFLICT(bb) DO UPDATE SET aa = 44;
  PRAGMA integrity_check;
} {ok}
do_execsql_test 3.1 {
  SELECT * FROM t1 NOT INDEXED;
} {11 33}
do_execsql_test 3.2 {
  SELECT * FROM t1 INDEXED BY t1bb;
} {11 33}
do_execsql_test 3.3 {
  DROP TABLE t1;
  CREATE TABLE t1(aa INTEGER PRIMARY KEY, bb INT, cc INT);
  INSERT INTO t1 VALUES(10,21,32),(11,22,33),(12,23,34);
  CREATE UNIQUE INDEX t1bb ON t1(bb);
  CREATE UNIQUE INDEX t1cc ON t1(cc);
  REPLACE INTO t1 VALUES(11,44,55)
    ON CONFLICT(bb) DO UPDATE SET aa = 99
    ON CONFLICT(cc) DO UPDATE SET aa = 99
    ON CONFLICT(bb) DO UPDATE SET aa = 99;
  PRAGMA integrity_check;
} {ok}
do_execsql_test 3.4 {
  SELECT * FROM t1 NOT INDEXED ORDER BY +aa;
} {10 21 32 11 44 55 12 23 34}
do_execsql_test 3.5 {
  SELECT * FROM t1 INDEXED BY t1bb ORDER BY +aa;
} {10 21 32 11 44 55 12 23 34}
do_execsql_test 3.6 {
  SELECT * FROM t1 INDEXED BY t1cc ORDER BY +aa;
} {10 21 32 11 44 55 12 23 34}

finish_test
Added test/values.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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 March 3
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix values


do_execsql_test 1.0 {
  CREATE TABLE x1(a, b, c);
}


explain_i {
  INSERT INTO x1(a, b, c) VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
}
do_execsql_test 1.1.1 {
  INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
}
do_execsql_test 1.1.2 {
  SELECT * FROM x1;
} {
  1 1 1
  2 2 2
  3 3 3
  4 4 4
}

do_execsql_test 1.2.0 {
  DELETE FROM x1
}
do_execsql_test 1.2.1 {
  INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 4, 4, 4;
  SELECT * FROM x1;
} {1 1 1  2 2 2   3 3 3  4 4 4}

sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 4

do_execsql_test 1.2.2 {
  DELETE FROM x1;
  INSERT INTO x1 
  VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5) 
  UNION ALL SELECT 6, 6, 6;
  SELECT * FROM x1;
} {1 1 1  2 2 2   3 3 3  4 4 4  5 5 5  6 6 6}

do_execsql_test 1.2.3 {
  DELETE FROM x1;
  INSERT INTO x1 
  VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)
  UNION ALL SELECT 6, 6, 6;
  SELECT * FROM x1;
} {1 1 1  2 2 2   3 3 3  4 4 4  6 6 6}

do_execsql_test 1.2.4 {
  DELETE FROM x1;
  INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 6, 6, 6;
  SELECT * FROM x1;
} {
 1 1 1
 2 2 2
 3 3 3
 6 6 6
}

set a 4
set b 5
set c 6
do_execsql_test 1.2.5 {
  DELETE FROM x1;
  INSERT INTO x1 
  VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), 
        (4, 4, $a), (5, 5, $b), (6, 6, $c)
}

do_execsql_test 1.2.6 {
  SELECT * FROM x1;
} {
  1 1 1
  2 2 2
  3 3 3
  4 4 4
  5 5 5
  6 6 6
}

#-------------------------------------------------------------------------
# SQLITE_LIMIT_COMPOUND_SELECT set to 0.
#
reset_db

do_execsql_test 2.0 {
  CREATE TABLE x1(a, b, c);
}

sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 3

do_catchsql_test 2.1.1 {
  INSERT INTO x1 VALUES
      (1, 1, 1), 
      (2, 2, 2), 
      (3, 3, 3), 
      (4, 4, 4), 
      (5, 5, 5), 
      (6, 6, 6), 
      (7, 7, 7), 
      (8, 8, 8), 
      (9, 9, 9), 
      (10, 10, 10, 10)
} {1 {all VALUES must have the same number of terms}}

do_catchsql_test 2.1.2 {
  INSERT INTO x1 VALUES
      (1, 1, 1), 
      (2, 2, 2, 2), 
      (3, 3, 3), 
      (4, 4, 4), 
      (5, 5, 5), 
      (6, 6, 6), 
      (7, 7, 7), 
      (8, 8, 8), 
      (9, 9, 9), 
      (10, 10, 10)
} {1 {all VALUES must have the same number of terms}}

sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 0

do_execsql_test 2.2 {
  INSERT INTO x1 VALUES
      (1, 1, 1), 
      (2, 2, 2), 
      (3, 3, 3), 
      (4, 4, 4), 
      (5, 5, 5), 
      (6, 6, 6), 
      (7, 7, 7), 
      (8, 8, 8), 
      (9, 9, 9), 
      (10, 10, 10)
} {}
do_execsql_test 2.3 {
  INSERT INTO x1 VALUES
      (1, 1, 1), 
      (2, 2, 2), 
      (3, 3, 3), 
      (4, 4, 4), 
      (5, 5, 5), 
      (6, 6, 6), 
      (7, 7, 7), 
      (8, 8, 8), 
      (9, 9, 9), 
      (10, 10, 10)
      UNION ALL 
      SELECT 5, 12, 12
      ORDER BY 1
} {}

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

do_execsql_test 3.0 {
  CREATE TABLE y1(x, y);
}

do_execsql_test 3.1.1 {
  DELETE FROM y1;
  INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 5);
}
do_execsql_test 3.1.2 {
  SELECT * FROM y1;
} {1 2  3 4  1 5}
do_execsql_test 3.2.1 {
  DELETE FROM y1;
  INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 6)
    , (row_number() OVER (), 7)
}
do_execsql_test 3.1.2 {
  SELECT * FROM y1;
} {1 2  3 4  1 6  1 7}

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

do_execsql_test 4.0 {
  CREATE TABLE x1(a PRIMARY KEY, b) WITHOUT ROWID;
}

foreach {tn iLimit} {1 0    2 3} { 
  sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT $iLimit

  do_execsql_test 4.1.1 {
    DELETE FROM x1;
    INSERT INTO x1 VALUES
        (1, 1),
        (2, (SELECT * FROM  (VALUES('a'), ('b'), ('c'), ('d')) ))
  }
  do_execsql_test 4.1.2 {
    SELECT * FROM x1
  } {1 1 2 a}

  do_execsql_test 4.2.1 {
    DELETE FROM x1;
    INSERT INTO x1 VALUES
        (1, 1),
        (2, 2),
        (3, 3),
        (4, 4),
        (5, (SELECT * FROM  (VALUES('a'), ('b'), ('c'), ('d')) ))
  }
  do_execsql_test 4.2.2 {
    SELECT * FROM x1
  } {1 1 2 2 3 3 4 4 5 a}

  do_execsql_test 4.3.1 {
    DELETE FROM x1;
    INSERT INTO x1 VALUES
        (1, (SELECT * FROM  (VALUES('a'), ('b'), ('c'), ('d'), ('e')) ))
  }
  do_execsql_test 4.3.2 {
    SELECT * FROM x1
  } {1 a}
}

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

do_execsql_test 5.0 {
  CREATE VIEW v1 AS VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9);
}
do_execsql_test 5.1 {
  SELECT * FROM v1
} {1 2 3 4 5 6 7 8 9}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
  CREATE TABLE t1(x);
  INSERT INTO t1 VALUES(1), (2);
}

do_execsql_test 6.1 {
  SELECT ( VALUES( x ), ( x ) ) FROM t1;
} {1 2}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
  CREATE TABLE t1(x);
  INSERT INTO t1 VALUES('x'), ('y');
}

do_execsql_test 6.1 {
  SELECT * FROM t1, (VALUES(1), (2))
} {x 1 x 2 y 1 y 2}

do_execsql_test 6.2 {
  VALUES(CAST(44 AS REAL)),(55);
} {44.0 55}

#------------------------------------------------------------------------
do_execsql_test 7.1 {
  WITH x1(a, b) AS (
    VALUES(1, 2), ('a', 'b')
  )
  SELECT * FROM x1 one, x1 two
} {
  1 2  1 2
  1 2  a b
  a b  1 2
  a b  a b
}

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

set VVV {
  ( VALUES('a', 'b'), ('c', 'd'), (123, NULL) )
}
set VVV2 {
  ( 
  SELECT 'a' AS column1, 'b' AS column2 
  UNION ALL SELECT 'c', 'd' UNION ALL SELECT 123, NULL
  )
}

do_execsql_test 8.0 {
  CREATE TABLE t1(x);
  INSERT INTO t1 VALUES('d'), (NULL), (123)
}
foreach {tn q res} {
  1 "SELECT * FROM t1 LEFT JOIN VVV" {
    d a b   d c d   d 123 {}
    {} a b   {} c d   {} 123 {}
    123 a b   123 c d   123 123 {}
  }

  2 "SELECT * FROM t1 LEFT JOIN VVV ON (column1=x)" {
    d {} {}
    {} {} {}
    123 123 {}
  }

  3 "SELECT * FROM t1 RIGHT JOIN VVV" {
    d a b   d c d   d 123 {}
    {} a b   {} c d   {} 123 {}
    123 a b   123 c d   123 123 {}
  }

  4 "SELECT * FROM t1 RIGHT JOIN VVV ON (column1=x)" {
    123 123 {}
    {} a b
    {} c d
  }

  5 "SELECT * FROM t1 FULL OUTER JOIN VVV ON (column1=x)" {
    d {} {}
    {} {} {}
    123 123 {}
    {} a b
    {} c d
  }

  6 "SELECT count(*) FROM VVV" { 3 }

  7 "SELECT (SELECT column1 FROM VVV)" { a }

  8 "SELECT * FROM VVV UNION ALL SELECT * FROM VVV" {
    a b c d 123 {}
    a b c d 123 {}
  }

  9 "SELECT * FROM VVV INTERSECT SELECT * FROM VVV" {
    123 {} a b c d 
  }

  10 "SELECT * FROM VVV eXCEPT SELECT * FROM VVV" { }

  11 "SELECT * FROM VVV eXCEPT SELECT 'a', 'b'" { 123 {} c d }

} {
  set q1 [string map [list VVV $VVV] $q]
  set q2 [string map [list VVV $VVV2] $q]
  set q3 "WITH VVV AS $VVV $q"

  do_execsql_test 8.1.$tn.1 $q1 $res
  do_execsql_test 8.1.$tn.2 $q2 $res
  do_execsql_test 8.1.$tn.3 $q3 $res
}

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

do_execsql_test 9.1 {
  VALUES(456), (123), (NULL) UNION ALL SELECT 122 ORDER BY 1
} { {} 122 123 456 }

do_execsql_test 9.2 {
  VALUES (1, 2), (3, 4), (
    ( SELECT column1 FROM ( VALUES (5, 6), (7, 8) ) ),
    ( SELECT max(column2) FROM ( VALUES (5, 1), (7, 6) ) )
  )
} { 1 2 3 4 5 6 }

do_execsql_test 10.1 {
  CREATE TABLE a2(a, b, c DEFAULT 'xyz');
}
do_execsql_test 10.2 {
  INSERT INTO a2(a) VALUES(3),(4);
}

#-------------------------------------------------------------------------
reset_db
ifcapable fts5 {
  do_execsql_test 11.0 {
    CREATE VIRTUAL TABLE ft USING fts3(x);
  }
  do_execsql_test 11.1 {
    INSERT INTO ft VALUES('one'), ('two');
  }
}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 12.0 {
  CREATE TABLE t1(a, b);
}
do_execsql_test 12.1 {
  INSERT INTO t1 SELECT 1, 2 UNION ALL VALUES(3, 4), (5, 6);
}
do_execsql_test 12.2 {
  SELECT * FROM t1
} {1 2 3 4 5 6}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 13.0 {
  CREATE TABLE t1(x);
  INSERT INTO t1 VALUES('xyz');

  SELECT (
      VALUES( (max(substr('abc', 1, 1), x)) ),
      (123),
      (456)
      )
  FROM t1;
} {xyz}

do_catchsql_test 13.1 {
  VALUES(300), (zeroblob(300) OVER win);
} {1 {zeroblob() may not be used as a window function}}

#--------------------------------------------------------------------------
reset_db
do_execsql_test 14.1 {
  PRAGMA encoding = utf16;
  CREATE TABLE t1(a, b);
} {}

db close
sqlite3 db test.db

do_execsql_test 14.2 {
  INSERT INTO t1 VALUES
    (17, 'craft'),
    (16, 'urtlek' IN(1,2,3));
}

#--------------------------------------------------------------------------
#
reset_db
do_eqp_test 15.1 {
  VALUES(1),(2),(3),(4),(5);
} {
  QUERY PLAN
  `--SCAN 5-ROW VALUES CLAUSE
}
do_execsql_test 15.2 {
  CREATE TABLE t1(a,b);
}
do_eqp_test 15.3 {
  INSERT INTO t1 VALUES
    (1,2),(3,4),(7,8);
} {
  QUERY PLAN
  `--SCAN 3-ROW VALUES CLAUSE
}
do_eqp_test 15.4 {
  INSERT INTO t1 VALUES
    (1,2),(3,4),(7,8),
    (5,row_number()OVER());
} {
  QUERY PLAN
  `--COMPOUND QUERY
     |--LEFT-MOST SUBQUERY
     |  `--SCAN 3-ROW VALUES CLAUSE
     `--UNION ALL
        |--CO-ROUTINE (subquery-xxxxxx)
        |  `--SCAN CONSTANT ROW
        `--SCAN (subquery-xxxxxx)
}
do_eqp_test 15.5 {
  SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6)), (VALUES('a'),('b'),('c'));
} {
  QUERY PLAN
  |--SCAN 6-ROW VALUES CLAUSE
  `--SCAN 3-ROW VALUES CLAUSE
}
do_execsql_test 15.6 {
  CREATE TABLE t2(x,y);
}
do_eqp_test 15.7 {
  SELECT * FROM t2 UNION ALL VALUES(1,2),(3,4),(5,6),(7,8);
} {
  QUERY PLAN
  `--COMPOUND QUERY
     |--LEFT-MOST SUBQUERY
     |  `--SCAN t2
     `--UNION ALL
        `--SCAN 4-ROW VALUES CLAUSE
}

#--------------------------------------------------------------------------
# The VALUES-as-coroutine optimization can be applied to later rows of
# a VALUES clause even if earlier rows do not qualify.
#
reset_db
do_execsql_test 16.1 {
  CREATE TABLE t1(a,b);
}
do_execsql_test 16.2 {
  BEGIN;
  INSERT INTO t1 VALUES(1,2),(3,4),(5,6),
     (7,row_number()OVER()),
     (9,10), (11,12), (13,14), (15,16);
  SELECT * FROM t1 ORDER BY a, b;
  ROLLBACK;
} {1 2 3 4 5 6 7 1 9 10 11 12 13 14 15 16}
do_eqp_test 16.3 {
  INSERT INTO t1 VALUES(1,2),(3,4),(5,6),
     (7,row_number()OVER()),
     (9,10), (11,12), (13,14), (15,16);
} {
  QUERY PLAN
  `--COMPOUND QUERY
     |--LEFT-MOST SUBQUERY
     |  `--SCAN 3-ROW VALUES CLAUSE
     |--UNION ALL
     |  |--CO-ROUTINE (subquery-xxxxxx)
     |  |  `--SCAN CONSTANT ROW
     |  `--SCAN (subquery-xxxxxx)
     `--UNION ALL
        `--SCAN 4-ROW VALUES CLAUSE
}
do_execsql_test 16.4 {
  BEGIN;
  INSERT INTO t1 VALUES
     (1,row_number()OVER()),
     (2,3), (4,5), (6,7);
  SELECT * FROM t1 ORDER BY a, b;
  ROLLBACK;
} {1 1 2 3 4 5 6 7}
do_eqp_test 16.5 {
  INSERT INTO t1 VALUES
     (1,row_number()OVER()),
     (2,3), (4,5), (6,7);
} {
  QUERY PLAN
  `--COMPOUND QUERY
     |--LEFT-MOST SUBQUERY
     |  |--CO-ROUTINE (subquery-xxxxxx)
     |  |  `--SCAN CONSTANT ROW
     |  `--SCAN (subquery-xxxxxx)
     `--UNION ALL
        `--SCAN 3-ROW VALUES CLAUSE
}
do_execsql_test 16.6 {
  BEGIN;
  INSERT INTO t1 VALUES
     (1,2),(3,4),
     (5,row_number()OVER()),
     (7,8),(9,10),(11,12),
     (13,row_number()OVER()),
     (15,16),(17,18),(19,20),(21,22);
  SELECT * FROM t1 ORDER BY a, b;
  ROLLBACK;
} { 1 2 3 4 5 1 7 8 9 10 11 12 13 1 15 16 17 18 19 20 21 22}
do_eqp_test 16.7 {
  INSERT INTO t1 VALUES
     (1,2),(3,4),
     (5,row_number()OVER()),
     (7,8),(9,10),(11,12),
     (13,row_number()OVER()),
     (15,16),(17,18),(19,20),(21,22);
} {
  QUERY PLAN
  `--COMPOUND QUERY
     |--LEFT-MOST SUBQUERY
     |  `--SCAN 2-ROW VALUES CLAUSE
     |--UNION ALL
     |  |--CO-ROUTINE (subquery-xxxxxx)
     |  |  `--SCAN CONSTANT ROW
     |  `--SCAN (subquery-xxxxxx)
     |--UNION ALL
     |  `--SCAN 3-ROW VALUES CLAUSE
     |--UNION ALL
     |  |--CO-ROUTINE (subquery-xxxxxx)
     |  |  `--SCAN CONSTANT ROW
     |  `--SCAN (subquery-xxxxxx)
     `--UNION ALL
        `--SCAN 4-ROW VALUES CLAUSE
}

finish_test
Added test/valuesfault.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024 March 3
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix valuesfault
source $testdir/malloc_common.tcl


do_execsql_test 1.0 {
  CREATE TABLE x1(a, b, c);
}
faultsim_save_and_close

do_faultsim_test 1 -prep {
  faultsim_restore_and_reopen
  sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 2
} -body {
  execsql {
    INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
  }
} -test {
  faultsim_test_result {0 {}} 
}


finish_test
Deleted test/wapp.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# Copyright (c) 2017 D. Richard Hipp
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Simplified BSD License (also
# known as the "2-Clause License" or "FreeBSD License".)
#
# This program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose.
#
#---------------------------------------------------------------------------
#
# Design rules:
#
#   (1)  All identifiers in the global namespace begin with "wapp"
#
#   (2)  Indentifiers intended for internal use only begin with "wappInt"
#
package require Tcl 8.6

# Add text to the end of the HTTP reply.  No interpretation or transformation
# of the text is performs.  The argument should be enclosed within {...}
#
proc wapp {txt} {
  global wapp
  dict append wapp .reply $txt
}

# Add text to the page under construction.  Do no escaping on the text.
#
# Though "unsafe" in general, there are uses for this kind of thing.
# For example, if you want to return the complete, unmodified content of
# a file:
#
#         set fd [open content.html rb]
#         wapp-unsafe [read $fd]
#         close $fd
#
# You could do the same thing using ordinary "wapp" instead of "wapp-unsafe".
# The difference is that wapp-safety-check will complain about the misuse
# of "wapp", but it assumes that the person who write "wapp-unsafe" understands
# the risks.
#
# Though occasionally necessary, the use of this interface should be minimized.
#
proc wapp-unsafe {txt} {
  global wapp
  dict append wapp .reply $txt
}

# Add text to the end of the reply under construction.  The following
# substitutions are made:
#
#     %html(...)          Escape text for inclusion in HTML
#     %url(...)           Escape text for use as a URL
#     %qp(...)            Escape text for use as a URI query parameter
#     %string(...)        Escape text for use within a JSON string
#     %unsafe(...)        No transformations of the text
#
# The substitutions above terminate at the first ")" character.  If the
# text of the TCL string in ... contains ")" characters itself, use instead:
#
#     %html%(...)%
#     %url%(...)%
#     %qp%(...)%
#     %string%(...)%
#     %unsafe%(...)%
#
# In other words, use "%(...)%" instead of "(...)" to include the TCL string
# to substitute.
#
# The %unsafe substitution should be avoided whenever possible, obviously.
# In addition to the substitutions above, the text also does backslash
# escapes.
#
# The wapp-trim proc works the same as wapp-subst except that it also removes
# whitespace from the left margin, so that the generated HTML/CSS/Javascript
# does not appear to be indented when delivered to the client web browser.
#
if {$tcl_version>=8.7} {
  proc wapp-subst {txt} {
    global wapp
    regsub -all -command \
       {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt
    dict append wapp .reply [subst -novariables -nocommand $txt]
  }
  proc wapp-trim {txt} {
    global wapp
    regsub -all {\n\s+} [string trim $txt] \n txt
    regsub -all -command \
       {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt
    dict append wapp .reply [subst -novariables -nocommand $txt]
  }
  proc wappInt-enc {all mode nu1 txt} {
    return [uplevel 2 "wappInt-enc-$mode \"$txt\""]
  }
} else {
  proc wapp-subst {txt} {
    global wapp
    regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \
           {[wappInt-enc-\1 "\3"]} txt
    dict append wapp .reply [uplevel 1 [list subst -novariables $txt]]
  }
  proc wapp-trim {txt} {
    global wapp
    regsub -all {\n\s+} [string trim $txt] \n txt
    regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \
           {[wappInt-enc-\1 "\3"]} txt
    dict append wapp .reply [uplevel 1 [list subst -novariables $txt]]
  }
}

# There must be a wappInt-enc-NAME routine for each possible substitution
# in wapp-subst.  Thus there are routines for "html", "url", "qp", and "unsafe".
#
#    wappInt-enc-html           Escape text so that it is safe to use in the
#                               body of an HTML document.
#
#    wappInt-enc-url            Escape text so that it is safe to pass as an
#                               argument to href= and src= attributes in HTML.
#
#    wappInt-enc-qp             Escape text so that it is safe to use as the
#                               value of a query parameter in a URL or in
#                               post data or in a cookie.
#
#    wappInt-enc-string         Escape ", ', \, and < for using inside of a
#                               javascript string literal.  The < character
#                               is escaped to prevent "</script>" from causing
#                               problems in embedded javascript.
#
#    wappInt-enc-unsafe         Perform no encoding at all.  Unsafe.
#
proc wappInt-enc-html {txt} {
  return [string map {& &amp; < &lt; > &gt; \" &quot; \\ &#92;} $txt]
}
proc wappInt-enc-unsafe {txt} {
  return $txt
}
proc wappInt-enc-url {s} {
  if {[regsub -all {[^-{}@~?=#_.:/a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} {
    set s [subst -novar -noback $s]
  }
  if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} {
    set s [subst -novar -noback $s]
  }
  return $s
}
proc wappInt-enc-qp {s} {
  if {[regsub -all {[^-{}_.a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} {
    set s [subst -novar -noback $s]
  }
  if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} {
    set s [subst -novar -noback $s]
  }
  return $s
}
proc wappInt-enc-string {s} {
  return [string map {\\ \\\\ \" \\\" ' \\' < \\u003c} $s]
}

# This is a helper routine for wappInt-enc-url and wappInt-enc-qp.  It returns
# an appropriate %HH encoding for the single character c.  If c is a unicode
# character, then this routine might return multiple bytes:  %HH%HH%HH
#
proc wappInt-%HHchar {c} {
  if {$c==" "} {return +}
  return [regsub -all .. [binary encode hex [encoding convertto utf-8 $c]] {%&}]
}


# Undo the www-url-encoded format.
#
# HT: This code stolen from ncgi.tcl
#
proc wappInt-decode-url {str} {
  set str [string map [list + { } "\\" "\\\\" \[ \\\[ \] \\\]] $str]
  regsub -all -- \
      {%([Ee][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \
      $str {[encoding convertfrom utf-8 [binary decode hex \1\2\3]]} str
  regsub -all -- \
      {%([CDcd][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])}                     \
      $str {[encoding convertfrom utf-8 [binary decode hex \1\2]]} str
  regsub -all -- {%([0-7][A-Fa-f0-9])} $str {\\u00\1} str
  return [subst -novar $str]
}

# Reset the document back to an empty string.
#
proc wapp-reset {} {
  global wapp
  dict set wapp .reply {}
}

# Change the mime-type of the result document.
#
proc wapp-mimetype {x} {
  global wapp
  dict set wapp .mimetype $x
}

# Change the reply code.
#
proc wapp-reply-code {x} {
  global wapp
  dict set wapp .reply-code $x
}

# Set a cookie
#
proc wapp-set-cookie {name value} {
  global wapp
  dict lappend wapp .new-cookies $name $value
}

# Unset a cookie
#
proc wapp-clear-cookie {name} {
  wapp-set-cookie $name {}
}

# Add extra entries to the reply header
#
proc wapp-reply-extra {name value} {
  global wapp
  dict lappend wapp .reply-extra $name $value
}

# Specifies how the web-page under construction should be cached.
# The argument should be one of:
#
#    no-cache
#    max-age=N             (for some integer number of seconds, N)
#    private,max-age=N
#
proc wapp-cache-control {x} {
  wapp-reply-extra Cache-Control $x
}

# Redirect to a different web page
#
proc wapp-redirect {uri} {
  wapp-reply-code {307 Redirect}
  wapp-reply-extra Location $uri
}

# Return the value of a wapp parameter
#
proc wapp-param {name {dflt {}}} {
  global wapp
  if {![dict exists $wapp $name]} {return $dflt}
  return [dict get $wapp $name]
}

# Return true if a and only if the wapp parameter $name exists
#
proc wapp-param-exists {name} {
  global wapp
  return [dict exists $wapp $name]
}

# Set the value of a wapp parameter
#
proc wapp-set-param {name value} {
  global wapp
  dict set wapp $name $value
}

# Return all parameter names that match the GLOB pattern, or all
# names if the GLOB pattern is omitted.
#
proc wapp-param-list {{glob {*}}} {
  global wapp
  return [dict keys $wapp $glob]
}

# By default, Wapp does not decode query parameters and POST parameters
# for cross-origin requests.  This is a security restriction, designed to
# help prevent cross-site request forgery (CSRF) attacks.
#
# As a consequence of this restriction, URLs for sites generated by Wapp
# that contain query parameters will not work as URLs found in other
# websites.  You cannot create a link from a second website into a Wapp
# website if the link contains query planner, by default.
#
# Of course, it is sometimes desirable to allow query parameters on external
# links.  For URLs for which this is safe, the application should invoke
# wapp-allow-xorigin-params.  This procedure tells Wapp that it is safe to
# go ahead and decode the query parameters even for cross-site requests.
#
# In other words, for Wapp security is the default setting.  Individual pages
# need to actively disable the cross-site request security if those pages
# are safe for cross-site access.
#
proc wapp-allow-xorigin-params {} {
  global wapp
  if {![dict exists $wapp .qp] && ![dict get $wapp SAME_ORIGIN]} {
    wappInt-decode-query-params
  }
}

# Set the content-security-policy.
#
# The default content-security-policy is very strict:  "default-src 'self'"
# The default policy prohibits the use of in-line javascript or CSS.
#
# Provide an alternative CSP as the argument.  Or use "off" to disable
# the CSP completely.
#
proc wapp-content-security-policy {val} {
  global wapp
  if {$val=="off"} {
    dict unset wapp .csp
  } else {
    dict set wapp .csp $val
  }
}

# Examine the bodys of all procedures in this program looking for
# unsafe calls to various Wapp interfaces.  Return a text string
# containing warnings. Return an empty string if all is ok.
#
# This routine is advisory only.  It misses some constructs that are
# dangerous and flags others that are safe.
#
proc wapp-safety-check {} {
  set res {}
  foreach p [info procs] {
    set ln 0
    foreach x [split [info body $p] \n] {
      incr ln
      if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail]
       && [string index $tail 0]!="\173"
       && [regexp {[[$]} $tail]
      } {
        append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n"
      }
      if {[regexp {^[ \t]*wapp-(subst|trim)[ \t]+[^\173]} $x all cx]} {
        append res "$p:$ln: unsafe \"wapp-$cx\" call: \"[string trim $x]\"\n"
      }
    }
  }
  return $res
}

# Return a string that descripts the current environment.  Applications
# might find this useful for debugging.
#
proc wapp-debug-env {} {
  global wapp
  set out {}
  foreach var [lsort [dict keys $wapp]] {
    if {[string index $var 0]=="."} continue
    append out "$var = [list [dict get $wapp $var]]\n"
  }
  append out "\[pwd\] = [list [pwd]]\n"
  return $out
}

# Tracing function for each HTTP request.  This is overridden by wapp-start
# if tracing is enabled.
#
proc wappInt-trace {} {}

# Start up a listening socket.  Arrange to invoke wappInt-new-connection
# for each inbound HTTP connection.
#
#    port            Listen on this TCP port.  0 means to select a port
#                    that is not currently in use
#
#    wappmode        One of "scgi", "remote-scgi", "server", or "local".
#
#    fromip          If not {}, then reject all requests from IP addresses
#                    other than $fromip
#
proc wappInt-start-listener {port wappmode fromip} {
  if {[string match *scgi $wappmode]} {
    set type SCGI
    set server [list wappInt-new-connection \
                wappInt-scgi-readable $wappmode $fromip]
  } else {
    set type HTTP
    set server [list wappInt-new-connection \
                wappInt-http-readable $wappmode $fromip]
  }
  if {$wappmode=="local" || $wappmode=="scgi"} {
    set x [socket -server $server -myaddr 127.0.0.1 $port]
  } else {
    set x [socket -server $server $port]
  }
  set coninfo [chan configure $x -sockname]
  set port [lindex $coninfo 2]
  if {$wappmode=="local"} {
    wappInt-start-browser http://127.0.0.1:$port/
  } elseif {$fromip!=""} {
    puts "Listening for $type requests on TCP port $port from IP $fromip"
  } else {
    puts "Listening for $type requests on TCP port $port"
  }
}

# Start a web-browser and point it at $URL
#
proc wappInt-start-browser {url} {
  global tcl_platform
  if {$tcl_platform(platform)=="windows"} {
    exec cmd /c start $url &
  } elseif {$tcl_platform(os)=="Darwin"} {
    exec open $url &
  } elseif {[catch {exec xdg-open $url}]} {
    exec firefox $url &
  }
}

# This routine is a "socket -server" callback.  The $chan, $ip, and $port
# arguments are added by the socket command.
#
# Arrange to invoke $callback when content is available on the new socket.
# The $callback will process inbound HTTP or SCGI content.  Reject the
# request if $fromip is not an empty string and does not match $ip.
#
proc wappInt-new-connection {callback wappmode fromip chan ip port} {
  upvar #0 wappInt-$chan W
  if {$fromip!="" && ![string match $fromip $ip]} {
    close $chan
    return
  }
  set W [dict create REMOTE_ADDR $ip REMOTE_PORT $port WAPP_MODE $wappmode \
         .header {}]
  fconfigure $chan -blocking 0 -translation binary
  fileevent $chan readable [list $callback $chan]
}

# Close an input channel
#
proc wappInt-close-channel {chan} {
  if {$chan=="stdout"} {
    # This happens after completing a CGI request
    exit 0
  } else {
    unset ::wappInt-$chan
    close $chan
  }
}

# Process new text received on an inbound HTTP request
#
proc wappInt-http-readable {chan} {
  if {[catch [list wappInt-http-readable-unsafe $chan] msg]} {
    puts stderr "$msg\n$::errorInfo"
    wappInt-close-channel $chan
  }
}
proc wappInt-http-readable-unsafe {chan} {
  upvar #0 wappInt-$chan W wapp wapp
  if {![dict exists $W .toread]} {
    # If the .toread key is not set, that means we are still reading
    # the header
    set line [string trimright [gets $chan]]
    set n [string length $line]
    if {$n>0} {
      if {[dict get $W .header]=="" || [regexp {^\s+} $line]} {
        dict append W .header $line
      } else {
        dict append W .header \n$line
      }
      if {[string length [dict get $W .header]]>100000} {
        error "HTTP request header too big - possible DOS attack"
      }
    } elseif {$n==0} {
      # We have reached the blank line that terminates the header.
      global argv0
      set a0 [file normalize $argv0]
      dict set W SCRIPT_FILENAME $a0
      dict set W DOCUMENT_ROOT [file dir $a0]
      if {[wappInt-parse-header $chan]} {
        catch {close $chan}
        return
      }
      set len 0
      if {[dict exists $W CONTENT_LENGTH]} {
        set len [dict get $W CONTENT_LENGTH]
      }
      if {$len>0} {
        # Still need to read the query content
        dict set W .toread $len
      } else {
        # There is no query content, so handle the request immediately
        set wapp $W
        wappInt-handle-request $chan 0
      }
    }
  } else {
    # If .toread is set, that means we are reading the query content.
    # Continue reading until .toread reaches zero.
    set got [read $chan [dict get $W .toread]]
    dict append W CONTENT $got
    dict set W .toread [expr {[dict get $W .toread]-[string length $got]}]
    if {[dict get $W .toread]<=0} {
      # Handle the request as soon as all the query content is received
      set wapp $W
      wappInt-handle-request $chan 0
    }
  }
}

# Decode the HTTP request header.
#
# This routine is always running inside of a [catch], so if
# any problems arise, simply raise an error.
#
proc wappInt-parse-header {chan} {
  upvar #0 wappInt-$chan W
  set hdr [split [dict get $W .header] \n]
  if {$hdr==""} {return 1}
  set req [lindex $hdr 0]
  dict set W REQUEST_METHOD [set method [lindex $req 0]]
  if {[lsearch {GET HEAD POST} $method]<0} {
    error "unsupported request method: \"[dict get $W REQUEST_METHOD]\""
  }
  set uri [lindex $req 1]
  set split_uri [split $uri ?]
  set uri0 [lindex $split_uri 0]
  if {![regexp {^/[-.a-z0-9_/]*$} $uri0]} {
    error "invalid request uri: \"$uri0\""
  }
  dict set W REQUEST_URI $uri0
  dict set W PATH_INFO $uri0
  set uri1 [lindex $split_uri 1]
  dict set W QUERY_STRING $uri1
  set n [llength $hdr]
  for {set i 1} {$i<$n} {incr i} {
    set x [lindex $hdr $i]
    if {![regexp {^(.+): +(.*)$} $x all name value]} {
      error "invalid header line: \"$x\""
    }
    set name [string toupper $name]
    switch -- $name {
      REFERER {set name HTTP_REFERER}
      USER-AGENT {set name HTTP_USER_AGENT}
      CONTENT-LENGTH {set name CONTENT_LENGTH}
      CONTENT-TYPE {set name CONTENT_TYPE}
      HOST {set name HTTP_HOST}
      COOKIE {set name HTTP_COOKIE}
      ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING}
      default {set name .hdr:$name}
    }
    dict set W $name $value
  }
  return 0
}

# Decode the QUERY_STRING parameters from a GET request or the
# application/x-www-form-urlencoded CONTENT from a POST request.
#
# This routine sets the ".qp" element of the ::wapp dict as a signal
# that query parameters have already been decoded.
#
proc wappInt-decode-query-params {} {
  global wapp
  dict set wapp .qp 1
  if {[dict exists $wapp QUERY_STRING]} {
    foreach qterm [split [dict get $wapp QUERY_STRING] &] {
      set qsplit [split $qterm =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][a-z0-9]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }
  if {[dict exists $wapp CONTENT_TYPE] && [dict exists $wapp CONTENT]} {
    set ctype [dict get $wapp CONTENT_TYPE]
    if {$ctype=="application/x-www-form-urlencoded"} {
      foreach qterm [split [string trim [dict get $wapp CONTENT]] &] {
        set qsplit [split $qterm =]
        set nm [lindex $qsplit 0]
        if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
          dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
        }
      }
    } elseif {[string match multipart/form-data* $ctype]} {
      regexp {^(.*?)\r\n(.*)$} [dict get $wapp CONTENT] all divider body
      set ndiv [string length $divider]
      while {[string length $body]} {
        set idx [string first $divider $body]
        set unit [string range $body 0 [expr {$idx-3}]]
        set body [string range $body [expr {$idx+$ndiv+2}] end]
        if {[regexp {^Content-Disposition: form-data; (.*?)\r\n\r\n(.*)$} \
             $unit unit hdr content]} {
          if {[regexp {name="(.*)"; filename="(.*)"\r\nContent-Type: (.*?)$}\
                $hdr hr name filename mimetype]} {
            dict set wapp $name.filename \
              [string map [list \\\" \" \\\\ \\] $filename]
            dict set wapp $name.mimetype $mimetype
            dict set wapp $name.content $content
          } elseif {[regexp {name="(.*)"} $hdr hr name]} {
            dict set wapp $name $content
          }
        }
      }
    }
  }
}

# Invoke application-supplied methods to generate a reply to
# a single HTTP request.
#
# This routine always runs within [catch], so handle exceptions by
# invoking [error].
#
proc wappInt-handle-request {chan useCgi} {
  global wapp
  dict set wapp .reply {}
  dict set wapp .mimetype {text/html; charset=utf-8}
  dict set wapp .reply-code {200 Ok}
  dict set wapp .csp {default-src 'self'}

  # Set up additional CGI environment values
  #
  if {![dict exists $wapp HTTP_HOST]} {
    dict set wapp BASE_URL {}
  } elseif {[dict exists $wapp HTTPS]} {
    dict set wapp BASE_URL https://[dict get $wapp HTTP_HOST]
  } else {
    dict set wapp BASE_URL http://[dict get $wapp HTTP_HOST]
  }
  if {![dict exists $wapp REQUEST_URI]} {
    dict set wapp REQUEST_URI /
  } elseif {[regsub {\?.*} [dict get $wapp REQUEST_URI] {} newR]} {
    # Some servers (ex: nginx) append the query parameters to REQUEST_URI.
    # These need to be stripped off
    dict set wapp REQUEST_URI $newR
  }
  if {[dict exists $wapp SCRIPT_NAME]} {
    dict append wapp BASE_URL [dict get $wapp SCRIPT_NAME]
  } else {
    dict set wapp SCRIPT_NAME {}
  }
  if {![dict exists $wapp PATH_INFO]} {
    # If PATH_INFO is missing (ex: nginx) then construct it
    set URI [dict get $wapp REQUEST_URI]
    set skip [string length [dict get $wapp SCRIPT_NAME]]
    dict set wapp PATH_INFO [string range $URI $skip end]
  }
  if {[regexp {^/([^/]+)(.*)$} [dict get $wapp PATH_INFO] all head tail]} {
    dict set wapp PATH_HEAD $head
    dict set wapp PATH_TAIL [string trimleft $tail /]
  } else {
    dict set wapp PATH_INFO {}
    dict set wapp PATH_HEAD {}
    dict set wapp PATH_TAIL {}
  }
  dict set wapp SELF_URL [dict get $wapp BASE_URL]/[dict get $wapp PATH_HEAD]

  # Parse query parameters from the query string, the cookies, and
  # POST data
  #
  if {[dict exists $wapp HTTP_COOKIE]} {
    foreach qterm [split [dict get $wapp HTTP_COOKIE] {;}] {
      set qsplit [split [string trim $qterm] =]
      set nm [lindex $qsplit 0]
      if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
        dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
      }
    }
  }
  set same_origin 0
  if {[dict exists $wapp HTTP_REFERER]} {
    set referer [dict get $wapp HTTP_REFERER]
    set base [dict get $wapp BASE_URL]
    if {$referer==$base || [string match $base/* $referer]} {
      set same_origin 1
    }
  }
  dict set wapp SAME_ORIGIN $same_origin
  if {$same_origin} {
    wappInt-decode-query-params
  }

  # Invoke the application-defined handler procedure for this page
  # request.  If an error occurs while running that procedure, generate
  # an HTTP reply that contains the error message.
  #
  wapp-before-dispatch-hook
  wappInt-trace
  set mname [dict get $wapp PATH_HEAD]
  if {[catch {
    if {$mname!="" && [llength [info proc wapp-page-$mname]]>0} {
      wapp-page-$mname
    } else {
      wapp-default
    }
  } msg]} {
    if {[wapp-param WAPP_MODE]=="local" || [wapp-param WAPP_MODE]=="server"} {
      puts "ERROR: $::errorInfo"
    }
    wapp-reset
    wapp-reply-code "500 Internal Server Error"
    wapp-mimetype text/html
    wapp-trim {
      <h1>Wapp Application Error</h1>
      <pre>%html($::errorInfo)</pre>
    }
    dict unset wapp .new-cookies
  }

  # Transmit the HTTP reply
  #
  if {$chan=="stdout"} {
    puts $chan "Status: [dict get $wapp .reply-code]\r"
  } else {
    puts $chan "HTTP/1.1 [dict get $wapp .reply-code]\r"
    puts $chan "Server: wapp\r"
    puts $chan "Connection: close\r"
  }
  if {[dict exists $wapp .reply-extra]} {
    foreach {name value} [dict get $wapp .reply-extra] {
      puts $chan "$name: $value\r"
    }
  }
  if {[dict exists $wapp .csp]} {
    puts $chan "Content-Security-Policy: [dict get $wapp .csp]\r"
  }
  set mimetype [dict get $wapp .mimetype]
  puts $chan "Content-Type: $mimetype\r"
  if {[dict exists $wapp .new-cookies]} {
    foreach {nm val} [dict get $wapp .new-cookies] {
      if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
        if {$val==""} {
          puts $chan "Set-Cookie: $nm=; HttpOnly; Path=/; Max-Age=1\r"
        } else {
          set val [wappInt-enc-url $val]
          puts $chan "Set-Cookie: $nm=$val; HttpOnly; Path=/\r"
        }
      }
    }
  }
  if {[string match text/* $mimetype]} {
    set reply [encoding convertto utf-8 [dict get $wapp .reply]]
    if {[regexp {\ygzip\y} [wapp-param HTTP_ACCEPT_ENCODING]]} {
      catch {
        set x [zlib gzip $reply]
        set reply $x
        puts $chan "Content-Encoding: gzip\r"
      }
    }
  } else {
    set reply [dict get $wapp .reply]
  }
  puts $chan "Content-Length: [string length $reply]\r"
  puts $chan \r
  puts -nonewline $chan $reply
  flush $chan
  wappInt-close-channel $chan
}

# This routine runs just prior to request-handler dispatch.  The
# default implementation is a no-op, but applications can override
# to do additional transformations or checks.
#
proc wapp-before-dispatch-hook {} {return}

# Process a single CGI request
#
proc wappInt-handle-cgi-request {} {
  global wapp env
  foreach key {
    CONTENT_LENGTH
    CONTENT_TYPE
    DOCUMENT_ROOT
    HTTP_ACCEPT_ENCODING
    HTTP_COOKIE
    HTTP_HOST
    HTTP_REFERER
    HTTP_USER_AGENT
    HTTPS
    PATH_INFO
    QUERY_STRING
    REMOTE_ADDR
    REQUEST_METHOD
    REQUEST_URI
    REMOTE_USER
    SCRIPT_FILENAME
    SCRIPT_NAME
    SERVER_NAME
    SERVER_PORT
    SERVER_PROTOCOL
  } {
    if {[info exists env($key)]} {
      dict set wapp $key $env($key)
    }
  }
  set len 0
  if {[dict exists $wapp CONTENT_LENGTH]} {
    set len [dict get $wapp CONTENT_LENGTH]
  }
  if {$len>0} {
    fconfigure stdin -translation binary
    dict set wapp CONTENT [read stdin $len]
  }
  dict set wapp WAPP_MODE cgi
  fconfigure stdout -translation binary
  wappInt-handle-request stdout 1
}

# Process new text received on an inbound SCGI request
#
proc wappInt-scgi-readable {chan} {
  if {[catch [list wappInt-scgi-readable-unsafe $chan] msg]} {
    puts stderr "$msg\n$::errorInfo"
    wappInt-close-channel $chan
  }
}
proc wappInt-scgi-readable-unsafe {chan} {
  upvar #0 wappInt-$chan W wapp wapp
  if {![dict exists $W .toread]} {
    # If the .toread key is not set, that means we are still reading
    # the header.
    #
    # An SGI header is short.  This implementation assumes the entire
    # header is available all at once.
    #
    dict set W .remove_addr [dict get $W REMOTE_ADDR]
    set req [read $chan 15]
    set n [string length $req]
    scan $req %d:%s len hdr
    incr len [string length "$len:,"]
    append hdr [read $chan [expr {$len-15}]]
    foreach {nm val} [split $hdr \000] {
      if {$nm==","} break
      dict set W $nm $val
    }
    set len 0
    if {[dict exists $W CONTENT_LENGTH]} {
      set len [dict get $W CONTENT_LENGTH]
    }
    if {$len>0} {
      # Still need to read the query content
      dict set W .toread $len
    } else {
      # There is no query content, so handle the request immediately
      dict set W SERVER_ADDR [dict get $W .remove_addr]
      set wapp $W
      wappInt-handle-request $chan 0
    }
  } else {
    # If .toread is set, that means we are reading the query content.
    # Continue reading until .toread reaches zero.
    set got [read $chan [dict get $W .toread]]
    dict append W CONTENT $got
    dict set W .toread [expr {[dict get $W .toread]-[string length $got]}]
    if {[dict get $W .toread]<=0} {
      # Handle the request as soon as all the query content is received
      dict set W SERVER_ADDR [dict get $W .remove_addr]
      set wapp $W
      wappInt-handle-request $chan 0
    }
  }
}

# Start up the wapp framework.  Parameters are a list passed as the
# single argument.
#
#    -server $PORT         Listen for HTTP requests on this TCP port $PORT
#
#    -local $PORT          Listen for HTTP requests on 127.0.0.1:$PORT
#
#    -scgi $PORT           Listen for SCGI requests on 127.0.0.1:$PORT
#
#    -remote-scgi $PORT    Listen for SCGI requests on TCP port $PORT
#
#    -cgi                  Handle a single CGI request
#
# With no arguments, the behavior is called "auto".  In "auto" mode,
# if the GATEWAY_INTERFACE environment variable indicates CGI, then run
# as CGI.  Otherwise, start an HTTP server bound to the loopback address
# only, on an arbitrary TCP port, and automatically launch a web browser
# on that TCP port.
#
# Additional options:
#
#    -fromip GLOB         Reject any incoming request where the remote
#                         IP address does not match the GLOB pattern.  This
#                         value defaults to '127.0.0.1' for -local and -scgi.
#
#    -nowait              Do not wait in the event loop.  Return immediately
#                         after all event handlers are established.
#
#    -trace               "puts" each request URL as it is handled, for
#                         debugging
#
#    -lint                Run wapp-safety-check on the application instead
#                         of running the application itself
#
#    -Dvar=value          Set TCL global variable "var" to "value"
#
#
proc wapp-start {arglist} {
  global env
  set mode auto
  set port 0
  set nowait 0
  set fromip {}
  set n [llength $arglist]
  for {set i 0} {$i<$n} {incr i} {
    set term [lindex $arglist $i]
    if {[string match --* $term]} {set term [string range $term 1 end]}
    switch -glob -- $term {
      -server {
        incr i;
        set mode "server"
        set port [lindex $arglist $i]
      }
      -local {
        incr i;
        set mode "local"
        set fromip 127.0.0.1
        set port [lindex $arglist $i]
      }
      -scgi {
        incr i;
        set mode "scgi"
        set fromip 127.0.0.1
        set port [lindex $arglist $i]
      }
      -remote-scgi {
        incr i;
        set mode "remote-scgi"
        set port [lindex $arglist $i]
      }
      -cgi {
        set mode "cgi"
      }
      -fromip {
        incr i
        set fromip [lindex $arglist $i]
      }
      -nowait {
        set nowait 1
      }
      -trace {
        proc wappInt-trace {} {
          set q [wapp-param QUERY_STRING]
          set uri [wapp-param BASE_URL][wapp-param PATH_INFO]
          if {$q!=""} {append uri ?$q}
          puts $uri
        }
      }
      -lint {
        set res [wapp-safety-check]
        if {$res!=""} {
          puts "Potential problems in this code:"
          puts $res
          exit 1
        } else {
          exit
        }
      }
      -D*=* {
        if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} {
          set ::$var $val
        }
      }
      default {
        error "unknown option: $term"
      }
    }
  }
  if {$mode=="auto"} {
    if {[info exists env(GATEWAY_INTERFACE)]
        && [string match CGI/1.* $env(GATEWAY_INTERFACE)]} {
      set mode cgi
    } else {
      set mode local
    }
  }
  if {$mode=="cgi"} {
    wappInt-handle-cgi-request
  } else {
    wappInt-start-listener $port $mode $fromip
    if {!$nowait} {
      vwait ::forever
    }
  }
}

# Call this version 1.0
package provide wapp 1.0
Deleted test/wapptest.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909













































































































































































































































































































































































































































































































































































































































































































































































































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
#!/bin/sh
# \
exec wapptclsh "$0" ${1+"$@"}

# package required wapp
source [file join [file dirname [info script]] wapp.tcl]

# Variables set by the "control" form:
#
#   G(platform) - User selected platform.
#   G(cfgglob)  - Glob pattern that all configurations must match
#   G(test)     - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only".
#   G(keep)     - Boolean. True to delete no files after each test.
#   G(msvc)     - Boolean. True to use MSVC as the compiler.
#   G(tcl)      - Use Tcl from this directory for builds.
#   G(jobs)     - How many sub-processes to run simultaneously.
#
set G(platform) $::tcl_platform(os)-$::tcl_platform(machine)
set G(cfgglob)  *
set G(test)     Normal
set G(keep)     1
set G(msvc)     0
set G(tcl)      [::tcl::pkgconfig get libdir,install]
set G(jobs)     3
set G(debug)    0

set G(noui)     0
set G(stdout)   0


proc wapptest_init {} {
  global G

  set lSave [list platform test keep msvc tcl jobs debug noui stdout cfgglob] 
  foreach k $lSave { set A($k) $G($k) }
  array unset G
  foreach k $lSave { set G($k) $A($k) }

  # The root of the SQLite source tree.
  set G(srcdir)   [file dirname [file dirname [info script]]]

  set G(sqlite_version) "unknown"

  # Either "config", "running" or "stopped":
  set G(state) "config"

  set G(hostname) "(unknown host)"
  catch { set G(hostname) [exec hostname] } 
  set G(host) $G(hostname)
  append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)"
  append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)"
}

proc wapptest_run {} {
  global G
  set_test_array
  set G(state) "running"

  wapptest_openlog

  wapptest_output "Running the following for $G(platform). $G(jobs) jobs."
  foreach t $G(test_array) {
    set config [dict get $t config]
    set target [dict get $t target]
    wapptest_output [format "    %-25s%s" $config $target]
  }
  wapptest_output [string repeat * 70]
}

proc releasetest_data {args} {
  global G
  set rtd [file join $G(srcdir) test releasetest_data.tcl]
  set fd [open "|[info nameofexecutable] $rtd $args" r+]
  set ret [read $fd]
  close $fd
  return $ret
}

# Generate the text for the box at the top of the UI. The current SQLite
# version, according to fossil, along with a warning if there are 
# uncommitted changes in the checkout.
#
proc generate_fossil_info {} {
  global G
  set pwd [pwd]
  cd $G(srcdir)
  set rc [catch {
    set r1 [exec fossil info]
    set r2 [exec fossil changes]
  }]
  cd $pwd
  if {$rc} return

  foreach line [split $r1 "\n"] {
    if {[regexp {^checkout: *(.*)$} $line -> co]} {
      wapp-trim { <br> %html($co) }
    }
  }

  if {[string trim $r2]!=""} {
    wapp-trim { 
      <br><span class=warning> 
      WARNING: Uncommitted changes in checkout
      </span>
    }
  }
}

# If the application is in "config" state, set the contents of the 
# ::G(test_array) global to reflect the tests that will be run. If the
# app is in some other state ("running" or "stopped"), this command
# is a no-op.
#
proc set_test_array {} {
  global G
  if { $G(state)=="config" } {
    set G(test_array) [list]
    set debug "-debug"
    if {$G(debug)==0} { set debug "-nodebug"}
    foreach {config target} [releasetest_data tests $debug $G(platform)] {

      # All configuration names must match $g(cfgglob), which defaults to *
      #
      if {![string match -nocase $G(cfgglob) $config]} continue

      # If using MSVC, do not run sanitize or valgrind tests. Or the
      # checksymbols test.
      if {$G(msvc) && (
          "Sanitize" == $config 
       || "checksymbols" in $target
       || "valgrindtest" in $target
      )} {
        continue
      }

      # If the test mode is not "Normal", override the target.
      #
      if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} {
        switch -- $G(test) {
          Veryquick { set target quicktest }
          Smoketest { set target smoketest }
          Build-Only {
            set target testfixture
            if {$::tcl_platform(platform)=="windows"} {
              set target testfixture.exe
            }
          }
        }
      }

      lappend G(test_array) [dict create config $config target $target]
    }
  }
}

proc count_tests_and_errors {name logfile} {
  global G

  set fd [open $logfile rb]
  set seen 0
  while {![eof $fd]} {
    set line [gets $fd]
    if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
      incr G(test.$name.nError) $nerr
      incr G(test.$name.nTest) $ntest
      set seen 1
      if {$nerr>0} {
        set G(test.$name.errmsg) $line
      }
    }
    if {[regexp {runtime error: +(.*)} $line all msg]} {
      # skip over "value is outside range" errors
      if {[regexp {.* is outside the range of representable} $line]} {
         # noop
      } else {
        incr G(test.$name.nError)
        if {$G(test.$name.errmsg)==""} {
          set G(test.$name.errmsg) $msg
        }
      }
    }
    if {[regexp {fatal error +(.*)} $line all msg]} {
      incr G(test.$name.nError)
      if {$G(test.$name.errmsg)==""} {
        set G(test.$name.errmsg) $msg
      }
    }
    if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} {
      incr G(test.$name.nError)
      if {$G(test.$name.errmsg)==""} {
        set G(test.$name.errmsg) $all
      }
    }
    if {[regexp {^VERSION: 3\.\d+.\d+} $line]} {
      set v [string range $line 9 end]
      if {$G(sqlite_version) eq "unknown"} {
        set G(sqlite_version) $v
      } elseif {$G(sqlite_version) ne $v} {
        set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}"
      }
    }
  }
  close $fd
  if {$G(test) == "Build-Only"} {
    incr G(test.$name.nTest)
    if {$G(test.$name.nError)>0} {
      set errmsg "Build failed"
    }
  } elseif {!$seen} {
    set G(test.$name.errmsg) "Test did not complete"
    if {[file readable core]} {
      append G(test.$name.errmsg) " - core file exists"
    }
  }
}

proc wapptest_output {str} {
  global G
  if {$G(stdout)} { puts $str }
  if {[info exists G(log)]} { 
    puts $G(log) $str 
    flush $G(log)
  }
}
proc wapptest_openlog {} {
  global G
  set G(log) [open wapptest-out.txt w+]
}
proc wapptest_closelog {} {
  global G
  close $G(log)
  unset G(log)
}

proc format_seconds {seconds} {
  set min [format %.2d [expr ($seconds / 60) % 60]]
  set  hr [format %.2d [expr $seconds / 3600]]
  set sec [format %.2d [expr $seconds % 60]]
  return "$hr:$min:$sec"
}

# This command is invoked once a slave process has finished running its
# tests, successfully or otherwise. Parameter $name is the name of the 
# test, $rc the exit code returned by the slave process.
#
proc slave_test_done {name rc} {
  global G
  set G(test.$name.done) [clock seconds]
  set G(test.$name.nError) 0
  set G(test.$name.nTest) 0
  set G(test.$name.errmsg) ""
  if {$rc} {
    incr G(test.$name.nError)
  }
  if {[file exists $G(test.$name.log)]} {
    count_tests_and_errors $name $G(test.$name.log)
  }

  # If the "keep files" checkbox is clear, delete all files except for
  # the executables and test logs. And any core file that is present.
  if {$G(keep)==0} {
    set keeplist {
      testfixture testfixture.exe
      sqlite3 sqlite3.exe
      test.log test-out.txt
      core
      wapptest_make.sh
      wapptest_configure.sh
      wapptest_run.tcl
    }
    foreach f [glob -nocomplain [file join $G(test.$name.dir) *]] {
      set t [file tail $f]
      if {[lsearch $keeplist $t]<0} {
        catch { file delete -force $f }
      }
    }
  }

  # Format a message regarding the success or failure of hte test.
  set t [format_seconds [expr $G(test.$name.done) - $G(test.$name.start)]]
  set res "OK"
  if {$G(test.$name.nError)} { set res "FAILED" }
  set dots [string repeat . [expr 60 - [string length $name]]]
  set msg "$name $dots $res ($t)"

  wapptest_output $msg
  if {[info exists G(test.$name.errmsg)] && $G(test.$name.errmsg)!=""} {
    wapptest_output "    $G(test.$name.errmsg)"
  }
}

# This is a fileevent callback invoked each time a file-descriptor that
# connects this process to a slave process is readable.
#
proc slave_fileevent {name} {
  global G
  set fd $G(test.$name.channel)

  if {[eof $fd]} {
    fconfigure $fd -blocking 1
    set rc [catch { close $fd }]
    unset G(test.$name.channel)
    slave_test_done $name $rc
  } else {
    set line [gets $fd]
    if {[string trim $line] != ""} { puts "Trace   : $name - \"$line\"" }
  }

  do_some_stuff
}

# Return the contents of the "slave script" - the script run by slave 
# processes to actually perform the test. All it does is execute the
# test script already written to disk (wapptest_cmd.sh or wapptest_cmd.bat).
#
proc wapptest_slave_script {} {
  global G
  if {$G(msvc)==0} {
    set dir [file join .. $G(srcdir)]
    set res [subst -nocommands {
      set rc [catch "exec sh wapptest_cmd.sh {$dir} >>& test.log" ]
      exit [set rc]
    }]
  } else {
    set dir [file nativename [file normalize $G(srcdir)]]
    set dir [string map [list "\\" "\\\\"] $dir]
    set res [subst -nocommands {
      set rc [catch "exec wapptest_cmd.bat {$dir} >>& test.log" ]
      exit [set rc]
    }]
  }

  set res
}


# Launch a slave process to run a test.
#
proc slave_launch {name target dir} {
  global G

  catch { file mkdir $dir } msg
  foreach f [glob -nocomplain [file join $dir *]] {
    catch { file delete -force $f }
  }
  set G(test.$name.dir) $dir

  # Write the test command to wapptest_cmd.sh|bat.
  #
  set ext sh
  if {$G(msvc)} { set ext bat }
  set fd1 [open [file join $dir wapptest_cmd.$ext] w]
  if {$G(msvc)} {
    puts $fd1 [releasetest_data script -msvc $name $target]
  } else {
    puts $fd1 [releasetest_data script $name $target]
  }
  close $fd1

  # Write the wapptest_run.tcl script to the test directory. To run the
  # commands in the other two files.
  #
  set fd3 [open [file join $dir wapptest_run.tcl] w]
  puts $fd3 [wapptest_slave_script]
  close $fd3

  set pwd [pwd]
  cd $dir
  set fd [open "|[info nameofexecutable] wapptest_run.tcl" r+]
  cd $pwd

  set G(test.$name.channel) $fd
  fconfigure $fd -blocking 0
  fileevent $fd readable [list slave_fileevent $name]
}

proc do_some_stuff {} {
  global G

  # Count the number of running jobs. A running job has an entry named
  # "channel" in its dictionary.
  set nRunning 0
  set bFinished 1
  foreach j $G(test_array) {
    set name [dict get $j config]
    if { [info exists G(test.$name.channel)]} { incr nRunning   }
    if {![info exists G(test.$name.done)]}    { set bFinished 0 }
  }

  if {$bFinished} {
    set nError 0
    set nTest 0
    set nConfig 0
    foreach j $G(test_array) {
      set name [dict get $j config]
      incr nError $G(test.$name.nError)
      incr nTest $G(test.$name.nTest)
      incr nConfig 
    }
    set G(result) "$nError errors from $nTest tests in $nConfig configurations."
    wapptest_output [string repeat * 70]
    wapptest_output $G(result)
    catch {
      append G(result) " SQLite version $G(sqlite_version)"
      wapptest_output " SQLite version $G(sqlite_version)"
    }
    set G(state) "stopped"
    wapptest_closelog
    if {$G(noui)} { exit 0 }
  } else {
    set nLaunch [expr $G(jobs) - $nRunning]
    foreach j $G(test_array) {
      if {$nLaunch<=0} break
      set name [dict get $j config]
      if { ![info exists G(test.$name.channel)]
        && ![info exists G(test.$name.done)]
      } {

        set target [dict get $j target]
        set dir [string tolower [string map {" " _ "-" _} $name]]
        set G(test.$name.start) [clock seconds]
        set G(test.$name.log) [file join $dir test.log]

        slave_launch $name $target $dir

        incr nLaunch -1
      }
    }
  }
}

proc generate_select_widget {label id lOpt opt} {
  wapp-trim {
    <label> %string($label) </label>
    <select id=%string($id) name=%string($id)>
  }
  foreach o $lOpt {
    set selected ""
    if {$o==$opt} { set selected " selected=1" }
    wapp-subst "<option $selected>$o</option>"
  }
  wapp-trim { </select> }
}

proc generate_main_page {{extra {}}} {
  global G
  set_test_array

  set hostname $G(hostname)
  wapp-trim {
    <html>
    <head>
      <title> %html($hostname): wapptest.tcl </title>
      <link rel="stylesheet" type="text/css" href="style.css"/>
    </head>
    <body>
  }

  set host $G(host)
  wapp-trim {
    <div class="border">%string($host)
  }
  generate_fossil_info
  wapp-trim {
    </div>
    <div class="border" id=controls> 
    <form action="control" method="post" name="control">
  }

  # Build the "platform" select widget. 
  set lOpt [releasetest_data platforms]
  generate_select_widget Platform control_platform $lOpt $G(platform)

  # Build the "test" select widget. 
  set lOpt [list Normal Veryquick Smoketest Build-Only] 
  generate_select_widget Test control_test $lOpt $G(test)

  # Build the "jobs" select widget. Options are 1 to 8.
  generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8 12 16} $G(jobs)

  switch $G(state) {
    config {
      set txt "Run Tests!"
      set id control_run
    }
    running {
      set txt "STOP Tests!"
      set id control_stop
    }
    stopped {
      set txt "Reset!"
      set id control_reset
    }
  }
  wapp-trim {
    <div class=right>
    <input id=%string($id) name=%string($id) type=submit value="%string($txt)">
    </input>
    </div>
  }

  wapp-trim {
  <br><br>
        <label> Tcl: </label>
        <input id="control_tcl" name="control_tcl"></input>
        <label> Keep files: </label>
        <input id="control_keep" name="control_keep" type=checkbox value=1>
        </input>
        <label> Use MSVC: </label>
        <input id="control_msvc" name="control_msvc" type=checkbox value=1>
        <label> Debug tests: </label>
        <input id="control_debug" name="control_debug" type=checkbox value=1>
        </input>
  }
  wapp-trim {
     </form>
  }
  wapp-trim {
     </div>
     <div id=tests>
  }
  wapp-page-tests

  set script "script/$G(state).js"
  wapp-trim {
    </div>
      <script src=%string($script)></script>
    </body>
    </html>
  }
}

proc wapp-default {} {
  generate_main_page
}

proc wapp-page-tests {} {
  global G
  wapp-trim { <table class="border" width=100%> }
  foreach t $G(test_array) {
    set config [dict get $t config]
    set target [dict get $t target]

    set class "testwait"
    set seconds ""

    if {[info exists G(test.$config.log)]} {
      if {[info exists G(test.$config.channel)]} {
        set class "testrunning"
        set seconds [expr [clock seconds] - $G(test.$config.start)]
      } elseif {[info exists G(test.$config.done)]} {
        if {$G(test.$config.nError)>0} {
          set class "testfail" 
        } else {
          set class "testdone"
        }
        set seconds [expr $G(test.$config.done) - $G(test.$config.start)]
      }
      set seconds [format_seconds $seconds]
    }

    wapp-trim {
      <tr class=%string($class)>
      <td class="nowrap"> %html($config) 
      <td class="padleft nowrap"> %html($target)
      <td class="padleft nowrap"> %html($seconds)
      <td class="padleft nowrap">
    }
    if {[info exists G(test.$config.log)]} {
      set log $G(test.$config.log)
      set uri "log/$log"
      wapp-trim {
        <a href=%url($uri)> %html($log) </a>
      }
    }
    if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} {
      set errmsg $G(test.$config.errmsg)
      wapp-trim {
        <tr class=testfail>
        <td> <td class="padleft" colspan=3> %html($errmsg)
      }
    }
  }

  wapp-trim { </table> }

  if {[info exists G(result)]} {
    set res $G(result)
    wapp-trim {
      <div class=border id=result> %string($res) </div>
    }
  }
}

# URI: /control
#
# Whenever the form at the top of the application page is submitted, it
# is submitted here.
#
proc wapp-page-control {} {
  global G
  if {$::G(state)=="config"} {
    set lControls [list platform test tcl jobs keep msvc debug]
    set G(msvc) 0
    set G(keep) 0
    set G(debug) 0
  } else {
    set lControls [list jobs]
  }
  foreach v $lControls {
    if {[wapp-param-exists control_$v]} {
      set G($v) [wapp-param control_$v]
    }
  }

  if {[wapp-param-exists control_run]} {
    # This is a "run test" command.
    wapptest_run
  }

  if {[wapp-param-exists control_stop]} {
    # A "STOP tests" command.
    set G(state) "stopped"
    set G(result) "Test halted by user"
    foreach j $G(test_array) {
      set name [dict get $j config]
      if { [info exists G(test.$name.channel)] } {
        close $G(test.$name.channel)
        unset G(test.$name.channel)
        slave_test_done $name 1
      }
    }
    wapptest_closelog
  }

  if {[wapp-param-exists control_reset]} {
    # A "reset app" command.
    set G(state) "config"
    wapptest_init
  }

  if {$::G(state) == "running"} {
    do_some_stuff
  }
  wapp-redirect /
}

# URI: /style.css
#
# Return the stylesheet for the application main page.
#
proc wapp-page-style.css {} {
  wapp-subst {

    /* The boxes with black borders use this class */
    .border {
      border: 3px groove #444444;
      padding: 1em;
      margin-top: 1em;
      margin-bottom: 1em;
    }

    /* Float to the right (used for the Run/Stop/Reset button) */
    .right { float: right; }

    /* Style for the large red warning at the top of the page */
    .warning {
      color: red;
      font-weight: bold;
    }

    /* Styles used by cells in the test table */
    .padleft { padding-left: 5ex; }
    .nowrap  { white-space: nowrap; }

    /* Styles for individual tests, depending on the outcome */
    .testwait    {              }
    .testrunning { color: blue  }
    .testdone    { color: green }
    .testfail    { color: red   }
  }
}

# URI: /script/${state}.js
#
# The last part of this URI is always "config.js", "running.js" or 
# "stopped.js", depending on the state of the application. It returns
# the javascript part of the front-end for the requested state to the
# browser.
#
proc wapp-page-script {} {
  regexp {[^/]*$} [wapp-param REQUEST_URI] script

  set tcl $::G(tcl)
  set keep $::G(keep)
  set msvc $::G(msvc)
  set debug $::G(debug)
  
  wapp-subst {
    var lElem = \["control_platform", "control_test", "control_msvc", 
        "control_jobs", "control_debug"
    \];
    lElem.forEach(function(e) {
      var elem = document.getElementById(e);
      elem.addEventListener("change", function() { control.submit() } );
    })

    elem = document.getElementById("control_tcl");
    elem.value = "%string($tcl)"

    elem = document.getElementById("control_keep");
    elem.checked = %string($keep);

    elem = document.getElementById("control_msvc");
    elem.checked = %string($msvc);

    elem = document.getElementById("control_debug");
    elem.checked = %string($debug);
  }

  if {$script != "config.js"} {
    wapp-subst {
      var lElem = \["control_platform", "control_test", 
          "control_tcl", "control_keep", "control_msvc", 
          "control_debug"
      \];
      lElem.forEach(function(e) {
        var elem = document.getElementById(e);
        elem.disabled = true;
      })
    }
  }

  if {$script == "running.js"} {
    wapp-subst {
      function reload_tests() {
        fetch('tests')
          .then( data => data.text() )
          .then( data => {
            document.getElementById("tests").innerHTML = data;
          })
          .then( data => {
            if( document.getElementById("result") ){
              document.location = document.location;
            } else {
              setTimeout(reload_tests, 1000)
            }
          });
      }

      setTimeout(reload_tests, 1000)
    }
  }
}

# URI: /env
#
# This is for debugging only. Serves no other purpose.
#
proc wapp-page-env {} {
  wapp-allow-xorigin-params
  wapp-trim {
    <h1>Wapp Environment</h1>\n<pre>
    <pre>%html([wapp-debug-env])</pre>
  }
}

# URI: /log/dirname/test.log
#
# This URI reads file "dirname/test.log" from disk, wraps it in a <pre>
# block, and returns it to the browser. Use for viewing log files.
#
proc wapp-page-log {} {
  set log [string range [wapp-param REQUEST_URI] 5 end]
  set fd [open $log]
  set data [read $fd]
  close $fd
  wapp-trim {
    <pre>
    %html($data)
    </pre>
  }
}

# Print out a usage message. Then do [exit 1].
#
proc wapptest_usage {} {
  puts stderr {
This Tcl script is used to test various configurations of SQLite. By
default it uses "wapp" to provide an interactive interface. Supported 
command line options (all optional) are:

    --platform    PLATFORM         (which tests to run)
    --config      GLOB             (only run configurations matching GLOB)
    --smoketest                    (run "make smoketest" only)
    --veryquick                    (run veryquick.test only)
    --buildonly                    (build executables, do not run tests)
    --jobs        N                (number of concurrent jobs)
    --tcl         DIR              (where to find tclConfig.sh)
    --deletefiles                  (delete extra files after each test)
    --msvc                         (Use MS Visual C)
    --debug                        (Also run [n]debugging versions of tests)
    --noui                         (do not use wapp)
  }
  exit 1
}

# Sort command line arguments into two groups: those that belong to wapp,
# and those that belong to the application.
set WAPPARG(-server)      1
set WAPPARG(-local)       1
set WAPPARG(-scgi)        1
set WAPPARG(-remote-scgi) 1
set WAPPARG(-fromip)      1
set WAPPARG(-nowait)      0
set WAPPARG(-cgi)         0
set lWappArg [list]
set lTestArg [list]
for {set i 0} {$i < [llength $argv]} {incr i} {
  set arg [lindex $argv $i]
  if {[string range $arg 0 1]=="--"} {
    set arg [string range $arg 1 end]
  }
  if {[info exists WAPPARG($arg)]} {
    lappend lWappArg $arg
    if {$WAPPARG($arg)} {
      incr i
      lappend lWappArg [lindex $argv $i]
    }
  } else {
    lappend lTestArg $arg
  }
}

wapptest_init
for {set i 0} {$i < [llength $lTestArg]} {incr i} {
  set opt [lindex $lTestArg $i]
  if {[string range $opt 0 1]=="--"} {
    set opt [string range $opt 1 end]
  }
  switch -- $opt {
    -platform {
      if {$i==[llength $lTestArg]-1} { wapptest_usage }
      incr i
      set arg [lindex $lTestArg $i]
      set lPlatform [releasetest_data platforms]
      if {[lsearch $lPlatform $arg]<0} {
        puts stderr "No such platform: $arg. Platforms are: $lPlatform"
        exit -1
      }
      set G(platform) $arg
    }

    -smoketest { set G(test) Smoketest }
    -veryquick { set G(test) Veryquick }
    -buildonly { set G(test) Build-Only }
    -jobs {
      if {$i==[llength $lTestArg]-1} { wapptest_usage }
      incr i
      set G(jobs) [lindex $lTestArg $i]
    }

    -tcl {
      if {$i==[llength $lTestArg]-1} { wapptest_usage }
      incr i
      set G(tcl) [lindex $lTestArg $i]
    }

    -deletefiles {
      set G(keep) 0
    }

    -msvc {
      set G(msvc) 1
    }

    -debug {
      set G(debug) 1
    }

    -noui {
      set G(noui) 1
      set G(stdout) 1
    }

    -config {
      if {$i==[llength $lTestArg]-1} { wapptest_usage }
      incr i
      set G(cfgglob) [lindex $lTestArg $i]
    }

    -stdout {
      set G(stdout) 1
    }

    default {
      puts stderr "Unrecognized option: [lindex $lTestArg $i]"
      wapptest_usage
    }
  }
}

if {$G(noui)==0} {
  wapp-start $lWappArg
} else {
  wapptest_run
  do_some_stuff
  vwait forever
}
Changes to test/where3.test.
487
488
489
490
491
492
493






















494
495
496
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







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



  do_execsql_test where3-7.$disabled_opt.8 {
    SELECT x3 FROM t73 LEFT JOIN t74 ON x4=y3;
  } {123 123}
  do_execsql_test where3-7.$disabled_opt.9 {
    SELECT DISTINCT x3 FROM t73 LEFT JOIN t74 ON x4=y3;
  } {123}
}

# 2023-12-23
# https://sqlite.org/forum/forumpost/2568d1f6e6
#
# Index usage should be "x=? and y=?" - equality on both values.
# Not: "x=? AND y>?" - inequality on "y"
# 
reset_db
do_execsql_test where3-8.1 {
  CREATE TABLE t1(a,b,c,d);  INSERT INTO t1 VALUES(1,2,3,4);
  CREATE TABLE t2(x,y);      INSERT INTO t2 VALUES(3,4);
  CREATE INDEX t2xy ON t2(x,y);
  SELECT 1 FROM t1 JOIN t2 ON x=c AND y=d WHERE d>0;
} 1
do_eqp_test where3-8.2 {
  SELECT 1 FROM t1 JOIN t2 ON x=c AND y=d WHERE d>0;
} {
  QUERY PLAN
  |--SCAN t1
  `--SEARCH t2 USING COVERING INDEX t2xy (x=? AND y=?)
}



finish_test
Changes to test/whereG.test.
307
308
309
310
311
312
313














314
315
316
317
318
319
320
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







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







} {0 0 0}
do_execsql_test 8.9 {
  SELECT * FROM t0 WHERE unlikely(t0.rowid <= '0');
} {}
do_execsql_test 8.10 {
  SELECT * FROM t0 WHERE likelihood(t0.rowid <= '0', 0.5);
} {}
# Forum https://sqlite.org/forum/forumpost/45ec3d9788
reset_db
do_execsql_test 8.11 {
  CREATE TABLE t1(c0 INT);
  INSERT INTO t1(c0) VALUES (NULL);
  CREATE INDEX i46 ON t1(CAST( (c0 IS TRUE) AS TEXT));
  CREATE VIEW v0(c2) AS SELECT CAST( (c0 IS TRUE) AS TEXT ) FROM t1;
}
do_execsql_test 8.12 {
  SELECT quote(c0), quote(c2) FROM t1, v0 WHERE  (0 < LIKELY(v0.c2));
} {NULL '0'} 
do_execsql_test 8.13 {
  SELECT quote(c0), quote(c2) FROM t1, v0 WHERE  (0 < LIKELY(v0.c2)) IS TRUE;
} {NULL '0'}

# 2019-12-31: assertion fault discovered by Yongheng's fuzzer.
# Harmless memIsValid() due to the code generators failure to
# release the registers used by OP_ResultRow.
#
do_execsql_test 9.10 {
  DROP TABLE IF EXISTS t1;
Changes to test/whereL.test.
45
46
47
48
49
50
51



























52
53
54
55
56
57
58
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







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







  ORDER BY t1.a;
} {
  QUERY PLAN
  |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
  |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
  `--SCAN t3
}
do_eqp_test 121 {
  SELECT * FROM t1, t2, t3
   WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=abs(5)
  ORDER BY t1.a;
} {
  QUERY PLAN
  |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
  |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
  `--SCAN t3
}

# The sqlite3ExprIsConstant() routine does not believe that
# the expression "coalesce(5,random())" is constant.  So the
# optimization does not apply in this case.
# 
sqlite3_create_function db
do_eqp_test 122 {
  SELECT * FROM t1, t2, t3
   WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=coalesce(5,random())
  ORDER BY t1.a;
} {
  QUERY PLAN
  |--SCAN t3
  |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
  |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
  `--USE TEMP B-TREE FOR ORDER BY
}

# Constant propagation in the face of collating sequences:
#
do_execsql_test 200 {
  CREATE TABLE c3(x COLLATE binary, y COLLATE nocase, z COLLATE binary);
  CREATE INDEX c3x ON c3(x);
  INSERT INTO c3 VALUES('ABC', 'ABC', 'abc');
204
205
206
207
208
209
210
211


















212
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








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

} 1
do_eqp_test 710 {
  SELECT v FROM t1 WHERE abs(v)=1 and v=1;
} {
  QUERY PLAN
  `--SEARCH t1 USING INDEX idx (<expr>=?)
}

# 2024-03-07 https://sqlite.org/forum/forumpost/ecdfc02339
# A refinement is needed to the enhancements tested by the prior test case
# to avoid another problem with indexes on constant expressions.
#
reset_db
db null NULL
do_execsql_test 800 {
  CREATE TABLE t0(c0, c1);
  CREATE TABLE t1(c2);
  CREATE INDEX i0 ON t1(NULL);
  INSERT INTO t1(c2) VALUES (0.2);
  CREATE VIEW v0(c3) AS SELECT DISTINCT c2 FROM t1;
  SELECT * FROM v0 LEFT JOIN t0 ON c3<NULL LEFT JOIN t1 ON 1;
} {0.2 NULL NULL 0.2}
do_execsql_test 810 {
  SELECT * FROM v0 LEFT JOIN t0 ON c3<NULL LEFT JOIN t1 ON 1 WHERE c2/0.1;
} {0.2 NULL NULL 0.2}

finish_test
Changes to test/window1.test.
1877
1878
1879
1880
1881
1882
1883
1884

1885
1886
1887
1888
1889
1890
1891
1877
1878
1879
1880
1881
1882
1883

1884
1885
1886
1887
1888
1889
1890
1891







-
+







  INSERT INTO t1(a) VALUES(22);
  CREATE TABLE t3(y);
  INSERT INTO t3(y) VALUES(5),(11),(-9);
  SELECT (
    SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
  )
  FROM t3;
} {1 {misuse of aggregate: sum()}}
} {0 5}

# 2020-06-06 ticket 1f6f353b684fc708
reset_db
do_execsql_test 58.1 {
  CREATE TABLE a(a, b, c);
  INSERT INTO a VALUES(1, 2, 3);
  INSERT INTO a VALUES(4, 5, 6);
Changes to tool/lemon.c.
54
55
56
57
58
59
60












































































61
62
63
64
65
66
67
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







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








/*
** Compilers are getting increasingly pedantic about type conversions
** as C evolves ever closer to Ada....  To work around the latest problems
** we have to define the following variant of strlen().
*/
#define lemonStrlen(X)   ((int)strlen(X))

/*
** Header on the linked list of memory allocations.
*/
typedef struct MemChunk MemChunk;
struct MemChunk {
  MemChunk *pNext;
  size_t sz;
  /* Actually memory follows */
};  

/*
** Global linked list of all memory allocations.
*/
static MemChunk *memChunkList = 0;

/*
** Wrappers around malloc(), calloc(), realloc() and free().
**
** All memory allocations are kept on a doubly-linked list.  The
** lemon_free_all() function can be called prior to exit to clean
** up any memory leaks.
**
** This is not necessary.  But compilers and getting increasingly
** fussy about memory leaks, even in command-line programs like Lemon
** where they do not matter.  So this code is provided to hush the
** warnings.
*/
static void *lemon_malloc(size_t nByte){
  MemChunk *p;
  if( nByte<0 ) return 0;
  p = malloc( nByte + sizeof(MemChunk) );
  if( p==0 ){
    fprintf(stderr, "Out of memory.  Failed to allocate %lld bytes.\n",
            (long long int)nByte);
    exit(1);
  }
  p->pNext = memChunkList;
  p->sz = nByte;
  memChunkList = p;
  return (void*)&p[1];
}
static void *lemon_calloc(size_t nElem, size_t sz){
  void *p = lemon_malloc(nElem*sz);
  memset(p, 0, nElem*sz);
  return p;
}
static void lemon_free(void *pOld){
  if( pOld ){
    MemChunk *p = (MemChunk*)pOld;
    p--;
    memset(pOld, 0, p->sz);
  }
}
static void *lemon_realloc(void *pOld, size_t nNew){
  void *pNew;
  MemChunk *p;
  if( pOld==0 ) return lemon_malloc(nNew);
  p = (MemChunk*)pOld;
  p--;
  if( p->sz>=nNew ) return pOld;
  pNew = lemon_malloc( nNew );
  memcpy(pNew, pOld, p->sz);
  return pNew;
}

/* Free all outstanding memory allocations.
** Do this right before exiting.
*/
static void lemon_free_all(void){
  while( memChunkList ){
    MemChunk *pNext = memChunkList->pNext;
    free( memChunkList );
    memChunkList = pNext;
  }
}

/*
** Compilers are starting to complain about the use of sprintf() and strcpy(),
** saying they are unsafe.  So we define our own versions of those routines too.
**
** There are three routines here:  lemon_sprintf(), lemon_vsprintf(), and
** lemon_addtext(). The first two are replacements for sprintf() and vsprintf().
414
415
416
417
418
419
420


421
422
423
424
425
426
427
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505







+
+







  char *accept;            /* Code to execute when the parser excepts */
  char *extracode;         /* Code appended to the generated file */
  char *tokendest;         /* Code to execute to destroy token data */
  char *vardest;           /* Code for the default non-terminal destructor */
  char *filename;          /* Name of the input file */
  char *outname;           /* Name of the current output file */
  char *tokenprefix;       /* A prefix added to token names in the .h file */
  char *reallocFunc;       /* Function to use to allocate stack space */
  char *freeFunc;          /* Function to use to free stack space */
  int nconflict;           /* Number of parsing conflicts */
  int nactiontab;          /* Number of entries in the yy_action[] table */
  int nlookaheadtab;       /* Number of entries in yy_lookahead[] */
  int tablesize;           /* Total table size of all tables in bytes */
  int basisflag;           /* Print only basis configurations */
  int printPreprocessed;   /* Show preprocessor output on stdout */
  int has_fallback;        /* True if any %fallback is seen in the grammar */
491
492
493
494
495
496
497
498

499
500
501
502
503
504
505
569
570
571
572
573
574
575

576
577
578
579
580
581
582
583







-
+







static struct action *Action_new(void){
  static struct action *actionfreelist = 0;
  struct action *newaction;

  if( actionfreelist==0 ){
    int i;
    int amt = 100;
    actionfreelist = (struct action *)calloc(amt, sizeof(struct action));
    actionfreelist = (struct action *)lemon_calloc(amt, sizeof(struct action));
    if( actionfreelist==0 ){
      fprintf(stderr,"Unable to allocate memory for a new parser action.");
      exit(1);
    }
    for(i=0; i<amt-1; i++) actionfreelist[i].next = &actionfreelist[i+1];
    actionfreelist[amt-1].next = 0;
  }
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
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







-
-
-
+
+
+




-
+


















-
+







#define acttab_yyaction(X,N)  ((X)->aAction[N].action)

/* The value for the N-th entry in yy_lookahead */
#define acttab_yylookahead(X,N)  ((X)->aAction[N].lookahead)

/* Free all memory associated with the given acttab */
void acttab_free(acttab *p){
  free( p->aAction );
  free( p->aLookahead );
  free( p );
  lemon_free( p->aAction );
  lemon_free( p->aLookahead );
  lemon_free( p );
}

/* Allocate a new acttab structure */
acttab *acttab_alloc(int nsymbol, int nterminal){
  acttab *p = (acttab *) calloc( 1, sizeof(*p) );
  acttab *p = (acttab *) lemon_calloc( 1, sizeof(*p) );
  if( p==0 ){
    fprintf(stderr,"Unable to allocate memory for a new acttab.");
    exit(1);
  }
  memset(p, 0, sizeof(*p));
  p->nsymbol = nsymbol;
  p->nterminal = nterminal;
  return p;
}

/* Add a new action to the current transaction set.
**
** This routine is called once for each lookahead for a particular
** state.
*/
void acttab_action(acttab *p, int lookahead, int action){
  if( p->nLookahead>=p->nLookaheadAlloc ){
    p->nLookaheadAlloc += 25;
    p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead,
    p->aLookahead = (struct lookahead_action *) lemon_realloc( p->aLookahead,
                             sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
    if( p->aLookahead==0 ){
      fprintf(stderr,"malloc failed\n");
      exit(1);
    }
  }
  if( p->nLookahead==0 ){
686
687
688
689
690
691
692
693

694
695
696
697
698
699
700
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778







-
+







  ** in the worst case.  The worst case occurs if the transaction set
  ** must be appended to the current action table
  */
  n = p->nsymbol + 1;
  if( p->nAction + n >= p->nActionAlloc ){
    int oldAlloc = p->nActionAlloc;
    p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
    p->aAction = (struct lookahead_action *) realloc( p->aAction,
    p->aAction = (struct lookahead_action *) lemon_realloc( p->aAction,
                          sizeof(p->aAction[0])*p->nActionAlloc);
    if( p->aAction==0 ){
      fprintf(stderr,"malloc failed\n");
      exit(1);
    }
    for(i=oldAlloc; i<p->nActionAlloc; i++){
      p->aAction[i].lookahead = -1;
1308
1309
1310
1311
1312
1313
1314
1315

1316
1317
1318
1319
1320
1321
1322
1386
1387
1388
1389
1390
1391
1392

1393
1394
1395
1396
1397
1398
1399
1400







-
+







static struct config *current = 0;       /* Top of list of configurations */
static struct config **currentend = 0;   /* Last on list of configs */
static struct config *basis = 0;         /* Top of list of basis configs */
static struct config **basisend = 0;     /* End of list of basis configs */

/* Return a pointer to a new configuration */
PRIVATE struct config *newconfig(void){
  return (struct config*)calloc(1, sizeof(struct config));
  return (struct config*)lemon_calloc(1, sizeof(struct config));
}

/* The configuration "old" is no longer used */
PRIVATE void deleteconfig(struct config *old)
{
  old->next = freelist;
  freelist = old;
1524
1525
1526
1527
1528
1529
1530
1531

1532
1533
1534
1535
1536

1537
1538
1539
1540
1541
1542
1543

1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557

1558
1559
1560
1561
1562
1563
1564
1565
1566
1567

1568
1569
1570
1571
1572
1573
1574
1602
1603
1604
1605
1606
1607
1608

1609
1610
1611
1612
1613

1614
1615
1616
1617
1618
1619
1620

1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634

1635
1636
1637
1638
1639
1640
1641
1642
1643
1644

1645
1646
1647
1648
1649
1650
1651
1652







-
+




-
+






-
+













-
+









-
+








/* This routine is called with the argument to each -D command-line option.
** Add the macro defined to the azDefine array.
*/
static void handle_D_option(char *z){
  char **paz;
  nDefine++;
  azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine);
  azDefine = (char **) lemon_realloc(azDefine, sizeof(azDefine[0])*nDefine);
  if( azDefine==0 ){
    fprintf(stderr,"out of memory\n");
    exit(1);
  }
  bDefineUsed = (char*)realloc(bDefineUsed, nDefine);
  bDefineUsed = (char*)lemon_realloc(bDefineUsed, nDefine);
  if( bDefineUsed==0 ){
    fprintf(stderr,"out of memory\n");
    exit(1);
  }
  bDefineUsed[nDefine-1] = 0;
  paz = &azDefine[nDefine-1];
  *paz = (char *) malloc( lemonStrlen(z)+1 );
  *paz = (char *) lemon_malloc( lemonStrlen(z)+1 );
  if( *paz==0 ){
    fprintf(stderr,"out of memory\n");
    exit(1);
  }
  lemon_strcpy(*paz, z);
  for(z=*paz; *z && *z!='='; z++){}
  *z = 0;
}

/* Rember the name of the output directory 
*/
static char *outputDir = NULL;
static void handle_d_option(char *z){
  outputDir = (char *) malloc( lemonStrlen(z)+1 );
  outputDir = (char *) lemon_malloc( lemonStrlen(z)+1 );
  if( outputDir==0 ){
    fprintf(stderr,"out of memory\n");
    exit(1);
  }
  lemon_strcpy(outputDir, z);
}

static char *user_templatename = NULL;
static void handle_T_option(char *z){
  user_templatename = (char *) malloc( lemonStrlen(z)+1 );
  user_templatename = (char *) lemon_malloc( lemonStrlen(z)+1 );
  if( user_templatename==0 ){
    memory_error();
  }
  lemon_strcpy(user_templatename, z);
}

/* Merge together to lists of rules ordered by rule.iRule */
1797
1798
1799
1800
1801
1802
1803

1804
1805
1806
1807
1808
1809
1810
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889







+







  }
  if( lem.nconflict > 0 ){
    fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict);
  }

  /* return 0 on success, 1 on failure. */
  exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0;
  lemon_free_all();
  exit(exitcode);
  return (exitcode);
}
/******************** From the file "msort.c" *******************************/
/*
** A generic merge-sort program.
**
2385
2386
2387
2388
2389
2390
2391
2392

2393
2394
2395
2396
2397
2398
2399
2464
2465
2466
2467
2468
2469
2470

2471
2472
2473
2474
2475
2476
2477
2478







-
+







        psp->errorcnt++;
        psp->state = RESYNC_AFTER_RULE_ERROR;
      }
      break;
    case IN_RHS:
      if( x[0]=='.' ){
        struct rule *rp;
        rp = (struct rule *)calloc( sizeof(struct rule) +
        rp = (struct rule *)lemon_calloc( sizeof(struct rule) +
             sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
        if( rp==0 ){
          ErrorMsg(psp->filename,psp->tokenlineno,
            "Can't allocate enough memory for this rule.");
          psp->errorcnt++;
          psp->prevrule = 0;
        }else{
2437
2438
2439
2440
2441
2442
2443
2444

2445
2446
2447
2448

2449
2450
2451
2452
2453
2454

2455
2456
2457
2458
2459
2460
2461
2516
2517
2518
2519
2520
2521
2522

2523
2524
2525
2526

2527
2528
2529
2530
2531
2532

2533
2534
2535
2536
2537
2538
2539
2540







-
+



-
+





-
+







          psp->alias[psp->nrhs] = 0;
          psp->nrhs++;
        }
      }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 && ISUPPER(x[1]) ){
        struct symbol *msp = psp->rhs[psp->nrhs-1];
        if( msp->type!=MULTITERMINAL ){
          struct symbol *origsp = msp;
          msp = (struct symbol *) calloc(1,sizeof(*msp));
          msp = (struct symbol *) lemon_calloc(1,sizeof(*msp));
          memset(msp, 0, sizeof(*msp));
          msp->type = MULTITERMINAL;
          msp->nsubsym = 1;
          msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*));
          msp->subsym = (struct symbol**)lemon_calloc(1,sizeof(struct symbol*));
          msp->subsym[0] = origsp;
          msp->name = origsp->name;
          psp->rhs[psp->nrhs-1] = msp;
        }
        msp->nsubsym++;
        msp->subsym = (struct symbol **) realloc(msp->subsym,
        msp->subsym = (struct symbol **) lemon_realloc(msp->subsym,
          sizeof(struct symbol*)*msp->nsubsym);
        msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
        if( ISLOWER(x[1]) || ISLOWER(msp->subsym[0]->name[0]) ){
          ErrorMsg(psp->filename,psp->tokenlineno,
            "Cannot form a compound containing a non-terminal");
          psp->errorcnt++;
        }
2527
2528
2529
2530
2531
2532
2533






2534
2535
2536
2537
2538
2539
2540
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625







+
+
+
+
+
+







          psp->insertLineMacro = 0;
        }else if( strcmp(x,"token_type")==0 ){
          psp->declargslot = &(psp->gp->tokentype);
          psp->insertLineMacro = 0;
        }else if( strcmp(x,"default_type")==0 ){
          psp->declargslot = &(psp->gp->vartype);
          psp->insertLineMacro = 0;
        }else if( strcmp(x,"realloc")==0 ){
          psp->declargslot = &(psp->gp->reallocFunc);
          psp->insertLineMacro = 0;
        }else if( strcmp(x,"free")==0 ){
          psp->declargslot = &(psp->gp->freeFunc);
          psp->insertLineMacro = 0;
        }else if( strcmp(x,"stack_size")==0 ){
          psp->declargslot = &(psp->gp->stacksize);
          psp->insertLineMacro = 0;
        }else if( strcmp(x,"start_symbol")==0 ){
          psp->declargslot = &(psp->gp->start);
          psp->insertLineMacro = 0;
        }else if( strcmp(x,"left")==0 ){
2657
2658
2659
2660
2661
2662
2663
2664

2665
2666
2667
2668
2669
2670
2671
2742
2743
2744
2745
2746
2747
2748

2749
2750
2751
2752
2753
2754
2755
2756







-
+







          for(z=psp->filename, nBack=0; *z; z++){
            if( *z=='\\' ) nBack++;
          }
          lemon_sprintf(zLine, "#line %d ", psp->tokenlineno);
          nLine = lemonStrlen(zLine);
          n += nLine + lemonStrlen(psp->filename) + nBack;
        }
        *psp->declargslot = (char *) realloc(*psp->declargslot, n);
        *psp->declargslot = (char *) lemon_realloc(*psp->declargslot, n);
        zBuf = *psp->declargslot + nOld;
        if( addLineMacro ){
          if( nOld && zBuf[-1]!='\n' ){
            *(zBuf++) = '\n';
          }
          memcpy(zBuf, zLine, nLine);
          zBuf += nLine;
2771
2772
2773
2774
2775
2776
2777
2778

2779
2780
2781
2782
2783
2784
2785
2856
2857
2858
2859
2860
2861
2862

2863
2864
2865
2866
2867
2868
2869
2870







-
+







      break;
    case WAITING_FOR_CLASS_TOKEN:
      if( x[0]=='.' ){
        psp->state = WAITING_FOR_DECL_OR_RULE;
      }else if( ISUPPER(x[0]) || ((x[0]=='|' || x[0]=='/') && ISUPPER(x[1])) ){
        struct symbol *msp = psp->tkclass;
        msp->nsubsym++;
        msp->subsym = (struct symbol **) realloc(msp->subsym,
        msp->subsym = (struct symbol **) lemon_realloc(msp->subsym,
          sizeof(struct symbol*)*msp->nsubsym);
        if( !ISUPPER(x[0]) ) x++;
        msp->subsym[msp->nsubsym-1] = Symbol_new(x);
      }else{
        ErrorMsg(psp->filename, psp->tokenlineno,
          "%%token_class argument \"%s\" should be a token", x);
        psp->errorcnt++;
2986
2987
2988
2989
2990
2991
2992
2993

2994
2995
2996

2997
2998
2999
3000
3001
3002
3003
3004

3005
3006
3007
3008
3009
3010
3011
3071
3072
3073
3074
3075
3076
3077

3078
3079
3080

3081
3082
3083
3084
3085
3086
3087
3088

3089
3090
3091
3092
3093
3094
3095
3096







-
+


-
+







-
+







    ErrorMsg(ps.filename,0,"Can't open this file for reading.");
    gp->errorcnt++;
    return;
  }
  fseek(fp,0,2);
  filesize = ftell(fp);
  rewind(fp);
  filebuf = (char *)malloc( filesize+1 );
  filebuf = (char *)lemon_malloc( filesize+1 );
  if( filesize>100000000 || filebuf==0 ){
    ErrorMsg(ps.filename,0,"Input file too large.");
    free(filebuf);
    lemon_free(filebuf);
    gp->errorcnt++;
    fclose(fp);
    return;
  }
  if( fread(filebuf,1,filesize,fp)!=filesize ){
    ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
      filesize);
    free(filebuf);
    lemon_free(filebuf);
    gp->errorcnt++;
    fclose(fp);
    return;
  }
  fclose(fp);
  filebuf[filesize] = 0;

3109
3110
3111
3112
3113
3114
3115
3116

3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134

3135
3136
3137
3138
3139
3140
3141
3194
3195
3196
3197
3198
3199
3200

3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218

3219
3220
3221
3222
3223
3224
3225
3226







-
+

















-
+







    }
    c = *cp;
    *cp = 0;                        /* Null terminate the token */
    parseonetoken(&ps);             /* Parse the token */
    *cp = (char)c;                  /* Restore the buffer */
    cp = nextcp;
  }
  free(filebuf);                    /* Release the buffer after parsing */
  lemon_free(filebuf);                    /* Release the buffer after parsing */
  gp->rule = ps.firstrule;
  gp->errorcnt = ps.errorcnt;
}
/*************************** From the file "plink.c" *********************/
/*
** Routines processing configuration follow-set propagation links
** in the LEMON parser generator.
*/
static struct plink *plink_freelist = 0;

/* Allocate a new plink */
struct plink *Plink_new(void){
  struct plink *newlink;

  if( plink_freelist==0 ){
    int i;
    int amt = 100;
    plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) );
    plink_freelist = (struct plink *)lemon_calloc( amt, sizeof(struct plink) );
    if( plink_freelist==0 ){
      fprintf(stderr,
      "Unable to allocate memory for a new follow-set propagation link.\n");
      exit(1);
    }
    for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1];
    plink_freelist[amt-1].next = 0;
3180
3181
3182
3183
3184
3185
3186
3187

3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206

3207
3208
3209
3210
3211
3212
3213
3265
3266
3267
3268
3269
3270
3271

3272


3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288

3289
3290
3291
3292
3293
3294
3295
3296







-
+
-
-
















-
+







  }
}
/*********************** From the file "report.c" **************************/
/*
** Procedures for generating reports and tables in the LEMON parser generator.
*/

/* Generate a filename with the given suffix.  Space to hold the
/* Generate a filename with the given suffix.
** name comes from malloc() and must be freed by the calling
** function.
*/
PRIVATE char *file_makename(struct lemon *lemp, const char *suffix)
{
  char *name;
  char *cp;
  char *filename = lemp->filename;
  int sz;

  if( outputDir ){
    cp = strrchr(filename, '/');
    if( cp ) filename = cp + 1;
  }
  sz = lemonStrlen(filename);
  sz += lemonStrlen(suffix);
  if( outputDir ) sz += lemonStrlen(outputDir) + 1;
  sz += 5;
  name = (char*)malloc( sz );
  name = (char*)lemon_malloc( sz );
  if( name==0 ){
    fprintf(stderr,"Can't allocate space for a filename.\n");
    exit(1);
  }
  name[0] = 0;
  if( outputDir ){
    lemon_strcpy(name, outputDir);
3226
3227
3228
3229
3230
3231
3232
3233

3234
3235
3236
3237
3238
3239
3240
3309
3310
3311
3312
3313
3314
3315

3316
3317
3318
3319
3320
3321
3322
3323







-
+







PRIVATE FILE *file_open(
  struct lemon *lemp,
  const char *suffix,
  const char *mode
){
  FILE *fp;

  if( lemp->outname ) free(lemp->outname);
  if( lemp->outname ) lemon_free(lemp->outname);
  lemp->outname = file_makename(lemp, suffix);
  fp = fopen(lemp->outname,mode);
  if( fp==0 && *mode=='w' ){
    fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname);
    lemp->errorcnt++;
    return 0;
  }
3542
3543
3544
3545
3546
3547
3548
3549

3550
3551
3552
3553
3554
3555
3556


3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572

3573
3574
3575
3576
3577
3578
3579
3625
3626
3627
3628
3629
3630
3631

3632
3633
3634
3635
3636
3637


3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654

3655
3656
3657
3658
3659
3660
3661
3662







-
+





-
-
+
+















-
+







  cp = strrchr(argv0,'\\');
#else
  cp = strrchr(argv0,'/');
#endif
  if( cp ){
    c = *cp;
    *cp = 0;
    path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 );
    path = (char *)lemon_malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 );
    if( path ) lemon_sprintf(path,"%s/%s",argv0,name);
    *cp = c;
  }else{
    pathlist = getenv("PATH");
    if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
    pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 );
    path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
    pathbuf = (char *) lemon_malloc( lemonStrlen(pathlist) + 1 );
    path = (char *)lemon_malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
    if( (pathbuf != 0) && (path!=0) ){
      pathbufptr = pathbuf;
      lemon_strcpy(pathbuf, pathlist);
      while( *pathbuf ){
        cp = strchr(pathbuf,':');
        if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)];
        c = *cp;
        *cp = 0;
        lemon_sprintf(path,"%s/%s",pathbuf,name);
        *cp = c;
        if( c==0 ) pathbuf[0] = 0;
        else pathbuf = &cp[1];
        if( access(path,modemask)==0 ) break;
      }
    }
    free(pathbufptr);
    lemon_free(pathbufptr);
  }
  return path;
}

/* Given an action, compute the integer value for that action
** which is to be put in the action table of the generated machine.
** Return negative if no action should be generated.
3696
3697
3698
3699
3700
3701
3702
3703

3704
3705
3706
3707
3708
3709
3710
3779
3780
3781
3782
3783
3784
3785

3786
3787
3788
3789
3790
3791
3792
3793







-
+







    return 0;
  }
  in = fopen(tpltname,"rb");
  if( in==0 ){
    fprintf(stderr,"Can't open the template file \"%s\".\n",tpltname);
    lemp->errorcnt++;
  }
  free(toFree);
  lemon_free(toFree);
  return in;
}

/* Print a #line directive line to the output file. */
PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename)
{
  fprintf(out,"#line %d \"",lineno);
3825
3826
3827
3828
3829
3830
3831
3832

3833
3834
3835
3836
3837
3838
3839
3908
3909
3910
3911
3912
3913
3914

3915
3916
3917
3918
3919
3920
3921
3922







-
+







      used += n;
      assert( used>=0 );
    }
    n = lemonStrlen(zText);
  }
  if( (int) (n+sizeof(zInt)*2+used) >= alloced ){
    alloced = n + sizeof(zInt)*2 + used + 200;
    z = (char *) realloc(z,  alloced);
    z = (char *) lemon_realloc(z,  alloced);
  }
  if( z==0 ) return empty;
  while( n-- > 0 ){
    c = *(zText++);
    if( c=='%' && n>0 && zText[0]=='d' ){
      lemon_sprintf(zInt, "%d", p1);
      p1 = p2;
4115
4116
4117
4118
4119
4120
4121
4122

4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139

4140
4141
4142
4143
4144
4145
4146
4198
4199
4200
4201
4202
4203
4204

4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221

4222
4223
4224
4225
4226
4227
4228
4229







-
+
















-
+







  char *stddt;              /* Standardized name for a datatype */
  int i,j;                  /* Loop counters */
  unsigned hash;            /* For hashing the name of a type */
  const char *name;         /* Name of the parser */

  /* Allocate and initialize types[] and allocate stddt[] */
  arraysize = lemp->nsymbol * 2;
  types = (char**)calloc( arraysize, sizeof(char*) );
  types = (char**)lemon_calloc( arraysize, sizeof(char*) );
  if( types==0 ){
    fprintf(stderr,"Out of memory.\n");
    exit(1);
  }
  for(i=0; i<arraysize; i++) types[i] = 0;
  maxdtlength = 0;
  if( lemp->vartype ){
    maxdtlength = lemonStrlen(lemp->vartype);
  }
  for(i=0; i<lemp->nsymbol; i++){
    int len;
    struct symbol *sp = lemp->symbols[i];
    if( sp->datatype==0 ) continue;
    len = lemonStrlen(sp->datatype);
    if( len>maxdtlength ) maxdtlength = len;
  }
  stddt = (char*)malloc( maxdtlength*2 + 1 );
  stddt = (char*)lemon_malloc( maxdtlength*2 + 1 );
  if( stddt==0 ){
    fprintf(stderr,"Out of memory.\n");
    exit(1);
  }

  /* Build a hash table of datatypes. The ".dtnum" field of each symbol
  ** is filled in with the hash index plus 1.  A ".dtnum" value of 0 is
4181
4182
4183
4184
4185
4186
4187
4188

4189
4190
4191
4192
4193
4194
4195
4264
4265
4266
4267
4268
4269
4270

4271
4272
4273
4274
4275
4276
4277
4278







-
+







        break;
      }
      hash++;
      if( hash>=(unsigned)arraysize ) hash = 0;
    }
    if( types[hash]==0 ){
      sp->dtnum = hash + 1;
      types[hash] = (char*)malloc( lemonStrlen(stddt)+1 );
      types[hash] = (char*)lemon_malloc( lemonStrlen(stddt)+1 );
      if( types[hash]==0 ){
        fprintf(stderr,"Out of memory.\n");
        exit(1);
      }
      lemon_strcpy(types[hash],stddt);
    }
  }
4203
4204
4205
4206
4207
4208
4209
4210

4211
4212
4213
4214
4215
4216


4217
4218
4219
4220
4221
4222
4223
4286
4287
4288
4289
4290
4291
4292

4293
4294
4295
4296
4297


4298
4299
4300
4301
4302
4303
4304
4305
4306







-
+




-
-
+
+







  if( mhflag ){ fprintf(out,"#endif\n"); lineno++; }
  fprintf(out,"typedef union {\n"); lineno++;
  fprintf(out,"  int yyinit;\n"); lineno++;
  fprintf(out,"  %sTOKENTYPE yy0;\n",name); lineno++;
  for(i=0; i<arraysize; i++){
    if( types[i]==0 ) continue;
    fprintf(out,"  %s yy%d;\n",types[i],i+1); lineno++;
    free(types[i]);
    lemon_free(types[i]);
  }
  if( lemp->errsym && lemp->errsym->useCnt ){
    fprintf(out,"  int yy%d;\n",lemp->errsym->dtnum); lineno++;
  }
  free(stddt);
  free(types);
  lemon_free(stddt);
  lemon_free(types);
  fprintf(out,"} YYMINORTYPE;\n"); lineno++;
  *plineno = lineno;
}

/*
** Return the name of a C datatype able to represent values between
** lwr and upr, inclusive.  If pnByte!=NULL then also write the sizeof
4305
4306
4307
4308
4309
4310
4311
4312

4313
4314
4315
4316
4317
4318
4319
4388
4389
4390
4391
4392
4393
4394

4395
4396
4397
4398
4399
4400
4401
4402







-
+







){
  FILE *out, *in, *sql;
  int  lineno;
  struct state *stp;
  struct action *ap;
  struct rule *rp;
  struct acttab *pActtab;
  int i, j, n, sz;
  int i, j, n, sz, mn, mx;
  int nLookAhead;
  int szActionType;     /* sizeof(YYACTIONTYPE) */
  int szCodeType;       /* sizeof(YYCODETYPE)   */
  const char *name;
  int mnTknOfst, mxTknOfst;
  int mnNtOfst, mxNtOfst;
  struct axset *ax;
4438
4439
4440
4441
4442
4443
4444
4445

4446
4447
4448
4449
4450
4451
4452
4521
4522
4523
4524
4525
4526
4527

4528
4529
4530
4531
4532
4533
4534
4535







-
+







  }

  /* Generate the include code, if any */
  tplt_print(out,lemp,lemp->include,&lineno);
  if( mhflag ){
    char *incName = file_makename(lemp, ".h");
    fprintf(out,"#include \"%s\"\n", incName); lineno++;
    free(incName);
    lemon_free(incName);
  }
  tplt_xfer(lemp->name,in,out,&lineno);

  /* Generate #defines for all tokens */
  if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
  else                    prefix = "";
  if( mhflag ){
4497
4498
4499
4500
4501
4502
4503















4504
4505
4506
4507
4508
4509
4510
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608







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







  }else{
    fprintf(out,"#define %sARG_SDECL\n",name); lineno++;
    fprintf(out,"#define %sARG_PDECL\n",name); lineno++;
    fprintf(out,"#define %sARG_PARAM\n",name); lineno++;
    fprintf(out,"#define %sARG_FETCH\n",name); lineno++;
    fprintf(out,"#define %sARG_STORE\n",name); lineno++;
  }
  if( lemp->reallocFunc ){
    fprintf(out,"#define YYREALLOC %s\n", lemp->reallocFunc); lineno++;
  }else{
    fprintf(out,"#define YYREALLOC realloc\n"); lineno++;
  }
  if( lemp->freeFunc ){
    fprintf(out,"#define YYFREE %s\n", lemp->freeFunc); lineno++;
  }else{
    fprintf(out,"#define YYFREE free\n"); lineno++;
  }
  if( lemp->reallocFunc && lemp->freeFunc ){
    fprintf(out,"#define YYDYNSTACK 1\n"); lineno++;
  }else{
    fprintf(out,"#define YYDYNSTACK 0\n"); lineno++;
  }
  if( lemp->ctx && lemp->ctx[0] ){
    i = lemonStrlen(lemp->ctx);
    while( i>=1 && ISSPACE(lemp->ctx[i-1]) ) i--;
    while( i>=1 && (ISALNUM(lemp->ctx[i-1]) || lemp->ctx[i-1]=='_') ) i--;
    fprintf(out,"#define %sCTX_SDECL %s;\n",name,lemp->ctx);  lineno++;
    fprintf(out,"#define %sCTX_PDECL ,%s\n",name,lemp->ctx);  lineno++;
    fprintf(out,"#define %sCTX_PARAM ,%s\n",name,&lemp->ctx[i]);  lineno++;
4530
4531
4532
4533
4534
4535
4536
4537

4538
4539
4540
4541
4542
4543
4544
4628
4629
4630
4631
4632
4633
4634

4635
4636
4637
4638
4639
4640
4641
4642







-
+







    fprintf(out,"#define YYFALLBACK 1\n");  lineno++;
  }

  /* Compute the action table, but do not output it yet.  The action
  ** table must be computed before generating the YYNSTATE macro because
  ** we need to know how many states can be eliminated.
  */
  ax = (struct axset *) calloc(lemp->nxstate*2, sizeof(ax[0]));
  ax = (struct axset *) lemon_calloc(lemp->nxstate*2, sizeof(ax[0]));
  if( ax==0 ){
    fprintf(stderr,"malloc failed\n");
    exit(1);
  }
  for(i=0; i<lemp->nxstate; i++){
    stp = lemp->sorted[i];
    ax[i*2].stp = stp;
4588
4589
4590
4591
4592
4593
4594
4595

4596
4597
4598
4599
4600
4601
4602
4686
4687
4688
4689
4690
4691
4692

4693
4694
4695
4696
4697
4698
4699
4700







-
+







      }
      printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n",
             i, stp->statenum, ax[i].isTkn ? "Token" : "Var  ",
             ax[i].nAction, pActtab->nAction, nn);
    }
#endif
  }
  free(ax);
  lemon_free(ax);

  /* Mark rules that are actually used for reduce actions after all
  ** optimizations have been applied
  */
  for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE;
  for(i=0; i<lemp->nxstate; i++){
    for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
4620
4621
4622
4623
4624
4625
4626
















4627
4628
4629
4630
4631
4632
4633
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747







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







  fprintf(out,"#define YY_MAX_SHIFTREDUCE   %d\n", i-1); lineno++;
  fprintf(out,"#define YY_ERROR_ACTION      %d\n", lemp->errAction); lineno++;
  fprintf(out,"#define YY_ACCEPT_ACTION     %d\n", lemp->accAction); lineno++;
  fprintf(out,"#define YY_NO_ACTION         %d\n", lemp->noAction); lineno++;
  fprintf(out,"#define YY_MIN_REDUCE        %d\n", lemp->minReduce); lineno++;
  i = lemp->minReduce + lemp->nrule;
  fprintf(out,"#define YY_MAX_REDUCE        %d\n", i-1); lineno++;

  /* Minimum and maximum token values that have a destructor */
  mn = mx = 0;
  for(i=0; i<lemp->nsymbol; i++){
    struct symbol *sp = lemp->symbols[i];

    if( sp && sp->type!=TERMINAL && sp->destructor ){
      if( mn==0 || sp->index<mn ) mn = sp->index;
      if( sp->index>mx ) mx = sp->index;
    }
  }
  if( lemp->tokendest ) mn = 0;
  if( lemp->vardest ) mx = lemp->nsymbol-1;
  fprintf(out,"#define YY_MIN_DSTRCTR       %d\n", mn);  lineno++;
  fprintf(out,"#define YY_MAX_DSTRCTR       %d\n", mx);  lineno++;    

  tplt_xfer(lemp->name,in,out,&lineno);

  /* Now output the action table and its associates:
  **
  **  yy_action[]        A single table containing all actions.
  **  yy_lookahead[]     A table containing the lookahead for each entry in
  **                     yy_action.  Used to detect hash collisions.
4763
4764
4765
4766
4767
4768
4769
4770

4771
4772
4773
4774
4775
4776
4777
4877
4878
4879
4880
4881
4882
4883

4884
4885
4886
4887
4888
4889
4890
4891







-
+







  }
  fprintf(out, "};\n"); lineno++;
  tplt_xfer(lemp->name,in,out,&lineno);

  /* Generate the table of fallback tokens.
  */
  if( lemp->has_fallback ){
    int mx = lemp->nterminal - 1;
    mx = lemp->nterminal - 1;
    /* 2019-08-28:  Generate fallback entries for every token to avoid
    ** having to do a range check on the index */
    /* while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } */
    lemp->tablesize += (mx+1)*szCodeType;
    for(i=0; i<=mx; i++){
      struct symbol *p = lemp->symbols[i];
      if( p->fallback==0 ){
5198
5199
5200
5201
5202
5203
5204
5205

5206
5207
5208
5209
5210
5211
5212
5213
5214
5215

5216
5217
5218
5219
5220
5221
5222
5312
5313
5314
5315
5316
5317
5318

5319
5320
5321
5322
5323
5324
5325
5326
5327
5328

5329
5330
5331
5332
5333
5334
5335
5336







-
+









-
+







{
  size = n+1;
}

/* Allocate a new set */
char *SetNew(void){
  char *s;
  s = (char*)calloc( size, 1);
  s = (char*)lemon_calloc( size, 1);
  if( s==0 ){
    memory_error();
  }
  return s;
}

/* Deallocate a set */
void SetFree(char *s)
{
  free(s);
  lemon_free(s);
}

/* Add a new element to the set.  Return TRUE if the element was added
** and FALSE if it was already there. */
int SetAdd(char *s, int e)
{
  int rv;
5267
5268
5269
5270
5271
5272
5273
5274

5275
5276
5277
5278
5279
5280
5281
5381
5382
5383
5384
5385
5386
5387

5388
5389
5390
5391
5392
5393
5394
5395







-
+







const char *Strsafe(const char *y)
{
  const char *z;
  char *cpy;

  if( y==0 ) return 0;
  z = Strsafe_find(y);
  if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){
  if( z==0 && (cpy=(char *)lemon_malloc( lemonStrlen(y)+1 ))!=0 ){
    lemon_strcpy(cpy,y);
    z = cpy;
    Strsafe_insert(z);
  }
  MemoryCheck(z);
  return z;
}
5303
5304
5305
5306
5307
5308
5309
5310

5311
5312
5313
5314

5315
5316

5317
5318
5319
5320
5321
5322
5323
5417
5418
5419
5420
5421
5422
5423

5424
5425
5426
5427

5428
5429

5430
5431
5432
5433
5434
5435
5436
5437







-
+



-
+

-
+








/* There is only one instance of the array, which is the following */
static struct s_x1 *x1a;

/* Allocate a new associative array */
void Strsafe_init(void){
  if( x1a ) return;
  x1a = (struct s_x1*)malloc( sizeof(struct s_x1) );
  x1a = (struct s_x1*)lemon_malloc( sizeof(struct s_x1) );
  if( x1a ){
    x1a->size = 1024;
    x1a->count = 0;
    x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*));
    x1a->tbl = (x1node*)lemon_calloc(1024, sizeof(x1node) + sizeof(x1node*));
    if( x1a->tbl==0 ){
      free(x1a);
      lemon_free(x1a);
      x1a = 0;
    }else{
      int i;
      x1a->ht = (x1node**)&(x1a->tbl[1024]);
      for(i=0; i<1024; i++) x1a->ht[i] = 0;
    }
  }
5344
5345
5346
5347
5348
5349
5350
5351

5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366

5367
5368
5369
5370
5371
5372
5373
5458
5459
5460
5461
5462
5463
5464

5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479

5480
5481
5482
5483
5484
5485
5486
5487







-
+














-
+







  }
  if( x1a->count>=x1a->size ){
    /* Need to make the hash table bigger */
    int i,arrSize;
    struct s_x1 array;
    array.size = arrSize = x1a->size*2;
    array.count = x1a->count;
    array.tbl = (x1node*)calloc(arrSize, sizeof(x1node) + sizeof(x1node*));
    array.tbl = (x1node*)lemon_calloc(arrSize, sizeof(x1node)+sizeof(x1node*));
    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
    array.ht = (x1node**)&(array.tbl[arrSize]);
    for(i=0; i<arrSize; i++) array.ht[i] = 0;
    for(i=0; i<x1a->count; i++){
      x1node *oldnp, *newnp;
      oldnp = &(x1a->tbl[i]);
      h = strhash(oldnp->data) & (arrSize-1);
      newnp = &(array.tbl[i]);
      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
      newnp->next = array.ht[h];
      newnp->data = oldnp->data;
      newnp->from = &(array.ht[h]);
      array.ht[h] = newnp;
    }
    /* free(x1a->tbl); // This program was originally for 16-bit machines.
    /* lemon_free(x1a->tbl); // This program was originally for 16-bit machines.
    ** Don't worry about freeing memory on modern platforms. */
    *x1a = array;
  }
  /* Insert the new data */
  h = ph & (x1a->size-1);
  np = &(x1a->tbl[x1a->count++]);
  np->data = data;
5400
5401
5402
5403
5404
5405
5406
5407

5408
5409
5410
5411
5412
5413
5414
5514
5515
5516
5517
5518
5519
5520

5521
5522
5523
5524
5525
5526
5527
5528







-
+







*/
struct symbol *Symbol_new(const char *x)
{
  struct symbol *sp;

  sp = Symbol_find(x);
  if( sp==0 ){
    sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
    sp = (struct symbol *)lemon_calloc(1, sizeof(struct symbol) );
    MemoryCheck(sp);
    sp->name = Strsafe(x);
    sp->type = ISUPPER(*x) ? TERMINAL : NONTERMINAL;
    sp->rule = 0;
    sp->fallback = 0;
    sp->prec = -1;
    sp->assoc = UNK;
5471
5472
5473
5474
5475
5476
5477
5478

5479
5480
5481
5482

5483
5484

5485
5486
5487
5488
5489
5490
5491
5585
5586
5587
5588
5589
5590
5591

5592
5593
5594
5595

5596
5597

5598
5599
5600
5601
5602
5603
5604
5605







-
+



-
+

-
+








/* There is only one instance of the array, which is the following */
static struct s_x2 *x2a;

/* Allocate a new associative array */
void Symbol_init(void){
  if( x2a ) return;
  x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
  x2a = (struct s_x2*)lemon_malloc( sizeof(struct s_x2) );
  if( x2a ){
    x2a->size = 128;
    x2a->count = 0;
    x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*));
    x2a->tbl = (x2node*)lemon_calloc(128, sizeof(x2node) + sizeof(x2node*));
    if( x2a->tbl==0 ){
      free(x2a);
      lemon_free(x2a);
      x2a = 0;
    }else{
      int i;
      x2a->ht = (x2node**)&(x2a->tbl[128]);
      for(i=0; i<128; i++) x2a->ht[i] = 0;
    }
  }
5512
5513
5514
5515
5516
5517
5518
5519

5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535

5536
5537
5538
5539
5540
5541
5542
5626
5627
5628
5629
5630
5631
5632

5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648

5649
5650
5651
5652
5653
5654
5655
5656







-
+















-
+







  }
  if( x2a->count>=x2a->size ){
    /* Need to make the hash table bigger */
    int i,arrSize;
    struct s_x2 array;
    array.size = arrSize = x2a->size*2;
    array.count = x2a->count;
    array.tbl = (x2node*)calloc(arrSize, sizeof(x2node) + sizeof(x2node*));
    array.tbl = (x2node*)lemon_calloc(arrSize, sizeof(x2node)+sizeof(x2node*));
    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
    array.ht = (x2node**)&(array.tbl[arrSize]);
    for(i=0; i<arrSize; i++) array.ht[i] = 0;
    for(i=0; i<x2a->count; i++){
      x2node *oldnp, *newnp;
      oldnp = &(x2a->tbl[i]);
      h = strhash(oldnp->key) & (arrSize-1);
      newnp = &(array.tbl[i]);
      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
      newnp->next = array.ht[h];
      newnp->key = oldnp->key;
      newnp->data = oldnp->data;
      newnp->from = &(array.ht[h]);
      array.ht[h] = newnp;
    }
    /* free(x2a->tbl); // This program was originally written for 16-bit
    /* lemon_free(x2a->tbl); // This program was originally written for 16-bit
    ** machines.  Don't worry about freeing this trivial amount of memory
    ** on modern platforms.  Just leak it. */
    *x2a = array;
  }
  /* Insert the new data */
  h = ph & (x2a->size-1);
  np = &(x2a->tbl[x2a->count++]);
5589
5590
5591
5592
5593
5594
5595
5596

5597
5598
5599
5600
5601
5602
5603
5703
5704
5705
5706
5707
5708
5709

5710
5711
5712
5713
5714
5715
5716
5717







-
+







** problems, or if the array is empty. */
struct symbol **Symbol_arrayof()
{
  struct symbol **array;
  int i,arrSize;
  if( x2a==0 ) return 0;
  arrSize = x2a->count;
  array = (struct symbol **)calloc(arrSize, sizeof(struct symbol *));
  array = (struct symbol **)lemon_calloc(arrSize, sizeof(struct symbol *));
  if( array ){
    for(i=0; i<arrSize; i++) array[i] = x2a->tbl[i].data;
  }
  return array;
}

/* Compare two configurations */
5637
5638
5639
5640
5641
5642
5643
5644

5645
5646
5647
5648
5649
5650
5651
5751
5752
5753
5754
5755
5756
5757

5758
5759
5760
5761
5762
5763
5764
5765







-
+







  return h;
}

/* Allocate a new state structure */
struct state *State_new()
{
  struct state *newstate;
  newstate = (struct state *)calloc(1, sizeof(struct state) );
  newstate = (struct state *)lemon_calloc(1, sizeof(struct state) );
  MemoryCheck(newstate);
  return newstate;
}

/* There is one instance of the following structure for each
** associative array of type "x3".
*/
5670
5671
5672
5673
5674
5675
5676
5677

5678
5679
5680
5681

5682
5683

5684
5685
5686
5687
5688
5689
5690
5784
5785
5786
5787
5788
5789
5790

5791
5792
5793
5794

5795
5796

5797
5798
5799
5800
5801
5802
5803
5804







-
+



-
+

-
+








/* There is only one instance of the array, which is the following */
static struct s_x3 *x3a;

/* Allocate a new associative array */
void State_init(void){
  if( x3a ) return;
  x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
  x3a = (struct s_x3*)lemon_malloc( sizeof(struct s_x3) );
  if( x3a ){
    x3a->size = 128;
    x3a->count = 0;
    x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*));
    x3a->tbl = (x3node*)lemon_calloc(128, sizeof(x3node) + sizeof(x3node*));
    if( x3a->tbl==0 ){
      free(x3a);
      lemon_free(x3a);
      x3a = 0;
    }else{
      int i;
      x3a->ht = (x3node**)&(x3a->tbl[128]);
      for(i=0; i<128; i++) x3a->ht[i] = 0;
    }
  }
5711
5712
5713
5714
5715
5716
5717
5718

5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734

5735
5736
5737
5738
5739
5740
5741
5825
5826
5827
5828
5829
5830
5831

5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847

5848
5849
5850
5851
5852
5853
5854
5855







-
+















-
+







  }
  if( x3a->count>=x3a->size ){
    /* Need to make the hash table bigger */
    int i,arrSize;
    struct s_x3 array;
    array.size = arrSize = x3a->size*2;
    array.count = x3a->count;
    array.tbl = (x3node*)calloc(arrSize, sizeof(x3node) + sizeof(x3node*));
    array.tbl = (x3node*)lemon_calloc(arrSize, sizeof(x3node)+sizeof(x3node*));
    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
    array.ht = (x3node**)&(array.tbl[arrSize]);
    for(i=0; i<arrSize; i++) array.ht[i] = 0;
    for(i=0; i<x3a->count; i++){
      x3node *oldnp, *newnp;
      oldnp = &(x3a->tbl[i]);
      h = statehash(oldnp->key) & (arrSize-1);
      newnp = &(array.tbl[i]);
      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
      newnp->next = array.ht[h];
      newnp->key = oldnp->key;
      newnp->data = oldnp->data;
      newnp->from = &(array.ht[h]);
      array.ht[h] = newnp;
    }
    free(x3a->tbl);
    lemon_free(x3a->tbl);
    *x3a = array;
  }
  /* Insert the new data */
  h = ph & (x3a->size-1);
  np = &(x3a->tbl[x3a->count++]);
  np->key = key;
  np->data = data;
5768
5769
5770
5771
5772
5773
5774
5775

5776
5777
5778
5779
5780
5781
5782
5882
5883
5884
5885
5886
5887
5888

5889
5890
5891
5892
5893
5894
5895
5896







-
+







** problems, or if the array is empty. */
struct state **State_arrayof(void)
{
  struct state **array;
  int i,arrSize;
  if( x3a==0 ) return 0;
  arrSize = x3a->count;
  array = (struct state **)calloc(arrSize, sizeof(struct state *));
  array = (struct state **)lemon_calloc(arrSize, sizeof(struct state *));
  if( array ){
    for(i=0; i<arrSize; i++) array[i] = x3a->tbl[i].data;
  }
  return array;
}

/* Hash a configuration */
5810
5811
5812
5813
5814
5815
5816
5817

5818
5819
5820
5821

5822
5823

5824
5825
5826
5827
5828
5829
5830
5924
5925
5926
5927
5928
5929
5930

5931
5932
5933
5934

5935
5936

5937
5938
5939
5940
5941
5942
5943
5944







-
+



-
+

-
+








/* There is only one instance of the array, which is the following */
static struct s_x4 *x4a;

/* Allocate a new associative array */
void Configtable_init(void){
  if( x4a ) return;
  x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
  x4a = (struct s_x4*)lemon_malloc( sizeof(struct s_x4) );
  if( x4a ){
    x4a->size = 64;
    x4a->count = 0;
    x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*));
    x4a->tbl = (x4node*)lemon_calloc(64, sizeof(x4node) + sizeof(x4node*));
    if( x4a->tbl==0 ){
      free(x4a);
      lemon_free(x4a);
      x4a = 0;
    }else{
      int i;
      x4a->ht = (x4node**)&(x4a->tbl[64]);
      for(i=0; i<64; i++) x4a->ht[i] = 0;
    }
  }
5851
5852
5853
5854
5855
5856
5857

5858

5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5965
5966
5967
5968
5969
5970
5971
5972

5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987



5988
5989
5990
5991
5992
5993
5994







+
-
+














-
-
-







  }
  if( x4a->count>=x4a->size ){
    /* Need to make the hash table bigger */
    int i,arrSize;
    struct s_x4 array;
    array.size = arrSize = x4a->size*2;
    array.count = x4a->count;
    array.tbl = (x4node*)lemon_calloc(arrSize,
    array.tbl = (x4node*)calloc(arrSize, sizeof(x4node) + sizeof(x4node*));
                                      sizeof(x4node) + sizeof(x4node*));
    if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
    array.ht = (x4node**)&(array.tbl[arrSize]);
    for(i=0; i<arrSize; i++) array.ht[i] = 0;
    for(i=0; i<x4a->count; i++){
      x4node *oldnp, *newnp;
      oldnp = &(x4a->tbl[i]);
      h = confighash(oldnp->data) & (arrSize-1);
      newnp = &(array.tbl[i]);
      if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
      newnp->next = array.ht[h];
      newnp->data = oldnp->data;
      newnp->from = &(array.ht[h]);
      array.ht[h] = newnp;
    }
    /* free(x4a->tbl); // This code was originall written for 16-bit machines.
    ** on modern machines, don't worry about freeing this trival amount of
    ** memory. */
    *x4a = array;
  }
  /* Insert the new data */
  h = ph & (x4a->size-1);
  np = &(x4a->tbl[x4a->count++]);
  np->data = data;
  if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next);
Changes to tool/lempar.c.
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
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







+
+
+













+
+




















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







**                       zero the stack is dynamically sized using realloc()
**    ParseARG_SDECL     A static variable declaration for the %extra_argument
**    ParseARG_PDECL     A parameter declaration for the %extra_argument
**    ParseARG_PARAM     Code to pass %extra_argument as a subroutine parameter
**    ParseARG_STORE     Code to store %extra_argument into yypParser
**    ParseARG_FETCH     Code to extract %extra_argument from yypParser
**    ParseCTX_*         As ParseARG_ except for %extra_context
**    YYREALLOC          Name of the realloc() function to use
**    YYFREE             Name of the free() function to use
**    YYDYNSTACK         True if stack space should be extended on heap
**    YYERRORSYMBOL      is the code number of the error symbol.  If not
**                       defined, then do no error processing.
**    YYNSTATE           the combined number of states.
**    YYNRULE            the number of rules in the grammar
**    YYNTOKEN           Number of terminal symbols
**    YY_MAX_SHIFT       Maximum value for shift actions
**    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
**    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
**    YY_ERROR_ACTION    The yy_action[] code for syntax error
**    YY_ACCEPT_ACTION   The yy_action[] code for accept
**    YY_NO_ACTION       The yy_action[] code for no-op
**    YY_MIN_REDUCE      Minimum value for reduce actions
**    YY_MAX_REDUCE      Maximum value for reduce actions
**    YY_MIN_DSTRCTR     Minimum symbol value that has a destructor
**    YY_MAX_DSTRCTR     Maximum symbol value that has a destructor
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
%%
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section
** to a macro that can assist in verifying code coverage.  For production
** code the yytestcase() macro should be turned off.  But it is useful
** for testing.
*/
#ifndef yytestcase
# define yytestcase(X)
#endif

/* Macro to determine if stack space has the ability to grow using
** heap memory.
*/
#if YYSTACKDEPTH<=0 || YYDYNSTACK
# define YYGROWABLESTACK 1
#else
# define YYGROWABLESTACK 0
#endif

/* Guarantee a minimum number of initial stack slots.
*/
#if YYSTACKDEPTH<=0
# undef YYSTACKDEPTH
# define YYSTACKDEPTH 2  /* Need a minimum stack size */
#endif


/* Next are the tables used to determine what action to take based on the
** current state and lookahead token.  These tables are used to implement
** functions that take a state number and lookahead value and return an
** action integer.  
**
208
209
210
211
212
213
214
215
216
217
218



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




236
237
238




239
240
241
242
243
244
245







-
-
-
-
+
+
+
-
-
-
-







  int yyhwm;                    /* High-water mark of the stack */
#endif
#ifndef YYNOERRORRECOVERY
  int yyerrcnt;                 /* Shifts left before out of the error */
#endif
  ParseARG_SDECL                /* A place to hold %extra_argument */
  ParseCTX_SDECL                /* A place to hold %extra_context */
#if YYSTACKDEPTH<=0
  int yystksz;                  /* Current side of the stack */
  yyStackEntry *yystack;        /* The parser's stack */
  yyStackEntry yystk0;          /* First stack entry */
  yyStackEntry *yystackEnd;           /* Last entry in the stack */
  yyStackEntry *yystack;              /* The parser stack */
  yyStackEntry yystk0[YYSTACKDEPTH];  /* Initial stack space */
#else
  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
  yyStackEntry *yystackEnd;            /* Last entry in the stack */
#endif
};
typedef struct yyParser yyParser;

#include <assert.h>
#ifndef NDEBUG
#include <stdio.h>
static FILE *yyTraceFILE = 0;
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
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299
300
301
302





303
304
305
306
307
308
309

310
311
312



313
314
315




316
317
318
319
320


321
322
323


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




350
351





352
353
354
355
356
357



358
359
360
361
362
363
364







-
+





+




-
-
-
-
-
+
+
+
+
+
+

-
+
+

-
-
-
+
+

-
-
-
-
+
+
+
+

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



















-
-
-
-
+
+
-
-
-
-
-






-
-
-







*/
static const char *const yyRuleName[] = {
%%
};
#endif /* NDEBUG */


#if YYSTACKDEPTH<=0
#if YYGROWABLESTACK
/*
** Try to increase the size of the parser stack.  Return the number
** of errors.  Return 0 on success.
*/
static int yyGrowStack(yyParser *p){
  int oldSize = 1 + (int)(p->yystackEnd - p->yystack);
  int newSize;
  int idx;
  yyStackEntry *pNew;

  newSize = p->yystksz*2 + 100;
  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
  if( p->yystack==&p->yystk0 ){
    pNew = malloc(newSize*sizeof(pNew[0]));
    if( pNew ) pNew[0] = p->yystk0;
  newSize = oldSize*2 + 100;
  idx = (int)(p->yytos - p->yystack);
  if( p->yystack==p->yystk0 ){
    pNew = YYREALLOC(0, newSize*sizeof(pNew[0]));
    if( pNew==0 ) return 1;
    memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0]));
  }else{
    pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
    pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0]));
    if( pNew==0 ) return 1;
  }
  if( pNew ){
    p->yystack = pNew;
    p->yytos = &p->yystack[idx];
  p->yystack = pNew;
  p->yytos = &p->yystack[idx];
#ifndef NDEBUG
    if( yyTraceFILE ){
      fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
              yyTracePrompt, p->yystksz, newSize);
    }
  if( yyTraceFILE ){
    fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
            yyTracePrompt, oldSize, newSize);
  }
#endif
    p->yystksz = newSize;
  }
  p->yystackEnd = &p->yystack[newSize-1];
  return 0;
}
  return pNew==0; 
}
#endif /* YYGROWABLESTACK */

#if !YYGROWABLESTACK
/* For builds that do no have a growable stack, yyGrowStack always
** returns an error.
*/
# define yyGrowStack(X) 1
#endif

/* Datatype of the argument to the memory allocated passed as the
** second argument to ParseAlloc() below.  This can be changed by
** putting an appropriate #define in the %include section of the input
** grammar.
*/
#ifndef YYMALLOCARGTYPE
# define YYMALLOCARGTYPE size_t
#endif

/* Initialize a new parser that has already been allocated.
*/
void ParseInit(void *yypRawParser ParseCTX_PDECL){
  yyParser *yypParser = (yyParser*)yypRawParser;
  ParseCTX_STORE
#ifdef YYTRACKMAXSTACKDEPTH
  yypParser->yyhwm = 0;
#endif
#if YYSTACKDEPTH<=0
  yypParser->yytos = NULL;
  yypParser->yystack = NULL;
  yypParser->yystksz = 0;
  yypParser->yystack = yypParser->yystk0;
  yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
  if( yyGrowStack(yypParser) ){
    yypParser->yystack = &yypParser->yystk0;
    yypParser->yystksz = 1;
  }
#endif
#ifndef YYNOERRORRECOVERY
  yypParser->yyerrcnt = -1;
#endif
  yypParser->yytos = yypParser->yystack;
  yypParser->yystack[0].stateno = 0;
  yypParser->yystack[0].major = 0;
#if YYSTACKDEPTH>0
  yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#endif
}

#ifndef Parse_ENGINEALWAYSONSTACK
/* 
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
422
423
424
425
426
427
428




429
430
431
















432
433
434
435
436
437
438
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







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







}

/*
** Clear all secondary memory allocations from the parser
*/
void ParseFinalize(void *p){
  yyParser *pParser = (yyParser*)p;

  /* In-lined version of calling yy_pop_parser_stack() for each
  ** element left in the stack */
  yyStackEntry *yytos = pParser->yytos;
  while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
#if YYSTACKDEPTH<=0
  if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
  while( yytos>pParser->yystack ){
#ifndef NDEBUG
    if( yyTraceFILE ){
      fprintf(yyTraceFILE,"%sPopping %s\n",
        yyTracePrompt,
        yyTokenName[yytos->major]);
    }
#endif
    if( yytos->major>=YY_MIN_DSTRCTR ){
      yy_destructor(pParser, yytos->major, &yytos->minor);
    }
    yytos--;
  }

#if YYGROWABLESTACK
  if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack);
#endif
}

#ifndef Parse_ENGINEALWAYSONSTACK
/* 
** Deallocate and destroy a parser.  Destructors are called for
** all stack elements before shutting the parser down.
650
651
652
653
654
655
656
657
658
659

660
661
662
663
664

665
666
667
668
669


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



688





689
690
691
692
693
694
695
696
697

698
699
700

701
702
703
704
705
706
707







-
-
-
+
-
-
-
-
-
+





+
+

-



-







  yypParser->yytos++;
#ifdef YYTRACKMAXSTACKDEPTH
  if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
    yypParser->yyhwm++;
    assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
  }
#endif
#if YYSTACKDEPTH>0 
  if( yypParser->yytos>yypParser->yystackEnd ){
    yypParser->yytos--;
  yytos = yypParser->yytos;
    yyStackOverflow(yypParser);
    return;
  }
#else
  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
  if( yytos>yypParser->yystackEnd ){
    if( yyGrowStack(yypParser) ){
      yypParser->yytos--;
      yyStackOverflow(yypParser);
      return;
    }
    yytos = yypParser->yytos;
    assert( yytos <= yypParser->yystackEnd );
  }
#endif
  if( yyNewState > YY_MAX_SHIFT ){
    yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
  }
  yytos = yypParser->yytos;
  yytos->stateno = yyNewState;
  yytos->major = yyMajor;
  yytos->minor.yy0 = yyMinor;
  yyTraceShift(yypParser, yyNewState, "Shift");
}

/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
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
932
933
934
935
936
937
938

939





940
941
942
943
944

945
946
947
948
949
950
951







-

-
-
-
-
-





-







#ifdef YYTRACKMAXSTACKDEPTH
        if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
          yypParser->yyhwm++;
          assert( yypParser->yyhwm ==
                  (int)(yypParser->yytos - yypParser->yystack));
        }
#endif
#if YYSTACKDEPTH>0 
        if( yypParser->yytos>=yypParser->yystackEnd ){
          yyStackOverflow(yypParser);
          break;
        }
#else
        if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
          if( yyGrowStack(yypParser) ){
            yyStackOverflow(yypParser);
            break;
          }
        }
#endif
      }
      yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor ParseCTX_PARAM);
    }else if( yyact <= YY_MAX_SHIFTREDUCE ){
      yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
#ifndef YYNOERRORRECOVERY
      yypParser->yyerrcnt--;
#endif
Changes to tool/mkopcodeh.tcl.
77
78
79
80
81
82
83

84
85
86
87
88
89
90
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91







+







  if {[regexp {^case OP_} $line]} {
    set line [split $line]
    set name [string trim [lindex $line 1] :]
    if {$name=="OP_Abortable"} continue;  # put OP_Abortable last 
    set op($name) -1
    set group($name) 0
    set jump($name) 0
    set jump0($name) 0
    set in1($name) 0
    set in2($name) 0
    set in3($name) 0
    set out2($name) 0
    set out3($name) 0
    set ncycle($name) 0
    for {set i 3} {$i<[llength $line]-1} {incr i} {
105
106
107
108
109
110
111

112
113
114
115
116
117
118
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120







+







         jump  {set jump($name) 1}
         in1   {set in1($name) 1}
         in2   {set in2($name) 1}
         in3   {set in3($name) 1}
         out2  {set out2($name) 1}
         out3  {set out3($name) 1}
         ncycle {set ncycle($name) 1}
         jump0 {set jump($name) 1; set jump0($name) 1;}
       }
    }
    if {$group($name)} {
      set newGroup 0
      if {[info exists groups($nGroup)]} {
        if {$prevName=="" || !$group($prevName)} {
          set newGroup 1
133
134
135
136
137
138
139

140
141
142
143
144
145
146
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149







+








# Assign numbers to all opcodes and output the result.
#
puts "/* Automatically generated.  Do not edit */"
puts "/* See the tool/mkopcodeh.tcl script for details */"
foreach name {OP_Noop OP_Explain OP_Abortable} {
  set jump($name) 0
  set jump0($name) 0
  set in1($name) 0
  set in2($name) 0
  set in3($name) 0
  set out2($name) 0
  set out3($name) 0
  set ncycle($name) 0
  set op($name) -1
252
253
254
255
256
257
258


259

260
261
262
263
264
265
266
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271







+
+
-
+







  if {![info exists used($i)]} {
    set def($i) "OP_NotUsed_$i"
  }
  if {$i>$max} {set max $i}
  set name $def($i)
  puts -nonewline [format {#define %-16s %3d} $name $i]
  set com {}
  if {[info exists jump0($name)] && $jump0($name)} {
    lappend com "jump0"
  if {[info exists jump($name)] && $jump($name)} {
  } elseif {[info exists jump($name)] && $jump($name)} {
    lappend com "jump"
  }
  if {[info exists sameas($i)]} {
    lappend com "same as $sameas($i)"
  }
  if {[info exists synopsis($name)]} {
    lappend com "synopsis: $synopsis($name)"
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
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







+















+







    if {$jump($name)}  {incr x 1}
    if {$in1($name)}   {incr x 2}
    if {$in2($name)}   {incr x 4}
    if {$in3($name)}   {incr x 8}
    if {$out2($name)}  {incr x 16}
    if {$out3($name)}  {incr x 32}
    if {$ncycle($name)}  {incr x 64}
    if {$jump0($name)}   {incr x 128}
  }
  set bv($i) $x
}
puts ""
puts "/* Properties such as \"out2\" or \"jump\" that are specified in"
puts "** comments following the \"case\" for each opcode in the vdbe.c"
puts "** are encoded into bitvectors as follows:"
puts "*/"
puts "#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */"
puts "#define OPFLG_IN1         0x02  /* in1:   P1 is an input */"
puts "#define OPFLG_IN2         0x04  /* in2:   P2 is an input */"
puts "#define OPFLG_IN3         0x08  /* in3:   P3 is an input */"
puts "#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */"
puts "#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */"
puts "#define OPFLG_NCYCLE      0x40  /* ncycle:Cycles count against P1 */"
puts "#define OPFLG_JUMP0       0x80  /* jump0:  P2 might be zero */"
puts "#define OPFLG_INITIALIZER \173\\"
for {set i 0} {$i<=$max} {incr i} {
  if {$i%8==0} {
    puts -nonewline [format "/* %3d */" $i]
  }
  puts -nonewline [format " 0x%02x," $bv($i)]
  if {$i%8==7} {
Changes to tool/mksqlite3c.tcl.
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27







-
+







# For example, the "parse.c" and "parse.h" files to implement the
# the parser are derived from "parse.y" using lemon.  And the
# "keywordhash.h" files is generated by a program named "mkkeywordhash".
#
# After the "tsrc" directory has been created and populated, run
# this script:
#
#      tclsh mksqlite3c.tcl
#      tclsh mksqlite3c.tcl [flags] [extra source files]
#
# The amalgamated SQLite code will be written into sqlite3.c
#

set help {Usage: tclsh mksqlite3c.tcl <options>
 where <options> is zero or more of the following with these effects:
   --nostatic     => Do not generate with compile-time modifiable linkage.
38
39
40
41
42
43
44

45
46
47
48
49
50
51
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52







+







#

set addstatic 1
set linemacros 0
set useapicall 0
set enable_recover 0
set srcdir tsrc
set extrasrc [list]

for {set i 0} {$i<[llength $argv]} {incr i} {
  set x [lindex $argv $i]
  if {[regexp {^-?-enable-recover$} $x]} {
    set enable_recover 1
  } elseif {[regexp {^-?-nostatic$} $x]} {
    set addstatic 0
59
60
61
62
63
64
65
66

67


68
69
70
71
72
73
74
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77







-
+

+
+







    if {$i==[llength $argv]} {
      error "No argument following $x"
    }
    set srcdir [lindex $argv $i]
  } elseif {[regexp {^-?-((help)|\?)$} $x]} {
    puts $help
    exit 0
  } else {
  } elseif {[regexp {^-?-} $x]} {
    error "unknown command-line option: $x"
  } else {
    lappend extrasrc $x
  }
}
set in [open $srcdir/sqlite3.h]
set cnt 0
set VERSION ?????
while {![eof $in]} {
  set line [gets $in]
345
346
347
348
349
350
351















352
353
354
355
356
357
358
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







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







      puts $out $line
    }
  }
  close $in
  section_comment "End of $tail"
}

# Read the source file named $filename and write it into the
# sqlite3.c output file. The only transformation is the trimming
# of EOL whitespace.
#
proc copy_file_verbatim {filename} {
  global out
  set in [open $filename r]
  set tail [file tail $filename]
  section_comment "Begin EXTRA_SRC file $tail"
  while {![eof $in]} {
    set line [string trimright [gets $in]]
    puts $out $line
  }
  section_comment "End of EXTRA_SRC $tail"
}

# Process the source files.  Process files containing commonly
# used subroutines first in order to help the compiler find
# inlining opportunities.
#
set flist {
   sqliteInt.h
466
467
468
469
470
471
472
473

474
475
476
477
478
479



480
481
482
483
484
485
486
487
488
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







-
+






+
+
+









   fts3_icu.c
   sqlite3rbu.c
   dbstat.c
   dbpage.c
   sqlite3session.c
   fts5.c
   stmt.c
} 
}
if {$enable_recover} {
  lappend flist sqlite3recover.c dbdata.c
}
foreach file $flist {
  copy_file $srcdir/$file
}
foreach file $extrasrc {
  copy_file_verbatim $file
}

puts $out \
"/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }"

puts $out \
"/************************** End of sqlite3.c ******************************/"

close $out
Changes to tool/speed-check.sh.
157
158
159
160
161
162
163



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







+
+
+







        ;;
    --cte)
        SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset cte"
        ;;
    --fp)
        SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset fp"
        ;;
    --parsenumber)
        SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset parsenumber"
        ;;
    --stmtscanstatus)
        SPEEDTEST_OPTS="$SPEEDTEST_OPTS --stmtscanstatus"
        ;;
    -*)
        CC_OPTS="$CC_OPTS $1"
        ;;
    *)
Changes to tool/sqldiff.c.
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
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







-
+
+











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







**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This is a utility program that computes the differences in content
** between two SQLite databases.
**
** To compile, simply link against SQLite.
** To compile, simply link against SQLite.  (Windows builds must also link
** against ext/consio/console_io.c.)
**
** See the showHelp() routine below for a brief description of how to
** run the utility.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include "sqlite3.h"

/* Output function substitutions that cause UTF8 characters to be rendered
** correctly on Windows:
**
**     fprintf()  ->  Wfprintf()
**     
*/
#if defined(_WIN32)
# include "console_io.h"
# define Wfprintf fPrintfUtf8
#else
# define Wfprintf fprintf
#endif

/*
** All global variables are gathered into the "g" singleton.
*/
struct GlobalVars {
  const char *zArgv0;       /* Name of program */
  int bSchemaOnly;          /* Only show schema differences */
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
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







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

-
+
-
-
-
+







+

-

-
+

+
+
-
+








+

-

-
+

-
+
+


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







/*
** Allowed values for g.fDebug
*/
#define DEBUG_COLUMN_NAMES  0x000001
#define DEBUG_DIFF_SQL      0x000002

/*
** Dynamic string object
*/
typedef struct Str Str;
struct Str {
  char *z;        /* Text of the string */
  int nAlloc;     /* Bytes allocated in z[] */
  int nUsed;      /* Bytes actually used in z[] */
};

** Clear and free an sqlite3_str object
/*
** Initialize a Str object
*/
static void strInit(Str *p){
static void strFree(sqlite3_str *pStr){
  p->z = 0;
  p->nAlloc = 0;
  p->nUsed = 0;
  sqlite3_free(sqlite3_str_finish(pStr));
}
  
/*
** Print an error resulting from faulting command-line arguments and
** abort the program.
*/
static void cmdlineError(const char *zFormat, ...){
  sqlite3_str *pOut = sqlite3_str_new(0);
  va_list ap;
  fprintf(stderr, "%s: ", g.zArgv0);
  va_start(ap, zFormat);
  vfprintf(stderr, zFormat, ap);
  sqlite3_str_vappendf(pOut, zFormat, ap);
  va_end(ap);
  Wfprintf(stderr, "%s: %s\n", g.zArgv0, sqlite3_str_value(pOut));
  strFree(pOut);
  fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0);
  Wfprintf(stderr, "\"%s --help\" for more help\n", g.zArgv0);
  exit(1);
}

/*
** Print an error message for an error that occurs at runtime, then
** abort the program.
*/
static void runtimeError(const char *zFormat, ...){
  sqlite3_str *pOut = sqlite3_str_new(0);
  va_list ap;
  fprintf(stderr, "%s: ", g.zArgv0);
  va_start(ap, zFormat);
  vfprintf(stderr, zFormat, ap);
  sqlite3_str_vappendf(pOut, zFormat, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  Wfprintf(stderr, "%s: %s\n", g.zArgv0, sqlite3_str_value(pOut));
  strFree(pOut);
  exit(1);
}

/*
** Free all memory held by a Str object
*/
static void strFree(Str *p){
  sqlite3_free(p->z);
  strInit(p);
}

/*
** Add formatted text to the end of a Str object
*/
static void strPrintf(Str *p, const char *zFormat, ...){
  int nNew;
  for(;;){
    if( p->z ){
      va_list ap;
      va_start(ap, zFormat);
      sqlite3_vsnprintf(p->nAlloc-p->nUsed, p->z+p->nUsed, zFormat, ap);
      va_end(ap);
      nNew = (int)strlen(p->z + p->nUsed);
    }else{
      nNew = p->nAlloc;
    }
    if( p->nUsed+nNew < p->nAlloc-1 ){
      p->nUsed += nNew;
      break;
    }
    p->nAlloc = p->nAlloc*2 + 1000;
    p->z = sqlite3_realloc(p->z, p->nAlloc);
    if( p->z==0 ) runtimeError("out of memory");
  }
}



/* Safely quote an SQL identifier.  Use the minimum amount of transformation
** necessary to allow the string to be used with %s.
**
** Space to hold the returned string is obtained from sqlite3_malloc().  The
** caller is responsible for ensuring this space is freed when no longer
449
450
451
452
453
454
455
456

457
458
459
460
461
462
463
464
465

466
467
468

469
470

471
472
473
474

475
476
477

478
479
480

481
482
483
484
485



486
487
488

489
490
491

492
493
494
495
496

497
498
499

500
501
502
503

504
505
506

507
508
509
510
511
512

513
514
515
516
517
518
519
420
421
422
423
424
425
426

427
428
429
430
431
432
433
434
435

436
437
438

439
440

441

442
443

444
445
446

447
448
449

450
451
452



453
454
455
456
457

458
459
460

461
462
463
464
465

466
467
468

469
470
471
472

473
474
475

476
477
478
479
480
481

482
483
484
485
486
487
488
489







-
+








-
+


-
+

-
+
-


-
+


-
+


-
+


-
-
-
+
+
+


-
+


-
+




-
+


-
+



-
+


-
+





-
+







  char *zId = safeId(zTab); /* Name of the table */
  char **az = 0;            /* List of columns */
  int nPk;                  /* Number of true primary key columns */
  int nCol;                 /* Number of data columns */
  int i;                    /* Loop counter */
  sqlite3_stmt *pStmt;      /* SQL statement */
  const char *zSep;         /* Separator string */
  Str ins;                  /* Beginning of the INSERT statement */
  sqlite3_str *pIns;        /* Beginning of the INSERT statement */

  pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema WHERE name=%Q", zTab);
  if( SQLITE_ROW==sqlite3_step(pStmt) ){
    fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
  }
  sqlite3_finalize(pStmt);
  if( !g.bSchemaOnly ){
    az = columnNames("aux", zTab, &nPk, 0);
    strInit(&ins);
    pIns = sqlite3_str_new(0);
    if( az==0 ){
      pStmt = db_prepare("SELECT * FROM aux.%s", zId);
      strPrintf(&ins,"INSERT INTO %s VALUES", zId);
      sqlite3_str_appendf(pIns,"INSERT INTO %s VALUES", zId);
    }else{
      Str sql;
      sqlite3_str *pSql = sqlite3_str_new(0);
      strInit(&sql);
      zSep =  "SELECT";
      for(i=0; az[i]; i++){
        strPrintf(&sql, "%s %s", zSep, az[i]);
        sqlite3_str_appendf(pSql, "%s %s", zSep, az[i]);
        zSep = ",";
      }
      strPrintf(&sql," FROM aux.%s", zId);
      sqlite3_str_appendf(pSql," FROM aux.%s", zId);
      zSep = " ORDER BY";
      for(i=1; i<=nPk; i++){
        strPrintf(&sql, "%s %d", zSep, i);
        sqlite3_str_appendf(pSql, "%s %d", zSep, i);
        zSep = ",";
      }
      pStmt = db_prepare("%s", sql.z);
      strFree(&sql);
      strPrintf(&ins, "INSERT INTO %s", zId);
      pStmt = db_prepare("%s", sqlite3_str_value(pSql));
      strFree(pSql);
      sqlite3_str_appendf(pIns, "INSERT INTO %s", zId);
      zSep = "(";
      for(i=0; az[i]; i++){
        strPrintf(&ins, "%s%s", zSep, az[i]);
        sqlite3_str_appendf(pIns, "%s%s", zSep, az[i]);
        zSep = ",";
      }
      strPrintf(&ins,") VALUES");
      sqlite3_str_appendf(pIns,") VALUES");
      namelistFree(az);
    }
    nCol = sqlite3_column_count(pStmt);
    while( SQLITE_ROW==sqlite3_step(pStmt) ){
      fprintf(out, "%s",ins.z);
      Wfprintf(out, "%s",sqlite3_str_value(pIns));
      zSep = "(";
      for(i=0; i<nCol; i++){
        fprintf(out, "%s",zSep);
        Wfprintf(out, "%s",zSep);
        printQuoted(out, sqlite3_column_value(pStmt,i));
        zSep = ",";
      }
      fprintf(out, ");\n");
      Wfprintf(out, ");\n");
    }
    sqlite3_finalize(pStmt);
    strFree(&ins);
    strFree(pIns);
  } /* endif !g.bSchemaOnly */
  pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema"
                     " WHERE type='index' AND tbl_name=%Q AND sql IS NOT NULL",
                     zTab);
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
    Wfprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
  }
  sqlite3_finalize(pStmt);
  sqlite3_free(zId);
}


/*
527
528
529
530
531
532
533
534

535
536
537
538
539

540
541
542
543
544
545
546
547

548
549

550
551
552


553
554

555
556
557
558
559
560
561
562
563

564
565

566
567
568
569
570
571
572
573
574



575

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
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
497
498
499
500
501
502
503

504
505
506
507
508

509
510
511
512
513
514
515
516

517
518

519
520


521
522
523

524
525
526
527
528
529
530
531
532

533
534

535
536
537
538
539
540
541



542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562

563
564
565
566
567
568
569
570

571
572
573
574
575
576
577

578
579
580

581
582

583
584
585
586
587

588
589
590
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
661
662
663
664







-
+




-
+







-
+

-
+

-
-
+
+

-
+








-
+

-
+






-
-
-
+
+
+

+
















-
+







-
+






-
+


-
+

-
+




-
+



-
+


-
+




-
+





-
+




-
+



-
+


-
+

-
+


-
-
+
+


-
+


-
+


-
+


-
+

-
+


-
-
+
+


-
+


-
+


-
+


-
+


-
+







  int nPk;                  /* Primary key columns in main */
  int nPk2;                 /* Primary key columns in aux */
  int n = 0;                /* Number of columns in main */
  int n2;                   /* Number of columns in aux */
  int nQ;                   /* Number of output columns in the diff query */
  int i;                    /* Loop counter */
  const char *zSep;         /* Separator string */
  Str sql;                  /* Comparison query */
  sqlite3_str *pSql;        /* Comparison query */
  sqlite3_stmt *pStmt;      /* Query statement to do the diff */
  const char *zLead =       /* Becomes line-comment for sqlite_schema */
    (g.bSchemaCompare)? "-- " : "";

  strInit(&sql);
  pSql = sqlite3_str_new(0);
  if( g.fDebug==DEBUG_COLUMN_NAMES ){
    /* Simply run columnNames() on all tables of the origin
    ** database and show the results.  This is used for testing
    ** and debugging of the columnNames() function.
    */
    az = columnNames("aux",zTab, &nPk, 0);
    if( az==0 ){
      printf("Rowid not accessible for %s\n", zId);
      Wfprintf(stdout, "Rowid not accessible for %s\n", zId);
    }else{
      printf("%s:", zId);
      Wfprintf(stdout, "%s:", zId);
      for(i=0; az[i]; i++){
        printf(" %s", az[i]);
        if( i+1==nPk ) printf(" *");
        Wfprintf(stdout, " %s", az[i]);
        if( i+1==nPk ) Wfprintf(stdout, " *");
      }
      printf("\n");
      Wfprintf(stdout, "\n");
    }
    goto end_diff_one_table;
  }

  if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){
    if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
      /* Table missing from second database. */
      if( g.bSchemaCompare )
        fprintf(out, "-- 2nd DB has no %s table\n", zTab);
        Wfprintf(out, "-- 2nd DB has no %s table\n", zTab);
      else
        fprintf(out, "DROP TABLE %s;\n", zId);
        Wfprintf(out, "DROP TABLE %s;\n", zId);
    }
    goto end_diff_one_table;
  }

  if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
    /* Table missing from source */
    if( g.bSchemaCompare )
      fprintf(out, "-- 1st DB has no %s table\n", zTab);
    else
    if( g.bSchemaCompare ){
      Wfprintf(out, "-- 1st DB has no %s table\n", zTab);
    }else{
      dump_table(zTab, out);
    }
    goto end_diff_one_table;
  }

  az = columnNames("main", zTab, &nPk, 0);
  az2 = columnNames("aux", zTab, &nPk2, 0);
  if( az && az2 ){
    for(n=0; az[n] && az2[n]; n++){
      if( sqlite3_stricmp(az[n],az2[n])!=0 ) break;
    }
  }
  if( az==0
   || az2==0
   || nPk!=nPk2
   || az[n]
  ){
    /* Schema mismatch */
    fprintf(out, "%sDROP TABLE %s; -- due to schema mismatch\n", zLead, zId);
    Wfprintf(out, "%sDROP TABLE %s; -- due to schema mismatch\n", zLead, zId);
    dump_table(zTab, out);
    goto end_diff_one_table;
  }

  /* Build the comparison query */
  for(n2=n; az2[n2]; n2++){
    char *zNTab = safeId(az2[n2]);
    fprintf(out, "ALTER TABLE %s ADD COLUMN %s;\n", zId, zNTab);
    Wfprintf(out, "ALTER TABLE %s ADD COLUMN %s;\n", zId, zNTab);
    sqlite3_free(zNTab);
  }
  nQ = nPk2+1+2*(n2-nPk2);
  if( n2>nPk2 ){
    zSep = "SELECT ";
    for(i=0; i<nPk; i++){
      strPrintf(&sql, "%sB.%s", zSep, az[i]);
      sqlite3_str_appendf(pSql, "%sB.%s", zSep, az[i]);
      zSep = ", ";
    }
    strPrintf(&sql, ", 1 /* changed row */");
    sqlite3_str_appendf(pSql, ", 1 /* changed row */");
    while( az[i] ){
      strPrintf(&sql, ", A.%s IS NOT B.%s, B.%s",
      sqlite3_str_appendf(pSql, ", A.%s IS NOT B.%s, B.%s",
                az[i], az2[i], az2[i]);
      i++;
    }
    while( az2[i] ){
      strPrintf(&sql, ", B.%s IS NOT NULL, B.%s",
      sqlite3_str_appendf(pSql, ", B.%s IS NOT NULL, B.%s",
                az2[i], az2[i]);
      i++;
    }
    strPrintf(&sql, "\n  FROM main.%s A, aux.%s B\n", zId, zId);
    sqlite3_str_appendf(pSql, "\n  FROM main.%s A, aux.%s B\n", zId, zId);
    zSep = " WHERE";
    for(i=0; i<nPk; i++){
      strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
      sqlite3_str_appendf(pSql, "%s A.%s=B.%s", zSep, az[i], az[i]);
      zSep = " AND";
    }
    zSep = "\n   AND (";
    while( az[i] ){
      strPrintf(&sql, "%sA.%s IS NOT B.%s%s\n",
      sqlite3_str_appendf(pSql, "%sA.%s IS NOT B.%s%s\n",
                zSep, az[i], az2[i], az2[i+1]==0 ? ")" : "");
      zSep = "        OR ";
      i++;
    }
    while( az2[i] ){
      strPrintf(&sql, "%sB.%s IS NOT NULL%s\n",
      sqlite3_str_appendf(pSql, "%sB.%s IS NOT NULL%s\n",
                zSep, az2[i], az2[i+1]==0 ? ")" : "");
      zSep = "        OR ";
      i++;
    }
    strPrintf(&sql, " UNION ALL\n");
    sqlite3_str_appendf(pSql, " UNION ALL\n");
  }
  zSep = "SELECT ";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%sA.%s", zSep, az[i]);
    sqlite3_str_appendf(pSql, "%sA.%s", zSep, az[i]);
    zSep = ", ";
  }
  strPrintf(&sql, ", 2 /* deleted row */");
  sqlite3_str_appendf(pSql, ", 2 /* deleted row */");
  while( az2[i] ){
    strPrintf(&sql, ", NULL, NULL");
    sqlite3_str_appendf(pSql, ", NULL, NULL");
    i++;
  }
  strPrintf(&sql, "\n  FROM main.%s A\n", zId);
  strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId);
  sqlite3_str_appendf(pSql, "\n  FROM main.%s A\n", zId);
  sqlite3_str_appendf(pSql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId);
  zSep =          "                   WHERE";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    zSep = " AND";
  }
  strPrintf(&sql, ")\n");
  sqlite3_str_appendf(pSql, ")\n");
  zSep = " UNION ALL\nSELECT ";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%sB.%s", zSep, az[i]);
    sqlite3_str_appendf(pSql, "%sB.%s", zSep, az[i]);
    zSep = ", ";
  }
  strPrintf(&sql, ", 3 /* inserted row */");
  sqlite3_str_appendf(pSql, ", 3 /* inserted row */");
  while( az2[i] ){
    strPrintf(&sql, ", 1, B.%s", az2[i]);
    sqlite3_str_appendf(pSql, ", 1, B.%s", az2[i]);
    i++;
  }
  strPrintf(&sql, "\n  FROM aux.%s B\n", zId);
  strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId);
  sqlite3_str_appendf(pSql, "\n  FROM aux.%s B\n", zId);
  sqlite3_str_appendf(pSql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId);
  zSep =          "                   WHERE";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    zSep = " AND";
  }
  strPrintf(&sql, ")\n ORDER BY");
  sqlite3_str_appendf(pSql, ")\n ORDER BY");
  zSep = " ";
  for(i=1; i<=nPk; i++){
    strPrintf(&sql, "%s%d", zSep, i);
    sqlite3_str_appendf(pSql, "%s%d", zSep, i);
    zSep = ", ";
  }
  strPrintf(&sql, ";\n");
  sqlite3_str_appendf(pSql, ";\n");

  if( g.fDebug & DEBUG_DIFF_SQL ){ 
    printf("SQL for %s:\n%s\n", zId, sql.z);
    printf("SQL for %s:\n%s\n", zId, sqlite3_str_value(pSql));
    goto end_diff_one_table;
  }

  /* Drop indexes that are missing in the destination */
  pStmt = db_prepare(
    "SELECT name FROM main.sqlite_schema"
    " WHERE type='index' AND tbl_name=%Q"
701
702
703
704
705
706
707
708

709
710
711
712
713
714
715
672
673
674
675
676
677
678

679
680
681
682
683
684
685
686







-
+







    fprintf(out, "DROP INDEX %s;\n", z);
    sqlite3_free(z);
  }
  sqlite3_finalize(pStmt);

  /* Run the query and output differences */
  if( !g.bSchemaOnly ){
    pStmt = db_prepare("%s", sql.z);
    pStmt = db_prepare("%s", sqlite3_str_value(pSql));
    while( SQLITE_ROW==sqlite3_step(pStmt) ){
      int iType = sqlite3_column_int(pStmt, nPk);
      if( iType==1 || iType==2 ){
        if( iType==1 ){       /* Change the content of a row */
          fprintf(out, "%sUPDATE %s", zLead, zId);
          zSep = " SET";
          for(i=nPk+1; i<nQ; i+=2){
759
760
761
762
763
764
765
766

767
768
769
770
771
772
773
730
731
732
733
734
735
736

737
738
739
740
741
742
743
744







-
+







    zTab, zTab);
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
  }
  sqlite3_finalize(pStmt);

end_diff_one_table:
  strFree(&sql);
  strFree(pSql);
  sqlite3_free(zId);
  namelistFree(az);
  namelistFree(az2);
  return;
}

/*
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
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







-
+






-
-
+
+








-
+




-
+

-
+

-
-
-
+
+
+

-
+



-
+


-
+


-
+

-
-
-
+
+
+

-
+






-
+

-
+





-
+

-
+

-
+




-
+

-
+




-
+
+

-
+



-
-
+
+








-
-
-
+
+
+





+
+
+













-
-
-
-
+
+
+
+


-
+



-
-
-
-
+
+
+
+

-
+




-
+

-
-
-
+
+
+



-
+







}

/*
** End of code copied from fossil.
**************************************************************************/

static void strPrintfArray(
  Str *pStr,                      /* String object to append to */
  sqlite3_str *pStr,              /* String object to append to */
  const char *zSep,               /* Separator string */
  const char *zFmt,               /* Format for each entry */
  char **az, int n                /* Array of strings & its size (or -1) */
){
  int i;
  for(i=0; az[i] && (i<n || n<0); i++){
    if( i!=0 ) strPrintf(pStr, "%s", zSep);
    strPrintf(pStr, zFmt, az[i], az[i], az[i]);
    if( i!=0 ) sqlite3_str_appendf(pStr, "%s", zSep);
    sqlite3_str_appendf(pStr, zFmt, az[i], az[i], az[i]);
  }
}

static void getRbudiffQuery(
  const char *zTab,
  char **azCol,
  int nPK,
  int bOtaRowid,
  Str *pSql
  sqlite3_str *pSql
){
  int i;

  /* First the newly inserted rows: **/ 
  strPrintf(pSql, "SELECT ");
  sqlite3_str_appendf(pSql, "SELECT ");
  strPrintfArray(pSql, ", ", "%s", azCol, -1);
  strPrintf(pSql, ", 0, ");       /* Set ota_control to 0 for an insert */
  sqlite3_str_appendf(pSql, ", 0, ");  /* Set ota_control to 0 for an insert */
  strPrintfArray(pSql, ", ", "NULL", azCol, -1);
  strPrintf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab);
  strPrintf(pSql, "    SELECT 1 FROM ", zTab);
  strPrintf(pSql, " main.%Q AS o WHERE ", zTab);
  sqlite3_str_appendf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab);
  sqlite3_str_appendf(pSql, "    SELECT 1 FROM ", zTab);
  sqlite3_str_appendf(pSql, " main.%Q AS o WHERE ", zTab);
  strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK);
  strPrintf(pSql, "\n) AND ");
  sqlite3_str_appendf(pSql, "\n) AND ");
  strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK);

  /* Deleted rows: */
  strPrintf(pSql, "\nUNION ALL\nSELECT ");
  sqlite3_str_appendf(pSql, "\nUNION ALL\nSELECT ");
  strPrintfArray(pSql, ", ", "%s", azCol, nPK);
  if( azCol[nPK] ){
    strPrintf(pSql, ", ");
    sqlite3_str_appendf(pSql, ", ");
    strPrintfArray(pSql, ", ", "NULL", &azCol[nPK], -1);
  }
  strPrintf(pSql, ", 1, ");       /* Set ota_control to 1 for a delete */
  sqlite3_str_appendf(pSql, ", 1, ");   /* Set ota_control to 1 for a delete */
  strPrintfArray(pSql, ", ", "NULL", azCol, -1);
  strPrintf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab);
  strPrintf(pSql, "    SELECT 1 FROM ", zTab);
  strPrintf(pSql, " aux.%Q AS o WHERE ", zTab);
  sqlite3_str_appendf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab);
  sqlite3_str_appendf(pSql, "    SELECT 1 FROM ", zTab);
  sqlite3_str_appendf(pSql, " aux.%Q AS o WHERE ", zTab);
  strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK);
  strPrintf(pSql, "\n) AND ");
  sqlite3_str_appendf(pSql, "\n) AND ");
  strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK);

  /* Updated rows. If all table columns are part of the primary key, there 
  ** can be no updates. In this case this part of the compound SELECT can
  ** be omitted altogether. */
  if( azCol[nPK] ){
    strPrintf(pSql, "\nUNION ALL\nSELECT ");
    sqlite3_str_appendf(pSql, "\nUNION ALL\nSELECT ");
    strPrintfArray(pSql, ", ", "n.%s", azCol, nPK);
    strPrintf(pSql, ",\n");
    sqlite3_str_appendf(pSql, ",\n");
    strPrintfArray(pSql, " ,\n", 
        "    CASE WHEN n.%s IS o.%s THEN NULL ELSE n.%s END", &azCol[nPK], -1
    );

    if( bOtaRowid==0 ){
      strPrintf(pSql, ", '");
      sqlite3_str_appendf(pSql, ", '");
      strPrintfArray(pSql, "", ".", azCol, nPK);
      strPrintf(pSql, "' ||\n");
      sqlite3_str_appendf(pSql, "' ||\n");
    }else{
      strPrintf(pSql, ",\n");
      sqlite3_str_appendf(pSql, ",\n");
    }
    strPrintfArray(pSql, " ||\n", 
        "    CASE WHEN n.%s IS o.%s THEN '.' ELSE 'x' END", &azCol[nPK], -1
    );
    strPrintf(pSql, "\nAS ota_control, ");
    sqlite3_str_appendf(pSql, "\nAS ota_control, ");
    strPrintfArray(pSql, ", ", "NULL", azCol, nPK);
    strPrintf(pSql, ",\n");
    sqlite3_str_appendf(pSql, ",\n");
    strPrintfArray(pSql, " ,\n", 
        "    CASE WHEN n.%s IS o.%s THEN NULL ELSE o.%s END", &azCol[nPK], -1
    );

    strPrintf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ", zTab, zTab);
    sqlite3_str_appendf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ",
                        zTab, zTab);
    strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK);
    strPrintf(pSql, " AND ota_control LIKE '%%x%%'");
    sqlite3_str_appendf(pSql, " AND ota_control LIKE '%%x%%'");
  }

  /* Now add an ORDER BY clause to sort everything by PK. */
  strPrintf(pSql, "\nORDER BY ");
  for(i=1; i<=nPK; i++) strPrintf(pSql, "%s%d", ((i>1)?", ":""), i);
  sqlite3_str_appendf(pSql, "\nORDER BY ");
  for(i=1; i<=nPK; i++) sqlite3_str_appendf(pSql, "%s%d", ((i>1)?", ":""), i);
}

static void rbudiff_one_table(const char *zTab, FILE *out){
  int bOtaRowid;                  /* True to use an ota_rowid column */
  int nPK;                        /* Number of primary key columns in table */
  char **azCol;                   /* NULL terminated array of col names */
  int i;
  int nCol;
  Str ct = {0, 0, 0};             /* The "CREATE TABLE data_xxx" statement */
  Str sql = {0, 0, 0};            /* Query to find differences */
  Str insert = {0, 0, 0};         /* First part of output INSERT statement */
  sqlite3_str *pCt;               /* The "CREATE TABLE data_xxx" statement */
  sqlite3_str *pSql;              /* Query to find differences */
  sqlite3_str *pInsert;           /* First part of output INSERT statement */
  sqlite3_stmt *pStmt = 0;
  int nRow = 0;                   /* Total rows in data_xxx table */

  /* --rbu mode must use real primary keys. */
  g.bSchemaPK = 1;
  pCt = sqlite3_str_new(0);
  pSql = sqlite3_str_new(0);
  pInsert = sqlite3_str_new(0);

  /* Check that the schemas of the two tables match. Exit early otherwise. */
  checkSchemasMatch(zTab);

  /* Grab the column names and PK details for the table(s). If no usable PK
  ** columns are found, bail out early.  */
  azCol = columnNames("main", zTab, &nPK, &bOtaRowid);
  if( azCol==0 ){
    runtimeError("table %s has no usable PK columns", zTab);
  }
  for(nCol=0; azCol[nCol]; nCol++);

  /* Build and output the CREATE TABLE statement for the data_xxx table */
  strPrintf(&ct, "CREATE TABLE IF NOT EXISTS 'data_%q'(", zTab);
  if( bOtaRowid ) strPrintf(&ct, "rbu_rowid, ");
  strPrintfArray(&ct, ", ", "%s", &azCol[bOtaRowid], -1);
  strPrintf(&ct, ", rbu_control);");
  sqlite3_str_appendf(pCt, "CREATE TABLE IF NOT EXISTS 'data_%q'(", zTab);
  if( bOtaRowid ) sqlite3_str_appendf(pCt, "rbu_rowid, ");
  strPrintfArray(pCt, ", ", "%s", &azCol[bOtaRowid], -1);
  sqlite3_str_appendf(pCt, ", rbu_control);");

  /* Get the SQL for the query to retrieve data from the two databases */
  getRbudiffQuery(zTab, azCol, nPK, bOtaRowid, &sql);
  getRbudiffQuery(zTab, azCol, nPK, bOtaRowid, pSql);

  /* Build the first part of the INSERT statement output for each row
  ** in the data_xxx table. */
  strPrintf(&insert, "INSERT INTO 'data_%q' (", zTab);
  if( bOtaRowid ) strPrintf(&insert, "rbu_rowid, ");
  strPrintfArray(&insert, ", ", "%s", &azCol[bOtaRowid], -1);
  strPrintf(&insert, ", rbu_control) VALUES(");
  sqlite3_str_appendf(pInsert, "INSERT INTO 'data_%q' (", zTab);
  if( bOtaRowid ) sqlite3_str_appendf(pInsert, "rbu_rowid, ");
  strPrintfArray(pInsert, ", ", "%s", &azCol[bOtaRowid], -1);
  sqlite3_str_appendf(pInsert, ", rbu_control) VALUES(");

  pStmt = db_prepare("%s", sql.z);
  pStmt = db_prepare("%s", sqlite3_str_value(pSql));

  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    
    /* If this is the first row output, print out the CREATE TABLE 
    ** statement first. And then set ct.z to NULL so that it is not 
    ** statement first. And reset pCt so that it will not be
    ** printed again.  */
    if( ct.z ){
      fprintf(out, "%s\n", ct.z);
      strFree(&ct);
    if( sqlite3_str_length(pCt) ){
      fprintf(out, "%s\n", sqlite3_str_value(pCt));
      sqlite3_str_reset(pCt);
    }

    /* Output the first part of the INSERT statement */
    fprintf(out, "%s", insert.z);
    fprintf(out, "%s", sqlite3_str_value(pInsert));
    nRow++;

    if( sqlite3_column_type(pStmt, nCol)==SQLITE_INTEGER ){
      for(i=0; i<=nCol; i++){
        if( i>0 ) fprintf(out, ", ");
        printQuoted(out, sqlite3_column_value(pStmt, i));
      }
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375





1376
1377
1378
1379
1380



1381
1382
1383
1384
1385
1386
1387
1340
1341
1342
1343
1344
1345
1346




1347
1348
1349
1350
1351
1352
1353



1354
1355
1356
1357
1358
1359
1360
1361
1362
1363







-
-
-
-
+
+
+
+
+


-
-
-
+
+
+








    /* And the closing bracket of the insert statement */
    fprintf(out, ");\n");
  }

  sqlite3_finalize(pStmt);
  if( nRow>0 ){
    Str cnt = {0, 0, 0};
    strPrintf(&cnt, "INSERT INTO rbu_count VALUES('data_%q', %d);", zTab, nRow);
    fprintf(out, "%s\n", cnt.z);
    strFree(&cnt);
    sqlite3_str *pCnt = sqlite3_str_new(0);
    sqlite3_str_appendf(pCnt,
         "INSERT INTO rbu_count VALUES('data_%q', %d);", zTab, nRow);
    fprintf(out, "%s\n", sqlite3_str_value(pCnt));
    strFree(pCnt);
  }

  strFree(&ct);
  strFree(&sql);
  strFree(&insert);
  strFree(pCt);
  strFree(pSql);
  strFree(pInsert);
}

/*
** Display a summary of differences between two versions of the same
** table table.
**
**   *  Number of rows changed
1395
1396
1397
1398
1399
1400
1401
1402

1403
1404
1405
1406
1407
1408
1409

1410
1411
1412
1413

1414
1415
1416
1417
1418
1419
1420

1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437

1438
1439
1440
1441
1442
1443

1444
1445

1446
1447
1448
1449

1450
1451
1452

1453
1454

1455
1456
1457

1458
1459
1460
1461
1462
1463




1464
1465
1466

1467
1468
1469
1470
1471
1472
1473





1474
1475
1476

1477
1478
1479

1480
1481
1482

1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506

1507

1508
1509
1510
1511

1512
1513
1514
1515
1516
1517
1518
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
1492
1493
1494
1495







-
+






-
+



-
+






-
+
















-
+





-
+

-
+



-
+


-
+

-
+


-
+


-
-
-
-
+
+
+
+


-
+


-
-
-
-
-
+
+
+
+
+


-
+


-
+


-
+




-
+



















+
-
+



-
+







  char **az2 = 0;           /* Columns in aux */
  int nPk;                  /* Primary key columns in main */
  int nPk2;                 /* Primary key columns in aux */
  int n = 0;                /* Number of columns in main */
  int n2;                   /* Number of columns in aux */
  int i;                    /* Loop counter */
  const char *zSep;         /* Separator string */
  Str sql;                  /* Comparison query */
  sqlite3_str *pSql;        /* Comparison query */
  sqlite3_stmt *pStmt;      /* Query statement to do the diff */
  sqlite3_int64 nUpdate;    /* Number of updated rows */
  sqlite3_int64 nUnchanged; /* Number of unmodified rows */
  sqlite3_int64 nDelete;    /* Number of deleted rows */
  sqlite3_int64 nInsert;    /* Number of inserted rows */

  strInit(&sql);
  pSql = sqlite3_str_new(0);
  if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){
    if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
      /* Table missing from second database. */
      fprintf(out, "%s: missing from second database\n", zTab);
      Wfprintf(out, "%s: missing from second database\n", zTab);
    }
    goto end_summarize_one_table;
  }

  if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){
    /* Table missing from source */
    fprintf(out, "%s: missing from first database\n", zTab);
    Wfprintf(out, "%s: missing from first database\n", zTab);
    goto end_summarize_one_table;
  }

  az = columnNames("main", zTab, &nPk, 0);
  az2 = columnNames("aux", zTab, &nPk2, 0);
  if( az && az2 ){
    for(n=0; az[n]; n++){
      if( sqlite3_stricmp(az[n],az2[n])!=0 ) break;
    }
  }
  if( az==0
   || az2==0
   || nPk!=nPk2
   || az[n]
  ){
    /* Schema mismatch */
    fprintf(out, "%s: incompatible schema\n", zTab);
    Wfprintf(out, "%s: incompatible schema\n", zTab);
    goto end_summarize_one_table;
  }

  /* Build the comparison query */
  for(n2=n; az[n2]; n2++){}
  strPrintf(&sql, "SELECT 1, count(*)");
  sqlite3_str_appendf(pSql, "SELECT 1, count(*)");
  if( n2==nPk2 ){
    strPrintf(&sql, ", 0\n");
    sqlite3_str_appendf(pSql, ", 0\n");
  }else{
    zSep = ", sum(";
    for(i=nPk; az[i]; i++){
      strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, az[i], az[i]);
      sqlite3_str_appendf(pSql, "%sA.%s IS NOT B.%s", zSep, az[i], az[i]);
      zSep = " OR ";
    }
    strPrintf(&sql, ")\n");
    sqlite3_str_appendf(pSql, ")\n");
  }
  strPrintf(&sql, "  FROM main.%s A, aux.%s B\n", zId, zId);
  sqlite3_str_appendf(pSql, "  FROM main.%s A, aux.%s B\n", zId, zId);
  zSep = " WHERE";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    zSep = " AND";
  }
  strPrintf(&sql, " UNION ALL\n");
  strPrintf(&sql, "SELECT 2, count(*), 0\n");
  strPrintf(&sql, "  FROM main.%s A\n", zId);
  strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B ", zId);
  sqlite3_str_appendf(pSql, " UNION ALL\n");
  sqlite3_str_appendf(pSql, "SELECT 2, count(*), 0\n");
  sqlite3_str_appendf(pSql, "  FROM main.%s A\n", zId);
  sqlite3_str_appendf(pSql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B ", zId);
  zSep = "WHERE";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    zSep = " AND";
  }
  strPrintf(&sql, ")\n");
  strPrintf(&sql, " UNION ALL\n");
  strPrintf(&sql, "SELECT 3, count(*), 0\n");
  strPrintf(&sql, "  FROM aux.%s B\n", zId);
  strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A ", zId);
  sqlite3_str_appendf(pSql, ")\n");
  sqlite3_str_appendf(pSql, " UNION ALL\n");
  sqlite3_str_appendf(pSql, "SELECT 3, count(*), 0\n");
  sqlite3_str_appendf(pSql, "  FROM aux.%s B\n", zId);
  sqlite3_str_appendf(pSql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A ", zId);
  zSep = "WHERE";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s", zSep, az[i], az[i]);
    zSep = " AND";
  }
  strPrintf(&sql, ")\n ORDER BY 1;\n");
  sqlite3_str_appendf(pSql, ")\n ORDER BY 1;\n");

  if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){ 
    printf("SQL for %s:\n%s\n", zId, sql.z);
    Wfprintf(stdout, "SQL for %s:\n%s\n", zId, sqlite3_str_value(pSql));
    goto end_summarize_one_table;
  }

  /* Run the query and output difference summary */
  pStmt = db_prepare("%s", sql.z);
  pStmt = db_prepare("%s", sqlite3_str_value(pSql));
  nUpdate = 0;
  nInsert = 0;
  nDelete = 0;
  nUnchanged = 0;
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    switch( sqlite3_column_int(pStmt,0) ){
      case 1:
        nUpdate = sqlite3_column_int64(pStmt,2);
        nUnchanged = sqlite3_column_int64(pStmt,1) - nUpdate;
        break;
      case 2:
        nDelete = sqlite3_column_int64(pStmt,1);
        break;
      case 3:
        nInsert = sqlite3_column_int64(pStmt,1);
        break;
    }
  }
  sqlite3_finalize(pStmt);
  Wfprintf(out,
  fprintf(out, "%s: %lld changes, %lld inserts, %lld deletes, %lld unchanged\n",
          "%s: %lld changes, %lld inserts, %lld deletes, %lld unchanged\n",
          zTab, nUpdate, nInsert, nDelete, nUnchanged);

end_summarize_one_table:
  strFree(&sql);
  strFree(pSql);
  sqlite3_free(zId);
  namelistFree(az);
  namelistFree(az2);
  return;
}

/*
1584
1585
1586
1587
1588
1589
1590
1591

1592
1593
1594
1595
1596
1597

1598
1599
1600
1601
1602
1603
1604
1561
1562
1563
1564
1565
1566
1567

1568
1569
1570
1571
1572
1573

1574
1575
1576
1577
1578
1579
1580
1581







-
+





-
+







  sqlite3_stmt *pStmt;          /* SQL statment */
  char *zId = safeId(zTab);     /* Escaped name of the table */
  char **azCol = 0;             /* List of escaped column names */
  int nCol = 0;                 /* Number of columns */
  int *aiFlg = 0;               /* 0 if column is not part of PK */
  int *aiPk = 0;                /* Column numbers for each PK column */
  int nPk = 0;                  /* Number of PRIMARY KEY columns */
  Str sql;                      /* SQL for the diff query */
  sqlite3_str *pSql;            /* SQL for the diff query */
  int i, k;                     /* Loop counters */
  const char *zSep;             /* List separator */

  /* Check that the schemas of the two tables match. Exit early otherwise. */
  checkSchemasMatch(zTab);
  strInit(&sql);
  pSql = sqlite3_str_new(0);

  pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab);
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    nCol++;
    azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol);
    if( azCol==0 ) runtimeError("out of memory");
    aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol);
1613
1614
1615
1616
1617
1618
1619
1620

1621
1622
1623

1624
1625

1626
1627
1628
1629

1630
1631

1632

1633
1634
1635
1636
1637
1638

1639
1640
1641

1642
1643

1644
1645
1646

1647
1648

1649
1650
1651
1652


1653
1654

1655

1656
1657
1658
1659


1660
1661
1662

1663
1664

1665
1666
1667
1668


1669
1670

1671

1672
1673
1674
1675


1676
1677
1678

1679
1680
1681

1682
1683
1684

1685
1686
1687
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697
1698
1699
1700
1701
1590
1591
1592
1593
1594
1595
1596

1597
1598
1599

1600
1601

1602
1603
1604
1605

1606
1607
1608
1609

1610
1611
1612
1613
1614
1615

1616
1617
1618

1619
1620

1621
1622
1623

1624
1625

1626
1627
1628


1629
1630
1631
1632
1633

1634
1635
1636


1637
1638
1639
1640

1641
1642

1643
1644
1645


1646
1647
1648
1649
1650

1651
1652
1653


1654
1655
1656
1657

1658
1659
1660

1661
1662
1663

1664
1665
1666
1667
1668
1669
1670
1671
1672
1673

1674
1675
1676
1677
1678
1679
1680
1681







-
+


-
+

-
+



-
+


+
-
+





-
+


-
+

-
+


-
+

-
+


-
-
+
+


+
-
+


-
-
+
+


-
+

-
+


-
-
+
+


+
-
+


-
-
+
+


-
+


-
+


-
+









-
+







      }
      aiPk[i-1] = nCol-1;
    }
  }
  sqlite3_finalize(pStmt);
  if( nPk==0 ) goto end_changeset_one_table; 
  if( nCol>nPk ){
    strPrintf(&sql, "SELECT %d", SQLITE_UPDATE);
    sqlite3_str_appendf(pSql, "SELECT %d", SQLITE_UPDATE);
    for(i=0; i<nCol; i++){
      if( aiFlg[i] ){
        strPrintf(&sql, ",\n       A.%s", azCol[i]);
        sqlite3_str_appendf(pSql, ",\n       A.%s", azCol[i]);
      }else{
        strPrintf(&sql, ",\n       A.%s IS NOT B.%s, A.%s, B.%s",
        sqlite3_str_appendf(pSql, ",\n       A.%s IS NOT B.%s, A.%s, B.%s",
                  azCol[i], azCol[i], azCol[i], azCol[i]);
      }
    }
    strPrintf(&sql,"\n  FROM main.%s A, aux.%s B\n", zId, zId);
    sqlite3_str_appendf(pSql,"\n  FROM main.%s A, aux.%s B\n", zId, zId);
    zSep = " WHERE";
    for(i=0; i<nPk; i++){
      sqlite3_str_appendf(pSql, "%s A.%s=B.%s",
      strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
                          zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
      zSep = " AND";
    }
    zSep = "\n   AND (";
    for(i=0; i<nCol; i++){
      if( aiFlg[i] ) continue;
      strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, azCol[i], azCol[i]);
      sqlite3_str_appendf(pSql, "%sA.%s IS NOT B.%s", zSep, azCol[i], azCol[i]);
      zSep = " OR\n        ";
    }
    strPrintf(&sql,")\n UNION ALL\n");
    sqlite3_str_appendf(pSql,")\n UNION ALL\n");
  }
  strPrintf(&sql, "SELECT %d", SQLITE_DELETE);
  sqlite3_str_appendf(pSql, "SELECT %d", SQLITE_DELETE);
  for(i=0; i<nCol; i++){
    if( aiFlg[i] ){
      strPrintf(&sql, ",\n       A.%s", azCol[i]);
      sqlite3_str_appendf(pSql, ",\n       A.%s", azCol[i]);
    }else{
      strPrintf(&sql, ",\n       1, A.%s, NULL", azCol[i]);
      sqlite3_str_appendf(pSql, ",\n       1, A.%s, NULL", azCol[i]);
    }
  }
  strPrintf(&sql, "\n  FROM main.%s A\n", zId);
  strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId);
  sqlite3_str_appendf(pSql, "\n  FROM main.%s A\n", zId);
  sqlite3_str_appendf(pSql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId);
  zSep =          "                   WHERE";
  for(i=0; i<nPk; i++){
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s",
    strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
                        zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
    zSep = " AND";
  }
  strPrintf(&sql, ")\n UNION ALL\n");
  strPrintf(&sql, "SELECT %d", SQLITE_INSERT);
  sqlite3_str_appendf(pSql, ")\n UNION ALL\n");
  sqlite3_str_appendf(pSql, "SELECT %d", SQLITE_INSERT);
  for(i=0; i<nCol; i++){
    if( aiFlg[i] ){
      strPrintf(&sql, ",\n       B.%s", azCol[i]);
      sqlite3_str_appendf(pSql, ",\n       B.%s", azCol[i]);
    }else{
      strPrintf(&sql, ",\n       1, NULL, B.%s", azCol[i]);
      sqlite3_str_appendf(pSql, ",\n       1, NULL, B.%s", azCol[i]);
    }
  }
  strPrintf(&sql, "\n  FROM aux.%s B\n", zId);
  strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId);
  sqlite3_str_appendf(pSql, "\n  FROM aux.%s B\n", zId);
  sqlite3_str_appendf(pSql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId);
  zSep =          "                   WHERE";
  for(i=0; i<nPk; i++){
    sqlite3_str_appendf(pSql, "%s A.%s=B.%s",
    strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
                        zSep, azCol[aiPk[i]], azCol[aiPk[i]]);
    zSep = " AND";
  }
  strPrintf(&sql, ")\n");
  strPrintf(&sql, " ORDER BY");
  sqlite3_str_appendf(pSql, ")\n");
  sqlite3_str_appendf(pSql, " ORDER BY");
  zSep = " ";
  for(i=0; i<nPk; i++){
    strPrintf(&sql, "%s %d", zSep, aiPk[i]+2);
    sqlite3_str_appendf(pSql, "%s %d", zSep, aiPk[i]+2);
    zSep = ",";
  }
  strPrintf(&sql, ";\n");
  sqlite3_str_appendf(pSql, ";\n");

  if( g.fDebug & DEBUG_DIFF_SQL ){ 
    printf("SQL for %s:\n%s\n", zId, sql.z);
    Wfprintf(stdout, "SQL for %s:\n%s\n", zId, sqlite3_str_value(pSql));
    goto end_changeset_one_table;
  }

  putc('T', out);
  putsVarint(out, (sqlite3_uint64)nCol);
  for(i=0; i<nCol; i++) putc(aiFlg[i], out);
  fwrite(zTab, 1, strlen(zTab), out);
  putc(0, out);

  pStmt = db_prepare("%s", sql.z);
  pStmt = db_prepare("%s", sqlite3_str_value(pSql));
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    int iType = sqlite3_column_int(pStmt,0);
    putc(iType, out);
    putc(0, out);
    switch( sqlite3_column_int(pStmt,0) ){
      case SQLITE_UPDATE: {
        for(k=1, i=0; i<nCol; i++){
1754
1755
1756
1757
1758
1759
1760
1761

1762
1763
1764
1765
1766
1767
1768
1734
1735
1736
1737
1738
1739
1740

1741
1742
1743
1744
1745
1746
1747
1748







-
+







  
end_changeset_one_table:
  while( nCol>0 ) sqlite3_free(azCol[--nCol]);
  sqlite3_free(azCol);
  sqlite3_free(aiPk);
  sqlite3_free(zId);
  sqlite3_free(aiFlg);
  strFree(&sql);
  strFree(pSql);
}

/*
** Return true if the ascii character passed as the only argument is a
** whitespace character. Otherwise return false.
*/
static int is_whitespace(char x){
1907
1908
1909
1910
1911
1912
1913
1914
1915


1916
1917
1918
1919
1920
1921
1922
1887
1888
1889
1890
1891
1892
1893


1894
1895
1896
1897
1898
1899
1900
1901
1902







-
-
+
+







  }
}

/*
** Print sketchy documentation for this utility program
*/
static void showHelp(void){
  printf("Usage: %s [options] DB1 DB2\n", g.zArgv0);
  printf(
  Wfprintf(stdout, "Usage: %s [options] DB1 DB2\n", g.zArgv0);
  Wfprintf(stdout,
"Output SQL text that would transform DB1 into DB2.\n"
"Options:\n"
"  --changeset FILE      Write a CHANGESET into FILE\n"
"  -L|--lib LIBRARY      Load an SQLite extension library\n"
"  --primarykey          Use schema-defined PRIMARY KEYs\n"
"  --rbu                 Output SQL to create/populate RBU table(s)\n"
"  --schema              Show only differences in the schema\n"
2045
2046
2047
2048
2049
2050
2051
2052

2053
2054

2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069

2070
2071
2072
2073
2074
2075
2025
2026
2027
2028
2029
2030
2031

2032
2033

2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048

2049
2050
2051
2052
2053
2054
2055







-
+

-
+














-
+






  }
  rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_schema", 0, 0, &zErrMsg);
  if( rc || zErrMsg ){
    cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2);
  }

  if( neverUseTransaction ) useTransaction = 0;
  if( useTransaction ) fprintf(out, "BEGIN TRANSACTION;\n");
  if( useTransaction ) Wfprintf(out, "BEGIN TRANSACTION;\n");
  if( xDiff==rbudiff_one_table ){
    fprintf(out, "CREATE TABLE IF NOT EXISTS rbu_count"
    Wfprintf(out, "CREATE TABLE IF NOT EXISTS rbu_count"
           "(tbl TEXT PRIMARY KEY COLLATE NOCASE, cnt INTEGER) "
           "WITHOUT ROWID;\n"
    );
  }
  if( zTab ){
    xDiff(zTab, out);
  }else{
    /* Handle tables one by one */
    pStmt = db_prepare("%s", all_tables_sql() );
    while( SQLITE_ROW==sqlite3_step(pStmt) ){
      xDiff((const char*)sqlite3_column_text(pStmt,0), out);
    }
    sqlite3_finalize(pStmt);
  }
  if( useTransaction ) printf("COMMIT;\n");
  if( useTransaction ) Wfprintf(stdout,"COMMIT;\n");

  /* TBD: Handle trigger differences */
  /* TBD: Handle view differences */
  sqlite3_close(g.db);
  return 0;
}
Changes to tool/sqlite3_analyzer.c.in.
15
16
17
18
19
20
21











































22



23

24
25
26
27
28
29
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







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

+
+
+

+






#define SQLITE_MAX_EXPR_DEPTH 0
#define SQLITE_OMIT_LOAD_EXTENSION 1
#if !defined(SQLITE_AMALGAMATION) && !defined(USE_EXTERNAL_SQLITE)
INCLUDE sqlite3.c
#endif
INCLUDE $ROOT/src/tclsqlite.c

#if defined(_WIN32)
INCLUDE $ROOT/ext/consio/console_io.h
INCLUDE $ROOT/ext/consio/console_io.c

/* Substitute "puts" command.  Only these forms recognized:
**
**      puts STRING
**      puts stderr STRING
**      puts -nonewline STRING
*/
static int subst_puts(
  void *NotUsed,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *const*objv
){
  FILE *pOut = stdout;
  const char *zOut;
  int addNewLine = 1;
  if( objc==2 ){
    zOut = Tcl_GetString(objv[1]);
  }else if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?stderr|-nonewline? STRING");
    return TCL_ERROR;
  }else{
    const char *zArg = Tcl_GetString(objv[1]);
    if( zArg==0 ) return TCL_ERROR;
    zOut = Tcl_GetString(objv[2]);
    if( strcmp(zArg, "stderr")==0 ){
      pOut = stderr;
    }else if( strcmp(zArg, "-nonewline")==0 ){
      addNewLine = 0;
    }else{
      Tcl_AppendResult(interp, "bad argument: ", zArg, 0);
      return TCL_ERROR;
    }
  }
  fPutsUtf8(zOut, pOut);
  if( addNewLine ) fPutsUtf8("\n", pOut);
  return TCL_OK;
}
#endif /* defined(_WIN32) */

const char *sqlite3_analyzer_init_proc(Tcl_Interp *interp){
#if defined(_WIN32)
  Tcl_CreateObjCommand(interp, "puts", subst_puts, 0, 0);
#else  
  (void)interp;
#endif
  return
BEGIN_STRING
INCLUDE $ROOT/tool/spaceanal.tcl
END_STRING
;
}
Changes to tool/srctree-check.tcl.
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
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







+
+
+
+
+
+
+
+
+
+
+










-
+
+


+







# Name of the TCL interpreter
#
set TCLSH [info nameofexe]

# Number of errors seen.
#
set NERR 0

######################### configure ###########################################

set conf [readfile $ROOT/configure]
set vers [readfile $ROOT/VERSION]
if {[string first $vers $conf]<=0} {
  puts "ERROR: ./configure does not agree with ./VERSION"
  puts "...... Fix: run autoconf"
  incr NERR
}
unset conf

######################### autoconf/tea/configure.ac ###########################

set confac [readfile $ROOT/autoconf/tea/configure.ac]
set vers [readfile $ROOT/VERSION]
set pattern {AC_INIT([sqlite],[}
append pattern [string trim $vers]
append pattern {])}
if {[string first $pattern $confac]<=0} {
  puts "ERROR: ./autoconf/tea/configure.ac does not agree with ./VERSION"
  puts "...... Fix: manually edit ./autoconf/tea/configure.ac to"
  puts "...... Fix: manually edit ./autoconf/tea/configure.ac and put the"
  puts "......      correct version number in AC_INIT()"
  incr NERR
}
unset confac

######################### autoconf/Makefile.msc ###############################

set f1 [readfile $ROOT/autoconf/Makefile.msc]
exec $TCLSH $ROOT/tool/mkmsvcmin.tcl $ROOT/Makefile.msc tmp1.txt
set f2 [readfile tmp1.txt]
file delete tmp1.txt