/ Check-in [f040a5bb]
Login

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

Overview
Comment:Merge enhancements and fixes from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1:f040a5bb62f3473fba6450c97c68f538d1df21ef
User & Date: drh 2016-02-09 15:44:18
Context
2016-02-13
14:07
Merge the changes for the 3.11.0 release candidate from trunk. check-in: 4d7a802e user: drh tags: sessions
2016-02-09
15:44
Merge enhancements and fixes from trunk. check-in: f040a5bb user: drh tags: sessions
02:12
Make sure every co-routines has its own set of temporary registers and does not share temporaries, since a co-routine might expect the content of a temporary register to be preserved across an OP_Yield. Proposed fix for ticket [d06a25c84454a]. check-in: ca72be86 user: drh tags: trunk
2016-02-05
14:15
Merge enhancements from trunk. check-in: a533608c user: drh tags: sessions
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

584
585
586
587
588
589
590






591
592
593
594
595
596
597
....
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
....
1228
1229
1230
1231
1232
1233
1234

1235
1236
1237
1238
1239
1240
1241
sqlite3$(TEXE):	$(TOP)/src/shell.c libsqlite3.la sqlite3.h
	$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
		$(TOP)/src/shell.c libsqlite3.la \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

sqldiff$(TEXE):	$(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS)







fuzzershell$(TEXE):	$(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(FUZZERSHELL_OPT) \
	  $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS)

fuzzcheck$(TEXE):	$(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS)
................................................................................
#
quicktest:	./testfixture$(TEXE)
	./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS)

# This is the common case.  Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test:	$(TESTPROGS) fastfuzztest
	./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS)

# Run a test using valgrind.  This can take a really long time
# because valgrind is so much slower than a native machine.
#
valgrindtest:	$(TESTPROGS) valgrindfuzz
	OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
................................................................................
	rm -f sqlite3.c
	rm -f sqlite3rc.h
	rm -f shell.c sqlite3ext.h
	rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c
	rm -f sqlite-*-output.vsix
	rm -f mptester mptester.exe
	rm -f rbu rbu.exe

	rm -f fuzzershell fuzzershell.exe
	rm -f fuzzcheck fuzzcheck.exe
	rm -f sqldiff sqldiff.exe
	rm -f fts5.* fts5parse.*

distclean:	clean
	rm -f config.h config.log config.status libtool Makefile sqlite3.pc







>
>
>
>
>
>







 







|







 







>







584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
....
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
....
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
sqlite3$(TEXE):	$(TOP)/src/shell.c libsqlite3.la sqlite3.h
	$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
		$(TOP)/src/shell.c libsqlite3.la \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

sqldiff$(TEXE):	$(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS)

srcck1$(BEXE):	$(TOP)/tool/srcck1.c
	$(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c

sourcetest:	srcck1$(BEXE) sqlite3.c
	./srcck1 sqlite3.c

fuzzershell$(TEXE):	$(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(FUZZERSHELL_OPT) \
	  $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS)

fuzzcheck$(TEXE):	$(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
	$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS)
................................................................................
#
quicktest:	./testfixture$(TEXE)
	./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS)

# This is the common case.  Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test:	$(TESTPROGS) sourcetest fastfuzztest
	./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS)

# Run a test using valgrind.  This can take a really long time
# because valgrind is so much slower than a native machine.
#
valgrindtest:	$(TESTPROGS) valgrindfuzz
	OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
................................................................................
	rm -f sqlite3.c
	rm -f sqlite3rc.h
	rm -f shell.c sqlite3ext.h
	rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c
	rm -f sqlite-*-output.vsix
	rm -f mptester mptester.exe
	rm -f rbu rbu.exe
	rm -f srcck1 srcck1.exe
	rm -f fuzzershell fuzzershell.exe
	rm -f fuzzcheck fuzzcheck.exe
	rm -f sqldiff sqldiff.exe
	rm -f fts5.* fts5parse.*

distclean:	clean
	rm -f config.h config.log config.status libtool Makefile sqlite3.pc

Changes to Makefile.msc.

262
263
264
265
266
267
268









269
270
271
272
273
274
275
...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
...
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
...
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
...
894
895
896
897
898
899
900

901
902
903
904
905
906
907
908
909









910
911
912
913
914
915
916
....
1412
1413
1414
1415
1416
1417
1418






1419
1420
1421
1422
1423
1424
1425
....
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
....
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
EXT_FEATURE_FLAGS =
!ENDIF
!ENDIF

###############################################################################
############################### END OF OPTIONS ################################
###############################################################################










# This assumes that MSVC is always installed in 32-bit Program Files directory
# and sets the variable for use in locating other 32-bit installs accordingly.
#
PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\..
PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)

................................................................................
# compiler binary for the target platform.  If it is not defined, simply define
# it to the legacy default value 'rc.exe'.
#
!IFNDEF RC
RC = rc.exe
!ENDIF

# Check for the MSVC runtime library path macro.  Othertise, this value will
# default to the 'lib' directory underneath the MSVC installation directory.
#
!IFNDEF CRTLIBPATH
CRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

CRTLIBPATH = $(CRTLIBPATH:\\=\)
................................................................................
!ELSEIF $(XCOMPILE)!=0
NCC = "$(VCINSTALLDIR)\bin\$(CC)"
NCC = $(NCC:\\=\)
!ELSE
NCC = $(CC)
!ENDIF

# Check for the MSVC native runtime library path macro.  Othertise,
# this value will default to the 'lib' directory underneath the MSVC
# installation directory.
#
!IFNDEF NCRTLIBPATH
NCRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

NCRTLIBPATH = $(NCRTLIBPATH:\\=\)

# Check for the Platform SDK library path macro.  Othertise, this
# value will default to the 'lib' directory underneath the Windows
# SDK installation directory (the environment variable used appears
# to be available when using Visual C++ 2008 or later via the
# command line).
#
!IFNDEF NSDKLIBPATH
NSDKLIBPATH = $(WINDOWSSDKDIR)\lib
!ENDIF

NSDKLIBPATH = $(NSDKLIBPATH:\\=\)











# C compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
!IF $(USE_FULLWARN)!=0
BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
!ELSE
................................................................................
!ENDIF

# Also, we need to dynamically link to the correct MSVC runtime
# when compiling for WinRT (e.g. debug or release) OR if the
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(FOR_WINRT)!=0 || $(FOR_WIN10)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
!ENDIF
................................................................................
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF


# When compiling for UAP, some extra linker options are also required.
#
!IF $(FOR_UAP)!=0 || $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib
LTLINKOPTS = $(LTLINKOPTS) mincore.lib
!IFDEF PSDKLIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)"
!ENDIF
!ENDIF










# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = $(LDOPTS)
................................................................................
$(SQLITE3EXE):	$(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
	$(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\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)
	$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)







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

fuzzcheck.exe:	$(TOP)\test\fuzzcheck.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(TOP)\test\fuzzcheck.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

................................................................................
	.\fuzzcheck.exe $(FUZZDATA)

fastfuzztest:	fuzzcheck.exe
	.\fuzzcheck.exe --limit-mem 100M $(FUZZDATA)

# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest:	testfixture.exe
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)

# This is the common case.  Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test:	$(TESTPROGS) fastfuzztest
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)

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

................................................................................
	del /Q .target_source 2>NUL
	del /Q tclsqlite3.exe 2>NUL
	del /Q testloadext.dll 2>NUL
	del /Q testfixture.exe test.db 2>NUL
	del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL
	del /Q changeset.exe 2>NUL
	del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
	del /Q mptester.exe wordcount.exe rbu.exe 2>NUL
	del /Q $(SQLITE3EXE) $(SQLITE3DLL) sqlite3.def 2>NUL
	del /Q sqlite3.c sqlite3-*.c 2>NUL
	del /Q sqlite3rc.h 2>NUL
	del /Q shell.c sqlite3ext.h 2>NUL
	del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
	del /Q sqlite-*-output.vsix 2>NUL
	del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe 2>NUL
	del /Q fts5.* fts5parse.* 2>NUL
# <</mark>>







>
>
>
>
>
>
>
>
>







 







|







 







|









|










>
>
>
>
>
>
>
>
>
>







 







|







 







>
|








>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>







 







|






|







 







|









262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
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
...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
...
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
....
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
....
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
....
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
EXT_FEATURE_FLAGS =
!ENDIF
!ENDIF

###############################################################################
############################### END OF OPTIONS ################################
###############################################################################

# When compiling for the Windows 10 platform, the PLATFORM macro must be set
# to an appropriate value (e.g. x86, x64, arm, arm64, etc).
#
!IF $(FOR_WIN10)!=0
!IFNDEF PLATFORM
!ERROR Using the FOR_WIN10 option requires a value for PLATFORM.
!ENDIF
!ENDIF

# This assumes that MSVC is always installed in 32-bit Program Files directory
# and sets the variable for use in locating other 32-bit installs accordingly.
#
PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\..
PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)

................................................................................
# compiler binary for the target platform.  If it is not defined, simply define
# it to the legacy default value 'rc.exe'.
#
!IFNDEF RC
RC = rc.exe
!ENDIF

# Check for the MSVC runtime library path macro.  Otherwise, this value will
# default to the 'lib' directory underneath the MSVC installation directory.
#
!IFNDEF CRTLIBPATH
CRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

CRTLIBPATH = $(CRTLIBPATH:\\=\)
................................................................................
!ELSEIF $(XCOMPILE)!=0
NCC = "$(VCINSTALLDIR)\bin\$(CC)"
NCC = $(NCC:\\=\)
!ELSE
NCC = $(CC)
!ENDIF

# Check for the MSVC native runtime library path macro.  Otherwise,
# this value will default to the 'lib' directory underneath the MSVC
# installation directory.
#
!IFNDEF NCRTLIBPATH
NCRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

NCRTLIBPATH = $(NCRTLIBPATH:\\=\)

# Check for the Platform SDK library path macro.  Otherwise, this
# value will default to the 'lib' directory underneath the Windows
# SDK installation directory (the environment variable used appears
# to be available when using Visual C++ 2008 or later via the
# command line).
#
!IFNDEF NSDKLIBPATH
NSDKLIBPATH = $(WINDOWSSDKDIR)\lib
!ENDIF

NSDKLIBPATH = $(NSDKLIBPATH:\\=\)

# Check for the UCRT library path macro.  Otherwise, this value will
# default to the version-specific, platform-specific 'lib' directory
# underneath the Windows SDK installation directory.
#
!IFNDEF UCRTLIBPATH
UCRTLIBPATH = $(WINDOWSSDKDIR)\lib\$(WINDOWSSDKLIBVERSION)\ucrt\$(PLATFORM)
!ENDIF

UCRTLIBPATH = $(UCRTLIBPATH:\\=\)

# C compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
!IF $(USE_FULLWARN)!=0
BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
!ELSE
................................................................................
!ENDIF

# Also, we need to dynamically link to the correct MSVC runtime
# when compiling for WinRT (e.g. debug or release) OR if the
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
!ENDIF
................................................................................
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF

# When compiling for UAP or the Windows 10 platform, some extra linker
# options are also required.
#
!IF $(FOR_UAP)!=0 || $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib
LTLINKOPTS = $(LTLINKOPTS) mincore.lib
!IFDEF PSDKLIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)"
!ENDIF
!ENDIF

!IF $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(UCRTLIBPATH)"
!IF $(DEBUG)>1
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrtd.lib /DEFAULTLIB:ucrtd.lib
!ELSE
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
!ENDIF
!ENDIF

# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = $(LDOPTS)
................................................................................
$(SQLITE3EXE):	$(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
	$(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\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)
	$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

srcck1.exe:	$(TOP)\tool\srcck1.c
	$(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c

sourcetest:	srcck1.exe sqlite3.c
	srcck1.exe sqlite3.c

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

fuzzcheck.exe:	$(TOP)\test\fuzzcheck.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(TOP)\test\fuzzcheck.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

................................................................................
	.\fuzzcheck.exe $(FUZZDATA)

fastfuzztest:	fuzzcheck.exe
	.\fuzzcheck.exe --limit-mem 100M $(FUZZDATA)

# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest:	testfixture.exe sourcetest
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)

# This is the common case.  Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test:	$(TESTPROGS) sourcetest fastfuzztest
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)

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

................................................................................
	del /Q .target_source 2>NUL
	del /Q tclsqlite3.exe 2>NUL
	del /Q testloadext.dll 2>NUL
	del /Q testfixture.exe test.db 2>NUL
	del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL
	del /Q changeset.exe 2>NUL
	del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
	del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
	del /Q $(SQLITE3EXE) $(SQLITE3DLL) sqlite3.def 2>NUL
	del /Q sqlite3.c sqlite3-*.c 2>NUL
	del /Q sqlite3rc.h 2>NUL
	del /Q shell.c sqlite3ext.h 2>NUL
	del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
	del /Q sqlite-*-output.vsix 2>NUL
	del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe 2>NUL
	del /Q fts5.* fts5parse.* 2>NUL
# <</mark>>

Changes to autoconf/Makefile.msc.

247
248
249
250
251
252
253









254
255
256
257
258
259
260
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
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
...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
...
779
780
781
782
783
784
785

786
787
788
789
790
791
792
793
794









795
796
797
798
799
800
801
EXT_FEATURE_FLAGS =
!ENDIF
!ENDIF

###############################################################################
############################### END OF OPTIONS ################################
###############################################################################










# This assumes that MSVC is always installed in 32-bit Program Files directory
# and sets the variable for use in locating other 32-bit installs accordingly.
#
PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\..
PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)

................................................................................
# compiler binary for the target platform.  If it is not defined, simply define
# it to the legacy default value 'rc.exe'.
#
!IFNDEF RC
RC = rc.exe
!ENDIF

# Check for the MSVC runtime library path macro.  Othertise, this value will
# default to the 'lib' directory underneath the MSVC installation directory.
#
!IFNDEF CRTLIBPATH
CRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

CRTLIBPATH = $(CRTLIBPATH:\\=\)
................................................................................
!ELSEIF $(XCOMPILE)!=0
NCC = "$(VCINSTALLDIR)\bin\$(CC)"
NCC = $(NCC:\\=\)
!ELSE
NCC = $(CC)
!ENDIF

# Check for the MSVC native runtime library path macro.  Othertise,
# this value will default to the 'lib' directory underneath the MSVC
# installation directory.
#
!IFNDEF NCRTLIBPATH
NCRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

NCRTLIBPATH = $(NCRTLIBPATH:\\=\)

# Check for the Platform SDK library path macro.  Othertise, this
# value will default to the 'lib' directory underneath the Windows
# SDK installation directory (the environment variable used appears
# to be available when using Visual C++ 2008 or later via the
# command line).
#
!IFNDEF NSDKLIBPATH
NSDKLIBPATH = $(WINDOWSSDKDIR)\lib
!ENDIF

NSDKLIBPATH = $(NSDKLIBPATH:\\=\)











# C compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
!IF $(USE_FULLWARN)!=0
BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
!ELSE
................................................................................
!ENDIF

# Also, we need to dynamically link to the correct MSVC runtime
# when compiling for WinRT (e.g. debug or release) OR if the
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(FOR_WINRT)!=0 || $(FOR_WIN10)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
!ENDIF
................................................................................
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF


# When compiling for UAP, some extra linker options are also required.
#
!IF $(FOR_UAP)!=0 || $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib
LTLINKOPTS = $(LTLINKOPTS) mincore.lib
!IFDEF PSDKLIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)"
!ENDIF
!ENDIF










# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = $(LDOPTS)







>
>
>
>
>
>
>
>
>







 







|







 







|









|










>
>
>
>
>
>
>
>
>
>







 







|







 







>
|








>
>
>
>
>
>
>
>
>







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
...
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
...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
...
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
EXT_FEATURE_FLAGS =
!ENDIF
!ENDIF

###############################################################################
############################### END OF OPTIONS ################################
###############################################################################

# When compiling for the Windows 10 platform, the PLATFORM macro must be set
# to an appropriate value (e.g. x86, x64, arm, arm64, etc).
#
!IF $(FOR_WIN10)!=0
!IFNDEF PLATFORM
!ERROR Using the FOR_WIN10 option requires a value for PLATFORM.
!ENDIF
!ENDIF

# This assumes that MSVC is always installed in 32-bit Program Files directory
# and sets the variable for use in locating other 32-bit installs accordingly.
#
PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\..
PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\)

................................................................................
# compiler binary for the target platform.  If it is not defined, simply define
# it to the legacy default value 'rc.exe'.
#
!IFNDEF RC
RC = rc.exe
!ENDIF

# Check for the MSVC runtime library path macro.  Otherwise, this value will
# default to the 'lib' directory underneath the MSVC installation directory.
#
!IFNDEF CRTLIBPATH
CRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

CRTLIBPATH = $(CRTLIBPATH:\\=\)
................................................................................
!ELSEIF $(XCOMPILE)!=0
NCC = "$(VCINSTALLDIR)\bin\$(CC)"
NCC = $(NCC:\\=\)
!ELSE
NCC = $(CC)
!ENDIF

# Check for the MSVC native runtime library path macro.  Otherwise,
# this value will default to the 'lib' directory underneath the MSVC
# installation directory.
#
!IFNDEF NCRTLIBPATH
NCRTLIBPATH = $(VCINSTALLDIR)\lib
!ENDIF

NCRTLIBPATH = $(NCRTLIBPATH:\\=\)

# Check for the Platform SDK library path macro.  Otherwise, this
# value will default to the 'lib' directory underneath the Windows
# SDK installation directory (the environment variable used appears
# to be available when using Visual C++ 2008 or later via the
# command line).
#
!IFNDEF NSDKLIBPATH
NSDKLIBPATH = $(WINDOWSSDKDIR)\lib
!ENDIF

NSDKLIBPATH = $(NSDKLIBPATH:\\=\)

# Check for the UCRT library path macro.  Otherwise, this value will
# default to the version-specific, platform-specific 'lib' directory
# underneath the Windows SDK installation directory.
#
!IFNDEF UCRTLIBPATH
UCRTLIBPATH = $(WINDOWSSDKDIR)\lib\$(WINDOWSSDKLIBVERSION)\ucrt\$(PLATFORM)
!ENDIF

UCRTLIBPATH = $(UCRTLIBPATH:\\=\)

# C compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
!IF $(USE_FULLWARN)!=0
BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS)
!ELSE
................................................................................
!ENDIF

# Also, we need to dynamically link to the correct MSVC runtime
# when compiling for WinRT (e.g. debug or release) OR if the
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
!ENDIF
................................................................................
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF

# When compiling for UAP or the Windows 10 platform, some extra linker
# options are also required.
#
!IF $(FOR_UAP)!=0 || $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib
LTLINKOPTS = $(LTLINKOPTS) mincore.lib
!IFDEF PSDKLIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)"
!ENDIF
!ENDIF

!IF $(FOR_WIN10)!=0
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(UCRTLIBPATH)"
!IF $(DEBUG)>1
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrtd.lib /DEFAULTLIB:ucrtd.lib
!ELSE
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
!ENDIF
!ENDIF

# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = $(LDOPTS)

Changes to ext/fts3/fts3_tokenizer.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
...
324
325
326
327
328
329
330

331
332
333
334
335
336
337
...
345
346
347
348
349
350
351


352
353
354
355
356
357
358
...
416
417
418
419
420
421
422

423
424
425
426
427

428
429
430
431
432
433
434

  pHash = (Fts3Hash *)sqlite3_user_data(context);

  zName = sqlite3_value_text(argv[0]);
  nName = sqlite3_value_bytes(argv[0])+1;

  if( argc==2 ){

    void *pOld;
    int n = sqlite3_value_bytes(argv[1]);
    if( zName==0 || n!=sizeof(pPtr) ){
      sqlite3_result_error(context, "argument type mismatch", -1);
      return;
    }
    pPtr = *(void **)sqlite3_value_blob(argv[1]);
    pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
    if( pOld==pPtr ){
      sqlite3_result_error(context, "out of memory", -1);
      return;
    }






  }else{

    if( zName ){
      pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
    }
    if( !pPtr ){
      char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
      sqlite3_result_error(context, zErr, -1);
      sqlite3_free(zErr);
................................................................................
    sqlite3_result_error(context, zErr, -1);
  }else{
    sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
  }
  Tcl_DecrRefCount(pRet);
}


static
int registerTokenizer(
  sqlite3 *db, 
  char *zName, 
  const sqlite3_tokenizer_module *p
){
  int rc;
................................................................................

  sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
  sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
  sqlite3_step(pStmt);

  return sqlite3_finalize(pStmt);
}



static
int queryTokenizer(
  sqlite3 *db, 
  char *zName,  
  const sqlite3_tokenizer_module **pp
){
................................................................................
  assert( p1==p2 );
  rc = queryTokenizer(db, "nosuchtokenizer", &p2);
  assert( rc==SQLITE_ERROR );
  assert( p2==0 );
  assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );

  /* Test the storage function */

  rc = registerTokenizer(db, "nosuchtokenizer", p1);
  assert( rc==SQLITE_OK );
  rc = queryTokenizer(db, "nosuchtokenizer", &p2);
  assert( rc==SQLITE_OK );
  assert( p2==p1 );


  sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
}

#endif

/*







>












>
>
>
>
>
>
|
>







 







>







 







>
>







 







>





>







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
...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

  pHash = (Fts3Hash *)sqlite3_user_data(context);

  zName = sqlite3_value_text(argv[0]);
  nName = sqlite3_value_bytes(argv[0])+1;

  if( argc==2 ){
#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
    void *pOld;
    int n = sqlite3_value_bytes(argv[1]);
    if( zName==0 || n!=sizeof(pPtr) ){
      sqlite3_result_error(context, "argument type mismatch", -1);
      return;
    }
    pPtr = *(void **)sqlite3_value_blob(argv[1]);
    pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
    if( pOld==pPtr ){
      sqlite3_result_error(context, "out of memory", -1);
      return;
    }
#else
    sqlite3_result_error(context, "fts3tokenize: " 
        "disabled - rebuild with -DSQLITE_ENABLE_FTS3_TOKENIZER", -1
    );
    return;
#endif /* SQLITE_ENABLE_FTS3_TOKENIZER */
  }else
  {
    if( zName ){
      pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
    }
    if( !pPtr ){
      char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
      sqlite3_result_error(context, zErr, -1);
      sqlite3_free(zErr);
................................................................................
    sqlite3_result_error(context, zErr, -1);
  }else{
    sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
  }
  Tcl_DecrRefCount(pRet);
}

#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
static
int registerTokenizer(
  sqlite3 *db, 
  char *zName, 
  const sqlite3_tokenizer_module *p
){
  int rc;
................................................................................

  sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
  sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
  sqlite3_step(pStmt);

  return sqlite3_finalize(pStmt);
}
#endif /* SQLITE_ENABLE_FTS3_TOKENIZER */


static
int queryTokenizer(
  sqlite3 *db, 
  char *zName,  
  const sqlite3_tokenizer_module **pp
){
................................................................................
  assert( p1==p2 );
  rc = queryTokenizer(db, "nosuchtokenizer", &p2);
  assert( rc==SQLITE_ERROR );
  assert( p2==0 );
  assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );

  /* Test the storage function */
#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
  rc = registerTokenizer(db, "nosuchtokenizer", p1);
  assert( rc==SQLITE_OK );
  rc = queryTokenizer(db, "nosuchtokenizer", &p2);
  assert( rc==SQLITE_OK );
  assert( p2==p1 );
#endif

  sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
}

#endif

/*

Changes to ext/fts5/fts5Int.h.

278
279
280
281
282
283
284

285
286
287
288
289
290
291
int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*);

typedef struct Fts5PoslistWriter Fts5PoslistWriter;
struct Fts5PoslistWriter {
  i64 iPrev;
};
int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);


int sqlite3Fts5PoslistNext64(
  const u8 *a, int n,             /* Buffer containing poslist */
  int *pi,                        /* IN/OUT: Offset within a[] */
  i64 *piOff                      /* IN/OUT: Current offset */
);








>







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*);

typedef struct Fts5PoslistWriter Fts5PoslistWriter;
struct Fts5PoslistWriter {
  i64 iPrev;
};
int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);
void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64);

int sqlite3Fts5PoslistNext64(
  const u8 *a, int n,             /* Buffer containing poslist */
  int *pi,                        /* IN/OUT: Offset within a[] */
  i64 *piOff                      /* IN/OUT: Current offset */
);

Changes to ext/fts5/fts5_buffer.c.

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
...
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
*/



#include "fts5Int.h"

int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){

  u32 nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
  u8 *pNew;
  while( nNew<nByte ){
    nNew = nNew * 2;
  }
  pNew = sqlite3_realloc(pBuf->p, nNew);
  if( pNew==0 ){
    *pRc = SQLITE_NOMEM;
    return 1;
  }else{
    pBuf->nSpace = nNew;
    pBuf->p = pNew;

  }
  return 0;
}


/*
** Encode value iVal as an SQLite varint and append it to the buffer object
................................................................................
){
  memset(pIter, 0, sizeof(*pIter));
  pIter->a = a;
  pIter->n = n;
  sqlite3Fts5PoslistReaderNext(pIter);
  return pIter->bEof;
}






















int sqlite3Fts5PoslistWriterAppend(
  Fts5Buffer *pBuf, 
  Fts5PoslistWriter *pWriter,
  i64 iPos
){
  static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
  int rc = SQLITE_OK;
  if( 0==fts5BufferGrow(&rc, pBuf, 5+5+5) ){
    if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
      pBuf->p[pBuf->n++] = 1;
      pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
      pWriter->iPrev = (iPos & colmask);
    }
    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2);
    pWriter->iPrev = iPos;
  }

  return rc;
}

void *sqlite3Fts5MallocZero(int *pRc, int nByte){
  void *pRet = 0;
  if( *pRc==SQLITE_OK ){
    pRet = sqlite3_malloc(nByte);
    if( pRet==0 && nByte>0 ){







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







 







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






<
|
|
<
<
<
<
<
<
<
<
>
|







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
...
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
*/



#include "fts5Int.h"

int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
  if( (u32)pBuf->nSpace<nByte ){
    u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
    u8 *pNew;
    while( nNew<nByte ){
      nNew = nNew * 2;
    }
    pNew = sqlite3_realloc(pBuf->p, nNew);
    if( pNew==0 ){
      *pRc = SQLITE_NOMEM;
      return 1;
    }else{
      pBuf->nSpace = nNew;
      pBuf->p = pNew;
    }
  }
  return 0;
}


/*
** Encode value iVal as an SQLite varint and append it to the buffer object
................................................................................
){
  memset(pIter, 0, sizeof(*pIter));
  pIter->a = a;
  pIter->n = n;
  sqlite3Fts5PoslistReaderNext(pIter);
  return pIter->bEof;
}

/*
** Append position iPos to the position list being accumulated in buffer
** pBuf, which must be already be large enough to hold the new data.
** The previous position written to this list is *piPrev. *piPrev is set
** to iPos before returning.
*/
void sqlite3Fts5PoslistSafeAppend(
  Fts5Buffer *pBuf, 
  i64 *piPrev, 
  i64 iPos
){
  static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
  if( (iPos & colmask) != (*piPrev & colmask) ){
    pBuf->p[pBuf->n++] = 1;
    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
    *piPrev = (iPos & colmask);
  }
  pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
  *piPrev = iPos;
}

int sqlite3Fts5PoslistWriterAppend(
  Fts5Buffer *pBuf, 
  Fts5PoslistWriter *pWriter,
  i64 iPos
){

  int rc;
  if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc;








  sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos);
  return SQLITE_OK;
}

void *sqlite3Fts5MallocZero(int *pRc, int nByte){
  void *pRet = 0;
  if( *pRc==SQLITE_OK ){
    pRet = sqlite3_malloc(nByte);
    if( pRet==0 && nByte>0 ){

Changes to ext/fts5/fts5_index.c.

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
....
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
....
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
....
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
....
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
....
4701
4702
4703
4704
4705
4706
4707
4708
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
....
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
....
5152
5153
5154
5155
5156
5157
5158

5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169

  /* 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 */
  u8 bFiltered;                   /* True if column-filter already applied */

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


................................................................................
    int iPoslist;
    if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
      iPoslist = pIter->iTermLeafOffset;
    }else{
      iPoslist = 4;
    }
    fts5IndexSkipVarint(pLeaf->p, iPoslist);
    assert( p->pConfig->eDetail==FTS5_DETAIL_NONE || iPoslist==(
        pIter->iLeafOffset - sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel)
    ));
    pIter->iLeafOffset = iPoslist;

    /* If this condition is true then the largest rowid for the current
    ** term may not be stored on the current page. So search forward to
    ** see where said rowid really is.  */
    if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
      int pgno;
................................................................................
** column filters are specified.
*/
static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
  pIter->base.iRowid = pSeg->iRowid;
  pIter->base.nData = pSeg->nPos;

  assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE );
  assert( pIter->pColset==0 || pIter->bFiltered );

  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    /* All data is stored on the current page. Populate the output 
    ** variables to point into the body of the page object. */
    pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
  }else{
    /* The data is distributed over two or more pages. Copy it into the
................................................................................
static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
  if( *pRc==SQLITE_OK ){
    Fts5Config *pConfig = pIter->pIndex->pConfig;
    if( pConfig->eDetail==FTS5_DETAIL_NONE ){
      pIter->xSetOutputs = fts5IterSetOutputs_None;
    }

    else if( pIter->pColset==0 || pIter->bFiltered ){
      pIter->xSetOutputs = fts5IterSetOutputs_Nocolset;
    }

    else if( pConfig->eDetail==FTS5_DETAIL_FULL ){
      pIter->xSetOutputs = fts5IterSetOutputs_Full;
    }

................................................................................
  Fts5Iter **ppOut                /* New object */
){
  Fts5Iter *pNew;
  pNew = fts5MultiIterAlloc(p, 2);
  if( pNew ){
    Fts5SegIter *pIter = &pNew->aSeg[1];

    pNew->bFiltered = 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 ){
................................................................................
*/
static void fts5MergePrefixLists(
  Fts5Index *p,                   /* FTS5 backend object */
  Fts5Buffer *p1,                 /* First list to merge */
  Fts5Buffer *p2                  /* Second list to merge */
){
  if( p2->n ){
    if( p1->n==0 ){
      fts5BufferSwap(p1, p2);
    }else{
      i64 iLastRowid = 0;
      Fts5DoclistIter i1;
      Fts5DoclistIter i2;
      Fts5Buffer out = {0, 0, 0};
      Fts5Buffer tmp = {0, 0, 0};

      if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return;
      fts5DoclistIterInit(p1, &i1);
      fts5DoclistIterInit(p2, &i2);

      while( 1 ){

        if( i1.iRowid<i2.iRowid ){
          /* Copy entry from i1 */
          fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
          fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
          fts5DoclistIterNext(&i1);
          if( i1.aPoslist==0 ) break;
        }
        else if( i2.iRowid!=i1.iRowid ){
          /* Copy entry from i2 */
          fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
          fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
          fts5DoclistIterNext(&i2);
          if( i2.aPoslist==0 ) break;
        }
        else{

          i64 iPos1 = 0;
          i64 iPos2 = 0;
          int iOff1 = 0;
          int iOff2 = 0;
          u8 *a1 = &i1.aPoslist[i1.nSize];
          u8 *a2 = &i2.aPoslist[i2.nSize];


          Fts5PoslistWriter writer;
          memset(&writer, 0, sizeof(writer));

          /* Merge the two position lists. */ 
          fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
          fts5BufferZero(&tmp);



          sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
          sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);


          while( iPos1>=0 || iPos2>=0 ){
            i64 iNew;
            if( iPos2<0 || (iPos1>=0 && iPos1<iPos2) ){
              iNew = iPos1;

              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
            }else{
              iNew = iPos2;

              sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);




              if( iPos1==iPos2 ){



                sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);






              }
            }
            if( iNew!=writer.iPrev || tmp.n==0 ){
              p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
              if( p->rc ) goto error_out;
            }
          }











          /* WRITEPOSLISTSIZE */
          fts5BufferSafeAppendVarint(&out, tmp.n * 2);
          fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
          fts5DoclistIterNext(&i1);
          fts5DoclistIterNext(&i2);
          if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
        }
      }

      if( i1.aPoslist ){
        fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
        fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
      }
      else if( i2.aPoslist ){
        fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
        fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
      }

     error_out:
      fts5BufferSet(&p->rc, p1, out.n, out.p);
      fts5BufferFree(&tmp);
      fts5BufferFree(&out);
    }
  }
}

static void fts5SetupPrefixIter(
  Fts5Index *p,                   /* Index to read from */
  int bDesc,                      /* True for "ORDER BY rowid DESC" */
  const u8 *pToken,               /* Buffer containing prefix to match */
................................................................................
** to the database. Additionally, assume that the contents of the %_data
** table may have changed on disk. So any in-memory caches of %_data 
** records must be invalidated.
*/
int sqlite3Fts5IndexRollback(Fts5Index *p){
  fts5CloseReader(p);
  fts5IndexDiscardData(p);
  assert( p->rc==SQLITE_OK );
  return SQLITE_OK;
}

/*
** The %_data table is completely empty when this function is called. This
** function populates it with the initial structure objects for each index,
** and the initial version of the "averages" record (a zero-byte blob).
................................................................................
        fts5StructureRelease(pStruct);
      }
    }else{
      /* Scan multiple terms in the main index */
      int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
      buf.p[0] = FTS5_MAIN_PREFIX;
      fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);

      fts5IterSetOutputCb(&p->rc, pRet);
      if( p->rc==SQLITE_OK ){
        Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
        if( p->rc==SQLITE_OK && pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
      }
    }

    if( p->rc ){
      sqlite3Fts5IterClose(&pRet->base);
      pRet = 0;
      fts5CloseReader(p);







<







 







<
<
<







 







|







 







|







 







<







 







<
<
<
|
|
|
|
|

|
|
|

|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|

>
|
|

<
|
|
>
>

|
|
>

<
<
|
<
>
|
|
<
>
|
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
|
|
<
<
<
|
|
>
>
>
|
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|

<
|
|
|
<







 







|







 







>



|







514
515
516
517
518
519
520

521
522
523
524
525
526
527
....
2025
2026
2027
2028
2029
2030
2031



2032
2033
2034
2035
2036
2037
2038
....
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
....
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
....
3351
3352
3353
3354
3355
3356
3357

3358
3359
3360
3361
3362
3363
3364
....
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
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
....
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
....
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181

  /* 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 */
};


................................................................................
    int iPoslist;
    if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
      iPoslist = pIter->iTermLeafOffset;
    }else{
      iPoslist = 4;
    }
    fts5IndexSkipVarint(pLeaf->p, iPoslist);



    pIter->iLeafOffset = iPoslist;

    /* If this condition is true then the largest rowid for the current
    ** term may not be stored on the current page. So search forward to
    ** see where said rowid really is.  */
    if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
      int pgno;
................................................................................
** column filters are specified.
*/
static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
  pIter->base.iRowid = pSeg->iRowid;
  pIter->base.nData = pSeg->nPos;

  assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE );
  assert( pIter->pColset==0 );

  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    /* All data is stored on the current page. Populate the output 
    ** variables to point into the body of the page object. */
    pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
  }else{
    /* The data is distributed over two or more pages. Copy it into the
................................................................................
static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
  if( *pRc==SQLITE_OK ){
    Fts5Config *pConfig = pIter->pIndex->pConfig;
    if( pConfig->eDetail==FTS5_DETAIL_NONE ){
      pIter->xSetOutputs = fts5IterSetOutputs_None;
    }

    else if( pIter->pColset==0 ){
      pIter->xSetOutputs = fts5IterSetOutputs_Nocolset;
    }

    else if( pConfig->eDetail==FTS5_DETAIL_FULL ){
      pIter->xSetOutputs = fts5IterSetOutputs_Full;
    }

................................................................................
  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 ){
................................................................................
*/
static void fts5MergePrefixLists(
  Fts5Index *p,                   /* FTS5 backend object */
  Fts5Buffer *p1,                 /* First list to merge */
  Fts5Buffer *p2                  /* Second list to merge */
){
  if( p2->n ){



    i64 iLastRowid = 0;
    Fts5DoclistIter i1;
    Fts5DoclistIter i2;
    Fts5Buffer out = {0, 0, 0};
    Fts5Buffer tmp = {0, 0, 0};

    if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return;
    fts5DoclistIterInit(p1, &i1);
    fts5DoclistIterInit(p2, &i2);

    while( 1 ){

      if( i1.iRowid<i2.iRowid ){
        /* Copy entry from i1 */
        fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
        fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
        fts5DoclistIterNext(&i1);
        if( i1.aPoslist==0 ) break;
      }
      else if( i2.iRowid!=i1.iRowid ){
        /* Copy entry from i2 */
        fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
        fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
        fts5DoclistIterNext(&i2);
        if( i2.aPoslist==0 ) break;
      }
      else{
        /* Merge the two position lists. */ 
        i64 iPos1 = 0;
        i64 iPos2 = 0;
        int iOff1 = 0;
        int iOff2 = 0;
        u8 *a1 = &i1.aPoslist[i1.nSize];
        u8 *a2 = &i2.aPoslist[i2.nSize];

        i64 iPrev = 0;
        Fts5PoslistWriter writer;
        memset(&writer, 0, sizeof(writer));


        fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
        fts5BufferZero(&tmp);
        sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist);
        if( p->rc ) break;

        sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
        sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
        assert( iPos1>=0 && iPos2>=0 );



        if( iPos1<iPos2 ){

          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
          sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
        }else{

          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
          sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
        }

        if( iPos1>=0 && iPos2>=0 ){
          while( 1 ){
            if( iPos1<iPos2 ){
              if( iPos1!=iPrev ){
                sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
              }
              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
              if( iPos1<0 ) break;
            }else{
              assert( iPos2!=iPrev );
              sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
              sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
              if( iPos2<0 ) break;
            }
          }



        }

        if( iPos1>=0 ){
          if( iPos1!=iPrev ){
            sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
          }
          fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
        }else{
          assert( iPos2>=0 && iPos2!=iPrev );
          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
          fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
        }

        /* WRITEPOSLISTSIZE */
        fts5BufferSafeAppendVarint(&out, tmp.n * 2);
        fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
        fts5DoclistIterNext(&i1);
        fts5DoclistIterNext(&i2);
        if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
      }
    }

    if( i1.aPoslist ){
      fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
      fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
    }
    else if( i2.aPoslist ){
      fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
      fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
    }


    fts5BufferSet(&p->rc, p1, out.n, out.p);
    fts5BufferFree(&tmp);
    fts5BufferFree(&out);

  }
}

static void fts5SetupPrefixIter(
  Fts5Index *p,                   /* Index to read from */
  int bDesc,                      /* True for "ORDER BY rowid DESC" */
  const u8 *pToken,               /* Buffer containing prefix to match */
................................................................................
** to the database. Additionally, assume that the contents of the %_data
** table may have changed on disk. So any in-memory caches of %_data 
** records must be invalidated.
*/
int sqlite3Fts5IndexRollback(Fts5Index *p){
  fts5CloseReader(p);
  fts5IndexDiscardData(p);
  /* assert( p->rc==SQLITE_OK ); */
  return SQLITE_OK;
}

/*
** The %_data table is completely empty when this function is called. This
** function populates it with the initial structure objects for each index,
** and the initial version of the "averages" record (a zero-byte blob).
................................................................................
        fts5StructureRelease(pStruct);
      }
    }else{
      /* Scan multiple terms in the main index */
      int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
      buf.p[0] = FTS5_MAIN_PREFIX;
      fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
      assert( pRet->pColset==0 );
      fts5IterSetOutputCb(&p->rc, pRet);
      if( p->rc==SQLITE_OK ){
        Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
        if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
      }
    }

    if( p->rc ){
      sqlite3Fts5IterClose(&pRet->base);
      pRet = 0;
      fts5CloseReader(p);

Changes to ext/fts5/fts5_main.c.

799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
...
816
817
818
819
820
821
822

823
824
825
826
827
828
829
**
** Return SQLITE_OK if nothing goes wrong.  SQLITE_OK is returned
** even if we reach end-of-file.  The fts5EofMethod() will be called
** subsequently to determine whether or not an EOF was hit.
*/
static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
  int rc = SQLITE_OK;

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

  if( pCsr->ePlan<3 ){
................................................................................
    rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
    CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
    fts5CsrNewrow(pCsr);
  }else{
    switch( pCsr->ePlan ){
      case FTS5_PLAN_SPECIAL: {
        CsrFlagSet(pCsr, FTS5CSR_EOF);

        break;
      }
  
      case FTS5_PLAN_SORTED_MATCH: {
        rc = fts5SorterNext(pCsr);
        break;
      }







|







 







>







799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
...
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
**
** Return SQLITE_OK if nothing goes wrong.  SQLITE_OK is returned
** even if we reach end-of-file.  The fts5EofMethod() will be called
** subsequently to determine whether or not an EOF was hit.
*/
static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
  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( pCsr->ePlan<3 ){
................................................................................
    rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
    CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
    fts5CsrNewrow(pCsr);
  }else{
    switch( pCsr->ePlan ){
      case FTS5_PLAN_SPECIAL: {
        CsrFlagSet(pCsr, FTS5CSR_EOF);
        rc = SQLITE_OK;
        break;
      }
  
      case FTS5_PLAN_SORTED_MATCH: {
        rc = fts5SorterNext(pCsr);
        break;
      }

Changes to ext/fts5/fts5_varint.c.

329
330
331
332
333
334
335

336


337
338
339
340
341
342
    return 2;
  }
  return fts5PutVarint64(p,v);
}


int sqlite3Fts5GetVarintLen(u32 iVal){

  if( iVal<(1 << 7 ) ) return 1;


  if( iVal<(1 << 14) ) return 2;
  if( iVal<(1 << 21) ) return 3;
  if( iVal<(1 << 28) ) return 4;
  return 5;
}








>

>
>






329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    return 2;
  }
  return fts5PutVarint64(p,v);
}


int sqlite3Fts5GetVarintLen(u32 iVal){
#if 0
  if( iVal<(1 << 7 ) ) return 1;
#endif
  assert( iVal>=(1 << 7) );
  if( iVal<(1 << 14) ) return 2;
  if( iVal<(1 << 21) ) return 3;
  if( iVal<(1 << 28) ) return 4;
  return 5;
}

Changes to ext/fts5/test/fts5ad.test.

7
8
9
10
11
12
13


14
15
16
17
18
19
20
#    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 script is testing the FTS5 module.
#


#

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

# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {







>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    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 script is testing the FTS5 module.
#
# More specifically, the focus is on testing prefix queries, both with and
# without prefix indexes.
#

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

# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {

Changes to ext/fts5/test/fts5config.test.

239
240
241
242
243
244
245




246
247
  5 {detail=',1'}
  6 {detail=''}
} {
  set res [list 1 {malformed detail=... directive}]
  do_catchsql_test 11.$tn "CREATE VIRTUAL TABLE f1 USING fts5(x, $opt)" $res
}





finish_test








>
>
>
>


239
240
241
242
243
244
245
246
247
248
249
250
251
  5 {detail=',1'}
  6 {detail=''}
} {
  set res [list 1 {malformed detail=... directive}]
  do_catchsql_test 11.$tn "CREATE VIRTUAL TABLE f1 USING fts5(x, $opt)" $res
}

do_catchsql_test 12.1 {
  INSERT INTO t1(t1, rank) VALUES('rank', NULL);;
} {1 {SQL logic error or missing database}}

finish_test

Changes to ext/fts5/test/fts5detail.test.

80
81
82
83
84
85
86




87
88
89
90
91
92
93
do_execsql_test 2.1 {
  INSERT INTO t2(t2) VALUES('integrity-check');
}

do_execsql_test 2.2 {
  SELECT fts5_test_poslist(t2) FROM t2('aa');
} {0.0.0}





set ::pc 0
#puts [nearset {{ax bx cx}} -pc ::pc -near 10 -- b*]
#exit

#-------------------------------------------------------------------------
# Check that the xInstCount, xInst, xPhraseFirst and xPhraseNext APIs







>
>
>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
do_execsql_test 2.1 {
  INSERT INTO t2(t2) VALUES('integrity-check');
}

do_execsql_test 2.2 {
  SELECT fts5_test_poslist(t2) FROM t2('aa');
} {0.0.0}

do_execsql_test 2.3 {
  SELECT fts5_test_collist(t2) FROM t2('aa');
} {0.0}

set ::pc 0
#puts [nearset {{ax bx cx}} -pc ::pc -near 10 -- b*]
#exit

#-------------------------------------------------------------------------
# Check that the xInstCount, xInst, xPhraseFirst and xPhraseNext APIs

Changes to main.mk.

483
484
485
486
487
488
489






490
491
492
493
494
495
496
...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
...
907
908
909
910
911
912
913

914
915
916
917
918
919
920
921
922
923
sqlite3$(EXE):	$(TOP)/src/shell.c libsqlite3.a sqlite3.h
	$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
		$(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)

sqldiff$(EXE):	$(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
	$(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \
		$(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB)







fuzzershell$(EXE):	$(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
	$(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
	  $(FUZZERSHELL_OPT) $(TOP)/tool/fuzzershell.c sqlite3.c \
	  $(TLIBS) $(THREADLIB)

fuzzcheck$(EXE):	$(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
................................................................................
#
quicktest:	./testfixture$(EXE)
	./testfixture$(EXE) $(TOP)/test/extraquick.test $(TESTOPTS)

# The default test case.  Runs most of the faster standard TCL tests,
# and fuzz tests, and sqlite3_analyzer and sqldiff tests.
#
test:	$(TESTPROGS) fastfuzztest
	./testfixture$(EXE) $(TOP)/test/veryquick.test $(TESTOPTS)

# Run a test using valgrind.  This can take a really long time
# because valgrind is so much slower than a native machine.
#
valgrindtest:	$(TESTPROGS) valgrindfuzz
	OMIT_MISUSE=1 valgrind -v \
................................................................................
	rm -f showjournal showjournal.exe
	rm -f showstat4 showstat4.exe
	rm -f showwal showwal.exe
	rm -f changeset changeset.exe
	rm -f speedtest1 speedtest1.exe
	rm -f wordcount wordcount.exe
	rm -f rbu rbu.exe

	rm -f sqlite3.c sqlite3-*.c fts?amal.c tclsqlite3.c
	rm -f sqlite3rc.h
	rm -f shell.c sqlite3ext.h
	rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c
	rm -f sqlite-*-output.vsix
	rm -f mptester mptester.exe
	rm -f fuzzershell fuzzershell.exe
	rm -f fuzzcheck fuzzcheck.exe
	rm -f sqldiff sqldiff.exe
	rm -f fts5.* fts5parse.*







>
>
>
>
>
>







 







|







 







>










483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
...
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
sqlite3$(EXE):	$(TOP)/src/shell.c libsqlite3.a sqlite3.h
	$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
		$(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)

sqldiff$(EXE):	$(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
	$(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \
		$(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB)

srcck1$(EXE):	$(TOP)/tool/srcck1.c
	$(BCC) -o srcck1$(EXE) $(TOP)/tool/srcck1.c

sourcetest:	srcck1$(EXE) sqlite3.c
	./srcck1 sqlite3.c

fuzzershell$(EXE):	$(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
	$(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
	  $(FUZZERSHELL_OPT) $(TOP)/tool/fuzzershell.c sqlite3.c \
	  $(TLIBS) $(THREADLIB)

fuzzcheck$(EXE):	$(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
................................................................................
#
quicktest:	./testfixture$(EXE)
	./testfixture$(EXE) $(TOP)/test/extraquick.test $(TESTOPTS)

# The default test case.  Runs most of the faster standard TCL tests,
# and fuzz tests, and sqlite3_analyzer and sqldiff tests.
#
test:	$(TESTPROGS) sourcetest fastfuzztest
	./testfixture$(EXE) $(TOP)/test/veryquick.test $(TESTOPTS)

# Run a test using valgrind.  This can take a really long time
# because valgrind is so much slower than a native machine.
#
valgrindtest:	$(TESTPROGS) valgrindfuzz
	OMIT_MISUSE=1 valgrind -v \
................................................................................
	rm -f showjournal showjournal.exe
	rm -f showstat4 showstat4.exe
	rm -f showwal showwal.exe
	rm -f changeset changeset.exe
	rm -f speedtest1 speedtest1.exe
	rm -f wordcount wordcount.exe
	rm -f rbu rbu.exe
	rm -f srcck1 srcck1.exe
	rm -f sqlite3.c sqlite3-*.c fts?amal.c tclsqlite3.c
	rm -f sqlite3rc.h
	rm -f shell.c sqlite3ext.h
	rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c
	rm -f sqlite-*-output.vsix
	rm -f mptester mptester.exe
	rm -f fuzzershell fuzzershell.exe
	rm -f fuzzcheck fuzzcheck.exe
	rm -f sqldiff sqldiff.exe
	rm -f fts5.* fts5parse.*

Changes to src/alter.c.

691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  */
  if( pDflt ){
    sqlite3_value *pVal = 0;
    int rc;
    rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
    assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    if( rc!=SQLITE_OK ){
      assert( db->mallocFailed = 1 );
      return;
    }
    if( !pVal ){
      sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
      return;
    }
    sqlite3ValueFree(pVal);







|







691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  */
  if( pDflt ){
    sqlite3_value *pVal = 0;
    int rc;
    rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
    assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    if( rc!=SQLITE_OK ){
      assert( db->mallocFailed == 1 );
      return;
    }
    if( !pVal ){
      sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
      return;
    }
    sqlite3ValueFree(pVal);

Changes to src/btree.c.

6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
....
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823

7824
7825
7826
7827
7828
7829
7830
7831
....
7856
7857
7858
7859
7860
7861
7862

7863
7864
7865
7866
7867
7868
7869
7870
....
9323
9324
9325
9326
9327
9328
9329
9330

9331
9332
9333
9334
9335
9336
9337
  ** Use a call to btreeParseCellPtr() to verify that the values above
  ** were computed correctly.
  */
#if SQLITE_DEBUG
  {
    CellInfo info;
    pPage->xParseCell(pPage, pCell, &info);
    assert( nHeader=(int)(info.pPayload - pCell) );
    assert( info.nKey==nKey );
    assert( *pnSize == info.nSize );
    assert( spaceLeft == info.nLocal );
  }
#endif

  /* Write the payload into the local Cell and any extra into overflow pages */
................................................................................
*/
static int balance(BtCursor *pCur){
  int rc = SQLITE_OK;
  const int nMin = pCur->pBt->usableSize * 2 / 3;
  u8 aBalanceQuickSpace[13];
  u8 *pFree = 0;

  TESTONLY( int balance_quick_called = 0 );
  TESTONLY( int balance_deeper_called = 0 );

  do {
    int iPage = pCur->iPage;
    MemPage *pPage = pCur->apPage[iPage];

    if( iPage==0 ){
      if( pPage->nOverflow ){
        /* The root page of the b-tree is overfull. In this case call the
        ** balance_deeper() function to create a new child for the root-page
        ** and copy the current contents of the root-page to it. The
        ** next iteration of the do-loop will balance the child page.
        */ 

        assert( (balance_deeper_called++)==0 );
        rc = balance_deeper(pPage, &pCur->apPage[1]);
        if( rc==SQLITE_OK ){
          pCur->iPage = 1;
          pCur->aiIdx[0] = 0;
          pCur->aiIdx[1] = 0;
          assert( pCur->apPage[1]->nOverflow );
        }
................................................................................
          ** buffer. 
          **
          ** The purpose of the following assert() is to check that only a
          ** single call to balance_quick() is made for each call to this
          ** function. If this were not verified, a subtle bug involving reuse
          ** of the aBalanceQuickSpace[] might sneak in.
          */

          assert( (balance_quick_called++)==0 );
          rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
        }else
#endif
        {
          /* In this case, call balance_nonroot() to redistribute cells
          ** between pPage and up to 2 of its sibling pages. This involves
          ** modifying the contents of pParent, which may cause pParent to
................................................................................
  BtShared *pBt = p->pBt;
  int savedDbFlags = pBt->db->flags;
  char zErr[100];
  VVA_ONLY( int nRef );

  sqlite3BtreeEnter(p);
  assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
  assert( (nRef = sqlite3PagerRefcount(pBt->pPager))>=0 );

  sCheck.pBt = pBt;
  sCheck.pPager = pBt->pPager;
  sCheck.nPage = btreePagecount(sCheck.pBt);
  sCheck.mxErr = mxErr;
  sCheck.nErr = 0;
  sCheck.mallocFailed = 0;
  sCheck.zPfx = 0;







|







 







|
|












>
|







 







>
|







 







|
>







6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
....
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
....
7857
7858
7859
7860
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
....
9325
9326
9327
9328
9329
9330
9331
9332
9333
9334
9335
9336
9337
9338
9339
9340
  ** Use a call to btreeParseCellPtr() to verify that the values above
  ** were computed correctly.
  */
#if SQLITE_DEBUG
  {
    CellInfo info;
    pPage->xParseCell(pPage, pCell, &info);
    assert( nHeader==(int)(info.pPayload - pCell) );
    assert( info.nKey==nKey );
    assert( *pnSize == info.nSize );
    assert( spaceLeft == info.nLocal );
  }
#endif

  /* Write the payload into the local Cell and any extra into overflow pages */
................................................................................
*/
static int balance(BtCursor *pCur){
  int rc = SQLITE_OK;
  const int nMin = pCur->pBt->usableSize * 2 / 3;
  u8 aBalanceQuickSpace[13];
  u8 *pFree = 0;

  VVA_ONLY( int balance_quick_called = 0 );
  VVA_ONLY( int balance_deeper_called = 0 );

  do {
    int iPage = pCur->iPage;
    MemPage *pPage = pCur->apPage[iPage];

    if( iPage==0 ){
      if( pPage->nOverflow ){
        /* The root page of the b-tree is overfull. In this case call the
        ** balance_deeper() function to create a new child for the root-page
        ** and copy the current contents of the root-page to it. The
        ** next iteration of the do-loop will balance the child page.
        */ 
        assert( balance_deeper_called==0 );
        VVA_ONLY( balance_deeper_called++ );
        rc = balance_deeper(pPage, &pCur->apPage[1]);
        if( rc==SQLITE_OK ){
          pCur->iPage = 1;
          pCur->aiIdx[0] = 0;
          pCur->aiIdx[1] = 0;
          assert( pCur->apPage[1]->nOverflow );
        }
................................................................................
          ** buffer. 
          **
          ** The purpose of the following assert() is to check that only a
          ** single call to balance_quick() is made for each call to this
          ** function. If this were not verified, a subtle bug involving reuse
          ** of the aBalanceQuickSpace[] might sneak in.
          */
          assert( balance_quick_called==0 ); 
          VVA_ONLY( balance_quick_called++ );
          rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
        }else
#endif
        {
          /* In this case, call balance_nonroot() to redistribute cells
          ** between pPage and up to 2 of its sibling pages. This involves
          ** modifying the contents of pParent, which may cause pParent to
................................................................................
  BtShared *pBt = p->pBt;
  int savedDbFlags = pBt->db->flags;
  char zErr[100];
  VVA_ONLY( int nRef );

  sqlite3BtreeEnter(p);
  assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
  VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
  assert( nRef>=0 );
  sCheck.pBt = pBt;
  sCheck.pPager = pBt->pPager;
  sCheck.nPage = btreePagecount(sCheck.pBt);
  sCheck.mxErr = mxErr;
  sCheck.nErr = 0;
  sCheck.mallocFailed = 0;
  sCheck.zPfx = 0;

Changes to src/build.c.

1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
      sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
      sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
      pParse->nTab = 2;
      addrTop = sqlite3VdbeCurrentAddr(v) + 1;
      sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
      sqlite3Select(pParse, pSelect, &dest);
      sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
      sqlite3VdbeJumpHere(v, addrTop - 1);
      if( pParse->nErr ) return;
      pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
      if( pSelTab==0 ) return;
      assert( p->aCol==0 );
      p->nCol = pSelTab->nCol;
      p->aCol = pSelTab->aCol;







|







1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
      sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
      sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
      pParse->nTab = 2;
      addrTop = sqlite3VdbeCurrentAddr(v) + 1;
      sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
      sqlite3Select(pParse, pSelect, &dest);
      sqlite3VdbeEndCoroutine(v, regYield);
      sqlite3VdbeJumpHere(v, addrTop - 1);
      if( pParse->nErr ) return;
      pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
      if( pSelTab==0 ) return;
      assert( p->aCol==0 );
      p->nCol = pSelTab->nCol;
      p->aCol = pSelTab->aCol;

Changes to src/insert.c.

681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
    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;
    if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
    sqlite3VdbeAddOp1(v, OP_EndCoroutine, 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







|







681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
    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;
    if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
    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

Changes to src/main.c.

3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
    ** assert() is disabled, then the return value is zero.  If X is
    ** false and assert() is enabled, then the assertion fires and the
    ** process aborts.  If X is false and assert() is disabled, then the
    ** return value is zero.
    */
    case SQLITE_TESTCTRL_ASSERT: {
      volatile int x = 0;
      assert( (x = va_arg(ap,int))!=0 );
      rc = x;
      break;
    }


    /*
    **  sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X)







|







3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
    ** assert() is disabled, then the return value is zero.  If X is
    ** false and assert() is enabled, then the assertion fires and the
    ** process aborts.  If X is false and assert() is disabled, then the
    ** return value is zero.
    */
    case SQLITE_TESTCTRL_ASSERT: {
      volatile int x = 0;
      assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
      rc = x;
      break;
    }


    /*
    **  sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X)

Changes to src/malloc.c.

622
623
624
625
626
627
628


629
630
631
632
633
634
635
636
637
638
639
640
...
646
647
648
649
650
651
652



653
654
655
656
657
658
659
  void *p;
  if( db ) return sqlite3DbMallocRawNN(db, n);
  p = sqlite3Malloc(n);
  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
  return p;
}
void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){


  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( db->pnBytesFreed==0 );
#ifndef SQLITE_OMIT_LOOKASIDE
  LookasideSlot *pBuf;
  if( db->lookaside.bDisable==0 ){
    assert( db->mallocFailed==0 );
    if( n>db->lookaside.sz ){
      db->lookaside.anStat[1]++;
    }else if( (pBuf = db->lookaside.pFree)==0 ){
      db->lookaside.anStat[2]++;
    }else{
................................................................................
      }
      return (void*)pBuf;
    }
  }else if( db->mallocFailed ){
    return 0;
  }
#else



  if( db->mallocFailed ){
    return 0;
  }
#endif
  return dbMallocRawFinish(db, n);
}








>
>



<
<







 







>
>
>







622
623
624
625
626
627
628
629
630
631
632
633


634
635
636
637
638
639
640
...
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  void *p;
  if( db ) return sqlite3DbMallocRawNN(db, n);
  p = sqlite3Malloc(n);
  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
  return p;
}
void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
#ifndef SQLITE_OMIT_LOOKASIDE
  LookasideSlot *pBuf;
  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( db->pnBytesFreed==0 );


  if( db->lookaside.bDisable==0 ){
    assert( db->mallocFailed==0 );
    if( n>db->lookaside.sz ){
      db->lookaside.anStat[1]++;
    }else if( (pBuf = db->lookaside.pFree)==0 ){
      db->lookaside.anStat[2]++;
    }else{
................................................................................
      }
      return (void*)pBuf;
    }
  }else if( db->mallocFailed ){
    return 0;
  }
#else
  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( db->pnBytesFreed==0 );
  if( db->mallocFailed ){
    return 0;
  }
#endif
  return dbMallocRawFinish(db, n);
}

Changes to src/select.c.

2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
....
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
....
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
  */
  addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
  VdbeComment((v, "left SELECT"));
  pPrior->iLimit = regLimitA;
  explainSetInteger(iSub1, pParse->iNextSelectId);
  sqlite3Select(pParse, pPrior, &destA);
  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
  sqlite3VdbeJumpHere(v, addr1);

  /* Generate a coroutine to evaluate the SELECT statement on 
  ** the right - the "B" select
  */
  addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
................................................................................
  savedOffset = p->iOffset;
  p->iLimit = regLimitB;
  p->iOffset = 0;  
  explainSetInteger(iSub2, pParse->iNextSelectId);
  sqlite3Select(pParse, p, &destB);
  p->iLimit = savedLimit;
  p->iOffset = savedOffset;
  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);

  /* Generate a subroutine that outputs the current row of the A
  ** select as the next output row of the compound select.
  */
  VdbeNoopComment((v, "Output routine for A"));
  addrOutA = generateOutputSubroutine(pParse,
                 p, &destA, pDest, regOutA,
................................................................................
      pItem->addrFillSub = addrTop;
      sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
      pItem->fg.viaCoroutine = 1;
      pItem->regResult = dest.iSdst;
      sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
      sqlite3VdbeJumpHere(v, addrTop-1);
      sqlite3ClearTempRegCache(pParse);
    }else{
      /* Generate a subroutine that will fill an ephemeral table with
      ** the content of this subquery.  pItem->addrFillSub will point
      ** to the address of the generated subroutine.  pItem->regReturn
      ** is a register allocated to hold the subroutine return address







|







 







|







 







|







2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
....
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
....
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
  */
  addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
  VdbeComment((v, "left SELECT"));
  pPrior->iLimit = regLimitA;
  explainSetInteger(iSub1, pParse->iNextSelectId);
  sqlite3Select(pParse, pPrior, &destA);
  sqlite3VdbeEndCoroutine(v, regAddrA);
  sqlite3VdbeJumpHere(v, addr1);

  /* Generate a coroutine to evaluate the SELECT statement on 
  ** the right - the "B" select
  */
  addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
................................................................................
  savedOffset = p->iOffset;
  p->iLimit = regLimitB;
  p->iOffset = 0;  
  explainSetInteger(iSub2, pParse->iNextSelectId);
  sqlite3Select(pParse, p, &destB);
  p->iLimit = savedLimit;
  p->iOffset = savedOffset;
  sqlite3VdbeEndCoroutine(v, regAddrB);

  /* Generate a subroutine that outputs the current row of the A
  ** select as the next output row of the compound select.
  */
  VdbeNoopComment((v, "Output routine for A"));
  addrOutA = generateOutputSubroutine(pParse,
                 p, &destA, pDest, regOutA,
................................................................................
      pItem->addrFillSub = addrTop;
      sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
      pItem->fg.viaCoroutine = 1;
      pItem->regResult = dest.iSdst;
      sqlite3VdbeEndCoroutine(v, pItem->regReturn);
      sqlite3VdbeJumpHere(v, addrTop-1);
      sqlite3ClearTempRegCache(pParse);
    }else{
      /* Generate a subroutine that will fill an ephemeral table with
      ** the content of this subquery.  pItem->addrFillSub will point
      ** to the address of the generated subroutine.  pItem->regReturn
      ** is a register allocated to hold the subroutine return address

Changes to src/test_config.c.

371
372
373
374
375
376
377






378
379
380
381
382
383
384
#endif

#ifdef SQLITE_ENABLE_FTS3
  Tcl_SetVar2(interp, "sqlite_options", "fts3", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "fts3", "0", TCL_GLOBAL_ONLY);
#endif







#ifdef SQLITE_ENABLE_FTS5
  Tcl_SetVar2(interp, "sqlite_options", "fts5", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "fts5", "0", TCL_GLOBAL_ONLY);
#endif








>
>
>
>
>
>







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#endif

#ifdef SQLITE_ENABLE_FTS3
  Tcl_SetVar2(interp, "sqlite_options", "fts3", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "fts3", "0", TCL_GLOBAL_ONLY);
#endif

#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
  Tcl_SetVar2(interp, "sqlite_options", "fts3_tokenizer", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "fts3_tokenizer", "0", TCL_GLOBAL_ONLY);
#endif

#ifdef SQLITE_ENABLE_FTS5
  Tcl_SetVar2(interp, "sqlite_options", "fts5", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "fts5", "0", TCL_GLOBAL_ONLY);
#endif

Changes to src/tokenize.c.

14
15
16
17
18
19
20














































































21
22
23
24
25
26



27
28
29
30
31
32
33
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
...
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
...
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
...
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
...
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
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
*/
#include "sqliteInt.h"
#include <stdlib.h>















































































/*
** The charMap() macro maps alphabetic characters into their
** lower-case ASCII equivalent.  On ASCII machines, this is just
** an upper-to-lower case map.  On EBCDIC machines we also need
** to adjust the encoding.  Only alphabetic characters and underscores
** need to be translated.



*/
#ifdef SQLITE_ASCII
# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
#endif
#ifdef SQLITE_EBCDIC
# define charMap(X) ebcdicToAscii[(unsigned char)X]
const unsigned char ebcdicToAscii[] = {
................................................................................

/*
** The sqlite3KeywordCode function looks up an identifier to determine if
** it is a keyword.  If it is a keyword, the token code of that keyword is 
** returned.  If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.h, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.h and then included into this source file by
** the #include below.
*/
#include "keywordhash.h"


................................................................................
/* Make the IdChar function accessible from ctime.c */
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3IsIdChar(u8 c){ return IdChar(c); }
#endif


/*
** Return the length of the token that begins at z[0]. 
** Store the token type in *tokenType before returning.
*/
int sqlite3GetToken(const unsigned char *z, int *tokenType){
  int i, c;
  switch( *z ){
    case ' ': case '\t': case '\n': case '\f': case '\r': {


      testcase( z[0]==' ' );
      testcase( z[0]=='\t' );
      testcase( z[0]=='\n' );
      testcase( z[0]=='\f' );
      testcase( z[0]=='\r' );
      for(i=1; sqlite3Isspace(z[i]); i++){}
      *tokenType = TK_SPACE;
      return i;
    }
    case '-': {
      if( z[1]=='-' ){
        for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
        *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
        return i;
      }
      *tokenType = TK_MINUS;
      return 1;
    }
    case '(': {
      *tokenType = TK_LP;
      return 1;
    }
    case ')': {
      *tokenType = TK_RP;
      return 1;
    }
    case ';': {
      *tokenType = TK_SEMI;
      return 1;
    }
    case '+': {
      *tokenType = TK_PLUS;
      return 1;
    }
    case '*': {
      *tokenType = TK_STAR;
      return 1;
    }
    case '/': {
      if( z[1]!='*' || z[2]==0 ){
        *tokenType = TK_SLASH;
        return 1;
      }
      for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
      if( c ) i++;
      *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
      return i;
    }
    case '%': {
      *tokenType = TK_REM;
      return 1;
    }
    case '=': {
      *tokenType = TK_EQ;
      return 1 + (z[1]=='=');
    }
    case '<': {
      if( (c=z[1])=='=' ){
        *tokenType = TK_LE;
        return 2;
      }else if( c=='>' ){
        *tokenType = TK_NE;
        return 2;
      }else if( c=='<' ){
................................................................................
        *tokenType = TK_LSHIFT;
        return 2;
      }else{
        *tokenType = TK_LT;
        return 1;
      }
    }
    case '>': {
      if( (c=z[1])=='=' ){
        *tokenType = TK_GE;
        return 2;
      }else if( c=='>' ){
        *tokenType = TK_RSHIFT;
        return 2;
      }else{
        *tokenType = TK_GT;
        return 1;
      }
    }
    case '!': {
      if( z[1]!='=' ){
        *tokenType = TK_ILLEGAL;
        return 2;
      }else{
        *tokenType = TK_NE;
        return 2;
      }
    }
    case '|': {
      if( z[1]!='|' ){
        *tokenType = TK_BITOR;
        return 1;
      }else{
        *tokenType = TK_CONCAT;
        return 2;
      }
    }
    case ',': {
      *tokenType = TK_COMMA;
      return 1;
    }
    case '&': {
      *tokenType = TK_BITAND;
      return 1;
    }
    case '~': {
      *tokenType = TK_BITNOT;
      return 1;
    }
    case '`':
    case '\'':
    case '"': {
      int delim = z[0];
      testcase( delim=='`' );
      testcase( delim=='\'' );
      testcase( delim=='"' );
      for(i=1; (c=z[i])!=0; i++){
        if( c==delim ){
          if( z[i+1]==delim ){
................................................................................
        *tokenType = TK_ID;
        return i+1;
      }else{
        *tokenType = TK_ILLEGAL;
        return i;
      }
    }
    case '.': {
#ifndef SQLITE_OMIT_FLOATING_POINT
      if( !sqlite3Isdigit(z[1]) )
#endif
      {
        *tokenType = TK_DOT;
        return 1;
      }
      /* If the next character is a digit, this is a floating point
      ** number that begins with ".".  Fall thru into the next case */
    }
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9': {
      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' );
      *tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
      if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
................................................................................
#endif
      while( IdChar(z[i]) ){
        *tokenType = TK_ILLEGAL;
        i++;
      }
      return i;
    }
    case '[': {
      for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
      *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
      return i;
    }
    case '?': {
      *tokenType = TK_VARIABLE;
      for(i=1; sqlite3Isdigit(z[i]); i++){}
      return i;
    }
#ifndef SQLITE_OMIT_TCL_VARIABLE
    case '$':
#endif
    case '@':  /* For compatibility with MS SQL Server */
    case '#':
    case ':': {
      int n = 0;
      testcase( z[0]=='$' );  testcase( z[0]=='@' );
      testcase( z[0]==':' );  testcase( z[0]=='#' );
      *tokenType = TK_VARIABLE;
      for(i=1; (c=z[i])!=0; i++){
        if( IdChar(c) ){
          n++;
................................................................................
        }else{
          break;
        }
      }
      if( n==0 ) *tokenType = TK_ILLEGAL;
      return i;
    }












#ifndef SQLITE_OMIT_BLOB_LITERAL
    case 'x': case 'X': {

      testcase( z[0]=='x' ); testcase( z[0]=='X' );
      if( z[1]=='\'' ){
        *tokenType = TK_BLOB;
        for(i=2; sqlite3Isxdigit(z[i]); i++){}
        if( z[i]!='\'' || i%2 ){
          *tokenType = TK_ILLEGAL;
          while( z[i] && z[i]!='\'' ){ i++; }
        }
        if( z[i] ) i++;
        return i;
      }
      /* Otherwise fall through to the next case */

    }
#endif
    default: {
      if( !IdChar(*z) ){

        break;
      }
      for(i=1; IdChar(z[i]); i++){}

      *tokenType = TK_ID;
      return keywordCode((char*)z, i, tokenType);

    }
  }

  *tokenType = TK_ILLEGAL;
  return 1;
}

/*
** Run the parser on the given SQL string.  The parser structure is
** passed in.  An SQLITE_ status code is returned.  If an error occurs
** then an and attempt is made to write an error message into 
** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that







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

|


|
<
>
>
>







 







|







 







|




|
|
>
>









|








|



|



|



|



|



|









|



|



|







 







|











|








|








|



|



|



|
<
<







 







|










|
<







 







|




|




|
|
<
<
<
<







 







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

<
>











|
>


<
|
>
|
|
<
>
|
<
>


>
|
|







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
...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
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
...
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
...
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
...
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
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
*/
#include "sqliteInt.h"
#include <stdlib.h>

/* Character classes for tokenizing
**
** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
** using a lookup table, whereas a switch() directly on c uses a binary search.
** The lookup table is much faster.  To maximize speed, and to ensure that
** a lookup table is used, all of the classes need to be small integers and
** all of them need to be used within the switch.
*/
#define CC_X          0    /* The letter 'x', or start of BLOB literal */
#define CC_KYWD       1    /* Alphabetics or '_'.  Usable in a keyword */
#define CC_ID         2    /* unicode characters usable in IDs */
#define CC_DIGIT      3    /* Digits */
#define CC_DOLLAR     4    /* '$' */
#define CC_VARALPHA   5    /* '@', '#', ':'.  Alphabetic SQL variables */
#define CC_VARNUM     6    /* '?'.  Numeric SQL variables */
#define CC_SPACE      7    /* Space characters */
#define CC_QUOTE      8    /* '"', '\'', or '`'.  String literals, quoted ids */
#define CC_QUOTE2     9    /* '['.   [...] style quoted ids */
#define CC_PIPE      10    /* '|'.   Bitwise OR or concatenate */
#define CC_MINUS     11    /* '-'.  Minus or SQL-style comment */
#define CC_LT        12    /* '<'.  Part of < or <= or <> */
#define CC_GT        13    /* '>'.  Part of > or >= */
#define CC_EQ        14    /* '='.  Part of = or == */
#define CC_BANG      15    /* '!'.  Part of != */
#define CC_SLASH     16    /* '/'.  / or c-style comment */
#define CC_LP        17    /* '(' */
#define CC_RP        18    /* ')' */
#define CC_SEMI      19    /* ';' */
#define CC_PLUS      20    /* '+' */
#define CC_STAR      21    /* '*' */
#define CC_PERCENT   22    /* '%' */
#define CC_COMMA     23    /* ',' */
#define CC_AND       24    /* '&' */
#define CC_TILDA     25    /* '~' */
#define CC_DOT       26    /* '.' */
#define CC_ILLEGAL   27    /* Illegal character */

static const unsigned char aiClass[] = {
#ifdef SQLITE_ASCII
/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */
/* 0x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7, 27,  7,  7, 27, 27,
/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 2x */    7, 15,  8,  5,  4, 22, 24,  8, 17, 18, 21, 20, 23, 11, 26, 16,
/* 3x */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  5, 19, 12, 14, 13,  6,
/* 4x */    5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
/* 5x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  9, 27, 27, 27,  1,
/* 6x */    8,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
/* 7x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1, 27, 10, 27, 25, 27,
/* 8x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* 9x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* Ax */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* Bx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* Cx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* Dx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* Ex */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* Fx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2
#endif
#ifdef SQLITE_EBCDIC
/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */
/* 0x */   27, 27, 27, 27, 27,  7, 27, 27, 27, 27, 27, 27,  7,  7, 27, 27,
/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 2x */   27, 27, 27, 27, 27,  7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 3x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 4x */    7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 12, 17, 20, 10,
/* 5x */   24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15,  4, 21, 18, 19, 27,
/* 6x */   11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22,  1, 13,  7,
/* 7x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  8,  5,  5,  5,  8, 14,  8,
/* 8x */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
/* 9x */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
/* 9x */   25,  1,  1,  1,  1,  1,  1,  0,  1,  1, 27, 27, 27, 27, 27, 27,
/* Bx */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  9, 27, 27, 27, 27, 27,
/* Cx */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
/* Dx */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
/* Ex */   27, 27,  1,  1,  1,  1,  1,  0,  1,  1, 27, 27, 27, 27, 27, 27,
/* Fx */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3, 27, 27, 27, 27, 27, 27,
#endif
};

/*
** The charMap() macro maps alphabetic characters (only) into their
** lower-case ASCII equivalent.  On ASCII machines, this is just
** an upper-to-lower case map.  On EBCDIC machines we also need
** to adjust the encoding.  The mapping is only valid for alphabetics

** which are the only characters for which this feature is used. 
**
** Used by keywordhash.h
*/
#ifdef SQLITE_ASCII
# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
#endif
#ifdef SQLITE_EBCDIC
# define charMap(X) ebcdicToAscii[(unsigned char)X]
const unsigned char ebcdicToAscii[] = {
................................................................................

/*
** The sqlite3KeywordCode function looks up an identifier to determine if
** it is a keyword.  If it is a keyword, the token code of that keyword is 
** returned.  If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.c, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.h and then included into this source file by
** the #include below.
*/
#include "keywordhash.h"


................................................................................
/* Make the IdChar function accessible from ctime.c */
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3IsIdChar(u8 c){ return IdChar(c); }
#endif


/*
** Return the length (in bytes) of the token that begins at z[0]. 
** Store the token type in *tokenType before returning.
*/
int sqlite3GetToken(const unsigned char *z, int *tokenType){
  int i, c;
  switch( aiClass[*z] ){  /* Switch on the character-class of the first byte
                          ** of the token. See the comment on the CC_ defines
                          ** above. */
    case CC_SPACE: {
      testcase( z[0]==' ' );
      testcase( z[0]=='\t' );
      testcase( z[0]=='\n' );
      testcase( z[0]=='\f' );
      testcase( z[0]=='\r' );
      for(i=1; sqlite3Isspace(z[i]); i++){}
      *tokenType = TK_SPACE;
      return i;
    }
    case CC_MINUS: {
      if( z[1]=='-' ){
        for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
        *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
        return i;
      }
      *tokenType = TK_MINUS;
      return 1;
    }
    case CC_LP: {
      *tokenType = TK_LP;
      return 1;
    }
    case CC_RP: {
      *tokenType = TK_RP;
      return 1;
    }
    case CC_SEMI: {
      *tokenType = TK_SEMI;
      return 1;
    }
    case CC_PLUS: {
      *tokenType = TK_PLUS;
      return 1;
    }
    case CC_STAR: {
      *tokenType = TK_STAR;
      return 1;
    }
    case CC_SLASH: {
      if( z[1]!='*' || z[2]==0 ){
        *tokenType = TK_SLASH;
        return 1;
      }
      for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
      if( c ) i++;
      *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
      return i;
    }
    case CC_PERCENT: {
      *tokenType = TK_REM;
      return 1;
    }
    case CC_EQ: {
      *tokenType = TK_EQ;
      return 1 + (z[1]=='=');
    }
    case CC_LT: {
      if( (c=z[1])=='=' ){
        *tokenType = TK_LE;
        return 2;
      }else if( c=='>' ){
        *tokenType = TK_NE;
        return 2;
      }else if( c=='<' ){
................................................................................
        *tokenType = TK_LSHIFT;
        return 2;
      }else{
        *tokenType = TK_LT;
        return 1;
      }
    }
    case CC_GT: {
      if( (c=z[1])=='=' ){
        *tokenType = TK_GE;
        return 2;
      }else if( c=='>' ){
        *tokenType = TK_RSHIFT;
        return 2;
      }else{
        *tokenType = TK_GT;
        return 1;
      }
    }
    case CC_BANG: {
      if( z[1]!='=' ){
        *tokenType = TK_ILLEGAL;
        return 2;
      }else{
        *tokenType = TK_NE;
        return 2;
      }
    }
    case CC_PIPE: {
      if( z[1]!='|' ){
        *tokenType = TK_BITOR;
        return 1;
      }else{
        *tokenType = TK_CONCAT;
        return 2;
      }
    }
    case CC_COMMA: {
      *tokenType = TK_COMMA;
      return 1;
    }
    case CC_AND: {
      *tokenType = TK_BITAND;
      return 1;
    }
    case CC_TILDA: {
      *tokenType = TK_BITNOT;
      return 1;
    }
    case CC_QUOTE: {


      int delim = z[0];
      testcase( delim=='`' );
      testcase( delim=='\'' );
      testcase( delim=='"' );
      for(i=1; (c=z[i])!=0; i++){
        if( c==delim ){
          if( z[i+1]==delim ){
................................................................................
        *tokenType = TK_ID;
        return i+1;
      }else{
        *tokenType = TK_ILLEGAL;
        return i;
      }
    }
    case CC_DOT: {
#ifndef SQLITE_OMIT_FLOATING_POINT
      if( !sqlite3Isdigit(z[1]) )
#endif
      {
        *tokenType = TK_DOT;
        return 1;
      }
      /* If the next character is a digit, this is a floating point
      ** number that begins with ".".  Fall thru into the next case */
    }
    case CC_DIGIT: {

      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' );
      *tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
      if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
................................................................................
#endif
      while( IdChar(z[i]) ){
        *tokenType = TK_ILLEGAL;
        i++;
      }
      return i;
    }
    case CC_QUOTE2: {
      for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
      *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
      return i;
    }
    case CC_VARNUM: {
      *tokenType = TK_VARIABLE;
      for(i=1; sqlite3Isdigit(z[i]); i++){}
      return i;
    }
    case CC_DOLLAR:
    case CC_VARALPHA: {




      int n = 0;
      testcase( z[0]=='$' );  testcase( z[0]=='@' );
      testcase( z[0]==':' );  testcase( z[0]=='#' );
      *tokenType = TK_VARIABLE;
      for(i=1; (c=z[i])!=0; i++){
        if( IdChar(c) ){
          n++;
................................................................................
        }else{
          break;
        }
      }
      if( n==0 ) *tokenType = TK_ILLEGAL;
      return i;
    }
    case CC_KYWD: {
      for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
      if( IdChar(z[i]) ){
        /* This token started out using characters that can appear in keywords,
        ** but z[i] is a character not allowed within keywords, so this must
        ** be an identifier instead */
        i++;
        break;
      }
      *tokenType = TK_ID;
      return keywordCode((char*)z, i, tokenType);
    }
#ifndef SQLITE_OMIT_BLOB_LITERAL

    case CC_X: {
      testcase( z[0]=='x' ); testcase( z[0]=='X' );
      if( z[1]=='\'' ){
        *tokenType = TK_BLOB;
        for(i=2; sqlite3Isxdigit(z[i]); i++){}
        if( z[i]!='\'' || i%2 ){
          *tokenType = TK_ILLEGAL;
          while( z[i] && z[i]!='\'' ){ i++; }
        }
        if( z[i] ) i++;
        return i;
      }
      /* If it is not a BLOB literal, then it must be an ID, since no
      ** SQL keywords start with the letter 'x'.  Fall through */
    }
#endif

    case CC_ID: {
      i = 1;
      break;
    }

    default: {
      *tokenType = TK_ILLEGAL;

      return 1;
    }
  }
  while( IdChar(z[i]) ){ i++; }
  *tokenType = TK_ID;
  return i;
}

/*
** Run the parser on the given SQL string.  The parser structure is
** passed in.  An SQLITE_ status code is returned.  If an error occurs
** then an and attempt is made to write an error message into 
** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that

Changes to src/vdbe.h.

178
179
180
181
182
183
184

185
186
187
188
189
190
191
int sqlite3VdbeGoto(Vdbe*,int);
int sqlite3VdbeLoadString(Vdbe*,int,const char*);
void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);

#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
  void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
#else
# define sqlite3VdbeVerifyNoMallocRequired(A,B)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);







>







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
int sqlite3VdbeGoto(Vdbe*,int);
int sqlite3VdbeLoadString(Vdbe*,int,const char*);
void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
void sqlite3VdbeEndCoroutine(Vdbe*,int);
#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
  void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
#else
# define sqlite3VdbeVerifyNoMallocRequired(A,B)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);

Changes to src/vdbeaux.c.

320
321
322
323
324
325
326















327
328
329
330
331
332
333
  int p3,             /* The P3 operand */
  int p4              /* The P4 operand as an integer */
){
  int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
  sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
  return addr;
}
















/*
** Create a new symbolic label for an instruction that has yet to be
** coded.  The symbolic label is really just a negative number.  The
** label can be used as the P2 value of an operation.  Later, when
** the label is resolved to a specific address, the VDBE will scan
** through its operation list and change all values of P2 which match







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







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
  int p3,             /* The P3 operand */
  int p4              /* The P4 operand as an integer */
){
  int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
  sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
  return addr;
}

/* Insert the end of a co-routine
*/
void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);

  /* Clear the temporary register cache, thereby ensuring that each
  ** co-routine has its own independent set of registers, because co-routines
  ** might expect their registers to be preserved across an OP_Yield, and
  ** that could cause problems if two or more co-routines are using the same
  ** temporary register.
  */
  v->pParse->nTempReg = 0;
  v->pParse->nRangeReg = 0;
}

/*
** Create a new symbolic label for an instruction that has yet to be
** coded.  The symbolic label is really just a negative number.  The
** label can be used as the P2 value of an operation.  Later, when
** the label is resolved to a specific address, the VDBE will scan
** through its operation list and change all values of P2 which match

Changes to test/analyze9.test.

1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)}
}


finish_test










<
<
<
1240
1241
1242
1243
1244
1245
1246



  SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)}
}


finish_test



Changes to test/analyzeB.test.

676
677
678
679
680
681
682
683
    set val $i
    do_execsql_test 20.3.$i {
      SELECT count(*) FROM sqlite_stat3 WHERE sample=$val
    } {1}
}

finish_test








<
676
677
678
679
680
681
682

    set val $i
    do_execsql_test 20.3.$i {
      SELECT count(*) FROM sqlite_stat3 WHERE sample=$val
    } {1}
}

finish_test

Changes to test/analyzeD.test.

110
111
112
113
114
115
116
117
do_eqp_test 1.8 {
  SELECT * FROM t1 WHERE a=13 AND c=150;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}

finish_test








<
110
111
112
113
114
115
116

do_eqp_test 1.8 {
  SELECT * FROM t1 WHERE a=13 AND c=150;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}

finish_test

Changes to test/cacheflush.test.

317
318
319
320
321
322
323
324
    SELECT a FROM ta;
    SELECT b FROM tb;
  }
} {a b}

test_restore_config_pagecache
finish_test








<
317
318
319
320
321
322
323

    SELECT a FROM ta;
    SELECT b FROM tb;
  }
} {a b}

test_restore_config_pagecache
finish_test

Changes to test/cffault.test.

152
153
154
155
156
157
158
159
} -test {
  faultsim_test_result {0 {1 1 3 3 5 5 7 7 9 9}} {1 {disk I/O error}}
  catchsql ROLLBACK
  faultsim_integrity_check
}

finish_test








<
152
153
154
155
156
157
158

} -test {
  faultsim_test_result {0 {1 1 3 3 5 5 7 7 9 9}} {1 {disk I/O error}}
  catchsql ROLLBACK
  faultsim_integrity_check
}

finish_test

Changes to test/corruptH.test.

170
171
172
173
174
175
176
177
      DELETE FROM t2 WHERE c=1;
    }
  }
  } msg] $msg
} {1 {database disk image is malformed}}

finish_test








<
170
171
172
173
174
175
176

      DELETE FROM t2 WHERE c=1;
    }
  }
  } msg] $msg
} {1 {database disk image is malformed}}

finish_test

Changes to test/corruptI.test.

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  INSERT INTO t1 VALUES(zeroblob(300));
  INSERT INTO t1 VALUES(zeroblob(600));
} {}
do_test 6.1 {
  db close
  hexio_write test.db 616 8FFFFFFF7F02
  sqlite3 db test.db
  breakpoint
  execsql { DELETE FROM t1 WHERE rowid=2 }
} {}

#-------------------------------------------------------------------------
# See what happens if the sqlite_master entry associated with a PRIMARY
# KEY or UNIQUE index is removed. 
#







<







202
203
204
205
206
207
208

209
210
211
212
213
214
215
  INSERT INTO t1 VALUES(zeroblob(300));
  INSERT INTO t1 VALUES(zeroblob(600));
} {}
do_test 6.1 {
  db close
  hexio_write test.db 616 8FFFFFFF7F02
  sqlite3 db test.db

  execsql { DELETE FROM t1 WHERE rowid=2 }
} {}

#-------------------------------------------------------------------------
# See what happens if the sqlite_master entry associated with a PRIMARY
# KEY or UNIQUE index is removed. 
#

Changes to test/cost.test.

283
284
285
286
287
288
289
290
291
292
    SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0
  } {
    0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)}
  }
}

finish_test










<
<
<
283
284
285
286
287
288
289



    SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0
  } {
    0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)}
  }
}

finish_test



Changes to test/e_blobbytes.test.

68
69
70
71
72
73
74
75
76
do_test 2.1 {
  sqlite3_blob_open db main q1 s 86 1 B
  list [catch { sqlite3_blob_write $B 86 "1" 1 } msg] $msg
} {1 SQLITE_ERROR}
sqlite3_blob_close $B

finish_test









<
<
68
69
70
71
72
73
74


do_test 2.1 {
  sqlite3_blob_open db main q1 s 86 1 B
  list [catch { sqlite3_blob_write $B 86 "1" 1 } msg] $msg
} {1 SQLITE_ERROR}
sqlite3_blob_close $B

finish_test


Changes to test/e_blobclose.test.

164
165
166
167
168
169
170
171
# EVIDENCE-OF: R-25894-51060 Calling this routine with a null pointer
# (such as would be returned by a failed call to sqlite3_blob_open()) is
# a harmless no-op.
#
do_test 4.0 { sqlite3_blob_close 0 } {}

finish_test








<
164
165
166
167
168
169
170

# EVIDENCE-OF: R-25894-51060 Calling this routine with a null pointer
# (such as would be returned by a failed call to sqlite3_blob_open()) is
# a harmless no-op.
#
do_test 4.0 { sqlite3_blob_close 0 } {}

finish_test

Changes to test/e_blobopen.test.

542
543
544
545
546
547
548
549
} [list \
    [string repeat [binary format c 1] 24] \
    [string repeat [binary format c 1] 45] \
]


finish_test








<
542
543
544
545
546
547
548

} [list \
    [string repeat [binary format c 1] 24] \
    [string repeat [binary format c 1] 45] \
]


finish_test

Changes to test/e_blobwrite.test.

197
198
199
200
201
202
203
204
} {
  2 xyz ........................................
}



finish_test








<
197
198
199
200
201
202
203

} {
  2 xyz ........................................
}



finish_test

Changes to test/e_walckpt.test.

747
748
749
750
751
752
753
754
  db2 eval COMMIT
  wal_checkpoint_v2 db truncate
} {0 0 0}



finish_test








<
747
748
749
750
751
752
753

  db2 eval COMMIT
  wal_checkpoint_v2 db truncate
} {0 0 0}



finish_test

Changes to test/fkey8.test.

99
100
101
102
103
104
105
106
    sqlite3_finalize $stmt
    set ret
  } $use_stmt
}


finish_test








<
99
100
101
102
103
104
105

    sqlite3_finalize $stmt
    set ret
  } $use_stmt
}


finish_test

Changes to test/fordelete.test.

203
204
205
206
207
208
209
210
} {1 2}
do_execsql_test 5.3 {
  DELETE FROM t1 WHERE a = 2;
} {}


finish_test








<
203
204
205
206
207
208
209

} {1 2}
do_execsql_test 5.3 {
  DELETE FROM t1 WHERE a = 2;
} {}


finish_test

Changes to test/fts3atoken.test.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
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
...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
202
203
204
205
206
207
208

209
210
211
212
213
214

215
216
217

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
  finish_test
  return
}

set ::testprefix fts3token

proc escape_string {str} {
  set out ""
  foreach char [split $str ""] {
    scan $char %c i
    if {$i<=127} {
      append out $char
................................................................................
      append out [format {\x%.4x} $i]
    }
  }
  set out
}

#--------------------------------------------------------------------------
# Test cases fts3token-1.* are the warm-body test for the SQL scalar
# function fts3_tokenizer(). The procedure is as follows:
#
#   1: Verify that there is no such fts3 tokenizer as 'blah'.
#
#   2: Query for the built-in tokenizer 'simple'. Insert a copy of the
#      retrieved value as tokenizer 'blah'.
#
................................................................................
#      same as that retrieved for 'simple'.
#
#   4: Test that it is now possible to create an fts3 table using 
#      tokenizer 'blah' (it was not possible in step 1).
#
#   5: Test that the table created to use tokenizer 'blah' is usable.
#

do_test fts3token-1.1 {
  catchsql {
    CREATE VIRTUAL TABLE t1 USING fts3(content, tokenize blah);
  }
} {1 {unknown tokenizer: blah}}
do_test fts3token-1.2 {
  execsql {
    SELECT fts3_tokenizer('blah', fts3_tokenizer('simple')) IS NULL;
  }
} {0}
do_test fts3token-1.3 {
  execsql {
    SELECT fts3_tokenizer('blah') == fts3_tokenizer('simple');
  }
} {1}
do_test fts3token-1.4 {
  catchsql {
    CREATE VIRTUAL TABLE t1 USING fts3(content, tokenize blah);
  }
} {0 {}}
do_test fts3token-1.5 {
  execsql {
    INSERT INTO t1(content) VALUES('There was movement at the station');
    INSERT INTO t1(content) VALUES('For the word has passed around');
    INSERT INTO t1(content) VALUES('That the colt from ol regret had got away');
    SELECT content FROM t1 WHERE content MATCH 'movement'
  }
} {{There was movement at the station}}






#--------------------------------------------------------------------------
# Test cases fts3token-2.* test error cases in the scalar function based
# API for getting and setting tokenizers.
#
do_test fts3token-2.1 {
  catchsql {
    SELECT fts3_tokenizer('nosuchtokenizer');
  }
} {1 {unknown tokenizer: nosuchtokenizer}}

#--------------------------------------------------------------------------
# Test cases fts3token-3.* test the three built-in tokenizers with a
# simple input string via the built-in test function. This is as much
# to test the test function as the tokenizer implementations.
#
do_test fts3token-3.1 {
  execsql {
    SELECT fts3_tokenizer_test('simple', 'I don''t see how');
  }
} {{0 i I 1 don don 2 t t 3 see see 4 how how}}
do_test fts3token-3.2 {
  execsql {
    SELECT fts3_tokenizer_test('porter', 'I don''t see how');
  }
} {{0 i I 1 don don 2 t t 3 see see 4 how how}}
ifcapable icu {
  do_test fts3token-3.3 {
    execsql {
      SELECT fts3_tokenizer_test('icu', 'I don''t see how');
    }
  } {{0 i I 1 don't don't 2 see see 3 how how}}
}

#--------------------------------------------------------------------------
# Test cases fts3token-4.* test the ICU tokenizer. In practice, this
# tokenizer only has two modes - "thai" and "everybody else". Some other
# Asian languages (Lao, Khmer etc.) require the same special treatment as 
# Thai, but ICU doesn't support them yet.
#
ifcapable icu {

  proc do_icu_test {name locale input output} {
    set ::out [db eval { SELECT fts3_tokenizer_test('icu', $locale, $input) }]
    do_test $name {
      lindex $::out 0
    } $output
  }
  
  do_icu_test fts3token-4.1 en_US  {}   {}
  do_icu_test fts3token-4.2 en_US {Test cases fts3} [list \
    0 test Test 1 cases cases 2 fts3 fts3
  ]

  # The following test shows that ICU is smart enough to recognise
  # Thai chararacters, even when the locale is set to English/United 
  # States.
  #
  set input "\u0e2d\u0e30\u0e44\u0e23\u0e19\u0e30\u0e04\u0e23\u0e31\u0e1a"
  set output    "0 \u0e2d\u0e30\u0e44\u0e23 \u0e2d\u0e30\u0e44\u0e23 "
  append output "1 \u0e19\u0e30 \u0e19\u0e30 "
  append output "2 \u0e04\u0e23\u0e31\u0e1a \u0e04\u0e23\u0e31\u0e1a"

  do_icu_test fts3token-4.3 th_TH  $input $output
  do_icu_test fts3token-4.4 en_US  $input $output

  # ICU handles an unknown locale by falling back to the default.
  # So this is not an error.
  do_icu_test fts3token-4.5 MiddleOfTheOcean  $input $output

  set    longtoken "AReallyReallyLongTokenOneThatWillSurelyRequire"
  append longtoken "AReallocInTheIcuTokenizerCode"

  set    input "short tokens then "
  append input $longtoken
  set    output "0 short short "
  append output "1 tokens tokens "
  append output "2 then then "
  append output "3 [string tolower $longtoken] $longtoken"

  do_icu_test fts3token-4.6 MiddleOfTheOcean  $input $output
  do_icu_test fts3token-4.7 th_TH  $input $output
  do_icu_test fts3token-4.8 en_US  $input $output

  do_execsql_test 5.1 {
    CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US);
    insert into x1 (name) values (NULL);
    insert into x1 (name) values (NULL);
    delete from x1;
  }
................................................................................

  do_test 5.2 {
    set str [cp_to_str {19968 26085 32822 32645 27874 23433 20986}]
    execsql { INSERT INTO x1 VALUES($str) }
  } {}
}

do_test fts3token-internal {
  execsql { SELECT fts3_tokenizer_internal_test() }
} {ok}

#-------------------------------------------------------------------------
# Test empty tokenizer names.
#
do_catchsql_test 6.1.1 {
................................................................................
do_catchsql_test 6.1.3 {
  CREATE VIRTUAL TABLE t3 USING fts4(tokenize="   ");
} {1 {unknown tokenizer:    }}

do_catchsql_test 6.2.1 {
  SELECT fts3_tokenizer(NULL);
} {1 {unknown tokenizer: }}

do_catchsql_test 6.2.2 {
  SELECT fts3_tokenizer(NULL, X'1234567812345678');
} {1 {argument type mismatch}}
do_catchsql_test 6.2.3 {
  SELECT fts3_tokenizer(NULL, X'12345678');
} {1 {argument type mismatch}}



finish_test







|







 







|







 







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

|


|






|



|




|





|







|













|
|












|
|



|











|
|
|







 







|







 







>
|
|
|
|
|
|
>



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
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
...
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

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
  finish_test
  return
}

set ::testprefix fts3atoken

proc escape_string {str} {
  set out ""
  foreach char [split $str ""] {
    scan $char %c i
    if {$i<=127} {
      append out $char
................................................................................
      append out [format {\x%.4x} $i]
    }
  }
  set out
}

#--------------------------------------------------------------------------
# Test cases fts3atoken-1.* are the warm-body test for the SQL scalar
# function fts3_tokenizer(). The procedure is as follows:
#
#   1: Verify that there is no such fts3 tokenizer as 'blah'.
#
#   2: Query for the built-in tokenizer 'simple'. Insert a copy of the
#      retrieved value as tokenizer 'blah'.
#
................................................................................
#      same as that retrieved for 'simple'.
#
#   4: Test that it is now possible to create an fts3 table using 
#      tokenizer 'blah' (it was not possible in step 1).
#
#   5: Test that the table created to use tokenizer 'blah' is usable.
#
ifcapable fts3_tokenizer {
  do_test fts3atoken-1.1 {
    catchsql {
      CREATE VIRTUAL TABLE t1 USING fts3(content, tokenize blah);
    }
  } {1 {unknown tokenizer: blah}}
  do_test fts3atoken-1.2 {
    execsql {
      SELECT fts3_tokenizer('blah', fts3_tokenizer('simple')) IS NULL;
    }
  } {0}
  do_test fts3atoken-1.3 {
    execsql {
      SELECT fts3_tokenizer('blah') == fts3_tokenizer('simple');
    }
  } {1}
  do_test fts3atoken-1.4 {
    catchsql {
      CREATE VIRTUAL TABLE t1 USING fts3(content, tokenize blah);
    }
  } {0 {}}
  do_test fts3atoken-1.5 {
    execsql {
      INSERT INTO t1(content) VALUES('There was movement at the station');
      INSERT INTO t1(content) VALUES('For the word has passed around');
      INSERT INTO t1(content) VALUES('That the colt from ol regret had got');
      SELECT content FROM t1 WHERE content MATCH 'movement'
    }
  } {{There was movement at the station}}
} else {
  do_catchsql_test 1.6 {
    SELECT fts3_tokenizer('blah', fts3_tokenizer('simple')) IS NULL;
  } {1 {fts3tokenize: disabled - rebuild with -DSQLITE_ENABLE_FTS3_TOKENIZER}}
}

#--------------------------------------------------------------------------
# Test cases fts3atoken-2.* test error cases in the scalar function based
# API for getting and setting tokenizers.
#
do_test fts3atoken-2.1 {
  catchsql {
    SELECT fts3_tokenizer('nosuchtokenizer');
  }
} {1 {unknown tokenizer: nosuchtokenizer}}

#--------------------------------------------------------------------------
# Test cases fts3atoken-3.* test the three built-in tokenizers with a
# simple input string via the built-in test function. This is as much
# to test the test function as the tokenizer implementations.
#
do_test fts3atoken-3.1 {
  execsql {
    SELECT fts3_tokenizer_test('simple', 'I don''t see how');
  }
} {{0 i I 1 don don 2 t t 3 see see 4 how how}}
do_test fts3atoken-3.2 {
  execsql {
    SELECT fts3_tokenizer_test('porter', 'I don''t see how');
  }
} {{0 i I 1 don don 2 t t 3 see see 4 how how}}
ifcapable icu {
  do_test fts3atoken-3.3 {
    execsql {
      SELECT fts3_tokenizer_test('icu', 'I don''t see how');
    }
  } {{0 i I 1 don't don't 2 see see 3 how how}}
}

#--------------------------------------------------------------------------
# Test cases fts3atoken-4.* test the ICU tokenizer. In practice, this
# tokenizer only has two modes - "thai" and "everybody else". Some other
# Asian languages (Lao, Khmer etc.) require the same special treatment as 
# Thai, but ICU doesn't support them yet.
#
ifcapable icu {

  proc do_icu_test {name locale input output} {
    set ::out [db eval { SELECT fts3_tokenizer_test('icu', $locale, $input) }]
    do_test $name {
      lindex $::out 0
    } $output
  }
  
  do_icu_test fts3atoken-4.1 en_US  {}   {}
  do_icu_test fts3atoken-4.2 en_US {Test cases fts3} [list \
    0 test Test 1 cases cases 2 fts3 fts3
  ]

  # The following test shows that ICU is smart enough to recognise
  # Thai chararacters, even when the locale is set to English/United 
  # States.
  #
  set input "\u0e2d\u0e30\u0e44\u0e23\u0e19\u0e30\u0e04\u0e23\u0e31\u0e1a"
  set output    "0 \u0e2d\u0e30\u0e44\u0e23 \u0e2d\u0e30\u0e44\u0e23 "
  append output "1 \u0e19\u0e30 \u0e19\u0e30 "
  append output "2 \u0e04\u0e23\u0e31\u0e1a \u0e04\u0e23\u0e31\u0e1a"

  do_icu_test fts3atoken-4.3 th_TH  $input $output
  do_icu_test fts3atoken-4.4 en_US  $input $output

  # ICU handles an unknown locale by falling back to the default.
  # So this is not an error.
  do_icu_test fts3atoken-4.5 MiddleOfTheOcean  $input $output

  set    longtoken "AReallyReallyLongTokenOneThatWillSurelyRequire"
  append longtoken "AReallocInTheIcuTokenizerCode"

  set    input "short tokens then "
  append input $longtoken
  set    output "0 short short "
  append output "1 tokens tokens "
  append output "2 then then "
  append output "3 [string tolower $longtoken] $longtoken"

  do_icu_test fts3atoken-4.6 MiddleOfTheOcean  $input $output
  do_icu_test fts3atoken-4.7 th_TH  $input $output
  do_icu_test fts3atoken-4.8 en_US  $input $output

  do_execsql_test 5.1 {
    CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US);
    insert into x1 (name) values (NULL);
    insert into x1 (name) values (NULL);
    delete from x1;
  }
................................................................................

  do_test 5.2 {
    set str [cp_to_str {19968 26085 32822 32645 27874 23433 20986}]
    execsql { INSERT INTO x1 VALUES($str) }
  } {}
}

do_test fts3atoken-internal {
  execsql { SELECT fts3_tokenizer_internal_test() }
} {ok}

#-------------------------------------------------------------------------
# Test empty tokenizer names.
#
do_catchsql_test 6.1.1 {
................................................................................
do_catchsql_test 6.1.3 {
  CREATE VIRTUAL TABLE t3 USING fts4(tokenize="   ");
} {1 {unknown tokenizer:    }}

do_catchsql_test 6.2.1 {
  SELECT fts3_tokenizer(NULL);
} {1 {unknown tokenizer: }}
ifcapable fts3_tokenizer {
  do_catchsql_test 6.2.2 {
    SELECT fts3_tokenizer(NULL, X'1234567812345678');
  } {1 {argument type mismatch}}
  do_catchsql_test 6.2.3 {
    SELECT fts3_tokenizer(NULL, X'12345678');
  } {1 {argument type mismatch}}
}


finish_test

Changes to test/fts3conf.test.

208
209
210
211
212
213
214
215
}
do_execsql_test 4.2.2 {
  SELECT * FROM t01 WHERE t01 MATCH 'b';
  INSERT INTO t01(t01) VALUES('integrity-check');
} {}

finish_test








<
208
209
210
211
212
213
214

}
do_execsql_test 4.2.2 {
  SELECT * FROM t01 WHERE t01 MATCH 'b';
  INSERT INTO t01(t01) VALUES('integrity-check');
} {}

finish_test

Changes to test/fts3expr4.test.

75
76
77
78
79
80
81
82
do_simple_expr_test 3.8 { "abc"* } { PHRASE 3 0 abc }
do_simple_expr_test 3.8 { "ab*c" } { PHRASE 3 0 ab+ c }

do_icu_expr_test    3.9 { "ab*c" } { PHRASE 3 0 ab+ * c }
do_icu_expr_test    3.10 { ab*c } { AND {PHRASE 3 0 ab+} {PHRASE 3 0 c}}

finish_test








<
75
76
77
78
79
80
81

do_simple_expr_test 3.8 { "abc"* } { PHRASE 3 0 abc }
do_simple_expr_test 3.8 { "ab*c" } { PHRASE 3 0 ab+ c }

do_icu_expr_test    3.9 { "ab*c" } { PHRASE 3 0 ab+ * c }
do_icu_expr_test    3.10 { ab*c } { AND {PHRASE 3 0 ab+} {PHRASE 3 0 c}}

finish_test

Changes to test/fts3join.test.

58
59
60
61
62
63
64
65
66
do_execsql_test 2.4 { SELECT * FROM ft3, ft2 WHERE y MATCH x; } {abc abc}

do_catchsql_test 2.5 { 
  SELECT * FROM ft3, ft2 WHERE y MATCH x AND x MATCH y; 
} {1 {unable to use function MATCH in the requested context}}

finish_test









<
<
58
59
60
61
62
63
64


do_execsql_test 2.4 { SELECT * FROM ft3, ft2 WHERE y MATCH x; } {abc abc}

do_catchsql_test 2.5 { 
  SELECT * FROM ft3, ft2 WHERE y MATCH x AND x MATCH y; 
} {1 {unable to use function MATCH in the requested context}}

finish_test


Changes to test/fts3matchinfo.test.

520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
...
548
549
550
551
552
553
554
555
    }
    lappend r2 $M
  }

  do_execsql_test 11.1.$tn.2  {
    SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr
  } $r2
  breakpoint

  do_execsql_test 11.1.$tn.2  {
    SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr
  } $r2
}
set sqlite_fts3_enable_parentheses 0

................................................................................
do_execsql_test 12.1 {
  INSERT INTO tt (rowid, c4, c45) VALUES(1, 'abc', 'abc');
  SELECT mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH 'abc';
} [list [list [expr 1<<4] [expr 1<<(45-32)]]]

set sqlite_fts3_enable_parentheses 0
finish_test








<







 







<
520
521
522
523
524
525
526

527
528
529
530
531
532
533
...
547
548
549
550
551
552
553

    }
    lappend r2 $M
  }

  do_execsql_test 11.1.$tn.2  {
    SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr
  } $r2


  do_execsql_test 11.1.$tn.2  {
    SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr
  } $r2
}
set sqlite_fts3_enable_parentheses 0

................................................................................
do_execsql_test 12.1 {
  INSERT INTO tt (rowid, c4, c45) VALUES(1, 'abc', 'abc');
  SELECT mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH 'abc';
} [list [list [expr 1<<4] [expr 1<<(45-32)]]]

set sqlite_fts3_enable_parentheses 0
finish_test

Changes to test/fts3offsets.test.

117
118
119
120
121
122
123
124
  2 {(A) x x x x x x x x x x x B} 
  1 {(A) (B) (C)}
}


set sqlite_fts3_enable_parentheses 0
finish_test








<
117
118
119
120
121
122
123

  2 {(A) x x x x x x x x x x x B} 
  1 {(A) (B) (C)}
}


set sqlite_fts3_enable_parentheses 0
finish_test

Changes to test/fts3snippet.test.

555
556
557
558
559
560
561
562
} {64}




set sqlite_fts3_enable_parentheses 0
finish_test








<
555
556
557
558
559
560
561

} {64}




set sqlite_fts3_enable_parentheses 0
finish_test

Changes to test/fts4check.test.

206
207
208
209
210
211
212
213

do_execsql_test 5.4 {
  CREATE VIRTUAL TABLE t5 USING fts4(a, prefix="1,2,3");
  INSERT INTO t5(t5) VALUES('integrity-check');
} {}

finish_test








<
206
207
208
209
210
211
212


do_execsql_test 5.4 {
  CREATE VIRTUAL TABLE t5 USING fts4(a, prefix="1,2,3");
  INSERT INTO t5(t5) VALUES('integrity-check');
} {}

finish_test

Changes to test/fts4content.test.

632
633
634
635
636
637
638
639

do_catchsql_test 11.1 {
  CREATE VIRTUAL TABLE x1 USING fts4(content=x1);
} {1 {vtable constructor called recursively: x1}}


finish_test








<
632
633
634
635
636
637
638


do_catchsql_test 11.1 {
  CREATE VIRTUAL TABLE x1 USING fts4(content=x1);
} {1 {vtable constructor called recursively: x1}}


finish_test

Changes to test/fts4growth.test.

430
431
432
433
434
435
436
437
  SELECT sum(length(block)) FROM x6_segments 
  WHERE blockid BETWEEN 23695 AND 24147
} {633507}



finish_test








<
430
431
432
433
434
435
436

  SELECT sum(length(block)) FROM x6_segments 
  WHERE blockid BETWEEN 23695 AND 24147
} {633507}



finish_test

Changes to test/fts4growth2.test.

86
87
88
89
90
91
92
93
    }
    execsql { SELECT max(level) FROM x1_segdir }
  } {1}
}


finish_test








<
86
87
88
89
90
91
92

    }
    execsql { SELECT max(level) FROM x1_segdir }
  } {1}
}


finish_test

Changes to test/fts4langid.test.

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
  for {set i 0} {$i < 50} {incr i} {
    execsql { 
      INSERT INTO t4(docid, content, lid) VALUES($i, 'The Quick Brown Fox', $i) 
    }
  }
}


do_test 4.1.0 {
  reset_db
  set ptr [fts3_test_tokenizer]
  execsql { SELECT fts3_tokenizer('testtokenizer', $ptr) }
  build_multilingual_db_2 db
} {}
do_execsql_test 4.1.1 {
  SELECT docid FROM t4 WHERE t4 MATCH 'quick';
} {0}
do_execsql_test 4.1.2 {
  SELECT docid FROM t4 WHERE t4 MATCH 'quick' AND lid=1;
} {}
do_execsql_test 4.1.3 {
  SELECT docid FROM t4 WHERE t4 MATCH 'Quick' AND lid=1;
} {1}
for {set i 0} {$i < 50} {incr i} {
  do_execsql_test 4.1.4.$i {
    SELECT count(*) FROM t4 WHERE t4 MATCH 'fox' AND lid=$i;
  } [expr 0==($i%2)]
}
do_catchsql_test 4.1.5 {
  INSERT INTO t4(content, lid) VALUES('hello world', 101)
} {1 {SQL logic error or missing database}}


#-------------------------------------------------------------------------
# Test cases 5.*
#
# The following test cases are designed to detect a 32-bit overflow bug
# that existed at one point.
#







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







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
  for {set i 0} {$i < 50} {incr i} {
    execsql { 
      INSERT INTO t4(docid, content, lid) VALUES($i, 'The Quick Brown Fox', $i) 
    }
  }
}

ifcapable fts3_tokenizer {
  do_test 4.1.0 {
    reset_db
    set ptr [fts3_test_tokenizer]
    execsql { SELECT fts3_tokenizer('testtokenizer', $ptr) }
    build_multilingual_db_2 db
  } {}
  do_execsql_test 4.1.1 {
    SELECT docid FROM t4 WHERE t4 MATCH 'quick';
  } {0}
  do_execsql_test 4.1.2 {
    SELECT docid FROM t4 WHERE t4 MATCH 'quick' AND lid=1;
  } {}
  do_execsql_test 4.1.3 {
    SELECT docid FROM t4 WHERE t4 MATCH 'Quick' AND lid=1;
  } {1}
  for {set i 0} {$i < 50} {incr i} {
    do_execsql_test 4.1.4.$i {
      SELECT count(*) FROM t4 WHERE t4 MATCH 'fox' AND lid=$i;
    } [expr 0==($i%2)]
  }
  do_catchsql_test 4.1.5 {
    INSERT INTO t4(content, lid) VALUES('hello world', 101)
  } {1 {SQL logic error or missing database}}
}

#-------------------------------------------------------------------------
# Test cases 5.*
#
# The following test cases are designed to detect a 32-bit overflow bug
# that existed at one point.
#

Changes to test/fts4noti.test.

224
225
226
227
228
229
230
231
232
233

  SELECT count(*) FROM t2 WHERE t2 MATCH 'no';
  SELECT count(*) FROM t2 WHERE t2 MATCH 'yes';
  SELECT count(*) FROM t2 WHERE t2 MATCH 'yep';
} {0 1 1 0 1 1}

finish_test










<
<
<
224
225
226
227
228
229
230




  SELECT count(*) FROM t2 WHERE t2 MATCH 'no';
  SELECT count(*) FROM t2 WHERE t2 MATCH 'yes';
  SELECT count(*) FROM t2 WHERE t2 MATCH 'yep';
} {0 1 1 0 1 1}

finish_test



Changes to test/fts4onepass.test.

140
141
142
143
144
145
146
147
      INSERT INTO ft2(ft2) VALUES('integrity-check');
    }
  }
  eval $tcl2
}

finish_test








<
140
141
142
143
144
145
146

      INSERT INTO ft2(ft2) VALUES('integrity-check');
    }
  }
  eval $tcl2
}

finish_test

Changes to test/fuzz3.test.

169
170
171
172
173
174
175
176
  do_test fuzz3-$ii.$iNew.[incr iTest] {
    db_checksum
  } $::cksum
}

test_restore_config_pagecache
finish_test








<
169
170
171
172
173
174
175

  do_test fuzz3-$ii.$iNew.[incr iTest] {
    db_checksum
  } $::cksum
}

test_restore_config_pagecache
finish_test

Changes to test/incrcorrupt.test.

120
121
122
123
124
125
126
127
do_test 2.14 { sqlite3_errmsg db } {not an error}

do_test 2.15 { sqlite3_finalize $stmt } {SQLITE_CORRUPT}
do_test 2.16 { sqlite3_errcode db } {SQLITE_CORRUPT}
do_test 2.17 { sqlite3_errmsg db } {database disk image is malformed}

finish_test








<
120
121
122
123
124
125
126

do_test 2.14 { sqlite3_errmsg db } {not an error}

do_test 2.15 { sqlite3_finalize $stmt } {SQLITE_CORRUPT}
do_test 2.16 { sqlite3_errcode db } {SQLITE_CORRUPT}
do_test 2.17 { sqlite3_errmsg db } {database disk image is malformed}

finish_test

Changes to test/mallocK.test.

168
169
170
171
172
173
174
175
  execsql { SELECT * FROM x2 WHERE x = str('19') AND y = str('4') }
} -test {
  faultsim_test_result [list 0 {}]
}


finish_test








<
168
169
170
171
172
173
174

  execsql { SELECT * FROM x2 WHERE x = str('19') AND y = str('4') }
} -test {
  faultsim_test_result [list 0 {}]
}


finish_test

Changes to test/mallocL.test.

36
37
38
39
40
41
42
43
  } -test {
    faultsim_test_result [list 0 [lrange $::vals 0 $::j]]
  }
}


finish_test








<
36
37
38
39
40
41
42

  } -test {
    faultsim_test_result [list 0 [lrange $::vals 0 $::j]]
  }
}


finish_test

Changes to test/ovfl.test.

41
42
43
44
45
46
47
48
49
} {}

do_execsql_test 1.2 {
  SELECT sum(length(c2)) FROM t1;
} [expr 2000 * 2000]

finish_test









<
<
41
42
43
44
45
46
47


} {}

do_execsql_test 1.2 {
  SELECT sum(length(c2)) FROM t1;
} [expr 2000 * 2000]

finish_test


Changes to test/pragma2.test.

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  UPDATE t2 SET c=c-1;
  PRAGMA lock_status;
} {main unlocked temp unknown aux1 exclusive}
db close
forcedelete test.db
sqlite3 db test.db

breakpoint
do_execsql_test pragma2-5.1 {
  PRAGMA page_size=16384;
  CREATE TABLE t1(x);
  PRAGMA cache_size=2;
  PRAGMA cache_spill=YES;
  PRAGMA cache_spill;
} {2}







<







251
252
253
254
255
256
257

258
259
260
261
262
263
264
  UPDATE t2 SET c=c-1;
  PRAGMA lock_status;
} {main unlocked temp unknown aux1 exclusive}
db close
forcedelete test.db
sqlite3 db test.db


do_execsql_test pragma2-5.1 {
  PRAGMA page_size=16384;
  CREATE TABLE t1(x);
  PRAGMA cache_size=2;
  PRAGMA cache_spill=YES;
  PRAGMA cache_spill;
} {2}

Changes to test/quota.test.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
ifcapable !curdir {
  finish_test
  return
}

source $testdir/malloc_common.tcl


unset -nocomplain defaultVfs
set defaultVfs [file_control_vfsname db]
db close

do_test quota-1.1 { sqlite3_quota_initialize nosuchvfs 1 } {SQLITE_ERROR}
do_test quota-1.2 { sqlite3_quota_initialize "" 1 }        {SQLITE_OK}
do_test quota-1.3 { sqlite3_quota_initialize "" 1 }        {SQLITE_MISUSE}







>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ifcapable !curdir {
  finish_test
  return
}

source $testdir/malloc_common.tcl

forcedelete bak.db
unset -nocomplain defaultVfs
set defaultVfs [file_control_vfsname db]
db close

do_test quota-1.1 { sqlite3_quota_initialize nosuchvfs 1 } {SQLITE_ERROR}
do_test quota-1.2 { sqlite3_quota_initialize "" 1 }        {SQLITE_OK}
do_test quota-1.3 { sqlite3_quota_initialize "" 1 }        {SQLITE_MISUSE}

Changes to test/rollback2.test.

150
151
152
153
154
155
156
157
} -select {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} -result {
  2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
}

finish_test








<
150
151
152
153
154
155
156

} -select {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} -result {
  2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
}

finish_test

Changes to test/rollbackfault.test.

76
77
78
79
80
81
82
83
84
      error "statements don't look right"
    }
  }
}


finish_test









<
<
76
77
78
79
80
81
82


      error "statements don't look right"
    }
  }
}


finish_test


Changes to test/select4.test.

911
912
913
914
915
916
917
918




















919
} {123 456}
do_execsql_test select4-14.16 {
  VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 99;
} {1 2 3 4 5}
do_execsql_test select4-14.17 {
  VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 3;
} {1 2 3}





















finish_test








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

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
} {123 456}
do_execsql_test select4-14.16 {
  VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 99;
} {1 2 3 4 5}
do_execsql_test select4-14.17 {
  VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 3;
} {1 2 3}

# Ticket https://www.sqlite.org/src/info/d06a25c84454a372
# Incorrect answer due to two co-routines using the same registers and expecting
# those register values to be preserved across a Yield.
#
do_execsql_test select4-15.1 {
  DROP TABLE IF EXISTS tx;
  CREATE TABLE tx(id INTEGER PRIMARY KEY, a, b);
  INSERT INTO tx(a,b) VALUES(33,456);
  INSERT INTO tx(a,b) VALUES(33,789);

  SELECT DISTINCT t0.id, t0.a, t0.b
    FROM tx AS t0, tx AS t1
   WHERE t0.a=t1.a AND t1.a=33 AND t0.b=456
  UNION
  SELECT DISTINCT t0.id, t0.a, t0.b
    FROM tx AS t0, tx AS t1
   WHERE t0.a=t1.a AND t1.a=33 AND t0.b=789
   ORDER BY 1;
} {1 33 456 2 33 789}

finish_test

Changes to test/select7.test.

216
217
218
219
220
221
222
223
224
do_catchsql_test 8.2 {
  CREATE VIEW v0 as SELECT x, y FROM t01 UNION SELECT x FROM t02;
  EXPLAIN QUERY PLAN SELECT * FROM v0 WHERE x='0' OR y;
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}


finish_test









<
<
216
217
218
219
220
221
222


do_catchsql_test 8.2 {
  CREATE VIEW v0 as SELECT x, y FROM t01 UNION SELECT x FROM t02;
  EXPLAIN QUERY PLAN SELECT * FROM v0 WHERE x='0' OR y;
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}


finish_test


Changes to test/shared3.test.

135
136
137
138
139
140
141
142
} {1}
do_test 3.5 {
  execsql { COMMIT }
} {}

sqlite3_enable_shared_cache $::enable_shared_cache
finish_test








<
135
136
137
138
139
140
141

} {1}
do_test 3.5 {
  execsql { COMMIT }
} {}

sqlite3_enable_shared_cache $::enable_shared_cache
finish_test

Changes to test/snapshot.test.

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# block of tests above.
#
do_execsql_test 2.1.0 {
  BEGIN;
    SELECT * FROM t1;
} {1 2 3 4 5 6 7 8}

breakpoint
do_test 2.1.1 {
  set snapshot [sqlite3_snapshot_get db main]
  execsql {
    COMMIT;
    INSERT INTO t1 VALUES(9, 10);
    SELECT * FROM t1;
  }







<







51
52
53
54
55
56
57

58
59
60
61
62
63
64
# block of tests above.
#
do_execsql_test 2.1.0 {
  BEGIN;
    SELECT * FROM t1;
} {1 2 3 4 5 6 7 8}


do_test 2.1.1 {
  set snapshot [sqlite3_snapshot_get db main]
  execsql {
    COMMIT;
    INSERT INTO t1 VALUES(9, 10);
    SELECT * FROM t1;
  }

Changes to test/sort3.test.

107
108
109
110
111
112
113
114
  440000 440000000 
  440000 440000000 
  440000 440000000 
  440000 440000000
}

finish_test








<
107
108
109
110
111
112
113

  440000 440000000 
  440000 440000000 
  440000 440000000 
  440000 440000000
}

finish_test

Changes to test/sort5.test.

38
39
40
41
42
43
44
45
do_execsql_test 1.2 {
  CREATE INDEX i1 ON t1(b);
}

db close
tvfs delete
finish_test








<
38
39
40
41
42
43
44

do_execsql_test 1.2 {
  CREATE INDEX i1 ON t1(b);
}

db close
tvfs delete
finish_test

Changes to test/spellfix.test.

399
400
401
402
403
404
405
406
  do_catchsql_test 7.5.2.$tn.1 $sql $err
  do_execsql_test 7.5.2.$tn.2 { SELECT rowid, word FROM t4 } $res
  do_test 7.5.2.$tn.3 { sqlite3_get_autocommit db } $bRollback
  catchsql ROLLBACK
}

finish_test








<
399
400
401
402
403
404
405

  do_catchsql_test 7.5.2.$tn.1 $sql $err
  do_execsql_test 7.5.2.$tn.2 { SELECT rowid, word FROM t4 } $res
  do_test 7.5.2.$tn.3 { sqlite3_get_autocommit db } $bRollback
  catchsql ROLLBACK
}

finish_test

Changes to test/sqllog.test.

106
107
108
109
110
111
112
113
114
115
116

catch { db close }
sqlite3_shutdown
unset ::env(SQLITE_SQLLOG_DIR)
unset ::env(SQLITE_SQLLOG_CONDITIONAL)
sqlite3_config_sqllog
sqlite3_initialize
breakpoint
finish_test









<

<
<
106
107
108
109
110
111
112

113



catch { db close }
sqlite3_shutdown
unset ::env(SQLITE_SQLLOG_DIR)
unset ::env(SQLITE_SQLLOG_CONDITIONAL)
sqlite3_config_sqllog
sqlite3_initialize

finish_test


Changes to test/tkt-9f2eb3abac.test.

72
73
74
75
76
77
78
79
} -body {
  execsql { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? AND e=? }
} -test {
  faultsim_test_result {0 {}} 
}

finish_test








<
72
73
74
75
76
77
78

} -body {
  execsql { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? AND e=? }
} -test {
  faultsim_test_result {0 {}} 
}

finish_test

Changes to test/tkt-ba7cbfaedc.test.

57
58
59
60
61
62
63
64
65
  select * from t1 group by id order by id asc;
  select * from t1 group by id order by id desc;
} {
  1 2 3 4 5   1 2 3 4 5   5 4 3 2 1
}

finish_test









<
<
57
58
59
60
61
62
63


  select * from t1 group by id order by id asc;
  select * from t1 group by id order by id desc;
} {
  1 2 3 4 5   1 2 3 4 5   5 4 3 2 1
}

finish_test


Changes to test/triggerE.test.

104
105
106
107
108
109
110
111
112
  INSERT INTO t2 VALUES(NULL, 'z');
  INSERT INTO t3 VALUES(1, 2);
  SELECT * FROM t3;
  SELECT * FROM t2;
} {1 2 x y z z}

finish_test









<
<
104
105
106
107
108
109
110


  INSERT INTO t2 VALUES(NULL, 'z');
  INSERT INTO t3 VALUES(1, 2);
  SELECT * FROM t3;
  SELECT * FROM t2;
} {1 2 x y z z}

finish_test


Changes to test/vtab_shared.test.

272
273
274
275
276
277
278
279
    db close
  } {}
  db2 close
}

sqlite3_enable_shared_cache 0
finish_test








<
272
273
274
275
276
277
278

    db close
  } {}
  db2 close
}

sqlite3_enable_shared_cache 0
finish_test

Changes to test/wal6.test.

232
233
234
235
236
237
238
239
} {0 {1 2}}
do_test 4.4.2 { 
  catchsql { SELECT * FROM t2 } db2 
} {1 {database disk image is malformed}}


finish_test








<
232
233
234
235
236
237
238

} {0 {1 2}}
do_test 4.4.2 { 
  catchsql { SELECT * FROM t2 } db2 
} {1 {database disk image is malformed}}


finish_test

Changes to test/waloverwrite.test.

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
...
157
158
159
160
161
162
163
164

      execsql {SAVEPOINT abc}
      for {set i 0} {$i < 5} {incr i} {
        foreach x [db eval {SELECT x FROM t1}] {
          execsql { UPDATE t1 SET y = randomblob(797) WHERE x=$x }
        }
      }
      breakpoint
      execsql {ROLLBACK TO abc}

    }

    set nPg [wal_frame_count test.db-wal 1024]
    expr $nPg>55 && $nPg<75
  } {1}
................................................................................
  do_test 1.$tn.10 {
    execsql { PRAGMA integrity_check } db2
  } ok
  db2 close
}

finish_test








<







 







<
127
128
129
130
131
132
133

134
135
136
137
138
139
140
...
156
157
158
159
160
161
162


      execsql {SAVEPOINT abc}
      for {set i 0} {$i < 5} {incr i} {
        foreach x [db eval {SELECT x FROM t1}] {
          execsql { UPDATE t1 SET y = randomblob(797) WHERE x=$x }
        }
      }

      execsql {ROLLBACK TO abc}

    }

    set nPg [wal_frame_count test.db-wal 1024]
    expr $nPg>55 && $nPg<75
  } {1}
................................................................................
  do_test 1.$tn.10 {
    execsql { PRAGMA integrity_check } db2
  } ok
  db2 close
}

finish_test

Changes to test/whereI.test.

85
86
87
88
89
90
91
92

  SELECT c||'.'||b FROM t3 WHERE a='t' OR d='t'
} {
  2.1 2.2 1.2
}

finish_test








<
85
86
87
88
89
90
91


  SELECT c||'.'||b FROM t3 WHERE a='t' OR d='t'
} {
  2.1 2.2 1.2
}

finish_test

Changes to test/withM.test.

68
69
70
71
72
73
74
75
76
77
  }
} -test {
  faultsim_test_result {0 {1 1 2 4 3 9 4 16 5 25}}
  db close
}

finish_test










<
<
<
68
69
70
71
72
73
74



  }
} -test {
  faultsim_test_result {0 {1 1 2 4 3 9 4 16 5 25}}
  db close
}

finish_test



Changes to tool/mkkeywordhash.c.

273
274
275
276
277
278
279
280



281
282
283
284
285
286
287
...
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
  { "WHEN",             "TK_WHEN",         ALWAYS                 },
  { "WHERE",            "TK_WHERE",        ALWAYS                 },
};

/* Number of keywords */
static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));

/* Map all alphabetic characters into the same case */



#define charMap(X)   (0x20|(X))

/*
** Comparision function for two Keyword records
*/
static int keywordCompare1(const void *a, const void *b){
  const Keyword *pA = (Keyword*)a;
................................................................................
    if( j>=5 ){
      printf("\n");
      j = 0;
    }
  }
  printf("%s  };\n", j==0 ? "" : "\n");

  printf("  int h, i;\n");

  printf("  if( n>=2 ){\n");
  printf("    h = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n",
          bestSize);
  printf("    for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n");
  printf("      if( aLen[i]==n &&"

                     " sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){\n");







  for(i=0; i<nKeyword; i++){
    printf("        testcase( i==%d ); /* %s */\n",
           i, aKeywordTable[i].zOrigName);
  }
  printf("        *pType = aCode[i];\n");
  printf("        break;\n");
  printf("      }\n");
  printf("    }\n");
  printf("  }\n");
  printf("  return n;\n");
  printf("}\n");
  printf("int sqlite3KeywordCode(const unsigned char *z, int n){\n");
  printf("  int id = TK_ID;\n");
  printf("  keywordCode((char*)z, n, &id);\n");
  printf("  return id;\n");
  printf("}\n");
  printf("#define SQLITE_N_KEYWORD %d\n", nKeyword);

  return 0;
}







|
>
>
>







 







|
>

|

|
|
>
|
>
>
>
>
>
>
>

|


|
|
<













273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
...
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
  { "WHEN",             "TK_WHEN",         ALWAYS                 },
  { "WHERE",            "TK_WHERE",        ALWAYS                 },
};

/* Number of keywords */
static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));

/* Map all alphabetic characters into lower-case for hashing.  This is
** only valid for alphabetics.  In particular it does not work for '_'
** and so the hash cannot be on a keyword position that might be an '_'.
*/
#define charMap(X)   (0x20|(X))

/*
** Comparision function for two Keyword records
*/
static int keywordCompare1(const void *a, const void *b){
  const Keyword *pA = (Keyword*)a;
................................................................................
    if( j>=5 ){
      printf("\n");
      j = 0;
    }
  }
  printf("%s  };\n", j==0 ? "" : "\n");

  printf("  int i, j;\n");
  printf("  const char *zKW;\n");
  printf("  if( n>=2 ){\n");
  printf("    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n",
          bestSize);
  printf("    for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){\n");
  printf("      if( aLen[i]!=n ) continue;\n");
  printf("      j = 0;\n");
  printf("      zKW = &zText[aOffset[i]];\n");
  printf("#ifdef SQLITE_ASCII\n");
  printf("      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }\n");
  printf("#endif\n");
  printf("#ifdef SQLITE_EBCDIC\n");
  printf("      while( j<n && toupper(z[j])==zKW[j] ){ j++; }\n");
  printf("#endif\n");
  printf("      if( j<n ) continue;\n");
  for(i=0; i<nKeyword; i++){
    printf("      testcase( i==%d ); /* %s */\n",
           i, aKeywordTable[i].zOrigName);
  }
  printf("      *pType = aCode[i];\n");
  printf("      break;\n");

  printf("    }\n");
  printf("  }\n");
  printf("  return n;\n");
  printf("}\n");
  printf("int sqlite3KeywordCode(const unsigned char *z, int n){\n");
  printf("  int id = TK_ID;\n");
  printf("  keywordCode((char*)z, n, &id);\n");
  printf("  return id;\n");
  printf("}\n");
  printf("#define SQLITE_N_KEYWORD %d\n", nKeyword);

  return 0;
}

Added tool/srcck1.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
/*
** The program does some simple static analysis of the sqlite3.c source
** file looking for mistakes.
**
** Usage:
**
**      ./srcck1 sqlite3.c
**
** This program looks for instances of assert(), ALWAYS(), NEVER() or
** testcase() that contain side-effects and reports errors if any such
** instances are found.
**
** The aim of this utility is to prevent recurrences of errors such
** as the one fixed at:
**
**   https://www.sqlite.org/src/info/a2952231ac7abe16
**
** Note that another similar error was found by this utility when it was
** first written.  That other error was fixed by the same check-in that
** committed the first version of this utility program.
*/
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

/* Read the complete text of a file into memory.  Return a pointer to
** the result.  Panic if unable to read the file or allocate memory.
*/
static char *readFile(const char *zFilename){
  FILE *in;
  char *z;
  long n;
  size_t got;

  in = fopen(zFilename, "rb");
  if( in==0 ){
    fprintf(stderr, "unable to open '%s' for reading\n", zFilename);
    exit(1);
  }
  fseek(in, 0, SEEK_END);
  n = ftell(in);
  rewind(in);
  z = malloc( n+1 );
  if( z==0 ){
    fprintf(stderr, "cannot allocate %d bytes to store '%s'\n", 
            (int)(n+1), zFilename);
    exit(1);
  }
  got = fread(z, 1, n, in);
  fclose(in);
  if( got!=(size_t)n ){
    fprintf(stderr, "only read %d of %d bytes from '%s'\n",
           (int)got, (int)n, zFilename);
    exit(1);
  }
  z[n] = 0;
  return z;
}

/* Change the C code in the argument to see if it might have
** side effects.  The only accurate way to know this is to do a full
** parse of the C code, which this routine does not do.  This routine
** uses a simple heuristic of looking for:
**
**    *  '=' not immediately after '>', '<', '!', or '='.
**    *  '++'
**    *  '--'
**
** If the code contains the phrase "side-effects-ok" is inside a 
** comment, then always return false.  This is used to disable checking
** for assert()s with deliberate side-effects, such as used by
** SQLITE_TESTCTRL_ASSERT - a facility that allows applications to
** determine at runtime whether or not assert()s are enabled.  
** Obviously, that determination cannot be made unless the assert()
** has some side-effect.
**
** Return true if a side effect is seen.  Return false if not.
*/
static int hasSideEffect(const char *z, unsigned int n){
  unsigned int i;
  for(i=0; i<n; i++){
    if( z[i]=='/' && strncmp(&z[i], "/*side-effects-ok*/", 19)==0 ) return 0;
    if( z[i]=='=' && i>0 && z[i-1]!='=' && z[i-1]!='>'
           && z[i-1]!='<' && z[i-1]!='!' && z[i+1]!='=' ) return 1;
    if( z[i]=='+' && z[i+1]=='+' ) return 1;
    if( z[i]=='-' && z[i+1]=='-' ) return 1;
  }
  return 0;
}

/* Return the number of bytes in string z[] prior to the first unmatched ')'
** character.
*/
static unsigned int findCloseParen(const char *z){
  unsigned int nOpen = 0;
  unsigned i;
  for(i=0; z[i]; i++){
    if( z[i]=='(' ) nOpen++;
    if( z[i]==')' ){
      if( nOpen==0 ) break;
      nOpen--;
    }
  }
  return i;
}

/* Search for instances of assert(...), ALWAYS(...), NEVER(...), and/or
** testcase(...) where the argument contains side effects.
**
** Print error messages whenever a side effect is found.  Return the number
** of problems seen.
*/
static unsigned int findAllSideEffects(const char *z){
  unsigned int lineno = 1;   /* Line number */
  unsigned int i;
  unsigned int nErr = 0;
  char c, prevC = 0;
  for(i=0; (c = z[i])!=0; prevC=c, i++){
    if( c=='\n' ){ lineno++; continue; }
    if( isalpha(c) && !isalpha(prevC) ){
      if( strncmp(&z[i],"assert(",7)==0
       || strncmp(&z[i],"ALWAYS(",7)==0
       || strncmp(&z[i],"NEVER(",6)==0
       || strncmp(&z[i],"testcase(",9)==0
      ){
        unsigned int n;
        const char *z2 = &z[i+5];
        while( z2[0]!='(' ){ z2++; }
        z2++;
        n = findCloseParen(z2);
        if( hasSideEffect(z2, n) ){
          nErr++;
          fprintf(stderr, "side-effect line %u: %.*s\n", lineno,
                  (int)(&z2[n+1] - &z[i]), &z[i]);
        }
      }
    }
  }
  return nErr;
}

int main(int argc, char **argv){
  char *z;
  unsigned int nErr = 0;
  if( argc!=2 ){
    fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
    return 1;
  }
  z = readFile(argv[1]);
  nErr = findAllSideEffects(z);
  free(z);
  if( nErr ){
    fprintf(stderr, "Found %u undesirable side-effects\n", nErr);
    return 1;
  }
  return 0; 
}