Fossil SCM

Sync with trunk.

florian 2024-12-12 16:58 timeline-keyboard-navigation merge
Commit 611f20e81708ee77c0d6a7b6103cb0723aa51731e8a6ec154fd4e0d45e6f74cd
157 files changed +1 -1 +4 -1 +1 -1 +7 +5 -3 +95 -28 +722 -241 +3 -3 +1 -1 +3370 -1991 +2361 -1405 +80 -13 +22 -17 +4 -1 +7 -6 +1 -1 +23 -6 +8 -1 +12 -4 +49 -1 +4 -3 -17 +3 -1 +9 -3 +114 -14 +221 -71 +28 -9 +13 -14 +52 -10 +52 -10 +50 -48 +146 -7 +1 -1 +8 -8 +26 -1 +2 +1 -1 +99 -9 +13 -5 +63 -35 +25 -5 +3 -1 +1 -1 +15 -3 +54 -6 +2 -2 +6 +4 -6 +4 -1 +152 -17 +2 -1 +16 -4 +13 -10 +2 -1 +7 -3 +465 -6 +581 +804 -168 +6 -2 +1 +12 -2 +9 -3 +4 -5 +7 -7 +83 -64 +16 -4 +7 -5 +5 -40 +9 +2 -1 +2 -1 +1 -1 +55 -3 +4 -4 +229 +40 -1 +20 +20 -20 +6 +2 +1 +2 -1 +1 -1 +1 +2 +4 -4 +3 -3 +2 -2 +2 -2 +3 -3 +2 -2 +6 -6 +2 -2 +1 -1 +1 -1 +2 -2 +26 -4 +2 -2 +1 -1 +4 -4 +1 -1 +10 -8 +13 -5 +3 -3 +1 -1 +3 -3 +6 -6 +1 -1 +1 -1 +9 -10 +1 -1 +3 -3 +2 -2 +1 -1 +1 -1 +1 -1 +1 -1 +4 -4 +4 -4 +2 -2 +5 -5 +1 -1 +3 -3 +1 -1 +1 -1 +2 -2 +2 -2 +8 -8 +7 -7 +10 -9 +1 -1 +2 -1 +6 -2 +4 -4 +2 -2 +1 -1 +1 -1 +2 -2 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +2 -3 +2 -2 +2 -2 +6 -5 +33 -13 +1 -1 +5 -5 +2 -2 +2 -2 +2 -2 +1 -1 +5 -5 +7 -4 +1 -1
~ BUILD.txt ~ Makefile.in ~ VERSION ~ auto.def ~ autosetup/autosetup ~ autosetup/autosetup-config.guess ~ autosetup/autosetup-config.sub ~ autosetup/autosetup-find-tclsh ~ autosetup/cc.tcl ~ extsrc/shell.c ~ extsrc/sqlite3.c ~ extsrc/sqlite3.h ~ fossil.1 ~ skins/darkmode/css.txt ~ skins/default/css.txt ~ src/add.c ~ src/allrepo.c ~ src/attach.c ~ src/bisect.c ~ src/blob.c ~ src/branch.c ~ src/browse.c ~ src/builtin.c ~ src/chat.c ~ src/checkin.c ~ src/comformat.c ~ src/configure.c ~ src/db.c ~ src/default.css ~ src/default.css ~ src/delta.c ~ src/diff.c ~ src/diff.tcl ~ src/diffcmd.c ~ src/dispatch.c ~ src/doc.c ~ src/event.c ~ src/file.c ~ src/finfo.c ~ src/forum.c ~ src/fossil.diff.js ~ src/fossil.dom.js ~ src/fossil.page.chat.js ~ src/fossil.page.pikchrshowasm.js ~ src/fossil.pikchr.js ~ src/glob.c ~ src/http.c ~ src/http_ssl.c ~ src/http_transport.c ~ src/info.c ~ src/interwiki.c ~ src/login.c ~ src/main.c ~ src/main.mk ~ src/manifest.c ~ src/merge.c ~ src/merge.tcl ~ src/merge3.c ~ src/patch.c ~ src/path.c ~ src/pikchrshow.c ~ src/rebuild.c ~ src/rss.c ~ src/schema.c ~ src/search.c ~ src/setup.c ~ src/setupuser.c ~ src/sitemap.c ~ src/th_tcl.c ~ src/timeline.c ~ src/timeline.c ~ src/tkt.c ~ src/update.c ~ src/wiki.c ~ src/winfile.c ~ src/xfer.c ~ test/comment.test ~ test/glob.test ~ test/settings.test ~ test/tester.tcl ~ test/utf8-comment.txt ~ tools/makemake.tcl ~ tools/man_page_command_list.tcl ~ win/Makefile.mingw ~ win/Makefile.msc ~ www/aboutcgi.wiki ~ www/adding_code.wiki ~ www/alerts.md ~ www/antibot.wiki ~ www/backoffice.md ~ www/blame.wiki ~ www/bugtheory.wiki ~ www/build.wiki ~ www/caps/index.md ~ www/caps/ref.html ~ www/cgi.wiki ~ www/changes.wiki ~ www/chat.md ~ www/checkin_names.wiki ~ www/concepts.wiki ~ www/contribute.wiki ~ www/custom_ticket.wiki ~ www/embeddeddoc.wiki ~ www/env-opts.md ~ www/event.wiki ~ www/fileedit-page.md ~ www/fileformat.wiki ~ www/forum.wiki ~ www/fossil-is-not-relational.md ~ www/fossil-v-git.wiki ~ www/fossil_prompt.wiki ~ www/gitusers.md ~ www/glossary.md ~ www/grep.md ~ www/hashpolicy.wiki ~ www/hints.wiki ~ www/history.md ~ www/hooks.md ~ www/index.wiki ~ www/inout.wiki ~ www/interwiki.md ~ www/json-api/api-artifact.md ~ www/json-api/api-auth.md ~ www/json-api/api-checkout.md ~ www/json-api/api-finfo.md ~ www/json-api/api-query.md ~ www/json-api/api-tag.md ~ www/json-api/conventions.md ~ www/json-api/hacking.md ~ www/makefile.wiki ~ www/mdtest/test1.md ~ www/newrepo.wiki ~ www/password.wiki ~ www/patchcmd.md ~ www/pikchr.md ~ www/qandc.wiki ~ www/quickstart.wiki ~ www/rebaseharm.md ~ www/selfcheck.wiki ~ www/selfhost.wiki ~ www/server/debian/service.md ~ www/server/openbsd/fastcgi.md ~ www/server/windows/service.md ~ www/settings.wiki ~ www/shunning.wiki ~ www/stats.wiki ~ www/style.wiki ~ www/sync.wiki ~ www/tech_overview.wiki ~ www/th1.md ~ www/theory1.wiki ~ www/tickets.wiki ~ www/unvers.wiki ~ www/userlinks.wiki ~ www/webui.wiki ~ www/whyallinone.md ~ www/wikitheory.wiki
+1 -1
--- BUILD.txt
+++ BUILD.txt
@@ -42,11 +42,11 @@
4242
mkdir build
4343
cd build
4444
../configure
4545
make
4646
47
-This will now keep all generates files separate from the maintained
47
+This will now keep all generated files separate from the maintained
4848
source code.
4949
5050
--------------------------------------------------------------------------
5151
5252
Here are some notes on what is happening behind the scenes:
5353
--- BUILD.txt
+++ BUILD.txt
@@ -42,11 +42,11 @@
42 mkdir build
43 cd build
44 ../configure
45 make
46
47 This will now keep all generates files separate from the maintained
48 source code.
49
50 --------------------------------------------------------------------------
51
52 Here are some notes on what is happening behind the scenes:
53
--- BUILD.txt
+++ BUILD.txt
@@ -42,11 +42,11 @@
42 mkdir build
43 cd build
44 ../configure
45 make
46
47 This will now keep all generated files separate from the maintained
48 source code.
49
50 --------------------------------------------------------------------------
51
52 Here are some notes on what is happening behind the scenes:
53
+4 -1
--- Makefile.in
+++ Makefile.in
@@ -51,11 +51,11 @@
5151
BCCFLAGS = @CPPFLAGS@ $(CFLAGS)
5252
TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H
5353
#
5454
# Fuzzing may be enable by appending -fsanitize=fuzzer -DFOSSIL_FUZZ
5555
# to the TCCFLAGS variable.
56
-# For more thorouth (but also slower) investigation
56
+# For more thorough (but also slower) investigation
5757
# -fsanitize=fuzzer,undefined,address
5858
# might be more useful.
5959
6060
INSTALLDIR = $(DESTDIR)@prefix@/bin
6161
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
@@ -92,10 +92,13 @@
9292
MAKE_COMPILATION_DB = @MAKE_COMPILATION_DB@
9393
9494
.PHONY: all tags
9595
9696
include $(SRCDIR)/main.mk
97
+SQLITE_OPTIONS += @SQLITE_OPTIONS_EXT@
98
+SHELL_OPTIONS += @SQLITE_OPTIONS_EXT@
99
+# ^^^ must come after main.mk is included
97100
98101
distclean: clean
99102
-rm -f autoconfig.h config.log Makefile
100103
-rm -f cscope.out tags
101104
102105
--- Makefile.in
+++ Makefile.in
@@ -51,11 +51,11 @@
51 BCCFLAGS = @CPPFLAGS@ $(CFLAGS)
52 TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H
53 #
54 # Fuzzing may be enable by appending -fsanitize=fuzzer -DFOSSIL_FUZZ
55 # to the TCCFLAGS variable.
56 # For more thorouth (but also slower) investigation
57 # -fsanitize=fuzzer,undefined,address
58 # might be more useful.
59
60 INSTALLDIR = $(DESTDIR)@prefix@/bin
61 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
@@ -92,10 +92,13 @@
92 MAKE_COMPILATION_DB = @MAKE_COMPILATION_DB@
93
94 .PHONY: all tags
95
96 include $(SRCDIR)/main.mk
 
 
 
97
98 distclean: clean
99 -rm -f autoconfig.h config.log Makefile
100 -rm -f cscope.out tags
101
102
--- Makefile.in
+++ Makefile.in
@@ -51,11 +51,11 @@
51 BCCFLAGS = @CPPFLAGS@ $(CFLAGS)
52 TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H
53 #
54 # Fuzzing may be enable by appending -fsanitize=fuzzer -DFOSSIL_FUZZ
55 # to the TCCFLAGS variable.
56 # For more thorough (but also slower) investigation
57 # -fsanitize=fuzzer,undefined,address
58 # might be more useful.
59
60 INSTALLDIR = $(DESTDIR)@prefix@/bin
61 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
@@ -92,10 +92,13 @@
92 MAKE_COMPILATION_DB = @MAKE_COMPILATION_DB@
93
94 .PHONY: all tags
95
96 include $(SRCDIR)/main.mk
97 SQLITE_OPTIONS += @SQLITE_OPTIONS_EXT@
98 SHELL_OPTIONS += @SQLITE_OPTIONS_EXT@
99 # ^^^ must come after main.mk is included
100
101 distclean: clean
102 -rm -f autoconfig.h config.log Makefile
103 -rm -f cscope.out tags
104
105
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.25
1
+2.26
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.25
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.26
2
+7
--- auto.def
+++ auto.def
@@ -104,18 +104,21 @@
104104
msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
105105
define TCLSH false ;# force "make test" failure via /usr/bin/false
106106
}
107107
}
108108
109
+define CFLAGS [get-env CFLAGS "-g -O2"]
109110
define EXTRA_CFLAGS "-Wall"
110111
define EXTRA_LDFLAGS ""
111112
define USE_SYSTEM_SQLITE 0
112113
define USE_LINENOISE 0
113114
define USE_MMAN_H 0
114115
define USE_SEE 0
115116
define SQLITE3_ORIGIN 0
116117
# SQLITE3_ORIGIN 0 = src/sqlite3, 1=src/sqlite3-see.c, 2=client-provided
118
+define SQLITE_OPTIONS_EXT ""
119
+# SQLITE_OPTIONS_EXT => build-dependent CFLAGS for sqlite3.c and shell.c
117120
118121
# Maintain the C89/C90-style order of variable declarations before statements.
119122
# Check if the compiler supports the respective warning flag.
120123
if {[cctest -cflags -Wdeclaration-after-statement]} {
121124
define-append EXTRA_CFLAGS -Wdeclaration-after-statement
@@ -401,10 +404,14 @@
401404
msg-result "Linked to zlib via default library path"
402405
} else {
403406
define-append EXTRA_LDFLAGS "$lcheck"
404407
msg-result "Linked to zlib via $lcheck"
405408
}
409
+ if {![check-function-in-lib compressBound z]} {
410
+ puts "Notice: disabling zlib compression in the SQL shell"
411
+ define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
412
+ }
406413
break
407414
}
408415
}
409416
set ::zlib_lib -lz
410417
}
411418
--- auto.def
+++ auto.def
@@ -104,18 +104,21 @@
104 msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
105 define TCLSH false ;# force "make test" failure via /usr/bin/false
106 }
107 }
108
 
109 define EXTRA_CFLAGS "-Wall"
110 define EXTRA_LDFLAGS ""
111 define USE_SYSTEM_SQLITE 0
112 define USE_LINENOISE 0
113 define USE_MMAN_H 0
114 define USE_SEE 0
115 define SQLITE3_ORIGIN 0
116 # SQLITE3_ORIGIN 0 = src/sqlite3, 1=src/sqlite3-see.c, 2=client-provided
 
 
117
118 # Maintain the C89/C90-style order of variable declarations before statements.
119 # Check if the compiler supports the respective warning flag.
120 if {[cctest -cflags -Wdeclaration-after-statement]} {
121 define-append EXTRA_CFLAGS -Wdeclaration-after-statement
@@ -401,10 +404,14 @@
401 msg-result "Linked to zlib via default library path"
402 } else {
403 define-append EXTRA_LDFLAGS "$lcheck"
404 msg-result "Linked to zlib via $lcheck"
405 }
 
 
 
 
406 break
407 }
408 }
409 set ::zlib_lib -lz
410 }
411
--- auto.def
+++ auto.def
@@ -104,18 +104,21 @@
104 msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
105 define TCLSH false ;# force "make test" failure via /usr/bin/false
106 }
107 }
108
109 define CFLAGS [get-env CFLAGS "-g -O2"]
110 define EXTRA_CFLAGS "-Wall"
111 define EXTRA_LDFLAGS ""
112 define USE_SYSTEM_SQLITE 0
113 define USE_LINENOISE 0
114 define USE_MMAN_H 0
115 define USE_SEE 0
116 define SQLITE3_ORIGIN 0
117 # SQLITE3_ORIGIN 0 = src/sqlite3, 1=src/sqlite3-see.c, 2=client-provided
118 define SQLITE_OPTIONS_EXT ""
119 # SQLITE_OPTIONS_EXT => build-dependent CFLAGS for sqlite3.c and shell.c
120
121 # Maintain the C89/C90-style order of variable declarations before statements.
122 # Check if the compiler supports the respective warning flag.
123 if {[cctest -cflags -Wdeclaration-after-statement]} {
124 define-append EXTRA_CFLAGS -Wdeclaration-after-statement
@@ -401,10 +404,14 @@
404 msg-result "Linked to zlib via default library path"
405 } else {
406 define-append EXTRA_LDFLAGS "$lcheck"
407 msg-result "Linked to zlib via $lcheck"
408 }
409 if {![check-function-in-lib compressBound z]} {
410 puts "Notice: disabling zlib compression in the SQL shell"
411 define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
412 }
413 break
414 }
415 }
416 set ::zlib_lib -lz
417 }
418
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -564,11 +564,14 @@
564564
set max [max $max [string length $opt]]
565565
}
566566
set indent [string repeat " " [expr {$max+4}]]
567567
set cols [getenv COLUMNS 80]
568568
catch {
569
- lassign [exec stty size] rows cols
569
+ lassign [exec stty size] _ sttycols
570
+ if {[string is integer -strict $sttycols]} {
571
+ set cols $sttycols
572
+ }
570573
}
571574
incr cols -1
572575
# Now output
573576
foreach help $::autosetup(optionhelp) {
574577
lassign $help opt module desc
@@ -908,12 +911,11 @@
908911
# @find-executable-path name
909912
#
910913
# Searches the path for an executable with the given name.
911914
# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
912915
# in which case the parameters are ignored.
913
-# The full path to the executable if found, or "" if not found.
914
-# Returns 1 if found, or 0 if not.
916
+# Returns the full path to the executable if found, or "" if not found.
915917
#
916918
proc find-executable-path {name} {
917919
# Ignore any parameters
918920
set name [lindex $name 0]
919921
# The empty string is never a valid executable
920922
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -564,11 +564,14 @@
564 set max [max $max [string length $opt]]
565 }
566 set indent [string repeat " " [expr {$max+4}]]
567 set cols [getenv COLUMNS 80]
568 catch {
569 lassign [exec stty size] rows cols
 
 
 
570 }
571 incr cols -1
572 # Now output
573 foreach help $::autosetup(optionhelp) {
574 lassign $help opt module desc
@@ -908,12 +911,11 @@
908 # @find-executable-path name
909 #
910 # Searches the path for an executable with the given name.
911 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
912 # in which case the parameters are ignored.
913 # The full path to the executable if found, or "" if not found.
914 # Returns 1 if found, or 0 if not.
915 #
916 proc find-executable-path {name} {
917 # Ignore any parameters
918 set name [lindex $name 0]
919 # The empty string is never a valid executable
920
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -564,11 +564,14 @@
564 set max [max $max [string length $opt]]
565 }
566 set indent [string repeat " " [expr {$max+4}]]
567 set cols [getenv COLUMNS 80]
568 catch {
569 lassign [exec stty size] _ sttycols
570 if {[string is integer -strict $sttycols]} {
571 set cols $sttycols
572 }
573 }
574 incr cols -1
575 # Now output
576 foreach help $::autosetup(optionhelp) {
577 lassign $help opt module desc
@@ -908,12 +911,11 @@
911 # @find-executable-path name
912 #
913 # Searches the path for an executable with the given name.
914 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
915 # in which case the parameters are ignored.
916 # Returns the full path to the executable if found, or "" if not found.
 
917 #
918 proc find-executable-path {name} {
919 # Ignore any parameters
920 set name [lindex $name 0]
921 # The empty string is never a valid executable
922
--- autosetup/autosetup-config.guess
+++ autosetup/autosetup-config.guess
@@ -1,16 +1,16 @@
11
#! /bin/sh
22
# Attempt to guess a canonical system name.
3
-# Copyright 1992-2021 Free Software Foundation, Inc.
3
+# Copyright 1992-2024 Free Software Foundation, Inc.
44
55
# shellcheck disable=SC2006,SC2268 # see below for rationale
66
7
-timestamp='2021-06-03'
7
+timestamp='2024-07-27'
88
99
# This file is free software; you can redistribute it and/or modify it
1010
# under the terms of the GNU General Public License as published by
11
-# the Free Software Foundation; either version 3 of the License, or
11
+# the Free Software Foundation, either version 3 of the License, or
1212
# (at your option) any later version.
1313
#
1414
# This program is distributed in the hope that it will be useful, but
1515
# WITHOUT ANY WARRANTY; without even the implied warranty of
1616
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -45,11 +45,11 @@
4545
me=`echo "$0" | sed -e 's,.*/,,'`
4646
4747
usage="\
4848
Usage: $0 [OPTION]
4949
50
-Output the configuration name of the system \`$me' is run on.
50
+Output the configuration name of the system '$me' is run on.
5151
5252
Options:
5353
-h, --help print this help, then exit
5454
-t, --time-stamp print date of last modification, then exit
5555
-v, --version print version number, then exit
@@ -58,17 +58,17 @@
5858
5959
version="\
6060
GNU config.guess ($timestamp)
6161
6262
Originally written by Per Bothner.
63
-Copyright 1992-2021 Free Software Foundation, Inc.
63
+Copyright 1992-2024 Free Software Foundation, Inc.
6464
6565
This is free software; see the source for copying conditions. There is NO
6666
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
6767
6868
help="
69
-Try \`$me --help' for more information."
69
+Try '$me --help' for more information."
7070
7171
# Parse command line
7272
while test $# -gt 0 ; do
7373
case $1 in
7474
--time-stamp | --time* | -t )
@@ -100,12 +100,12 @@
100100
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
101101
# compiler to aid in system detection is discouraged as it requires
102102
# temporary files to be created and, as you can see below, it is a
103103
# headache to deal with in a portable fashion.
104104
105
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
106
-# use `HOST_CC' if defined, but it is deprecated.
105
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
106
+# use 'HOST_CC' if defined, but it is deprecated.
107107
108108
# Portable tmp directory creation inspired by the Autoconf team.
109109
110110
tmp=
111111
# shellcheck disable=SC2172
@@ -121,11 +121,11 @@
121121
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
122122
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
123123
dummy=$tmp/dummy
124124
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
125125
,,) echo "int x;" > "$dummy.c"
126
- for driver in cc gcc c89 c99 ; do
126
+ for driver in cc gcc c17 c99 c89 ; do
127127
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
128128
CC_FOR_BUILD=$driver
129129
break
130130
fi
131131
done
@@ -153,22 +153,28 @@
153153
Linux|GNU|GNU/*)
154154
LIBC=unknown
155155
156156
set_cc_for_build
157157
cat <<-EOF > "$dummy.c"
158
+ #if defined(__ANDROID__)
159
+ LIBC=android
160
+ #else
158161
#include <features.h>
159162
#if defined(__UCLIBC__)
160163
LIBC=uclibc
161164
#elif defined(__dietlibc__)
162165
LIBC=dietlibc
163166
#elif defined(__GLIBC__)
164167
LIBC=gnu
168
+ #elif defined(__LLVM_LIBC__)
169
+ LIBC=llvm
165170
#else
166171
#include <stdarg.h>
167172
/* First heuristic to detect musl libc. */
168173
#ifdef __DEFINED_va_list
169174
LIBC=musl
175
+ #endif
170176
#endif
171177
#endif
172178
EOF
173179
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
174180
eval "$cc_set_libc"
@@ -435,11 +441,11 @@
435441
# If there is a compiler, see if it is configured for 64-bit objects.
436442
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
437443
# This test works for both compilers.
438444
if test "$CC_FOR_BUILD" != no_compiler_found; then
439445
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
440
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
446
+ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
441447
grep IS_64BIT_ARCH >/dev/null
442448
then
443449
SUN_ARCH=x86_64
444450
fi
445451
fi
@@ -457,11 +463,11 @@
457463
case `/usr/bin/arch -k` in
458464
Series*|S4*)
459465
UNAME_RELEASE=`uname -v`
460466
;;
461467
esac
462
- # Japanese Language versions have a version number like `4.1.3-JL'.
468
+ # Japanese Language versions have a version number like '4.1.3-JL'.
463469
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
464470
GUESS=sparc-sun-sunos$SUN_REL
465471
;;
466472
sun3*:SunOS:*:*)
467473
GUESS=m68k-sun-sunos$UNAME_RELEASE
@@ -626,11 +632,12 @@
626632
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
627633
set_cc_for_build
628634
sed 's/^ //' << EOF > "$dummy.c"
629635
#include <sys/systemcfg.h>
630636
631
- main()
637
+ int
638
+ main ()
632639
{
633640
if (!__power_pc())
634641
exit(1);
635642
puts("powerpc-ibm-aix3.2.5");
636643
exit(0);
@@ -710,11 +717,12 @@
710717
711718
#define _HPUX_SOURCE
712719
#include <stdlib.h>
713720
#include <unistd.h>
714721
715
- int main ()
722
+ int
723
+ main ()
716724
{
717725
#if defined(_SC_KERNEL_BITS)
718726
long bits = sysconf(_SC_KERNEL_BITS);
719727
#endif
720728
long cpu = sysconf (_SC_CPU_VERSION);
@@ -902,11 +910,11 @@
902910
FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
903911
GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
904912
fi
905913
;;
906914
*:FreeBSD:*:*)
907
- UNAME_PROCESSOR=`/usr/bin/uname -p`
915
+ UNAME_PROCESSOR=`uname -p`
908916
case $UNAME_PROCESSOR in
909917
amd64)
910918
UNAME_PROCESSOR=x86_64 ;;
911919
i386)
912920
UNAME_PROCESSOR=i586 ;;
@@ -927,10 +935,13 @@
927935
GUESS=$UNAME_MACHINE-pc-msys
928936
;;
929937
i*:PW*:*)
930938
GUESS=$UNAME_MACHINE-pc-pw32
931939
;;
940
+ *:SerenityOS:*:*)
941
+ GUESS=$UNAME_MACHINE-pc-serenity
942
+ ;;
932943
*:Interix*:*)
933944
case $UNAME_MACHINE in
934945
x86)
935946
GUESS=i586-pc-interix$UNAME_RELEASE
936947
;;
@@ -961,15 +972,41 @@
961972
# other systems with GNU libc and userland
962973
GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
963974
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
964975
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
965976
;;
977
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
978
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
979
+ ;;
980
+ *:[Mm]anagarm:*:*)
981
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
982
+ ;;
966983
*:Minix:*:*)
967984
GUESS=$UNAME_MACHINE-unknown-minix
968985
;;
969986
aarch64:Linux:*:*)
970
- GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
987
+ set_cc_for_build
988
+ CPU=$UNAME_MACHINE
989
+ LIBCABI=$LIBC
990
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
991
+ ABI=64
992
+ sed 's/^ //' << EOF > "$dummy.c"
993
+ #ifdef __ARM_EABI__
994
+ #ifdef __ARM_PCS_VFP
995
+ ABI=eabihf
996
+ #else
997
+ ABI=eabi
998
+ #endif
999
+ #endif
1000
+EOF
1001
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
1002
+ eval "$cc_set_abi"
1003
+ case $ABI in
1004
+ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
1005
+ esac
1006
+ fi
1007
+ GUESS=$CPU-unknown-linux-$LIBCABI
9711008
;;
9721009
aarch64_be:Linux:*:*)
9731010
UNAME_MACHINE=aarch64_be
9741011
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
9751012
;;
@@ -1031,11 +1068,20 @@
10311068
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
10321069
;;
10331070
k1om:Linux:*:*)
10341071
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
10351072
;;
1036
- loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
1073
+ kvx:Linux:*:*)
1074
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1075
+ ;;
1076
+ kvx:cos:*:*)
1077
+ GUESS=$UNAME_MACHINE-unknown-cos
1078
+ ;;
1079
+ kvx:mbr:*:*)
1080
+ GUESS=$UNAME_MACHINE-unknown-mbr
1081
+ ;;
1082
+ loongarch32:Linux:*:* | loongarch64:Linux:*:*)
10371083
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
10381084
;;
10391085
m32r*:Linux:*:*)
10401086
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
10411087
;;
@@ -1146,20 +1192,31 @@
11461192
vax:Linux:*:*)
11471193
GUESS=$UNAME_MACHINE-dec-linux-$LIBC
11481194
;;
11491195
x86_64:Linux:*:*)
11501196
set_cc_for_build
1197
+ CPU=$UNAME_MACHINE
11511198
LIBCABI=$LIBC
11521199
if test "$CC_FOR_BUILD" != no_compiler_found; then
1153
- if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
1154
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
1155
- grep IS_X32 >/dev/null
1156
- then
1157
- LIBCABI=${LIBC}x32
1158
- fi
1159
- fi
1160
- GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
1200
+ ABI=64
1201
+ sed 's/^ //' << EOF > "$dummy.c"
1202
+ #ifdef __i386__
1203
+ ABI=x86
1204
+ #else
1205
+ #ifdef __ILP32__
1206
+ ABI=x32
1207
+ #endif
1208
+ #endif
1209
+EOF
1210
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
1211
+ eval "$cc_set_abi"
1212
+ case $ABI in
1213
+ x86) CPU=i686 ;;
1214
+ x32) LIBCABI=${LIBC}x32 ;;
1215
+ esac
1216
+ fi
1217
+ GUESS=$CPU-pc-linux-$LIBCABI
11611218
;;
11621219
xtensa*:Linux:*:*)
11631220
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
11641221
;;
11651222
i*86:DYNIX/ptx:4*:*)
@@ -1175,11 +1232,11 @@
11751232
# I just have to hope. -- rms.
11761233
# Use sysv4.2uw... so that sysv4* matches it.
11771234
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
11781235
;;
11791236
i*86:OS/2:*:*)
1180
- # If we were able to find `uname', then EMX Unix compatibility
1237
+ # If we were able to find 'uname', then EMX Unix compatibility
11811238
# is probably installed.
11821239
GUESS=$UNAME_MACHINE-pc-os2-emx
11831240
;;
11841241
i*86:XTS-300:*:STOP)
11851242
GUESS=$UNAME_MACHINE-unknown-stop
@@ -1316,11 +1373,11 @@
13161373
GUESS=$UNAME_MACHINE-sni-sysv4
13171374
else
13181375
GUESS=ns32k-sni-sysv
13191376
fi
13201377
;;
1321
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
1378
+ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
13221379
# says <[email protected]>
13231380
GUESS=i586-unisys-sysv4
13241381
;;
13251382
*:UNIX_System_V:4*:FTX*)
13261383
# From Gerald Hewes <[email protected]>.
@@ -1362,12 +1419,15 @@
13621419
GUESS=i586-pc-beos
13631420
;;
13641421
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
13651422
GUESS=i586-pc-haiku
13661423
;;
1367
- x86_64:Haiku:*:*)
1368
- GUESS=x86_64-unknown-haiku
1424
+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC
1425
+ GUESS=powerpc-apple-haiku
1426
+ ;;
1427
+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
1428
+ GUESS=$UNAME_MACHINE-unknown-haiku
13691429
;;
13701430
SX-4:SUPER-UX:*:*)
13711431
GUESS=sx4-nec-superux$UNAME_RELEASE
13721432
;;
13731433
SX-5:SUPER-UX:*:*)
@@ -1520,10 +1580,13 @@
15201580
GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
15211581
;;
15221582
i*86:rdos:*:*)
15231583
GUESS=$UNAME_MACHINE-pc-rdos
15241584
;;
1585
+ i*86:Fiwix:*:*)
1586
+ GUESS=$UNAME_MACHINE-pc-fiwix
1587
+ ;;
15251588
*:AROS:*:*)
15261589
GUESS=$UNAME_MACHINE-unknown-aros
15271590
;;
15281591
x86_64:VMkernel:*:*)
15291592
GUESS=$UNAME_MACHINE-unknown-esx
@@ -1532,10 +1595,13 @@
15321595
GUESS=x86_64-unknown-onefs
15331596
;;
15341597
*:Unleashed:*:*)
15351598
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
15361599
;;
1600
+ *:Ironclad:*:*)
1601
+ GUESS=$UNAME_MACHINE-unknown-ironclad
1602
+ ;;
15371603
esac
15381604
15391605
# Do we have a guess based on uname results?
15401606
if test "x$GUESS" != x; then
15411607
echo "$GUESS"
@@ -1555,10 +1621,11 @@
15551621
#if defined(_SIZE_T_) || defined(SIGLOST)
15561622
#include <sys/utsname.h>
15571623
#endif
15581624
#endif
15591625
#endif
1626
+int
15601627
main ()
15611628
{
15621629
#if defined (sony)
15631630
#if defined (MIPSEB)
15641631
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
15651632
--- autosetup/autosetup-config.guess
+++ autosetup/autosetup-config.guess
@@ -1,16 +1,16 @@
1 #! /bin/sh
2 # Attempt to guess a canonical system name.
3 # Copyright 1992-2021 Free Software Foundation, Inc.
4
5 # shellcheck disable=SC2006,SC2268 # see below for rationale
6
7 timestamp='2021-06-03'
8
9 # This file is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -45,11 +45,11 @@
45 me=`echo "$0" | sed -e 's,.*/,,'`
46
47 usage="\
48 Usage: $0 [OPTION]
49
50 Output the configuration name of the system \`$me' is run on.
51
52 Options:
53 -h, --help print this help, then exit
54 -t, --time-stamp print date of last modification, then exit
55 -v, --version print version number, then exit
@@ -58,17 +58,17 @@
58
59 version="\
60 GNU config.guess ($timestamp)
61
62 Originally written by Per Bothner.
63 Copyright 1992-2021 Free Software Foundation, Inc.
64
65 This is free software; see the source for copying conditions. There is NO
66 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
67
68 help="
69 Try \`$me --help' for more information."
70
71 # Parse command line
72 while test $# -gt 0 ; do
73 case $1 in
74 --time-stamp | --time* | -t )
@@ -100,12 +100,12 @@
100 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
101 # compiler to aid in system detection is discouraged as it requires
102 # temporary files to be created and, as you can see below, it is a
103 # headache to deal with in a portable fashion.
104
105 # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
106 # use `HOST_CC' if defined, but it is deprecated.
107
108 # Portable tmp directory creation inspired by the Autoconf team.
109
110 tmp=
111 # shellcheck disable=SC2172
@@ -121,11 +121,11 @@
121 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
122 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
123 dummy=$tmp/dummy
124 case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
125 ,,) echo "int x;" > "$dummy.c"
126 for driver in cc gcc c89 c99 ; do
127 if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
128 CC_FOR_BUILD=$driver
129 break
130 fi
131 done
@@ -153,22 +153,28 @@
153 Linux|GNU|GNU/*)
154 LIBC=unknown
155
156 set_cc_for_build
157 cat <<-EOF > "$dummy.c"
 
 
 
158 #include <features.h>
159 #if defined(__UCLIBC__)
160 LIBC=uclibc
161 #elif defined(__dietlibc__)
162 LIBC=dietlibc
163 #elif defined(__GLIBC__)
164 LIBC=gnu
 
 
165 #else
166 #include <stdarg.h>
167 /* First heuristic to detect musl libc. */
168 #ifdef __DEFINED_va_list
169 LIBC=musl
 
170 #endif
171 #endif
172 EOF
173 cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
174 eval "$cc_set_libc"
@@ -435,11 +441,11 @@
435 # If there is a compiler, see if it is configured for 64-bit objects.
436 # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
437 # This test works for both compilers.
438 if test "$CC_FOR_BUILD" != no_compiler_found; then
439 if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
440 (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
441 grep IS_64BIT_ARCH >/dev/null
442 then
443 SUN_ARCH=x86_64
444 fi
445 fi
@@ -457,11 +463,11 @@
457 case `/usr/bin/arch -k` in
458 Series*|S4*)
459 UNAME_RELEASE=`uname -v`
460 ;;
461 esac
462 # Japanese Language versions have a version number like `4.1.3-JL'.
463 SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
464 GUESS=sparc-sun-sunos$SUN_REL
465 ;;
466 sun3*:SunOS:*:*)
467 GUESS=m68k-sun-sunos$UNAME_RELEASE
@@ -626,11 +632,12 @@
626 if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
627 set_cc_for_build
628 sed 's/^ //' << EOF > "$dummy.c"
629 #include <sys/systemcfg.h>
630
631 main()
 
632 {
633 if (!__power_pc())
634 exit(1);
635 puts("powerpc-ibm-aix3.2.5");
636 exit(0);
@@ -710,11 +717,12 @@
710
711 #define _HPUX_SOURCE
712 #include <stdlib.h>
713 #include <unistd.h>
714
715 int main ()
 
716 {
717 #if defined(_SC_KERNEL_BITS)
718 long bits = sysconf(_SC_KERNEL_BITS);
719 #endif
720 long cpu = sysconf (_SC_CPU_VERSION);
@@ -902,11 +910,11 @@
902 FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
903 GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
904 fi
905 ;;
906 *:FreeBSD:*:*)
907 UNAME_PROCESSOR=`/usr/bin/uname -p`
908 case $UNAME_PROCESSOR in
909 amd64)
910 UNAME_PROCESSOR=x86_64 ;;
911 i386)
912 UNAME_PROCESSOR=i586 ;;
@@ -927,10 +935,13 @@
927 GUESS=$UNAME_MACHINE-pc-msys
928 ;;
929 i*:PW*:*)
930 GUESS=$UNAME_MACHINE-pc-pw32
931 ;;
 
 
 
932 *:Interix*:*)
933 case $UNAME_MACHINE in
934 x86)
935 GUESS=i586-pc-interix$UNAME_RELEASE
936 ;;
@@ -961,15 +972,41 @@
961 # other systems with GNU libc and userland
962 GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
963 GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
964 GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
965 ;;
 
 
 
 
 
 
966 *:Minix:*:*)
967 GUESS=$UNAME_MACHINE-unknown-minix
968 ;;
969 aarch64:Linux:*:*)
970 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
971 ;;
972 aarch64_be:Linux:*:*)
973 UNAME_MACHINE=aarch64_be
974 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
975 ;;
@@ -1031,11 +1068,20 @@
1031 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1032 ;;
1033 k1om:Linux:*:*)
1034 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1035 ;;
1036 loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
 
 
 
 
 
 
 
 
 
1037 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1038 ;;
1039 m32r*:Linux:*:*)
1040 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1041 ;;
@@ -1146,20 +1192,31 @@
1146 vax:Linux:*:*)
1147 GUESS=$UNAME_MACHINE-dec-linux-$LIBC
1148 ;;
1149 x86_64:Linux:*:*)
1150 set_cc_for_build
 
1151 LIBCABI=$LIBC
1152 if test "$CC_FOR_BUILD" != no_compiler_found; then
1153 if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
1154 (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
1155 grep IS_X32 >/dev/null
1156 then
1157 LIBCABI=${LIBC}x32
1158 fi
1159 fi
1160 GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
 
 
 
 
 
 
 
 
 
 
1161 ;;
1162 xtensa*:Linux:*:*)
1163 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1164 ;;
1165 i*86:DYNIX/ptx:4*:*)
@@ -1175,11 +1232,11 @@
1175 # I just have to hope. -- rms.
1176 # Use sysv4.2uw... so that sysv4* matches it.
1177 GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
1178 ;;
1179 i*86:OS/2:*:*)
1180 # If we were able to find `uname', then EMX Unix compatibility
1181 # is probably installed.
1182 GUESS=$UNAME_MACHINE-pc-os2-emx
1183 ;;
1184 i*86:XTS-300:*:STOP)
1185 GUESS=$UNAME_MACHINE-unknown-stop
@@ -1316,11 +1373,11 @@
1316 GUESS=$UNAME_MACHINE-sni-sysv4
1317 else
1318 GUESS=ns32k-sni-sysv
1319 fi
1320 ;;
1321 PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
1322 # says <[email protected]>
1323 GUESS=i586-unisys-sysv4
1324 ;;
1325 *:UNIX_System_V:4*:FTX*)
1326 # From Gerald Hewes <[email protected]>.
@@ -1362,12 +1419,15 @@
1362 GUESS=i586-pc-beos
1363 ;;
1364 BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
1365 GUESS=i586-pc-haiku
1366 ;;
1367 x86_64:Haiku:*:*)
1368 GUESS=x86_64-unknown-haiku
 
 
 
1369 ;;
1370 SX-4:SUPER-UX:*:*)
1371 GUESS=sx4-nec-superux$UNAME_RELEASE
1372 ;;
1373 SX-5:SUPER-UX:*:*)
@@ -1520,10 +1580,13 @@
1520 GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
1521 ;;
1522 i*86:rdos:*:*)
1523 GUESS=$UNAME_MACHINE-pc-rdos
1524 ;;
 
 
 
1525 *:AROS:*:*)
1526 GUESS=$UNAME_MACHINE-unknown-aros
1527 ;;
1528 x86_64:VMkernel:*:*)
1529 GUESS=$UNAME_MACHINE-unknown-esx
@@ -1532,10 +1595,13 @@
1532 GUESS=x86_64-unknown-onefs
1533 ;;
1534 *:Unleashed:*:*)
1535 GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
1536 ;;
 
 
 
1537 esac
1538
1539 # Do we have a guess based on uname results?
1540 if test "x$GUESS" != x; then
1541 echo "$GUESS"
@@ -1555,10 +1621,11 @@
1555 #if defined(_SIZE_T_) || defined(SIGLOST)
1556 #include <sys/utsname.h>
1557 #endif
1558 #endif
1559 #endif
 
1560 main ()
1561 {
1562 #if defined (sony)
1563 #if defined (MIPSEB)
1564 /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
1565
--- autosetup/autosetup-config.guess
+++ autosetup/autosetup-config.guess
@@ -1,16 +1,16 @@
1 #! /bin/sh
2 # Attempt to guess a canonical system name.
3 # Copyright 1992-2024 Free Software Foundation, Inc.
4
5 # shellcheck disable=SC2006,SC2268 # see below for rationale
6
7 timestamp='2024-07-27'
8
9 # This file is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -45,11 +45,11 @@
45 me=`echo "$0" | sed -e 's,.*/,,'`
46
47 usage="\
48 Usage: $0 [OPTION]
49
50 Output the configuration name of the system '$me' is run on.
51
52 Options:
53 -h, --help print this help, then exit
54 -t, --time-stamp print date of last modification, then exit
55 -v, --version print version number, then exit
@@ -58,17 +58,17 @@
58
59 version="\
60 GNU config.guess ($timestamp)
61
62 Originally written by Per Bothner.
63 Copyright 1992-2024 Free Software Foundation, Inc.
64
65 This is free software; see the source for copying conditions. There is NO
66 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
67
68 help="
69 Try '$me --help' for more information."
70
71 # Parse command line
72 while test $# -gt 0 ; do
73 case $1 in
74 --time-stamp | --time* | -t )
@@ -100,12 +100,12 @@
100 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
101 # compiler to aid in system detection is discouraged as it requires
102 # temporary files to be created and, as you can see below, it is a
103 # headache to deal with in a portable fashion.
104
105 # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
106 # use 'HOST_CC' if defined, but it is deprecated.
107
108 # Portable tmp directory creation inspired by the Autoconf team.
109
110 tmp=
111 # shellcheck disable=SC2172
@@ -121,11 +121,11 @@
121 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
122 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
123 dummy=$tmp/dummy
124 case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
125 ,,) echo "int x;" > "$dummy.c"
126 for driver in cc gcc c17 c99 c89 ; do
127 if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
128 CC_FOR_BUILD=$driver
129 break
130 fi
131 done
@@ -153,22 +153,28 @@
153 Linux|GNU|GNU/*)
154 LIBC=unknown
155
156 set_cc_for_build
157 cat <<-EOF > "$dummy.c"
158 #if defined(__ANDROID__)
159 LIBC=android
160 #else
161 #include <features.h>
162 #if defined(__UCLIBC__)
163 LIBC=uclibc
164 #elif defined(__dietlibc__)
165 LIBC=dietlibc
166 #elif defined(__GLIBC__)
167 LIBC=gnu
168 #elif defined(__LLVM_LIBC__)
169 LIBC=llvm
170 #else
171 #include <stdarg.h>
172 /* First heuristic to detect musl libc. */
173 #ifdef __DEFINED_va_list
174 LIBC=musl
175 #endif
176 #endif
177 #endif
178 EOF
179 cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
180 eval "$cc_set_libc"
@@ -435,11 +441,11 @@
441 # If there is a compiler, see if it is configured for 64-bit objects.
442 # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
443 # This test works for both compilers.
444 if test "$CC_FOR_BUILD" != no_compiler_found; then
445 if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
446 (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
447 grep IS_64BIT_ARCH >/dev/null
448 then
449 SUN_ARCH=x86_64
450 fi
451 fi
@@ -457,11 +463,11 @@
463 case `/usr/bin/arch -k` in
464 Series*|S4*)
465 UNAME_RELEASE=`uname -v`
466 ;;
467 esac
468 # Japanese Language versions have a version number like '4.1.3-JL'.
469 SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
470 GUESS=sparc-sun-sunos$SUN_REL
471 ;;
472 sun3*:SunOS:*:*)
473 GUESS=m68k-sun-sunos$UNAME_RELEASE
@@ -626,11 +632,12 @@
632 if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
633 set_cc_for_build
634 sed 's/^ //' << EOF > "$dummy.c"
635 #include <sys/systemcfg.h>
636
637 int
638 main ()
639 {
640 if (!__power_pc())
641 exit(1);
642 puts("powerpc-ibm-aix3.2.5");
643 exit(0);
@@ -710,11 +717,12 @@
717
718 #define _HPUX_SOURCE
719 #include <stdlib.h>
720 #include <unistd.h>
721
722 int
723 main ()
724 {
725 #if defined(_SC_KERNEL_BITS)
726 long bits = sysconf(_SC_KERNEL_BITS);
727 #endif
728 long cpu = sysconf (_SC_CPU_VERSION);
@@ -902,11 +910,11 @@
910 FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
911 GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
912 fi
913 ;;
914 *:FreeBSD:*:*)
915 UNAME_PROCESSOR=`uname -p`
916 case $UNAME_PROCESSOR in
917 amd64)
918 UNAME_PROCESSOR=x86_64 ;;
919 i386)
920 UNAME_PROCESSOR=i586 ;;
@@ -927,10 +935,13 @@
935 GUESS=$UNAME_MACHINE-pc-msys
936 ;;
937 i*:PW*:*)
938 GUESS=$UNAME_MACHINE-pc-pw32
939 ;;
940 *:SerenityOS:*:*)
941 GUESS=$UNAME_MACHINE-pc-serenity
942 ;;
943 *:Interix*:*)
944 case $UNAME_MACHINE in
945 x86)
946 GUESS=i586-pc-interix$UNAME_RELEASE
947 ;;
@@ -961,15 +972,41 @@
972 # other systems with GNU libc and userland
973 GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
974 GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
975 GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
976 ;;
977 x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
978 GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
979 ;;
980 *:[Mm]anagarm:*:*)
981 GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
982 ;;
983 *:Minix:*:*)
984 GUESS=$UNAME_MACHINE-unknown-minix
985 ;;
986 aarch64:Linux:*:*)
987 set_cc_for_build
988 CPU=$UNAME_MACHINE
989 LIBCABI=$LIBC
990 if test "$CC_FOR_BUILD" != no_compiler_found; then
991 ABI=64
992 sed 's/^ //' << EOF > "$dummy.c"
993 #ifdef __ARM_EABI__
994 #ifdef __ARM_PCS_VFP
995 ABI=eabihf
996 #else
997 ABI=eabi
998 #endif
999 #endif
1000 EOF
1001 cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
1002 eval "$cc_set_abi"
1003 case $ABI in
1004 eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
1005 esac
1006 fi
1007 GUESS=$CPU-unknown-linux-$LIBCABI
1008 ;;
1009 aarch64_be:Linux:*:*)
1010 UNAME_MACHINE=aarch64_be
1011 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1012 ;;
@@ -1031,11 +1068,20 @@
1068 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1069 ;;
1070 k1om:Linux:*:*)
1071 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1072 ;;
1073 kvx:Linux:*:*)
1074 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1075 ;;
1076 kvx:cos:*:*)
1077 GUESS=$UNAME_MACHINE-unknown-cos
1078 ;;
1079 kvx:mbr:*:*)
1080 GUESS=$UNAME_MACHINE-unknown-mbr
1081 ;;
1082 loongarch32:Linux:*:* | loongarch64:Linux:*:*)
1083 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1084 ;;
1085 m32r*:Linux:*:*)
1086 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1087 ;;
@@ -1146,20 +1192,31 @@
1192 vax:Linux:*:*)
1193 GUESS=$UNAME_MACHINE-dec-linux-$LIBC
1194 ;;
1195 x86_64:Linux:*:*)
1196 set_cc_for_build
1197 CPU=$UNAME_MACHINE
1198 LIBCABI=$LIBC
1199 if test "$CC_FOR_BUILD" != no_compiler_found; then
1200 ABI=64
1201 sed 's/^ //' << EOF > "$dummy.c"
1202 #ifdef __i386__
1203 ABI=x86
1204 #else
1205 #ifdef __ILP32__
1206 ABI=x32
1207 #endif
1208 #endif
1209 EOF
1210 cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
1211 eval "$cc_set_abi"
1212 case $ABI in
1213 x86) CPU=i686 ;;
1214 x32) LIBCABI=${LIBC}x32 ;;
1215 esac
1216 fi
1217 GUESS=$CPU-pc-linux-$LIBCABI
1218 ;;
1219 xtensa*:Linux:*:*)
1220 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
1221 ;;
1222 i*86:DYNIX/ptx:4*:*)
@@ -1175,11 +1232,11 @@
1232 # I just have to hope. -- rms.
1233 # Use sysv4.2uw... so that sysv4* matches it.
1234 GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
1235 ;;
1236 i*86:OS/2:*:*)
1237 # If we were able to find 'uname', then EMX Unix compatibility
1238 # is probably installed.
1239 GUESS=$UNAME_MACHINE-pc-os2-emx
1240 ;;
1241 i*86:XTS-300:*:STOP)
1242 GUESS=$UNAME_MACHINE-unknown-stop
@@ -1316,11 +1373,11 @@
1373 GUESS=$UNAME_MACHINE-sni-sysv4
1374 else
1375 GUESS=ns32k-sni-sysv
1376 fi
1377 ;;
1378 PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
1379 # says <[email protected]>
1380 GUESS=i586-unisys-sysv4
1381 ;;
1382 *:UNIX_System_V:4*:FTX*)
1383 # From Gerald Hewes <[email protected]>.
@@ -1362,12 +1419,15 @@
1419 GUESS=i586-pc-beos
1420 ;;
1421 BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
1422 GUESS=i586-pc-haiku
1423 ;;
1424 ppc:Haiku:*:*) # Haiku running on Apple PowerPC
1425 GUESS=powerpc-apple-haiku
1426 ;;
1427 *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
1428 GUESS=$UNAME_MACHINE-unknown-haiku
1429 ;;
1430 SX-4:SUPER-UX:*:*)
1431 GUESS=sx4-nec-superux$UNAME_RELEASE
1432 ;;
1433 SX-5:SUPER-UX:*:*)
@@ -1520,10 +1580,13 @@
1580 GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
1581 ;;
1582 i*86:rdos:*:*)
1583 GUESS=$UNAME_MACHINE-pc-rdos
1584 ;;
1585 i*86:Fiwix:*:*)
1586 GUESS=$UNAME_MACHINE-pc-fiwix
1587 ;;
1588 *:AROS:*:*)
1589 GUESS=$UNAME_MACHINE-unknown-aros
1590 ;;
1591 x86_64:VMkernel:*:*)
1592 GUESS=$UNAME_MACHINE-unknown-esx
@@ -1532,10 +1595,13 @@
1595 GUESS=x86_64-unknown-onefs
1596 ;;
1597 *:Unleashed:*:*)
1598 GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
1599 ;;
1600 *:Ironclad:*:*)
1601 GUESS=$UNAME_MACHINE-unknown-ironclad
1602 ;;
1603 esac
1604
1605 # Do we have a guess based on uname results?
1606 if test "x$GUESS" != x; then
1607 echo "$GUESS"
@@ -1555,10 +1621,11 @@
1621 #if defined(_SIZE_T_) || defined(SIGLOST)
1622 #include <sys/utsname.h>
1623 #endif
1624 #endif
1625 #endif
1626 int
1627 main ()
1628 {
1629 #if defined (sony)
1630 #if defined (MIPSEB)
1631 /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
1632
--- autosetup/autosetup-config.sub
+++ autosetup/autosetup-config.sub
@@ -1,16 +1,16 @@
11
#! /bin/sh
22
# Configuration validation subroutine script.
3
-# Copyright 1992-2021 Free Software Foundation, Inc.
3
+# Copyright 1992-2024 Free Software Foundation, Inc.
44
5
-# shellcheck disable=SC2006,SC2268 # see below for rationale
5
+# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale
66
7
-timestamp='2021-07-03'
7
+timestamp='2024-05-27'
88
99
# This file is free software; you can redistribute it and/or modify it
1010
# under the terms of the GNU General Public License as published by
11
-# the Free Software Foundation; either version 3 of the License, or
11
+# the Free Software Foundation, either version 3 of the License, or
1212
# (at your option) any later version.
1313
#
1414
# This program is distributed in the hope that it will be useful, but
1515
# WITHOUT ANY WARRANTY; without even the implied warranty of
1616
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -74,17 +74,17 @@
7474
Report bugs and patches to <[email protected]>."
7575
7676
version="\
7777
GNU config.sub ($timestamp)
7878
79
-Copyright 1992-2021 Free Software Foundation, Inc.
79
+Copyright 1992-2024 Free Software Foundation, Inc.
8080
8181
This is free software; see the source for copying conditions. There is NO
8282
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
8383
8484
help="
85
-Try \`$me --help' for more information."
85
+Try '$me --help' for more information."
8686
8787
# Parse command line
8888
while test $# -gt 0 ; do
8989
case $1 in
9090
--time-stamp | --time* | -t )
@@ -118,19 +118,20 @@
118118
*) echo "$me: too many arguments$help" >&2
119119
exit 1;;
120120
esac
121121
122122
# Split fields of configuration type
123
-# shellcheck disable=SC2162
123
+saved_IFS=$IFS
124124
IFS="-" read field1 field2 field3 field4 <<EOF
125125
$1
126126
EOF
127
+IFS=$saved_IFS
127128
128129
# Separate into logical components for further validation
129130
case $1 in
130131
*-*-*-*-*)
131
- echo Invalid configuration \`"$1"\': more than four components >&2
132
+ echo "Invalid configuration '$1': more than four components" >&2
132133
exit 1
133134
;;
134135
*-*-*-*)
135136
basic_machine=$field1-$field2
136137
basic_os=$field3-$field4
@@ -138,14 +139,25 @@
138139
*-*-*)
139140
# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
140141
# parts
141142
maybe_os=$field2-$field3
142143
case $maybe_os in
143
- nto-qnx* | linux-* | uclinux-uclibc* \
144
- | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
145
- | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
146
- | storm-chaos* | os2-emx* | rtmk-nova*)
144
+ cloudabi*-eabi* \
145
+ | kfreebsd*-gnu* \
146
+ | knetbsd*-gnu* \
147
+ | kopensolaris*-gnu* \
148
+ | linux-* \
149
+ | managarm-* \
150
+ | netbsd*-eabi* \
151
+ | netbsd*-gnu* \
152
+ | nto-qnx* \
153
+ | os2-emx* \
154
+ | rtmk-nova* \
155
+ | storm-chaos* \
156
+ | uclinux-gnu* \
157
+ | uclinux-uclibc* \
158
+ | windows-* )
147159
basic_machine=$field1
148160
basic_os=$maybe_os
149161
;;
150162
android-linux)
151163
basic_machine=$field1-unknown
@@ -156,37 +168,105 @@
156168
basic_os=$field3
157169
;;
158170
esac
159171
;;
160172
*-*)
161
- # A lone config we happen to match not fitting any pattern
162173
case $field1-$field2 in
174
+ # Shorthands that happen to contain a single dash
175
+ convex-c[12] | convex-c3[248])
176
+ basic_machine=$field2-convex
177
+ basic_os=
178
+ ;;
163179
decstation-3100)
164180
basic_machine=mips-dec
165181
basic_os=
166182
;;
167183
*-*)
168184
# Second component is usually, but not always the OS
169185
case $field2 in
170
- # Prevent following clause from handling this valid os
186
+ # Do not treat sunos as a manufacturer
171187
sun*os*)
172188
basic_machine=$field1
173189
basic_os=$field2
174190
;;
175191
# Manufacturers
176
- dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
177
- | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
178
- | unicom* | ibm* | next | hp | isi* | apollo | altos* \
179
- | convergent* | ncr* | news | 32* | 3600* | 3100* \
180
- | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
181
- | ultra | tti* | harris | dolphin | highlevel | gould \
182
- | cbm | ns | masscomp | apple | axis | knuth | cray \
183
- | microblaze* | sim | cisco \
184
- | oki | wec | wrs | winbond)
192
+ 3100* \
193
+ | 32* \
194
+ | 3300* \
195
+ | 3600* \
196
+ | 7300* \
197
+ | acorn \
198
+ | altos* \
199
+ | apollo \
200
+ | apple \
201
+ | atari \
202
+ | att* \
203
+ | axis \
204
+ | be \
205
+ | bull \
206
+ | cbm \
207
+ | ccur \
208
+ | cisco \
209
+ | commodore \
210
+ | convergent* \
211
+ | convex* \
212
+ | cray \
213
+ | crds \
214
+ | dec* \
215
+ | delta* \
216
+ | dg \
217
+ | digital \
218
+ | dolphin \
219
+ | encore* \
220
+ | gould \
221
+ | harris \
222
+ | highlevel \
223
+ | hitachi* \
224
+ | hp \
225
+ | ibm* \
226
+ | intergraph \
227
+ | isi* \
228
+ | knuth \
229
+ | masscomp \
230
+ | microblaze* \
231
+ | mips* \
232
+ | motorola* \
233
+ | ncr* \
234
+ | news \
235
+ | next \
236
+ | ns \
237
+ | oki \
238
+ | omron* \
239
+ | pc533* \
240
+ | rebel \
241
+ | rom68k \
242
+ | rombug \
243
+ | semi \
244
+ | sequent* \
245
+ | siemens \
246
+ | sgi* \
247
+ | siemens \
248
+ | sim \
249
+ | sni \
250
+ | sony* \
251
+ | stratus \
252
+ | sun \
253
+ | sun[234]* \
254
+ | tektronix \
255
+ | tti* \
256
+ | ultra \
257
+ | unicom* \
258
+ | wec \
259
+ | winbond \
260
+ | wrs)
185261
basic_machine=$field1-$field2
186262
basic_os=
187263
;;
264
+ zephyr*)
265
+ basic_machine=$field1-unknown
266
+ basic_os=$field2
267
+ ;;
188268
*)
189269
basic_machine=$field1
190270
basic_os=$field2
191271
;;
192272
esac
@@ -263,30 +343,10 @@
263343
;;
264344
cegcc)
265345
basic_machine=arm-unknown
266346
basic_os=cegcc
267347
;;
268
- convex-c1)
269
- basic_machine=c1-convex
270
- basic_os=bsd
271
- ;;
272
- convex-c2)
273
- basic_machine=c2-convex
274
- basic_os=bsd
275
- ;;
276
- convex-c32)
277
- basic_machine=c32-convex
278
- basic_os=bsd
279
- ;;
280
- convex-c34)
281
- basic_machine=c34-convex
282
- basic_os=bsd
283
- ;;
284
- convex-c38)
285
- basic_machine=c38-convex
286
- basic_os=bsd
287
- ;;
288348
cray)
289349
basic_machine=j90-cray
290350
basic_os=unicos
291351
;;
292352
crds | unos)
@@ -705,13 +765,21 @@
705765
decsystem20* | dec20*)
706766
cpu=pdp10
707767
vendor=dec
708768
basic_os=tops20
709769
;;
710
- delta | 3300 | motorola-3300 | motorola-delta \
711
- | 3300-motorola | delta-motorola)
770
+ delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300)
712771
cpu=m68k
713772
vendor=motorola
714773
;;
715
- dpx2*)
774
+ # This used to be dpx2*, but that gets the RS6000-based
775
+ # DPX/20 and the x86-based DPX/2-100 wrong. See
776
+ # https://oldskool.silicium.org/stations/bull_dpx20.htm
777
+ # https://www.feb-patrimoine.com/english/bull_dpx2.htm
778
+ # https://www.feb-patrimoine.com/english/unix_and_bull.htm
779
+ dpx2 | dpx2[23]00 | dpx2[23]xx)
716780
cpu=m68k
717781
vendor=bull
782
+ ;;
783
+ dpx2100 | dpx21xx)
784
+ cpu=i386
785
+ vendor=bull
@@ -718,6 +786,9 @@
718
- basic_os=sysv3
786
+ ;;
787
+ dpx20)
788
+ cpu=rs6000
789
+ vendor=bull
719790
;;
720791
encore | umax | mmax)
721792
cpu=ns32k
722793
vendor=encore
723794
;;
@@ -828,22 +899,10 @@
828899
basic_os=newsos
829900
;;
830901
next | m*-next)
831902
cpu=m68k
832903
vendor=next
833
- case $basic_os in
834
- openstep*)
835
- ;;
836
- nextstep*)
837
- ;;
838
- ns2*)
839
- basic_os=nextstep2
840
- ;;
841
- *)
842
- basic_os=nextstep3
843
- ;;
844
- esac
845904
;;
846905
np1)
847906
cpu=np1
848907
vendor=gould
849908
;;
@@ -928,16 +987,17 @@
928987
cpu=sparc
929988
vendor=`echo "$basic_machine" | sed 's/-.*//'`
930989
;;
931990
932991
*-*)
933
- # shellcheck disable=SC2162
992
+ saved_IFS=$IFS
934993
IFS="-" read cpu vendor <<EOF
935994
$basic_machine
936995
EOF
996
+ IFS=$saved_IFS
937997
;;
938
- # We use `pc' rather than `unknown'
998
+ # We use 'pc' rather than 'unknown'
939999
# because (1) that's what they normally are, and
9401000
# (2) the word "unknown" tends to confuse beginning users.
9411001
i*86 | x86_64)
9421002
cpu=$basic_machine
9431003
vendor=pc
@@ -961,19 +1021,23 @@
9611021
9621022
unset -v basic_machine
9631023
9641024
# Decode basic machines in the full and proper CPU-Company form.
9651025
case $cpu-$vendor in
966
- # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
967
- # some cases the only manufacturer, in others, it is the most popular.
1026
+ # Here we handle the default manufacturer of certain CPU types in canonical form.
1027
+ # It is in some cases the only manufacturer, in others, it is the most popular.
1028
+ c[12]-convex | c[12]-unknown | c3[248]-convex | c3[248]-unknown)
1029
+ vendor=convex
1030
+ basic_os=${basic_os:-bsd}
1031
+ ;;
9681032
craynv-unknown)
9691033
vendor=cray
9701034
basic_os=${basic_os:-unicosmp}
9711035
;;
9721036
c90-unknown | c90-cray)
9731037
vendor=cray
974
- basic_os=${Basic_os:-unicos}
1038
+ basic_os=${basic_os:-unicos}
9751039
;;
9761040
fx80-unknown)
9771041
vendor=alliant
9781042
;;
9791043
romp-unknown)
@@ -1010,23 +1074,46 @@
10101074
cpu=xps100
10111075
vendor=honeywell
10121076
;;
10131077
10141078
# Here we normalize CPU types with a missing or matching vendor
1015
- dpx20-unknown | dpx20-bull)
1016
- cpu=rs6000
1017
- vendor=bull
1079
+ armh-unknown | armh-alt)
1080
+ cpu=armv7l
1081
+ vendor=alt
1082
+ basic_os=${basic_os:-linux-gnueabihf}
1083
+ ;;
1084
+
1085
+ # Normalized CPU+vendor pairs that imply an OS, if not otherwise specified
1086
+ m68k-isi)
1087
+ basic_os=${basic_os:-sysv}
1088
+ ;;
1089
+ m68k-sony)
1090
+ basic_os=${basic_os:-newsos}
1091
+ ;;
1092
+ m68k-tektronix)
1093
+ basic_os=${basic_os:-bsd}
1094
+ ;;
1095
+ m88k-harris)
1096
+ basic_os=${basic_os:-sysv3}
1097
+ ;;
1098
+ i386-bull | m68k-bull)
1099
+ basic_os=${basic_os:-sysv3}
1100
+ ;;
1101
+ rs6000-bull)
10181102
basic_os=${basic_os:-bosx}
10191103
;;
1104
+ mips-sni)
1105
+ basic_os=${basic_os:-sysv4}
1106
+ ;;
10201107
10211108
# Here we normalize CPU types irrespective of the vendor
10221109
amd64-*)
10231110
cpu=x86_64
10241111
;;
10251112
blackfin-*)
10261113
cpu=bfin
1027
- basic_os=linux
1114
+ basic_os=${basic_os:-linux}
10281115
;;
10291116
c54x-*)
10301117
cpu=tic54x
10311118
;;
10321119
c55x-*)
@@ -1045,37 +1132,34 @@
10451132
ms1-*)
10461133
cpu=mt
10471134
;;
10481135
m68knommu-*)
10491136
cpu=m68k
1050
- basic_os=linux
1137
+ basic_os=${basic_os:-linux}
10511138
;;
10521139
m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
10531140
cpu=s12z
10541141
;;
10551142
openrisc-*)
10561143
cpu=or32
10571144
;;
10581145
parisc-*)
10591146
cpu=hppa
1060
- basic_os=linux
1147
+ basic_os=${basic_os:-linux}
10611148
;;
10621149
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
10631150
cpu=i586
10641151
;;
1065
- pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
1152
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
10661153
cpu=i686
10671154
;;
10681155
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
10691156
cpu=i686
10701157
;;
10711158
pentium4-*)
10721159
cpu=i786
10731160
;;
1074
- pc98-*)
1075
- cpu=i386
1076
- ;;
10771161
ppc-* | ppcbe-*)
10781162
cpu=powerpc
10791163
;;
10801164
ppcle-* | powerpclittle-*)
10811165
cpu=powerpcle
@@ -1105,17 +1189,14 @@
11051189
cpu=mipstx39
11061190
;;
11071191
tx39el-*)
11081192
cpu=mipstx39el
11091193
;;
1110
- x64-*)
1111
- cpu=x86_64
1112
- ;;
11131194
xscale-* | xscalee[bl]-*)
11141195
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
11151196
;;
1116
- arm64-*)
1197
+ arm64-* | aarch64le-*)
11171198
cpu=aarch64
11181199
;;
11191200
11201201
# Recognize the canonical CPU Types that limit and/or modify the
11211202
# company names they are paired with.
@@ -1163,118 +1244,235 @@
11631244
11641245
*)
11651246
# Recognize the canonical CPU types that are allowed with any
11661247
# company name.
11671248
case $cpu in
1168
- 1750a | 580 \
1249
+ 1750a \
1250
+ | 580 \
1251
+ | [cjt]90 \
11691252
| a29k \
1170
- | aarch64 | aarch64_be \
1253
+ | aarch64 \
1254
+ | aarch64_be \
1255
+ | aarch64c \
11711256
| abacus \
1172
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
1173
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
1174
- | alphapca5[67] | alpha64pca5[67] \
1257
+ | alpha \
1258
+ | alpha64 \
1259
+ | alpha64ev56 \
1260
+ | alpha64ev6[78] \
1261
+ | alpha64ev[4-8] \
1262
+ | alpha64pca5[67] \
1263
+ | alphaev56 \
1264
+ | alphaev6[78] \
1265
+ | alphaev[4-8] \
1266
+ | alphapca5[67] \
11751267
| am33_2.0 \
11761268
| amdgcn \
1177
- | arc | arceb | arc32 | arc64 \
1178
- | arm | arm[lb]e | arme[lb] | armv* \
1179
- | avr | avr32 \
1269
+ | arc \
1270
+ | arc32 \
1271
+ | arc64 \
1272
+ | arceb \
1273
+ | arm \
1274
+ | arm64e \
1275
+ | arm64ec \
1276
+ | arm[lb]e \
1277
+ | arme[lb] \
1278
+ | armv* \
11801279
| asmjs \
1280
+ | avr \
1281
+ | avr32 \
11811282
| ba \
1182
- | be32 | be64 \
1183
- | bfin | bpf | bs2000 \
1184
- | c[123]* | c30 | [cjt]90 | c4x \
1185
- | c8051 | clipper | craynv | csky | cydra \
1186
- | d10v | d30v | dlx | dsp16xx \
1187
- | e2k | elxsi | epiphany \
1188
- | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
1189
- | h8300 | h8500 \
1190
- | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
1283
+ | be32 \
1284
+ | be64 \
1285
+ | bfin \
1286
+ | bpf \
1287
+ | bs2000 \
1288
+ | c30 \
1289
+ | c4x \
1290
+ | c8051 \
1291
+ | c[123]* \
1292
+ | clipper \
1293
+ | craynv \
1294
+ | csky \
1295
+ | cydra \
1296
+ | d10v \
1297
+ | d30v \
1298
+ | dlx \
1299
+ | dsp16xx \
1300
+ | e2k \
1301
+ | elxsi \
1302
+ | epiphany \
1303
+ | f30[01] \
1304
+ | f700 \
1305
+ | fido \
1306
+ | fr30 \
1307
+ | frv \
1308
+ | ft32 \
1309
+ | fx80 \
1310
+ | h8300 \
1311
+ | h8500 \
11911312
| hexagon \
1192
- | i370 | i*86 | i860 | i960 | ia16 | ia64 \
1193
- | ip2k | iq2000 \
1313
+ | hppa \
1314
+ | hppa1.[01] \
1315
+ | hppa2.0 \
1316
+ | hppa2.0[nw] \
1317
+ | hppa64 \
1318
+ | i*86 \
1319
+ | i370 \
1320
+ | i860 \
1321
+ | i960 \
1322
+ | ia16 \
1323
+ | ia64 \
1324
+ | ip2k \
1325
+ | iq2000 \
1326
+ | javascript \
11941327
| k1om \
1195
- | le32 | le64 \
1328
+ | kvx \
1329
+ | le32 \
1330
+ | le64 \
11961331
| lm32 \
1197
- | loongarch32 | loongarch64 | loongarchx32 \
1198
- | m32c | m32r | m32rle \
1199
- | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
1200
- | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
1201
- | m88110 | m88k | maxq | mb | mcore | mep | metag \
1202
- | microblaze | microblazeel \
1203
- | mips | mipsbe | mipseb | mipsel | mipsle \
1204
- | mips16 \
1205
- | mips64 | mips64eb | mips64el \
1206
- | mips64octeon | mips64octeonel \
1207
- | mips64orion | mips64orionel \
1208
- | mips64r5900 | mips64r5900el \
1209
- | mips64vr | mips64vrel \
1210
- | mips64vr4100 | mips64vr4100el \
1211
- | mips64vr4300 | mips64vr4300el \
1212
- | mips64vr5000 | mips64vr5000el \
1213
- | mips64vr5900 | mips64vr5900el \
1214
- | mipsisa32 | mipsisa32el \
1215
- | mipsisa32r2 | mipsisa32r2el \
1216
- | mipsisa32r3 | mipsisa32r3el \
1217
- | mipsisa32r5 | mipsisa32r5el \
1218
- | mipsisa32r6 | mipsisa32r6el \
1219
- | mipsisa64 | mipsisa64el \
1220
- | mipsisa64r2 | mipsisa64r2el \
1221
- | mipsisa64r3 | mipsisa64r3el \
1222
- | mipsisa64r5 | mipsisa64r5el \
1223
- | mipsisa64r6 | mipsisa64r6el \
1224
- | mipsisa64sb1 | mipsisa64sb1el \
1225
- | mipsisa64sr71k | mipsisa64sr71kel \
1226
- | mipsr5900 | mipsr5900el \
1227
- | mipstx39 | mipstx39el \
1332
+ | loongarch32 \
1333
+ | loongarch64 \
1334
+ | m32c \
1335
+ | m32r \
1336
+ | m32rle \
1337
+ | m5200 \
1338
+ | m68000 \
1339
+ | m680[012346]0 \
1340
+ | m6811 \
1341
+ | m6812 \
1342
+ | m68360 \
1343
+ | m683?2 \
1344
+ | m68hc11 \
1345
+ | m68hc12 \
1346
+ | m68hcs12x \
1347
+ | m68k \
1348
+ | m88110 \
1349
+ | m88k \
1350
+ | maxq \
1351
+ | mb \
1352
+ | mcore \
1353
+ | mep \
1354
+ | metag \
1355
+ | microblaze \
1356
+ | microblazeel \
1357
+ | mips* \
12281358
| mmix \
1229
- | mn10200 | mn10300 \
1359
+ | mn10200 \
1360
+ | mn10300 \
12301361
| moxie \
1231
- | mt \
12321362
| msp430 \
1233
- | nds32 | nds32le | nds32be \
1363
+ | mt \
1364
+ | nanomips* \
1365
+ | nds32 \
1366
+ | nds32be \
1367
+ | nds32le \
12341368
| nfp \
1235
- | nios | nios2 | nios2eb | nios2el \
1236
- | none | np1 | ns16k | ns32k | nvptx \
1369
+ | nios \
1370
+ | nios2 \
1371
+ | nios2eb \
1372
+ | nios2el \
1373
+ | none \
1374
+ | np1 \
1375
+ | ns16k \
1376
+ | ns32k \
1377
+ | nvptx \
12371378
| open8 \
12381379
| or1k* \
12391380
| or32 \
12401381
| orion \
1382
+ | pdp10 \
1383
+ | pdp11 \
12411384
| picochip \
1242
- | pdp10 | pdp11 | pj | pjl | pn | power \
1243
- | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
1385
+ | pj \
1386
+ | pjl \
1387
+ | pn \
1388
+ | power \
1389
+ | powerpc \
1390
+ | powerpc64 \
1391
+ | powerpc64le \
1392
+ | powerpcle \
1393
+ | powerpcspe \
12441394
| pru \
12451395
| pyramid \
1246
- | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
1247
- | rl78 | romp | rs6000 | rx \
1248
- | s390 | s390x \
1396
+ | riscv \
1397
+ | riscv32 \
1398
+ | riscv32be \
1399
+ | riscv64 \
1400
+ | riscv64be \
1401
+ | rl78 \
1402
+ | romp \
1403
+ | rs6000 \
1404
+ | rx \
1405
+ | s390 \
1406
+ | s390x \
12491407
| score \
1250
- | sh | shl \
1251
- | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
1252
- | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
1253
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
1408
+ | sh \
1409
+ | sh64 \
1410
+ | sh64le \
1411
+ | sh[12345][lb]e \
1412
+ | sh[1234] \
1413
+ | sh[1234]e[lb] \
1414
+ | sh[23]e \
1415
+ | sh[23]ele \
1416
+ | sh[24]a \
1417
+ | sh[24]ae[lb] \
1418
+ | sh[lb]e \
1419
+ | she[lb] \
1420
+ | shl \
1421
+ | sparc \
1422
+ | sparc64 \
1423
+ | sparc64b \
1424
+ | sparc64v \
1425
+ | sparc86x \
1426
+ | sparclet \
12541427
| sparclite \
1255
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
1428
+ | sparcv8 \
1429
+ | sparcv9 \
1430
+ | sparcv9b \
1431
+ | sparcv9v \
12561432
| spu \
1433
+ | sv1 \
1434
+ | sx* \
12571435
| tahoe \
12581436
| thumbv7* \
1259
- | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
1437
+ | tic30 \
1438
+ | tic4x \
1439
+ | tic54x \
1440
+ | tic55x \
1441
+ | tic6x \
1442
+ | tic80 \
12601443
| tron \
12611444
| ubicom32 \
1262
- | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
1445
+ | v70 \
1446
+ | v810 \
1447
+ | v850 \
1448
+ | v850e \
1449
+ | v850e1 \
1450
+ | v850e2 \
1451
+ | v850e2v3 \
1452
+ | v850es \
12631453
| vax \
1454
+ | vc4 \
12641455
| visium \
12651456
| w65 \
1266
- | wasm32 | wasm64 \
1457
+ | wasm32 \
1458
+ | wasm64 \
12671459
| we32k \
1268
- | x86 | x86_64 | xc16x | xgate | xps100 \
1269
- | xstormy16 | xtensa* \
1460
+ | x86 \
1461
+ | x86_64 \
1462
+ | xc16x \
1463
+ | xgate \
1464
+ | xps100 \
1465
+ | xstormy16 \
1466
+ | xtensa* \
12701467
| ymp \
1271
- | z8k | z80)
1468
+ | z80 \
1469
+ | z8k)
12721470
;;
12731471
12741472
*)
1275
- echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
1473
+ echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
12761474
exit 1
12771475
;;
12781476
esac
12791477
;;
12801478
esac
@@ -1291,15 +1489,16 @@
12911489
;;
12921490
esac
12931491
12941492
# Decode manufacturer-specific aliases for certain operating systems.
12951493
1296
-if test x$basic_os != x
1494
+if test x"$basic_os" != x
12971495
then
12981496
1299
-# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
1497
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
13001498
# set os.
1499
+obj=
13011500
case $basic_os in
13021501
gnu/linux*)
13031502
kernel=linux
13041503
os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
13051504
;;
@@ -1310,14 +1509,15 @@
13101509
nto-qnx*)
13111510
kernel=nto
13121511
os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
13131512
;;
13141513
*-*)
1315
- # shellcheck disable=SC2162
1514
+ saved_IFS=$IFS
13161515
IFS="-" read kernel os <<EOF
13171516
$basic_os
13181517
EOF
1518
+ IFS=$saved_IFS
13191519
;;
13201520
# Default OS when just kernel was specified
13211521
nto*)
13221522
kernel=nto
13231523
os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
@@ -1324,10 +1524,14 @@
13241524
;;
13251525
linux*)
13261526
kernel=linux
13271527
os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
13281528
;;
1529
+ managarm*)
1530
+ kernel=managarm
1531
+ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
1532
+ ;;
13291533
*)
13301534
kernel=
13311535
os=$basic_os
13321536
;;
13331537
esac
@@ -1350,10 +1554,27 @@
13501554
solaris)
13511555
os=solaris2
13521556
;;
13531557
unixware*)
13541558
os=sysv4.2uw
1559
+ ;;
1560
+ # The marketing names for NeXT's operating systems were
1561
+ # NeXTSTEP, NeXTSTEP 2, OpenSTEP 3, OpenSTEP 4. 'openstep' is
1562
+ # mapped to 'openstep3', but 'openstep1' and 'openstep2' are
1563
+ # mapped to 'nextstep' and 'nextstep2', consistent with the
1564
+ # treatment of SunOS/Solaris.
1565
+ ns | ns1 | nextstep | nextstep1 | openstep1)
1566
+ os=nextstep
1567
+ ;;
1568
+ ns2 | nextstep2 | openstep2)
1569
+ os=nextstep2
1570
+ ;;
1571
+ ns3 | nextstep3 | openstep | openstep3)
1572
+ os=openstep3
1573
+ ;;
1574
+ ns4 | nextstep4 | openstep4)
1575
+ os=openstep4
13551576
;;
13561577
# es1800 is here to avoid being matched by es* (a different OS)
13571578
es1800*)
13581579
os=ose
13591580
;;
@@ -1421,10 +1642,11 @@
14211642
wince*)
14221643
os=wince
14231644
;;
14241645
utek*)
14251646
os=bsd
1647
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|tektronix|'`
14261648
;;
14271649
dynix*)
14281650
os=bsd
14291651
;;
14301652
acis*)
@@ -1437,25 +1659,29 @@
14371659
os=syllable
14381660
;;
14391661
386bsd)
14401662
os=bsd
14411663
;;
1442
- ctix* | uts*)
1664
+ ctix*)
1665
+ os=sysv
1666
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|convergent|'`
1667
+ ;;
1668
+ uts*)
14431669
os=sysv
14441670
;;
14451671
nova*)
1446
- os=rtmk-nova
1447
- ;;
1448
- ns2)
1449
- os=nextstep2
1672
+ kernel=rtmk
1673
+ os=nova
14501674
;;
14511675
# Preserve the version number of sinix5.
14521676
sinix5.*)
14531677
os=`echo "$os" | sed -e 's|sinix|sysv|'`
1678
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
14541679
;;
14551680
sinix*)
14561681
os=sysv4
1682
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
14571683
;;
14581684
tpf*)
14591685
os=tpf
14601686
;;
14611687
triton*)
@@ -1489,13 +1715,19 @@
14891715
case $cpu in
14901716
arm*)
14911717
os=eabi
14921718
;;
14931719
*)
1494
- os=elf
1720
+ os=
1721
+ obj=elf
14951722
;;
14961723
esac
1724
+ ;;
1725
+ aout* | coff* | elf* | pe*)
1726
+ # These are machine code file formats, not OSes
1727
+ obj=$os
1728
+ os=
14971729
;;
14981730
*)
14991731
# No normalization, but not necessarily accepted, that comes below.
15001732
;;
15011733
esac
@@ -1511,47 +1743,57 @@
15111743
# that MANUFACTURER isn't an operating system. Otherwise, code above
15121744
# will signal an error saying that MANUFACTURER isn't an operating
15131745
# system, and we'll never get to this point.
15141746
15151747
kernel=
1748
+obj=
15161749
case $cpu-$vendor in
15171750
score-*)
1518
- os=elf
1751
+ os=
1752
+ obj=elf
15191753
;;
15201754
spu-*)
1521
- os=elf
1755
+ os=
1756
+ obj=elf
15221757
;;
15231758
*-acorn)
15241759
os=riscix1.2
15251760
;;
15261761
arm*-rebel)
15271762
kernel=linux
15281763
os=gnu
15291764
;;
15301765
arm*-semi)
1531
- os=aout
1766
+ os=
1767
+ obj=aout
15321768
;;
15331769
c4x-* | tic4x-*)
1534
- os=coff
1770
+ os=
1771
+ obj=coff
15351772
;;
15361773
c8051-*)
1537
- os=elf
1774
+ os=
1775
+ obj=elf
15381776
;;
15391777
clipper-intergraph)
15401778
os=clix
15411779
;;
15421780
hexagon-*)
1543
- os=elf
1781
+ os=
1782
+ obj=elf
15441783
;;
15451784
tic54x-*)
1546
- os=coff
1785
+ os=
1786
+ obj=coff
15471787
;;
15481788
tic55x-*)
1549
- os=coff
1789
+ os=
1790
+ obj=coff
15501791
;;
15511792
tic6x-*)
1552
- os=coff
1793
+ os=
1794
+ obj=coff
15531795
;;
15541796
# This must come before the *-dec entry.
15551797
pdp10-*)
15561798
os=tops20
15571799
;;
@@ -1569,32 +1811,47 @@
15691811
;;
15701812
m68000-sun)
15711813
os=sunos3
15721814
;;
15731815
m68*-cisco)
1574
- os=aout
1816
+ os=
1817
+ obj=aout
15751818
;;
15761819
mep-*)
1577
- os=elf
1820
+ os=
1821
+ obj=elf
1822
+ ;;
1823
+ # The -sgi and -siemens entries must be before the mips- entry
1824
+ # or we get the wrong os.
1825
+ *-sgi)
1826
+ os=irix
1827
+ ;;
1828
+ *-siemens)
1829
+ os=sysv4
15781830
;;
15791831
mips*-cisco)
1580
- os=elf
1832
+ os=
1833
+ obj=elf
15811834
;;
1582
- mips*-*)
1583
- os=elf
1835
+ mips*-*|nanomips*-*)
1836
+ os=
1837
+ obj=elf
15841838
;;
15851839
or32-*)
1586
- os=coff
1840
+ os=
1841
+ obj=coff
15871842
;;
1588
- *-tti) # must be before sparc entry or we get the wrong os.
1843
+ # This must be before the sparc-* entry or we get the wrong os.
1844
+ *-tti)
15891845
os=sysv3
15901846
;;
15911847
sparc-* | *-sun)
15921848
os=sunos4.1.1
15931849
;;
15941850
pru-*)
1595
- os=elf
1851
+ os=
1852
+ obj=elf
15961853
;;
15971854
*-be)
15981855
os=beos
15991856
;;
16001857
*-ibm)
@@ -1614,11 +1871,11 @@
16141871
;;
16151872
*-hp)
16161873
os=hpux
16171874
;;
16181875
*-hitachi)
1619
- os=hiux
1876
+ os=hiuxwe2
16201877
;;
16211878
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
16221879
os=sysv
16231880
;;
16241881
*-cbm)
@@ -1658,27 +1915,23 @@
16581915
os=bsd
16591916
;;
16601917
*-encore)
16611918
os=bsd
16621919
;;
1663
- *-sgi)
1664
- os=irix
1665
- ;;
1666
- *-siemens)
1667
- os=sysv4
1668
- ;;
16691920
*-masscomp)
16701921
os=rtu
16711922
;;
16721923
f30[01]-fujitsu | f700-fujitsu)
16731924
os=uxpv
16741925
;;
16751926
*-rom68k)
1676
- os=coff
1927
+ os=
1928
+ obj=coff
16771929
;;
16781930
*-*bug)
1679
- os=coff
1931
+ os=
1932
+ obj=coff
16801933
;;
16811934
*-apple)
16821935
os=macos
16831936
;;
16841937
*-atari*)
@@ -1692,96 +1945,324 @@
16921945
;;
16931946
esac
16941947
16951948
fi
16961949
1697
-# Now, validate our (potentially fixed-up) OS.
1950
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
1951
+
16981952
case $os in
16991953
# Sometimes we do "kernel-libc", so those need to count as OSes.
1700
- musl* | newlib* | uclibc*)
1954
+ llvm* | musl* | newlib* | relibc* | uclibc*)
17011955
;;
17021956
# Likewise for "kernel-abi"
17031957
eabi* | gnueabi*)
17041958
;;
17051959
# VxWorks passes extra cpu info in the 4th filed.
17061960
simlinux | simwindows | spe)
1961
+ ;;
1962
+ # See `case $cpu-$os` validation below
1963
+ ghcjs)
17071964
;;
17081965
# Now accept the basic system types.
1709
- # The portable systems comes first.
17101966
# Each alternative MUST end in a * to match a version number.
1711
- gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
1712
- | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
1713
- | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
1714
- | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
1715
- | hiux* | abug | nacl* | netware* | windows* \
1716
- | os9* | macos* | osx* | ios* \
1717
- | mpw* | magic* | mmixware* | mon960* | lnews* \
1718
- | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
1719
- | aos* | aros* | cloudabi* | sortix* | twizzler* \
1720
- | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
1721
- | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
1722
- | mirbsd* | netbsd* | dicos* | openedition* | ose* \
1723
- | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
1724
- | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
1725
- | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
1726
- | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
1727
- | udi* | lites* | ieee* | go32* | aux* | hcos* \
1728
- | chorusrdb* | cegcc* | glidix* | serenity* \
1729
- | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
1730
- | midipix* | mingw32* | mingw64* | mint* \
1731
- | uxpv* | beos* | mpeix* | udk* | moxiebox* \
1732
- | interix* | uwin* | mks* | rhapsody* | darwin* \
1733
- | openstep* | oskit* | conix* | pw32* | nonstopux* \
1734
- | storm-chaos* | tops10* | tenex* | tops20* | its* \
1735
- | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
1736
- | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
1737
- | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
1738
- | skyos* | haiku* | rdos* | toppers* | drops* | es* \
1739
- | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
1740
- | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
1741
- | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
1967
+ abug \
1968
+ | aix* \
1969
+ | amdhsa* \
1970
+ | amigados* \
1971
+ | amigaos* \
1972
+ | android* \
1973
+ | aof* \
1974
+ | aos* \
1975
+ | aros* \
1976
+ | atheos* \
1977
+ | auroraux* \
1978
+ | aux* \
1979
+ | beos* \
1980
+ | bitrig* \
1981
+ | bme* \
1982
+ | bosx* \
1983
+ | bsd* \
1984
+ | cegcc* \
1985
+ | chorusos* \
1986
+ | chorusrdb* \
1987
+ | clix* \
1988
+ | cloudabi* \
1989
+ | cnk* \
1990
+ | conix* \
1991
+ | cos* \
1992
+ | cxux* \
1993
+ | cygwin* \
1994
+ | darwin* \
1995
+ | dgux* \
1996
+ | dicos* \
1997
+ | dnix* \
1998
+ | domain* \
1999
+ | dragonfly* \
2000
+ | drops* \
2001
+ | ebmon* \
2002
+ | ecoff* \
2003
+ | ekkobsd* \
2004
+ | emscripten* \
2005
+ | emx* \
2006
+ | es* \
2007
+ | fiwix* \
2008
+ | freebsd* \
2009
+ | fuchsia* \
2010
+ | genix* \
2011
+ | genode* \
2012
+ | glidix* \
2013
+ | gnu* \
2014
+ | go32* \
2015
+ | haiku* \
2016
+ | hcos* \
2017
+ | hiux* \
2018
+ | hms* \
2019
+ | hpux* \
2020
+ | ieee* \
2021
+ | interix* \
2022
+ | ios* \
2023
+ | iris* \
2024
+ | irix* \
2025
+ | ironclad* \
2026
+ | isc* \
2027
+ | its* \
2028
+ | l4re* \
2029
+ | libertybsd* \
2030
+ | lites* \
2031
+ | lnews* \
2032
+ | luna* \
2033
+ | lynxos* \
2034
+ | mach* \
2035
+ | macos* \
2036
+ | magic* \
2037
+ | mbr* \
2038
+ | midipix* \
2039
+ | midnightbsd* \
2040
+ | mingw32* \
2041
+ | mingw64* \
2042
+ | minix* \
2043
+ | mint* \
2044
+ | mirbsd* \
2045
+ | mks* \
2046
+ | mlibc* \
2047
+ | mmixware* \
2048
+ | mon960* \
2049
+ | morphos* \
2050
+ | moss* \
2051
+ | moxiebox* \
2052
+ | mpeix* \
2053
+ | mpw* \
2054
+ | msdos* \
2055
+ | msys* \
2056
+ | mvs* \
2057
+ | nacl* \
2058
+ | netbsd* \
2059
+ | netware* \
2060
+ | newsos* \
2061
+ | nextstep* \
2062
+ | nindy* \
2063
+ | nonstopux* \
2064
+ | nova* \
2065
+ | nsk* \
2066
+ | nucleus* \
2067
+ | nx6 \
2068
+ | nx7 \
2069
+ | oabi* \
2070
+ | ohos* \
2071
+ | onefs* \
2072
+ | openbsd* \
2073
+ | openedition* \
2074
+ | openstep* \
2075
+ | os108* \
2076
+ | os2* \
2077
+ | os400* \
2078
+ | os68k* \
2079
+ | os9* \
2080
+ | ose* \
2081
+ | osf* \
2082
+ | oskit* \
2083
+ | osx* \
2084
+ | palmos* \
2085
+ | phoenix* \
2086
+ | plan9* \
2087
+ | powermax* \
2088
+ | powerunix* \
2089
+ | proelf* \
2090
+ | psos* \
2091
+ | psp* \
2092
+ | ptx* \
2093
+ | pw32* \
2094
+ | qnx* \
2095
+ | rdos* \
2096
+ | redox* \
2097
+ | rhapsody* \
2098
+ | riscix* \
2099
+ | riscos* \
2100
+ | rtems* \
2101
+ | rtmk* \
2102
+ | rtu* \
2103
+ | scout* \
2104
+ | secbsd* \
2105
+ | sei* \
2106
+ | serenity* \
2107
+ | sim* \
2108
+ | skyos* \
2109
+ | solaris* \
2110
+ | solidbsd* \
2111
+ | sortix* \
2112
+ | storm-chaos* \
2113
+ | sunos \
2114
+ | sunos[34]* \
2115
+ | superux* \
2116
+ | syllable* \
2117
+ | sym* \
2118
+ | sysv* \
2119
+ | tenex* \
2120
+ | tirtos* \
2121
+ | toppers* \
2122
+ | tops10* \
2123
+ | tops20* \
2124
+ | tpf* \
2125
+ | tvos* \
2126
+ | twizzler* \
2127
+ | uclinux* \
2128
+ | udi* \
2129
+ | udk* \
2130
+ | ultrix* \
2131
+ | unicos* \
2132
+ | uniplus* \
2133
+ | unleashed* \
2134
+ | unos* \
2135
+ | uwin* \
2136
+ | uxpv* \
2137
+ | v88r* \
2138
+ |*vms* \
2139
+ | vos* \
2140
+ | vsta* \
2141
+ | vxsim* \
2142
+ | vxworks* \
2143
+ | wasi* \
2144
+ | watchos* \
2145
+ | wince* \
2146
+ | windiss* \
2147
+ | windows* \
2148
+ | winnt* \
2149
+ | xenix* \
2150
+ | xray* \
2151
+ | zephyr* \
2152
+ | zvmoe* )
17422153
;;
17432154
# This one is extra strict with allowed versions
17442155
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
17452156
# Don't forget version if it is 3.2v4 or newer.
17462157
;;
2158
+ # This refers to builds using the UEFI calling convention
2159
+ # (which depends on the architecture) and PE file format.
2160
+ # Note that this is both a different calling convention and
2161
+ # different file format than that of GNU-EFI
2162
+ # (x86_64-w64-mingw32).
2163
+ uefi)
2164
+ ;;
17472165
none)
17482166
;;
2167
+ kernel* | msvc* )
2168
+ # Restricted further below
2169
+ ;;
2170
+ '')
2171
+ if test x"$obj" = x
2172
+ then
2173
+ echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
2174
+ fi
2175
+ ;;
2176
+ *)
2177
+ echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
2178
+ exit 1
2179
+ ;;
2180
+esac
2181
+
2182
+case $obj in
2183
+ aout* | coff* | elf* | pe*)
2184
+ ;;
2185
+ '')
2186
+ # empty is fine
2187
+ ;;
17492188
*)
1750
- echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
2189
+ echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
2190
+ exit 1
2191
+ ;;
2192
+esac
2193
+
2194
+# Here we handle the constraint that a (synthetic) cpu and os are
2195
+# valid only in combination with each other and nowhere else.
2196
+case $cpu-$os in
2197
+ # The "javascript-unknown-ghcjs" triple is used by GHC; we
2198
+ # accept it here in order to tolerate that, but reject any
2199
+ # variations.
2200
+ javascript-ghcjs)
2201
+ ;;
2202
+ javascript-* | *-ghcjs)
2203
+ echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
17512204
exit 1
17522205
;;
17532206
esac
17542207
17552208
# As a final step for OS-related things, validate the OS-kernel combination
17562209
# (given a valid OS), if there is a kernel.
1757
-case $kernel-$os in
1758
- linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
2210
+case $kernel-$os-$obj in
2211
+ linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
2212
+ | linux-mlibc*- | linux-musl*- | linux-newlib*- \
2213
+ | linux-relibc*- | linux-uclibc*- | linux-ohos*- )
2214
+ ;;
2215
+ uclinux-uclibc*- | uclinux-gnu*- )
2216
+ ;;
2217
+ managarm-mlibc*- | managarm-kernel*- )
17592218
;;
1760
- uclinux-uclibc* )
2219
+ windows*-msvc*-)
17612220
;;
1762
- -dietlibc* | -newlib* | -musl* | -uclibc* )
2221
+ -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
2222
+ | -uclibc*- )
17632223
# These are just libc implementations, not actual OSes, and thus
17642224
# require a kernel.
1765
- echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
2225
+ echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
2226
+ exit 1
2227
+ ;;
2228
+ -kernel*- )
2229
+ echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
2230
+ exit 1
2231
+ ;;
2232
+ *-kernel*- )
2233
+ echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
2234
+ exit 1
2235
+ ;;
2236
+ *-msvc*- )
2237
+ echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
17662238
exit 1
17672239
;;
1768
- kfreebsd*-gnu* | kopensolaris*-gnu*)
1769
- ;;
1770
- vxworks-simlinux | vxworks-simwindows | vxworks-spe)
1771
- ;;
1772
- nto-qnx*)
1773
- ;;
1774
- os2-emx)
1775
- ;;
1776
- *-eabi* | *-gnueabi*)
1777
- ;;
1778
- -*)
2240
+ kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-)
2241
+ ;;
2242
+ vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
2243
+ ;;
2244
+ nto-qnx*-)
2245
+ ;;
2246
+ os2-emx-)
2247
+ ;;
2248
+ rtmk-nova-)
2249
+ ;;
2250
+ *-eabi*- | *-gnueabi*-)
2251
+ ;;
2252
+ none--*)
2253
+ # None (no kernel, i.e. freestanding / bare metal),
2254
+ # can be paired with an machine code file format
2255
+ ;;
2256
+ -*-)
17792257
# Blank kernel with real OS is always fine.
17802258
;;
1781
- *-*)
1782
- echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
2259
+ --*)
2260
+ # Blank kernel and OS with real machine code file format is always fine.
2261
+ ;;
2262
+ *-*-*)
2263
+ echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
17832264
exit 1
17842265
;;
17852266
esac
17862267
17872268
# Here we handle the case where we know the os, and the CPU type, but not the
@@ -1790,11 +2271,11 @@
17902271
unknown)
17912272
case $cpu-$os in
17922273
*-riscix*)
17932274
vendor=acorn
17942275
;;
1795
- *-sunos*)
2276
+ *-sunos* | *-solaris*)
17962277
vendor=sun
17972278
;;
17982279
*-cnk* | *-aix*)
17992280
vendor=ibm
18002281
;;
@@ -1860,14 +2341,14 @@
18602341
;;
18612342
esac
18622343
;;
18632344
esac
18642345
1865
-echo "$cpu-$vendor-${kernel:+$kernel-}$os"
2346
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
18662347
exit
18672348
18682349
# Local variables:
18692350
# eval: (add-hook 'before-save-hook 'time-stamp)
18702351
# time-stamp-start: "timestamp='"
18712352
# time-stamp-format: "%:y-%02m-%02d"
18722353
# time-stamp-end: "'"
18732354
# End:
18742355
--- autosetup/autosetup-config.sub
+++ autosetup/autosetup-config.sub
@@ -1,16 +1,16 @@
1 #! /bin/sh
2 # Configuration validation subroutine script.
3 # Copyright 1992-2021 Free Software Foundation, Inc.
4
5 # shellcheck disable=SC2006,SC2268 # see below for rationale
6
7 timestamp='2021-07-03'
8
9 # This file is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -74,17 +74,17 @@
74 Report bugs and patches to <[email protected]>."
75
76 version="\
77 GNU config.sub ($timestamp)
78
79 Copyright 1992-2021 Free Software Foundation, Inc.
80
81 This is free software; see the source for copying conditions. There is NO
82 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
83
84 help="
85 Try \`$me --help' for more information."
86
87 # Parse command line
88 while test $# -gt 0 ; do
89 case $1 in
90 --time-stamp | --time* | -t )
@@ -118,19 +118,20 @@
118 *) echo "$me: too many arguments$help" >&2
119 exit 1;;
120 esac
121
122 # Split fields of configuration type
123 # shellcheck disable=SC2162
124 IFS="-" read field1 field2 field3 field4 <<EOF
125 $1
126 EOF
 
127
128 # Separate into logical components for further validation
129 case $1 in
130 *-*-*-*-*)
131 echo Invalid configuration \`"$1"\': more than four components >&2
132 exit 1
133 ;;
134 *-*-*-*)
135 basic_machine=$field1-$field2
136 basic_os=$field3-$field4
@@ -138,14 +139,25 @@
138 *-*-*)
139 # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
140 # parts
141 maybe_os=$field2-$field3
142 case $maybe_os in
143 nto-qnx* | linux-* | uclinux-uclibc* \
144 | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
145 | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
146 | storm-chaos* | os2-emx* | rtmk-nova*)
 
 
 
 
 
 
 
 
 
 
 
147 basic_machine=$field1
148 basic_os=$maybe_os
149 ;;
150 android-linux)
151 basic_machine=$field1-unknown
@@ -156,37 +168,105 @@
156 basic_os=$field3
157 ;;
158 esac
159 ;;
160 *-*)
161 # A lone config we happen to match not fitting any pattern
162 case $field1-$field2 in
 
 
 
 
 
163 decstation-3100)
164 basic_machine=mips-dec
165 basic_os=
166 ;;
167 *-*)
168 # Second component is usually, but not always the OS
169 case $field2 in
170 # Prevent following clause from handling this valid os
171 sun*os*)
172 basic_machine=$field1
173 basic_os=$field2
174 ;;
175 # Manufacturers
176 dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
177 | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
178 | unicom* | ibm* | next | hp | isi* | apollo | altos* \
179 | convergent* | ncr* | news | 32* | 3600* | 3100* \
180 | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
181 | ultra | tti* | harris | dolphin | highlevel | gould \
182 | cbm | ns | masscomp | apple | axis | knuth | cray \
183 | microblaze* | sim | cisco \
184 | oki | wec | wrs | winbond)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185 basic_machine=$field1-$field2
186 basic_os=
187 ;;
 
 
 
 
188 *)
189 basic_machine=$field1
190 basic_os=$field2
191 ;;
192 esac
@@ -263,30 +343,10 @@
263 ;;
264 cegcc)
265 basic_machine=arm-unknown
266 basic_os=cegcc
267 ;;
268 convex-c1)
269 basic_machine=c1-convex
270 basic_os=bsd
271 ;;
272 convex-c2)
273 basic_machine=c2-convex
274 basic_os=bsd
275 ;;
276 convex-c32)
277 basic_machine=c32-convex
278 basic_os=bsd
279 ;;
280 convex-c34)
281 basic_machine=c34-convex
282 basic_os=bsd
283 ;;
284 convex-c38)
285 basic_machine=c38-convex
286 basic_os=bsd
287 ;;
288 cray)
289 basic_machine=j90-cray
290 basic_os=unicos
291 ;;
292 crds | unos)
@@ -705,13 +765,21 @@
705 decsystem20* | dec20*)
706 cpu=pdp10
707 vendor=dec
708 basic_os=tops20
709 ;;
710 delta | 3300 | motorola-3300 | motorola-delta \
711 | 3300-motorola | delta-motorola)
712 cpu=m68k
713 vendor=motorola
714 ;;
715 dpx2*)
 
 
 
 
 
716 cpu=m68k
717 vendor=bull
 
 
 
 
@@ -718,6 +786,9 @@
718 basic_os=sysv3
 
 
 
719 ;;
720 encore | umax | mmax)
721 cpu=ns32k
722 vendor=encore
723 ;;
@@ -828,22 +899,10 @@
828 basic_os=newsos
829 ;;
830 next | m*-next)
831 cpu=m68k
832 vendor=next
833 case $basic_os in
834 openstep*)
835 ;;
836 nextstep*)
837 ;;
838 ns2*)
839 basic_os=nextstep2
840 ;;
841 *)
842 basic_os=nextstep3
843 ;;
844 esac
845 ;;
846 np1)
847 cpu=np1
848 vendor=gould
849 ;;
@@ -928,16 +987,17 @@
928 cpu=sparc
929 vendor=`echo "$basic_machine" | sed 's/-.*//'`
930 ;;
931
932 *-*)
933 # shellcheck disable=SC2162
934 IFS="-" read cpu vendor <<EOF
935 $basic_machine
936 EOF
 
937 ;;
938 # We use `pc' rather than `unknown'
939 # because (1) that's what they normally are, and
940 # (2) the word "unknown" tends to confuse beginning users.
941 i*86 | x86_64)
942 cpu=$basic_machine
943 vendor=pc
@@ -961,19 +1021,23 @@
961
962 unset -v basic_machine
963
964 # Decode basic machines in the full and proper CPU-Company form.
965 case $cpu-$vendor in
966 # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
967 # some cases the only manufacturer, in others, it is the most popular.
 
 
 
 
968 craynv-unknown)
969 vendor=cray
970 basic_os=${basic_os:-unicosmp}
971 ;;
972 c90-unknown | c90-cray)
973 vendor=cray
974 basic_os=${Basic_os:-unicos}
975 ;;
976 fx80-unknown)
977 vendor=alliant
978 ;;
979 romp-unknown)
@@ -1010,23 +1074,46 @@
1010 cpu=xps100
1011 vendor=honeywell
1012 ;;
1013
1014 # Here we normalize CPU types with a missing or matching vendor
1015 dpx20-unknown | dpx20-bull)
1016 cpu=rs6000
1017 vendor=bull
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1018 basic_os=${basic_os:-bosx}
1019 ;;
 
 
 
1020
1021 # Here we normalize CPU types irrespective of the vendor
1022 amd64-*)
1023 cpu=x86_64
1024 ;;
1025 blackfin-*)
1026 cpu=bfin
1027 basic_os=linux
1028 ;;
1029 c54x-*)
1030 cpu=tic54x
1031 ;;
1032 c55x-*)
@@ -1045,37 +1132,34 @@
1045 ms1-*)
1046 cpu=mt
1047 ;;
1048 m68knommu-*)
1049 cpu=m68k
1050 basic_os=linux
1051 ;;
1052 m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
1053 cpu=s12z
1054 ;;
1055 openrisc-*)
1056 cpu=or32
1057 ;;
1058 parisc-*)
1059 cpu=hppa
1060 basic_os=linux
1061 ;;
1062 pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
1063 cpu=i586
1064 ;;
1065 pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
1066 cpu=i686
1067 ;;
1068 pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
1069 cpu=i686
1070 ;;
1071 pentium4-*)
1072 cpu=i786
1073 ;;
1074 pc98-*)
1075 cpu=i386
1076 ;;
1077 ppc-* | ppcbe-*)
1078 cpu=powerpc
1079 ;;
1080 ppcle-* | powerpclittle-*)
1081 cpu=powerpcle
@@ -1105,17 +1189,14 @@
1105 cpu=mipstx39
1106 ;;
1107 tx39el-*)
1108 cpu=mipstx39el
1109 ;;
1110 x64-*)
1111 cpu=x86_64
1112 ;;
1113 xscale-* | xscalee[bl]-*)
1114 cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
1115 ;;
1116 arm64-*)
1117 cpu=aarch64
1118 ;;
1119
1120 # Recognize the canonical CPU Types that limit and/or modify the
1121 # company names they are paired with.
@@ -1163,118 +1244,235 @@
1163
1164 *)
1165 # Recognize the canonical CPU types that are allowed with any
1166 # company name.
1167 case $cpu in
1168 1750a | 580 \
 
 
1169 | a29k \
1170 | aarch64 | aarch64_be \
 
 
1171 | abacus \
1172 | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
1173 | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
1174 | alphapca5[67] | alpha64pca5[67] \
 
 
 
 
 
 
 
1175 | am33_2.0 \
1176 | amdgcn \
1177 | arc | arceb | arc32 | arc64 \
1178 | arm | arm[lb]e | arme[lb] | armv* \
1179 | avr | avr32 \
 
 
 
 
 
 
 
1180 | asmjs \
 
 
1181 | ba \
1182 | be32 | be64 \
1183 | bfin | bpf | bs2000 \
1184 | c[123]* | c30 | [cjt]90 | c4x \
1185 | c8051 | clipper | craynv | csky | cydra \
1186 | d10v | d30v | dlx | dsp16xx \
1187 | e2k | elxsi | epiphany \
1188 | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
1189 | h8300 | h8500 \
1190 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1191 | hexagon \
1192 | i370 | i*86 | i860 | i960 | ia16 | ia64 \
1193 | ip2k | iq2000 \
 
 
 
 
 
 
 
 
 
 
 
 
1194 | k1om \
1195 | le32 | le64 \
 
 
1196 | lm32 \
1197 | loongarch32 | loongarch64 | loongarchx32 \
1198 | m32c | m32r | m32rle \
1199 | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
1200 | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
1201 | m88110 | m88k | maxq | mb | mcore | mep | metag \
1202 | microblaze | microblazeel \
1203 | mips | mipsbe | mipseb | mipsel | mipsle \
1204 | mips16 \
1205 | mips64 | mips64eb | mips64el \
1206 | mips64octeon | mips64octeonel \
1207 | mips64orion | mips64orionel \
1208 | mips64r5900 | mips64r5900el \
1209 | mips64vr | mips64vrel \
1210 | mips64vr4100 | mips64vr4100el \
1211 | mips64vr4300 | mips64vr4300el \
1212 | mips64vr5000 | mips64vr5000el \
1213 | mips64vr5900 | mips64vr5900el \
1214 | mipsisa32 | mipsisa32el \
1215 | mipsisa32r2 | mipsisa32r2el \
1216 | mipsisa32r3 | mipsisa32r3el \
1217 | mipsisa32r5 | mipsisa32r5el \
1218 | mipsisa32r6 | mipsisa32r6el \
1219 | mipsisa64 | mipsisa64el \
1220 | mipsisa64r2 | mipsisa64r2el \
1221 | mipsisa64r3 | mipsisa64r3el \
1222 | mipsisa64r5 | mipsisa64r5el \
1223 | mipsisa64r6 | mipsisa64r6el \
1224 | mipsisa64sb1 | mipsisa64sb1el \
1225 | mipsisa64sr71k | mipsisa64sr71kel \
1226 | mipsr5900 | mipsr5900el \
1227 | mipstx39 | mipstx39el \
1228 | mmix \
1229 | mn10200 | mn10300 \
 
1230 | moxie \
1231 | mt \
1232 | msp430 \
1233 | nds32 | nds32le | nds32be \
 
 
 
 
1234 | nfp \
1235 | nios | nios2 | nios2eb | nios2el \
1236 | none | np1 | ns16k | ns32k | nvptx \
 
 
 
 
 
 
 
1237 | open8 \
1238 | or1k* \
1239 | or32 \
1240 | orion \
 
 
1241 | picochip \
1242 | pdp10 | pdp11 | pj | pjl | pn | power \
1243 | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
 
 
 
 
 
 
 
1244 | pru \
1245 | pyramid \
1246 | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
1247 | rl78 | romp | rs6000 | rx \
1248 | s390 | s390x \
 
 
 
 
 
 
 
 
1249 | score \
1250 | sh | shl \
1251 | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
1252 | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
1253 | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1254 | sparclite \
1255 | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
 
 
 
1256 | spu \
 
 
1257 | tahoe \
1258 | thumbv7* \
1259 | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
 
 
 
 
 
1260 | tron \
1261 | ubicom32 \
1262 | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
 
 
 
 
 
 
 
1263 | vax \
 
1264 | visium \
1265 | w65 \
1266 | wasm32 | wasm64 \
 
1267 | we32k \
1268 | x86 | x86_64 | xc16x | xgate | xps100 \
1269 | xstormy16 | xtensa* \
 
 
 
 
 
1270 | ymp \
1271 | z8k | z80)
 
1272 ;;
1273
1274 *)
1275 echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
1276 exit 1
1277 ;;
1278 esac
1279 ;;
1280 esac
@@ -1291,15 +1489,16 @@
1291 ;;
1292 esac
1293
1294 # Decode manufacturer-specific aliases for certain operating systems.
1295
1296 if test x$basic_os != x
1297 then
1298
1299 # First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
1300 # set os.
 
1301 case $basic_os in
1302 gnu/linux*)
1303 kernel=linux
1304 os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
1305 ;;
@@ -1310,14 +1509,15 @@
1310 nto-qnx*)
1311 kernel=nto
1312 os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
1313 ;;
1314 *-*)
1315 # shellcheck disable=SC2162
1316 IFS="-" read kernel os <<EOF
1317 $basic_os
1318 EOF
 
1319 ;;
1320 # Default OS when just kernel was specified
1321 nto*)
1322 kernel=nto
1323 os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
@@ -1324,10 +1524,14 @@
1324 ;;
1325 linux*)
1326 kernel=linux
1327 os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
1328 ;;
 
 
 
 
1329 *)
1330 kernel=
1331 os=$basic_os
1332 ;;
1333 esac
@@ -1350,10 +1554,27 @@
1350 solaris)
1351 os=solaris2
1352 ;;
1353 unixware*)
1354 os=sysv4.2uw
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1355 ;;
1356 # es1800 is here to avoid being matched by es* (a different OS)
1357 es1800*)
1358 os=ose
1359 ;;
@@ -1421,10 +1642,11 @@
1421 wince*)
1422 os=wince
1423 ;;
1424 utek*)
1425 os=bsd
 
1426 ;;
1427 dynix*)
1428 os=bsd
1429 ;;
1430 acis*)
@@ -1437,25 +1659,29 @@
1437 os=syllable
1438 ;;
1439 386bsd)
1440 os=bsd
1441 ;;
1442 ctix* | uts*)
 
 
 
 
1443 os=sysv
1444 ;;
1445 nova*)
1446 os=rtmk-nova
1447 ;;
1448 ns2)
1449 os=nextstep2
1450 ;;
1451 # Preserve the version number of sinix5.
1452 sinix5.*)
1453 os=`echo "$os" | sed -e 's|sinix|sysv|'`
 
1454 ;;
1455 sinix*)
1456 os=sysv4
 
1457 ;;
1458 tpf*)
1459 os=tpf
1460 ;;
1461 triton*)
@@ -1489,13 +1715,19 @@
1489 case $cpu in
1490 arm*)
1491 os=eabi
1492 ;;
1493 *)
1494 os=elf
 
1495 ;;
1496 esac
 
 
 
 
 
1497 ;;
1498 *)
1499 # No normalization, but not necessarily accepted, that comes below.
1500 ;;
1501 esac
@@ -1511,47 +1743,57 @@
1511 # that MANUFACTURER isn't an operating system. Otherwise, code above
1512 # will signal an error saying that MANUFACTURER isn't an operating
1513 # system, and we'll never get to this point.
1514
1515 kernel=
 
1516 case $cpu-$vendor in
1517 score-*)
1518 os=elf
 
1519 ;;
1520 spu-*)
1521 os=elf
 
1522 ;;
1523 *-acorn)
1524 os=riscix1.2
1525 ;;
1526 arm*-rebel)
1527 kernel=linux
1528 os=gnu
1529 ;;
1530 arm*-semi)
1531 os=aout
 
1532 ;;
1533 c4x-* | tic4x-*)
1534 os=coff
 
1535 ;;
1536 c8051-*)
1537 os=elf
 
1538 ;;
1539 clipper-intergraph)
1540 os=clix
1541 ;;
1542 hexagon-*)
1543 os=elf
 
1544 ;;
1545 tic54x-*)
1546 os=coff
 
1547 ;;
1548 tic55x-*)
1549 os=coff
 
1550 ;;
1551 tic6x-*)
1552 os=coff
 
1553 ;;
1554 # This must come before the *-dec entry.
1555 pdp10-*)
1556 os=tops20
1557 ;;
@@ -1569,32 +1811,47 @@
1569 ;;
1570 m68000-sun)
1571 os=sunos3
1572 ;;
1573 m68*-cisco)
1574 os=aout
 
1575 ;;
1576 mep-*)
1577 os=elf
 
 
 
 
 
 
 
 
 
1578 ;;
1579 mips*-cisco)
1580 os=elf
 
1581 ;;
1582 mips*-*)
1583 os=elf
 
1584 ;;
1585 or32-*)
1586 os=coff
 
1587 ;;
1588 *-tti) # must be before sparc entry or we get the wrong os.
 
1589 os=sysv3
1590 ;;
1591 sparc-* | *-sun)
1592 os=sunos4.1.1
1593 ;;
1594 pru-*)
1595 os=elf
 
1596 ;;
1597 *-be)
1598 os=beos
1599 ;;
1600 *-ibm)
@@ -1614,11 +1871,11 @@
1614 ;;
1615 *-hp)
1616 os=hpux
1617 ;;
1618 *-hitachi)
1619 os=hiux
1620 ;;
1621 i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
1622 os=sysv
1623 ;;
1624 *-cbm)
@@ -1658,27 +1915,23 @@
1658 os=bsd
1659 ;;
1660 *-encore)
1661 os=bsd
1662 ;;
1663 *-sgi)
1664 os=irix
1665 ;;
1666 *-siemens)
1667 os=sysv4
1668 ;;
1669 *-masscomp)
1670 os=rtu
1671 ;;
1672 f30[01]-fujitsu | f700-fujitsu)
1673 os=uxpv
1674 ;;
1675 *-rom68k)
1676 os=coff
 
1677 ;;
1678 *-*bug)
1679 os=coff
 
1680 ;;
1681 *-apple)
1682 os=macos
1683 ;;
1684 *-atari*)
@@ -1692,96 +1945,324 @@
1692 ;;
1693 esac
1694
1695 fi
1696
1697 # Now, validate our (potentially fixed-up) OS.
 
1698 case $os in
1699 # Sometimes we do "kernel-libc", so those need to count as OSes.
1700 musl* | newlib* | uclibc*)
1701 ;;
1702 # Likewise for "kernel-abi"
1703 eabi* | gnueabi*)
1704 ;;
1705 # VxWorks passes extra cpu info in the 4th filed.
1706 simlinux | simwindows | spe)
 
 
 
1707 ;;
1708 # Now accept the basic system types.
1709 # The portable systems comes first.
1710 # Each alternative MUST end in a * to match a version number.
1711 gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
1712 | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
1713 | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
1714 | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
1715 | hiux* | abug | nacl* | netware* | windows* \
1716 | os9* | macos* | osx* | ios* \
1717 | mpw* | magic* | mmixware* | mon960* | lnews* \
1718 | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
1719 | aos* | aros* | cloudabi* | sortix* | twizzler* \
1720 | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
1721 | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
1722 | mirbsd* | netbsd* | dicos* | openedition* | ose* \
1723 | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
1724 | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
1725 | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
1726 | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
1727 | udi* | lites* | ieee* | go32* | aux* | hcos* \
1728 | chorusrdb* | cegcc* | glidix* | serenity* \
1729 | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
1730 | midipix* | mingw32* | mingw64* | mint* \
1731 | uxpv* | beos* | mpeix* | udk* | moxiebox* \
1732 | interix* | uwin* | mks* | rhapsody* | darwin* \
1733 | openstep* | oskit* | conix* | pw32* | nonstopux* \
1734 | storm-chaos* | tops10* | tenex* | tops20* | its* \
1735 | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
1736 | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
1737 | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
1738 | skyos* | haiku* | rdos* | toppers* | drops* | es* \
1739 | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
1740 | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
1741 | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1742 ;;
1743 # This one is extra strict with allowed versions
1744 sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
1745 # Don't forget version if it is 3.2v4 or newer.
1746 ;;
 
 
 
 
 
 
 
1747 none)
1748 ;;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1749 *)
1750 echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1751 exit 1
1752 ;;
1753 esac
1754
1755 # As a final step for OS-related things, validate the OS-kernel combination
1756 # (given a valid OS), if there is a kernel.
1757 case $kernel-$os in
1758 linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
 
 
 
 
 
 
1759 ;;
1760 uclinux-uclibc* )
1761 ;;
1762 -dietlibc* | -newlib* | -musl* | -uclibc* )
 
1763 # These are just libc implementations, not actual OSes, and thus
1764 # require a kernel.
1765 echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
 
 
 
 
 
 
 
 
 
 
 
 
1766 exit 1
1767 ;;
1768 kfreebsd*-gnu* | kopensolaris*-gnu*)
1769 ;;
1770 vxworks-simlinux | vxworks-simwindows | vxworks-spe)
1771 ;;
1772 nto-qnx*)
1773 ;;
1774 os2-emx)
1775 ;;
1776 *-eabi* | *-gnueabi*)
1777 ;;
1778 -*)
 
 
 
 
 
 
1779 # Blank kernel with real OS is always fine.
1780 ;;
1781 *-*)
1782 echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
 
 
 
1783 exit 1
1784 ;;
1785 esac
1786
1787 # Here we handle the case where we know the os, and the CPU type, but not the
@@ -1790,11 +2271,11 @@
1790 unknown)
1791 case $cpu-$os in
1792 *-riscix*)
1793 vendor=acorn
1794 ;;
1795 *-sunos*)
1796 vendor=sun
1797 ;;
1798 *-cnk* | *-aix*)
1799 vendor=ibm
1800 ;;
@@ -1860,14 +2341,14 @@
1860 ;;
1861 esac
1862 ;;
1863 esac
1864
1865 echo "$cpu-$vendor-${kernel:+$kernel-}$os"
1866 exit
1867
1868 # Local variables:
1869 # eval: (add-hook 'before-save-hook 'time-stamp)
1870 # time-stamp-start: "timestamp='"
1871 # time-stamp-format: "%:y-%02m-%02d"
1872 # time-stamp-end: "'"
1873 # End:
1874
--- autosetup/autosetup-config.sub
+++ autosetup/autosetup-config.sub
@@ -1,16 +1,16 @@
1 #! /bin/sh
2 # Configuration validation subroutine script.
3 # Copyright 1992-2024 Free Software Foundation, Inc.
4
5 # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale
6
7 timestamp='2024-05-27'
8
9 # This file is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -74,17 +74,17 @@
74 Report bugs and patches to <[email protected]>."
75
76 version="\
77 GNU config.sub ($timestamp)
78
79 Copyright 1992-2024 Free Software Foundation, Inc.
80
81 This is free software; see the source for copying conditions. There is NO
82 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
83
84 help="
85 Try '$me --help' for more information."
86
87 # Parse command line
88 while test $# -gt 0 ; do
89 case $1 in
90 --time-stamp | --time* | -t )
@@ -118,19 +118,20 @@
118 *) echo "$me: too many arguments$help" >&2
119 exit 1;;
120 esac
121
122 # Split fields of configuration type
123 saved_IFS=$IFS
124 IFS="-" read field1 field2 field3 field4 <<EOF
125 $1
126 EOF
127 IFS=$saved_IFS
128
129 # Separate into logical components for further validation
130 case $1 in
131 *-*-*-*-*)
132 echo "Invalid configuration '$1': more than four components" >&2
133 exit 1
134 ;;
135 *-*-*-*)
136 basic_machine=$field1-$field2
137 basic_os=$field3-$field4
@@ -138,14 +139,25 @@
139 *-*-*)
140 # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
141 # parts
142 maybe_os=$field2-$field3
143 case $maybe_os in
144 cloudabi*-eabi* \
145 | kfreebsd*-gnu* \
146 | knetbsd*-gnu* \
147 | kopensolaris*-gnu* \
148 | linux-* \
149 | managarm-* \
150 | netbsd*-eabi* \
151 | netbsd*-gnu* \
152 | nto-qnx* \
153 | os2-emx* \
154 | rtmk-nova* \
155 | storm-chaos* \
156 | uclinux-gnu* \
157 | uclinux-uclibc* \
158 | windows-* )
159 basic_machine=$field1
160 basic_os=$maybe_os
161 ;;
162 android-linux)
163 basic_machine=$field1-unknown
@@ -156,37 +168,105 @@
168 basic_os=$field3
169 ;;
170 esac
171 ;;
172 *-*)
 
173 case $field1-$field2 in
174 # Shorthands that happen to contain a single dash
175 convex-c[12] | convex-c3[248])
176 basic_machine=$field2-convex
177 basic_os=
178 ;;
179 decstation-3100)
180 basic_machine=mips-dec
181 basic_os=
182 ;;
183 *-*)
184 # Second component is usually, but not always the OS
185 case $field2 in
186 # Do not treat sunos as a manufacturer
187 sun*os*)
188 basic_machine=$field1
189 basic_os=$field2
190 ;;
191 # Manufacturers
192 3100* \
193 | 32* \
194 | 3300* \
195 | 3600* \
196 | 7300* \
197 | acorn \
198 | altos* \
199 | apollo \
200 | apple \
201 | atari \
202 | att* \
203 | axis \
204 | be \
205 | bull \
206 | cbm \
207 | ccur \
208 | cisco \
209 | commodore \
210 | convergent* \
211 | convex* \
212 | cray \
213 | crds \
214 | dec* \
215 | delta* \
216 | dg \
217 | digital \
218 | dolphin \
219 | encore* \
220 | gould \
221 | harris \
222 | highlevel \
223 | hitachi* \
224 | hp \
225 | ibm* \
226 | intergraph \
227 | isi* \
228 | knuth \
229 | masscomp \
230 | microblaze* \
231 | mips* \
232 | motorola* \
233 | ncr* \
234 | news \
235 | next \
236 | ns \
237 | oki \
238 | omron* \
239 | pc533* \
240 | rebel \
241 | rom68k \
242 | rombug \
243 | semi \
244 | sequent* \
245 | siemens \
246 | sgi* \
247 | siemens \
248 | sim \
249 | sni \
250 | sony* \
251 | stratus \
252 | sun \
253 | sun[234]* \
254 | tektronix \
255 | tti* \
256 | ultra \
257 | unicom* \
258 | wec \
259 | winbond \
260 | wrs)
261 basic_machine=$field1-$field2
262 basic_os=
263 ;;
264 zephyr*)
265 basic_machine=$field1-unknown
266 basic_os=$field2
267 ;;
268 *)
269 basic_machine=$field1
270 basic_os=$field2
271 ;;
272 esac
@@ -263,30 +343,10 @@
343 ;;
344 cegcc)
345 basic_machine=arm-unknown
346 basic_os=cegcc
347 ;;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348 cray)
349 basic_machine=j90-cray
350 basic_os=unicos
351 ;;
352 crds | unos)
@@ -705,13 +765,21 @@
765 decsystem20* | dec20*)
766 cpu=pdp10
767 vendor=dec
768 basic_os=tops20
769 ;;
770 delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300)
 
771 cpu=m68k
772 vendor=motorola
773 ;;
774 # This used to be dpx2*, but that gets the RS6000-based
775 # DPX/20 and the x86-based DPX/2-100 wrong. See
776 # https://oldskool.silicium.org/stations/bull_dpx20.htm
777 # https://www.feb-patrimoine.com/english/bull_dpx2.htm
778 # https://www.feb-patrimoine.com/english/unix_and_bull.htm
779 dpx2 | dpx2[23]00 | dpx2[23]xx)
780 cpu=m68k
781 vendor=bull
782 ;;
783 dpx2100 | dpx21xx)
784 cpu=i386
785 vendor=bull
@@ -718,6 +786,9 @@
786 ;;
787 dpx20)
788 cpu=rs6000
789 vendor=bull
790 ;;
791 encore | umax | mmax)
792 cpu=ns32k
793 vendor=encore
794 ;;
@@ -828,22 +899,10 @@
899 basic_os=newsos
900 ;;
901 next | m*-next)
902 cpu=m68k
903 vendor=next
 
 
 
 
 
 
 
 
 
 
 
 
904 ;;
905 np1)
906 cpu=np1
907 vendor=gould
908 ;;
@@ -928,16 +987,17 @@
987 cpu=sparc
988 vendor=`echo "$basic_machine" | sed 's/-.*//'`
989 ;;
990
991 *-*)
992 saved_IFS=$IFS
993 IFS="-" read cpu vendor <<EOF
994 $basic_machine
995 EOF
996 IFS=$saved_IFS
997 ;;
998 # We use 'pc' rather than 'unknown'
999 # because (1) that's what they normally are, and
1000 # (2) the word "unknown" tends to confuse beginning users.
1001 i*86 | x86_64)
1002 cpu=$basic_machine
1003 vendor=pc
@@ -961,19 +1021,23 @@
1021
1022 unset -v basic_machine
1023
1024 # Decode basic machines in the full and proper CPU-Company form.
1025 case $cpu-$vendor in
1026 # Here we handle the default manufacturer of certain CPU types in canonical form.
1027 # It is in some cases the only manufacturer, in others, it is the most popular.
1028 c[12]-convex | c[12]-unknown | c3[248]-convex | c3[248]-unknown)
1029 vendor=convex
1030 basic_os=${basic_os:-bsd}
1031 ;;
1032 craynv-unknown)
1033 vendor=cray
1034 basic_os=${basic_os:-unicosmp}
1035 ;;
1036 c90-unknown | c90-cray)
1037 vendor=cray
1038 basic_os=${basic_os:-unicos}
1039 ;;
1040 fx80-unknown)
1041 vendor=alliant
1042 ;;
1043 romp-unknown)
@@ -1010,23 +1074,46 @@
1074 cpu=xps100
1075 vendor=honeywell
1076 ;;
1077
1078 # Here we normalize CPU types with a missing or matching vendor
1079 armh-unknown | armh-alt)
1080 cpu=armv7l
1081 vendor=alt
1082 basic_os=${basic_os:-linux-gnueabihf}
1083 ;;
1084
1085 # Normalized CPU+vendor pairs that imply an OS, if not otherwise specified
1086 m68k-isi)
1087 basic_os=${basic_os:-sysv}
1088 ;;
1089 m68k-sony)
1090 basic_os=${basic_os:-newsos}
1091 ;;
1092 m68k-tektronix)
1093 basic_os=${basic_os:-bsd}
1094 ;;
1095 m88k-harris)
1096 basic_os=${basic_os:-sysv3}
1097 ;;
1098 i386-bull | m68k-bull)
1099 basic_os=${basic_os:-sysv3}
1100 ;;
1101 rs6000-bull)
1102 basic_os=${basic_os:-bosx}
1103 ;;
1104 mips-sni)
1105 basic_os=${basic_os:-sysv4}
1106 ;;
1107
1108 # Here we normalize CPU types irrespective of the vendor
1109 amd64-*)
1110 cpu=x86_64
1111 ;;
1112 blackfin-*)
1113 cpu=bfin
1114 basic_os=${basic_os:-linux}
1115 ;;
1116 c54x-*)
1117 cpu=tic54x
1118 ;;
1119 c55x-*)
@@ -1045,37 +1132,34 @@
1132 ms1-*)
1133 cpu=mt
1134 ;;
1135 m68knommu-*)
1136 cpu=m68k
1137 basic_os=${basic_os:-linux}
1138 ;;
1139 m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
1140 cpu=s12z
1141 ;;
1142 openrisc-*)
1143 cpu=or32
1144 ;;
1145 parisc-*)
1146 cpu=hppa
1147 basic_os=${basic_os:-linux}
1148 ;;
1149 pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
1150 cpu=i586
1151 ;;
1152 pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
1153 cpu=i686
1154 ;;
1155 pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
1156 cpu=i686
1157 ;;
1158 pentium4-*)
1159 cpu=i786
1160 ;;
 
 
 
1161 ppc-* | ppcbe-*)
1162 cpu=powerpc
1163 ;;
1164 ppcle-* | powerpclittle-*)
1165 cpu=powerpcle
@@ -1105,17 +1189,14 @@
1189 cpu=mipstx39
1190 ;;
1191 tx39el-*)
1192 cpu=mipstx39el
1193 ;;
 
 
 
1194 xscale-* | xscalee[bl]-*)
1195 cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
1196 ;;
1197 arm64-* | aarch64le-*)
1198 cpu=aarch64
1199 ;;
1200
1201 # Recognize the canonical CPU Types that limit and/or modify the
1202 # company names they are paired with.
@@ -1163,118 +1244,235 @@
1244
1245 *)
1246 # Recognize the canonical CPU types that are allowed with any
1247 # company name.
1248 case $cpu in
1249 1750a \
1250 | 580 \
1251 | [cjt]90 \
1252 | a29k \
1253 | aarch64 \
1254 | aarch64_be \
1255 | aarch64c \
1256 | abacus \
1257 | alpha \
1258 | alpha64 \
1259 | alpha64ev56 \
1260 | alpha64ev6[78] \
1261 | alpha64ev[4-8] \
1262 | alpha64pca5[67] \
1263 | alphaev56 \
1264 | alphaev6[78] \
1265 | alphaev[4-8] \
1266 | alphapca5[67] \
1267 | am33_2.0 \
1268 | amdgcn \
1269 | arc \
1270 | arc32 \
1271 | arc64 \
1272 | arceb \
1273 | arm \
1274 | arm64e \
1275 | arm64ec \
1276 | arm[lb]e \
1277 | arme[lb] \
1278 | armv* \
1279 | asmjs \
1280 | avr \
1281 | avr32 \
1282 | ba \
1283 | be32 \
1284 | be64 \
1285 | bfin \
1286 | bpf \
1287 | bs2000 \
1288 | c30 \
1289 | c4x \
1290 | c8051 \
1291 | c[123]* \
1292 | clipper \
1293 | craynv \
1294 | csky \
1295 | cydra \
1296 | d10v \
1297 | d30v \
1298 | dlx \
1299 | dsp16xx \
1300 | e2k \
1301 | elxsi \
1302 | epiphany \
1303 | f30[01] \
1304 | f700 \
1305 | fido \
1306 | fr30 \
1307 | frv \
1308 | ft32 \
1309 | fx80 \
1310 | h8300 \
1311 | h8500 \
1312 | hexagon \
1313 | hppa \
1314 | hppa1.[01] \
1315 | hppa2.0 \
1316 | hppa2.0[nw] \
1317 | hppa64 \
1318 | i*86 \
1319 | i370 \
1320 | i860 \
1321 | i960 \
1322 | ia16 \
1323 | ia64 \
1324 | ip2k \
1325 | iq2000 \
1326 | javascript \
1327 | k1om \
1328 | kvx \
1329 | le32 \
1330 | le64 \
1331 | lm32 \
1332 | loongarch32 \
1333 | loongarch64 \
1334 | m32c \
1335 | m32r \
1336 | m32rle \
1337 | m5200 \
1338 | m68000 \
1339 | m680[012346]0 \
1340 | m6811 \
1341 | m6812 \
1342 | m68360 \
1343 | m683?2 \
1344 | m68hc11 \
1345 | m68hc12 \
1346 | m68hcs12x \
1347 | m68k \
1348 | m88110 \
1349 | m88k \
1350 | maxq \
1351 | mb \
1352 | mcore \
1353 | mep \
1354 | metag \
1355 | microblaze \
1356 | microblazeel \
1357 | mips* \
 
 
 
 
 
1358 | mmix \
1359 | mn10200 \
1360 | mn10300 \
1361 | moxie \
 
1362 | msp430 \
1363 | mt \
1364 | nanomips* \
1365 | nds32 \
1366 | nds32be \
1367 | nds32le \
1368 | nfp \
1369 | nios \
1370 | nios2 \
1371 | nios2eb \
1372 | nios2el \
1373 | none \
1374 | np1 \
1375 | ns16k \
1376 | ns32k \
1377 | nvptx \
1378 | open8 \
1379 | or1k* \
1380 | or32 \
1381 | orion \
1382 | pdp10 \
1383 | pdp11 \
1384 | picochip \
1385 | pj \
1386 | pjl \
1387 | pn \
1388 | power \
1389 | powerpc \
1390 | powerpc64 \
1391 | powerpc64le \
1392 | powerpcle \
1393 | powerpcspe \
1394 | pru \
1395 | pyramid \
1396 | riscv \
1397 | riscv32 \
1398 | riscv32be \
1399 | riscv64 \
1400 | riscv64be \
1401 | rl78 \
1402 | romp \
1403 | rs6000 \
1404 | rx \
1405 | s390 \
1406 | s390x \
1407 | score \
1408 | sh \
1409 | sh64 \
1410 | sh64le \
1411 | sh[12345][lb]e \
1412 | sh[1234] \
1413 | sh[1234]e[lb] \
1414 | sh[23]e \
1415 | sh[23]ele \
1416 | sh[24]a \
1417 | sh[24]ae[lb] \
1418 | sh[lb]e \
1419 | she[lb] \
1420 | shl \
1421 | sparc \
1422 | sparc64 \
1423 | sparc64b \
1424 | sparc64v \
1425 | sparc86x \
1426 | sparclet \
1427 | sparclite \
1428 | sparcv8 \
1429 | sparcv9 \
1430 | sparcv9b \
1431 | sparcv9v \
1432 | spu \
1433 | sv1 \
1434 | sx* \
1435 | tahoe \
1436 | thumbv7* \
1437 | tic30 \
1438 | tic4x \
1439 | tic54x \
1440 | tic55x \
1441 | tic6x \
1442 | tic80 \
1443 | tron \
1444 | ubicom32 \
1445 | v70 \
1446 | v810 \
1447 | v850 \
1448 | v850e \
1449 | v850e1 \
1450 | v850e2 \
1451 | v850e2v3 \
1452 | v850es \
1453 | vax \
1454 | vc4 \
1455 | visium \
1456 | w65 \
1457 | wasm32 \
1458 | wasm64 \
1459 | we32k \
1460 | x86 \
1461 | x86_64 \
1462 | xc16x \
1463 | xgate \
1464 | xps100 \
1465 | xstormy16 \
1466 | xtensa* \
1467 | ymp \
1468 | z80 \
1469 | z8k)
1470 ;;
1471
1472 *)
1473 echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
1474 exit 1
1475 ;;
1476 esac
1477 ;;
1478 esac
@@ -1291,15 +1489,16 @@
1489 ;;
1490 esac
1491
1492 # Decode manufacturer-specific aliases for certain operating systems.
1493
1494 if test x"$basic_os" != x
1495 then
1496
1497 # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
1498 # set os.
1499 obj=
1500 case $basic_os in
1501 gnu/linux*)
1502 kernel=linux
1503 os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
1504 ;;
@@ -1310,14 +1509,15 @@
1509 nto-qnx*)
1510 kernel=nto
1511 os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
1512 ;;
1513 *-*)
1514 saved_IFS=$IFS
1515 IFS="-" read kernel os <<EOF
1516 $basic_os
1517 EOF
1518 IFS=$saved_IFS
1519 ;;
1520 # Default OS when just kernel was specified
1521 nto*)
1522 kernel=nto
1523 os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
@@ -1324,10 +1524,14 @@
1524 ;;
1525 linux*)
1526 kernel=linux
1527 os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
1528 ;;
1529 managarm*)
1530 kernel=managarm
1531 os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
1532 ;;
1533 *)
1534 kernel=
1535 os=$basic_os
1536 ;;
1537 esac
@@ -1350,10 +1554,27 @@
1554 solaris)
1555 os=solaris2
1556 ;;
1557 unixware*)
1558 os=sysv4.2uw
1559 ;;
1560 # The marketing names for NeXT's operating systems were
1561 # NeXTSTEP, NeXTSTEP 2, OpenSTEP 3, OpenSTEP 4. 'openstep' is
1562 # mapped to 'openstep3', but 'openstep1' and 'openstep2' are
1563 # mapped to 'nextstep' and 'nextstep2', consistent with the
1564 # treatment of SunOS/Solaris.
1565 ns | ns1 | nextstep | nextstep1 | openstep1)
1566 os=nextstep
1567 ;;
1568 ns2 | nextstep2 | openstep2)
1569 os=nextstep2
1570 ;;
1571 ns3 | nextstep3 | openstep | openstep3)
1572 os=openstep3
1573 ;;
1574 ns4 | nextstep4 | openstep4)
1575 os=openstep4
1576 ;;
1577 # es1800 is here to avoid being matched by es* (a different OS)
1578 es1800*)
1579 os=ose
1580 ;;
@@ -1421,10 +1642,11 @@
1642 wince*)
1643 os=wince
1644 ;;
1645 utek*)
1646 os=bsd
1647 vendor=`echo "$vendor" | sed -e 's|^unknown$|tektronix|'`
1648 ;;
1649 dynix*)
1650 os=bsd
1651 ;;
1652 acis*)
@@ -1437,25 +1659,29 @@
1659 os=syllable
1660 ;;
1661 386bsd)
1662 os=bsd
1663 ;;
1664 ctix*)
1665 os=sysv
1666 vendor=`echo "$vendor" | sed -e 's|^unknown$|convergent|'`
1667 ;;
1668 uts*)
1669 os=sysv
1670 ;;
1671 nova*)
1672 kernel=rtmk
1673 os=nova
 
 
1674 ;;
1675 # Preserve the version number of sinix5.
1676 sinix5.*)
1677 os=`echo "$os" | sed -e 's|sinix|sysv|'`
1678 vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
1679 ;;
1680 sinix*)
1681 os=sysv4
1682 vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
1683 ;;
1684 tpf*)
1685 os=tpf
1686 ;;
1687 triton*)
@@ -1489,13 +1715,19 @@
1715 case $cpu in
1716 arm*)
1717 os=eabi
1718 ;;
1719 *)
1720 os=
1721 obj=elf
1722 ;;
1723 esac
1724 ;;
1725 aout* | coff* | elf* | pe*)
1726 # These are machine code file formats, not OSes
1727 obj=$os
1728 os=
1729 ;;
1730 *)
1731 # No normalization, but not necessarily accepted, that comes below.
1732 ;;
1733 esac
@@ -1511,47 +1743,57 @@
1743 # that MANUFACTURER isn't an operating system. Otherwise, code above
1744 # will signal an error saying that MANUFACTURER isn't an operating
1745 # system, and we'll never get to this point.
1746
1747 kernel=
1748 obj=
1749 case $cpu-$vendor in
1750 score-*)
1751 os=
1752 obj=elf
1753 ;;
1754 spu-*)
1755 os=
1756 obj=elf
1757 ;;
1758 *-acorn)
1759 os=riscix1.2
1760 ;;
1761 arm*-rebel)
1762 kernel=linux
1763 os=gnu
1764 ;;
1765 arm*-semi)
1766 os=
1767 obj=aout
1768 ;;
1769 c4x-* | tic4x-*)
1770 os=
1771 obj=coff
1772 ;;
1773 c8051-*)
1774 os=
1775 obj=elf
1776 ;;
1777 clipper-intergraph)
1778 os=clix
1779 ;;
1780 hexagon-*)
1781 os=
1782 obj=elf
1783 ;;
1784 tic54x-*)
1785 os=
1786 obj=coff
1787 ;;
1788 tic55x-*)
1789 os=
1790 obj=coff
1791 ;;
1792 tic6x-*)
1793 os=
1794 obj=coff
1795 ;;
1796 # This must come before the *-dec entry.
1797 pdp10-*)
1798 os=tops20
1799 ;;
@@ -1569,32 +1811,47 @@
1811 ;;
1812 m68000-sun)
1813 os=sunos3
1814 ;;
1815 m68*-cisco)
1816 os=
1817 obj=aout
1818 ;;
1819 mep-*)
1820 os=
1821 obj=elf
1822 ;;
1823 # The -sgi and -siemens entries must be before the mips- entry
1824 # or we get the wrong os.
1825 *-sgi)
1826 os=irix
1827 ;;
1828 *-siemens)
1829 os=sysv4
1830 ;;
1831 mips*-cisco)
1832 os=
1833 obj=elf
1834 ;;
1835 mips*-*|nanomips*-*)
1836 os=
1837 obj=elf
1838 ;;
1839 or32-*)
1840 os=
1841 obj=coff
1842 ;;
1843 # This must be before the sparc-* entry or we get the wrong os.
1844 *-tti)
1845 os=sysv3
1846 ;;
1847 sparc-* | *-sun)
1848 os=sunos4.1.1
1849 ;;
1850 pru-*)
1851 os=
1852 obj=elf
1853 ;;
1854 *-be)
1855 os=beos
1856 ;;
1857 *-ibm)
@@ -1614,11 +1871,11 @@
1871 ;;
1872 *-hp)
1873 os=hpux
1874 ;;
1875 *-hitachi)
1876 os=hiuxwe2
1877 ;;
1878 i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
1879 os=sysv
1880 ;;
1881 *-cbm)
@@ -1658,27 +1915,23 @@
1915 os=bsd
1916 ;;
1917 *-encore)
1918 os=bsd
1919 ;;
 
 
 
 
 
 
1920 *-masscomp)
1921 os=rtu
1922 ;;
1923 f30[01]-fujitsu | f700-fujitsu)
1924 os=uxpv
1925 ;;
1926 *-rom68k)
1927 os=
1928 obj=coff
1929 ;;
1930 *-*bug)
1931 os=
1932 obj=coff
1933 ;;
1934 *-apple)
1935 os=macos
1936 ;;
1937 *-atari*)
@@ -1692,96 +1945,324 @@
1945 ;;
1946 esac
1947
1948 fi
1949
1950 # Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
1951
1952 case $os in
1953 # Sometimes we do "kernel-libc", so those need to count as OSes.
1954 llvm* | musl* | newlib* | relibc* | uclibc*)
1955 ;;
1956 # Likewise for "kernel-abi"
1957 eabi* | gnueabi*)
1958 ;;
1959 # VxWorks passes extra cpu info in the 4th filed.
1960 simlinux | simwindows | spe)
1961 ;;
1962 # See `case $cpu-$os` validation below
1963 ghcjs)
1964 ;;
1965 # Now accept the basic system types.
 
1966 # Each alternative MUST end in a * to match a version number.
1967 abug \
1968 | aix* \
1969 | amdhsa* \
1970 | amigados* \
1971 | amigaos* \
1972 | android* \
1973 | aof* \
1974 | aos* \
1975 | aros* \
1976 | atheos* \
1977 | auroraux* \
1978 | aux* \
1979 | beos* \
1980 | bitrig* \
1981 | bme* \
1982 | bosx* \
1983 | bsd* \
1984 | cegcc* \
1985 | chorusos* \
1986 | chorusrdb* \
1987 | clix* \
1988 | cloudabi* \
1989 | cnk* \
1990 | conix* \
1991 | cos* \
1992 | cxux* \
1993 | cygwin* \
1994 | darwin* \
1995 | dgux* \
1996 | dicos* \
1997 | dnix* \
1998 | domain* \
1999 | dragonfly* \
2000 | drops* \
2001 | ebmon* \
2002 | ecoff* \
2003 | ekkobsd* \
2004 | emscripten* \
2005 | emx* \
2006 | es* \
2007 | fiwix* \
2008 | freebsd* \
2009 | fuchsia* \
2010 | genix* \
2011 | genode* \
2012 | glidix* \
2013 | gnu* \
2014 | go32* \
2015 | haiku* \
2016 | hcos* \
2017 | hiux* \
2018 | hms* \
2019 | hpux* \
2020 | ieee* \
2021 | interix* \
2022 | ios* \
2023 | iris* \
2024 | irix* \
2025 | ironclad* \
2026 | isc* \
2027 | its* \
2028 | l4re* \
2029 | libertybsd* \
2030 | lites* \
2031 | lnews* \
2032 | luna* \
2033 | lynxos* \
2034 | mach* \
2035 | macos* \
2036 | magic* \
2037 | mbr* \
2038 | midipix* \
2039 | midnightbsd* \
2040 | mingw32* \
2041 | mingw64* \
2042 | minix* \
2043 | mint* \
2044 | mirbsd* \
2045 | mks* \
2046 | mlibc* \
2047 | mmixware* \
2048 | mon960* \
2049 | morphos* \
2050 | moss* \
2051 | moxiebox* \
2052 | mpeix* \
2053 | mpw* \
2054 | msdos* \
2055 | msys* \
2056 | mvs* \
2057 | nacl* \
2058 | netbsd* \
2059 | netware* \
2060 | newsos* \
2061 | nextstep* \
2062 | nindy* \
2063 | nonstopux* \
2064 | nova* \
2065 | nsk* \
2066 | nucleus* \
2067 | nx6 \
2068 | nx7 \
2069 | oabi* \
2070 | ohos* \
2071 | onefs* \
2072 | openbsd* \
2073 | openedition* \
2074 | openstep* \
2075 | os108* \
2076 | os2* \
2077 | os400* \
2078 | os68k* \
2079 | os9* \
2080 | ose* \
2081 | osf* \
2082 | oskit* \
2083 | osx* \
2084 | palmos* \
2085 | phoenix* \
2086 | plan9* \
2087 | powermax* \
2088 | powerunix* \
2089 | proelf* \
2090 | psos* \
2091 | psp* \
2092 | ptx* \
2093 | pw32* \
2094 | qnx* \
2095 | rdos* \
2096 | redox* \
2097 | rhapsody* \
2098 | riscix* \
2099 | riscos* \
2100 | rtems* \
2101 | rtmk* \
2102 | rtu* \
2103 | scout* \
2104 | secbsd* \
2105 | sei* \
2106 | serenity* \
2107 | sim* \
2108 | skyos* \
2109 | solaris* \
2110 | solidbsd* \
2111 | sortix* \
2112 | storm-chaos* \
2113 | sunos \
2114 | sunos[34]* \
2115 | superux* \
2116 | syllable* \
2117 | sym* \
2118 | sysv* \
2119 | tenex* \
2120 | tirtos* \
2121 | toppers* \
2122 | tops10* \
2123 | tops20* \
2124 | tpf* \
2125 | tvos* \
2126 | twizzler* \
2127 | uclinux* \
2128 | udi* \
2129 | udk* \
2130 | ultrix* \
2131 | unicos* \
2132 | uniplus* \
2133 | unleashed* \
2134 | unos* \
2135 | uwin* \
2136 | uxpv* \
2137 | v88r* \
2138 |*vms* \
2139 | vos* \
2140 | vsta* \
2141 | vxsim* \
2142 | vxworks* \
2143 | wasi* \
2144 | watchos* \
2145 | wince* \
2146 | windiss* \
2147 | windows* \
2148 | winnt* \
2149 | xenix* \
2150 | xray* \
2151 | zephyr* \
2152 | zvmoe* )
2153 ;;
2154 # This one is extra strict with allowed versions
2155 sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
2156 # Don't forget version if it is 3.2v4 or newer.
2157 ;;
2158 # This refers to builds using the UEFI calling convention
2159 # (which depends on the architecture) and PE file format.
2160 # Note that this is both a different calling convention and
2161 # different file format than that of GNU-EFI
2162 # (x86_64-w64-mingw32).
2163 uefi)
2164 ;;
2165 none)
2166 ;;
2167 kernel* | msvc* )
2168 # Restricted further below
2169 ;;
2170 '')
2171 if test x"$obj" = x
2172 then
2173 echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
2174 fi
2175 ;;
2176 *)
2177 echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
2178 exit 1
2179 ;;
2180 esac
2181
2182 case $obj in
2183 aout* | coff* | elf* | pe*)
2184 ;;
2185 '')
2186 # empty is fine
2187 ;;
2188 *)
2189 echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
2190 exit 1
2191 ;;
2192 esac
2193
2194 # Here we handle the constraint that a (synthetic) cpu and os are
2195 # valid only in combination with each other and nowhere else.
2196 case $cpu-$os in
2197 # The "javascript-unknown-ghcjs" triple is used by GHC; we
2198 # accept it here in order to tolerate that, but reject any
2199 # variations.
2200 javascript-ghcjs)
2201 ;;
2202 javascript-* | *-ghcjs)
2203 echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
2204 exit 1
2205 ;;
2206 esac
2207
2208 # As a final step for OS-related things, validate the OS-kernel combination
2209 # (given a valid OS), if there is a kernel.
2210 case $kernel-$os-$obj in
2211 linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
2212 | linux-mlibc*- | linux-musl*- | linux-newlib*- \
2213 | linux-relibc*- | linux-uclibc*- | linux-ohos*- )
2214 ;;
2215 uclinux-uclibc*- | uclinux-gnu*- )
2216 ;;
2217 managarm-mlibc*- | managarm-kernel*- )
2218 ;;
2219 windows*-msvc*-)
2220 ;;
2221 -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
2222 | -uclibc*- )
2223 # These are just libc implementations, not actual OSes, and thus
2224 # require a kernel.
2225 echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
2226 exit 1
2227 ;;
2228 -kernel*- )
2229 echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
2230 exit 1
2231 ;;
2232 *-kernel*- )
2233 echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
2234 exit 1
2235 ;;
2236 *-msvc*- )
2237 echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
2238 exit 1
2239 ;;
2240 kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-)
2241 ;;
2242 vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
2243 ;;
2244 nto-qnx*-)
2245 ;;
2246 os2-emx-)
2247 ;;
2248 rtmk-nova-)
2249 ;;
2250 *-eabi*- | *-gnueabi*-)
2251 ;;
2252 none--*)
2253 # None (no kernel, i.e. freestanding / bare metal),
2254 # can be paired with an machine code file format
2255 ;;
2256 -*-)
2257 # Blank kernel with real OS is always fine.
2258 ;;
2259 --*)
2260 # Blank kernel and OS with real machine code file format is always fine.
2261 ;;
2262 *-*-*)
2263 echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
2264 exit 1
2265 ;;
2266 esac
2267
2268 # Here we handle the case where we know the os, and the CPU type, but not the
@@ -1790,11 +2271,11 @@
2271 unknown)
2272 case $cpu-$os in
2273 *-riscix*)
2274 vendor=acorn
2275 ;;
2276 *-sunos* | *-solaris*)
2277 vendor=sun
2278 ;;
2279 *-cnk* | *-aix*)
2280 vendor=ibm
2281 ;;
@@ -1860,14 +2341,14 @@
2341 ;;
2342 esac
2343 ;;
2344 esac
2345
2346 echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
2347 exit
2348
2349 # Local variables:
2350 # eval: (add-hook 'before-save-hook 'time-stamp)
2351 # time-stamp-start: "timestamp='"
2352 # time-stamp-format: "%:y-%02m-%02d"
2353 # time-stamp-end: "'"
2354 # End:
2355
--- autosetup/autosetup-find-tclsh
+++ autosetup/autosetup-find-tclsh
@@ -3,14 +3,14 @@
33
# If not found, builds a bootstrap jimsh in current dir from source
44
# Prefer $autosetup_tclsh if is set in the environment (unless ./jimsh0 works)
55
# If an argument is given, use that as the test instead of autosetup-test-tclsh
66
d="`dirname "$0"`"
77
for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
8
- { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
8
+ { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
99
done
1010
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
1111
for cc in ${CC_FOR_BUILD:-cc} gcc; do
12
- { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev/null || continue
13
- ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
12
+ { $cc -o jimsh0 "$d/jimsh0.c"; } >/dev/null 2>&1 || continue
13
+ ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
1414
done
1515
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
1616
echo false
1717
--- autosetup/autosetup-find-tclsh
+++ autosetup/autosetup-find-tclsh
@@ -3,14 +3,14 @@
3 # If not found, builds a bootstrap jimsh in current dir from source
4 # Prefer $autosetup_tclsh if is set in the environment (unless ./jimsh0 works)
5 # If an argument is given, use that as the test instead of autosetup-test-tclsh
6 d="`dirname "$0"`"
7 for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
8 { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
9 done
10 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
11 for cc in ${CC_FOR_BUILD:-cc} gcc; do
12 { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev/null || continue
13 ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
14 done
15 echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
16 echo false
17
--- autosetup/autosetup-find-tclsh
+++ autosetup/autosetup-find-tclsh
@@ -3,14 +3,14 @@
3 # If not found, builds a bootstrap jimsh in current dir from source
4 # Prefer $autosetup_tclsh if is set in the environment (unless ./jimsh0 works)
5 # If an argument is given, use that as the test instead of autosetup-test-tclsh
6 d="`dirname "$0"`"
7 for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
8 { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
9 done
10 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
11 for cc in ${CC_FOR_BUILD:-cc} gcc; do
12 { $cc -o jimsh0 "$d/jimsh0.c"; } >/dev/null 2>&1 || continue
13 ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
14 done
15 echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
16 echo false
17
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -3,11 +3,11 @@
33
44
# @synopsis:
55
#
66
# The 'cc' module supports checking various 'features' of the C or C++
77
# compiler/linker environment. Common commands are 'cc-check-includes',
8
-# 'cc-check-types', 'cc-check-functions', 'cc-with', 'make-config-header' and 'make-template'.
8
+# 'cc-check-types', 'cc-check-functions', 'cc-with' and 'make-config-header'
99
#
1010
# The following environment variables are used if set:
1111
#
1212
## CC - C compiler
1313
## CXX - C++ compiler
1414
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -3,11 +3,11 @@
3
4 # @synopsis:
5 #
6 # The 'cc' module supports checking various 'features' of the C or C++
7 # compiler/linker environment. Common commands are 'cc-check-includes',
8 # 'cc-check-types', 'cc-check-functions', 'cc-with', 'make-config-header' and 'make-template'.
9 #
10 # The following environment variables are used if set:
11 #
12 ## CC - C compiler
13 ## CXX - C++ compiler
14
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -3,11 +3,11 @@
3
4 # @synopsis:
5 #
6 # The 'cc' module supports checking various 'features' of the C or C++
7 # compiler/linker environment. Common commands are 'cc-check-includes',
8 # 'cc-check-types', 'cc-check-functions', 'cc-with' and 'make-config-header'
9 #
10 # The following environment variables are used if set:
11 #
12 ## CC - C compiler
13 ## CXX - C++ compiler
14
+3370 -1991
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -120,13 +120,10 @@
120120
#include <math.h>
121121
#include "sqlite3.h"
122122
typedef sqlite3_int64 i64;
123123
typedef sqlite3_uint64 u64;
124124
typedef unsigned char u8;
125
-#if SQLITE_USER_AUTHENTICATION
126
-# include "sqlite3userauth.h"
127
-#endif
128125
#include <ctype.h>
129126
#include <stdarg.h>
130127
131128
#if !defined(_WIN32) && !defined(WIN32)
132129
# include <signal.h>
@@ -208,12 +205,10 @@
208205
# define unlink _unlink
209206
# endif
210207
# ifndef strdup
211208
# define strdup _strdup
212209
# endif
213
-# undef popen
214
-# define popen _popen
215210
# undef pclose
216211
# define pclose _pclose
217212
# endif
218213
#else
219214
/* Make sure isatty() has a prototype. */
@@ -253,10 +248,370 @@
253248
/* string conversion routines only needed on Win32 */
254249
extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
255250
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
256251
#endif
257252
253
+/************************* Begin ../ext/misc/sqlite3_stdio.h ******************/
254
+/*
255
+** 2024-09-24
256
+**
257
+** The author disclaims copyright to this source code. In place of
258
+** a legal notice, here is a blessing:
259
+**
260
+** May you do good and not evil.
261
+** May you find forgiveness for yourself and forgive others.
262
+** May you share freely, never taking more than you give.
263
+**
264
+*************************************************************************
265
+**
266
+** This header file contains definitions of interfaces that provide
267
+** cross-platform I/O for UTF-8 content.
268
+**
269
+** On most platforms, the interfaces definitions in this file are
270
+** just #defines. For example sqlite3_fopen() is a macro that resolves
271
+** to the standard fopen() in the C-library.
272
+**
273
+** But Windows does not have a standard C-library, at least not one that
274
+** can handle UTF-8. So for windows build, the interfaces resolve to new
275
+** C-language routines contained in the separate sqlite3_stdio.c source file.
276
+**
277
+** So on all non-Windows platforms, simply #include this header file and
278
+** use the interfaces defined herein. Then to run your application on Windows,
279
+** also link in the accompanying sqlite3_stdio.c source file when compiling
280
+** to get compatible interfaces.
281
+*/
282
+#ifndef _SQLITE3_STDIO_H_
283
+#define _SQLITE3_STDIO_H_ 1
284
+#ifdef _WIN32
285
+/**** Definitions For Windows ****/
286
+#include <stdio.h>
287
+#include <windows.h>
288
+
289
+FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
290
+FILE *sqlite3_popen(const char *zCommand, const char *type);
291
+char *sqlite3_fgets(char *s, int size, FILE *stream);
292
+int sqlite3_fputs(const char *s, FILE *stream);
293
+int sqlite3_fprintf(FILE *stream, const char *format, ...);
294
+void sqlite3_fsetmode(FILE *stream, int mode);
295
+
296
+
297
+#else
298
+/**** Definitions For All Other Platforms ****/
299
+#include <stdio.h>
300
+#define sqlite3_fopen fopen
301
+#define sqlite3_popen popen
302
+#define sqlite3_fgets fgets
303
+#define sqlite3_fputs fputs
304
+#define sqlite3_fprintf fprintf
305
+#define sqlite3_fsetmode(F,X) /*no-op*/
306
+
307
+#endif
308
+#endif /* _SQLITE3_STDIO_H_ */
309
+
310
+/************************* End ../ext/misc/sqlite3_stdio.h ********************/
311
+/************************* Begin ../ext/misc/sqlite3_stdio.c ******************/
312
+/*
313
+** 2024-09-24
314
+**
315
+** The author disclaims copyright to this source code. In place of
316
+** a legal notice, here is a blessing:
317
+**
318
+** May you do good and not evil.
319
+** May you find forgiveness for yourself and forgive others.
320
+** May you share freely, never taking more than you give.
321
+**
322
+*************************************************************************
323
+**
324
+** Implementation of standard I/O interfaces for UTF-8 that are missing
325
+** on Windows.
326
+*/
327
+#ifdef _WIN32 /* This file is a no-op on all platforms except Windows */
328
+#ifndef _SQLITE3_STDIO_H_
329
+/* #include "sqlite3_stdio.h" */
330
+#endif
331
+#undef WIN32_LEAN_AND_MEAN
332
+#define WIN32_LEAN_AND_MEAN
333
+#include <windows.h>
334
+#include <stdlib.h>
335
+#include <string.h>
336
+#include <stdio.h>
337
+#include <assert.h>
338
+/* #include "sqlite3.h" */
339
+#include <ctype.h>
340
+#include <stdarg.h>
341
+#include <io.h>
342
+#include <fcntl.h>
343
+
344
+/*
345
+** If the SQLITE_U8TEXT_ONLY option is defined, then use O_U8TEXT
346
+** when appropriate on all output. (Sometimes use O_BINARY when
347
+** rendering ASCII text in cases where NL-to-CRLF expansion would
348
+** not be correct.)
349
+**
350
+** If the SQLITE_U8TEXT_STDIO option is defined, then use O_U8TEXT
351
+** when appropriate when writing to stdout or stderr. Use O_BINARY
352
+** or O_TEXT (depending on things like the .mode and the .crlf setting
353
+** in the CLI, or other context clues in other applications) for all
354
+** other output channels.
355
+**
356
+** The default behavior, if neither of the above is defined is to
357
+** use O_U8TEXT when writing to the Windows console (or anything
358
+** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
359
+** for all other output channels.
360
+*/
361
+#if defined(SQLITE_U8TEXT_ONLY)
362
+# define UseWtextForOutput(fd) 1
363
+# define UseWtextForInput(fd) 1
364
+# define IsConsole(fd) _isatty(_fileno(fd))
365
+#elif defined(SQLITE_U8TEXT_STDIO)
366
+# define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr)
367
+# define UseWtextForInput(fd) ((fd)==stdin)
368
+# define IsConsole(fd) _isatty(_fileno(fd))
369
+#else
370
+# define UseWtextForOutput(fd) _isatty(_fileno(fd))
371
+# define UseWtextForInput(fd) _isatty(_fileno(fd))
372
+# define IsConsole(fd) 1
373
+#endif
374
+
375
+/*
376
+** Global variables determine if simulated O_BINARY mode is to be
377
+** used for stdout or other, respectively. Simulated O_BINARY mode
378
+** means the mode is usually O_BINARY, but switches to O_U8TEXT for
379
+** unicode characters U+0080 or greater (any character that has a
380
+** multi-byte representation in UTF-8). This is the only way we
381
+** have found to render Unicode characters on a Windows console while
382
+** at the same time avoiding undesirable \n to \r\n translation.
383
+*/
384
+static int simBinaryStdout = 0;
385
+static int simBinaryOther = 0;
386
+
387
+
388
+/*
389
+** Determine if simulated binary mode should be used for output to fd
390
+*/
391
+static int UseBinaryWText(FILE *fd){
392
+ if( fd==stdout || fd==stderr ){
393
+ return simBinaryStdout;
394
+ }else{
395
+ return simBinaryOther;
396
+ }
397
+}
398
+
399
+
400
+/*
401
+** Work-alike for the fopen() routine from the standard C library.
402
+*/
403
+FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
404
+ FILE *fp = 0;
405
+ wchar_t *b1, *b2;
406
+ int sz1, sz2;
407
+
408
+ sz1 = (int)strlen(zFilename);
409
+ sz2 = (int)strlen(zMode);
410
+ b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
411
+ b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
412
+ if( b1 && b2 ){
413
+ sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
414
+ b1[sz1] = 0;
415
+ sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
416
+ b2[sz2] = 0;
417
+ fp = _wfopen(b1, b2);
418
+ }
419
+ sqlite3_free(b1);
420
+ sqlite3_free(b2);
421
+ simBinaryOther = 0;
422
+ return fp;
423
+}
424
+
425
+
426
+/*
427
+** Work-alike for the popen() routine from the standard C library.
428
+*/
429
+FILE *sqlite3_popen(const char *zCommand, const char *zMode){
430
+ FILE *fp = 0;
431
+ wchar_t *b1, *b2;
432
+ int sz1, sz2;
433
+
434
+ sz1 = (int)strlen(zCommand);
435
+ sz2 = (int)strlen(zMode);
436
+ b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
437
+ b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
438
+ if( b1 && b2 ){
439
+ sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
440
+ b1[sz1] = 0;
441
+ sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
442
+ b2[sz2] = 0;
443
+ fp = _wpopen(b1, b2);
444
+ }
445
+ sqlite3_free(b1);
446
+ sqlite3_free(b2);
447
+ return fp;
448
+}
449
+
450
+/*
451
+** Work-alike for fgets() from the standard C library.
452
+*/
453
+char *sqlite3_fgets(char *buf, int sz, FILE *in){
454
+ if( UseWtextForInput(in) ){
455
+ /* When reading from the command-prompt in Windows, it is necessary
456
+ ** to use _O_WTEXT input mode to read UTF-16 characters, then translate
457
+ ** that into UTF-8. Otherwise, non-ASCII characters all get translated
458
+ ** into '?'.
459
+ */
460
+ wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
461
+ if( b1==0 ) return 0;
462
+#ifndef SQLITE_USE_STDIO_FOR_CONSOLE
463
+ DWORD nRead = 0;
464
+ if( IsConsole(in)
465
+ && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz, &nRead, 0)
466
+ ){
467
+ b1[nRead] = 0;
468
+ }else
469
+#endif
470
+ {
471
+ _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
472
+ if( fgetws(b1, sz/4, in)==0 ){
473
+ sqlite3_free(b1);
474
+ return 0;
475
+ }
476
+ }
477
+ WideCharToMultiByte(CP_UTF8, 0, b1, -1, buf, sz, 0, 0);
478
+ sqlite3_free(b1);
479
+ return buf;
480
+ }else{
481
+ /* Reading from a file or other input source, just read bytes without
482
+ ** any translation. */
483
+ return fgets(buf, sz, in);
484
+ }
485
+}
486
+
487
+/*
488
+** Send ASCII text as O_BINARY. But for Unicode characters U+0080 and
489
+** greater, switch to O_U8TEXT.
490
+*/
491
+static void piecemealOutput(wchar_t *b1, int sz, FILE *out){
492
+ int i;
493
+ wchar_t c;
494
+ while( sz>0 ){
495
+ for(i=0; i<sz && b1[i]>=0x80; i++){}
496
+ if( i>0 ){
497
+ c = b1[i];
498
+ b1[i] = 0;
499
+ fflush(out);
500
+ _setmode(_fileno(out), _O_U8TEXT);
501
+ fputws(b1, out);
502
+ fflush(out);
503
+ b1 += i;
504
+ b1[0] = c;
505
+ sz -= i;
506
+ }else{
507
+ fflush(out);
508
+ _setmode(_fileno(out), _O_TEXT);
509
+ _setmode(_fileno(out), _O_BINARY);
510
+ fwrite(&b1[0], 1, 1, out);
511
+ for(i=1; i<sz && b1[i]<0x80; i++){
512
+ fwrite(&b1[i], 1, 1, out);
513
+ }
514
+ fflush(out);
515
+ _setmode(_fileno(out), _O_U8TEXT);
516
+ b1 += i;
517
+ sz -= i;
518
+ }
519
+ }
520
+}
521
+
522
+/*
523
+** Work-alike for fputs() from the standard C library.
524
+*/
525
+int sqlite3_fputs(const char *z, FILE *out){
526
+ if( !UseWtextForOutput(out) ){
527
+ /* Writing to a file or other destination, just write bytes without
528
+ ** any translation. */
529
+ return fputs(z, out);
530
+ }else{
531
+ /* One must use UTF16 in order to get unicode support when writing
532
+ ** to the console on Windows.
533
+ */
534
+ int sz = (int)strlen(z);
535
+ wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
536
+ if( b1==0 ) return 0;
537
+ sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
538
+ b1[sz] = 0;
539
+
540
+#ifndef SQLITE_STDIO_FOR_CONSOLE
541
+ DWORD nWr = 0;
542
+ if( IsConsole(out)
543
+ && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
544
+ ){
545
+ /* If writing to the console, then the WriteConsoleW() is all we
546
+ ** need to do. */
547
+ }else
548
+#endif
549
+ {
550
+ /* For non-console I/O, or if SQLITE_USE_STDIO_FOR_CONSOLE is defined
551
+ ** then write using the standard library. */
552
+ _setmode(_fileno(out), _O_U8TEXT);
553
+ if( UseBinaryWText(out) ){
554
+ piecemealOutput(b1, sz, out);
555
+ }else{
556
+ fputws(b1, out);
557
+ }
558
+ }
559
+ sqlite3_free(b1);
560
+ return 0;
561
+ }
562
+}
563
+
564
+
565
+/*
566
+** Work-alike for fprintf() from the standard C library.
567
+*/
568
+int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
569
+ int rc;
570
+ if( UseWtextForOutput(out) ){
571
+ /* When writing to the command-prompt in Windows, it is necessary
572
+ ** to use _O_WTEXT input mode and write UTF-16 characters.
573
+ */
574
+ char *z;
575
+ va_list ap;
576
+
577
+ va_start(ap, zFormat);
578
+ z = sqlite3_vmprintf(zFormat, ap);
579
+ va_end(ap);
580
+ sqlite3_fputs(z, out);
581
+ rc = (int)strlen(z);
582
+ sqlite3_free(z);
583
+ }else{
584
+ /* Writing to a file or other destination, just write bytes without
585
+ ** any translation. */
586
+ va_list ap;
587
+ va_start(ap, zFormat);
588
+ rc = vfprintf(out, zFormat, ap);
589
+ va_end(ap);
590
+ }
591
+ return rc;
592
+}
593
+
594
+/*
595
+** Set the mode for an output stream. mode argument is typically _O_BINARY or
596
+** _O_TEXT.
597
+*/
598
+void sqlite3_fsetmode(FILE *fp, int mode){
599
+ if( !UseWtextForOutput(fp) ){
600
+ fflush(fp);
601
+ _setmode(_fileno(fp), mode);
602
+ }else if( fp==stdout || fp==stderr ){
603
+ simBinaryStdout = (mode==_O_BINARY);
604
+ }else{
605
+ simBinaryOther = (mode==_O_BINARY);
606
+ }
607
+}
608
+
609
+#endif /* defined(_WIN32) */
610
+
611
+/************************* End ../ext/misc/sqlite3_stdio.c ********************/
612
+
258613
/* Use console I/O package as a direct INCLUDE. */
259614
#define SQLITE_INTERNAL_LINKAGE static
260615
261616
#ifdef SQLITE_SHELL_FIDDLE
262617
/* Deselect most features from the console I/O package for Fiddle. */
@@ -264,1118 +619,13 @@
264619
# define SQLITE_CIO_NO_CLASSIFY
265620
# define SQLITE_CIO_NO_TRANSLATE
266621
# define SQLITE_CIO_NO_SETMODE
267622
# define SQLITE_CIO_NO_FLUSH
268623
#endif
269
-/************************* Begin ../ext/consio/console_io.h ******************/
270
-/*
271
-** 2023 November 1
272
-**
273
-** The author disclaims copyright to this source code. In place of
274
-** a legal notice, here is a blessing:
275
-**
276
-** May you do good and not evil.
277
-** May you find forgiveness for yourself and forgive others.
278
-** May you share freely, never taking more than you give.
279
-**
280
-********************************************************************************
281
-** This file exposes various interfaces used for console and other I/O
282
-** by the SQLite project command-line tools. These interfaces are used
283
-** at either source conglomeration time, compilation time, or run time.
284
-** This source provides for either inclusion into conglomerated,
285
-** "single-source" forms or separate compilation then linking.
286
-**
287
-** Platform dependencies are "hidden" here by various stratagems so
288
-** that, provided certain conditions are met, the programs using this
289
-** source or object code compiled from it need no explicit conditional
290
-** compilation in their source for their console and stream I/O.
291
-**
292
-** The symbols and functionality exposed here are not a public API.
293
-** This code may change in tandem with other project code as needed.
294
-**
295
-** When this .h file and its companion .c are directly incorporated into
296
-** a source conglomeration (such as shell.c), the preprocessor symbol
297
-** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
298
-** translation for Windows is effected for the build.
299
-*/
300
-#define HAVE_CONSOLE_IO_H 1
301
-#ifndef SQLITE_INTERNAL_LINKAGE
302
-# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
303
-# include <stdio.h>
304
-#else
305
-# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
306
-#endif
307
-
308
-#ifndef SQLITE3_H
309
-/* # include "sqlite3.h" */
310
-#endif
311
-
312
-#ifndef SQLITE_CIO_NO_CLASSIFY
313
-
314
-/* Define enum for use with following function. */
315
-typedef enum StreamsAreConsole {
316
- SAC_NoConsole = 0,
317
- SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
318
- SAC_AnyConsole = 0x7
319
-} StreamsAreConsole;
320
-
321
-/*
322
-** Classify the three standard I/O streams according to whether
323
-** they are connected to a console attached to the process.
324
-**
325
-** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
326
-** or SAC_NoConsole if none of the streams reaches a console.
327
-**
328
-** This function should be called before any I/O is done with
329
-** the given streams. As a side-effect, the given inputs are
330
-** recorded so that later I/O operations on them may be done
331
-** differently than the C library FILE* I/O would be done,
332
-** iff the stream is used for the I/O functions that follow,
333
-** and to support the ones that use an implicit stream.
334
-**
335
-** On some platforms, stream or console mode alteration (aka
336
-** "Setup") may be made which is undone by consoleRestore().
337
-*/
338
-SQLITE_INTERNAL_LINKAGE StreamsAreConsole
339
-consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
340
-/* A usual call for convenience: */
341
-#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
342
-
343
-/*
344
-** After an initial call to consoleClassifySetup(...), renew
345
-** the same setup it effected. (A call not after is an error.)
346
-** This will restore state altered by consoleRestore();
347
-**
348
-** Applications which run an inferior (child) process which
349
-** inherits the same I/O streams may call this function after
350
-** such a process exits to guard against console mode changes.
351
-*/
352
-SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
353
-
354
-/*
355
-** Undo any side-effects left by consoleClassifySetup(...).
356
-**
357
-** This should be called after consoleClassifySetup() and
358
-** before the process terminates normally. It is suitable
359
-** for use with the atexit() C library procedure. After
360
-** this call, no console I/O should be done until one of
361
-** console{Classify or Renew}Setup(...) is called again.
362
-**
363
-** Applications which run an inferior (child) process that
364
-** inherits the same I/O streams might call this procedure
365
-** before so that said process will have a console setup
366
-** however users have configured it or come to expect.
367
-*/
368
-SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
369
-
370
-#else /* defined(SQLITE_CIO_NO_CLASSIFY) */
371
-# define consoleClassifySetup(i,o,e)
372
-# define consoleRenewSetup()
373
-# define consoleRestore()
374
-#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
375
-
376
-#ifndef SQLITE_CIO_NO_REDIRECT
377
-/*
378
-** Set stream to be used for the functions below which write
379
-** to "the designated X stream", where X is Output or Error.
380
-** Returns the previous value.
381
-**
382
-** Alternatively, pass the special value, invalidFileStream,
383
-** to get the designated stream value without setting it.
384
-**
385
-** Before the designated streams are set, they default to
386
-** those passed to consoleClassifySetup(...), and before
387
-** that is called they default to stdout and stderr.
388
-**
389
-** It is error to close a stream so designated, then, without
390
-** designating another, use the corresponding {o,e}Emit(...).
391
-*/
392
-SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
393
-SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
394
-# ifdef CONSIO_SET_ERROR_STREAM
395
-SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
396
-# endif
397
-#else
398
-# define setOutputStream(pf)
399
-# define setErrorStream(pf)
400
-#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
401
-
402
-#ifndef SQLITE_CIO_NO_TRANSLATE
403
-/*
404
-** Emit output like fprintf(). If the output is going to the
405
-** console and translation from UTF-8 is necessary, perform
406
-** the needed translation. Otherwise, write formatted output
407
-** to the provided stream almost as-is, possibly with newline
408
-** translation as specified by set{Binary,Text}Mode().
409
-*/
410
-SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
411
-/* Like fPrintfUtf8 except stream is always the designated output. */
412
-SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
413
-/* Like fPrintfUtf8 except stream is always the designated error. */
414
-SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
415
-
416
-/*
417
-** Emit output like fputs(). If the output is going to the
418
-** console and translation from UTF-8 is necessary, perform
419
-** the needed translation. Otherwise, write given text to the
420
-** provided stream almost as-is, possibly with newline
421
-** translation as specified by set{Binary,Text}Mode().
422
-*/
423
-SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
424
-/* Like fPutsUtf8 except stream is always the designated output. */
425
-SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
426
-/* Like fPutsUtf8 except stream is always the designated error. */
427
-SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
428
-
429
-/*
430
-** Emit output like fPutsUtf8(), except that the length of the
431
-** accepted char or character sequence is limited by nAccept.
432
-**
433
-** Returns the number of accepted char values.
434
-*/
435
-#ifdef CONSIO_SPUTB
436
-SQLITE_INTERNAL_LINKAGE int
437
-fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
438
-/* Like fPutbUtf8 except stream is always the designated output. */
439
-#endif
440
-SQLITE_INTERNAL_LINKAGE int
441
-oPutbUtf8(const char *cBuf, int nAccept);
442
-/* Like fPutbUtf8 except stream is always the designated error. */
443
-#ifdef CONSIO_EPUTB
444
-SQLITE_INTERNAL_LINKAGE int
445
-ePutbUtf8(const char *cBuf, int nAccept);
446
-#endif
447
-
448
-/*
449
-** Flush the given output stream. Return non-zero for success, else 0.
450
-*/
451
-#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
452
-SQLITE_INTERNAL_LINKAGE int
453
-fFlushBuffer(FILE *pfOut);
454
-#endif
455
-
456
-/*
457
-** Collect input like fgets(...) with special provisions for input
458
-** from the console on such platforms as require same. Newline
459
-** translation may be done as set by set{Binary,Text}Mode().
460
-** As a convenience, pfIn==NULL is treated as stdin.
461
-*/
462
-SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
463
-/* Like fGetsUtf8 except stream is always the designated input. */
464
-/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
465
-
466
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
467
-
468
-#ifndef SQLITE_CIO_NO_SETMODE
469
-/*
470
-** Set given stream for binary mode, where newline translation is
471
-** not done, or for text mode where, for some platforms, newlines
472
-** are translated to the platform's conventional char sequence.
473
-** If bFlush true, flush the stream.
474
-**
475
-** An additional side-effect is that if the stream is one passed
476
-** to consoleClassifySetup() as an output, it is flushed first.
477
-**
478
-** Note that binary/text mode has no effect on console I/O
479
-** translation. On all platforms, newline to the console starts
480
-** a new line and CR,LF chars from the console become a newline.
481
-*/
482
-SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
483
-SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
484
-#endif
485
-
486
-#ifdef SQLITE_CIO_PROMPTED_IN
487
-typedef struct Prompts {
488
- int numPrompts;
489
- const char **azPrompts;
490
-} Prompts;
491
-
492
-/*
493
-** Macros for use of a line editor.
494
-**
495
-** The following macros define operations involving use of a
496
-** line-editing library or simple console interaction.
497
-** A "T" argument is a text (char *) buffer or filename.
498
-** A "N" argument is an integer.
499
-**
500
-** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
501
-** SHELL_READ_HISTORY(T) // Read history from file named by T.
502
-** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
503
-** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
504
-**
505
-** A console program which does interactive console input is
506
-** expected to call:
507
-** SHELL_READ_HISTORY(T) before collecting such input;
508
-** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
509
-** SHELL_STIFLE_HISTORY(N) after console input ceases; then
510
-** SHELL_WRITE_HISTORY(T) before the program exits.
511
-*/
512
-
513
-/*
514
-** Retrieve a single line of input text from an input stream.
515
-**
516
-** If pfIn is the input stream passed to consoleClassifySetup(),
517
-** and azPrompt is not NULL, then a prompt is issued before the
518
-** line is collected, as selected by the isContinuation flag.
519
-** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
520
-**
521
-** If zBufPrior is not NULL then it is a buffer from a prior
522
-** call to this routine that can be reused, or will be freed.
523
-**
524
-** The result is stored in space obtained from malloc() and
525
-** must either be freed by the caller or else passed back to
526
-** this function as zBufPrior for reuse.
527
-**
528
-** This function may call upon services of a line-editing
529
-** library to interactively collect line edited input.
530
-*/
531
-SQLITE_INTERNAL_LINKAGE char *
532
-shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
533
- short isContinuation, Prompts azPrompt);
534
-#endif /* defined(SQLITE_CIO_PROMPTED_IN) */
535
-/*
536
-** TBD: Define an interface for application(s) to generate
537
-** completion candidates for use by the line-editor.
538
-**
539
-** This may be premature; the CLI is the only application
540
-** that does this. Yet, getting line-editing melded into
541
-** console I/O is desirable because a line-editing library
542
-** may have to establish console operating mode, possibly
543
-** in a way that interferes with the above functionality.
544
-*/
545
-
546
-#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
547
-/* Skip over as much z[] input char sequence as is valid UTF-8,
548
-** limited per nAccept char's or whole characters and containing
549
-** no char cn such that ((1<<cn) & ccm)!=0. On return, the
550
-** sequence z:return (inclusive:exclusive) is validated UTF-8.
551
-** Limit: nAccept>=0 => char count, nAccept<0 => character
552
- */
553
-SQLITE_INTERNAL_LINKAGE const char*
554
-zSkipValidUtf8(const char *z, int nAccept, long ccm);
555
-
556
-#endif
557
-
558
-/************************* End ../ext/consio/console_io.h ********************/
559
-/************************* Begin ../ext/consio/console_io.c ******************/
560
-/*
561
-** 2023 November 4
562
-**
563
-** The author disclaims copyright to this source code. In place of
564
-** a legal notice, here is a blessing:
565
-**
566
-** May you do good and not evil.
567
-** May you find forgiveness for yourself and forgive others.
568
-** May you share freely, never taking more than you give.
569
-**
570
-********************************************************************************
571
-** This file implements various interfaces used for console and stream I/O
572
-** by the SQLite project command-line tools, as explained in console_io.h .
573
-** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
574
-*/
575
-
576
-#ifndef SQLITE_CDECL
577
-# define SQLITE_CDECL
578
-#endif
579
-
580
-#ifndef SHELL_NO_SYSINC
581
-# include <stdarg.h>
582
-# include <string.h>
583
-# include <stdlib.h>
584
-# include <limits.h>
585
-# include <assert.h>
586
-/* # include "sqlite3.h" */
587
-#endif
588
-#ifndef HAVE_CONSOLE_IO_H
589
-# include "console_io.h"
590
-#endif
591
-#if defined(_MSC_VER)
592
-# pragma warning(disable : 4204)
593
-#endif
594
-
595
-#ifndef SQLITE_CIO_NO_TRANSLATE
596
-# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
597
-# ifndef SHELL_NO_SYSINC
598
-# include <io.h>
599
-# include <fcntl.h>
600
-# undef WIN32_LEAN_AND_MEAN
601
-# define WIN32_LEAN_AND_MEAN
602
-# include <windows.h>
603
-# endif
604
-# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
605
-# else
606
-# ifndef SHELL_NO_SYSINC
607
-# include <unistd.h>
608
-# endif
609
-# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
610
-# endif
611
-#else
612
-# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
613
-#endif
614
-
615
-#if CIO_WIN_WC_XLATE
616
-static HANDLE handleOfFile(FILE *pf){
617
- int fileDesc = _fileno(pf);
618
- union { intptr_t osfh; HANDLE fh; } fid = {
619
- (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
620
- };
621
- return fid.fh;
622
-}
623
-#endif
624
-
625
-#ifndef SQLITE_CIO_NO_TRANSLATE
626
-typedef struct PerStreamTags {
627
-# if CIO_WIN_WC_XLATE
628
- HANDLE hx;
629
- DWORD consMode;
630
- char acIncomplete[4];
631
-# else
632
- short reachesConsole;
633
-# endif
634
- FILE *pf;
635
-} PerStreamTags;
636
-
637
-/* Define NULL-like value for things which can validly be 0. */
638
-# define SHELL_INVALID_FILE_PTR ((FILE *)~0)
639
-# if CIO_WIN_WC_XLATE
640
-# define SHELL_INVALID_CONS_MODE 0xFFFF0000
641
-# endif
642
-
643
-# if CIO_WIN_WC_XLATE
644
-# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
645
- {0,0,0,0}, SHELL_INVALID_FILE_PTR }
646
-# else
647
-# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
648
-# endif
649
-
650
-/* Quickly say whether a known output is going to the console. */
651
-# if CIO_WIN_WC_XLATE
652
-static short pstReachesConsole(PerStreamTags *ppst){
653
- return (ppst->hx != INVALID_HANDLE_VALUE);
654
-}
655
-# else
656
-# define pstReachesConsole(ppst) 0
657
-# endif
658
-
659
-# if CIO_WIN_WC_XLATE
660
-static void restoreConsoleArb(PerStreamTags *ppst){
661
- if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
662
-}
663
-# else
664
-# define restoreConsoleArb(ppst)
665
-# endif
666
-
667
-/* Say whether FILE* appears to be a console, collect associated info. */
668
-static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
669
-# if CIO_WIN_WC_XLATE
670
- short rv = 0;
671
- DWORD dwCM = SHELL_INVALID_CONS_MODE;
672
- HANDLE fh = handleOfFile(pf);
673
- ppst->pf = pf;
674
- if( INVALID_HANDLE_VALUE != fh ){
675
- rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
676
- }
677
- ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
678
- ppst->consMode = dwCM;
679
- return rv;
680
-# else
681
- ppst->pf = pf;
682
- ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
683
- return ppst->reachesConsole;
684
-# endif
685
-}
686
-
687
-# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
688
-# define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4)
689
-# endif
690
-
691
-# if CIO_WIN_WC_XLATE
692
-/* Define console modes for use with the Windows Console API. */
693
-# define SHELL_CONI_MODE \
694
- (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
695
- | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
696
-# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
697
- | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
698
-# endif
699
-
700
-typedef struct ConsoleInfo {
701
- PerStreamTags pstSetup[3];
702
- PerStreamTags pstDesignated[3];
703
- StreamsAreConsole sacSetup;
704
-} ConsoleInfo;
705
-
706
-static short isValidStreamInfo(PerStreamTags *ppst){
707
- return (ppst->pf != SHELL_INVALID_FILE_PTR);
708
-}
709
-
710
-static ConsoleInfo consoleInfo = {
711
- { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
712
- { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
713
- SAC_NoConsole /* sacSetup */
714
-};
715
-
716
-SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
717
-
718
-# if CIO_WIN_WC_XLATE
719
-static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
720
- if( pstReachesConsole(ppst) ){
721
- DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
722
- SetConsoleMode(ppst->hx, cm);
723
- }
724
-}
725
-# else
726
-# define maybeSetupAsConsole(ppst,odir)
727
-# endif
728
-
729
-SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
730
-# if CIO_WIN_WC_XLATE
731
- int ix = 0;
732
- while( ix < 6 ){
733
- PerStreamTags *ppst = (ix<3)?
734
- &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
735
- maybeSetupAsConsole(ppst, (ix % 3)>0);
736
- ++ix;
737
- }
738
-# endif
739
-}
740
-
741
-SQLITE_INTERNAL_LINKAGE StreamsAreConsole
742
-consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
743
- StreamsAreConsole rv = SAC_NoConsole;
744
- FILE* apf[3] = { pfIn, pfOut, pfErr };
745
- int ix;
746
- for( ix = 2; ix >= 0; --ix ){
747
- PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
748
- if( streamOfConsole(apf[ix], ppst) ){
749
- rv |= (SAC_InConsole<<ix);
750
- }
751
- consoleInfo.pstDesignated[ix] = *ppst;
752
- if( ix > 0 ) fflush(apf[ix]);
753
- }
754
- consoleInfo.sacSetup = rv;
755
- consoleRenewSetup();
756
- return rv;
757
-}
758
-
759
-SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
760
-# if CIO_WIN_WC_XLATE
761
- static ConsoleInfo *pci = &consoleInfo;
762
- if( pci->sacSetup ){
763
- int ix;
764
- for( ix=0; ix<3; ++ix ){
765
- if( pci->sacSetup & (SAC_InConsole<<ix) ){
766
- PerStreamTags *ppst = &pci->pstSetup[ix];
767
- SetConsoleMode(ppst->hx, ppst->consMode);
768
- }
769
- }
770
- }
771
-# endif
772
-}
773
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
774
-
775
-#ifdef SQLITE_CIO_INPUT_REDIR
776
-/* Say whether given FILE* is among those known, via either
777
-** consoleClassifySetup() or set{Output,Error}Stream, as
778
-** readable, and return an associated PerStreamTags pointer
779
-** if so. Otherwise, return 0.
780
-*/
781
-static PerStreamTags * isKnownReadable(FILE *pf){
782
- static PerStreamTags *apst[] = {
783
- &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
784
- };
785
- int ix = 0;
786
- do {
787
- if( apst[ix]->pf == pf ) break;
788
- } while( apst[++ix] != 0 );
789
- return apst[ix];
790
-}
791
-#endif
792
-
793
-#ifndef SQLITE_CIO_NO_TRANSLATE
794
-/* Say whether given FILE* is among those known, via either
795
-** consoleClassifySetup() or set{Output,Error}Stream, as
796
-** writable, and return an associated PerStreamTags pointer
797
-** if so. Otherwise, return 0.
798
-*/
799
-static PerStreamTags * isKnownWritable(FILE *pf){
800
- static PerStreamTags *apst[] = {
801
- &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
802
- &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
803
- };
804
- int ix = 0;
805
- do {
806
- if( apst[ix]->pf == pf ) break;
807
- } while( apst[++ix] != 0 );
808
- return apst[ix];
809
-}
810
-
811
-static FILE *designateEmitStream(FILE *pf, unsigned chix){
812
- FILE *rv = consoleInfo.pstDesignated[chix].pf;
813
- if( pf == invalidFileStream ) return rv;
814
- else{
815
- /* Setting a possibly new output stream. */
816
- PerStreamTags *ppst = isKnownWritable(pf);
817
- if( ppst != 0 ){
818
- PerStreamTags pst = *ppst;
819
- consoleInfo.pstDesignated[chix] = pst;
820
- }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
821
- }
822
- return rv;
823
-}
824
-
825
-SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
826
- return designateEmitStream(pf, 1);
827
-}
828
-# ifdef CONSIO_SET_ERROR_STREAM
829
-SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
830
- return designateEmitStream(pf, 2);
831
-}
832
-# endif
833
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
834
-
835
-#ifndef SQLITE_CIO_NO_SETMODE
836
-# if CIO_WIN_WC_XLATE
837
-static void setModeFlushQ(FILE *pf, short bFlush, int mode){
838
- if( bFlush ) fflush(pf);
839
- _setmode(_fileno(pf), mode);
840
-}
841
-# else
842
-# define setModeFlushQ(f, b, m) if(b) fflush(f)
843
-# endif
844
-
845
-SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
846
- setModeFlushQ(pf, bFlush, _O_BINARY);
847
-}
848
-SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
849
- setModeFlushQ(pf, bFlush, _O_TEXT);
850
-}
851
-# undef setModeFlushQ
852
-
853
-#else /* defined(SQLITE_CIO_NO_SETMODE) */
854
-# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
855
-# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
856
-#endif /* defined(SQLITE_CIO_NO_SETMODE) */
857
-
858
-#ifndef SQLITE_CIO_NO_TRANSLATE
859
-# if CIO_WIN_WC_XLATE
860
-/* Write buffer cBuf as output to stream known to reach console,
861
-** limited to ncTake char's. Return ncTake on success, else 0. */
862
-static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
863
- int rv = 0;
864
- if( z!=NULL ){
865
- int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
866
- if( nwc > 0 ){
867
- WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
868
- if( zw!=NULL ){
869
- nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
870
- if( nwc > 0 ){
871
- /* Translation from UTF-8 to UTF-16, then WCHARs out. */
872
- if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
873
- rv = ncTake;
874
- }
875
- }
876
- sqlite3_free(zw);
877
- }
878
- }
879
- }
880
- return rv;
881
-}
882
-
883
-/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
884
-static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
885
- char *z = sqlite3_vmprintf(zFormat, ap);
886
- if( z ){
887
- int rv = conZstrEmit(ppst, z, (int)strlen(z));
888
- sqlite3_free(z);
889
- return rv;
890
- }else return 0;
891
-}
892
-# endif /* CIO_WIN_WC_XLATE */
893
-
894
-# ifdef CONSIO_GET_EMIT_STREAM
895
-static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
896
- PerStreamTags *ppst){
897
- PerStreamTags *rv = isKnownWritable(pf);
898
- short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
899
- if( rv != 0 && isValid ) return rv;
900
- streamOfConsole(pf, ppst);
901
- return ppst;
902
-}
903
-# endif
904
-
905
-/* Get stream info, either for designated output or error stream when
906
-** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
907
-** In either case, ppst references a caller-owned PerStreamTags
908
-** struct which may be filled in if none of the known writable
909
-** streams is being held by consoleInfo. The ppf parameter is a
910
-** byref output when chix!=0 and a byref input when chix==0.
911
- */
912
-static PerStreamTags *
913
-getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
914
- /* in/out */ FILE **ppf){
915
- PerStreamTags *ppstTry;
916
- FILE *pfEmit;
917
- if( chix > 0 ){
918
- ppstTry = &consoleInfo.pstDesignated[chix];
919
- if( !isValidStreamInfo(ppstTry) ){
920
- ppstTry = &consoleInfo.pstSetup[chix];
921
- pfEmit = ppst->pf;
922
- }else pfEmit = ppstTry->pf;
923
- if( !isValidStreamInfo(ppstTry) ){
924
- pfEmit = (chix > 1)? stderr : stdout;
925
- ppstTry = ppst;
926
- streamOfConsole(pfEmit, ppstTry);
927
- }
928
- *ppf = pfEmit;
929
- }else{
930
- ppstTry = isKnownWritable(*ppf);
931
- if( ppstTry != 0 ) return ppstTry;
932
- streamOfConsole(*ppf, ppst);
933
- return ppst;
934
- }
935
- return ppstTry;
936
-}
937
-
938
-SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
939
- va_list ap;
940
- int rv;
941
- FILE *pfOut;
942
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
943
-# if CIO_WIN_WC_XLATE
944
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
945
-# else
946
- getEmitStreamInfo(1, &pst, &pfOut);
947
-# endif
948
- assert(zFormat!=0);
949
- va_start(ap, zFormat);
950
-# if CIO_WIN_WC_XLATE
951
- if( pstReachesConsole(ppst) ){
952
- rv = conioVmPrintf(ppst, zFormat, ap);
953
- }else{
954
-# endif
955
- rv = vfprintf(pfOut, zFormat, ap);
956
-# if CIO_WIN_WC_XLATE
957
- }
958
-# endif
959
- va_end(ap);
960
- return rv;
961
-}
962
-
963
-SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
964
- va_list ap;
965
- int rv;
966
- FILE *pfErr;
967
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
968
-# if CIO_WIN_WC_XLATE
969
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
970
-# else
971
- getEmitStreamInfo(2, &pst, &pfErr);
972
-# endif
973
- assert(zFormat!=0);
974
- va_start(ap, zFormat);
975
-# if CIO_WIN_WC_XLATE
976
- if( pstReachesConsole(ppst) ){
977
- rv = conioVmPrintf(ppst, zFormat, ap);
978
- }else{
979
-# endif
980
- rv = vfprintf(pfErr, zFormat, ap);
981
-# if CIO_WIN_WC_XLATE
982
- }
983
-# endif
984
- va_end(ap);
985
- return rv;
986
-}
987
-
988
-SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
989
- va_list ap;
990
- int rv;
991
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
992
-# if CIO_WIN_WC_XLATE
993
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
994
-# else
995
- getEmitStreamInfo(0, &pst, &pfO);
996
-# endif
997
- assert(zFormat!=0);
998
- va_start(ap, zFormat);
999
-# if CIO_WIN_WC_XLATE
1000
- if( pstReachesConsole(ppst) ){
1001
- maybeSetupAsConsole(ppst, 1);
1002
- rv = conioVmPrintf(ppst, zFormat, ap);
1003
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
1004
- }else{
1005
-# endif
1006
- rv = vfprintf(pfO, zFormat, ap);
1007
-# if CIO_WIN_WC_XLATE
1008
- }
1009
-# endif
1010
- va_end(ap);
1011
- return rv;
1012
-}
1013
-
1014
-SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
1015
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1016
-# if CIO_WIN_WC_XLATE
1017
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
1018
-# else
1019
- getEmitStreamInfo(0, &pst, &pfO);
1020
-# endif
1021
- assert(z!=0);
1022
-# if CIO_WIN_WC_XLATE
1023
- if( pstReachesConsole(ppst) ){
1024
- int rv;
1025
- maybeSetupAsConsole(ppst, 1);
1026
- rv = conZstrEmit(ppst, z, (int)strlen(z));
1027
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
1028
- return rv;
1029
- }else {
1030
-# endif
1031
- return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
1032
-# if CIO_WIN_WC_XLATE
1033
- }
1034
-# endif
1035
-}
1036
-
1037
-SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
1038
- FILE *pfErr;
1039
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1040
-# if CIO_WIN_WC_XLATE
1041
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
1042
-# else
1043
- getEmitStreamInfo(2, &pst, &pfErr);
1044
-# endif
1045
- assert(z!=0);
1046
-# if CIO_WIN_WC_XLATE
1047
- if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
1048
- else {
1049
-# endif
1050
- return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
1051
-# if CIO_WIN_WC_XLATE
1052
- }
1053
-# endif
1054
-}
1055
-
1056
-SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
1057
- FILE *pfOut;
1058
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1059
-# if CIO_WIN_WC_XLATE
1060
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
1061
-# else
1062
- getEmitStreamInfo(1, &pst, &pfOut);
1063
-# endif
1064
- assert(z!=0);
1065
-# if CIO_WIN_WC_XLATE
1066
- if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
1067
- else {
1068
-# endif
1069
- return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
1070
-# if CIO_WIN_WC_XLATE
1071
- }
1072
-# endif
1073
-}
1074
-
1075
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
1076
-
1077
-#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
1078
-/* Skip over as much z[] input char sequence as is valid UTF-8,
1079
-** limited per nAccept char's or whole characters and containing
1080
-** no char cn such that ((1<<cn) & ccm)!=0. On return, the
1081
-** sequence z:return (inclusive:exclusive) is validated UTF-8.
1082
-** Limit: nAccept>=0 => char count, nAccept<0 => character
1083
- */
1084
-SQLITE_INTERNAL_LINKAGE const char*
1085
-zSkipValidUtf8(const char *z, int nAccept, long ccm){
1086
- int ng = (nAccept<0)? -nAccept : 0;
1087
- const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
1088
- assert(z!=0);
1089
- while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
1090
- char c = *z;
1091
- if( (c & 0x80) == 0 ){
1092
- if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
1093
- ++z; /* ASCII */
1094
- }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
1095
- else{
1096
- const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
1097
- do{
1098
- if( pcLimit && zt >= pcLimit ) return z;
1099
- else{
1100
- char ct = *zt++;
1101
- if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
1102
- /* Trailing bytes are too few, too many, or invalid. */
1103
- return z;
1104
- }
1105
- }
1106
- } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
1107
- z = zt;
1108
- }
1109
- }
1110
- return z;
1111
-}
1112
-#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
1113
-
1114
-#ifndef SQLITE_CIO_NO_TRANSLATE
1115
-# ifdef CONSIO_SPUTB
1116
-SQLITE_INTERNAL_LINKAGE int
1117
-fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
1118
- assert(pfO!=0);
1119
-# if CIO_WIN_WC_XLATE
1120
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1121
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
1122
- if( pstReachesConsole(ppst) ){
1123
- int rv;
1124
- maybeSetupAsConsole(ppst, 1);
1125
- rv = conZstrEmit(ppst, cBuf, nAccept);
1126
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
1127
- return rv;
1128
- }else {
1129
-# endif
1130
- return (int)fwrite(cBuf, 1, nAccept, pfO);
1131
-# if CIO_WIN_WC_XLATE
1132
- }
1133
-# endif
1134
-}
1135
-# endif
1136
-
1137
-SQLITE_INTERNAL_LINKAGE int
1138
-oPutbUtf8(const char *cBuf, int nAccept){
1139
- FILE *pfOut;
1140
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1141
-# if CIO_WIN_WC_XLATE
1142
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
1143
-# else
1144
- getEmitStreamInfo(1, &pst, &pfOut);
1145
-# endif
1146
-# if CIO_WIN_WC_XLATE
1147
- if( pstReachesConsole(ppst) ){
1148
- return conZstrEmit(ppst, cBuf, nAccept);
1149
- }else {
1150
-# endif
1151
- return (int)fwrite(cBuf, 1, nAccept, pfOut);
1152
-# if CIO_WIN_WC_XLATE
1153
- }
1154
-# endif
1155
-}
1156
-
1157
-/*
1158
-** Flush the given output stream. Return non-zero for success, else 0.
1159
-*/
1160
-#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
1161
-SQLITE_INTERNAL_LINKAGE int
1162
-fFlushBuffer(FILE *pfOut){
1163
-# if CIO_WIN_WC_XLATE && !defined(SHELL_OMIT_FIO_DUPE)
1164
- return FlushFileBuffers(handleOfFile(pfOut))? 1 : 0;
1165
-# else
1166
- return fflush(pfOut);
1167
-# endif
1168
-}
1169
-#endif
1170
-
1171
-#if CIO_WIN_WC_XLATE \
1172
- && !defined(SHELL_OMIT_FIO_DUPE) \
1173
- && defined(SQLITE_USE_ONLY_WIN32)
1174
-static struct FileAltIds {
1175
- int fd;
1176
- HANDLE fh;
1177
-} altIdsOfFile(FILE *pf){
1178
- struct FileAltIds rv = { _fileno(pf) };
1179
- union { intptr_t osfh; HANDLE fh; } fid = {
1180
- (rv.fd>=0)? _get_osfhandle(rv.fd) : (intptr_t)INVALID_HANDLE_VALUE
1181
- };
1182
- rv.fh = fid.fh;
1183
- return rv;
1184
-}
1185
-
1186
-SQLITE_INTERNAL_LINKAGE size_t
1187
-cfWrite(const void *buf, size_t osz, size_t ocnt, FILE *pf){
1188
- size_t rv = 0;
1189
- struct FileAltIds fai = altIdsOfFile(pf);
1190
- int fmode = _setmode(fai.fd, _O_BINARY);
1191
- _setmode(fai.fd, fmode);
1192
- while( rv < ocnt ){
1193
- size_t nbo = osz;
1194
- while( nbo > 0 ){
1195
- DWORD dwno = (nbo>(1L<<24))? 1L<<24 : (DWORD)nbo;
1196
- BOOL wrc = TRUE;
1197
- BOOL genCR = (fmode & _O_TEXT)!=0;
1198
- if( genCR ){
1199
- const char *pnl = (const char*)memchr(buf, '\n', nbo);
1200
- if( pnl ) nbo = pnl - (const char*)buf;
1201
- else genCR = 0;
1202
- }
1203
- if( dwno>0 ) wrc = WriteFile(fai.fh, buf, dwno, 0,0);
1204
- if( genCR && wrc ){
1205
- wrc = WriteFile(fai.fh, "\r\n", 2, 0,0);
1206
- ++dwno; /* Skip over the LF */
1207
- }
1208
- if( !wrc ) return rv;
1209
- buf = (const char*)buf + dwno;
1210
- nbo += dwno;
1211
- }
1212
- ++rv;
1213
- }
1214
- return rv;
1215
-}
1216
-
1217
-SQLITE_INTERNAL_LINKAGE char *
1218
-cfGets(char *cBuf, int n, FILE *pf){
1219
- int nci = 0;
1220
- struct FileAltIds fai = altIdsOfFile(pf);
1221
- int fmode = _setmode(fai.fd, _O_BINARY);
1222
- BOOL eatCR = (fmode & _O_TEXT)!=0;
1223
- _setmode(fai.fd, fmode);
1224
- while( nci < n-1 ){
1225
- DWORD nr;
1226
- if( !ReadFile(fai.fh, cBuf+nci, 1, &nr, 0) || nr==0 ) break;
1227
- if( nr>0 && (!eatCR || cBuf[nci]!='\r') ) nci += nr;
1228
- }
1229
- if( nci < n ) cBuf[nci] = 0;
1230
- return (nci>0)? cBuf : 0;
1231
-}
1232
-# else
1233
-# define cfWrite(b,os,no,f) fwrite(b,os,no,f)
1234
-# define cfGets(b,n,f) fgets(b,n,f)
1235
-# endif
1236
-
1237
-# ifdef CONSIO_EPUTB
1238
-SQLITE_INTERNAL_LINKAGE int
1239
-ePutbUtf8(const char *cBuf, int nAccept){
1240
- FILE *pfErr;
1241
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1242
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
1243
-# if CIO_WIN_WC_XLATE
1244
- if( pstReachesConsole(ppst) ){
1245
- return conZstrEmit(ppst, cBuf, nAccept);
1246
- }else {
1247
-# endif
1248
- return (int)cfWrite(cBuf, 1, nAccept, pfErr);
1249
-# if CIO_WIN_WC_XLATE
1250
- }
1251
-# endif
1252
-}
1253
-# endif /* defined(CONSIO_EPUTB) */
1254
-
1255
-SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
1256
- if( pfIn==0 ) pfIn = stdin;
1257
-# if CIO_WIN_WC_XLATE
1258
- if( pfIn == consoleInfo.pstSetup[0].pf
1259
- && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
1260
-# if CIO_WIN_WC_XLATE==1
1261
-# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
1262
- WCHAR wcBuf[SHELL_GULP+1];
1263
- int lend = 0, noc = 0;
1264
- if( ncMax > 0 ) cBuf[0] = 0;
1265
- while( noc < ncMax-8-1 && !lend ){
1266
- /* There is room for at least 2 more characters and a 0-terminator. */
1267
- int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
1268
-# undef SHELL_GULP
1269
- DWORD nbr = 0;
1270
- BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
1271
- if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
1272
- /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
1273
- DWORD nbrx;
1274
- bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
1275
- if( bRC ) nbr += nbrx;
1276
- }
1277
- if( !bRC || (noc==0 && nbr==0) ) return 0;
1278
- if( nbr > 0 ){
1279
- int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
1280
- if( nmb != 0 && noc+nmb <= ncMax ){
1281
- int iseg = noc;
1282
- nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
1283
- noc += nmb;
1284
- /* Fixup line-ends as coded by Windows for CR (or "Enter".)
1285
- ** This is done without regard for any setMode{Text,Binary}()
1286
- ** call that might have been done on the interactive input.
1287
- */
1288
- if( noc > 0 ){
1289
- if( cBuf[noc-1]=='\n' ){
1290
- lend = 1;
1291
- if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
1292
- }
1293
- }
1294
- /* Check for ^Z (anywhere in line) too, to act as EOF. */
1295
- while( iseg < noc ){
1296
- if( cBuf[iseg]=='\x1a' ){
1297
- noc = iseg; /* Chop ^Z and anything following. */
1298
- lend = 1; /* Counts as end of line too. */
1299
- break;
1300
- }
1301
- ++iseg;
1302
- }
1303
- }else break; /* Drop apparent garbage in. (Could assert.) */
1304
- }else break;
1305
- }
1306
- /* If got nothing, (after ^Z chop), must be at end-of-file. */
1307
- if( noc > 0 ){
1308
- cBuf[noc] = 0;
1309
- return cBuf;
1310
- }else return 0;
1311
-# endif
1312
- }else{
1313
-# endif
1314
- return cfGets(cBuf, ncMax, pfIn);
1315
-# if CIO_WIN_WC_XLATE
1316
- }
1317
-# endif
1318
-}
1319
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
1320
-
1321
-#if defined(_MSC_VER)
1322
-# pragma warning(default : 4204)
1323
-#endif
1324
-
1325
-#undef SHELL_INVALID_FILE_PTR
1326
-
1327
-/************************* End ../ext/consio/console_io.c ********************/
1328
-
1329
-#ifndef SQLITE_SHELL_FIDDLE
1330
-
1331
-/* From here onward, fgets() is redirected to the console_io library. */
1332
-# define fgets(b,n,f) fGetsUtf8(b,n,f)
1333
-/*
1334
- * Define macros for emitting output text in various ways:
1335
- * sputz(s, z) => emit 0-terminated string z to given stream s
1336
- * sputf(s, f, ...) => emit varargs per format f to given stream s
1337
- * oputz(z) => emit 0-terminated string z to default stream
1338
- * oputf(f, ...) => emit varargs per format f to default stream
1339
- * eputz(z) => emit 0-terminated string z to error stream
1340
- * eputf(f, ...) => emit varargs per format f to error stream
1341
- * oputb(b, n) => emit char buffer b[0..n-1] to default stream
1342
- *
1343
- * Note that the default stream is whatever has been last set via:
1344
- * setOutputStream(FILE *pf)
1345
- * This is normally the stream that CLI normal output goes to.
1346
- * For the stand-alone CLI, it is stdout with no .output redirect.
1347
- *
1348
- * The ?putz(z) forms are required for the Fiddle builds for string literal
1349
- * output, in aid of enforcing format string to argument correspondence.
1350
- */
1351
-# define sputz(s,z) fPutsUtf8(z,s)
1352
-# define sputf fPrintfUtf8
1353
-# define oputz(z) oPutsUtf8(z)
1354
-# define oputf oPrintfUtf8
1355
-# define eputz(z) ePutsUtf8(z)
1356
-# define eputf ePrintfUtf8
1357
-# define oputb(buf,na) oPutbUtf8(buf,na)
1358
-# define fflush(s) fFlushBuffer(s);
1359
-
1360
-#else
1361
-/* For Fiddle, all console handling and emit redirection is omitted. */
1362
-/* These next 3 macros are for emitting formatted output. When complaints
1363
- * from the WASM build are issued for non-formatted output, when a mere
1364
- * string literal is to be emitted, the ?putz(z) forms should be used.
1365
- * (This permits compile-time checking of format string / argument mismatch.)
1366
- */
1367
-# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
1368
-# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
1369
-# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
1370
-/* These next 3 macros are for emitting simple string literals. */
1371
-# define oputz(z) fputs(z,stdout)
1372
-# define eputz(z) fputs(z,stderr)
1373
-# define sputz(fp,z) fputs(z,fp)
1374
-# define oputb(buf,na) fwrite(buf,1,na,stdout)
1375
-# undef fflush
1376
-#endif
624
+
625
+#define eputz(z) sqlite3_fputs(z,stderr)
626
+#define sputz(fp,z) sqlite3_fputs(z,fp)
1377627
1378628
/* True if the timer is enabled */
1379629
static int enableTimer = 0;
1380630
1381631
/* A version of strcmp() that works with NULL values */
@@ -1416,10 +666,11 @@
1416666
struct timeval ru_utime; /* user CPU time used */
1417667
struct timeval ru_stime; /* system CPU time used */
1418668
};
1419669
#define getrusage(A,B) memset(B,0,sizeof(*B))
1420670
#endif
671
+
1421672
1422673
/* Saved resource information for the beginning of an operation */
1423674
static struct rusage sBegin; /* CPU time at start */
1424675
static sqlite3_int64 iBegin; /* Wall-clock time at start */
1425676
@@ -1440,24 +691,24 @@
1440691
}
1441692
1442693
/*
1443694
** Print the timing results.
1444695
*/
1445
-static void endTimer(void){
696
+static void endTimer(FILE *out){
1446697
if( enableTimer ){
1447698
sqlite3_int64 iEnd = timeOfDay();
1448699
struct rusage sEnd;
1449700
getrusage(RUSAGE_SELF, &sEnd);
1450
- sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
701
+ sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
1451702
(iEnd - iBegin)*0.001,
1452703
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
1453704
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
1454705
}
1455706
}
1456707
1457708
#define BEGIN_TIMER beginTimer()
1458
-#define END_TIMER endTimer()
709
+#define END_TIMER(X) endTimer(X)
1459710
#define HAS_TIMER 1
1460711
1461712
#elif (defined(_WIN32) || defined(WIN32))
1462713
1463714
/* Saved resource information for the beginning of an operation */
@@ -1519,29 +770,29 @@
1519770
}
1520771
1521772
/*
1522773
** Print the timing results.
1523774
*/
1524
-static void endTimer(void){
775
+static void endTimer(FILE *out){
1525776
if( enableTimer && getProcessTimesAddr){
1526777
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
1527778
sqlite3_int64 ftWallEnd = timeOfDay();
1528779
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
1529
- sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
780
+ sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
1530781
(ftWallEnd - ftWallBegin)*0.001,
1531782
timeDiff(&ftUserBegin, &ftUserEnd),
1532783
timeDiff(&ftKernelBegin, &ftKernelEnd));
1533784
}
1534785
}
1535786
1536787
#define BEGIN_TIMER beginTimer()
1537
-#define END_TIMER endTimer()
788
+#define END_TIMER(X) endTimer(X)
1538789
#define HAS_TIMER hasTimer()
1539790
1540791
#else
1541792
#define BEGIN_TIMER
1542
-#define END_TIMER
793
+#define END_TIMER(X) /*no-op*/
1543794
#define HAS_TIMER 0
1544795
#endif
1545796
1546797
/*
1547798
** Used to prevent warnings about unused parameters
@@ -1738,41 +989,216 @@
1738989
char *z;
1739990
if( iotrace==0 ) return;
1740991
va_start(ap, zFormat);
1741992
z = sqlite3_vmprintf(zFormat, ap);
1742993
va_end(ap);
1743
- sputf(iotrace, "%s", z);
994
+ sqlite3_fprintf(iotrace, "%s", z);
1744995
sqlite3_free(z);
1745996
}
1746997
#endif
1747998
999
+/* Lookup table to estimate the number of columns consumed by a Unicode
1000
+** character.
1001
+*/
1002
+static const struct {
1003
+ unsigned char w; /* Width of the character in columns */
1004
+ int iFirst; /* First character in a span having this width */
1005
+} aUWidth[] = {
1006
+ /* {1, 0x00000}, */
1007
+ {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488},
1008
+ {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0},
1009
+ {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7},
1010
+ {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616},
1011
+ {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6},
1012
+ {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee},
1013
+ {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730},
1014
+ {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4},
1015
+ {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941},
1016
+ {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955},
1017
+ {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc},
1018
+ {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce},
1019
+ {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c},
1020
+ {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49},
1021
+ {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81},
1022
+ {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6},
1023
+ {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2},
1024
+ {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d},
1025
+ {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d},
1026
+ {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83},
1027
+ {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e},
1028
+ {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e},
1029
+ {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf},
1030
+ {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce},
1031
+ {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d},
1032
+ {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5},
1033
+ {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34},
1034
+ {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2},
1035
+ {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8},
1036
+ {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36},
1037
+ {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71},
1038
+ {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
1039
+ {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
1040
+ {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
1041
+ {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
1042
+ {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
1043
+ {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
1044
+ {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
1045
+ {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7},
1046
+ {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b},
1047
+ {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923},
1048
+ {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939},
1049
+ {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04},
1050
+ {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c},
1051
+ {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74},
1052
+ {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b},
1053
+ {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064},
1054
+ {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329},
1055
+ {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f},
1056
+ {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806},
1057
+ {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827},
1058
+ {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e},
1059
+ {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20},
1060
+ {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00},
1061
+ {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc},
1062
+ {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c},
1063
+ {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40},
1064
+ {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185},
1065
+ {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245},
1066
+ {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001},
1067
+ {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0}
1068
+};
1069
+
17481070
/*
1749
-** Output string zUtf to Out stream as w characters. If w is negative,
1071
+** Return an estimate of the width, in columns, for the single Unicode
1072
+** character c. For normal characters, the answer is always 1. But the
1073
+** estimate might be 0 or 2 for zero-width and double-width characters.
1074
+**
1075
+** Different display devices display unicode using different widths. So
1076
+** it is impossible to know that true display width with 100% accuracy.
1077
+** Inaccuracies in the width estimates might cause columns to be misaligned.
1078
+** Unfortunately, there is nothing we can do about that.
1079
+*/
1080
+int cli_wcwidth(int c){
1081
+ int iFirst, iLast;
1082
+
1083
+ /* Fast path for common characters */
1084
+ if( c<=0x300 ) return 1;
1085
+
1086
+ /* The general case */
1087
+ iFirst = 0;
1088
+ iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1;
1089
+ while( iFirst<iLast-1 ){
1090
+ int iMid = (iFirst+iLast)/2;
1091
+ int cMid = aUWidth[iMid].iFirst;
1092
+ if( cMid < c ){
1093
+ iFirst = iMid;
1094
+ }else if( cMid > c ){
1095
+ iLast = iMid - 1;
1096
+ }else{
1097
+ return aUWidth[iMid].w;
1098
+ }
1099
+ }
1100
+ if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w;
1101
+ return aUWidth[iLast].w;
1102
+}
1103
+
1104
+/*
1105
+** Compute the value and length of a multi-byte UTF-8 character that
1106
+** begins at z[0]. Return the length. Write the Unicode value into *pU.
1107
+**
1108
+** This routine only works for *multi-byte* UTF-8 characters.
1109
+*/
1110
+static int decodeUtf8(const unsigned char *z, int *pU){
1111
+ if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){
1112
+ *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f);
1113
+ return 2;
1114
+ }
1115
+ if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){
1116
+ *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f);
1117
+ return 3;
1118
+ }
1119
+ if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80
1120
+ && (z[3] & 0xc0)==0x80
1121
+ ){
1122
+ *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6
1123
+ | (z[4] & 0x3f);
1124
+ return 4;
1125
+ }
1126
+ *pU = 0;
1127
+ return 1;
1128
+}
1129
+
1130
+
1131
+#if 0 /* NOT USED */
1132
+/*
1133
+** Return the width, in display columns, of a UTF-8 string.
1134
+**
1135
+** Each normal character counts as 1. Zero-width characters count
1136
+** as zero, and double-width characters count as 2.
1137
+*/
1138
+int cli_wcswidth(const char *z){
1139
+ const unsigned char *a = (const unsigned char*)z;
1140
+ int n = 0;
1141
+ int i = 0;
1142
+ unsigned char c;
1143
+ while( (c = a[i])!=0 ){
1144
+ if( c>=0xc0 ){
1145
+ int u;
1146
+ int len = decodeUtf8(&a[i], &u);
1147
+ i += len;
1148
+ n += cli_wcwidth(u);
1149
+ }else if( c>=' ' ){
1150
+ n++;
1151
+ i++;
1152
+ }else{
1153
+ i++;
1154
+ }
1155
+ }
1156
+ return n;
1157
+}
1158
+#endif
1159
+
1160
+/*
1161
+** Output string zUtf to stdout as w characters. If w is negative,
17501162
** then right-justify the text. W is the width in UTF-8 characters, not
17511163
** in bytes. This is different from the %*.*s specification in printf
17521164
** since with %*.*s the width is measured in bytes, not characters.
1165
+**
1166
+** Take into account zero-width and double-width Unicode characters.
1167
+** In other words, a zero-width character does not count toward the
1168
+** the w limit. A double-width character counts as two.
17531169
*/
1754
-static void utf8_width_print(int w, const char *zUtf){
1755
- int i;
1756
- int n;
1170
+static void utf8_width_print(FILE *out, int w, const char *zUtf){
1171
+ const unsigned char *a = (const unsigned char*)zUtf;
1172
+ unsigned char c;
1173
+ int i = 0;
1174
+ int n = 0;
17571175
int aw = w<0 ? -w : w;
17581176
if( zUtf==0 ) zUtf = "";
1759
- for(i=n=0; zUtf[i]; i++){
1760
- if( (zUtf[i]&0xc0)!=0x80 ){
1177
+ while( (c = a[i])!=0 ){
1178
+ if( (c&0xc0)==0xc0 ){
1179
+ int u;
1180
+ int len = decodeUtf8(a+i, &u);
1181
+ int x = cli_wcwidth(u);
1182
+ if( x+n>aw ){
1183
+ break;
1184
+ }
1185
+ i += len;
1186
+ n += x;
1187
+ }else if( n>=aw ){
1188
+ break;
1189
+ }else{
17611190
n++;
1762
- if( n==aw ){
1763
- do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
1764
- break;
1765
- }
1191
+ i++;
17661192
}
17671193
}
17681194
if( n>=aw ){
1769
- oputf("%.*s", i, zUtf);
1195
+ sqlite3_fprintf(out, "%.*s", i, zUtf);
17701196
}else if( w<0 ){
1771
- oputf("%*s%s", aw-n, "", zUtf);
1197
+ sqlite3_fprintf(out, "%*s%s", aw-n, "", zUtf);
17721198
}else{
1773
- oputf("%s%*s", zUtf, aw-n, "");
1199
+ sqlite3_fprintf(out, "%s%*s", zUtf, aw-n, "");
17741200
}
17751201
}
17761202
17771203
17781204
/*
@@ -1834,11 +1260,11 @@
18341260
struct __stat64 x = {0};
18351261
# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
18361262
/* On Windows, open first, then check the stream nature. This order
18371263
** is necessary because _stat() and sibs, when checking a named pipe,
18381264
** effectively break the pipe as its supplier sees it. */
1839
- FILE *rv = fopen(zFile, "rb");
1265
+ FILE *rv = sqlite3_fopen(zFile, "rb");
18401266
if( rv==0 ) return 0;
18411267
if( _fstat64(_fileno(rv), &x) != 0
18421268
|| !STAT_CHR_SRC(x.st_mode)){
18431269
fclose(rv);
18441270
rv = 0;
@@ -1848,11 +1274,11 @@
18481274
struct stat x = {0};
18491275
int rc = stat(zFile, &x);
18501276
# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
18511277
if( rc!=0 ) return 0;
18521278
if( STAT_CHR_SRC(x.st_mode) ){
1853
- return fopen(zFile, "rb");
1279
+ return sqlite3_fopen(zFile, "rb");
18541280
}else{
18551281
return 0;
18561282
}
18571283
#endif
18581284
#undef STAT_CHR_SRC
@@ -1875,11 +1301,11 @@
18751301
if( n+100>nLine ){
18761302
nLine = nLine*2 + 100;
18771303
zLine = realloc(zLine, nLine);
18781304
shell_check_oom(zLine);
18791305
}
1880
- if( fgets(&zLine[n], nLine - n, in)==0 ){
1306
+ if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
18811307
if( n==0 ){
18821308
free(zLine);
18831309
return 0;
18841310
}
18851311
zLine[n] = 0;
@@ -2941,11 +2367,11 @@
29412367
**
29422368
******************************************************************************
29432369
**
29442370
** This SQLite extension implements functions that compute SHA3 hashes
29452371
** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
2946
-** Two SQL functions are implemented:
2372
+** Three SQL functions are implemented:
29472373
**
29482374
** sha3(X,SIZE)
29492375
** sha3_agg(Y,SIZE)
29502376
** sha3_query(Z,SIZE)
29512377
**
@@ -3783,10 +3209,422 @@
37833209
}
37843210
return rc;
37853211
}
37863212
37873213
/************************* End ../ext/misc/shathree.c ********************/
3214
+/************************* Begin ../ext/misc/sha1.c ******************/
3215
+/*
3216
+** 2017-01-27
3217
+**
3218
+** The author disclaims copyright to this source code. In place of
3219
+** a legal notice, here is a blessing:
3220
+**
3221
+** May you do good and not evil.
3222
+** May you find forgiveness for yourself and forgive others.
3223
+** May you share freely, never taking more than you give.
3224
+**
3225
+******************************************************************************
3226
+**
3227
+** This SQLite extension implements functions that compute SHA1 hashes.
3228
+** Two SQL functions are implemented:
3229
+**
3230
+** sha1(X)
3231
+** sha1_query(Y)
3232
+**
3233
+** The sha1(X) function computes the SHA1 hash of the input X, or NULL if
3234
+** X is NULL.
3235
+**
3236
+** The sha1_query(Y) function evalutes all queries in the SQL statements of Y
3237
+** and returns a hash of their results.
3238
+*/
3239
+/* #include "sqlite3ext.h" */
3240
+SQLITE_EXTENSION_INIT1
3241
+#include <assert.h>
3242
+#include <string.h>
3243
+#include <stdarg.h>
3244
+
3245
+/******************************************************************************
3246
+** The Hash Engine
3247
+*/
3248
+/* Context for the SHA1 hash */
3249
+typedef struct SHA1Context SHA1Context;
3250
+struct SHA1Context {
3251
+ unsigned int state[5];
3252
+ unsigned int count[2];
3253
+ unsigned char buffer[64];
3254
+};
3255
+
3256
+#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
3257
+#define rol(x,k) SHA_ROT(x,k,32-(k))
3258
+#define ror(x,k) SHA_ROT(x,32-(k),k)
3259
+
3260
+#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
3261
+ |(rol(block[i],8)&0x00FF00FF))
3262
+#define blk0be(i) block[i]
3263
+#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
3264
+ ^block[(i+2)&15]^block[i&15],1))
3265
+
3266
+/*
3267
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
3268
+ *
3269
+ * Rl0() for little-endian and Rb0() for big-endian. Endianness is
3270
+ * determined at run-time.
3271
+ */
3272
+#define Rl0(v,w,x,y,z,i) \
3273
+ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
3274
+#define Rb0(v,w,x,y,z,i) \
3275
+ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
3276
+#define R1(v,w,x,y,z,i) \
3277
+ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
3278
+#define R2(v,w,x,y,z,i) \
3279
+ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
3280
+#define R3(v,w,x,y,z,i) \
3281
+ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
3282
+#define R4(v,w,x,y,z,i) \
3283
+ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
3284
+
3285
+/*
3286
+ * Hash a single 512-bit block. This is the core of the algorithm.
3287
+ */
3288
+static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
3289
+ unsigned int qq[5]; /* a, b, c, d, e; */
3290
+ static int one = 1;
3291
+ unsigned int block[16];
3292
+ memcpy(block, buffer, 64);
3293
+ memcpy(qq,state,5*sizeof(unsigned int));
3294
+
3295
+#define a qq[0]
3296
+#define b qq[1]
3297
+#define c qq[2]
3298
+#define d qq[3]
3299
+#define e qq[4]
3300
+
3301
+ /* Copy p->state[] to working vars */
3302
+ /*
3303
+ a = state[0];
3304
+ b = state[1];
3305
+ c = state[2];
3306
+ d = state[3];
3307
+ e = state[4];
3308
+ */
3309
+
3310
+ /* 4 rounds of 20 operations each. Loop unrolled. */
3311
+ if( 1 == *(unsigned char*)&one ){
3312
+ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
3313
+ Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
3314
+ Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
3315
+ Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
3316
+ }else{
3317
+ Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
3318
+ Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
3319
+ Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
3320
+ Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
3321
+ }
3322
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
3323
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
3324
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
3325
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
3326
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
3327
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
3328
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
3329
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
3330
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
3331
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
3332
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
3333
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
3334
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
3335
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
3336
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
3337
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
3338
+
3339
+ /* Add the working vars back into context.state[] */
3340
+ state[0] += a;
3341
+ state[1] += b;
3342
+ state[2] += c;
3343
+ state[3] += d;
3344
+ state[4] += e;
3345
+
3346
+#undef a
3347
+#undef b
3348
+#undef c
3349
+#undef d
3350
+#undef e
3351
+}
3352
+
3353
+
3354
+/* Initialize a SHA1 context */
3355
+static void hash_init(SHA1Context *p){
3356
+ /* SHA1 initialization constants */
3357
+ p->state[0] = 0x67452301;
3358
+ p->state[1] = 0xEFCDAB89;
3359
+ p->state[2] = 0x98BADCFE;
3360
+ p->state[3] = 0x10325476;
3361
+ p->state[4] = 0xC3D2E1F0;
3362
+ p->count[0] = p->count[1] = 0;
3363
+}
3364
+
3365
+/* Add new content to the SHA1 hash */
3366
+static void hash_step(
3367
+ SHA1Context *p, /* Add content to this context */
3368
+ const unsigned char *data, /* Data to be added */
3369
+ unsigned int len /* Number of bytes in data */
3370
+){
3371
+ unsigned int i, j;
3372
+
3373
+ j = p->count[0];
3374
+ if( (p->count[0] += len << 3) < j ){
3375
+ p->count[1] += (len>>29)+1;
3376
+ }
3377
+ j = (j >> 3) & 63;
3378
+ if( (j + len) > 63 ){
3379
+ (void)memcpy(&p->buffer[j], data, (i = 64-j));
3380
+ SHA1Transform(p->state, p->buffer);
3381
+ for(; i + 63 < len; i += 64){
3382
+ SHA1Transform(p->state, &data[i]);
3383
+ }
3384
+ j = 0;
3385
+ }else{
3386
+ i = 0;
3387
+ }
3388
+ (void)memcpy(&p->buffer[j], &data[i], len - i);
3389
+}
3390
+
3391
+/* Compute a string using sqlite3_vsnprintf() and hash it */
3392
+static void hash_step_vformat(
3393
+ SHA1Context *p, /* Add content to this context */
3394
+ const char *zFormat,
3395
+ ...
3396
+){
3397
+ va_list ap;
3398
+ int n;
3399
+ char zBuf[50];
3400
+ va_start(ap, zFormat);
3401
+ sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
3402
+ va_end(ap);
3403
+ n = (int)strlen(zBuf);
3404
+ hash_step(p, (unsigned char*)zBuf, n);
3405
+}
3406
+
3407
+
3408
+/* Add padding and compute the message digest. Render the
3409
+** message digest as lower-case hexadecimal and put it into
3410
+** zOut[]. zOut[] must be at least 41 bytes long. */
3411
+static void hash_finish(
3412
+ SHA1Context *p, /* The SHA1 context to finish and render */
3413
+ char *zOut, /* Store hex or binary hash here */
3414
+ int bAsBinary /* 1 for binary hash, 0 for hex hash */
3415
+){
3416
+ unsigned int i;
3417
+ unsigned char finalcount[8];
3418
+ unsigned char digest[20];
3419
+ static const char zEncode[] = "0123456789abcdef";
3420
+
3421
+ for (i = 0; i < 8; i++){
3422
+ finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
3423
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
3424
+ }
3425
+ hash_step(p, (const unsigned char *)"\200", 1);
3426
+ while ((p->count[0] & 504) != 448){
3427
+ hash_step(p, (const unsigned char *)"\0", 1);
3428
+ }
3429
+ hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
3430
+ for (i = 0; i < 20; i++){
3431
+ digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
3432
+ }
3433
+ if( bAsBinary ){
3434
+ memcpy(zOut, digest, 20);
3435
+ }else{
3436
+ for(i=0; i<20; i++){
3437
+ zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
3438
+ zOut[i*2+1] = zEncode[digest[i] & 0xf];
3439
+ }
3440
+ zOut[i*2]= 0;
3441
+ }
3442
+}
3443
+/* End of the hashing logic
3444
+*****************************************************************************/
3445
+
3446
+/*
3447
+** Implementation of the sha1(X) function.
3448
+**
3449
+** Return a lower-case hexadecimal rendering of the SHA1 hash of the
3450
+** argument X. If X is a BLOB, it is hashed as is. For all other
3451
+** types of input, X is converted into a UTF-8 string and the string
3452
+** is hash without the trailing 0x00 terminator. The hash of a NULL
3453
+** value is NULL.
3454
+*/
3455
+static void sha1Func(
3456
+ sqlite3_context *context,
3457
+ int argc,
3458
+ sqlite3_value **argv
3459
+){
3460
+ SHA1Context cx;
3461
+ int eType = sqlite3_value_type(argv[0]);
3462
+ int nByte = sqlite3_value_bytes(argv[0]);
3463
+ char zOut[44];
3464
+
3465
+ assert( argc==1 );
3466
+ if( eType==SQLITE_NULL ) return;
3467
+ hash_init(&cx);
3468
+ if( eType==SQLITE_BLOB ){
3469
+ hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
3470
+ }else{
3471
+ hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
3472
+ }
3473
+ if( sqlite3_user_data(context)!=0 ){
3474
+ hash_finish(&cx, zOut, 1);
3475
+ sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
3476
+ }else{
3477
+ hash_finish(&cx, zOut, 0);
3478
+ sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
3479
+ }
3480
+}
3481
+
3482
+/*
3483
+** Implementation of the sha1_query(SQL) function.
3484
+**
3485
+** This function compiles and runs the SQL statement(s) given in the
3486
+** argument. The results are hashed using SHA1 and that hash is returned.
3487
+**
3488
+** The original SQL text is included as part of the hash.
3489
+**
3490
+** The hash is not just a concatenation of the outputs. Each query
3491
+** is delimited and each row and value within the query is delimited,
3492
+** with all values being marked with their datatypes.
3493
+*/
3494
+static void sha1QueryFunc(
3495
+ sqlite3_context *context,
3496
+ int argc,
3497
+ sqlite3_value **argv
3498
+){
3499
+ sqlite3 *db = sqlite3_context_db_handle(context);
3500
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
3501
+ sqlite3_stmt *pStmt = 0;
3502
+ int nCol; /* Number of columns in the result set */
3503
+ int i; /* Loop counter */
3504
+ int rc;
3505
+ int n;
3506
+ const char *z;
3507
+ SHA1Context cx;
3508
+ char zOut[44];
3509
+
3510
+ assert( argc==1 );
3511
+ if( zSql==0 ) return;
3512
+ hash_init(&cx);
3513
+ while( zSql[0] ){
3514
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
3515
+ if( rc ){
3516
+ char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
3517
+ zSql, sqlite3_errmsg(db));
3518
+ sqlite3_finalize(pStmt);
3519
+ sqlite3_result_error(context, zMsg, -1);
3520
+ sqlite3_free(zMsg);
3521
+ return;
3522
+ }
3523
+ if( !sqlite3_stmt_readonly(pStmt) ){
3524
+ char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
3525
+ sqlite3_finalize(pStmt);
3526
+ sqlite3_result_error(context, zMsg, -1);
3527
+ sqlite3_free(zMsg);
3528
+ return;
3529
+ }
3530
+ nCol = sqlite3_column_count(pStmt);
3531
+ z = sqlite3_sql(pStmt);
3532
+ n = (int)strlen(z);
3533
+ hash_step_vformat(&cx,"S%d:",n);
3534
+ hash_step(&cx,(unsigned char*)z,n);
3535
+
3536
+ /* Compute a hash over the result of the query */
3537
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
3538
+ hash_step(&cx,(const unsigned char*)"R",1);
3539
+ for(i=0; i<nCol; i++){
3540
+ switch( sqlite3_column_type(pStmt,i) ){
3541
+ case SQLITE_NULL: {
3542
+ hash_step(&cx, (const unsigned char*)"N",1);
3543
+ break;
3544
+ }
3545
+ case SQLITE_INTEGER: {
3546
+ sqlite3_uint64 u;
3547
+ int j;
3548
+ unsigned char x[9];
3549
+ sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
3550
+ memcpy(&u, &v, 8);
3551
+ for(j=8; j>=1; j--){
3552
+ x[j] = u & 0xff;
3553
+ u >>= 8;
3554
+ }
3555
+ x[0] = 'I';
3556
+ hash_step(&cx, x, 9);
3557
+ break;
3558
+ }
3559
+ case SQLITE_FLOAT: {
3560
+ sqlite3_uint64 u;
3561
+ int j;
3562
+ unsigned char x[9];
3563
+ double r = sqlite3_column_double(pStmt,i);
3564
+ memcpy(&u, &r, 8);
3565
+ for(j=8; j>=1; j--){
3566
+ x[j] = u & 0xff;
3567
+ u >>= 8;
3568
+ }
3569
+ x[0] = 'F';
3570
+ hash_step(&cx,x,9);
3571
+ break;
3572
+ }
3573
+ case SQLITE_TEXT: {
3574
+ int n2 = sqlite3_column_bytes(pStmt, i);
3575
+ const unsigned char *z2 = sqlite3_column_text(pStmt, i);
3576
+ hash_step_vformat(&cx,"T%d:",n2);
3577
+ hash_step(&cx, z2, n2);
3578
+ break;
3579
+ }
3580
+ case SQLITE_BLOB: {
3581
+ int n2 = sqlite3_column_bytes(pStmt, i);
3582
+ const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
3583
+ hash_step_vformat(&cx,"B%d:",n2);
3584
+ hash_step(&cx, z2, n2);
3585
+ break;
3586
+ }
3587
+ }
3588
+ }
3589
+ }
3590
+ sqlite3_finalize(pStmt);
3591
+ }
3592
+ hash_finish(&cx, zOut, 0);
3593
+ sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
3594
+}
3595
+
3596
+
3597
+#ifdef _WIN32
3598
+
3599
+#endif
3600
+int sqlite3_sha_init(
3601
+ sqlite3 *db,
3602
+ char **pzErrMsg,
3603
+ const sqlite3_api_routines *pApi
3604
+){
3605
+ int rc = SQLITE_OK;
3606
+ static int one = 1;
3607
+ SQLITE_EXTENSION_INIT2(pApi);
3608
+ (void)pzErrMsg; /* Unused parameter */
3609
+ rc = sqlite3_create_function(db, "sha1", 1,
3610
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
3611
+ 0, sha1Func, 0, 0);
3612
+ if( rc==SQLITE_OK ){
3613
+ rc = sqlite3_create_function(db, "sha1b", 1,
3614
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
3615
+ (void*)&one, sha1Func, 0, 0);
3616
+ }
3617
+ if( rc==SQLITE_OK ){
3618
+ rc = sqlite3_create_function(db, "sha1_query", 1,
3619
+ SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
3620
+ sha1QueryFunc, 0, 0);
3621
+ }
3622
+ return rc;
3623
+}
3624
+
3625
+/************************* End ../ext/misc/sha1.c ********************/
37883626
/************************* Begin ../ext/misc/uint.c ******************/
37893627
/*
37903628
** 2020-04-14
37913629
**
37923630
** The author disclaims copyright to this source code. In place of
@@ -5075,11 +4913,11 @@
50754913
}else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
50764914
p->a[p->nUsed++] = y;
50774915
}else if( p->bKeepSorted ){
50784916
int i;
50794917
i = percentBinarySearch(p, y, 0);
5080
- if( i<p->nUsed ){
4918
+ if( i<(int)p->nUsed ){
50814919
memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
50824920
}
50834921
p->a[i] = y;
50844922
p->nUsed++;
50854923
}else{
@@ -5191,11 +5029,11 @@
51915029
51925030
/* Find and remove the row */
51935031
i = percentBinarySearch(p, y, 1);
51945032
if( i>=0 ){
51955033
p->nUsed--;
5196
- if( i<p->nUsed ){
5034
+ if( i<(int)p->nUsed ){
51975035
memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
51985036
}
51995037
}
52005038
}
52015039
@@ -5251,15 +5089,15 @@
52515089
sqlite3 *db,
52525090
char **pzErrMsg,
52535091
const sqlite3_api_routines *pApi
52545092
){
52555093
int rc = SQLITE_OK;
5256
- int i;
5257
-#if defined(SQLITE3_H) || defined(SQLITE_STATIC_PERCENTILE)
5258
- (void)pApi; /* Unused parameter */
5259
-#else
5094
+ unsigned int i;
5095
+#ifdef SQLITE3EXT_H
52605096
SQLITE_EXTENSION_INIT2(pApi);
5097
+#else
5098
+ (void)pApi; /* Unused parameter */
52615099
#endif
52625100
(void)pzErrMsg; /* Unused parameter */
52635101
for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
52645102
rc = sqlite3_create_window_function(db,
52655103
aPercentFunc[i].zName,
@@ -7012,50 +6850,58 @@
70126850
aIdx[4] = i;
70136851
idxNum |= 0x40;
70146852
}
70156853
continue;
70166854
}
7017
- if( pConstraint->iColumn==SERIES_COLUMN_VALUE ){
7018
- switch( op ){
7019
- case SQLITE_INDEX_CONSTRAINT_EQ:
7020
- case SQLITE_INDEX_CONSTRAINT_IS: {
7021
- idxNum |= 0x0080;
7022
- idxNum &= ~0x3300;
7023
- aIdx[5] = i;
7024
- aIdx[6] = -1;
7025
- bStartSeen = 1;
7026
- break;
7027
- }
7028
- case SQLITE_INDEX_CONSTRAINT_GE: {
7029
- if( idxNum & 0x0080 ) break;
7030
- idxNum |= 0x0100;
7031
- idxNum &= ~0x0200;
7032
- aIdx[5] = i;
7033
- bStartSeen = 1;
7034
- break;
7035
- }
7036
- case SQLITE_INDEX_CONSTRAINT_GT: {
7037
- if( idxNum & 0x0080 ) break;
7038
- idxNum |= 0x0200;
7039
- idxNum &= ~0x0100;
7040
- aIdx[5] = i;
7041
- bStartSeen = 1;
7042
- break;
7043
- }
7044
- case SQLITE_INDEX_CONSTRAINT_LE: {
7045
- if( idxNum & 0x0080 ) break;
7046
- idxNum |= 0x1000;
7047
- idxNum &= ~0x2000;
7048
- aIdx[6] = i;
7049
- break;
7050
- }
7051
- case SQLITE_INDEX_CONSTRAINT_LT: {
7052
- if( idxNum & 0x0080 ) break;
7053
- idxNum |= 0x2000;
7054
- idxNum &= ~0x1000;
7055
- aIdx[6] = i;
7056
- break;
6855
+ if( pConstraint->iColumn<SERIES_COLUMN_START ){
6856
+ if( pConstraint->iColumn==SERIES_COLUMN_VALUE && pConstraint->usable ){
6857
+ switch( op ){
6858
+ case SQLITE_INDEX_CONSTRAINT_EQ:
6859
+ case SQLITE_INDEX_CONSTRAINT_IS: {
6860
+ idxNum |= 0x0080;
6861
+ idxNum &= ~0x3300;
6862
+ aIdx[5] = i;
6863
+ aIdx[6] = -1;
6864
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
6865
+ bStartSeen = 1;
6866
+#endif
6867
+ break;
6868
+ }
6869
+ case SQLITE_INDEX_CONSTRAINT_GE: {
6870
+ if( idxNum & 0x0080 ) break;
6871
+ idxNum |= 0x0100;
6872
+ idxNum &= ~0x0200;
6873
+ aIdx[5] = i;
6874
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
6875
+ bStartSeen = 1;
6876
+#endif
6877
+ break;
6878
+ }
6879
+ case SQLITE_INDEX_CONSTRAINT_GT: {
6880
+ if( idxNum & 0x0080 ) break;
6881
+ idxNum |= 0x0200;
6882
+ idxNum &= ~0x0100;
6883
+ aIdx[5] = i;
6884
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
6885
+ bStartSeen = 1;
6886
+#endif
6887
+ break;
6888
+ }
6889
+ case SQLITE_INDEX_CONSTRAINT_LE: {
6890
+ if( idxNum & 0x0080 ) break;
6891
+ idxNum |= 0x1000;
6892
+ idxNum &= ~0x2000;
6893
+ aIdx[6] = i;
6894
+ break;
6895
+ }
6896
+ case SQLITE_INDEX_CONSTRAINT_LT: {
6897
+ if( idxNum & 0x0080 ) break;
6898
+ idxNum |= 0x2000;
6899
+ idxNum &= ~0x1000;
6900
+ aIdx[6] = i;
6901
+ break;
6902
+ }
70576903
}
70586904
}
70596905
continue;
70606906
}
70616907
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
@@ -8115,11 +7961,11 @@
81157961
** If the optional MTIME argument is present, then it is interpreted
81167962
** as an integer - the number of seconds since the unix epoch. The
81177963
** modification-time of the target file is set to this value before
81187964
** returning.
81197965
**
8120
-** If three or more arguments are passed to this function and an
7966
+** If five or more arguments are passed to this function and an
81217967
** error is encountered, an exception is raised.
81227968
**
81237969
** READFILE(FILE):
81247970
**
81257971
** Read and return the contents of file FILE (type blob) from disk.
@@ -8185,10 +8031,17 @@
81858031
# define lstat(path,buf) stat(path,buf)
81868032
#endif
81878033
#include <time.h>
81888034
#include <errno.h>
81898035
8036
+/* When used as part of the CLI, the sqlite3_stdio.h module will have
8037
+** been included before this one. In that case use the sqlite3_stdio.h
8038
+** #defines. If not, create our own for fopen().
8039
+*/
8040
+#ifndef _SQLITE3_STDIO_H_
8041
+# define sqlite3_fopen fopen
8042
+#endif
81908043
81918044
/*
81928045
** Structure of the fsdir() table-valued function
81938046
*/
81948047
/* 0 1 2 3 4 5 */
@@ -8217,11 +8070,11 @@
82178070
sqlite3_int64 nIn;
82188071
void *pBuf;
82198072
sqlite3 *db;
82208073
int mxBlob;
82218074
8222
- in = fopen(zName, "rb");
8075
+ in = sqlite3_fopen(zName, "rb");
82238076
if( in==0 ){
82248077
/* File does not exist or is unreadable. Leave the result set to NULL. */
82258078
return;
82268079
}
82278080
fseek(in, 0, SEEK_END);
@@ -8472,11 +8325,11 @@
84728325
}
84738326
}else{
84748327
sqlite3_int64 nWrite = 0;
84758328
const char *z;
84768329
int rc = 0;
8477
- FILE *out = fopen(zFile, "wb");
8330
+ FILE *out = sqlite3_fopen(zFile, "wb");
84788331
if( out==0 ) return 1;
84798332
z = (const char*)sqlite3_value_blob(pData);
84808333
if( z ){
84818334
sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
84828335
nWrite = sqlite3_value_bytes(pData);
@@ -10333,10 +10186,18 @@
1033310186
#ifndef SQLITE_NO_STDINT
1033410187
# include <stdint.h>
1033510188
#endif
1033610189
1033710190
#include <zlib.h>
10191
+
10192
+/* When used as part of the CLI, the sqlite3_stdio.h module will have
10193
+** been included before this one. In that case use the sqlite3_stdio.h
10194
+** #defines. If not, create our own for fopen().
10195
+*/
10196
+#ifndef _SQLITE3_STDIO_H_
10197
+# define sqlite3_fopen fopen
10198
+#endif
1033810199
1033910200
#ifndef SQLITE_OMIT_VIRTUALTABLE
1034010201
1034110202
#ifndef SQLITE_AMALGAMATION
1034210203
@@ -11590,11 +11451,11 @@
1159011451
}else{
1159111452
zFile = (const char*)sqlite3_value_text(argv[0]);
1159211453
}
1159311454
1159411455
if( 0==pTab->pWriteFd && 0==bInMemory ){
11595
- pCsr->pFile = zFile ? fopen(zFile, "rb") : 0;
11456
+ pCsr->pFile = zFile ? sqlite3_fopen(zFile, "rb") : 0;
1159611457
if( pCsr->pFile==0 ){
1159711458
zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
1159811459
rc = SQLITE_ERROR;
1159911460
}else{
1160011461
rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
@@ -11780,11 +11641,11 @@
1178011641
1178111642
/* Open a write fd on the file. Also load the entire central directory
1178211643
** structure into memory. During the transaction any new file data is
1178311644
** appended to the archive file, but the central directory is accumulated
1178411645
** in main-memory until the transaction is committed. */
11785
- pTab->pWriteFd = fopen(pTab->zFile, "ab+");
11646
+ pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
1178611647
if( pTab->pWriteFd==0 ){
1178711648
pTab->base.zErrMsg = sqlite3_mprintf(
1178811649
"zipfile: failed to open file %s for writing", pTab->zFile
1178911650
);
1179011651
rc = SQLITE_ERROR;
@@ -14233,10 +14094,70 @@
1423314094
}
1423414095
1423514096
return rc;
1423614097
}
1423714098
14099
+/*
14100
+** This function tests if the schema of the main database of database handle
14101
+** db contains an object named zTab. Assuming no error occurs, output parameter
14102
+** (*pbContains) is set to true if zTab exists, or false if it does not.
14103
+**
14104
+** Or, if an error occurs, an SQLite error code is returned. The final value
14105
+** of (*pbContains) is undefined in this case.
14106
+*/
14107
+static int expertDbContainsObject(
14108
+ sqlite3 *db,
14109
+ const char *zTab,
14110
+ int *pbContains /* OUT: True if object exists */
14111
+){
14112
+ const char *zSql = "SELECT 1 FROM sqlite_schema WHERE name = ?";
14113
+ sqlite3_stmt *pSql = 0;
14114
+ int rc = SQLITE_OK;
14115
+ int ret = 0;
14116
+
14117
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
14118
+ if( rc==SQLITE_OK ){
14119
+ sqlite3_bind_text(pSql, 1, zTab, -1, SQLITE_STATIC);
14120
+ if( SQLITE_ROW==sqlite3_step(pSql) ){
14121
+ ret = 1;
14122
+ }
14123
+ rc = sqlite3_finalize(pSql);
14124
+ }
14125
+
14126
+ *pbContains = ret;
14127
+ return rc;
14128
+}
14129
+
14130
+/*
14131
+** Execute SQL command zSql using database handle db. If no error occurs,
14132
+** set (*pzErr) to NULL and return SQLITE_OK.
14133
+**
14134
+** If an error does occur, return an SQLite error code and set (*pzErr) to
14135
+** point to a buffer containing an English language error message. Except,
14136
+** if the error message begins with "no such module:", then ignore the
14137
+** error and return as if the SQL statement had succeeded.
14138
+**
14139
+** This is used to copy as much of the database schema as possible while
14140
+** ignoring any errors related to missing virtual table modules.
14141
+*/
14142
+static int expertSchemaSql(sqlite3 *db, const char *zSql, char **pzErr){
14143
+ int rc = SQLITE_OK;
14144
+ char *zErr = 0;
14145
+
14146
+ rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
14147
+ if( rc!=SQLITE_OK && zErr ){
14148
+ int nErr = STRLEN(zErr);
14149
+ if( nErr>=15 && memcmp(zErr, "no such module:", 15)==0 ){
14150
+ sqlite3_free(zErr);
14151
+ rc = SQLITE_OK;
14152
+ zErr = 0;
14153
+ }
14154
+ }
14155
+
14156
+ *pzErr = zErr;
14157
+ return rc;
14158
+}
1423814159
1423914160
static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
1424014161
int rc = idxRegisterVtab(p);
1424114162
sqlite3_stmt *pSchema = 0;
1424214163
@@ -14244,30 +14165,39 @@
1424414165
**
1424514166
** 1) Add an entry to the p->pTable list, and
1424614167
** 2) Create the equivalent virtual table in dbv.
1424714168
*/
1424814169
rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
14249
- "SELECT type, name, sql, 1 FROM sqlite_schema "
14250
- "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
14170
+ "SELECT type, name, sql, 1, "
14171
+ " substr(sql,1,14)=='create virtual' COLLATE nocase "
14172
+ "FROM sqlite_schema "
14173
+ "WHERE type IN ('table','view') AND "
14174
+ " substr(name,1,7)!='sqlite_' COLLATE nocase "
1425114175
" UNION ALL "
14252
- "SELECT type, name, sql, 2 FROM sqlite_schema "
14176
+ "SELECT type, name, sql, 2, 0 FROM sqlite_schema "
1425314177
"WHERE type = 'trigger'"
1425414178
" AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
14255
- "ORDER BY 4, 1"
14179
+ "ORDER BY 4, 5 DESC, 1"
1425614180
);
1425714181
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
1425814182
const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
1425914183
const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
1426014184
const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
14185
+ int bVirtual = sqlite3_column_int(pSchema, 4);
14186
+ int bExists = 0;
1426114187
1426214188
if( zType==0 || zName==0 ) continue;
14263
- if( zType[0]=='v' || zType[1]=='r' ){
14264
- if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
14189
+ rc = expertDbContainsObject(p->dbv, zName, &bExists);
14190
+ if( rc || bExists ) continue;
14191
+
14192
+ if( zType[0]=='v' || zType[1]=='r' || bVirtual ){
14193
+ /* A view. Or a trigger on a view. */
14194
+ if( zSql ) rc = expertSchemaSql(p->dbv, zSql, pzErrmsg);
1426514195
}else{
1426614196
IdxTable *pTab;
1426714197
rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
14268
- if( rc==SQLITE_OK ){
14198
+ if( rc==SQLITE_OK && ALWAYS(pTab!=0) ){
1426914199
int i;
1427014200
char *zInner = 0;
1427114201
char *zOuter = 0;
1427214202
pTab->pNext = p->pTable;
1427314203
p->pTable = pTab;
@@ -14464,10 +14394,16 @@
1446414394
sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
1446514395
while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
1446614396
const char *zComma = zCols==0 ? "" : ", ";
1446714397
const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
1446814398
const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
14399
+ if( zName==0 ){
14400
+ /* This index contains an expression. Ignore it. */
14401
+ sqlite3_free(zCols);
14402
+ sqlite3_free(zOrder);
14403
+ return sqlite3_reset(pIndexXInfo);
14404
+ }
1446914405
zCols = idxAppendText(&rc, zCols,
1447014406
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
1447114407
zComma, zName, nCol, zName, zColl
1447214408
);
1447314409
zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
@@ -14792,16 +14728,22 @@
1479214728
1479314729
/* Copy the entire schema of database [db] into [dbm]. */
1479414730
if( rc==SQLITE_OK ){
1479514731
sqlite3_stmt *pSql = 0;
1479614732
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
14797
- "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
14798
- " AND sql NOT LIKE 'CREATE VIRTUAL %%' ORDER BY rowid"
14733
+ "SELECT sql, name, substr(sql,1,14)=='create virtual' COLLATE nocase"
14734
+ " FROM sqlite_schema WHERE substr(name,1,7)!='sqlite_' COLLATE nocase"
14735
+ " ORDER BY 3 DESC, rowid"
1479914736
);
1480014737
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
1480114738
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
14802
- if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
14739
+ const char *zName = (const char*)sqlite3_column_text(pSql, 1);
14740
+ int bExists = 0;
14741
+ rc = expertDbContainsObject(pNew->dbm, zName, &bExists);
14742
+ if( rc==SQLITE_OK && zSql && bExists==0 ){
14743
+ rc = expertSchemaSql(pNew->dbm, zSql, pzErrmsg);
14744
+ }
1480314745
}
1480414746
idxFinalize(&rc, pSql);
1480514747
}
1480614748
1480714749
/* Create the vtab schema */
@@ -16211,10 +16153,1197 @@
1621116153
}
1621216154
return rc;
1621316155
}
1621416156
1621516157
/************************* End ../ext/misc/stmtrand.c ********************/
16158
+/************************* Begin ../ext/misc/vfstrace.c ******************/
16159
+/*
16160
+** 2011 March 16
16161
+**
16162
+** The author disclaims copyright to this source code. In place of
16163
+** a legal notice, here is a blessing:
16164
+**
16165
+** May you do good and not evil.
16166
+** May you find forgiveness for yourself and forgive others.
16167
+** May you share freely, never taking more than you give.
16168
+**
16169
+******************************************************************************
16170
+**
16171
+** This file contains code implements a VFS shim that writes diagnostic
16172
+** output for each VFS call, similar to "strace".
16173
+**
16174
+** USAGE:
16175
+**
16176
+** This source file exports a single symbol which is the name of a
16177
+** function:
16178
+**
16179
+** int vfstrace_register(
16180
+** const char *zTraceName, // Name of the newly constructed VFS
16181
+** const char *zOldVfsName, // Name of the underlying VFS
16182
+** int (*xOut)(const char*,void*), // Output routine. ex: fputs
16183
+** void *pOutArg, // 2nd argument to xOut. ex: stderr
16184
+** int makeDefault // Make the new VFS the default
16185
+** );
16186
+**
16187
+** Applications that want to trace their VFS usage must provide a callback
16188
+** function with this prototype:
16189
+**
16190
+** int traceOutput(const char *zMessage, void *pAppData);
16191
+**
16192
+** This function will "output" the trace messages, where "output" can
16193
+** mean different things to different applications. The traceOutput function
16194
+** for the command-line shell (see shell.c) is "fputs" from the standard
16195
+** library, which means that all trace output is written on the stream
16196
+** specified by the second argument. In the case of the command-line shell
16197
+** the second argument is stderr. Other applications might choose to output
16198
+** trace information to a file, over a socket, or write it into a buffer.
16199
+**
16200
+** The vfstrace_register() function creates a new "shim" VFS named by
16201
+** the zTraceName parameter. A "shim" VFS is an SQLite backend that does
16202
+** not really perform the duties of a true backend, but simply filters or
16203
+** interprets VFS calls before passing them off to another VFS which does
16204
+** the actual work. In this case the other VFS - the one that does the
16205
+** real work - is identified by the second parameter, zOldVfsName. If
16206
+** the 2nd parameter is NULL then the default VFS is used. The common
16207
+** case is for the 2nd parameter to be NULL.
16208
+**
16209
+** The third and fourth parameters are the pointer to the output function
16210
+** and the second argument to the output function. For the SQLite
16211
+** command-line shell, when the -vfstrace option is used, these parameters
16212
+** are fputs and stderr, respectively.
16213
+**
16214
+** The fifth argument is true (non-zero) to cause the newly created VFS
16215
+** to become the default VFS. The common case is for the fifth parameter
16216
+** to be true.
16217
+**
16218
+** The call to vfstrace_register() simply creates the shim VFS that does
16219
+** tracing. The application must also arrange to use the new VFS for
16220
+** all database connections that are created and for which tracing is
16221
+** desired. This can be done by specifying the trace VFS using URI filename
16222
+** notation, or by specifying the trace VFS as the 4th parameter to
16223
+** sqlite3_open_v2() or by making the trace VFS be the default (by setting
16224
+** the 5th parameter of vfstrace_register() to 1).
16225
+**
16226
+**
16227
+** ENABLING VFSTRACE IN A COMMAND-LINE SHELL
16228
+**
16229
+** The SQLite command line shell implemented by the shell.c source file
16230
+** can be used with this module. To compile in -vfstrace support, first
16231
+** gather this file (test_vfstrace.c), the shell source file (shell.c),
16232
+** and the SQLite amalgamation source files (sqlite3.c, sqlite3.h) into
16233
+** the working directory. Then compile using a command like the following:
16234
+**
16235
+** gcc -o sqlite3 -Os -I. -DSQLITE_ENABLE_VFSTRACE \
16236
+** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
16237
+** -DHAVE_READLINE -DHAVE_USLEEP=1 \
16238
+** shell.c test_vfstrace.c sqlite3.c -ldl -lreadline -lncurses
16239
+**
16240
+** The gcc command above works on Linux and provides (in addition to the
16241
+** -vfstrace option) support for FTS3 and FTS4, RTREE, and command-line
16242
+** editing using the readline library. The command-line shell does not
16243
+** use threads so we added -DSQLITE_THREADSAFE=0 just to make the code
16244
+** run a little faster. For compiling on a Mac, you'll probably need
16245
+** to omit the -DHAVE_READLINE, the -lreadline, and the -lncurses options.
16246
+** The compilation could be simplified to just this:
16247
+**
16248
+** gcc -DSQLITE_ENABLE_VFSTRACE \
16249
+** shell.c test_vfstrace.c sqlite3.c -ldl -lpthread
16250
+**
16251
+** In this second example, all unnecessary options have been removed
16252
+** Note that since the code is now threadsafe, we had to add the -lpthread
16253
+** option to pull in the pthreads library.
16254
+**
16255
+** To cross-compile for windows using MinGW, a command like this might
16256
+** work:
16257
+**
16258
+** /opt/mingw/bin/i386-mingw32msvc-gcc -o sqlite3.exe -Os -I \
16259
+** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
16260
+** shell.c test_vfstrace.c sqlite3.c
16261
+**
16262
+** Similar compiler commands will work on different systems. The key
16263
+** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
16264
+** the shell.c source file will know to include the -vfstrace command-line
16265
+** option and (2) you must compile and link the three source files
16266
+** shell,c, test_vfstrace.c, and sqlite3.c.
16267
+**
16268
+** RUNTIME CONTROL OF VFSTRACE OUTPUT
16269
+**
16270
+** The application can use the "vfstrace" pragma to control which VFS
16271
+** APIs are traced. To disable all output:
16272
+**
16273
+** PRAGMA vfstrace('-all');
16274
+**
16275
+** To enable all output (which is the default setting):
16276
+**
16277
+** PRAGMA vfstrace('+all');
16278
+**
16279
+** Individual APIs can be enabled or disabled by name, with or without
16280
+** the initial "x" character. For example, to set up for tracing lock
16281
+** primatives only:
16282
+**
16283
+** PRAGMA vfstrace('-all, +Lock,Unlock,ShmLock');
16284
+**
16285
+** The argument to the vfstrace pragma ignores capitalization and any
16286
+** characters other than alphabetics, '+', and '-'.
16287
+*/
16288
+#include <stdlib.h>
16289
+#include <string.h>
16290
+/* #include "sqlite3.h" */
16291
+
16292
+/*
16293
+** An instance of this structure is attached to the each trace VFS to
16294
+** provide auxiliary information.
16295
+*/
16296
+typedef struct vfstrace_info vfstrace_info;
16297
+struct vfstrace_info {
16298
+ sqlite3_vfs *pRootVfs; /* The underlying real VFS */
16299
+ int (*xOut)(const char*, void*); /* Send output here */
16300
+ unsigned int mTrace; /* Mask of interfaces to trace */
16301
+ u8 bOn; /* Tracing on/off */
16302
+ void *pOutArg; /* First argument to xOut */
16303
+ const char *zVfsName; /* Name of this trace-VFS */
16304
+ sqlite3_vfs *pTraceVfs; /* Pointer back to the trace VFS */
16305
+};
16306
+
16307
+/*
16308
+** The sqlite3_file object for the trace VFS
16309
+*/
16310
+typedef struct vfstrace_file vfstrace_file;
16311
+struct vfstrace_file {
16312
+ sqlite3_file base; /* Base class. Must be first */
16313
+ vfstrace_info *pInfo; /* The trace-VFS to which this file belongs */
16314
+ const char *zFName; /* Base name of the file */
16315
+ sqlite3_file *pReal; /* The real underlying file */
16316
+};
16317
+
16318
+/*
16319
+** Bit values for vfstrace_info.mTrace.
16320
+*/
16321
+#define VTR_CLOSE 0x00000001
16322
+#define VTR_READ 0x00000002
16323
+#define VTR_WRITE 0x00000004
16324
+#define VTR_TRUNC 0x00000008
16325
+#define VTR_SYNC 0x00000010
16326
+#define VTR_FSIZE 0x00000020
16327
+#define VTR_LOCK 0x00000040
16328
+#define VTR_UNLOCK 0x00000080
16329
+#define VTR_CRL 0x00000100
16330
+#define VTR_FCTRL 0x00000200
16331
+#define VTR_SECSZ 0x00000400
16332
+#define VTR_DEVCHAR 0x00000800
16333
+#define VTR_SHMLOCK 0x00001000
16334
+#define VTR_SHMMAP 0x00002000
16335
+#define VTR_SHMBAR 0x00004000
16336
+#define VTR_SHMUNMAP 0x00008000
16337
+#define VTR_OPEN 0x00010000
16338
+#define VTR_DELETE 0x00020000
16339
+#define VTR_ACCESS 0x00040000
16340
+#define VTR_FULLPATH 0x00080000
16341
+#define VTR_DLOPEN 0x00100000
16342
+#define VTR_DLERR 0x00200000
16343
+#define VTR_DLSYM 0x00400000
16344
+#define VTR_DLCLOSE 0x00800000
16345
+#define VTR_RAND 0x01000000
16346
+#define VTR_SLEEP 0x02000000
16347
+#define VTR_CURTIME 0x04000000
16348
+#define VTR_LASTERR 0x08000000
16349
+
16350
+/*
16351
+** Method declarations for vfstrace_file.
16352
+*/
16353
+static int vfstraceClose(sqlite3_file*);
16354
+static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
16355
+static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
16356
+static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
16357
+static int vfstraceSync(sqlite3_file*, int flags);
16358
+static int vfstraceFileSize(sqlite3_file*, sqlite3_int64 *pSize);
16359
+static int vfstraceLock(sqlite3_file*, int);
16360
+static int vfstraceUnlock(sqlite3_file*, int);
16361
+static int vfstraceCheckReservedLock(sqlite3_file*, int *);
16362
+static int vfstraceFileControl(sqlite3_file*, int op, void *pArg);
16363
+static int vfstraceSectorSize(sqlite3_file*);
16364
+static int vfstraceDeviceCharacteristics(sqlite3_file*);
16365
+static int vfstraceShmLock(sqlite3_file*,int,int,int);
16366
+static int vfstraceShmMap(sqlite3_file*,int,int,int, void volatile **);
16367
+static void vfstraceShmBarrier(sqlite3_file*);
16368
+static int vfstraceShmUnmap(sqlite3_file*,int);
16369
+
16370
+/*
16371
+** Method declarations for vfstrace_vfs.
16372
+*/
16373
+static int vfstraceOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
16374
+static int vfstraceDelete(sqlite3_vfs*, const char *zName, int syncDir);
16375
+static int vfstraceAccess(sqlite3_vfs*, const char *zName, int flags, int *);
16376
+static int vfstraceFullPathname(sqlite3_vfs*, const char *zName, int, char *);
16377
+static void *vfstraceDlOpen(sqlite3_vfs*, const char *zFilename);
16378
+static void vfstraceDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
16379
+static void (*vfstraceDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
16380
+static void vfstraceDlClose(sqlite3_vfs*, void*);
16381
+static int vfstraceRandomness(sqlite3_vfs*, int nByte, char *zOut);
16382
+static int vfstraceSleep(sqlite3_vfs*, int microseconds);
16383
+static int vfstraceCurrentTime(sqlite3_vfs*, double*);
16384
+static int vfstraceGetLastError(sqlite3_vfs*, int, char*);
16385
+static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
16386
+static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
16387
+static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, const char *);
16388
+static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
16389
+
16390
+/*
16391
+** Return a pointer to the tail of the pathname. Examples:
16392
+**
16393
+** /home/drh/xyzzy.txt -> xyzzy.txt
16394
+** xyzzy.txt -> xyzzy.txt
16395
+*/
16396
+static const char *fileTail(const char *z){
16397
+ size_t i;
16398
+ if( z==0 ) return 0;
16399
+ i = strlen(z)-1;
16400
+ while( i>0 && z[i-1]!='/' ){ i--; }
16401
+ return &z[i];
16402
+}
16403
+
16404
+/*
16405
+** Send trace output defined by zFormat and subsequent arguments.
16406
+*/
16407
+static void vfstrace_printf(
16408
+ vfstrace_info *pInfo,
16409
+ const char *zFormat,
16410
+ ...
16411
+){
16412
+ va_list ap;
16413
+ char *zMsg;
16414
+ if( pInfo->bOn ){
16415
+ va_start(ap, zFormat);
16416
+ zMsg = sqlite3_vmprintf(zFormat, ap);
16417
+ va_end(ap);
16418
+ pInfo->xOut(zMsg, pInfo->pOutArg);
16419
+ sqlite3_free(zMsg);
16420
+ }
16421
+}
16422
+
16423
+/*
16424
+** Try to convert an error code into a symbolic name for that error code.
16425
+*/
16426
+static const char *vfstrace_errcode_name(int rc ){
16427
+ const char *zVal = 0;
16428
+ switch( rc ){
16429
+ case SQLITE_OK: zVal = "SQLITE_OK"; break;
16430
+ case SQLITE_INTERNAL: zVal = "SQLITE_INTERNAL"; break;
16431
+ case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
16432
+ case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
16433
+ case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
16434
+ case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
16435
+ case SQLITE_LOCKED: zVal = "SQLITE_LOCKED"; break;
16436
+ case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
16437
+ case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
16438
+ case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
16439
+ case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
16440
+ case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
16441
+ case SQLITE_NOTFOUND: zVal = "SQLITE_NOTFOUND"; break;
16442
+ case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
16443
+ case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
16444
+ case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
16445
+ case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
16446
+ case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
16447
+ case SQLITE_TOOBIG: zVal = "SQLITE_TOOBIG"; break;
16448
+ case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
16449
+ case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
16450
+ case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
16451
+ case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
16452
+ case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
16453
+ case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
16454
+ case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
16455
+ case SQLITE_IOERR_FSYNC: zVal = "SQLITE_IOERR_FSYNC"; break;
16456
+ case SQLITE_IOERR_DIR_FSYNC: zVal = "SQLITE_IOERR_DIR_FSYNC"; break;
16457
+ case SQLITE_IOERR_TRUNCATE: zVal = "SQLITE_IOERR_TRUNCATE"; break;
16458
+ case SQLITE_IOERR_FSTAT: zVal = "SQLITE_IOERR_FSTAT"; break;
16459
+ case SQLITE_IOERR_UNLOCK: zVal = "SQLITE_IOERR_UNLOCK"; break;
16460
+ case SQLITE_IOERR_RDLOCK: zVal = "SQLITE_IOERR_RDLOCK"; break;
16461
+ case SQLITE_IOERR_DELETE: zVal = "SQLITE_IOERR_DELETE"; break;
16462
+ case SQLITE_IOERR_BLOCKED: zVal = "SQLITE_IOERR_BLOCKED"; break;
16463
+ case SQLITE_IOERR_NOMEM: zVal = "SQLITE_IOERR_NOMEM"; break;
16464
+ case SQLITE_IOERR_ACCESS: zVal = "SQLITE_IOERR_ACCESS"; break;
16465
+ case SQLITE_IOERR_CHECKRESERVEDLOCK:
16466
+ zVal = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
16467
+ case SQLITE_IOERR_LOCK: zVal = "SQLITE_IOERR_LOCK"; break;
16468
+ case SQLITE_IOERR_CLOSE: zVal = "SQLITE_IOERR_CLOSE"; break;
16469
+ case SQLITE_IOERR_DIR_CLOSE: zVal = "SQLITE_IOERR_DIR_CLOSE"; break;
16470
+ case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
16471
+ case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
16472
+ case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
16473
+ case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
16474
+ case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
16475
+ case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
16476
+ case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
16477
+ case SQLITE_READONLY_DBMOVED: zVal = "SQLITE_READONLY_DBMOVED"; break;
16478
+ case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
16479
+ case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
16480
+ case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
16481
+ }
16482
+ return zVal;
16483
+}
16484
+
16485
+/*
16486
+** Convert value rc into a string and print it using zFormat. zFormat
16487
+** should have exactly one %s
16488
+*/
16489
+static void vfstrace_print_errcode(
16490
+ vfstrace_info *pInfo,
16491
+ const char *zFormat,
16492
+ int rc
16493
+){
16494
+ const char *zVal;
16495
+ char zBuf[50];
16496
+ zVal = vfstrace_errcode_name(rc);
16497
+ if( zVal==0 ){
16498
+ zVal = vfstrace_errcode_name(rc&0xff);
16499
+ if( zVal ){
16500
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%s | 0x%x", zVal, rc&0xffff00);
16501
+ }else{
16502
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d (0x%x)", rc, rc);
16503
+ }
16504
+ zVal = zBuf;
16505
+ }
16506
+ vfstrace_printf(pInfo, zFormat, zVal);
16507
+}
16508
+
16509
+/*
16510
+** Append to a buffer.
16511
+*/
16512
+static void strappend(char *z, int *pI, const char *zAppend){
16513
+ int i = *pI;
16514
+ while( zAppend[0] ){ z[i++] = *(zAppend++); }
16515
+ z[i] = 0;
16516
+ *pI = i;
16517
+}
16518
+
16519
+/*
16520
+** Turn tracing output on or off according to mMask.
16521
+*/
16522
+static void vfstraceOnOff(vfstrace_info *pInfo, unsigned int mMask){
16523
+ pInfo->bOn = (pInfo->mTrace & mMask)!=0;
16524
+}
16525
+
16526
+/*
16527
+** Close an vfstrace-file.
16528
+*/
16529
+static int vfstraceClose(sqlite3_file *pFile){
16530
+ vfstrace_file *p = (vfstrace_file *)pFile;
16531
+ vfstrace_info *pInfo = p->pInfo;
16532
+ int rc;
16533
+ vfstraceOnOff(pInfo, VTR_CLOSE);
16534
+ vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo->zVfsName, p->zFName);
16535
+ rc = p->pReal->pMethods->xClose(p->pReal);
16536
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16537
+ if( rc==SQLITE_OK ){
16538
+ sqlite3_free((void*)p->base.pMethods);
16539
+ p->base.pMethods = 0;
16540
+ }
16541
+ return rc;
16542
+}
16543
+
16544
+/*
16545
+** Read data from an vfstrace-file.
16546
+*/
16547
+static int vfstraceRead(
16548
+ sqlite3_file *pFile,
16549
+ void *zBuf,
16550
+ int iAmt,
16551
+ sqlite_int64 iOfst
16552
+){
16553
+ vfstrace_file *p = (vfstrace_file *)pFile;
16554
+ vfstrace_info *pInfo = p->pInfo;
16555
+ int rc;
16556
+ vfstraceOnOff(pInfo, VTR_READ);
16557
+ vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
16558
+ pInfo->zVfsName, p->zFName, iAmt, iOfst);
16559
+ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
16560
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16561
+ return rc;
16562
+}
16563
+
16564
+/*
16565
+** Write data to an vfstrace-file.
16566
+*/
16567
+static int vfstraceWrite(
16568
+ sqlite3_file *pFile,
16569
+ const void *zBuf,
16570
+ int iAmt,
16571
+ sqlite_int64 iOfst
16572
+){
16573
+ vfstrace_file *p = (vfstrace_file *)pFile;
16574
+ vfstrace_info *pInfo = p->pInfo;
16575
+ int rc;
16576
+ vfstraceOnOff(pInfo, VTR_WRITE);
16577
+ vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
16578
+ pInfo->zVfsName, p->zFName, iAmt, iOfst);
16579
+ rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
16580
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16581
+ return rc;
16582
+}
16583
+
16584
+/*
16585
+** Truncate an vfstrace-file.
16586
+*/
16587
+static int vfstraceTruncate(sqlite3_file *pFile, sqlite_int64 size){
16588
+ vfstrace_file *p = (vfstrace_file *)pFile;
16589
+ vfstrace_info *pInfo = p->pInfo;
16590
+ int rc;
16591
+ vfstraceOnOff(pInfo, VTR_TRUNC);
16592
+ vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo->zVfsName, p->zFName,
16593
+ size);
16594
+ rc = p->pReal->pMethods->xTruncate(p->pReal, size);
16595
+ vfstrace_printf(pInfo, " -> %d\n", rc);
16596
+ return rc;
16597
+}
16598
+
16599
+/*
16600
+** Sync an vfstrace-file.
16601
+*/
16602
+static int vfstraceSync(sqlite3_file *pFile, int flags){
16603
+ vfstrace_file *p = (vfstrace_file *)pFile;
16604
+ vfstrace_info *pInfo = p->pInfo;
16605
+ int rc;
16606
+ int i;
16607
+ char zBuf[100];
16608
+ memcpy(zBuf, "|0", 3);
16609
+ i = 0;
16610
+ if( flags & SQLITE_SYNC_FULL ) strappend(zBuf, &i, "|FULL");
16611
+ else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL");
16612
+ if( flags & SQLITE_SYNC_DATAONLY ) strappend(zBuf, &i, "|DATAONLY");
16613
+ if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){
16614
+ sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
16615
+ }
16616
+ vfstraceOnOff(pInfo, VTR_SYNC);
16617
+ vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName,
16618
+ &zBuf[1]);
16619
+ rc = p->pReal->pMethods->xSync(p->pReal, flags);
16620
+ vfstrace_printf(pInfo, " -> %d\n", rc);
16621
+ return rc;
16622
+}
16623
+
16624
+/*
16625
+** Return the current file-size of an vfstrace-file.
16626
+*/
16627
+static int vfstraceFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
16628
+ vfstrace_file *p = (vfstrace_file *)pFile;
16629
+ vfstrace_info *pInfo = p->pInfo;
16630
+ int rc;
16631
+ vfstraceOnOff(pInfo, VTR_FSIZE);
16632
+ vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo->zVfsName, p->zFName);
16633
+ rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
16634
+ vfstrace_print_errcode(pInfo, " -> %s,", rc);
16635
+ vfstrace_printf(pInfo, " size=%lld\n", *pSize);
16636
+ return rc;
16637
+}
16638
+
16639
+/*
16640
+** Return the name of a lock.
16641
+*/
16642
+static const char *lockName(int eLock){
16643
+ const char *azLockNames[] = {
16644
+ "NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
16645
+ };
16646
+ if( eLock<0 || eLock>=(int)(sizeof(azLockNames)/sizeof(azLockNames[0])) ){
16647
+ return "???";
16648
+ }else{
16649
+ return azLockNames[eLock];
16650
+ }
16651
+}
16652
+
16653
+/*
16654
+** Lock an vfstrace-file.
16655
+*/
16656
+static int vfstraceLock(sqlite3_file *pFile, int eLock){
16657
+ vfstrace_file *p = (vfstrace_file *)pFile;
16658
+ vfstrace_info *pInfo = p->pInfo;
16659
+ int rc;
16660
+ vfstraceOnOff(pInfo, VTR_LOCK);
16661
+ vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo->zVfsName, p->zFName,
16662
+ lockName(eLock));
16663
+ rc = p->pReal->pMethods->xLock(p->pReal, eLock);
16664
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16665
+ return rc;
16666
+}
16667
+
16668
+/*
16669
+** Unlock an vfstrace-file.
16670
+*/
16671
+static int vfstraceUnlock(sqlite3_file *pFile, int eLock){
16672
+ vfstrace_file *p = (vfstrace_file *)pFile;
16673
+ vfstrace_info *pInfo = p->pInfo;
16674
+ int rc;
16675
+ vfstraceOnOff(pInfo, VTR_UNLOCK);
16676
+ vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo->zVfsName, p->zFName,
16677
+ lockName(eLock));
16678
+ rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
16679
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16680
+ return rc;
16681
+}
16682
+
16683
+/*
16684
+** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
16685
+*/
16686
+static int vfstraceCheckReservedLock(sqlite3_file *pFile, int *pResOut){
16687
+ vfstrace_file *p = (vfstrace_file *)pFile;
16688
+ vfstrace_info *pInfo = p->pInfo;
16689
+ int rc;
16690
+ vfstraceOnOff(pInfo, VTR_CRL);
16691
+ vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)",
16692
+ pInfo->zVfsName, p->zFName);
16693
+ rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
16694
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
16695
+ vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
16696
+ return rc;
16697
+}
16698
+
16699
+/*
16700
+** File control method. For custom operations on an vfstrace-file.
16701
+*/
16702
+static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
16703
+ vfstrace_file *p = (vfstrace_file *)pFile;
16704
+ vfstrace_info *pInfo = p->pInfo;
16705
+ int rc;
16706
+ char zBuf[100];
16707
+ char zBuf2[100];
16708
+ char *zOp;
16709
+ char *zRVal = 0;
16710
+ vfstraceOnOff(pInfo, VTR_FCTRL);
16711
+ switch( op ){
16712
+ case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
16713
+ case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
16714
+ case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
16715
+ case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
16716
+ case SQLITE_FCNTL_SIZE_HINT: {
16717
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
16718
+ *(sqlite3_int64*)pArg);
16719
+ zOp = zBuf;
16720
+ break;
16721
+ }
16722
+ case SQLITE_FCNTL_CHUNK_SIZE: {
16723
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "CHUNK_SIZE,%d", *(int*)pArg);
16724
+ zOp = zBuf;
16725
+ break;
16726
+ }
16727
+ case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
16728
+ case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
16729
+ case SQLITE_FCNTL_PERSIST_WAL: {
16730
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "PERSIST_WAL,%d", *(int*)pArg);
16731
+ zOp = zBuf;
16732
+ break;
16733
+ }
16734
+ case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
16735
+ case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
16736
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break;
16737
+ case SQLITE_FCNTL_PRAGMA: {
16738
+ const char *const* a = (const char*const*)pArg;
16739
+ if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){
16740
+ const u8 *zArg = (const u8*)a[2];
16741
+ if( zArg[0]>='0' && zArg[0]<=9 ){
16742
+ pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0);
16743
+ }else{
16744
+ static const struct {
16745
+ const char *z;
16746
+ unsigned int m;
16747
+ } aKw[] = {
16748
+ { "all", 0xffffffff },
16749
+ { "close", VTR_CLOSE },
16750
+ { "read", VTR_READ },
16751
+ { "write", VTR_WRITE },
16752
+ { "truncate", VTR_TRUNC },
16753
+ { "sync", VTR_SYNC },
16754
+ { "filesize", VTR_FSIZE },
16755
+ { "lock", VTR_LOCK },
16756
+ { "unlock", VTR_UNLOCK },
16757
+ { "checkreservedlock", VTR_CRL },
16758
+ { "filecontrol", VTR_FCTRL },
16759
+ { "sectorsize", VTR_SECSZ },
16760
+ { "devicecharacteristics", VTR_DEVCHAR },
16761
+ { "shmlock", VTR_SHMLOCK },
16762
+ { "shmmap", VTR_SHMMAP },
16763
+ { "shmummap", VTR_SHMUNMAP },
16764
+ { "shmbarrier", VTR_SHMBAR },
16765
+ { "open", VTR_OPEN },
16766
+ { "delete", VTR_DELETE },
16767
+ { "access", VTR_ACCESS },
16768
+ { "fullpathname", VTR_FULLPATH },
16769
+ { "dlopen", VTR_DLOPEN },
16770
+ { "dlerror", VTR_DLERR },
16771
+ { "dlsym", VTR_DLSYM },
16772
+ { "dlclose", VTR_DLCLOSE },
16773
+ { "randomness", VTR_RAND },
16774
+ { "sleep", VTR_SLEEP },
16775
+ { "currenttime", VTR_CURTIME },
16776
+ { "currenttimeint64", VTR_CURTIME },
16777
+ { "getlasterror", VTR_LASTERR },
16778
+ };
16779
+ int onOff = 1;
16780
+ while( zArg[0] ){
16781
+ int jj, n;
16782
+ while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
16783
+ && !isalpha(zArg[0]) ) zArg++;
16784
+ if( zArg[0]==0 ) break;
16785
+ if( zArg[0]=='-' ){
16786
+ onOff = 0;
16787
+ zArg++;
16788
+ }else if( zArg[0]=='+' ){
16789
+ onOff = 1;
16790
+ zArg++;
16791
+ }
16792
+ while( !isalpha(zArg[0]) ){
16793
+ if( zArg[0]==0 ) break;
16794
+ zArg++;
16795
+ }
16796
+ if( zArg[0]=='x' && isalpha(zArg[1]) ) zArg++;
16797
+ for(n=0; isalpha(zArg[n]); n++){}
16798
+ for(jj=0; jj<(int)(sizeof(aKw)/sizeof(aKw[0])); jj++){
16799
+ if( sqlite3_strnicmp(aKw[jj].z,(const char*)zArg,n)==0 ){
16800
+ if( onOff ){
16801
+ pInfo->mTrace |= aKw[jj].m;
16802
+ }else{
16803
+ pInfo->mTrace &= ~aKw[jj].m;
16804
+ }
16805
+ break;
16806
+ }
16807
+ }
16808
+ zArg += n;
16809
+ }
16810
+ }
16811
+ }
16812
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "PRAGMA,[%s,%s]",a[1],a[2]);
16813
+ zOp = zBuf;
16814
+ break;
16815
+ }
16816
+ case SQLITE_FCNTL_BUSYHANDLER: zOp = "BUSYHANDLER"; break;
16817
+ case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
16818
+ case SQLITE_FCNTL_MMAP_SIZE: {
16819
+ sqlite3_int64 iMMap = *(sqlite3_int64*)pArg;
16820
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "MMAP_SIZE,%lld",iMMap);
16821
+ zOp = zBuf;
16822
+ break;
16823
+ }
16824
+ case SQLITE_FCNTL_TRACE: zOp = "TRACE"; break;
16825
+ case SQLITE_FCNTL_HAS_MOVED: zOp = "HAS_MOVED"; break;
16826
+ case SQLITE_FCNTL_SYNC: zOp = "SYNC"; break;
16827
+ case SQLITE_FCNTL_COMMIT_PHASETWO: zOp = "COMMIT_PHASETWO"; break;
16828
+ case SQLITE_FCNTL_WIN32_SET_HANDLE: zOp = "WIN32_SET_HANDLE"; break;
16829
+ case SQLITE_FCNTL_WAL_BLOCK: zOp = "WAL_BLOCK"; break;
16830
+ case SQLITE_FCNTL_ZIPVFS: zOp = "ZIPVFS"; break;
16831
+ case SQLITE_FCNTL_RBU: zOp = "RBU"; break;
16832
+ case SQLITE_FCNTL_VFS_POINTER: zOp = "VFS_POINTER"; break;
16833
+ case SQLITE_FCNTL_JOURNAL_POINTER: zOp = "JOURNAL_POINTER"; break;
16834
+ case SQLITE_FCNTL_WIN32_GET_HANDLE: zOp = "WIN32_GET_HANDLE"; break;
16835
+ case SQLITE_FCNTL_PDB: zOp = "PDB"; break;
16836
+ case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: zOp = "BEGIN_ATOMIC_WRITE"; break;
16837
+ case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: zOp = "COMMIT_ATOMIC_WRITE"; break;
16838
+ case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
16839
+ zOp = "ROLLBACK_ATOMIC_WRITE";
16840
+ break;
16841
+ }
16842
+ case SQLITE_FCNTL_LOCK_TIMEOUT: {
16843
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "LOCK_TIMEOUT,%d", *(int*)pArg);
16844
+ zOp = zBuf;
16845
+ break;
16846
+ }
16847
+ case SQLITE_FCNTL_DATA_VERSION: zOp = "DATA_VERSION"; break;
16848
+ case SQLITE_FCNTL_SIZE_LIMIT: zOp = "SIZE_LIMIT"; break;
16849
+ case SQLITE_FCNTL_CKPT_DONE: zOp = "CKPT_DONE"; break;
16850
+ case SQLITE_FCNTL_RESERVE_BYTES: zOp = "RESERVED_BYTES"; break;
16851
+ case SQLITE_FCNTL_CKPT_START: zOp = "CKPT_START"; break;
16852
+ case SQLITE_FCNTL_EXTERNAL_READER: zOp = "EXTERNAL_READER"; break;
16853
+ case SQLITE_FCNTL_CKSM_FILE: zOp = "CKSM_FILE"; break;
16854
+ case SQLITE_FCNTL_RESET_CACHE: zOp = "RESET_CACHE"; break;
16855
+ case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
16856
+ default: {
16857
+ sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
16858
+ zOp = zBuf;
16859
+ break;
16860
+ }
16861
+ }
16862
+ vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
16863
+ pInfo->zVfsName, p->zFName, zOp);
16864
+ rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
16865
+ if( rc==SQLITE_OK ){
16866
+ switch( op ){
16867
+ case SQLITE_FCNTL_VFSNAME: {
16868
+ *(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
16869
+ pInfo->zVfsName, *(char**)pArg);
16870
+ zRVal = *(char**)pArg;
16871
+ break;
16872
+ }
16873
+ case SQLITE_FCNTL_MMAP_SIZE: {
16874
+ sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%lld", *(sqlite3_int64*)pArg);
16875
+ zRVal = zBuf2;
16876
+ break;
16877
+ }
16878
+ case SQLITE_FCNTL_HAS_MOVED:
16879
+ case SQLITE_FCNTL_PERSIST_WAL: {
16880
+ sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%d", *(int*)pArg);
16881
+ zRVal = zBuf2;
16882
+ break;
16883
+ }
16884
+ case SQLITE_FCNTL_PRAGMA:
16885
+ case SQLITE_FCNTL_TEMPFILENAME: {
16886
+ zRVal = *(char**)pArg;
16887
+ break;
16888
+ }
16889
+ }
16890
+ }
16891
+ if( zRVal ){
16892
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
16893
+ vfstrace_printf(pInfo, ", %s\n", zRVal);
16894
+ }else{
16895
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16896
+ }
16897
+ return rc;
16898
+}
16899
+
16900
+/*
16901
+** Return the sector-size in bytes for an vfstrace-file.
16902
+*/
16903
+static int vfstraceSectorSize(sqlite3_file *pFile){
16904
+ vfstrace_file *p = (vfstrace_file *)pFile;
16905
+ vfstrace_info *pInfo = p->pInfo;
16906
+ int rc;
16907
+ vfstraceOnOff(pInfo, VTR_SECSZ);
16908
+ vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo->zVfsName, p->zFName);
16909
+ rc = p->pReal->pMethods->xSectorSize(p->pReal);
16910
+ vfstrace_printf(pInfo, " -> %d\n", rc);
16911
+ return rc;
16912
+}
16913
+
16914
+/*
16915
+** Return the device characteristic flags supported by an vfstrace-file.
16916
+*/
16917
+static int vfstraceDeviceCharacteristics(sqlite3_file *pFile){
16918
+ vfstrace_file *p = (vfstrace_file *)pFile;
16919
+ vfstrace_info *pInfo = p->pInfo;
16920
+ int rc;
16921
+ vfstraceOnOff(pInfo, VTR_DEVCHAR);
16922
+ vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
16923
+ pInfo->zVfsName, p->zFName);
16924
+ rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
16925
+ vfstrace_printf(pInfo, " -> 0x%08x\n", rc);
16926
+ return rc;
16927
+}
16928
+
16929
+/*
16930
+** Shared-memory operations.
16931
+*/
16932
+static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
16933
+ static const char *azLockName[] = {
16934
+ "WRITE",
16935
+ "CKPT",
16936
+ "RECOVER",
16937
+ "READ0",
16938
+ "READ1",
16939
+ "READ2",
16940
+ "READ3",
16941
+ "READ4",
16942
+ };
16943
+ vfstrace_file *p = (vfstrace_file *)pFile;
16944
+ vfstrace_info *pInfo = p->pInfo;
16945
+ int rc;
16946
+ char zLck[100];
16947
+ int i = 0;
16948
+ vfstraceOnOff(pInfo, VTR_SHMLOCK);
16949
+ memcpy(zLck, "|0", 3);
16950
+ if( flags & SQLITE_SHM_UNLOCK ) strappend(zLck, &i, "|UNLOCK");
16951
+ if( flags & SQLITE_SHM_LOCK ) strappend(zLck, &i, "|LOCK");
16952
+ if( flags & SQLITE_SHM_SHARED ) strappend(zLck, &i, "|SHARED");
16953
+ if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE");
16954
+ if( flags & ~(0xf) ){
16955
+ sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
16956
+ }
16957
+ if( ofst>=0 && ofst<(int)(sizeof(azLockName)/sizeof(azLockName[0])) ){
16958
+ vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d(%s),n=%d,%s)",
16959
+ pInfo->zVfsName, p->zFName, ofst, azLockName[ofst],
16960
+ n, &zLck[1]);
16961
+ }else{
16962
+ vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=5d,n=%d,%s)",
16963
+ pInfo->zVfsName, p->zFName, ofst,
16964
+ n, &zLck[1]);
16965
+ }
16966
+ rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
16967
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16968
+ return rc;
16969
+}
16970
+static int vfstraceShmMap(
16971
+ sqlite3_file *pFile,
16972
+ int iRegion,
16973
+ int szRegion,
16974
+ int isWrite,
16975
+ void volatile **pp
16976
+){
16977
+ vfstrace_file *p = (vfstrace_file *)pFile;
16978
+ vfstrace_info *pInfo = p->pInfo;
16979
+ int rc;
16980
+ vfstraceOnOff(pInfo, VTR_SHMMAP);
16981
+ vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,*)",
16982
+ pInfo->zVfsName, p->zFName, iRegion, szRegion, isWrite);
16983
+ rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
16984
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16985
+ return rc;
16986
+}
16987
+static void vfstraceShmBarrier(sqlite3_file *pFile){
16988
+ vfstrace_file *p = (vfstrace_file *)pFile;
16989
+ vfstrace_info *pInfo = p->pInfo;
16990
+ vfstraceOnOff(pInfo, VTR_SHMBAR);
16991
+ vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo->zVfsName, p->zFName);
16992
+ p->pReal->pMethods->xShmBarrier(p->pReal);
16993
+}
16994
+static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
16995
+ vfstrace_file *p = (vfstrace_file *)pFile;
16996
+ vfstrace_info *pInfo = p->pInfo;
16997
+ int rc;
16998
+ vfstraceOnOff(pInfo, VTR_SHMUNMAP);
16999
+ vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
17000
+ pInfo->zVfsName, p->zFName, delFlag);
17001
+ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
17002
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17003
+ return rc;
17004
+}
17005
+
17006
+
17007
+
17008
+/*
17009
+** Open an vfstrace file handle.
17010
+*/
17011
+static int vfstraceOpen(
17012
+ sqlite3_vfs *pVfs,
17013
+ const char *zName,
17014
+ sqlite3_file *pFile,
17015
+ int flags,
17016
+ int *pOutFlags
17017
+){
17018
+ int rc;
17019
+ vfstrace_file *p = (vfstrace_file *)pFile;
17020
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17021
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17022
+ p->pInfo = pInfo;
17023
+ p->zFName = zName ? fileTail(zName) : "<temp>";
17024
+ p->pReal = (sqlite3_file *)&p[1];
17025
+ rc = pRoot->xOpen(pRoot, zName, p->pReal, flags, pOutFlags);
17026
+ vfstraceOnOff(pInfo, VTR_OPEN);
17027
+ vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
17028
+ pInfo->zVfsName, p->zFName, flags);
17029
+ if( p->pReal->pMethods ){
17030
+ sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
17031
+ const sqlite3_io_methods *pSub = p->pReal->pMethods;
17032
+ memset(pNew, 0, sizeof(*pNew));
17033
+ pNew->iVersion = pSub->iVersion;
17034
+ pNew->xClose = vfstraceClose;
17035
+ pNew->xRead = vfstraceRead;
17036
+ pNew->xWrite = vfstraceWrite;
17037
+ pNew->xTruncate = vfstraceTruncate;
17038
+ pNew->xSync = vfstraceSync;
17039
+ pNew->xFileSize = vfstraceFileSize;
17040
+ pNew->xLock = vfstraceLock;
17041
+ pNew->xUnlock = vfstraceUnlock;
17042
+ pNew->xCheckReservedLock = vfstraceCheckReservedLock;
17043
+ pNew->xFileControl = vfstraceFileControl;
17044
+ pNew->xSectorSize = vfstraceSectorSize;
17045
+ pNew->xDeviceCharacteristics = vfstraceDeviceCharacteristics;
17046
+ if( pNew->iVersion>=2 ){
17047
+ pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
17048
+ pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
17049
+ pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
17050
+ pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
17051
+ }
17052
+ pFile->pMethods = pNew;
17053
+ }
17054
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
17055
+ if( pOutFlags ){
17056
+ vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
17057
+ }else{
17058
+ vfstrace_printf(pInfo, "\n");
17059
+ }
17060
+ return rc;
17061
+}
17062
+
17063
+/*
17064
+** Delete the file located at zPath. If the dirSync argument is true,
17065
+** ensure the file-system modifications are synced to disk before
17066
+** returning.
17067
+*/
17068
+static int vfstraceDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
17069
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17070
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17071
+ int rc;
17072
+ vfstraceOnOff(pInfo, VTR_DELETE);
17073
+ vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
17074
+ pInfo->zVfsName, zPath, dirSync);
17075
+ rc = pRoot->xDelete(pRoot, zPath, dirSync);
17076
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17077
+ return rc;
17078
+}
17079
+
17080
+/*
17081
+** Test for access permissions. Return true if the requested permission
17082
+** is available, or false otherwise.
17083
+*/
17084
+static int vfstraceAccess(
17085
+ sqlite3_vfs *pVfs,
17086
+ const char *zPath,
17087
+ int flags,
17088
+ int *pResOut
17089
+){
17090
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17091
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17092
+ int rc;
17093
+ vfstraceOnOff(pInfo, VTR_ACCESS);
17094
+ vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
17095
+ pInfo->zVfsName, zPath, flags);
17096
+ rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
17097
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
17098
+ vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
17099
+ return rc;
17100
+}
17101
+
17102
+/*
17103
+** Populate buffer zOut with the full canonical pathname corresponding
17104
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
17105
+** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
17106
+*/
17107
+static int vfstraceFullPathname(
17108
+ sqlite3_vfs *pVfs,
17109
+ const char *zPath,
17110
+ int nOut,
17111
+ char *zOut
17112
+){
17113
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17114
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17115
+ int rc;
17116
+ vfstraceOnOff(pInfo, VTR_FULLPATH);
17117
+ vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
17118
+ pInfo->zVfsName, zPath);
17119
+ rc = pRoot->xFullPathname(pRoot, zPath, nOut, zOut);
17120
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
17121
+ vfstrace_printf(pInfo, ", out=\"%.*s\"\n", nOut, zOut);
17122
+ return rc;
17123
+}
17124
+
17125
+/*
17126
+** Open the dynamic library located at zPath and return a handle.
17127
+*/
17128
+static void *vfstraceDlOpen(sqlite3_vfs *pVfs, const char *zPath){
17129
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17130
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17131
+ vfstraceOnOff(pInfo, VTR_DLOPEN);
17132
+ vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo->zVfsName, zPath);
17133
+ return pRoot->xDlOpen(pRoot, zPath);
17134
+}
17135
+
17136
+/*
17137
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
17138
+** utf-8 string describing the most recent error encountered associated
17139
+** with dynamic libraries.
17140
+*/
17141
+static void vfstraceDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
17142
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17143
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17144
+ vfstraceOnOff(pInfo, VTR_DLERR);
17145
+ vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo->zVfsName, nByte);
17146
+ pRoot->xDlError(pRoot, nByte, zErrMsg);
17147
+ vfstrace_printf(pInfo, " -> \"%s\"", zErrMsg);
17148
+}
17149
+
17150
+/*
17151
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
17152
+*/
17153
+static void (*vfstraceDlSym(sqlite3_vfs *pVfs,void *p,const char *zSym))(void){
17154
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17155
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17156
+ vfstrace_printf(pInfo, "%s.xDlSym(\"%s\")\n", pInfo->zVfsName, zSym);
17157
+ return pRoot->xDlSym(pRoot, p, zSym);
17158
+}
17159
+
17160
+/*
17161
+** Close the dynamic library handle pHandle.
17162
+*/
17163
+static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
17164
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17165
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17166
+ vfstraceOnOff(pInfo, VTR_DLCLOSE);
17167
+ vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
17168
+ pRoot->xDlClose(pRoot, pHandle);
17169
+}
17170
+
17171
+/*
17172
+** Populate the buffer pointed to by zBufOut with nByte bytes of
17173
+** random data.
17174
+*/
17175
+static int vfstraceRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
17176
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17177
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17178
+ vfstraceOnOff(pInfo, VTR_RAND);
17179
+ vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo->zVfsName, nByte);
17180
+ return pRoot->xRandomness(pRoot, nByte, zBufOut);
17181
+}
17182
+
17183
+/*
17184
+** Sleep for nMicro microseconds. Return the number of microseconds
17185
+** actually slept.
17186
+*/
17187
+static int vfstraceSleep(sqlite3_vfs *pVfs, int nMicro){
17188
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17189
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17190
+ vfstraceOnOff(pInfo, VTR_SLEEP);
17191
+ vfstrace_printf(pInfo, "%s.xSleep(%d)\n", pInfo->zVfsName, nMicro);
17192
+ return pRoot->xSleep(pRoot, nMicro);
17193
+}
17194
+
17195
+/*
17196
+** Return the current time as a Julian Day number in *pTimeOut.
17197
+*/
17198
+static int vfstraceCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
17199
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17200
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17201
+ int rc;
17202
+ vfstraceOnOff(pInfo, VTR_CURTIME);
17203
+ vfstrace_printf(pInfo, "%s.xCurrentTime()", pInfo->zVfsName);
17204
+ rc = pRoot->xCurrentTime(pRoot, pTimeOut);
17205
+ vfstrace_printf(pInfo, " -> %.17g\n", *pTimeOut);
17206
+ return rc;
17207
+}
17208
+static int vfstraceCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
17209
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17210
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17211
+ int rc;
17212
+ vfstraceOnOff(pInfo, VTR_CURTIME);
17213
+ vfstrace_printf(pInfo, "%s.xCurrentTimeInt64()", pInfo->zVfsName);
17214
+ rc = pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
17215
+ vfstrace_printf(pInfo, " -> %lld\n", *pTimeOut);
17216
+ return rc;
17217
+}
17218
+
17219
+/*
17220
+** Return the most recent error code and message
17221
+*/
17222
+static int vfstraceGetLastError(sqlite3_vfs *pVfs, int nErr, char *zErr){
17223
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17224
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17225
+ int rc;
17226
+ vfstraceOnOff(pInfo, VTR_LASTERR);
17227
+ vfstrace_printf(pInfo, "%s.xGetLastError(%d,zBuf)", pInfo->zVfsName, nErr);
17228
+ if( nErr ) zErr[0] = 0;
17229
+ rc = pRoot->xGetLastError(pRoot, nErr, zErr);
17230
+ vfstrace_printf(pInfo, " -> zBuf[] = \"%s\", rc = %d\n", nErr?zErr:"", rc);
17231
+ return rc;
17232
+}
17233
+
17234
+/*
17235
+** Override system calls.
17236
+*/
17237
+static int vfstraceSetSystemCall(
17238
+ sqlite3_vfs *pVfs,
17239
+ const char *zName,
17240
+ sqlite3_syscall_ptr pFunc
17241
+){
17242
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17243
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17244
+ return pRoot->xSetSystemCall(pRoot, zName, pFunc);
17245
+}
17246
+static sqlite3_syscall_ptr vfstraceGetSystemCall(
17247
+ sqlite3_vfs *pVfs,
17248
+ const char *zName
17249
+){
17250
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17251
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17252
+ return pRoot->xGetSystemCall(pRoot, zName);
17253
+}
17254
+static const char *vfstraceNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
17255
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17256
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
17257
+ return pRoot->xNextSystemCall(pRoot, zName);
17258
+}
17259
+
17260
+
17261
+/*
17262
+** Clients invoke this routine to construct a new trace-vfs shim.
17263
+**
17264
+** Return SQLITE_OK on success.
17265
+**
17266
+** SQLITE_NOMEM is returned in the case of a memory allocation error.
17267
+** SQLITE_NOTFOUND is returned if zOldVfsName does not exist.
17268
+*/
17269
+int vfstrace_register(
17270
+ const char *zTraceName, /* Name of the newly constructed VFS */
17271
+ const char *zOldVfsName, /* Name of the underlying VFS */
17272
+ int (*xOut)(const char*,void*), /* Output routine. ex: fputs */
17273
+ void *pOutArg, /* 2nd argument to xOut. ex: stderr */
17274
+ int makeDefault /* True to make the new VFS the default */
17275
+){
17276
+ sqlite3_vfs *pNew;
17277
+ sqlite3_vfs *pRoot;
17278
+ vfstrace_info *pInfo;
17279
+ size_t nName;
17280
+ size_t nByte;
17281
+
17282
+ pRoot = sqlite3_vfs_find(zOldVfsName);
17283
+ if( pRoot==0 ) return SQLITE_NOTFOUND;
17284
+ nName = strlen(zTraceName);
17285
+ nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
17286
+ pNew = sqlite3_malloc64( nByte );
17287
+ if( pNew==0 ) return SQLITE_NOMEM;
17288
+ memset(pNew, 0, nByte);
17289
+ pInfo = (vfstrace_info*)&pNew[1];
17290
+ pNew->iVersion = pRoot->iVersion;
17291
+ pNew->szOsFile = pRoot->szOsFile + sizeof(vfstrace_file);
17292
+ pNew->mxPathname = pRoot->mxPathname;
17293
+ pNew->zName = (char*)&pInfo[1];
17294
+ memcpy((char*)&pInfo[1], zTraceName, nName+1);
17295
+ pNew->pAppData = pInfo;
17296
+ pNew->xOpen = vfstraceOpen;
17297
+ pNew->xDelete = vfstraceDelete;
17298
+ pNew->xAccess = vfstraceAccess;
17299
+ pNew->xFullPathname = vfstraceFullPathname;
17300
+ pNew->xDlOpen = pRoot->xDlOpen==0 ? 0 : vfstraceDlOpen;
17301
+ pNew->xDlError = pRoot->xDlError==0 ? 0 : vfstraceDlError;
17302
+ pNew->xDlSym = pRoot->xDlSym==0 ? 0 : vfstraceDlSym;
17303
+ pNew->xDlClose = pRoot->xDlClose==0 ? 0 : vfstraceDlClose;
17304
+ pNew->xRandomness = vfstraceRandomness;
17305
+ pNew->xSleep = vfstraceSleep;
17306
+ pNew->xCurrentTime = vfstraceCurrentTime;
17307
+ pNew->xGetLastError = pRoot->xGetLastError==0 ? 0 : vfstraceGetLastError;
17308
+ if( pNew->iVersion>=2 ){
17309
+ pNew->xCurrentTimeInt64 = pRoot->xCurrentTimeInt64==0 ? 0 :
17310
+ vfstraceCurrentTimeInt64;
17311
+ if( pNew->iVersion>=3 ){
17312
+ pNew->xSetSystemCall = pRoot->xSetSystemCall==0 ? 0 :
17313
+ vfstraceSetSystemCall;
17314
+ pNew->xGetSystemCall = pRoot->xGetSystemCall==0 ? 0 :
17315
+ vfstraceGetSystemCall;
17316
+ pNew->xNextSystemCall = pRoot->xNextSystemCall==0 ? 0 :
17317
+ vfstraceNextSystemCall;
17318
+ }
17319
+ }
17320
+ pInfo->pRootVfs = pRoot;
17321
+ pInfo->xOut = xOut;
17322
+ pInfo->pOutArg = pOutArg;
17323
+ pInfo->zVfsName = pNew->zName;
17324
+ pInfo->pTraceVfs = pNew;
17325
+ pInfo->mTrace = 0xffffffff;
17326
+ pInfo->bOn = 1;
17327
+ vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
17328
+ pInfo->zVfsName, pRoot->zName);
17329
+ return sqlite3_vfs_register(pNew, makeDefault);
17330
+}
17331
+
17332
+/*
17333
+** Look for the named VFS. If it is a TRACEVFS, then unregister it
17334
+** and delete it.
17335
+*/
17336
+void vfstrace_unregister(const char *zTraceName){
17337
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(zTraceName);
17338
+ if( pVfs==0 ) return;
17339
+ if( pVfs->xOpen!=vfstraceOpen ) return;
17340
+ sqlite3_vfs_unregister(pVfs);
17341
+ sqlite3_free(pVfs);
17342
+}
17343
+
17344
+/************************* End ../ext/misc/vfstrace.c ********************/
1621617345
1621717346
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
1621817347
#define SQLITE_SHELL_HAVE_RECOVER 1
1621917348
#else
1622017349
#define SQLITE_SHELL_HAVE_RECOVER 0
@@ -18241,11 +19370,11 @@
1824119370
}while( strstr(z,zBuf)!=0 );
1824219371
return zBuf;
1824319372
}
1824419373
1824519374
/*
18246
-** Implementation of scalar SQL function "escape_crnl". The argument passed to
19375
+** Implementation of scalar SQL function "escape_crlf". The argument passed to
1824719376
** this function is the output of built-in function quote(). If the first
1824819377
** character of the input is "'", indicating that the value passed to quote()
1824919378
** was a text value, then this function searches the input for "\n" and "\r"
1825019379
** characters and adds a wrapper similar to the following:
1825119380
**
@@ -18252,11 +19381,11 @@
1825219381
** replace(replace(<input>, '\n', char(10), '\r', char(13));
1825319382
**
1825419383
** Or, if the first character of the input is not "'", then a copy of the input
1825519384
** is returned.
1825619385
*/
18257
-static void recoverEscapeCrnl(
19386
+static void recoverEscapeCrlf(
1825819387
sqlite3_context *context,
1825919388
int argc,
1826019389
sqlite3_value **argv
1826119390
){
1826219391
const char *zText = (const char*)sqlite3_value_text(argv[0]);
@@ -18467,11 +19596,11 @@
1846719596
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
1846819597
} aFunc[] = {
1846919598
{ "getpage", 1, recoverGetPage },
1847019599
{ "page_is_used", 1, recoverPageIsUsed },
1847119600
{ "read_i32", 2, recoverReadI32 },
18472
- { "escape_crnl", 1, recoverEscapeCrnl },
19601
+ { "escape_crlf", 1, recoverEscapeCrlf },
1847319602
};
1847419603
1847519604
const int flags = SQLITE_OPEN_URI|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
1847619605
sqlite3 *db = 0; /* New database handle */
1847719606
int ii; /* For iterating through aFunc[] */
@@ -18820,11 +19949,11 @@
1882019949
assert( pTab->aCol[ii].iField>=0 && pTab->aCol[ii].iBind>=1 );
1882119950
zSql = recoverMPrintf(p, "%z%s%Q", zSql, zSep, pTab->aCol[ii].zCol);
1882219951
1882319952
if( bSql ){
1882419953
zBind = recoverMPrintf(p,
18825
- "%z%sescape_crnl(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
19954
+ "%z%sescape_crlf(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
1882619955
);
1882719956
zSqlSep = "||', '||";
1882819957
}else{
1882919958
zBind = recoverMPrintf(p, "%z%s?%d", zBind, zSep, pTab->aCol[ii].iBind);
1883019959
}
@@ -19322,10 +20451,12 @@
1932220451
apVal[iField] = sqlite3_value_dup( pVal );
1932320452
if( apVal[iField]==0 ){
1932420453
recoverError(p, SQLITE_NOMEM, 0);
1932520454
}
1932620455
p1->nVal = iField+1;
20456
+ }else if( pTab->nCol==0 ){
20457
+ p1->nVal = pTab->nCol;
1932720458
}
1932820459
p1->iPrevCell = iCell;
1932920460
p1->iPrevPage = iPage;
1933020461
}
1933120462
}else{
@@ -20437,10 +21568,11 @@
2043721568
u8 nEqpLevel; /* Depth of the EQP output graph */
2043821569
u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
2043921570
u8 bSafeMode; /* True to prohibit unsafe operations */
2044021571
u8 bSafeModePersist; /* The long-term value of bSafeMode */
2044121572
u8 eRestoreState; /* See comments above doAutoDetectRestore() */
21573
+ u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
2044221574
ColModeOpts cmOpts; /* Option values affecting columnar mode output */
2044321575
unsigned statsOn; /* True to display memory stats before each finalize */
2044421576
unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
2044521577
int inputNesting; /* Track nesting level of .read and other redirects */
2044621578
int outCount; /* Revert to stdout when reaching zero */
@@ -20582,10 +21714,11 @@
2058221714
#define MODE_Table 15 /* MySQL-style table formatting */
2058321715
#define MODE_Box 16 /* Unicode box-drawing characters */
2058421716
#define MODE_Count 17 /* Output only a count of the rows of output */
2058521717
#define MODE_Off 18 /* No query output shown */
2058621718
#define MODE_ScanExp 19 /* Like MODE_Explain, but for ".scanstats vm" */
21719
+#define MODE_Www 20 /* Full web-page output */
2058721720
2058821721
static const char *modeDescr[] = {
2058921722
"line",
2059021723
"column",
2059121724
"list",
@@ -20602,11 +21735,13 @@
2060221735
"json",
2060321736
"markdown",
2060421737
"table",
2060521738
"box",
2060621739
"count",
20607
- "off"
21740
+ "off",
21741
+ "scanexp",
21742
+ "www",
2060821743
};
2060921744
2061021745
/*
2061121746
** These are the column/row/line separators used by the various
2061221747
** import/export modes.
@@ -20630,11 +21765,11 @@
2063021765
** A callback for the sqlite3_log() interface.
2063121766
*/
2063221767
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
2063321768
ShellState *p = (ShellState*)pArg;
2063421769
if( p->pLog==0 ) return;
20635
- sputf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
21770
+ sqlite3_fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
2063621771
fflush(p->pLog);
2063721772
}
2063821773
2063921774
/*
2064021775
** SQL function: shell_putsnl(X)
@@ -20645,13 +21780,13 @@
2064521780
static void shellPutsFunc(
2064621781
sqlite3_context *pCtx,
2064721782
int nVal,
2064821783
sqlite3_value **apVal
2064921784
){
20650
- /* Unused: (ShellState*)sqlite3_user_data(pCtx); */
21785
+ ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
2065121786
(void)nVal;
20652
- oputf("%s\n", sqlite3_value_text(apVal[0]));
21787
+ sqlite3_fprintf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
2065321788
sqlite3_result_value(pCtx, apVal[0]);
2065421789
}
2065521790
2065621791
/*
2065721792
** If in safe mode, print an error message described by the arguments
@@ -20666,11 +21801,11 @@
2066621801
va_list ap;
2066721802
char *zMsg;
2066821803
va_start(ap, zErrMsg);
2066921804
zMsg = sqlite3_vmprintf(zErrMsg, ap);
2067021805
va_end(ap);
20671
- eputf("line %d: %s\n", p->lineno, zMsg);
21806
+ sqlite3_fprintf(stderr, "line %d: %s\n", p->lineno, zMsg);
2067221807
exit(1);
2067321808
}
2067421809
}
2067521810
2067621811
/*
@@ -20699,11 +21834,11 @@
2069921834
char *zTempFile = 0;
2070021835
sqlite3 *db;
2070121836
char *zCmd = 0;
2070221837
int bBin;
2070321838
int rc;
20704
- int hasCRNL = 0;
21839
+ int hasCRLF = 0;
2070521840
FILE *f = 0;
2070621841
sqlite3_int64 sz;
2070721842
sqlite3_int64 x;
2070821843
unsigned char *p = 0;
2070921844
@@ -20733,11 +21868,11 @@
2073321868
}
2073421869
}
2073521870
bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
2073621871
/* When writing the file to be edited, do \n to \r\n conversions on systems
2073721872
** that want \r\n line endings */
20738
- f = fopen(zTempFile, bBin ? "wb" : "w");
21873
+ f = sqlite3_fopen(zTempFile, bBin ? "wb" : "w");
2073921874
if( f==0 ){
2074021875
sqlite3_result_error(context, "edit() cannot open temp file", -1);
2074121876
goto edit_func_end;
2074221877
}
2074321878
sz = sqlite3_value_bytes(argv[0]);
@@ -20744,11 +21879,11 @@
2074421879
if( bBin ){
2074521880
x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
2074621881
}else{
2074721882
const char *z = (const char*)sqlite3_value_text(argv[0]);
2074821883
/* Remember whether or not the value originally contained \r\n */
20749
- if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
21884
+ if( z && strstr(z,"\r\n")!=0 ) hasCRLF = 1;
2075021885
x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
2075121886
}
2075221887
fclose(f);
2075321888
f = 0;
2075421889
if( x!=sz ){
@@ -20764,11 +21899,11 @@
2076421899
sqlite3_free(zCmd);
2076521900
if( rc ){
2076621901
sqlite3_result_error(context, "EDITOR returned non-zero", -1);
2076721902
goto edit_func_end;
2076821903
}
20769
- f = fopen(zTempFile, "rb");
21904
+ f = sqlite3_fopen(zTempFile, "rb");
2077021905
if( f==0 ){
2077121906
sqlite3_result_error(context,
2077221907
"edit() cannot reopen temp file after edit", -1);
2077321908
goto edit_func_end;
2077421909
}
@@ -20789,11 +21924,11 @@
2078921924
}
2079021925
if( bBin ){
2079121926
sqlite3_result_blob64(context, p, sz, sqlite3_free);
2079221927
}else{
2079321928
sqlite3_int64 i, j;
20794
- if( hasCRNL ){
21929
+ if( hasCRLF ){
2079521930
/* If the original contains \r\n then do no conversions back to \n */
2079621931
}else{
2079721932
/* If the file did not originally contain \r\n then convert any new
2079821933
** \r\n back into \n */
2079921934
p[sz] = 0;
@@ -20830,15 +21965,30 @@
2083021965
p->mode = p->modePrior;
2083121966
p->shellFlgs = p->priorShFlgs;
2083221967
memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
2083321968
memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
2083421969
}
21970
+
21971
+/*
21972
+** Set output mode to text or binary for Windows.
21973
+*/
21974
+static void setCrlfMode(ShellState *p){
21975
+#ifdef _WIN32
21976
+ if( p->crlfMode ){
21977
+ sqlite3_fsetmode(p->out, _O_TEXT);
21978
+ }else{
21979
+ sqlite3_fsetmode(p->out, _O_BINARY);
21980
+ }
21981
+#else
21982
+ UNUSED_PARAMETER(p);
21983
+#endif
21984
+}
2083521985
2083621986
/*
2083721987
** Output the given string as a hex-encoded blob (eg. X'1234' )
2083821988
*/
20839
-static void output_hex_blob(const void *pBlob, int nBlob){
21989
+static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
2084021990
int i;
2084121991
unsigned char *aBlob = (unsigned char*)pBlob;
2084221992
2084321993
char *zStr = sqlite3_malloc(nBlob*2 + 1);
2084421994
shell_check_oom(zStr);
@@ -20851,11 +22001,11 @@
2085122001
zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
2085222002
zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
2085322003
}
2085422004
zStr[i*2] = '\0';
2085522005
20856
- oputf("X'%s'", zStr);
22006
+ sqlite3_fprintf(out, "X'%s'", zStr);
2085722007
sqlite3_free(zStr);
2085822008
}
2085922009
2086022010
/*
2086122011
** Find a string that is not found anywhere in z[]. Return a pointer
@@ -20881,46 +22031,40 @@
2088122031
/*
2088222032
** Output the given string as a quoted string using SQL quoting conventions.
2088322033
**
2088422034
** See also: output_quoted_escaped_string()
2088522035
*/
20886
-static void output_quoted_string(const char *z){
22036
+static void output_quoted_string(ShellState *p, const char *z){
2088722037
int i;
2088822038
char c;
20889
-#ifndef SQLITE_SHELL_FIDDLE
20890
- FILE *pfO = setOutputStream(invalidFileStream);
20891
- setBinaryMode(pfO, 1);
20892
-#endif
22039
+ FILE *out = p->out;
22040
+ sqlite3_fsetmode(out, _O_BINARY);
2089322041
if( z==0 ) return;
2089422042
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
2089522043
if( c==0 ){
20896
- oputf("'%s'",z);
22044
+ sqlite3_fprintf(out, "'%s'",z);
2089722045
}else{
20898
- oputz("'");
22046
+ sqlite3_fputs("'", out);
2089922047
while( *z ){
2090022048
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
2090122049
if( c=='\'' ) i++;
2090222050
if( i ){
20903
- oputf("%.*s", i, z);
22051
+ sqlite3_fprintf(out, "%.*s", i, z);
2090422052
z += i;
2090522053
}
2090622054
if( c=='\'' ){
20907
- oputz("'");
22055
+ sqlite3_fputs("'", out);
2090822056
continue;
2090922057
}
2091022058
if( c==0 ){
2091122059
break;
2091222060
}
2091322061
z++;
2091422062
}
20915
- oputz("'");
22063
+ sqlite3_fputs("'", out);
2091622064
}
20917
-#ifndef SQLITE_SHELL_FIDDLE
20918
- setTextMode(pfO, 1);
20919
-#else
20920
- setTextMode(stdout, 1);
20921
-#endif
22065
+ setCrlfMode(p);
2092222066
}
2092322067
2092422068
/*
2092522069
** Output the given string as a quoted string using SQL quoting conventions.
2092622070
** Additionallly , escape the "\n" and "\r" characters so that they do not
@@ -20928,20 +22072,18 @@
2092822072
** systems.
2092922073
**
2093022074
** This is like output_quoted_string() but with the addition of the \r\n
2093122075
** escape mechanism.
2093222076
*/
20933
-static void output_quoted_escaped_string(const char *z){
22077
+static void output_quoted_escaped_string(ShellState *p, const char *z){
2093422078
int i;
2093522079
char c;
20936
-#ifndef SQLITE_SHELL_FIDDLE
20937
- FILE *pfO = setOutputStream(invalidFileStream);
20938
- setBinaryMode(pfO, 1);
20939
-#endif
22080
+ FILE *out = p->out;
22081
+ sqlite3_fsetmode(out, _O_BINARY);
2094022082
for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
2094122083
if( c==0 ){
20942
- oputf("'%s'",z);
22084
+ sqlite3_fprintf(out, "'%s'",z);
2094322085
}else{
2094422086
const char *zNL = 0;
2094522087
const char *zCR = 0;
2094622088
int nNL = 0;
2094722089
int nCR = 0;
@@ -20949,52 +22091,48 @@
2094922091
for(i=0; z[i]; i++){
2095022092
if( z[i]=='\n' ) nNL++;
2095122093
if( z[i]=='\r' ) nCR++;
2095222094
}
2095322095
if( nNL ){
20954
- oputz("replace(");
22096
+ sqlite3_fputs("replace(", out);
2095522097
zNL = unused_string(z, "\\n", "\\012", zBuf1);
2095622098
}
2095722099
if( nCR ){
20958
- oputz("replace(");
22100
+ sqlite3_fputs("replace(", out);
2095922101
zCR = unused_string(z, "\\r", "\\015", zBuf2);
2096022102
}
20961
- oputz("'");
22103
+ sqlite3_fputs("'", out);
2096222104
while( *z ){
2096322105
for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
2096422106
if( c=='\'' ) i++;
2096522107
if( i ){
20966
- oputf("%.*s", i, z);
22108
+ sqlite3_fprintf(out, "%.*s", i, z);
2096722109
z += i;
2096822110
}
2096922111
if( c=='\'' ){
20970
- oputz("'");
22112
+ sqlite3_fputs("'", out);
2097122113
continue;
2097222114
}
2097322115
if( c==0 ){
2097422116
break;
2097522117
}
2097622118
z++;
2097722119
if( c=='\n' ){
20978
- oputz(zNL);
22120
+ sqlite3_fputs(zNL, out);
2097922121
continue;
2098022122
}
20981
- oputz(zCR);
22123
+ sqlite3_fputs(zCR, out);
2098222124
}
20983
- oputz("'");
22125
+ sqlite3_fputs("'", out);
2098422126
if( nCR ){
20985
- oputf(",'%s',char(13))", zCR);
22127
+ sqlite3_fprintf(out, ",'%s',char(13))", zCR);
2098622128
}
2098722129
if( nNL ){
20988
- oputf(",'%s',char(10))", zNL);
22130
+ sqlite3_fprintf(out, ",'%s',char(10))", zNL);
2098922131
}
2099022132
}
20991
-#ifndef SQLITE_SHELL_FIDDLE
20992
- setTextMode(pfO, 1);
20993
-#else
20994
- setTextMode(stdout, 1);
20995
-#endif
22133
+ setCrlfMode(p);
2099622134
}
2099722135
2099822136
/*
2099922137
** Find earliest of chars within s specified in zAny.
2100022138
** With ns == ~0, is like strpbrk(s,zAny) and s must be 0-terminated.
@@ -21010,26 +22148,64 @@
2101022148
}
2101122149
++zAny;
2101222150
}
2101322151
return pcFirst;
2101422152
}
22153
+
22154
+/* Skip over as much z[] input char sequence as is valid UTF-8,
22155
+** limited per nAccept char's or whole characters and containing
22156
+** no char cn such that ((1<<cn) & ccm)!=0. On return, the
22157
+** sequence z:return (inclusive:exclusive) is validated UTF-8.
22158
+** Limit: nAccept>=0 => char count, nAccept<0 => character
22159
+ */
22160
+const char *zSkipValidUtf8(const char *z, int nAccept, long ccm){
22161
+ int ng = (nAccept<0)? -nAccept : 0;
22162
+ const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
22163
+ assert(z!=0);
22164
+ while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
22165
+ unsigned char c = *(u8*)z;
22166
+ if( c<0x7f ){
22167
+ if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
22168
+ ++z; /* ASCII */
22169
+ }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
22170
+ else{
22171
+ const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
22172
+ do{
22173
+ if( pcLimit && zt >= pcLimit ) return z;
22174
+ else{
22175
+ char ct = *zt++;
22176
+ if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
22177
+ /* Trailing bytes are too few, too many, or invalid. */
22178
+ return z;
22179
+ }
22180
+ }
22181
+ } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
22182
+ z = zt;
22183
+ }
22184
+ }
22185
+ return z;
22186
+}
22187
+
22188
+
2101522189
/*
2101622190
** Output the given string as a quoted according to C or TCL quoting rules.
2101722191
*/
21018
-static void output_c_string(const char *z){
22192
+static void output_c_string(FILE *out, const char *z){
2101922193
char c;
2102022194
static const char *zq = "\"";
2102122195
static long ctrlMask = ~0L;
2102222196
static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */
2102322197
char ace[3] = "\\?";
2102422198
char cbsSay;
21025
- oputz(zq);
22199
+ sqlite3_fputs(zq, out);
2102622200
while( *z!=0 ){
2102722201
const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0);
2102822202
const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask);
2102922203
const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast;
21030
- if( pcEnd > z ) oputb(z, (int)(pcEnd-z));
22204
+ if( pcEnd > z ){
22205
+ sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
22206
+ }
2103122207
if( (c = *pcEnd)==0 ) break;
2103222208
++pcEnd;
2103322209
switch( c ){
2103422210
case '\\': case '"':
2103522211
cbsSay = (char)c;
@@ -21040,47 +22216,47 @@
2104022216
case '\f': cbsSay = 'f'; break;
2104122217
default: cbsSay = 0; break;
2104222218
}
2104322219
if( cbsSay ){
2104422220
ace[1] = cbsSay;
21045
- oputz(ace);
22221
+ sqlite3_fputs(ace, out);
2104622222
}else if( !isprint(c&0xff) ){
21047
- oputf("\\%03o", c&0xff);
22223
+ sqlite3_fprintf(out, "\\%03o", c&0xff);
2104822224
}else{
2104922225
ace[1] = (char)c;
21050
- oputz(ace+1);
22226
+ sqlite3_fputs(ace+1, out);
2105122227
}
2105222228
z = pcEnd;
2105322229
}
21054
- oputz(zq);
22230
+ sqlite3_fputs(zq, out);
2105522231
}
2105622232
2105722233
/*
21058
-** Output the given string as a quoted according to JSON quoting rules.
22234
+** Output the given string as quoted according to JSON quoting rules.
2105922235
*/
21060
-static void output_json_string(const char *z, i64 n){
21061
- char c;
22236
+static void output_json_string(FILE *out, const char *z, i64 n){
22237
+ unsigned char c;
2106222238
static const char *zq = "\"";
2106322239
static long ctrlMask = ~0L;
2106422240
static const char *zDQBS = "\"\\";
2106522241
const char *pcLimit;
2106622242
char ace[3] = "\\?";
2106722243
char cbsSay;
2106822244
2106922245
if( z==0 ) z = "";
2107022246
pcLimit = z + ((n<0)? strlen(z) : (size_t)n);
21071
- oputz(zq);
22247
+ sqlite3_fputs(zq, out);
2107222248
while( z < pcLimit ){
2107322249
const char *pcDQBS = anyOfInStr(z, zDQBS, pcLimit-z);
2107422250
const char *pcPast = zSkipValidUtf8(z, (int)(pcLimit-z), ctrlMask);
2107522251
const char *pcEnd = (pcDQBS && pcDQBS < pcPast)? pcDQBS : pcPast;
2107622252
if( pcEnd > z ){
21077
- oputb(z, (int)(pcEnd-z));
22253
+ sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
2107822254
z = pcEnd;
2107922255
}
2108022256
if( z >= pcLimit ) break;
21081
- c = *(z++);
22257
+ c = (unsigned char)*(z++);
2108222258
switch( c ){
2108322259
case '"': case '\\':
2108422260
cbsSay = (char)c;
2108522261
break;
2108622262
case '\b': cbsSay = 'b'; break;
@@ -21090,26 +22266,26 @@
2109022266
case '\t': cbsSay = 't'; break;
2109122267
default: cbsSay = 0; break;
2109222268
}
2109322269
if( cbsSay ){
2109422270
ace[1] = cbsSay;
21095
- oputz(ace);
21096
- }else if( c<=0x1f ){
21097
- oputf("u%04x", c);
22271
+ sqlite3_fputs(ace, out);
22272
+ }else if( c<=0x1f || c>=0x7f ){
22273
+ sqlite3_fprintf(out, "\\u%04x", c);
2109822274
}else{
2109922275
ace[1] = (char)c;
21100
- oputz(ace+1);
22276
+ sqlite3_fputs(ace+1, out);
2110122277
}
2110222278
}
21103
- oputz(zq);
22279
+ sqlite3_fputs(zq, out);
2110422280
}
2110522281
2110622282
/*
2110722283
** Output the given string with characters that are special to
2110822284
** HTML escaped.
2110922285
*/
21110
-static void output_html_string(const char *z){
22286
+static void output_html_string(FILE *out, const char *z){
2111122287
int i;
2111222288
if( z==0 ) z = "";
2111322289
while( *z ){
2111422290
for(i=0; z[i]
2111522291
&& z[i]!='<'
@@ -21117,22 +22293,22 @@
2111722293
&& z[i]!='>'
2111822294
&& z[i]!='\"'
2111922295
&& z[i]!='\'';
2112022296
i++){}
2112122297
if( i>0 ){
21122
- oputf("%.*s",i,z);
22298
+ sqlite3_fprintf(out, "%.*s",i,z);
2112322299
}
2112422300
if( z[i]=='<' ){
21125
- oputz("&lt;");
22301
+ sqlite3_fputs("&lt;", out);
2112622302
}else if( z[i]=='&' ){
21127
- oputz("&amp;");
22303
+ sqlite3_fputs("&amp;", out);
2112822304
}else if( z[i]=='>' ){
21129
- oputz("&gt;");
22305
+ sqlite3_fputs("&gt;", out);
2113022306
}else if( z[i]=='\"' ){
21131
- oputz("&quot;");
22307
+ sqlite3_fputs("&quot;", out);
2113222308
}else if( z[i]=='\'' ){
21133
- oputz("&#39;");
22309
+ sqlite3_fputs("&#39;", out);
2113422310
}else{
2113522311
break;
2113622312
}
2113722313
z += i + 1;
2113822314
}
@@ -21167,11 +22343,11 @@
2116722343
** the null value. Strings are quoted if necessary. The separator
2116822344
** is only issued if bSep is true.
2116922345
*/
2117022346
static void output_csv(ShellState *p, const char *z, int bSep){
2117122347
if( z==0 ){
21172
- oputf("%s",p->nullValue);
22348
+ sqlite3_fprintf(p->out, "%s",p->nullValue);
2117322349
}else{
2117422350
unsigned i;
2117522351
for(i=0; z[i]; i++){
2117622352
if( needCsvQuote[((unsigned char*)z)[i]] ){
2117722353
i = 0;
@@ -21179,18 +22355,18 @@
2117922355
}
2118022356
}
2118122357
if( i==0 || strstr(z, p->colSeparator)!=0 ){
2118222358
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
2118322359
shell_check_oom(zQuoted);
21184
- oputz(zQuoted);
22360
+ sqlite3_fputs(zQuoted, p->out);
2118522361
sqlite3_free(zQuoted);
2118622362
}else{
21187
- oputz(z);
22363
+ sqlite3_fputs(z, p->out);
2118822364
}
2118922365
}
2119022366
if( bSep ){
21191
- oputz(p->colSeparator);
22367
+ sqlite3_fputs(p->colSeparator, p->out);
2119222368
}
2119322369
}
2119422370
2119522371
/*
2119622372
** This routine runs when the user presses Ctrl-C
@@ -21294,20 +22470,20 @@
2129422470
const char *az[4];
2129522471
az[0] = zA1;
2129622472
az[1] = zA2;
2129722473
az[2] = zA3;
2129822474
az[3] = zA4;
21299
- oputf("authorizer: %s", azAction[op]);
22475
+ sqlite3_fprintf(p->out, "authorizer: %s", azAction[op]);
2130022476
for(i=0; i<4; i++){
21301
- oputz(" ");
22477
+ sqlite3_fputs(" ", p->out);
2130222478
if( az[i] ){
21303
- output_c_string(az[i]);
22479
+ output_c_string(p->out, az[i]);
2130422480
}else{
21305
- oputz("NULL");
22481
+ sqlite3_fputs("NULL", p->out);
2130622482
}
2130722483
}
21308
- oputz("\n");
22484
+ sqlite3_fputs("\n", p->out);
2130922485
if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
2131022486
return SQLITE_OK;
2131122487
}
2131222488
#endif
2131322489
@@ -21319,11 +22495,11 @@
2131922495
**
2132022496
** If the schema statement in z[] contains a start-of-comment and if
2132122497
** sqlite3_complete() returns false, try to terminate the comment before
2132222498
** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
2132322499
*/
21324
-static void printSchemaLine(const char *z, const char *zTail){
22500
+static void printSchemaLine(FILE *out, const char *z, const char *zTail){
2132522501
char *zToFree = 0;
2132622502
if( z==0 ) return;
2132722503
if( zTail==0 ) return;
2132822504
if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
2132922505
const char *zOrig = z;
@@ -21341,20 +22517,20 @@
2134122517
}
2134222518
sqlite3_free(zNew);
2134322519
}
2134422520
}
2134522521
if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
21346
- oputf("CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
22522
+ sqlite3_fprintf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
2134722523
}else{
21348
- oputf("%s%s", z, zTail);
22524
+ sqlite3_fprintf(out, "%s%s", z, zTail);
2134922525
}
2135022526
sqlite3_free(zToFree);
2135122527
}
21352
-static void printSchemaLineN(char *z, int n, const char *zTail){
22528
+static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
2135322529
char c = z[n];
2135422530
z[n] = 0;
21355
- printSchemaLine(z, zTail);
22531
+ printSchemaLine(out, z, zTail);
2135622532
z[n] = c;
2135722533
}
2135822534
2135922535
/*
2136022536
** Return true if string z[] has nothing but whitespace and comments to the
@@ -21378,11 +22554,11 @@
2137822554
EQPGraphRow *pNew;
2137922555
i64 nText;
2138022556
if( zText==0 ) return;
2138122557
nText = strlen(zText);
2138222558
if( p->autoEQPtest ){
21383
- oputf("%d,%d,%s\n", iEqpId, p2, zText);
22559
+ sqlite3_fprintf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
2138422560
}
2138522561
pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
2138622562
shell_check_oom(pNew);
2138722563
pNew->iEqpId = iEqpId;
2138822564
pNew->iParentId = p2;
@@ -21426,11 +22602,12 @@
2142622602
i64 n = strlen(p->sGraph.zPrefix);
2142722603
char *z;
2142822604
for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
2142922605
pNext = eqp_next_row(p, iEqpId, pRow);
2143022606
z = pRow->zText;
21431
- oputf("%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z);
22607
+ sqlite3_fprintf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
22608
+ pNext ? "|--" : "`--", z);
2143222609
if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
2143322610
memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
2143422611
eqp_render_level(p, pRow->iEqpId);
2143522612
p->sGraph.zPrefix[n] = 0;
2143622613
}
@@ -21446,17 +22623,17 @@
2144622623
if( pRow->zText[0]=='-' ){
2144722624
if( pRow->pNext==0 ){
2144822625
eqp_reset(p);
2144922626
return;
2145022627
}
21451
- oputf("%s\n", pRow->zText+3);
22628
+ sqlite3_fprintf(p->out, "%s\n", pRow->zText+3);
2145222629
p->sGraph.pRow = pRow->pNext;
2145322630
sqlite3_free(pRow);
2145422631
}else if( nCycle>0 ){
21455
- oputf("QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
22632
+ sqlite3_fprintf(p->out, "QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
2145622633
}else{
21457
- oputz("QUERY PLAN\n");
22634
+ sqlite3_fputs("QUERY PLAN\n", p->out);
2145822635
}
2145922636
p->sGraph.zPrefix[0] = 0;
2146022637
eqp_render_level(p, 0);
2146122638
eqp_reset(p);
2146222639
}
@@ -21468,33 +22645,33 @@
2146822645
*/
2146922646
static int progress_handler(void *pClientData) {
2147022647
ShellState *p = (ShellState*)pClientData;
2147122648
p->nProgress++;
2147222649
if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
21473
- oputf("Progress limit reached (%u)\n", p->nProgress);
22650
+ sqlite3_fprintf(p->out, "Progress limit reached (%u)\n", p->nProgress);
2147422651
if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
2147522652
if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
2147622653
return 1;
2147722654
}
2147822655
if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
21479
- oputf("Progress %u\n", p->nProgress);
22656
+ sqlite3_fprintf(p->out, "Progress %u\n", p->nProgress);
2148022657
}
2148122658
return 0;
2148222659
}
2148322660
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
2148422661
2148522662
/*
2148622663
** Print N dashes
2148722664
*/
21488
-static void print_dashes(int N){
22665
+static void print_dashes(FILE *out, int N){
2148922666
const char zDash[] = "--------------------------------------------------";
2149022667
const int nDash = sizeof(zDash) - 1;
2149122668
while( N>nDash ){
21492
- oputz(zDash);
22669
+ sqlite3_fputs(zDash, out);
2149322670
N -= nDash;
2149422671
}
21495
- oputf("%.*s", N, zDash);
22672
+ sqlite3_fprintf(out, "%.*s", N, zDash);
2149622673
}
2149722674
2149822675
/*
2149922676
** Print a markdown or table-style row separator using ascii-art
2150022677
*/
@@ -21503,19 +22680,19 @@
2150322680
int nArg,
2150422681
const char *zSep
2150522682
){
2150622683
int i;
2150722684
if( nArg>0 ){
21508
- oputz(zSep);
21509
- print_dashes(p->actualWidth[0]+2);
22685
+ sqlite3_fputs(zSep, p->out);
22686
+ print_dashes(p->out, p->actualWidth[0]+2);
2151022687
for(i=1; i<nArg; i++){
21511
- oputz(zSep);
21512
- print_dashes(p->actualWidth[i]+2);
22688
+ sqlite3_fputs(zSep, p->out);
22689
+ print_dashes(p->out, p->actualWidth[i]+2);
2151322690
}
21514
- oputz(zSep);
22691
+ sqlite3_fputs(zSep, p->out);
2151522692
}
21516
- oputz("\n");
22693
+ sqlite3_fputs("\n", p->out);
2151722694
}
2151822695
2151922696
/*
2152022697
** This is the callback routine that the shell
2152122698
** invokes for each row of a query result.
@@ -21541,13 +22718,13 @@
2154122718
if( azArg==0 ) break;
2154222719
for(i=0; i<nArg; i++){
2154322720
int len = strlen30(azCol[i] ? azCol[i] : "");
2154422721
if( len>w ) w = len;
2154522722
}
21546
- if( p->cnt++>0 ) oputz(p->rowSeparator);
22723
+ if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
2154722724
for(i=0; i<nArg; i++){
21548
- oputf("%*s = %s%s", w, azCol[i],
22725
+ sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
2154922726
azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
2155022727
}
2155122728
break;
2155222729
}
2155322730
case MODE_ScanExp:
@@ -21571,16 +22748,16 @@
2157122748
if( nArg>nWidth ) nArg = nWidth;
2157222749
2157322750
/* If this is the first row seen, print out the headers */
2157422751
if( p->cnt++==0 ){
2157522752
for(i=0; i<nArg; i++){
21576
- utf8_width_print(aWidth[i], azCol[ aMap[i] ]);
21577
- oputz(i==nArg-1 ? "\n" : " ");
22753
+ utf8_width_print(p->out, aWidth[i], azCol[ aMap[i] ]);
22754
+ sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
2157822755
}
2157922756
for(i=0; i<nArg; i++){
21580
- print_dashes(aWidth[i]);
21581
- oputz(i==nArg-1 ? "\n" : " ");
22757
+ print_dashes(p->out, aWidth[i]);
22758
+ sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
2158222759
}
2158322760
}
2158422761
2158522762
/* If there is no data, exit early. */
2158622763
if( azArg==0 ) break;
@@ -21594,21 +22771,21 @@
2159422771
w = strlenChar(zVal);
2159522772
zSep = " ";
2159622773
}
2159722774
if( i==iIndent && p->aiIndent && p->pStmt ){
2159822775
if( p->iIndent<p->nIndent ){
21599
- oputf("%*.s", p->aiIndent[p->iIndent], "");
22776
+ sqlite3_fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
2160022777
}
2160122778
p->iIndent++;
2160222779
}
21603
- utf8_width_print(w, zVal ? zVal : p->nullValue);
21604
- oputz(i==nArg-1 ? "\n" : zSep);
22780
+ utf8_width_print(p->out, w, zVal ? zVal : p->nullValue);
22781
+ sqlite3_fputs(i==nArg-1 ? "\n" : zSep, p->out);
2160522782
}
2160622783
break;
2160722784
}
2160822785
case MODE_Semi: { /* .schema and .fullschema output */
21609
- printSchemaLine(azArg[0], ";\n");
22786
+ printSchemaLine(p->out, azArg[0], ";\n");
2161022787
break;
2161122788
}
2161222789
case MODE_Pretty: { /* .schema and .fullschema with --indent */
2161322790
char *z;
2161422791
int j;
@@ -21619,11 +22796,11 @@
2161922796
assert( nArg==1 );
2162022797
if( azArg[0]==0 ) break;
2162122798
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
2162222799
|| sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
2162322800
){
21624
- oputf("%s;\n", azArg[0]);
22801
+ sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
2162522802
break;
2162622803
}
2162722804
z = sqlite3_mprintf("%s", azArg[0]);
2162822805
shell_check_oom(z);
2162922806
j = 0;
@@ -21652,255 +22829,265 @@
2165222829
}else if( c=='(' ){
2165322830
nParen++;
2165422831
}else if( c==')' ){
2165522832
nParen--;
2165622833
if( nLine>0 && nParen==0 && j>0 ){
21657
- printSchemaLineN(z, j, "\n");
22834
+ printSchemaLineN(p->out, z, j, "\n");
2165822835
j = 0;
2165922836
}
2166022837
}
2166122838
z[j++] = c;
2166222839
if( nParen==1 && cEnd==0
2166322840
&& (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
2166422841
){
2166522842
if( c=='\n' ) j--;
21666
- printSchemaLineN(z, j, "\n ");
22843
+ printSchemaLineN(p->out, z, j, "\n ");
2166722844
j = 0;
2166822845
nLine++;
2166922846
while( IsSpace(z[i+1]) ){ i++; }
2167022847
}
2167122848
}
2167222849
z[j] = 0;
2167322850
}
21674
- printSchemaLine(z, ";\n");
22851
+ printSchemaLine(p->out, z, ";\n");
2167522852
sqlite3_free(z);
2167622853
break;
2167722854
}
2167822855
case MODE_List: {
2167922856
if( p->cnt++==0 && p->showHeader ){
2168022857
for(i=0; i<nArg; i++){
21681
- oputf("%s%s",azCol[i], i==nArg-1 ? p->rowSeparator : p->colSeparator);
22858
+ sqlite3_fprintf(p->out, "%s%s", azCol[i],
22859
+ i==nArg-1 ? p->rowSeparator : p->colSeparator);
2168222860
}
2168322861
}
2168422862
if( azArg==0 ) break;
2168522863
for(i=0; i<nArg; i++){
2168622864
char *z = azArg[i];
2168722865
if( z==0 ) z = p->nullValue;
21688
- oputz(z);
21689
- oputz((i<nArg-1)? p->colSeparator : p->rowSeparator);
22866
+ sqlite3_fputs(z, p->out);
22867
+ sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
2169022868
}
2169122869
break;
2169222870
}
22871
+ case MODE_Www:
2169322872
case MODE_Html: {
21694
- if( p->cnt++==0 && p->showHeader ){
21695
- oputz("<TR>");
22873
+ if( p->cnt==0 && p->cMode==MODE_Www ){
22874
+ sqlite3_fputs(
22875
+ "</PRE>\n"
22876
+ "<TABLE border='1' cellspacing='0' cellpadding='2'>\n"
22877
+ ,p->out
22878
+ );
22879
+ }
22880
+ if( p->cnt==0 && (p->showHeader || p->cMode==MODE_Www) ){
22881
+ sqlite3_fputs("<TR>", p->out);
2169622882
for(i=0; i<nArg; i++){
21697
- oputz("<TH>");
21698
- output_html_string(azCol[i]);
21699
- oputz("</TH>\n");
22883
+ sqlite3_fputs("<TH>", p->out);
22884
+ output_html_string(p->out, azCol[i]);
22885
+ sqlite3_fputs("</TH>\n", p->out);
2170022886
}
21701
- oputz("</TR>\n");
22887
+ sqlite3_fputs("</TR>\n", p->out);
2170222888
}
22889
+ p->cnt++;
2170322890
if( azArg==0 ) break;
21704
- oputz("<TR>");
22891
+ sqlite3_fputs("<TR>", p->out);
2170522892
for(i=0; i<nArg; i++){
21706
- oputz("<TD>");
21707
- output_html_string(azArg[i] ? azArg[i] : p->nullValue);
21708
- oputz("</TD>\n");
22893
+ sqlite3_fputs("<TD>", p->out);
22894
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
22895
+ sqlite3_fputs("</TD>\n", p->out);
2170922896
}
21710
- oputz("</TR>\n");
22897
+ sqlite3_fputs("</TR>\n", p->out);
2171122898
break;
2171222899
}
2171322900
case MODE_Tcl: {
2171422901
if( p->cnt++==0 && p->showHeader ){
2171522902
for(i=0; i<nArg; i++){
21716
- output_c_string(azCol[i] ? azCol[i] : "");
21717
- if(i<nArg-1) oputz(p->colSeparator);
22903
+ output_c_string(p->out, azCol[i] ? azCol[i] : "");
22904
+ if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
2171822905
}
21719
- oputz(p->rowSeparator);
22906
+ sqlite3_fputs(p->rowSeparator, p->out);
2172022907
}
2172122908
if( azArg==0 ) break;
2172222909
for(i=0; i<nArg; i++){
21723
- output_c_string(azArg[i] ? azArg[i] : p->nullValue);
21724
- if(i<nArg-1) oputz(p->colSeparator);
22910
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
22911
+ if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
2172522912
}
21726
- oputz(p->rowSeparator);
22913
+ sqlite3_fputs(p->rowSeparator, p->out);
2172722914
break;
2172822915
}
2172922916
case MODE_Csv: {
21730
- setBinaryMode(p->out, 1);
22917
+ sqlite3_fsetmode(p->out, _O_BINARY);
2173122918
if( p->cnt++==0 && p->showHeader ){
2173222919
for(i=0; i<nArg; i++){
2173322920
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
2173422921
}
21735
- oputz(p->rowSeparator);
22922
+ sqlite3_fputs(p->rowSeparator, p->out);
2173622923
}
2173722924
if( nArg>0 ){
2173822925
for(i=0; i<nArg; i++){
2173922926
output_csv(p, azArg[i], i<nArg-1);
2174022927
}
21741
- oputz(p->rowSeparator);
22928
+ sqlite3_fputs(p->rowSeparator, p->out);
2174222929
}
21743
- setTextMode(p->out, 1);
22930
+ setCrlfMode(p);
2174422931
break;
2174522932
}
2174622933
case MODE_Insert: {
2174722934
if( azArg==0 ) break;
21748
- oputf("INSERT INTO %s",p->zDestTable);
22935
+ sqlite3_fprintf(p->out, "INSERT INTO %s",p->zDestTable);
2174922936
if( p->showHeader ){
21750
- oputz("(");
22937
+ sqlite3_fputs("(", p->out);
2175122938
for(i=0; i<nArg; i++){
21752
- if( i>0 ) oputz(",");
22939
+ if( i>0 ) sqlite3_fputs(",", p->out);
2175322940
if( quoteChar(azCol[i]) ){
2175422941
char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
2175522942
shell_check_oom(z);
21756
- oputz(z);
22943
+ sqlite3_fputs(z, p->out);
2175722944
sqlite3_free(z);
2175822945
}else{
21759
- oputf("%s", azCol[i]);
22946
+ sqlite3_fprintf(p->out, "%s", azCol[i]);
2176022947
}
2176122948
}
21762
- oputz(")");
22949
+ sqlite3_fputs(")", p->out);
2176322950
}
2176422951
p->cnt++;
2176522952
for(i=0; i<nArg; i++){
21766
- oputz(i>0 ? "," : " VALUES(");
22953
+ sqlite3_fputs(i>0 ? "," : " VALUES(", p->out);
2176722954
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
21768
- oputz("NULL");
22955
+ sqlite3_fputs("NULL", p->out);
2176922956
}else if( aiType && aiType[i]==SQLITE_TEXT ){
2177022957
if( ShellHasFlag(p, SHFLG_Newlines) ){
21771
- output_quoted_string(azArg[i]);
22958
+ output_quoted_string(p, azArg[i]);
2177222959
}else{
21773
- output_quoted_escaped_string(azArg[i]);
22960
+ output_quoted_escaped_string(p, azArg[i]);
2177422961
}
2177522962
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
21776
- oputz(azArg[i]);
22963
+ sqlite3_fputs(azArg[i], p->out);
2177722964
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
2177822965
char z[50];
2177922966
double r = sqlite3_column_double(p->pStmt, i);
2178022967
sqlite3_uint64 ur;
2178122968
memcpy(&ur,&r,sizeof(r));
2178222969
if( ur==0x7ff0000000000000LL ){
21783
- oputz("9.0e+999");
22970
+ sqlite3_fputs("9.0e+999", p->out);
2178422971
}else if( ur==0xfff0000000000000LL ){
21785
- oputz("-9.0e+999");
22972
+ sqlite3_fputs("-9.0e+999", p->out);
2178622973
}else{
2178722974
sqlite3_int64 ir = (sqlite3_int64)r;
2178822975
if( r==(double)ir ){
2178922976
sqlite3_snprintf(50,z,"%lld.0", ir);
2179022977
}else{
2179122978
sqlite3_snprintf(50,z,"%!.20g", r);
2179222979
}
21793
- oputz(z);
22980
+ sqlite3_fputs(z, p->out);
2179422981
}
2179522982
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2179622983
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2179722984
int nBlob = sqlite3_column_bytes(p->pStmt, i);
21798
- output_hex_blob(pBlob, nBlob);
22985
+ output_hex_blob(p->out, pBlob, nBlob);
2179922986
}else if( isNumber(azArg[i], 0) ){
21800
- oputz(azArg[i]);
22987
+ sqlite3_fputs(azArg[i], p->out);
2180122988
}else if( ShellHasFlag(p, SHFLG_Newlines) ){
21802
- output_quoted_string(azArg[i]);
22989
+ output_quoted_string(p, azArg[i]);
2180322990
}else{
21804
- output_quoted_escaped_string(azArg[i]);
22991
+ output_quoted_escaped_string(p, azArg[i]);
2180522992
}
2180622993
}
21807
- oputz(");\n");
22994
+ sqlite3_fputs(");\n", p->out);
2180822995
break;
2180922996
}
2181022997
case MODE_Json: {
2181122998
if( azArg==0 ) break;
2181222999
if( p->cnt==0 ){
21813
- fputs("[{", p->out);
23000
+ sqlite3_fputs("[{", p->out);
2181423001
}else{
21815
- fputs(",\n{", p->out);
23002
+ sqlite3_fputs(",\n{", p->out);
2181623003
}
2181723004
p->cnt++;
2181823005
for(i=0; i<nArg; i++){
21819
- output_json_string(azCol[i], -1);
21820
- oputz(":");
23006
+ output_json_string(p->out, azCol[i], -1);
23007
+ sqlite3_fputs(":", p->out);
2182123008
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
21822
- oputz("null");
23009
+ sqlite3_fputs("null", p->out);
2182323010
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
2182423011
char z[50];
2182523012
double r = sqlite3_column_double(p->pStmt, i);
2182623013
sqlite3_uint64 ur;
2182723014
memcpy(&ur,&r,sizeof(r));
2182823015
if( ur==0x7ff0000000000000LL ){
21829
- oputz("9.0e+999");
23016
+ sqlite3_fputs("9.0e+999", p->out);
2183023017
}else if( ur==0xfff0000000000000LL ){
21831
- oputz("-9.0e+999");
23018
+ sqlite3_fputs("-9.0e+999", p->out);
2183223019
}else{
2183323020
sqlite3_snprintf(50,z,"%!.20g", r);
21834
- oputz(z);
23021
+ sqlite3_fputs(z, p->out);
2183523022
}
2183623023
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2183723024
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2183823025
int nBlob = sqlite3_column_bytes(p->pStmt, i);
21839
- output_json_string(pBlob, nBlob);
23026
+ output_json_string(p->out, pBlob, nBlob);
2184023027
}else if( aiType && aiType[i]==SQLITE_TEXT ){
21841
- output_json_string(azArg[i], -1);
23028
+ output_json_string(p->out, azArg[i], -1);
2184223029
}else{
21843
- oputz(azArg[i]);
23030
+ sqlite3_fputs(azArg[i], p->out);
2184423031
}
2184523032
if( i<nArg-1 ){
21846
- oputz(",");
23033
+ sqlite3_fputs(",", p->out);
2184723034
}
2184823035
}
21849
- oputz("}");
23036
+ sqlite3_fputs("}", p->out);
2185023037
break;
2185123038
}
2185223039
case MODE_Quote: {
2185323040
if( azArg==0 ) break;
2185423041
if( p->cnt==0 && p->showHeader ){
2185523042
for(i=0; i<nArg; i++){
21856
- if( i>0 ) fputs(p->colSeparator, p->out);
21857
- output_quoted_string(azCol[i]);
23043
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23044
+ output_quoted_string(p, azCol[i]);
2185823045
}
21859
- fputs(p->rowSeparator, p->out);
23046
+ sqlite3_fputs(p->rowSeparator, p->out);
2186023047
}
2186123048
p->cnt++;
2186223049
for(i=0; i<nArg; i++){
21863
- if( i>0 ) fputs(p->colSeparator, p->out);
23050
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
2186423051
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
21865
- oputz("NULL");
23052
+ sqlite3_fputs("NULL", p->out);
2186623053
}else if( aiType && aiType[i]==SQLITE_TEXT ){
21867
- output_quoted_string(azArg[i]);
23054
+ output_quoted_string(p, azArg[i]);
2186823055
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
21869
- oputz(azArg[i]);
23056
+ sqlite3_fputs(azArg[i], p->out);
2187023057
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
2187123058
char z[50];
2187223059
double r = sqlite3_column_double(p->pStmt, i);
2187323060
sqlite3_snprintf(50,z,"%!.20g", r);
21874
- oputz(z);
23061
+ sqlite3_fputs(z, p->out);
2187523062
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2187623063
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2187723064
int nBlob = sqlite3_column_bytes(p->pStmt, i);
21878
- output_hex_blob(pBlob, nBlob);
23065
+ output_hex_blob(p->out, pBlob, nBlob);
2187923066
}else if( isNumber(azArg[i], 0) ){
21880
- oputz(azArg[i]);
23067
+ sqlite3_fputs(azArg[i], p->out);
2188123068
}else{
21882
- output_quoted_string(azArg[i]);
23069
+ output_quoted_string(p, azArg[i]);
2188323070
}
2188423071
}
21885
- fputs(p->rowSeparator, p->out);
23072
+ sqlite3_fputs(p->rowSeparator, p->out);
2188623073
break;
2188723074
}
2188823075
case MODE_Ascii: {
2188923076
if( p->cnt++==0 && p->showHeader ){
2189023077
for(i=0; i<nArg; i++){
21891
- if( i>0 ) oputz(p->colSeparator);
21892
- oputz(azCol[i] ? azCol[i] : "");
23078
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23079
+ sqlite3_fputs(azCol[i] ? azCol[i] : "", p->out);
2189323080
}
21894
- oputz(p->rowSeparator);
23081
+ sqlite3_fputs(p->rowSeparator, p->out);
2189523082
}
2189623083
if( azArg==0 ) break;
2189723084
for(i=0; i<nArg; i++){
21898
- if( i>0 ) oputz(p->colSeparator);
21899
- oputz(azArg[i] ? azArg[i] : p->nullValue);
23085
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23086
+ sqlite3_fputs(azArg[i] ? azArg[i] : p->nullValue, p->out);
2190023087
}
21901
- oputz(p->rowSeparator);
23088
+ sqlite3_fputs(p->rowSeparator, p->out);
2190223089
break;
2190323090
}
2190423091
case MODE_EQP: {
2190523092
eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
2190623093
break;
@@ -21975,11 +23162,11 @@
2197523162
"INSERT INTO selftest(tno,op,cmd,ans)"
2197623163
" SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
2197723164
"DROP TABLE [_shell$self];"
2197823165
,0,0,&zErrMsg);
2197923166
if( zErrMsg ){
21980
- eputf("SELFTEST initialization failure: %s\n", zErrMsg);
23167
+ sqlite3_fprintf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
2198123168
sqlite3_free(zErrMsg);
2198223169
}
2198323170
sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
2198423171
}
2198523172
@@ -22078,36 +23265,37 @@
2207823265
int i;
2207923266
const char *z;
2208023267
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
2208123268
if( rc!=SQLITE_OK || !pSelect ){
2208223269
char *zContext = shell_error_context(zSelect, p->db);
22083
- oputf("/**** ERROR: (%d) %s *****/\n%s",
23270
+ sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n%s",
2208423271
rc, sqlite3_errmsg(p->db), zContext);
2208523272
sqlite3_free(zContext);
2208623273
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
2208723274
return rc;
2208823275
}
2208923276
rc = sqlite3_step(pSelect);
2209023277
nResult = sqlite3_column_count(pSelect);
2209123278
while( rc==SQLITE_ROW ){
2209223279
z = (const char*)sqlite3_column_text(pSelect, 0);
22093
- oputf("%s", z);
23280
+ sqlite3_fprintf(p->out, "%s", z);
2209423281
for(i=1; i<nResult; i++){
22095
- oputf(",%s", sqlite3_column_text(pSelect, i));
23282
+ sqlite3_fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
2209623283
}
2209723284
if( z==0 ) z = "";
2209823285
while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
2209923286
if( z[0] ){
22100
- oputz("\n;\n");
23287
+ sqlite3_fputs("\n;\n", p->out);
2210123288
}else{
22102
- oputz(";\n");
23289
+ sqlite3_fputs(";\n", p->out);
2210323290
}
2210423291
rc = sqlite3_step(pSelect);
2210523292
}
2210623293
rc = sqlite3_finalize(pSelect);
2210723294
if( rc!=SQLITE_OK ){
22108
- oputf("/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
23295
+ sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n",
23296
+ rc, sqlite3_errmsg(p->db));
2210923297
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
2211023298
}
2211123299
return rc;
2211223300
}
2211323301
@@ -22139,17 +23327,17 @@
2213923327
2214023328
#ifdef __linux__
2214123329
/*
2214223330
** Attempt to display I/O stats on Linux using /proc/PID/io
2214323331
*/
22144
-static void displayLinuxIoStats(void){
23332
+static void displayLinuxIoStats(FILE *out){
2214523333
FILE *in;
2214623334
char z[200];
2214723335
sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
22148
- in = fopen(z, "rb");
23336
+ in = sqlite3_fopen(z, "rb");
2214923337
if( in==0 ) return;
22150
- while( fgets(z, sizeof(z), in)!=0 ){
23338
+ while( sqlite3_fgets(z, sizeof(z), in)!=0 ){
2215123339
static const struct {
2215223340
const char *zPattern;
2215323341
const char *zDesc;
2215423342
} aTrans[] = {
2215523343
{ "rchar: ", "Bytes received by read():" },
@@ -22162,11 +23350,11 @@
2216223350
};
2216323351
int i;
2216423352
for(i=0; i<ArraySize(aTrans); i++){
2216523353
int n = strlen30(aTrans[i].zPattern);
2216623354
if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
22167
- oputf("%-36s %s", aTrans[i].zDesc, &z[n]);
23355
+ sqlite3_fprintf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
2216823356
break;
2216923357
}
2217023358
}
2217123359
}
2217223360
fclose(in);
@@ -22175,10 +23363,11 @@
2217523363
2217623364
/*
2217723365
** Display a single line of status using 64-bit values.
2217823366
*/
2217923367
static void displayStatLine(
23368
+ FILE *out, /* Write to this channel */
2218023369
char *zLabel, /* Label for this one line */
2218123370
char *zFormat, /* Format for the result */
2218223371
int iStatusCtrl, /* Which status to display */
2218323372
int bReset /* True to reset the stats */
2218423373
){
@@ -22193,11 +23382,11 @@
2219323382
if( nPercent>1 ){
2219423383
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
2219523384
}else{
2219623385
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
2219723386
}
22198
- oputf("%-36s %s\n", zLabel, zLine);
23387
+ sqlite3_fprintf(out, "%-36s %s\n", zLabel, zLine);
2219923388
}
2220023389
2220123390
/*
2220223391
** Display memory stats.
2220323392
*/
@@ -22206,130 +23395,152 @@
2220623395
ShellState *pArg, /* Pointer to ShellState */
2220723396
int bReset /* True to reset the stats */
2220823397
){
2220923398
int iCur;
2221023399
int iHiwtr;
23400
+ FILE *out;
2221123401
if( pArg==0 || pArg->out==0 ) return 0;
23402
+ out = pArg->out;
2221223403
2221323404
if( pArg->pStmt && pArg->statsOn==2 ){
2221423405
int nCol, i, x;
2221523406
sqlite3_stmt *pStmt = pArg->pStmt;
2221623407
char z[100];
2221723408
nCol = sqlite3_column_count(pStmt);
22218
- oputf("%-36s %d\n", "Number of output columns:", nCol);
23409
+ sqlite3_fprintf(out, "%-36s %d\n", "Number of output columns:", nCol);
2221923410
for(i=0; i<nCol; i++){
2222023411
sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
22221
- oputf("%-36s %s\n", z, sqlite3_column_name(pStmt,i));
23412
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
2222223413
#ifndef SQLITE_OMIT_DECLTYPE
2222323414
sqlite3_snprintf(30, z+x, "declared type:");
22224
- oputf("%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
23415
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
2222523416
#endif
2222623417
#ifdef SQLITE_ENABLE_COLUMN_METADATA
2222723418
sqlite3_snprintf(30, z+x, "database name:");
22228
- oputf("%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
23419
+ sqlite3_fprintf(out, "%-36s %s\n", z,
23420
+ sqlite3_column_database_name(pStmt,i));
2222923421
sqlite3_snprintf(30, z+x, "table name:");
22230
- oputf("%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
23422
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
2223123423
sqlite3_snprintf(30, z+x, "origin name:");
22232
- oputf("%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
23424
+ sqlite3_fprintf(out, "%-36s %s\n", z,sqlite3_column_origin_name(pStmt,i));
2223323425
#endif
2223423426
}
2223523427
}
2223623428
2223723429
if( pArg->statsOn==3 ){
2223823430
if( pArg->pStmt ){
2223923431
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset);
22240
- oputf("VM-steps: %d\n", iCur);
23432
+ sqlite3_fprintf(out, "VM-steps: %d\n", iCur);
2224123433
}
2224223434
return 0;
2224323435
}
2224423436
22245
- displayStatLine("Memory Used:",
23437
+ displayStatLine(out, "Memory Used:",
2224623438
"%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
22247
- displayStatLine("Number of Outstanding Allocations:",
23439
+ displayStatLine(out, "Number of Outstanding Allocations:",
2224823440
"%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
2224923441
if( pArg->shellFlgs & SHFLG_Pagecache ){
22250
- displayStatLine("Number of Pcache Pages Used:",
23442
+ displayStatLine(out, "Number of Pcache Pages Used:",
2225123443
"%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
2225223444
}
22253
- displayStatLine("Number of Pcache Overflow Bytes:",
23445
+ displayStatLine(out, "Number of Pcache Overflow Bytes:",
2225423446
"%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
22255
- displayStatLine("Largest Allocation:",
23447
+ displayStatLine(out, "Largest Allocation:",
2225623448
"%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
22257
- displayStatLine("Largest Pcache Allocation:",
23449
+ displayStatLine(out, "Largest Pcache Allocation:",
2225823450
"%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
2225923451
#ifdef YYTRACKMAXSTACKDEPTH
22260
- displayStatLine("Deepest Parser Stack:",
23452
+ displayStatLine(out, "Deepest Parser Stack:",
2226123453
"%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
2226223454
#endif
2226323455
2226423456
if( db ){
2226523457
if( pArg->shellFlgs & SHFLG_Lookaside ){
2226623458
iHiwtr = iCur = -1;
2226723459
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
2226823460
&iCur, &iHiwtr, bReset);
22269
- oputf("Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
23461
+ sqlite3_fprintf(out,
23462
+ "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
2227023463
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
2227123464
&iCur, &iHiwtr, bReset);
22272
- oputf("Successful lookaside attempts: %d\n", iHiwtr);
23465
+ sqlite3_fprintf(out,
23466
+ "Successful lookaside attempts: %d\n", iHiwtr);
2227323467
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
2227423468
&iCur, &iHiwtr, bReset);
22275
- oputf("Lookaside failures due to size: %d\n", iHiwtr);
23469
+ sqlite3_fprintf(out,
23470
+ "Lookaside failures due to size: %d\n", iHiwtr);
2227623471
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
2227723472
&iCur, &iHiwtr, bReset);
22278
- oputf("Lookaside failures due to OOM: %d\n", iHiwtr);
23473
+ sqlite3_fprintf(out,
23474
+ "Lookaside failures due to OOM: %d\n", iHiwtr);
2227923475
}
2228023476
iHiwtr = iCur = -1;
2228123477
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
22282
- oputf("Pager Heap Usage: %d bytes\n", iCur);
23478
+ sqlite3_fprintf(out,
23479
+ "Pager Heap Usage: %d bytes\n", iCur);
2228323480
iHiwtr = iCur = -1;
2228423481
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
22285
- oputf("Page cache hits: %d\n", iCur);
23482
+ sqlite3_fprintf(out,
23483
+ "Page cache hits: %d\n", iCur);
2228623484
iHiwtr = iCur = -1;
2228723485
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
22288
- oputf("Page cache misses: %d\n", iCur);
23486
+ sqlite3_fprintf(out,
23487
+ "Page cache misses: %d\n", iCur);
2228923488
iHiwtr = iCur = -1;
2229023489
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
22291
- oputf("Page cache writes: %d\n", iCur);
23490
+ sqlite3_fprintf(out,
23491
+ "Page cache writes: %d\n", iCur);
2229223492
iHiwtr = iCur = -1;
2229323493
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
22294
- oputf("Page cache spills: %d\n", iCur);
23494
+ sqlite3_fprintf(out,
23495
+ "Page cache spills: %d\n", iCur);
2229523496
iHiwtr = iCur = -1;
2229623497
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
22297
- oputf("Schema Heap Usage: %d bytes\n", iCur);
23498
+ sqlite3_fprintf(out,
23499
+ "Schema Heap Usage: %d bytes\n", iCur);
2229823500
iHiwtr = iCur = -1;
2229923501
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
22300
- oputf("Statement Heap/Lookaside Usage: %d bytes\n", iCur);
23502
+ sqlite3_fprintf(out,
23503
+ "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
2230123504
}
2230223505
2230323506
if( pArg->pStmt ){
2230423507
int iHit, iMiss;
2230523508
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
2230623509
bReset);
22307
- oputf("Fullscan Steps: %d\n", iCur);
23510
+ sqlite3_fprintf(out,
23511
+ "Fullscan Steps: %d\n", iCur);
2230823512
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
22309
- oputf("Sort Operations: %d\n", iCur);
23513
+ sqlite3_fprintf(out,
23514
+ "Sort Operations: %d\n", iCur);
2231023515
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
22311
- oputf("Autoindex Inserts: %d\n", iCur);
23516
+ sqlite3_fprintf(out,
23517
+ "Autoindex Inserts: %d\n", iCur);
2231223518
iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT,
2231323519
bReset);
2231423520
iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS,
2231523521
bReset);
2231623522
if( iHit || iMiss ){
22317
- oputf("Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
23523
+ sqlite3_fprintf(out,
23524
+ "Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
2231823525
}
2231923526
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
22320
- oputf("Virtual Machine Steps: %d\n", iCur);
23527
+ sqlite3_fprintf(out,
23528
+ "Virtual Machine Steps: %d\n", iCur);
2232123529
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
22322
- oputf("Reprepare operations: %d\n", iCur);
23530
+ sqlite3_fprintf(out,
23531
+ "Reprepare operations: %d\n", iCur);
2232323532
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
22324
- oputf("Number of times run: %d\n", iCur);
23533
+ sqlite3_fprintf(out,
23534
+ "Number of times run: %d\n", iCur);
2232523535
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
22326
- oputf("Memory used by prepared stmt: %d\n", iCur);
23536
+ sqlite3_fprintf(out,
23537
+ "Memory used by prepared stmt: %d\n", iCur);
2232723538
}
2232823539
2232923540
#ifdef __linux__
22330
- displayLinuxIoStats();
23541
+ displayLinuxIoStats(pArg->out);
2233123542
#endif
2233223543
2233323544
/* Do not remove this machine readable comment: extra-stats-output-here */
2233423545
2233523546
return 0;
@@ -22721,21 +23932,21 @@
2272123932
#define BOX_1234 "\342\224\274" /* U+253c -|- */
2272223933
2272323934
/* Draw horizontal line N characters long using unicode box
2272423935
** characters
2272523936
*/
22726
-static void print_box_line(int N){
23937
+static void print_box_line(FILE *out, int N){
2272723938
const char zDash[] =
2272823939
BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
2272923940
BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
2273023941
const int nDash = sizeof(zDash) - 1;
2273123942
N *= 3;
2273223943
while( N>nDash ){
22733
- oputz(zDash);
23944
+ sqlite3_fputs(zDash, out);
2273423945
N -= nDash;
2273523946
}
22736
- oputf("%.*s", N, zDash);
23947
+ sqlite3_fprintf(out, "%.*s", N, zDash);
2273723948
}
2273823949
2273923950
/*
2274023951
** Draw a horizontal separator for a MODE_Box table.
2274123952
*/
@@ -22746,19 +23957,19 @@
2274623957
const char *zSep2,
2274723958
const char *zSep3
2274823959
){
2274923960
int i;
2275023961
if( nArg>0 ){
22751
- oputz(zSep1);
22752
- print_box_line(p->actualWidth[0]+2);
23962
+ sqlite3_fputs(zSep1, p->out);
23963
+ print_box_line(p->out, p->actualWidth[0]+2);
2275323964
for(i=1; i<nArg; i++){
22754
- oputz(zSep2);
22755
- print_box_line(p->actualWidth[i]+2);
23965
+ sqlite3_fputs(zSep2, p->out);
23966
+ print_box_line(p->out, p->actualWidth[i]+2);
2275623967
}
22757
- oputz(zSep3);
23968
+ sqlite3_fputs(zSep3, p->out);
2275823969
}
22759
- oputz("\n");
23970
+ sqlite3_fputs("\n", p->out);
2276023971
}
2276123972
2276223973
/*
2276323974
** z[] is a line of text that is to be displayed the .mode box or table or
2276423975
** similar tabular formats. z[] might contain control characters such
@@ -22788,16 +23999,26 @@
2278823999
}
2278924000
if( mxWidth<0 ) mxWidth = -mxWidth;
2279024001
if( mxWidth==0 ) mxWidth = 1000000;
2279124002
i = j = n = 0;
2279224003
while( n<mxWidth ){
22793
- if( z[i]>=' ' ){
24004
+ unsigned char c = z[i];
24005
+ if( c>=0xc0 ){
24006
+ int u;
24007
+ int len = decodeUtf8(&z[i], &u);
24008
+ i += len;
24009
+ j += len;
24010
+ n += cli_wcwidth(u);
24011
+ continue;
24012
+ }
24013
+ if( c>=' ' ){
2279424014
n++;
22795
- do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
24015
+ i++;
24016
+ j++;
2279624017
continue;
2279724018
}
22798
- if( z[i]=='\t' ){
24019
+ if( c=='\t' ){
2279924020
do{
2280024021
n++;
2280124022
j++;
2280224023
}while( (n&7)!=0 && n<mxWidth );
2280324024
i++;
@@ -22835,13 +24056,21 @@
2283524056
}
2283624057
zOut = malloc( j+1 );
2283724058
shell_check_oom(zOut);
2283824059
i = j = n = 0;
2283924060
while( i<k ){
22840
- if( z[i]>=' ' ){
24061
+ unsigned char c = z[i];
24062
+ if( c>=0xc0 ){
24063
+ int u;
24064
+ int len = decodeUtf8(&z[i], &u);
24065
+ do{ zOut[j++] = z[i++]; }while( (--len)>0 );
24066
+ n += cli_wcwidth(u);
24067
+ continue;
24068
+ }
24069
+ if( c>=' ' ){
2284124070
n++;
22842
- do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 );
24071
+ zOut[j++] = z[i++];
2284324072
continue;
2284424073
}
2284524074
if( z[i]=='\t' ){
2284624075
do{
2284724076
n++;
@@ -23017,97 +24246,99 @@
2301724246
rowSep = "\n";
2301824247
if( p->showHeader ){
2301924248
for(i=0; i<nColumn; i++){
2302024249
w = p->actualWidth[i];
2302124250
if( p->colWidth[i]<0 ) w = -w;
23022
- utf8_width_print(w, azData[i]);
23023
- fputs(i==nColumn-1?"\n":" ", p->out);
24251
+ utf8_width_print(p->out, w, azData[i]);
24252
+ sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
2302424253
}
2302524254
for(i=0; i<nColumn; i++){
23026
- print_dashes(p->actualWidth[i]);
23027
- fputs(i==nColumn-1?"\n":" ", p->out);
24255
+ print_dashes(p->out, p->actualWidth[i]);
24256
+ sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
2302824257
}
2302924258
}
2303024259
break;
2303124260
}
2303224261
case MODE_Table: {
2303324262
colSep = " | ";
2303424263
rowSep = " |\n";
2303524264
print_row_separator(p, nColumn, "+");
23036
- fputs("| ", p->out);
24265
+ sqlite3_fputs("| ", p->out);
2303724266
for(i=0; i<nColumn; i++){
2303824267
w = p->actualWidth[i];
2303924268
n = strlenChar(azData[i]);
23040
- oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
23041
- oputz(i==nColumn-1?" |\n":" | ");
24269
+ sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
24270
+ azData[i], (w-n+1)/2, "");
24271
+ sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
2304224272
}
2304324273
print_row_separator(p, nColumn, "+");
2304424274
break;
2304524275
}
2304624276
case MODE_Markdown: {
2304724277
colSep = " | ";
2304824278
rowSep = " |\n";
23049
- fputs("| ", p->out);
24279
+ sqlite3_fputs("| ", p->out);
2305024280
for(i=0; i<nColumn; i++){
2305124281
w = p->actualWidth[i];
2305224282
n = strlenChar(azData[i]);
23053
- oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
23054
- oputz(i==nColumn-1?" |\n":" | ");
24283
+ sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
24284
+ azData[i], (w-n+1)/2, "");
24285
+ sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
2305524286
}
2305624287
print_row_separator(p, nColumn, "|");
2305724288
break;
2305824289
}
2305924290
case MODE_Box: {
2306024291
colSep = " " BOX_13 " ";
2306124292
rowSep = " " BOX_13 "\n";
2306224293
print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
23063
- oputz(BOX_13 " ");
24294
+ sqlite3_fputs(BOX_13 " ", p->out);
2306424295
for(i=0; i<nColumn; i++){
2306524296
w = p->actualWidth[i];
2306624297
n = strlenChar(azData[i]);
23067
- oputf("%*s%s%*s%s",
24298
+ sqlite3_fprintf(p->out, "%*s%s%*s%s",
2306824299
(w-n)/2, "", azData[i], (w-n+1)/2, "",
2306924300
i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
2307024301
}
2307124302
print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
2307224303
break;
2307324304
}
2307424305
}
2307524306
for(i=nColumn, j=0; i<nTotal; i++, j++){
2307624307
if( j==0 && p->cMode!=MODE_Column ){
23077
- oputz(p->cMode==MODE_Box?BOX_13" ":"| ");
24308
+ sqlite3_fputs(p->cMode==MODE_Box?BOX_13" ":"| ", p->out);
2307824309
}
2307924310
z = azData[i];
2308024311
if( z==0 ) z = p->nullValue;
2308124312
w = p->actualWidth[j];
2308224313
if( p->colWidth[j]<0 ) w = -w;
23083
- utf8_width_print(w, z);
24314
+ utf8_width_print(p->out, w, z);
2308424315
if( j==nColumn-1 ){
23085
- oputz(rowSep);
24316
+ sqlite3_fputs(rowSep, p->out);
2308624317
if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
2308724318
if( p->cMode==MODE_Table ){
2308824319
print_row_separator(p, nColumn, "+");
2308924320
}else if( p->cMode==MODE_Box ){
2309024321
print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
2309124322
}else if( p->cMode==MODE_Column ){
23092
- oputz("\n");
24323
+ sqlite3_fputs("\n", p->out);
2309324324
}
2309424325
}
2309524326
j = -1;
2309624327
if( seenInterrupt ) goto columnar_end;
2309724328
}else{
23098
- oputz(colSep);
24329
+ sqlite3_fputs(colSep, p->out);
2309924330
}
2310024331
}
2310124332
if( p->cMode==MODE_Table ){
2310224333
print_row_separator(p, nColumn, "+");
2310324334
}else if( p->cMode==MODE_Box ){
2310424335
print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
2310524336
}
2310624337
columnar_end:
2310724338
if( seenInterrupt ){
23108
- oputz("Interrupt\n");
24339
+ sqlite3_fputs("Interrupt\n", p->out);
2310924340
}
2311024341
nData = (nRow+1)*nColumn;
2311124342
for(i=0; i<nData; i++){
2311224343
z = azData[i];
2311324344
if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
@@ -23190,11 +24421,13 @@
2319024421
}
2319124422
}
2319224423
} while( SQLITE_ROW == rc );
2319324424
sqlite3_free(pData);
2319424425
if( pArg->cMode==MODE_Json ){
23195
- fputs("]\n", pArg->out);
24426
+ sqlite3_fputs("]\n", pArg->out);
24427
+ }else if( pArg->cMode==MODE_Www ){
24428
+ sqlite3_fputs("</TABLE>\n<PRE>\n", pArg->out);
2319624429
}else if( pArg->cMode==MODE_Count ){
2319724430
char zBuf[200];
2319824431
sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
2319924432
nRow, nRow!=1 ? "s" : "");
2320024433
printf("%s", zBuf);
@@ -23239,10 +24472,11 @@
2323924472
int bCancel,
2324024473
char **pzErr
2324124474
){
2324224475
int rc = SQLITE_OK;
2324324476
sqlite3expert *p = pState->expert.pExpert;
24477
+ FILE *out = pState->out;
2324424478
assert( p );
2324524479
assert( bCancel || pzErr==0 || *pzErr==0 );
2324624480
if( bCancel==0 ){
2324724481
int bVerbose = pState->expert.bVerbose;
2324824482
@@ -23251,24 +24485,25 @@
2325124485
int nQuery = sqlite3_expert_count(p);
2325224486
int i;
2325324487
2325424488
if( bVerbose ){
2325524489
const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
23256
- oputz("-- Candidates -----------------------------\n");
23257
- oputf("%s\n", zCand);
24490
+ sqlite3_fputs("-- Candidates -----------------------------\n", out);
24491
+ sqlite3_fprintf(out, "%s\n", zCand);
2325824492
}
2325924493
for(i=0; i<nQuery; i++){
2326024494
const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
2326124495
const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
2326224496
const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
2326324497
if( zIdx==0 ) zIdx = "(no new indexes)\n";
2326424498
if( bVerbose ){
23265
- oputf("-- Query %d --------------------------------\n",i+1);
23266
- oputf("%s\n\n", zSql);
24499
+ sqlite3_fprintf(out,
24500
+ "-- Query %d --------------------------------\n"
24501
+ "%s\n\n"
24502
+ ,i+1, zSql);
2326724503
}
23268
- oputf("%s\n", zIdx);
23269
- oputf("%s\n", zEQP);
24504
+ sqlite3_fprintf(out, "%s\n%s\n", zIdx, zEQP);
2327024505
}
2327124506
}
2327224507
}
2327324508
sqlite3_expert_destroy(p);
2327424509
pState->expert.pExpert = 0;
@@ -23299,30 +24534,31 @@
2329924534
if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){
2330024535
pState->expert.bVerbose = 1;
2330124536
}
2330224537
else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
2330324538
if( i==(nArg-1) ){
23304
- eputf("option requires an argument: %s\n", z);
24539
+ sqlite3_fprintf(stderr, "option requires an argument: %s\n", z);
2330524540
rc = SQLITE_ERROR;
2330624541
}else{
2330724542
iSample = (int)integerValue(azArg[++i]);
2330824543
if( iSample<0 || iSample>100 ){
23309
- eputf("value out of range: %s\n", azArg[i]);
24544
+ sqlite3_fprintf(stderr,"value out of range: %s\n", azArg[i]);
2331024545
rc = SQLITE_ERROR;
2331124546
}
2331224547
}
2331324548
}
2331424549
else{
23315
- eputf("unknown option: %s\n", z);
24550
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
2331624551
rc = SQLITE_ERROR;
2331724552
}
2331824553
}
2331924554
2332024555
if( rc==SQLITE_OK ){
2332124556
pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
2332224557
if( pState->expert.pExpert==0 ){
23323
- eputf("sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
24558
+ sqlite3_fprintf(stderr,
24559
+ "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
2332424560
rc = SQLITE_ERROR;
2332524561
}else{
2332624562
sqlite3_expert_config(
2332724563
pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
2332824564
);
@@ -23647,33 +24883,33 @@
2364724883
if( zType==0 ) return 0;
2364824884
dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
2364924885
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
2365024886
2365124887
if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
23652
- if( !dataOnly ) oputz("DELETE FROM sqlite_sequence;\n");
24888
+ /* no-op */
2365324889
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
23654
- if( !dataOnly ) oputz("ANALYZE sqlite_schema;\n");
24890
+ if( !dataOnly ) sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
2365524891
}else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
2365624892
return 0;
2365724893
}else if( dataOnly ){
2365824894
/* no-op */
2365924895
}else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
2366024896
char *zIns;
2366124897
if( !p->writableSchema ){
23662
- oputz("PRAGMA writable_schema=ON;\n");
24898
+ sqlite3_fputs("PRAGMA writable_schema=ON;\n", p->out);
2366324899
p->writableSchema = 1;
2366424900
}
2366524901
zIns = sqlite3_mprintf(
2366624902
"INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
2366724903
"VALUES('table','%q','%q',0,'%q');",
2366824904
zTable, zTable, zSql);
2366924905
shell_check_oom(zIns);
23670
- oputf("%s\n", zIns);
24906
+ sqlite3_fprintf(p->out, "%s\n", zIns);
2367124907
sqlite3_free(zIns);
2367224908
return 0;
2367324909
}else{
23674
- printSchemaLine(zSql, ";\n");
24910
+ printSchemaLine(p->out, zSql, ";\n");
2367524911
}
2367624912
2367724913
if( cli_strcmp(zType, "table")==0 ){
2367824914
ShellText sSelect;
2367924915
ShellText sTable;
@@ -23727,11 +24963,11 @@
2372724963
savedMode = p->mode;
2372824964
p->zDestTable = sTable.z;
2372924965
p->mode = p->cMode = MODE_Insert;
2373024966
rc = shell_exec(p, sSelect.z, 0);
2373124967
if( (rc&0xff)==SQLITE_CORRUPT ){
23732
- oputz("/****** CORRUPTION ERROR *******/\n");
24968
+ sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
2373324969
toggleSelectOrder(p->db);
2373424970
shell_exec(p, sSelect.z, 0);
2373524971
toggleSelectOrder(p->db);
2373624972
}
2373724973
p->zDestTable = savedDestTable;
@@ -23758,28 +24994,28 @@
2375824994
char *zErr = 0;
2375924995
rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
2376024996
if( rc==SQLITE_CORRUPT ){
2376124997
char *zQ2;
2376224998
int len = strlen30(zQuery);
23763
- oputz("/****** CORRUPTION ERROR *******/\n");
24999
+ sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
2376425000
if( zErr ){
23765
- oputf("/****** %s ******/\n", zErr);
25001
+ sqlite3_fprintf(p->out, "/****** %s ******/\n", zErr);
2376625002
sqlite3_free(zErr);
2376725003
zErr = 0;
2376825004
}
2376925005
zQ2 = malloc( len+100 );
2377025006
if( zQ2==0 ) return rc;
2377125007
sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
2377225008
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
2377325009
if( rc ){
23774
- oputf("/****** ERROR: %s ******/\n", zErr);
25010
+ sqlite3_fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
2377525011
}else{
2377625012
rc = SQLITE_CORRUPT;
2377725013
}
23778
- sqlite3_free(zErr);
2377925014
free(zQ2);
2378025015
}
25016
+ sqlite3_free(zErr);
2378125017
return rc;
2378225018
}
2378325019
2378425020
/*
2378525021
** Text of help messages.
@@ -23832,18 +25068,17 @@
2383225068
#ifndef SQLITE_SHELL_FIDDLE
2383325069
".check GLOB Fail if output since .testcase does not match",
2383425070
".clone NEWDB Clone data into NEWDB from the existing database",
2383525071
#endif
2383625072
".connection [close] [#] Open or close an auxiliary database connection",
23837
-#if defined(_WIN32) || defined(WIN32)
23838
- ".crnl on|off Translate \\n to \\r\\n. Default ON",
23839
-#endif
25073
+ ".crlf ?on|off? Whether or not to use \\r\\n line endings",
2384025074
".databases List names and files of attached databases",
2384125075
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
2384225076
#if SQLITE_SHELL_HAVE_RECOVER
2384325077
".dbinfo ?DB? Show status information about the database",
2384425078
#endif
25079
+ ".dbtotxt Hex dump of the database file",
2384525080
".dump ?OBJECTS? Render database content as SQL",
2384625081
" Options:",
2384725082
" --data-only Output only INSERT statements",
2384825083
" --newlines Allow unescaped newline characters in output",
2384925084
" --nosys Omit system tables (ex: \"sqlite_stat1\")",
@@ -23940,13 +25175,15 @@
2394025175
#endif
2394125176
".nullvalue STRING Use STRING in place of NULL values",
2394225177
#ifndef SQLITE_SHELL_FIDDLE
2394325178
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
2394425179
" If FILE begins with '|' then open as a pipe",
23945
- " --bom Put a UTF8 byte-order mark at the beginning",
23946
- " -e Send output to the system text editor",
23947
- " -x Send output as CSV to a spreadsheet (same as \".excel\")",
25180
+ " --bom Put a UTF8 byte-order mark at the beginning",
25181
+ " -e Send output to the system text editor",
25182
+ " --plain Use text/plain output instead of HTML for -w option",
25183
+ " -w Send output as HTML to a web browser (same as \".www\")",
25184
+ " -x Send output as CSV to a spreadsheet (same as \".excel\")",
2394825185
/* Note that .open is (partially) available in WASM builds but is
2394925186
** currently only intended to be used by the fiddle tool, not
2395025187
** end users, so is "undocumented." */
2395125188
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
2395225189
" Options:",
@@ -23965,10 +25202,12 @@
2396525202
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
2396625203
" If FILE begins with '|' then open it as a pipe.",
2396725204
" Options:",
2396825205
" --bom Prefix output with a UTF8 byte-order mark",
2396925206
" -e Send output to the system text editor",
25207
+ " --plain Use text/plain for -w option",
25208
+ " -w Send output to a web browser",
2397025209
" -x Send output as CSV to a spreadsheet",
2397125210
#endif
2397225211
".parameter CMD ... Manage SQL parameter bindings",
2397325212
" clear Erase all bindings",
2397425213
" init Initialize the TEMP table that holds bindings",
@@ -24078,10 +25317,14 @@
2407825317
".vfsinfo ?AUX? Information about the top-level VFS",
2407925318
".vfslist List all available VFSes",
2408025319
".vfsname ?AUX? Print the name of the VFS stack",
2408125320
".width NUM1 NUM2 ... Set minimum column widths for columnar output",
2408225321
" Negative values right-justify",
25322
+#ifndef SQLITE_SHELL_FIDDLE
25323
+ ".www Display output of the next command in web browser",
25324
+ " --plain Show results as text/plain, not as HTML",
25325
+#endif
2408325326
};
2408425327
2408525328
/*
2408625329
** Output help text.
2408725330
**
@@ -24126,24 +25369,24 @@
2412625369
hh &= ~HH_Summary;
2412725370
break;
2412825371
}
2412925372
if( ((hw^hh)&HH_Undoc)==0 ){
2413025373
if( (hh&HH_Summary)!=0 ){
24131
- sputf(out, ".%s\n", azHelp[i]+1);
25374
+ sqlite3_fprintf(out, ".%s\n", azHelp[i]+1);
2413225375
++n;
2413325376
}else if( (hw&HW_SummaryOnly)==0 ){
24134
- sputf(out, "%s\n", azHelp[i]);
25377
+ sqlite3_fprintf(out, "%s\n", azHelp[i]);
2413525378
}
2413625379
}
2413725380
}
2413825381
}else{
2413925382
/* Seek documented commands for which zPattern is an exact prefix */
2414025383
zPat = sqlite3_mprintf(".%s*", zPattern);
2414125384
shell_check_oom(zPat);
2414225385
for(i=0; i<ArraySize(azHelp); i++){
2414325386
if( sqlite3_strglob(zPat, azHelp[i])==0 ){
24144
- sputf(out, "%s\n", azHelp[i]);
25387
+ sqlite3_fprintf(out, "%s\n", azHelp[i]);
2414525388
j = i+1;
2414625389
n++;
2414725390
}
2414825391
}
2414925392
sqlite3_free(zPat);
@@ -24150,11 +25393,11 @@
2415025393
if( n ){
2415125394
if( n==1 ){
2415225395
/* when zPattern is a prefix of exactly one command, then include
2415325396
** the details of that command, which should begin at offset j */
2415425397
while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
24155
- sputf(out, "%s\n", azHelp[j]);
25398
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
2415625399
j++;
2415725400
}
2415825401
}
2415925402
return n;
2416025403
}
@@ -24167,14 +25410,14 @@
2416725410
while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
2416825411
continue;
2416925412
}
2417025413
if( azHelp[i][0]=='.' ) j = i;
2417125414
if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
24172
- sputf(out, "%s\n", azHelp[j]);
25415
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
2417325416
while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
2417425417
j++;
24175
- sputf(out, "%s\n", azHelp[j]);
25418
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
2417625419
}
2417725420
i = j;
2417825421
n++;
2417925422
}
2418025423
}
@@ -24200,35 +25443,35 @@
2420025443
**
2420125444
** NULL is returned if any error is encountered. The final value of *pnByte
2420225445
** is undefined in this case.
2420325446
*/
2420425447
static char *readFile(const char *zName, int *pnByte){
24205
- FILE *in = fopen(zName, "rb");
25448
+ FILE *in = sqlite3_fopen(zName, "rb");
2420625449
long nIn;
2420725450
size_t nRead;
2420825451
char *pBuf;
2420925452
int rc;
2421025453
if( in==0 ) return 0;
2421125454
rc = fseek(in, 0, SEEK_END);
2421225455
if( rc!=0 ){
24213
- eputf("Error: '%s' not seekable\n", zName);
25456
+ sqlite3_fprintf(stderr,"Error: '%s' not seekable\n", zName);
2421425457
fclose(in);
2421525458
return 0;
2421625459
}
2421725460
nIn = ftell(in);
2421825461
rewind(in);
2421925462
pBuf = sqlite3_malloc64( nIn+1 );
2422025463
if( pBuf==0 ){
24221
- eputz("Error: out of memory\n");
25464
+ sqlite3_fputs("Error: out of memory\n", stderr);
2422225465
fclose(in);
2422325466
return 0;
2422425467
}
2422525468
nRead = fread(pBuf, nIn, 1, in);
2422625469
fclose(in);
2422725470
if( nRead!=1 ){
2422825471
sqlite3_free(pBuf);
24229
- eputf("Error: cannot read '%s'\n", zName);
25472
+ sqlite3_fprintf(stderr,"Error: cannot read '%s'\n", zName);
2423025473
return 0;
2423125474
}
2423225475
pBuf[nIn] = 0;
2423325476
if( pnByte ) *pnByte = nIn;
2423425477
return pBuf;
@@ -24290,11 +25533,11 @@
2429025533
** archive and the dfltZip flag is true, then assume it is a ZIP archive.
2429125534
** Otherwise, assume an ordinary database regardless of the filename if
2429225535
** the type cannot be determined from content.
2429325536
*/
2429425537
int deduceDatabaseType(const char *zName, int dfltZip){
24295
- FILE *f = fopen(zName, "rb");
25538
+ FILE *f = sqlite3_fopen(zName, "rb");
2429625539
size_t n;
2429725540
int rc = SHELL_OPEN_UNSPEC;
2429825541
char zBuf[100];
2429925542
if( f==0 ){
2430025543
if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
@@ -24343,13 +25586,13 @@
2434325586
FILE *in;
2434425587
const char *zDbFilename = p->pAuxDb->zDbFilename;
2434525588
unsigned int x[16];
2434625589
char zLine[1000];
2434725590
if( zDbFilename ){
24348
- in = fopen(zDbFilename, "r");
25591
+ in = sqlite3_fopen(zDbFilename, "r");
2434925592
if( in==0 ){
24350
- eputf("cannot open \"%s\" for reading\n", zDbFilename);
25593
+ sqlite3_fprintf(stderr,"cannot open \"%s\" for reading\n", zDbFilename);
2435125594
return 0;
2435225595
}
2435325596
nLine = 0;
2435425597
}else{
2435525598
in = p->in;
@@ -24356,24 +25599,24 @@
2435625599
nLine = p->lineno;
2435725600
if( in==0 ) in = stdin;
2435825601
}
2435925602
*pnData = 0;
2436025603
nLine++;
24361
- if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
25604
+ if( sqlite3_fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
2436225605
rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
2436325606
if( rc!=2 ) goto readHexDb_error;
2436425607
if( n<0 ) goto readHexDb_error;
2436525608
if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
2436625609
n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
2436725610
a = sqlite3_malloc( n ? n : 1 );
2436825611
shell_check_oom(a);
2436925612
memset(a, 0, n);
2437025613
if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
24371
- eputz("invalid pagesize\n");
25614
+ sqlite3_fputs("invalid pagesize\n", stderr);
2437225615
goto readHexDb_error;
2437325616
}
24374
- for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
25617
+ for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){
2437525618
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
2437625619
if( rc==2 ){
2437725620
iOffset = k;
2437825621
continue;
2437925622
}
@@ -24401,18 +25644,18 @@
2440125644
2440225645
readHexDb_error:
2440325646
if( in!=p->in ){
2440425647
fclose(in);
2440525648
}else{
24406
- while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
25649
+ while( sqlite3_fgets(zLine, sizeof(zLine), p->in)!=0 ){
2440725650
nLine++;
2440825651
if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
2440925652
}
2441025653
p->lineno = nLine;
2441125654
}
2441225655
sqlite3_free(a);
24413
- eputf("Error on line %d of --hexdb input\n", nLine);
25656
+ sqlite3_fprintf(stderr,"Error on line %d of --hexdb input\n", nLine);
2441425657
return 0;
2441525658
}
2441625659
#endif /* SQLITE_OMIT_DESERIALIZE */
2441725660
2441825661
/*
@@ -24483,22 +25726,24 @@
2448325726
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
2448425727
break;
2448525728
}
2448625729
}
2448725730
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
24488
- eputf("Error: unable to open database \"%s\": %s\n",
25731
+ sqlite3_fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
2448925732
zDbFilename, sqlite3_errmsg(p->db));
2449025733
if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
2449125734
exit(1);
2449225735
}
2449325736
sqlite3_close(p->db);
2449425737
sqlite3_open(":memory:", &p->db);
2449525738
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
24496
- eputz("Also: unable to open substitute in-memory database.\n");
25739
+ sqlite3_fputs("Also: unable to open substitute in-memory database.\n",
25740
+ stderr);
2449725741
exit(1);
2449825742
}else{
24499
- eputf("Notice: using substitute in-memory database instead of \"%s\"\n",
25743
+ sqlite3_fprintf(stderr,
25744
+ "Notice: using substitute in-memory database instead of \"%s\"\n",
2450025745
zDbFilename);
2450125746
}
2450225747
}
2450325748
globalDb = p->db;
2450425749
sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
@@ -24511,10 +25756,11 @@
2451125756
}
2451225757
2451325758
#ifndef SQLITE_OMIT_LOAD_EXTENSION
2451425759
sqlite3_enable_load_extension(p->db, 1);
2451525760
#endif
25761
+ sqlite3_sha_init(p->db, 0, 0);
2451625762
sqlite3_shathree_init(p->db, 0, 0);
2451725763
sqlite3_uint_init(p->db, 0, 0);
2451825764
sqlite3_stmtrand_init(p->db, 0, 0);
2451925765
sqlite3_decimal_init(p->db, 0, 0);
2452025766
sqlite3_percentile_init(p->db, 0, 0);
@@ -24605,11 +25851,11 @@
2460525851
}
2460625852
rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
2460725853
SQLITE_DESERIALIZE_RESIZEABLE |
2460825854
SQLITE_DESERIALIZE_FREEONCLOSE);
2460925855
if( rc ){
24610
- eputf("Error: sqlite3_deserialize() returns %d\n", rc);
25856
+ sqlite3_fprintf(stderr,"Error: sqlite3_deserialize() returns %d\n", rc);
2461125857
}
2461225858
if( p->szMax>0 ){
2461325859
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
2461425860
}
2461525861
}
@@ -24629,15 +25875,17 @@
2462925875
** Attempt to close the database connection. Report errors.
2463025876
*/
2463125877
void close_db(sqlite3 *db){
2463225878
int rc = sqlite3_close(db);
2463325879
if( rc ){
24634
- eputf("Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
25880
+ sqlite3_fprintf(stderr,
25881
+ "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
2463525882
}
2463625883
}
2463725884
24638
-#if HAVE_READLINE || HAVE_EDITLINE
25885
+#if (HAVE_READLINE || HAVE_EDITLINE) \
25886
+ && !defined(SQLITE_OMIT_READLINE_COMPLETION)
2463925887
/*
2464025888
** Readline completion callbacks
2464125889
*/
2464225890
static char *readline_completion_generator(const char *text, int state){
2464325891
static sqlite3_stmt *pStmt = 0;
@@ -24671,19 +25919,26 @@
2467125919
#elif HAVE_LINENOISE
2467225920
/*
2467325921
** Linenoise completion callback. Note that the 3rd argument is from
2467425922
** the "msteveb" version of linenoise, not the "antirez" version.
2467525923
*/
24676
-static void linenoise_completion(const char *zLine, linenoiseCompletions *lc,
24677
- void *pUserData){
25924
+static void linenoise_completion(
25925
+ const char *zLine,
25926
+ linenoiseCompletions *lc
25927
+#if HAVE_LINENOISE==2
25928
+ ,void *pUserData
25929
+#endif
25930
+){
2467825931
i64 nLine = strlen(zLine);
2467925932
i64 i, iStart;
2468025933
sqlite3_stmt *pStmt = 0;
2468125934
char *zSql;
2468225935
char zBuf[1000];
2468325936
25937
+#if HAVE_LINENOISE==2
2468425938
UNUSED_PARAMETER(pUserData);
25939
+#endif
2468525940
if( nLine>(i64)sizeof(zBuf)-30 ) return;
2468625941
if( zLine[0]=='.' || zLine[0]=='#') return;
2468725942
for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
2468825943
if( i==nLine-1 ) return;
2468925944
iStart = i+1;
@@ -24793,11 +26048,12 @@
2479326048
return 1;
2479426049
}
2479526050
if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
2479626051
return 0;
2479726052
}
24798
- eputf("ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
26053
+ sqlite3_fprintf(stderr,
26054
+ "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
2479926055
return 0;
2480026056
}
2480126057
2480226058
/*
2480326059
** Set or clear a shell flag according to a boolean value.
@@ -24820,22 +26076,22 @@
2482026076
/*
2482126077
** Try to open an output file. The names "stdout" and "stderr" are
2482226078
** recognized and do the right thing. NULL is returned if the output
2482326079
** filename is "off".
2482426080
*/
24825
-static FILE *output_file_open(const char *zFile, int bTextMode){
26081
+static FILE *output_file_open(const char *zFile){
2482626082
FILE *f;
2482726083
if( cli_strcmp(zFile,"stdout")==0 ){
2482826084
f = stdout;
2482926085
}else if( cli_strcmp(zFile, "stderr")==0 ){
2483026086
f = stderr;
2483126087
}else if( cli_strcmp(zFile, "off")==0 ){
2483226088
f = 0;
2483326089
}else{
24834
- f = fopen(zFile, bTextMode ? "w" : "wb");
26090
+ f = sqlite3_fopen(zFile, "w");
2483526091
if( f==0 ){
24836
- eputf("Error: cannot open \"%s\"\n", zFile);
26092
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
2483726093
}
2483826094
}
2483926095
return f;
2484026096
}
2484126097
@@ -24884,16 +26140,17 @@
2488426140
if( nSql>1000000000 ) nSql = 1000000000;
2488526141
while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
2488626142
switch( mType ){
2488726143
case SQLITE_TRACE_ROW:
2488826144
case SQLITE_TRACE_STMT: {
24889
- sputf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
26145
+ sqlite3_fprintf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
2489026146
break;
2489126147
}
2489226148
case SQLITE_TRACE_PROFILE: {
2489326149
sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
24894
- sputf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
26150
+ sqlite3_fprintf(p->traceOut,
26151
+ "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
2489526152
break;
2489626153
}
2489726154
}
2489826155
return 0;
2489926156
}
@@ -24996,14 +26253,15 @@
2499626253
do{ p->n--; }while( p->z[p->n]!=cQuote );
2499726254
p->cTerm = c;
2499826255
break;
2499926256
}
2500026257
if( pc==cQuote && c!='\r' ){
25001
- eputf("%s:%d: unescaped %c character\n", p->zFile, p->nLine, cQuote);
26258
+ sqlite3_fprintf(stderr,"%s:%d: unescaped %c character\n",
26259
+ p->zFile, p->nLine, cQuote);
2500226260
}
2500326261
if( c==EOF ){
25004
- eputf("%s:%d: unterminated %c-quoted field\n",
26262
+ sqlite3_fprintf(stderr,"%s:%d: unterminated %c-quoted field\n",
2500526263
p->zFile, startLine, cQuote);
2500626264
p->cTerm = c;
2500726265
break;
2500826266
}
2500926267
import_append_char(p, c);
@@ -25098,11 +26356,11 @@
2509826356
2509926357
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
2510026358
shell_check_oom(zQuery);
2510126359
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2510226360
if( rc ){
25103
- eputf("Error %d: %s on [%s]\n",
26361
+ sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
2510426362
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
2510526363
goto end_data_xfer;
2510626364
}
2510726365
n = sqlite3_column_count(pQuery);
2510826366
zInsert = sqlite3_malloc64(200 + nTable + n*3);
@@ -25115,11 +26373,11 @@
2511526373
i += 2;
2511626374
}
2511726375
memcpy(zInsert+i, ");", 3);
2511826376
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
2511926377
if( rc ){
25120
- eputf("Error %d: %s on [%s]\n",
26378
+ sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
2512126379
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), zInsert);
2512226380
goto end_data_xfer;
2512326381
}
2512426382
for(k=0; k<2; k++){
2512526383
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
@@ -25151,11 +26409,11 @@
2515126409
}
2515226410
}
2515326411
} /* End for */
2515426412
rc = sqlite3_step(pInsert);
2515526413
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
25156
- eputf("Error %d: %s\n",
26414
+ sqlite3_fprintf(stderr,"Error %d: %s\n",
2515726415
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb));
2515826416
}
2515926417
sqlite3_reset(pInsert);
2516026418
cnt++;
2516126419
if( (cnt%spinRate)==0 ){
@@ -25169,11 +26427,11 @@
2516926427
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
2517026428
zTable);
2517126429
shell_check_oom(zQuery);
2517226430
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2517326431
if( rc ){
25174
- eputf("Warning: cannot step \"%s\" backwards", zTable);
26432
+ sqlite3_fprintf(stderr,"Warning: cannot step \"%s\" backwards", zTable);
2517526433
break;
2517626434
}
2517726435
} /* End for(k=0...) */
2517826436
2517926437
end_data_xfer:
@@ -25206,23 +26464,24 @@
2520626464
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
2520726465
" WHERE %s ORDER BY rowid ASC", zWhere);
2520826466
shell_check_oom(zQuery);
2520926467
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2521026468
if( rc ){
25211
- eputf("Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
26469
+ sqlite3_fprintf(stderr,
26470
+ "Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
2521226471
sqlite3_errmsg(p->db), zQuery);
2521326472
goto end_schema_xfer;
2521426473
}
2521526474
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2521626475
zName = sqlite3_column_text(pQuery, 0);
2521726476
zSql = sqlite3_column_text(pQuery, 1);
2521826477
if( zName==0 || zSql==0 ) continue;
2521926478
if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ){
25220
- sputf(stdout, "%s... ", zName); fflush(stdout);
26479
+ sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
2522126480
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2522226481
if( zErrMsg ){
25223
- eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
26482
+ sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2522426483
sqlite3_free(zErrMsg);
2522526484
zErrMsg = 0;
2522626485
}
2522726486
}
2522826487
if( xForEach ){
@@ -25236,23 +26495,23 @@
2523626495
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
2523726496
" WHERE %s ORDER BY rowid DESC", zWhere);
2523826497
shell_check_oom(zQuery);
2523926498
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2524026499
if( rc ){
25241
- eputf("Error: (%d) %s on [%s]\n",
26500
+ sqlite3_fprintf(stderr,"Error: (%d) %s on [%s]\n",
2524226501
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
2524326502
goto end_schema_xfer;
2524426503
}
2524526504
while( sqlite3_step(pQuery)==SQLITE_ROW ){
2524626505
zName = sqlite3_column_text(pQuery, 0);
2524726506
zSql = sqlite3_column_text(pQuery, 1);
2524826507
if( zName==0 || zSql==0 ) continue;
2524926508
if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue;
25250
- sputf(stdout, "%s... ", zName); fflush(stdout);
26509
+ sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
2525126510
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2525226511
if( zErrMsg ){
25253
- eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
26512
+ sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2525426513
sqlite3_free(zErrMsg);
2525526514
zErrMsg = 0;
2525626515
}
2525726516
if( xForEach ){
2525826517
xForEach(p, newDb, (const char*)zName);
@@ -25272,16 +26531,17 @@
2527226531
*/
2527326532
static void tryToClone(ShellState *p, const char *zNewDb){
2527426533
int rc;
2527526534
sqlite3 *newDb = 0;
2527626535
if( access(zNewDb,0)==0 ){
25277
- eputf("File \"%s\" already exists.\n", zNewDb);
26536
+ sqlite3_fprintf(stderr,"File \"%s\" already exists.\n", zNewDb);
2527826537
return;
2527926538
}
2528026539
rc = sqlite3_open(zNewDb, &newDb);
2528126540
if( rc ){
25282
- eputf("Cannot create output database: %s\n", sqlite3_errmsg(newDb));
26541
+ sqlite3_fprintf(stderr,
26542
+ "Cannot create output database: %s\n", sqlite3_errmsg(newDb));
2528326543
}else{
2528426544
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
2528526545
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
2528626546
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
2528726547
tryToCloneSchema(p, newDb, "type!='table'", 0);
@@ -25294,14 +26554,22 @@
2529426554
#ifndef SQLITE_SHELL_FIDDLE
2529526555
/*
2529626556
** Change the output stream (file or pipe or console) to something else.
2529726557
*/
2529826558
static void output_redir(ShellState *p, FILE *pfNew){
25299
- if( p->out != stdout ) eputz("Output already redirected.\n");
25300
- else{
26559
+ if( p->out != stdout ){
26560
+ sqlite3_fputs("Output already redirected.\n", stderr);
26561
+ }else{
2530126562
p->out = pfNew;
25302
- setOutputStream(pfNew);
26563
+ setCrlfMode(p);
26564
+ if( p->mode==MODE_Www ){
26565
+ sqlite3_fputs(
26566
+ "<!DOCTYPE html>\n"
26567
+ "<HTML><BODY><PRE>\n",
26568
+ p->out
26569
+ );
26570
+ }
2530326571
}
2530426572
}
2530526573
2530626574
/*
2530726575
** Change the output file back to stdout.
@@ -25314,10 +26582,13 @@
2531426582
if( p->outfile[0]=='|' ){
2531526583
#ifndef SQLITE_OMIT_POPEN
2531626584
pclose(p->out);
2531726585
#endif
2531826586
}else{
26587
+ if( p->mode==MODE_Www ){
26588
+ sqlite3_fputs("</PRE></BODY></HTML>\n", p->out);
26589
+ }
2531926590
output_file_close(p->out);
2532026591
#ifndef SQLITE_NOHAVE_SYSTEM
2532126592
if( p->doXdgOpen ){
2532226593
const char *zXdgOpenCmd =
2532326594
#if defined(_WIN32)
@@ -25328,11 +26599,11 @@
2532826599
"xdg-open";
2532926600
#endif
2533026601
char *zCmd;
2533126602
zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
2533226603
if( system(zCmd) ){
25333
- eputf("Failed: [%s]\n", zCmd);
26604
+ sqlite3_fprintf(stderr,"Failed: [%s]\n", zCmd);
2533426605
}else{
2533526606
/* Give the start/open/xdg-open command some time to get
2533626607
** going before we continue, and potential delete the
2533726608
** p->zTempFile data file out from under it */
2533826609
sqlite3_sleep(2000);
@@ -25343,28 +26614,34 @@
2534326614
}
2534426615
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
2534526616
}
2534626617
p->outfile[0] = 0;
2534726618
p->out = stdout;
25348
- setOutputStream(stdout);
26619
+ setCrlfMode(p);
2534926620
}
2535026621
#else
2535126622
# define output_redir(SS,pfO)
2535226623
# define output_reset(SS)
2535326624
#endif
2535426625
2535526626
/*
2535626627
** Run an SQL command and return the single integer result.
2535726628
*/
25358
-static int db_int(sqlite3 *db, const char *zSql){
26629
+static int db_int(sqlite3 *db, const char *zSql, ...){
2535926630
sqlite3_stmt *pStmt;
2536026631
int res = 0;
25361
- sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
26632
+ char *z;
26633
+ va_list ap;
26634
+ va_start(ap, zSql);
26635
+ z = sqlite3_vmprintf(zSql, ap);
26636
+ va_end(ap);
26637
+ sqlite3_prepare_v2(db, z, -1, &pStmt, 0);
2536226638
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
2536326639
res = sqlite3_column_int(pStmt,0);
2536426640
}
2536526641
sqlite3_finalize(pStmt);
26642
+ sqlite3_free(z);
2536626643
return res;
2536726644
}
2536826645
2536926646
#if SQLITE_SHELL_HAVE_RECOVER
2537026647
/*
@@ -25419,11 +26696,11 @@
2541926696
if( p->db==0 ) return 1;
2542026697
rc = sqlite3_prepare_v2(p->db,
2542126698
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
2542226699
-1, &pStmt, 0);
2542326700
if( rc ){
25424
- eputf("error: %s\n", sqlite3_errmsg(p->db));
26701
+ sqlite3_fprintf(stderr,"error: %s\n", sqlite3_errmsg(p->db));
2542526702
sqlite3_finalize(pStmt);
2542626703
return 1;
2542726704
}
2542826705
sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
2542926706
if( sqlite3_step(pStmt)==SQLITE_ROW
@@ -25432,58 +26709,149 @@
2543226709
const u8 *pb = sqlite3_column_blob(pStmt,0);
2543326710
shell_check_oom(pb);
2543426711
memcpy(aHdr, pb, 100);
2543526712
sqlite3_finalize(pStmt);
2543626713
}else{
25437
- eputz("unable to read database header\n");
26714
+ sqlite3_fputs("unable to read database header\n", stderr);
2543826715
sqlite3_finalize(pStmt);
2543926716
return 1;
2544026717
}
2544126718
i = get2byteInt(aHdr+16);
2544226719
if( i==1 ) i = 65536;
25443
- oputf("%-20s %d\n", "database page size:", i);
25444
- oputf("%-20s %d\n", "write format:", aHdr[18]);
25445
- oputf("%-20s %d\n", "read format:", aHdr[19]);
25446
- oputf("%-20s %d\n", "reserved bytes:", aHdr[20]);
26720
+ sqlite3_fprintf(p->out, "%-20s %d\n", "database page size:", i);
26721
+ sqlite3_fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
26722
+ sqlite3_fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
26723
+ sqlite3_fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
2544726724
for(i=0; i<ArraySize(aField); i++){
2544826725
int ofst = aField[i].ofst;
2544926726
unsigned int val = get4byteInt(aHdr + ofst);
25450
- oputf("%-20s %u", aField[i].zName, val);
26727
+ sqlite3_fprintf(p->out, "%-20s %u", aField[i].zName, val);
2545126728
switch( ofst ){
2545226729
case 56: {
25453
- if( val==1 ) oputz(" (utf8)");
25454
- if( val==2 ) oputz(" (utf16le)");
25455
- if( val==3 ) oputz(" (utf16be)");
26730
+ if( val==1 ) sqlite3_fputs(" (utf8)", p->out);
26731
+ if( val==2 ) sqlite3_fputs(" (utf16le)", p->out);
26732
+ if( val==3 ) sqlite3_fputs(" (utf16be)", p->out);
2545626733
}
2545726734
}
25458
- oputz("\n");
26735
+ sqlite3_fputs("\n", p->out);
2545926736
}
2546026737
if( zDb==0 ){
2546126738
zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
2546226739
}else if( cli_strcmp(zDb,"temp")==0 ){
2546326740
zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
2546426741
}else{
2546526742
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
2546626743
}
2546726744
for(i=0; i<ArraySize(aQuery); i++){
25468
- char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
25469
- int val = db_int(p->db, zSql);
25470
- sqlite3_free(zSql);
25471
- oputf("%-20s %d\n", aQuery[i].zName, val);
26745
+ int val = db_int(p->db, aQuery[i].zSql, zSchemaTab);
26746
+ sqlite3_fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
2547226747
}
2547326748
sqlite3_free(zSchemaTab);
2547426749
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
25475
- oputf("%-20s %u\n", "data version", iDataVersion);
26750
+ sqlite3_fprintf(p->out, "%-20s %u\n", "data version", iDataVersion);
2547626751
return 0;
2547726752
}
2547826753
#endif /* SQLITE_SHELL_HAVE_RECOVER */
26754
+
26755
+/*
26756
+** Implementation of the ".dbtotxt" command.
26757
+**
26758
+** Return 1 on error, 2 to exit, and 0 otherwise.
26759
+*/
26760
+static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
26761
+ sqlite3_stmt *pStmt = 0;
26762
+ sqlite3_int64 nPage = 0;
26763
+ int pgSz = 0;
26764
+ const char *zTail;
26765
+ char *zName = 0;
26766
+ int rc, i, j;
26767
+ unsigned char bShow[256]; /* Characters ok to display */
26768
+
26769
+ UNUSED_PARAMETER(nArg);
26770
+ UNUSED_PARAMETER(azArg);
26771
+ memset(bShow, '.', sizeof(bShow));
26772
+ for(i=' '; i<='~'; i++){
26773
+ if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
26774
+ }
26775
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_size", -1, &pStmt, 0);
26776
+ if( rc ) goto dbtotxt_error;
26777
+ rc = 0;
26778
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
26779
+ pgSz = sqlite3_column_int(pStmt, 0);
26780
+ sqlite3_finalize(pStmt);
26781
+ pStmt = 0;
26782
+ if( pgSz<512 || pgSz>65536 || (pgSz&(pgSz-1))!=0 ) goto dbtotxt_error;
26783
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_count", -1, &pStmt, 0);
26784
+ if( rc ) goto dbtotxt_error;
26785
+ rc = 0;
26786
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
26787
+ nPage = sqlite3_column_int64(pStmt, 0);
26788
+ sqlite3_finalize(pStmt);
26789
+ pStmt = 0;
26790
+ if( nPage<1 ) goto dbtotxt_error;
26791
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA databases", -1, &pStmt, 0);
26792
+ if( rc ) goto dbtotxt_error;
26793
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ){
26794
+ zTail = "unk.db";
26795
+ }else{
26796
+ const char *zFilename = (const char*)sqlite3_column_text(pStmt, 2);
26797
+ if( zFilename==0 || zFilename[0]==0 ) zFilename = "unk.db";
26798
+ zTail = strrchr(zFilename, '/');
26799
+#if defined(_WIN32)
26800
+ if( zTail==0 ) zTail = strrchr(zFilename, '\\');
26801
+#endif
26802
+ }
26803
+ zName = strdup(zTail);
26804
+ shell_check_oom(zName);
26805
+ sqlite3_fprintf(p->out, "| size %lld pagesize %d filename %s\n",
26806
+ nPage*pgSz, pgSz, zName);
26807
+ sqlite3_finalize(pStmt);
26808
+ pStmt = 0;
26809
+ rc = sqlite3_prepare_v2(p->db,
26810
+ "SELECT pgno, data FROM sqlite_dbpage ORDER BY pgno", -1, &pStmt, 0);
26811
+ if( rc ) goto dbtotxt_error;
26812
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
26813
+ sqlite3_int64 pgno = sqlite3_column_int64(pStmt, 0);
26814
+ const u8 *aData = sqlite3_column_blob(pStmt, 1);
26815
+ int seenPageLabel = 0;
26816
+ for(i=0; i<pgSz; i+=16){
26817
+ const u8 *aLine = aData+i;
26818
+ for(j=0; j<16 && aLine[j]==0; j++){}
26819
+ if( j==16 ) continue;
26820
+ if( !seenPageLabel ){
26821
+ sqlite3_fprintf(p->out, "| page %lld offset %lld\n", pgno, pgno*pgSz);
26822
+ seenPageLabel = 1;
26823
+ }
26824
+ sqlite3_fprintf(p->out, "| %5d:", i);
26825
+ for(j=0; j<16; j++) sqlite3_fprintf(p->out, " %02x", aLine[j]);
26826
+ sqlite3_fprintf(p->out, " ");
26827
+ for(j=0; j<16; j++){
26828
+ unsigned char c = (unsigned char)aLine[j];
26829
+ sqlite3_fprintf(p->out, "%c", bShow[c]);
26830
+ }
26831
+ sqlite3_fprintf(p->out, "\n");
26832
+ }
26833
+ }
26834
+ sqlite3_finalize(pStmt);
26835
+ sqlite3_fprintf(p->out, "| end %s\n", zName);
26836
+ free(zName);
26837
+ return 0;
26838
+
26839
+dbtotxt_error:
26840
+ if( rc ){
26841
+ sqlite3_fprintf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
26842
+ }
26843
+ sqlite3_finalize(pStmt);
26844
+ free(zName);
26845
+ return 1;
26846
+}
2547926847
2548026848
/*
2548126849
** Print the given string as an error message.
2548226850
*/
2548326851
static void shellEmitError(const char *zErr){
25484
- eputf("Error: %s\n", zErr);
26852
+ sqlite3_fprintf(stderr,"Error: %s\n", zErr);
2548526853
}
2548626854
/*
2548726855
** Print the current sqlite3_errmsg() value to stderr and return 1.
2548826856
*/
2548926857
static int shellDatabaseError(sqlite3 *db){
@@ -25726,10 +27094,11 @@
2572627094
int bGroupByParent = 0; /* If -groupbyparent is present */
2572727095
int i; /* To iterate through azArg[] */
2572827096
const char *zIndent = ""; /* How much to indent CREATE INDEX by */
2572927097
int rc; /* Return code */
2573027098
sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
27099
+ FILE *out = pState->out; /* Send output here */
2573127100
2573227101
/*
2573327102
** This SELECT statement returns one row for each foreign key constraint
2573427103
** in the schema of the main database. The column values are:
2573527104
**
@@ -25801,11 +27170,12 @@
2580127170
else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
2580227171
bGroupByParent = 1;
2580327172
zIndent = " ";
2580427173
}
2580527174
else{
25806
- eputf("Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
27175
+ sqlite3_fprintf(stderr,
27176
+ "Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
2580727177
return SQLITE_ERROR;
2580827178
}
2580927179
}
2581027180
2581127181
/* Register the fkey_collate_clause() SQL function */
@@ -25845,44 +27215,45 @@
2584527215
}
2584627216
rc = sqlite3_finalize(pExplain);
2584727217
if( rc!=SQLITE_OK ) break;
2584827218
2584927219
if( res<0 ){
25850
- eputz("Error: internal error");
27220
+ sqlite3_fputs("Error: internal error", stderr);
2585127221
break;
2585227222
}else{
2585327223
if( bGroupByParent
2585427224
&& (bVerbose || res==0)
2585527225
&& (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
2585627226
){
25857
- oputf("-- Parent table %s\n", zParent);
27227
+ sqlite3_fprintf(out, "-- Parent table %s\n", zParent);
2585827228
sqlite3_free(zPrev);
2585927229
zPrev = sqlite3_mprintf("%s", zParent);
2586027230
}
2586127231
2586227232
if( res==0 ){
25863
- oputf("%s%s --> %s\n", zIndent, zCI, zTarget);
27233
+ sqlite3_fprintf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
2586427234
}else if( bVerbose ){
25865
- oputf("%s/* no extra indexes required for %s -> %s */\n",
27235
+ sqlite3_fprintf(out,
27236
+ "%s/* no extra indexes required for %s -> %s */\n",
2586627237
zIndent, zFrom, zTarget
2586727238
);
2586827239
}
2586927240
}
2587027241
}
2587127242
sqlite3_free(zPrev);
2587227243
2587327244
if( rc!=SQLITE_OK ){
25874
- eputf("%s\n", sqlite3_errmsg(db));
27245
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
2587527246
}
2587627247
2587727248
rc2 = sqlite3_finalize(pSql);
2587827249
if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
2587927250
rc = rc2;
25880
- eputf("%s\n", sqlite3_errmsg(db));
27251
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
2588127252
}
2588227253
}else{
25883
- eputf("%s\n", sqlite3_errmsg(db));
27254
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
2588427255
}
2588527256
2588627257
return rc;
2588727258
}
2588827259
@@ -25898,13 +27269,13 @@
2589827269
n = (nArg>=2 ? strlen30(azArg[1]) : 0);
2589927270
if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
2590027271
return lintFkeyIndexes(pState, azArg, nArg);
2590127272
2590227273
usage:
25903
- eputf("Usage %s sub-command ?switches...?\n", azArg[0]);
25904
- eputz("Where sub-commands are:\n");
25905
- eputz(" fkey-indexes\n");
27274
+ sqlite3_fprintf(stderr,"Usage %s sub-command ?switches...?\n", azArg[0]);
27275
+ sqlite3_fprintf(stderr, "Where sub-commands are:\n");
27276
+ sqlite3_fprintf(stderr, " fkey-indexes\n");
2590627277
return SQLITE_ERROR;
2590727278
}
2590827279
2590927280
static void shellPrepare(
2591027281
sqlite3 *db,
@@ -25914,11 +27285,12 @@
2591427285
){
2591527286
*ppStmt = 0;
2591627287
if( *pRc==SQLITE_OK ){
2591727288
int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
2591827289
if( rc!=SQLITE_OK ){
25919
- eputf("sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
27290
+ sqlite3_fprintf(stderr,
27291
+ "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
2592027292
*pRc = rc;
2592127293
}
2592227294
}
2592327295
}
2592427296
@@ -25958,11 +27330,11 @@
2595827330
if( pStmt ){
2595927331
sqlite3 *db = sqlite3_db_handle(pStmt);
2596027332
int rc = sqlite3_finalize(pStmt);
2596127333
if( *pRc==SQLITE_OK ){
2596227334
if( rc!=SQLITE_OK ){
25963
- eputf("SQL error: %s\n", sqlite3_errmsg(db));
27335
+ sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
2596427336
}
2596527337
*pRc = rc;
2596627338
}
2596727339
}
2596827340
}
@@ -25980,11 +27352,11 @@
2598027352
){
2598127353
int rc = sqlite3_reset(pStmt);
2598227354
if( *pRc==SQLITE_OK ){
2598327355
if( rc!=SQLITE_OK ){
2598427356
sqlite3 *db = sqlite3_db_handle(pStmt);
25985
- eputf("SQL error: %s\n", sqlite3_errmsg(db));
27357
+ sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
2598627358
}
2598727359
*pRc = rc;
2598827360
}
2598927361
}
2599027362
#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
@@ -26009,10 +27381,11 @@
2600927381
char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
2601027382
const char *zFile; /* --file argument, or NULL */
2601127383
const char *zDir; /* --directory argument, or NULL */
2601227384
char **azArg; /* Array of command arguments */
2601327385
ShellState *p; /* Shell state */
27386
+ FILE *out; /* Output to this stream */
2601427387
sqlite3 *db; /* Database containing the archive */
2601527388
};
2601627389
2601727390
/*
2601827391
** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
@@ -26032,13 +27405,13 @@
2603227405
va_start(ap, zFmt);
2603327406
z = sqlite3_vmprintf(zFmt, ap);
2603427407
va_end(ap);
2603527408
shellEmitError(z);
2603627409
if( pAr->fromCmdLine ){
26037
- eputz("Use \"-A\" for more help\n");
27410
+ sqlite3_fputs("Use \"-A\" for more help\n", stderr);
2603827411
}else{
26039
- eputz("Use \".archive --help\" for more help\n");
27412
+ sqlite3_fputs("Use \".archive --help\" for more help\n", stderr);
2604027413
}
2604127414
sqlite3_free(z);
2604227415
return SQLITE_ERROR;
2604327416
}
2604427417
@@ -26134,11 +27507,11 @@
2613427507
};
2613527508
int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
2613627509
struct ArSwitch *pEnd = &aSwitch[nSwitch];
2613727510
2613827511
if( nArg<=1 ){
26139
- eputz("Wrong number of arguments. Usage:\n");
27512
+ sqlite3_fprintf(stderr, "Wrong number of arguments. Usage:\n");
2614027513
return arUsage(stderr);
2614127514
}else{
2614227515
char *z = azArg[1];
2614327516
if( z[0]!='-' ){
2614427517
/* Traditional style [tar] invocation */
@@ -26240,11 +27613,11 @@
2624027613
}
2624127614
}
2624227615
}
2624327616
}
2624427617
if( pAr->eCmd==0 ){
26245
- eputz("Required argument missing. Usage:\n");
27618
+ sqlite3_fprintf(stderr, "Required argument missing. Usage:\n");
2624627619
return arUsage(stderr);
2624727620
}
2624827621
return SQLITE_OK;
2624927622
}
2625027623
@@ -26283,11 +27656,11 @@
2628327656
if( SQLITE_ROW==sqlite3_step(pTest) ){
2628427657
bOk = 1;
2628527658
}
2628627659
shellReset(&rc, pTest);
2628727660
if( rc==SQLITE_OK && bOk==0 ){
26288
- eputf("not found in archive: %s\n", z);
27661
+ sqlite3_fprintf(stderr,"not found in archive: %s\n", z);
2628927662
rc = SQLITE_ERROR;
2629027663
}
2629127664
}
2629227665
shellFinalize(&rc, pTest);
2629327666
}
@@ -26350,19 +27723,19 @@
2635027723
arWhereClause(&rc, pAr, &zWhere);
2635127724
2635227725
shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
2635327726
pAr->zSrcTable, zWhere);
2635427727
if( pAr->bDryRun ){
26355
- oputf("%s\n", sqlite3_sql(pSql));
27728
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
2635627729
}else{
2635727730
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
2635827731
if( pAr->bVerbose ){
26359
- oputf("%s % 10d %s %s\n",
27732
+ sqlite3_fprintf(pAr->out, "%s % 10d %s %s\n",
2636027733
sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1),
2636127734
sqlite3_column_text(pSql, 2),sqlite3_column_text(pSql, 3));
2636227735
}else{
26363
- oputf("%s\n", sqlite3_column_text(pSql, 0));
27736
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
2636427737
}
2636527738
}
2636627739
}
2636727740
shellFinalize(&rc, pSql);
2636827741
sqlite3_free(zWhere);
@@ -26385,11 +27758,11 @@
2638527758
}
2638627759
if( rc==SQLITE_OK ){
2638727760
zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
2638827761
pAr->zSrcTable, zWhere);
2638927762
if( pAr->bDryRun ){
26390
- oputf("%s\n", zSql);
27763
+ sqlite3_fprintf(pAr->out, "%s\n", zSql);
2639127764
}else{
2639227765
char *zErr = 0;
2639327766
rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
2639427767
if( rc==SQLITE_OK ){
2639527768
rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
@@ -26398,11 +27771,11 @@
2639827771
}else{
2639927772
rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0);
2640027773
}
2640127774
}
2640227775
if( zErr ){
26403
- sputf(stdout, "ERROR: %s\n", zErr); /* stdout? */
27776
+ sqlite3_fprintf(stdout, "ERROR: %s\n", zErr); /* stdout? */
2640427777
sqlite3_free(zErr);
2640527778
}
2640627779
}
2640727780
}
2640827781
sqlite3_free(zWhere);
@@ -26462,15 +27835,15 @@
2646227835
** populating them changes the timestamp). */
2646327836
for(i=0; i<2; i++){
2646427837
j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
2646527838
sqlite3_bind_int(pSql, j, i);
2646627839
if( pAr->bDryRun ){
26467
- oputf("%s\n", sqlite3_sql(pSql));
27840
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
2646827841
}else{
2646927842
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
2647027843
if( i==0 && pAr->bVerbose ){
26471
- oputf("%s\n", sqlite3_column_text(pSql, 0));
27844
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
2647227845
}
2647327846
}
2647427847
}
2647527848
shellReset(&rc, pSql);
2647627849
}
@@ -26486,17 +27859,17 @@
2648627859
** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out.
2648727860
*/
2648827861
static int arExecSql(ArCommand *pAr, const char *zSql){
2648927862
int rc;
2649027863
if( pAr->bDryRun ){
26491
- oputf("%s\n", zSql);
27864
+ sqlite3_fprintf(pAr->out, "%s\n", zSql);
2649227865
rc = SQLITE_OK;
2649327866
}else{
2649427867
char *zErr = 0;
2649527868
rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
2649627869
if( zErr ){
26497
- sputf(stdout, "ERROR: %s\n", zErr);
27870
+ sqlite3_fprintf(stdout, "ERROR: %s\n", zErr);
2649827871
sqlite3_free(zErr);
2649927872
}
2650027873
}
2650127874
return rc;
2650227875
}
@@ -26641,10 +28014,11 @@
2664128014
cmd.fromCmdLine = fromCmdLine;
2664228015
rc = arParseCommand(azArg, nArg, &cmd);
2664328016
if( rc==SQLITE_OK ){
2664428017
int eDbType = SHELL_OPEN_UNSPEC;
2664528018
cmd.p = pState;
28019
+ cmd.out = pState->out;
2664628020
cmd.db = pState->db;
2664728021
if( cmd.zFile ){
2664828022
eDbType = deduceDatabaseType(cmd.zFile, 1);
2664928023
}else{
2665028024
eDbType = pState->openMode;
@@ -26667,17 +28041,18 @@
2666728041
}else{
2666828042
flags = SQLITE_OPEN_READONLY;
2666928043
}
2667028044
cmd.db = 0;
2667128045
if( cmd.bDryRun ){
26672
- oputf("-- open database '%s'%s\n", cmd.zFile,
28046
+ sqlite3_fprintf(cmd.out, "-- open database '%s'%s\n", cmd.zFile,
2667328047
eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
2667428048
}
2667528049
rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
2667628050
eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
2667728051
if( rc!=SQLITE_OK ){
26678
- eputf("cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db));
28052
+ sqlite3_fprintf(stderr, "cannot open file: %s (%s)\n",
28053
+ cmd.zFile, sqlite3_errmsg(cmd.db));
2667928054
goto end_ar_command;
2668028055
}
2668128056
sqlite3_fileio_init(cmd.db, 0, 0);
2668228057
sqlite3_sqlar_init(cmd.db, 0, 0);
2668328058
sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
@@ -26686,11 +28061,11 @@
2668628061
}
2668728062
if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
2668828063
if( cmd.eCmd!=AR_CMD_CREATE
2668928064
&& sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
2669028065
){
26691
- eputz("database does not contain an 'sqlar' table\n");
28066
+ sqlite3_fprintf(stderr, "database does not contain an 'sqlar' table\n");
2669228067
rc = SQLITE_ERROR;
2669328068
goto end_ar_command;
2669428069
}
2669528070
cmd.zSrcTable = sqlite3_mprintf("sqlar");
2669628071
}
@@ -26744,11 +28119,11 @@
2674428119
** This function is used as a callback by the recover extension. Simply
2674528120
** print the supplied SQL statement to stdout.
2674628121
*/
2674728122
static int recoverSqlCb(void *pCtx, const char *zSql){
2674828123
ShellState *pState = (ShellState*)pCtx;
26749
- sputf(pState->out, "%s;\n", zSql);
28124
+ sqlite3_fprintf(pState->out, "%s;\n", zSql);
2675028125
return SQLITE_OK;
2675128126
}
2675228127
2675328128
/*
2675428129
** This function is called to recover data from the database. A script
@@ -26787,11 +28162,11 @@
2678728162
}else
2678828163
if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
2678928164
bRowids = 0;
2679028165
}
2679128166
else{
26792
- eputf("unexpected option: %s\n", azArg[i]);
28167
+ sqlite3_fprintf(stderr,"unexpected option: %s\n", azArg[i]);
2679328168
showHelp(pState->out, azArg[0]);
2679428169
return 1;
2679528170
}
2679628171
}
2679728172
@@ -26806,11 +28181,11 @@
2680628181
2680728182
sqlite3_recover_run(p);
2680828183
if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
2680928184
const char *zErr = sqlite3_recover_errmsg(p);
2681028185
int errCode = sqlite3_recover_errcode(p);
26811
- eputf("sql error: %s (%d)\n", zErr, errCode);
28186
+ sqlite3_fprintf(stderr,"sql error: %s (%d)\n", zErr, errCode);
2681228187
}
2681328188
rc = sqlite3_recover_finish(p);
2681428189
return rc;
2681528190
}
2681628191
#endif /* SQLITE_SHELL_HAVE_RECOVER */
@@ -26828,25 +28203,25 @@
2682828203
i64 nError = 0;
2682928204
const char *zErr = 0;
2683028205
while( SQLITE_OK==sqlite3_intck_step(p) ){
2683128206
const char *zMsg = sqlite3_intck_message(p);
2683228207
if( zMsg ){
26833
- oputf("%s\n", zMsg);
28208
+ sqlite3_fprintf(pState->out, "%s\n", zMsg);
2683428209
nError++;
2683528210
}
2683628211
nStep++;
2683728212
if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){
2683828213
sqlite3_intck_unlock(p);
2683928214
}
2684028215
}
2684128216
rc = sqlite3_intck_error(p, &zErr);
2684228217
if( zErr ){
26843
- eputf("%s\n", zErr);
28218
+ sqlite3_fprintf(stderr,"%s\n", zErr);
2684428219
}
2684528220
sqlite3_intck_close(p);
2684628221
26847
- oputf("%lld steps, %lld errors\n", nStep, nError);
28222
+ sqlite3_fprintf(pState->out, "%lld steps, %lld errors\n", nStep, nError);
2684828223
}
2684928224
2685028225
return rc;
2685128226
}
2685228227
@@ -26865,11 +28240,11 @@
2686528240
*/
2686628241
#ifdef SHELL_DEBUG
2686728242
#define rc_err_oom_die(rc) \
2686828243
if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
2686928244
else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
26870
- eputf("E:%d\n",rc), assert(0)
28245
+ sqlite3_fprintf(stderr,"E:%d\n",rc), assert(0)
2687128246
#else
2687228247
static void rc_err_oom_die(int rc){
2687328248
if( rc==SQLITE_NOMEM ) shell_check_oom(0);
2687428249
assert(rc==SQLITE_OK||rc==SQLITE_DONE);
2687528250
}
@@ -27023,12 +28398,12 @@
2702328398
}else if( *pDb==0 ){
2702428399
return 0;
2702528400
}else{
2702628401
/* Formulate the columns spec, close the DB, zero *pDb. */
2702728402
char *zColsSpec = 0;
27028
- int hasDupes = db_int(*pDb, zHasDupes);
27029
- int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
28403
+ int hasDupes = db_int(*pDb, "%s", zHasDupes);
28404
+ int nDigits = (hasDupes)? db_int(*pDb, "%s", zColDigits) : 0;
2703028405
if( hasDupes ){
2703128406
#ifdef SHELL_COLUMN_RENAME_CLEAN
2703228407
rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
2703328408
rc_err_oom_die(rc);
2703428409
#endif
@@ -27039,11 +28414,11 @@
2703928414
sqlite3_bind_int(pStmt, 1, nDigits);
2704028415
rc = sqlite3_step(pStmt);
2704128416
sqlite3_finalize(pStmt);
2704228417
if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
2704328418
}
27044
- assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
28419
+ assert(db_int(*pDb, "%s", zHasDupes)==0); /* Consider: remove this */
2704528420
rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
2704628421
rc_err_oom_die(rc);
2704728422
rc = sqlite3_step(pStmt);
2704828423
if( rc==SQLITE_ROW ){
2704928424
zColsSpec = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
@@ -27082,12 +28457,13 @@
2708228457
shellPreparePrintf(p->db, &rc, &pStmt,
2708328458
"SELECT 1 FROM sqlite_schema o WHERE "
2708428459
"sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true"
2708528460
);
2708628461
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
27087
- oputz("/* WARNING: "
27088
- "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n"
28462
+ sqlite3_fputs("/* WARNING: "
28463
+ "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n",
28464
+ p->out
2708928465
);
2709028466
}
2709128467
shellFinalize(&rc, pStmt);
2709228468
return rc;
2709328469
}
@@ -27114,16 +28490,18 @@
2711428490
return SQLITE_OK;
2711528491
}
2711628492
if( faultsim_state.iCnt ){
2711728493
if( faultsim_state.iCnt>0 ) faultsim_state.iCnt--;
2711828494
if( faultsim_state.eVerbose>=2 ){
27119
- oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
28495
+ sqlite3_fprintf(stdout,
28496
+ "FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
2712028497
}
2712128498
return SQLITE_OK;
2712228499
}
2712328500
if( faultsim_state.eVerbose>=1 ){
27124
- oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
28501
+ sqlite3_fprintf(stdout,
28502
+ "FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
2712528503
}
2712628504
faultsim_state.iCnt = faultsim_state.iInterval;
2712728505
faultsim_state.nHit++;
2712828506
if( faultsim_state.nRepeat>0 && faultsim_state.nRepeat<=faultsim_state.nHit ){
2712928507
faultsim_state.iCnt = -1;
@@ -27182,11 +28560,11 @@
2718228560
clearTempFile(p);
2718328561
2718428562
#ifndef SQLITE_OMIT_AUTHORIZATION
2718528563
if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
2718628564
if( nArg!=2 ){
27187
- eputz("Usage: .auth ON|OFF\n");
28565
+ sqlite3_fprintf(stderr, "Usage: .auth ON|OFF\n");
2718828566
rc = 1;
2718928567
goto meta_command_exit;
2719028568
}
2719128569
open_db(p, 0);
2719228570
if( booleanValue(azArg[1]) ){
@@ -27229,32 +28607,32 @@
2722928607
}else
2723028608
if( cli_strcmp(z, "-async")==0 ){
2723128609
bAsync = 1;
2723228610
}else
2723328611
{
27234
- eputf("unknown option: %s\n", azArg[j]);
28612
+ sqlite3_fprintf(stderr,"unknown option: %s\n", azArg[j]);
2723528613
return 1;
2723628614
}
2723728615
}else if( zDestFile==0 ){
2723828616
zDestFile = azArg[j];
2723928617
}else if( zDb==0 ){
2724028618
zDb = zDestFile;
2724128619
zDestFile = azArg[j];
2724228620
}else{
27243
- eputz("Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
28621
+ sqlite3_fprintf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
2724428622
return 1;
2724528623
}
2724628624
}
2724728625
if( zDestFile==0 ){
27248
- eputz("missing FILENAME argument on .backup\n");
28626
+ sqlite3_fprintf(stderr, "missing FILENAME argument on .backup\n");
2724928627
return 1;
2725028628
}
2725128629
if( zDb==0 ) zDb = "main";
2725228630
rc = sqlite3_open_v2(zDestFile, &pDest,
2725328631
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
2725428632
if( rc!=SQLITE_OK ){
27255
- eputf("Error: cannot open \"%s\"\n", zDestFile);
28633
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zDestFile);
2725628634
close_db(pDest);
2725728635
return 1;
2725828636
}
2725928637
if( bAsync ){
2726028638
sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
@@ -27286,23 +28664,14 @@
2728628664
eputz("Usage: .bail on|off\n");
2728728665
rc = 1;
2728828666
}
2728928667
}else
2729028668
27291
- /* Undocumented. Legacy only. See "crnl" below */
28669
+ /* Undocumented. Legacy only. See "crlf" below */
2729228670
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
27293
- if( nArg==2 ){
27294
- if( booleanValue(azArg[1]) ){
27295
- setBinaryMode(p->out, 1);
27296
- }else{
27297
- setTextMode(p->out, 1);
27298
- }
27299
- }else{
27300
- eputz("The \".binary\" command is deprecated. Use \".crnl\" instead.\n"
27301
- "Usage: .binary on|off\n");
27302
- rc = 1;
27303
- }
28671
+ eputz("The \".binary\" command is deprecated.\n");
28672
+ rc = 1;
2730428673
}else
2730528674
2730628675
/* The undocumented ".breakpoint" command causes a call to the no-op
2730728676
** routine named test_breakpoint().
2730828677
*/
@@ -27320,11 +28689,11 @@
2732028689
sqlite3_free(z);
2732128690
#else
2732228691
rc = chdir(azArg[1]);
2732328692
#endif
2732428693
if( rc ){
27325
- eputf("Cannot change to directory \"%s\"\n", azArg[1]);
28694
+ sqlite3_fprintf(stderr,"Cannot change to directory \"%s\"\n", azArg[1]);
2732628695
rc = 1;
2732728696
}
2732828697
}else{
2732928698
eputz("Usage: .cd DIRECTORY\n");
2733028699
rc = 1;
@@ -27353,15 +28722,16 @@
2735328722
eputz("Usage: .check GLOB-PATTERN\n");
2735428723
rc = 2;
2735528724
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
2735628725
rc = 2;
2735728726
}else if( testcase_glob(azArg[1],zRes)==0 ){
27358
- eputf("testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
28727
+ sqlite3_fprintf(stderr,
28728
+ "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
2735928729
p->zTestcase, azArg[1], zRes);
2736028730
rc = 1;
2736128731
}else{
27362
- oputf("testcase-%s ok\n", p->zTestcase);
28732
+ sqlite3_fprintf(p->out, "testcase-%s ok\n", p->zTestcase);
2736328733
p->nCheck++;
2736428734
}
2736528735
sqlite3_free(zRes);
2736628736
}else
2736728737
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -27390,13 +28760,13 @@
2739028760
zFile = "(memory)";
2739128761
}else if( zFile[0]==0 ){
2739228762
zFile = "(temporary-file)";
2739328763
}
2739428764
if( p->pAuxDb == &p->aAuxDb[i] ){
27395
- sputf(stdout, "ACTIVE %d: %s\n", i, zFile);
28765
+ sqlite3_fprintf(stdout, "ACTIVE %d: %s\n", i, zFile);
2739628766
}else if( p->aAuxDb[i].db!=0 ){
27397
- sputf(stdout, " %d: %s\n", i, zFile);
28767
+ sqlite3_fprintf(stdout, " %d: %s\n", i, zFile);
2739828768
}
2739928769
}
2740028770
}else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
2740128771
int i = azArg[1][0] - '0';
2740228772
if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
@@ -27422,24 +28792,22 @@
2742228792
eputz("Usage: .connection [close] [CONNECTION-NUMBER]\n");
2742328793
rc = 1;
2742428794
}
2742528795
}else
2742628796
27427
- if( c=='c' && n==4 && cli_strncmp(azArg[0], "crnl", n)==0 ){
28797
+ if( c=='c' && n==4
28798
+ && (cli_strncmp(azArg[0], "crlf", n)==0
28799
+ || cli_strncmp(azArg[0], "crnl",n)==0)
28800
+ ){
2742828801
if( nArg==2 ){
27429
- if( booleanValue(azArg[1]) ){
27430
- setTextMode(p->out, 1);
27431
- }else{
27432
- setBinaryMode(p->out, 1);
27433
- }
27434
- }else{
27435
-#if !defined(_WIN32) && !defined(WIN32)
27436
- eputz("The \".crnl\" is a no-op on non-Windows machines.\n");
28802
+#ifdef _WIN32
28803
+ p->crlfMode = booleanValue(azArg[1]);
28804
+#else
28805
+ p->crlfMode = 0;
2743728806
#endif
27438
- eputz("Usage: .crnl on|off\n");
27439
- rc = 1;
2744028807
}
28808
+ sqlite3_fprintf(stderr, "crlf is %s\n", p->crlfMode ? "ON" : "OFF");
2744128809
}else
2744228810
2744328811
if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
2744428812
char **azName = 0;
2744528813
int nName = 0;
@@ -27465,11 +28833,11 @@
2746528833
sqlite3_finalize(pStmt);
2746628834
for(i=0; i<nName; i++){
2746728835
int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
2746828836
int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
2746928837
const char *z = azName[i*2+1];
27470
- oputf("%s: %s %s%s\n",
28838
+ sqlite3_fprintf(p->out, "%s: %s %s%s\n",
2747128839
azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w",
2747228840
eTxn==SQLITE_TXN_NONE ? "" :
2747328841
eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
2747428842
free(azName[i*2]);
2747528843
free(azName[i*2+1]);
@@ -27507,15 +28875,16 @@
2750728875
if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
2750828876
if( nArg>=3 ){
2750928877
sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
2751028878
}
2751128879
sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
27512
- oputf("%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
28880
+ sqlite3_fprintf(p->out, "%19s %s\n",
28881
+ aDbConfig[ii].zName, v ? "on" : "off");
2751328882
if( nArg>1 ) break;
2751428883
}
2751528884
if( nArg>1 && ii==ArraySize(aDbConfig) ){
27516
- eputf("Error: unknown dbconfig \"%s\"\n", azArg[1]);
28885
+ sqlite3_fprintf(stderr,"Error: unknown dbconfig \"%s\"\n", azArg[1]);
2751728886
eputz("Enter \".dbconfig\" with no arguments for a list\n");
2751828887
}
2751928888
}else
2752028889
2752128890
#if SQLITE_SHELL_HAVE_RECOVER
@@ -27561,11 +28930,12 @@
2756128930
}else
2756228931
if( cli_strcmp(z,"nosys")==0 ){
2756328932
ShellSetFlag(p, SHFLG_DumpNoSys);
2756428933
}else
2756528934
{
27566
- eputf("Unknown option \"%s\" on \".dump\"\n", azArg[i]);
28935
+ sqlite3_fprintf(stderr,
28936
+ "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
2756728937
rc = 1;
2756828938
sqlite3_free(zLike);
2756928939
goto meta_command_exit;
2757028940
}
2757128941
}else{
@@ -27596,12 +28966,12 @@
2759628966
outputDumpWarning(p, zLike);
2759728967
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
2759828968
/* When playing back a "dump", the content might appear in an order
2759928969
** which causes immediate foreign key constraints to be violated.
2760028970
** So disable foreign-key constraint enforcement to prevent problems. */
27601
- oputz("PRAGMA foreign_keys=OFF;\n");
27602
- oputz("BEGIN TRANSACTION;\n");
28971
+ sqlite3_fputs("PRAGMA foreign_keys=OFF;\n", p->out);
28972
+ sqlite3_fputs("BEGIN TRANSACTION;\n", p->out);
2760328973
}
2760428974
p->writableSchema = 0;
2760528975
p->showHeader = 0;
2760628976
/* Set writable_schema=ON since doing so forces SQLite to initialize
2760728977
** as much of the schema as it can even if the sqlite_schema table is
@@ -27629,17 +28999,17 @@
2762928999
run_table_dump_query(p, zSql);
2763029000
sqlite3_free(zSql);
2763129001
}
2763229002
sqlite3_free(zLike);
2763329003
if( p->writableSchema ){
27634
- oputz("PRAGMA writable_schema=OFF;\n");
29004
+ sqlite3_fputs("PRAGMA writable_schema=OFF;\n", p->out);
2763529005
p->writableSchema = 0;
2763629006
}
2763729007
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
2763829008
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
2763929009
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
27640
- oputz(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
29010
+ sqlite3_fputs(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n", p->out);
2764129011
}
2764229012
p->showHeader = savedShowHeader;
2764329013
p->shellFlgs = savedShellFlags;
2764429014
}else
2764529015
@@ -27649,10 +29019,14 @@
2764929019
}else{
2765029020
eputz("Usage: .echo on|off\n");
2765129021
rc = 1;
2765229022
}
2765329023
}else
29024
+
29025
+ if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
29026
+ rc = shell_dbtotxt_command(p, nArg, azArg);
29027
+ }else
2765429028
2765529029
if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
2765629030
if( nArg==2 ){
2765729031
p->autoEQPtest = 0;
2765829032
if( p->autoEQPtrace ){
@@ -27715,11 +29089,12 @@
2771529089
}else
2771629090
2771729091
#ifndef SQLITE_OMIT_VIRTUALTABLE
2771829092
if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
2771929093
if( p->bSafeMode ){
27720
- eputf("Cannot run experimental commands such as \"%s\" in safe mode\n",
29094
+ sqlite3_fprintf(stderr,
29095
+ "Cannot run experimental commands such as \"%s\" in safe mode\n",
2772129096
azArg[0]);
2772229097
rc = 1;
2772329098
}else{
2772429099
open_db(p, 0);
2772529100
expertDotCommand(p, azArg, nArg);
@@ -27772,13 +29147,14 @@
2777229147
if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
2777329148
}
2777429149
2777529150
/* --help lists all file-controls */
2777629151
if( cli_strcmp(zCmd,"help")==0 ){
27777
- oputz("Available file-controls:\n");
29152
+ sqlite3_fputs("Available file-controls:\n", p->out);
2777829153
for(i=0; i<ArraySize(aCtrl); i++){
27779
- oputf(" .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
29154
+ sqlite3_fprintf(p->out,
29155
+ " .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
2778029156
}
2778129157
rc = 1;
2778229158
goto meta_command_exit;
2778329159
}
2778429160
@@ -27789,19 +29165,19 @@
2778929165
if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
2779029166
if( filectrl<0 ){
2779129167
filectrl = aCtrl[i].ctrlCode;
2779229168
iCtrl = i;
2779329169
}else{
27794
- eputf("Error: ambiguous file-control: \"%s\"\n"
29170
+ sqlite3_fprintf(stderr,"Error: ambiguous file-control: \"%s\"\n"
2779529171
"Use \".filectrl --help\" for help\n", zCmd);
2779629172
rc = 1;
2779729173
goto meta_command_exit;
2779829174
}
2779929175
}
2780029176
}
2780129177
if( filectrl<0 ){
27802
- eputf("Error: unknown file-control: %s\n"
29178
+ sqlite3_fprintf(stderr,"Error: unknown file-control: %s\n"
2780329179
"Use \".filectrl --help\" for help\n", zCmd);
2780429180
}else{
2780529181
switch(filectrl){
2780629182
case SQLITE_FCNTL_SIZE_LIMIT: {
2780729183
if( nArg!=2 && nArg!=3 ) break;
@@ -27841,11 +29217,11 @@
2784129217
case SQLITE_FCNTL_TEMPFILENAME: {
2784229218
char *z = 0;
2784329219
if( nArg!=2 ) break;
2784429220
sqlite3_file_control(p->db, zSchema, filectrl, &z);
2784529221
if( z ){
27846
- oputf("%s\n", z);
29222
+ sqlite3_fprintf(p->out, "%s\n", z);
2784729223
sqlite3_free(z);
2784829224
}
2784929225
isOk = 2;
2785029226
break;
2785129227
}
@@ -27855,23 +29231,24 @@
2785529231
x = atoi(azArg[2]);
2785629232
sqlite3_file_control(p->db, zSchema, filectrl, &x);
2785729233
}
2785829234
x = -1;
2785929235
sqlite3_file_control(p->db, zSchema, filectrl, &x);
27860
- oputf("%d\n", x);
29236
+ sqlite3_fprintf(p->out, "%d\n", x);
2786129237
isOk = 2;
2786229238
break;
2786329239
}
2786429240
}
2786529241
}
2786629242
if( isOk==0 && iCtrl>=0 ){
27867
- oputf("Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
29243
+ sqlite3_fprintf(p->out, "Usage: .filectrl %s %s\n",
29244
+ zCmd, aCtrl[iCtrl].zUsage);
2786829245
rc = 1;
2786929246
}else if( isOk==1 ){
2787029247
char zBuf[100];
2787129248
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
27872
- oputf("%s\n", zBuf);
29249
+ sqlite3_fprintf(p->out, "%s\n", zBuf);
2787329250
}
2787429251
}else
2787529252
2787629253
if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
2787729254
ShellState data;
@@ -27908,19 +29285,19 @@
2790829285
doStats = sqlite3_step(pStmt)==SQLITE_ROW;
2790929286
sqlite3_finalize(pStmt);
2791029287
}
2791129288
}
2791229289
if( doStats==0 ){
27913
- oputz("/* No STAT tables available */\n");
29290
+ sqlite3_fputs("/* No STAT tables available */\n", p->out);
2791429291
}else{
27915
- oputz("ANALYZE sqlite_schema;\n");
29292
+ sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
2791629293
data.cMode = data.mode = MODE_Insert;
2791729294
data.zDestTable = "sqlite_stat1";
2791829295
shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
2791929296
data.zDestTable = "sqlite_stat4";
2792029297
shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
27921
- oputz("ANALYZE sqlite_schema;\n");
29298
+ sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
2792229299
}
2792329300
}else
2792429301
2792529302
if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
2792629303
if( nArg==2 ){
@@ -27934,11 +29311,11 @@
2793429311
2793529312
if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){
2793629313
if( nArg>=2 ){
2793729314
n = showHelp(p->out, azArg[1]);
2793829315
if( n==0 ){
27939
- oputf("Nothing matches '%s'\n", azArg[1]);
29316
+ sqlite3_fprintf(p->out, "Nothing matches '%s'\n", azArg[1]);
2794029317
}
2794129318
}else{
2794229319
showHelp(p->out, 0);
2794329320
}
2794429321
}else
@@ -27977,11 +29354,11 @@
2797729354
if( zFile==0 ){
2797829355
zFile = z;
2797929356
}else if( zTable==0 ){
2798029357
zTable = z;
2798129358
}else{
27982
- oputf("ERROR: extra argument: \"%s\". Usage:\n", z);
29359
+ sqlite3_fprintf(p->out, "ERROR: extra argument: \"%s\". Usage:\n",z);
2798329360
showHelp(p->out, "import");
2798429361
goto meta_command_exit;
2798529362
}
2798629363
}else if( cli_strcmp(z,"-v")==0 ){
2798729364
eVerbose++;
@@ -27998,17 +29375,17 @@
2799829375
sCtx.cColSep = ',';
2799929376
sCtx.cRowSep = '\n';
2800029377
xRead = csv_read_one_field;
2800129378
useOutputMode = 0;
2800229379
}else{
28003
- oputf("ERROR: unknown option: \"%s\". Usage:\n", z);
29380
+ sqlite3_fprintf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
2800429381
showHelp(p->out, "import");
2800529382
goto meta_command_exit;
2800629383
}
2800729384
}
2800829385
if( zTable==0 ){
28009
- oputf("ERROR: missing %s argument. Usage:\n",
29386
+ sqlite3_fprintf(p->out, "ERROR: missing %s argument. Usage:\n",
2801029387
zFile==0 ? "FILE" : "TABLE");
2801129388
showHelp(p->out, "import");
2801229389
goto meta_command_exit;
2801329390
}
2801429391
seenInterrupt = 0;
@@ -28054,32 +29431,32 @@
2805429431
if( sCtx.zFile[0]=='|' ){
2805529432
#ifdef SQLITE_OMIT_POPEN
2805629433
eputz("Error: pipes are not supported in this OS\n");
2805729434
goto meta_command_exit;
2805829435
#else
28059
- sCtx.in = popen(sCtx.zFile+1, "r");
29436
+ sCtx.in = sqlite3_popen(sCtx.zFile+1, "r");
2806029437
sCtx.zFile = "<pipe>";
2806129438
sCtx.xCloser = pclose;
2806229439
#endif
2806329440
}else{
28064
- sCtx.in = fopen(sCtx.zFile, "rb");
29441
+ sCtx.in = sqlite3_fopen(sCtx.zFile, "rb");
2806529442
sCtx.xCloser = fclose;
2806629443
}
2806729444
if( sCtx.in==0 ){
28068
- eputf("Error: cannot open \"%s\"\n", zFile);
29445
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
2806929446
goto meta_command_exit;
2807029447
}
2807129448
if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
2807229449
char zSep[2];
2807329450
zSep[1] = 0;
2807429451
zSep[0] = sCtx.cColSep;
28075
- oputz("Column separator ");
28076
- output_c_string(zSep);
28077
- oputz(", row separator ");
29452
+ sqlite3_fputs("Column separator ", p->out);
29453
+ output_c_string(p->out, zSep);
29454
+ sqlite3_fputs(", row separator ", p->out);
2807829455
zSep[0] = sCtx.cRowSep;
28079
- output_c_string(zSep);
28080
- oputz("\n");
29456
+ output_c_string(p->out, zSep);
29457
+ sqlite3_fputs("\n", p->out);
2808129458
}
2808229459
sCtx.z = sqlite3_malloc64(120);
2808329460
if( sCtx.z==0 ){
2808429461
import_cleanup(&sCtx);
2808529462
shell_out_of_memory();
@@ -28087,11 +29464,15 @@
2808729464
/* Below, resources must be freed before exit. */
2808829465
while( (nSkip--)>0 ){
2808929466
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
2809029467
}
2809129468
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
28092
- if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){
29469
+ if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0)
29470
+ && 0==db_int(p->db, "SELECT count(*) FROM \"%w\".sqlite_schema"
29471
+ " WHERE name=%Q AND type='view'",
29472
+ zSchema ? zSchema : "main", zTable)
29473
+ ){
2809329474
/* Table does not exist. Create it. */
2809429475
sqlite3 *dbCols = 0;
2809529476
char *zRenames = 0;
2809629477
char *zColDefs;
2809729478
zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
@@ -28100,18 +29481,18 @@
2810029481
zAutoColumn(sCtx.z, &dbCols, 0);
2810129482
if( sCtx.cTerm!=sCtx.cColSep ) break;
2810229483
}
2810329484
zColDefs = zAutoColumn(0, &dbCols, &zRenames);
2810429485
if( zRenames!=0 ){
28105
- sputf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
29486
+ sqlite3_fprintf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
2810629487
"Columns renamed during .import %s due to duplicates:\n"
2810729488
"%s\n", sCtx.zFile, zRenames);
2810829489
sqlite3_free(zRenames);
2810929490
}
2811029491
assert(dbCols==0);
2811129492
if( zColDefs==0 ){
28112
- eputf("%s: empty file\n", sCtx.zFile);
29493
+ sqlite3_fprintf(stderr,"%s: empty file\n", sCtx.zFile);
2811329494
import_cleanup(&sCtx);
2811429495
rc = 1;
2811529496
sqlite3_free(zCreate);
2811629497
goto meta_command_exit;
2811729498
}
@@ -28119,17 +29500,20 @@
2811929500
if( zCreate==0 ){
2812029501
import_cleanup(&sCtx);
2812129502
shell_out_of_memory();
2812229503
}
2812329504
if( eVerbose>=1 ){
28124
- oputf("%s\n", zCreate);
29505
+ sqlite3_fprintf(p->out, "%s\n", zCreate);
2812529506
}
2812629507
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
29508
+ if( rc ){
29509
+ sqlite3_fprintf(stderr,
29510
+ "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
29511
+ }
2812729512
sqlite3_free(zCreate);
2812829513
zCreate = 0;
2812929514
if( rc ){
28130
- eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
2813129515
import_cleanup(&sCtx);
2813229516
rc = 1;
2813329517
goto meta_command_exit;
2813429518
}
2813529519
}
@@ -28180,11 +29564,11 @@
2818029564
}
2818129565
zSql[j++] = ')';
2818229566
zSql[j] = 0;
2818329567
assert( j<nByte );
2818429568
if( eVerbose>=2 ){
28185
- oputf("Insert using: %s\n", zSql);
29569
+ sqlite3_fprintf(p->out, "Insert using: %s\n", zSql);
2818629570
}
2818729571
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2818829572
sqlite3_free(zSql);
2818929573
zSql = 0;
2819029574
if( rc ){
@@ -28219,11 +29603,11 @@
2821929603
if( z==0 && (xRead==csv_read_one_field) && i==nCol-1 && i>0 ){
2822029604
z = "";
2822129605
}
2822229606
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
2822329607
if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
28224
- eputf("%s:%d: expected %d columns but found %d"
29608
+ sqlite3_fprintf(stderr,"%s:%d: expected %d columns but found %d"
2822529609
" - filling the rest with NULL\n",
2822629610
sCtx.zFile, startLine, nCol, i+1);
2822729611
i += 2;
2822829612
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
2822929613
}
@@ -28231,18 +29615,19 @@
2823129615
if( sCtx.cTerm==sCtx.cColSep ){
2823229616
do{
2823329617
xRead(&sCtx);
2823429618
i++;
2823529619
}while( sCtx.cTerm==sCtx.cColSep );
28236
- eputf("%s:%d: expected %d columns but found %d - extras ignored\n",
29620
+ sqlite3_fprintf(stderr,
29621
+ "%s:%d: expected %d columns but found %d - extras ignored\n",
2823729622
sCtx.zFile, startLine, nCol, i);
2823829623
}
2823929624
if( i>=nCol ){
2824029625
sqlite3_step(pStmt);
2824129626
rc = sqlite3_reset(pStmt);
2824229627
if( rc!=SQLITE_OK ){
28243
- eputf("%s:%d: INSERT failed: %s\n",
29628
+ sqlite3_fprintf(stderr,"%s:%d: INSERT failed: %s\n",
2824429629
sCtx.zFile, startLine, sqlite3_errmsg(p->db));
2824529630
sCtx.nErr++;
2824629631
}else{
2824729632
sCtx.nRow++;
2824829633
}
@@ -28251,11 +29636,12 @@
2825129636
2825229637
import_cleanup(&sCtx);
2825329638
sqlite3_finalize(pStmt);
2825429639
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
2825529640
if( eVerbose>0 ){
28256
- oputf("Added %d rows with %d errors using %d lines of input\n",
29641
+ sqlite3_fprintf(p->out,
29642
+ "Added %d rows with %d errors using %d lines of input\n",
2825729643
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
2825829644
}
2825929645
}else
2826029646
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
2826129647
@@ -28267,11 +29653,11 @@
2826729653
int tnum = 0;
2826829654
int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
2826929655
int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
2827029656
int i;
2827129657
if( !ShellHasFlag(p,SHFLG_TestingMode) ){
28272
- eputf(".%s unavailable without --unsafe-testing\n",
29658
+ sqlite3_fprintf(stderr,".%s unavailable without --unsafe-testing\n",
2827329659
"imposter");
2827429660
rc = 1;
2827529661
goto meta_command_exit;
2827629662
}
2827729663
if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
@@ -28333,11 +29719,11 @@
2833329719
zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
2833429720
}
2833529721
}
2833629722
sqlite3_finalize(pStmt);
2833729723
if( i==0 || tnum==0 ){
28338
- eputf("no such index: \"%s\"\n", azArg[1]);
29724
+ sqlite3_fprintf(stderr,"no such index: \"%s\"\n", azArg[1]);
2833929725
rc = 1;
2834029726
sqlite3_free(zCollist);
2834129727
goto meta_command_exit;
2834229728
}
2834329729
if( lenPK==0 ) lenPK = 100000;
@@ -28348,18 +29734,20 @@
2834829734
rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
2834929735
if( rc==SQLITE_OK ){
2835029736
rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
2835129737
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
2835229738
if( rc ){
28353
- eputf("Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
29739
+ sqlite3_fprintf(stderr,
29740
+ "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
2835429741
}else{
28355
- sputf(stdout, "%s;\n", zSql);
28356
- sputf(stdout, "WARNING: writing to an imposter table will corrupt"
29742
+ sqlite3_fprintf(stdout, "%s;\n", zSql);
29743
+ sqlite3_fprintf(stdout,
29744
+ "WARNING: writing to an imposter table will corrupt"
2835729745
" the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index");
2835829746
}
2835929747
}else{
28360
- eputf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
29748
+ sqlite3_fprintf(stderr,"SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
2836129749
rc = 1;
2836229750
}
2836329751
sqlite3_free(zSql);
2836429752
}else
2836529753
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
@@ -28369,11 +29757,11 @@
2836929757
if( nArg==2 ){
2837029758
iArg = integerValue(azArg[1]);
2837129759
if( iArg==0 ) iArg = -1;
2837229760
}
2837329761
if( (nArg!=1 && nArg!=2) || iArg<0 ){
28374
- eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
29762
+ sqlite3_fprintf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n");
2837529763
rc = 1;
2837629764
goto meta_command_exit;
2837729765
}
2837829766
open_db(p, 0);
2837929767
rc = intckDatabaseCmd(p, iArg);
@@ -28388,13 +29776,13 @@
2838829776
sqlite3IoTrace = 0;
2838929777
}else if( cli_strcmp(azArg[1], "-")==0 ){
2839029778
sqlite3IoTrace = iotracePrintf;
2839129779
iotrace = stdout;
2839229780
}else{
28393
- iotrace = fopen(azArg[1], "w");
29781
+ iotrace = sqlite3_fopen(azArg[1], "w");
2839429782
if( iotrace==0 ){
28395
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
29783
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
2839629784
sqlite3IoTrace = 0;
2839729785
rc = 1;
2839829786
}else{
2839929787
sqlite3IoTrace = iotracePrintf;
2840029788
}
@@ -28422,11 +29810,11 @@
2842229810
};
2842329811
int i, n2;
2842429812
open_db(p, 0);
2842529813
if( nArg==1 ){
2842629814
for(i=0; i<ArraySize(aLimit); i++){
28427
- sputf(stdout, "%20s %d\n", aLimit[i].zLimitName,
29815
+ sqlite3_fprintf(stdout, "%20s %d\n", aLimit[i].zLimitName,
2842829816
sqlite3_limit(p->db, aLimit[i].limitCode, -1));
2842929817
}
2843029818
}else if( nArg>3 ){
2843129819
eputz("Usage: .limit NAME ?NEW-VALUE?\n");
2843229820
rc = 1;
@@ -28437,28 +29825,28 @@
2843729825
for(i=0; i<ArraySize(aLimit); i++){
2843829826
if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
2843929827
if( iLimit<0 ){
2844029828
iLimit = i;
2844129829
}else{
28442
- eputf("ambiguous limit: \"%s\"\n", azArg[1]);
29830
+ sqlite3_fprintf(stderr,"ambiguous limit: \"%s\"\n", azArg[1]);
2844329831
rc = 1;
2844429832
goto meta_command_exit;
2844529833
}
2844629834
}
2844729835
}
2844829836
if( iLimit<0 ){
28449
- eputf("unknown limit: \"%s\"\n"
29837
+ sqlite3_fprintf(stderr,"unknown limit: \"%s\"\n"
2845029838
"enter \".limits\" with no arguments for a list.\n",
2845129839
azArg[1]);
2845229840
rc = 1;
2845329841
goto meta_command_exit;
2845429842
}
2845529843
if( nArg==3 ){
2845629844
sqlite3_limit(p->db, aLimit[iLimit].limitCode,
2845729845
(int)integerValue(azArg[2]));
2845829846
}
28459
- sputf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
29847
+ sqlite3_fprintf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
2846029848
sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
2846129849
}
2846229850
}else
2846329851
2846429852
if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){
@@ -28503,11 +29891,11 @@
2850329891
" than \"on\" or \"off\"\n");
2850429892
zFile = "off";
2850529893
}
2850629894
output_file_close(p->pLog);
2850729895
if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
28508
- p->pLog = output_file_open(zFile, 0);
29896
+ p->pLog = output_file_open(zFile);
2850929897
}
2851029898
}else
2851129899
2851229900
if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
2851329901
const char *zMode = 0;
@@ -28537,35 +29925,37 @@
2853729925
cmOpts = cmo;
2853829926
}
2853929927
}else if( zTabname==0 ){
2854029928
zTabname = z;
2854129929
}else if( z[0]=='-' ){
28542
- eputf("unknown option: %s\n", z);
29930
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
2854329931
eputz("options:\n"
2854429932
" --noquote\n"
2854529933
" --quote\n"
2854629934
" --wordwrap on/off\n"
2854729935
" --wrap N\n"
2854829936
" --ww\n");
2854929937
rc = 1;
2855029938
goto meta_command_exit;
2855129939
}else{
28552
- eputf("extra argument: \"%s\"\n", z);
29940
+ sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
2855329941
rc = 1;
2855429942
goto meta_command_exit;
2855529943
}
2855629944
}
2855729945
if( zMode==0 ){
2855829946
if( p->mode==MODE_Column
2855929947
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
2856029948
){
28561
- oputf("current output mode: %s --wrap %d --wordwrap %s --%squote\n",
29949
+ sqlite3_fprintf(p->out,
29950
+ "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
2856229951
modeDescr[p->mode], p->cmOpts.iWrap,
2856329952
p->cmOpts.bWordWrap ? "on" : "off",
2856429953
p->cmOpts.bQuote ? "" : "no");
2856529954
}else{
28566
- oputf("current output mode: %s\n", modeDescr[p->mode]);
29955
+ sqlite3_fprintf(p->out,
29956
+ "current output mode: %s\n", modeDescr[p->mode]);
2856729957
}
2856829958
zMode = modeDescr[p->mode];
2856929959
}
2857029960
n2 = strlen30(zMode);
2857129961
if( cli_strncmp(zMode,"lines",n2)==0 ){
@@ -28634,11 +30024,11 @@
2863430024
if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){
2863530025
if( nArg!=2 ){
2863630026
eputz("Usage: .nonce NONCE\n");
2863730027
rc = 1;
2863830028
}else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
28639
- eputf("line %d: incorrect nonce: \"%s\"\n",
30029
+ sqlite3_fprintf(stderr,"line %d: incorrect nonce: \"%s\"\n",
2864030030
p->lineno, azArg[1]);
2864130031
exit(1);
2864230032
}else{
2864330033
p->bSafeMode = 0;
2864430034
return 0; /* Return immediately to bypass the safe mode reset
@@ -28689,15 +30079,15 @@
2868930079
p->szMax = integerValue(azArg[++iName]);
2869030080
#endif /* SQLITE_OMIT_DESERIALIZE */
2869130081
}else
2869230082
#endif /* !SQLITE_SHELL_FIDDLE */
2869330083
if( z[0]=='-' ){
28694
- eputf("unknown option: %s\n", z);
30084
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
2869530085
rc = 1;
2869630086
goto meta_command_exit;
2869730087
}else if( zFN ){
28698
- eputf("extra argument: \"%s\"\n", z);
30088
+ sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
2869930089
rc = 1;
2870030090
goto meta_command_exit;
2870130091
}else{
2870230092
zFN = z;
2870330093
}
@@ -28735,11 +30125,11 @@
2873530125
zNewFilename = 0;
2873630126
}
2873730127
p->pAuxDb->zDbFilename = zNewFilename;
2873830128
open_db(p, OPEN_DB_KEEPALIVE);
2873930129
if( p->db==0 ){
28740
- eputf("Error: cannot open '%s'\n", zNewFilename);
30130
+ sqlite3_fprintf(stderr,"Error: cannot open '%s'\n", zNewFilename);
2874130131
sqlite3_free(zNewFilename);
2874230132
}else{
2874330133
p->pAuxDb->zFreeOnClose = zNewFilename;
2874430134
}
2874530135
}
@@ -28753,22 +30143,26 @@
2875330143
#ifndef SQLITE_SHELL_FIDDLE
2875430144
if( (c=='o'
2875530145
&& (cli_strncmp(azArg[0], "output", n)==0
2875630146
|| cli_strncmp(azArg[0], "once", n)==0))
2875730147
|| (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
30148
+ || (c=='w' && n==3 && cli_strcmp(azArg[0],"www")==0)
2875830149
){
2875930150
char *zFile = 0;
28760
- int bTxtMode = 0;
2876130151
int i;
2876230152
int eMode = 0;
28763
- int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
28764
- static const char *zBomUtf8 = "\xef\xbb\xbf";
30153
+ int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */
30154
+ int bPlain = 0; /* --plain option */
30155
+ static const char *zBomUtf8 = "\357\273\277";
2876530156
const char *zBom = 0;
2876630157
2876730158
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
2876830159
if( c=='e' ){
2876930160
eMode = 'x';
30161
+ bOnce = 2;
30162
+ }else if( c=='w' ){
30163
+ eMode = 'w';
2877030164
bOnce = 2;
2877130165
}else if( cli_strncmp(azArg[0],"once",n)==0 ){
2877230166
bOnce = 1;
2877330167
}
2877430168
for(i=1; i<nArg; i++){
@@ -28775,28 +30169,34 @@
2877530169
char *z = azArg[i];
2877630170
if( z[0]=='-' ){
2877730171
if( z[1]=='-' ) z++;
2877830172
if( cli_strcmp(z,"-bom")==0 ){
2877930173
zBom = zBomUtf8;
28780
- }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
30174
+ }else if( cli_strcmp(z,"-plain")==0 ){
30175
+ bPlain = 1;
30176
+ }else if( c=='o' && cli_strcmp(z,"-x")==0 ){
2878130177
eMode = 'x'; /* spreadsheet */
28782
- }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
30178
+ }else if( c=='o' && cli_strcmp(z,"-e")==0 ){
2878330179
eMode = 'e'; /* text editor */
30180
+ }else if( c=='o' && cli_strcmp(z,"-w")==0 ){
30181
+ eMode = 'w'; /* Web browser */
2878430182
}else{
28785
- oputf("ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
30183
+ sqlite3_fprintf(p->out,
30184
+ "ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
2878630185
showHelp(p->out, azArg[0]);
2878730186
rc = 1;
2878830187
goto meta_command_exit;
2878930188
}
28790
- }else if( zFile==0 && eMode!='e' && eMode!='x' ){
30189
+ }else if( zFile==0 && eMode==0 ){
2879130190
zFile = sqlite3_mprintf("%s", z);
2879230191
if( zFile && zFile[0]=='|' ){
2879330192
while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
2879430193
break;
2879530194
}
2879630195
}else{
28797
- oputf("ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
30196
+ sqlite3_fprintf(p->out,
30197
+ "ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
2879830198
showHelp(p->out, azArg[0]);
2879930199
rc = 1;
2880030200
sqlite3_free(zFile);
2880130201
goto meta_command_exit;
2880230202
}
@@ -28809,24 +30209,31 @@
2880930209
}else{
2881030210
p->outCount = 0;
2881130211
}
2881230212
output_reset(p);
2881330213
#ifndef SQLITE_NOHAVE_SYSTEM
28814
- if( eMode=='e' || eMode=='x' ){
30214
+ if( eMode=='e' || eMode=='x' || eMode=='w' ){
2881530215
p->doXdgOpen = 1;
2881630216
outputModePush(p);
2881730217
if( eMode=='x' ){
2881830218
/* spreadsheet mode. Output as CSV. */
2881930219
newTempFile(p, "csv");
2882030220
ShellClearFlag(p, SHFLG_Echo);
2882130221
p->mode = MODE_Csv;
2882230222
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
2882330223
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
30224
+#ifdef _WIN32
30225
+ zBom = zBomUtf8; /* Always include the BOM on Windows, as Excel does
30226
+ ** not work without it. */
30227
+#endif
30228
+ }else if( eMode=='w' ){
30229
+ /* web-browser mode. */
30230
+ newTempFile(p, "html");
30231
+ if( !bPlain ) p->mode = MODE_Www;
2882430232
}else{
2882530233
/* text editor mode */
2882630234
newTempFile(p, "txt");
28827
- bTxtMode = 1;
2882830235
}
2882930236
sqlite3_free(zFile);
2883030237
zFile = sqlite3_mprintf("%s", p->zTempFile);
2883130238
}
2883230239
#endif /* SQLITE_NOHAVE_SYSTEM */
@@ -28835,30 +30242,36 @@
2883530242
#ifdef SQLITE_OMIT_POPEN
2883630243
eputz("Error: pipes are not supported in this OS\n");
2883730244
rc = 1;
2883830245
output_redir(p, stdout);
2883930246
#else
28840
- FILE *pfPipe = popen(zFile + 1, "w");
30247
+ FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
2884130248
if( pfPipe==0 ){
28842
- eputf("Error: cannot open pipe \"%s\"\n", zFile + 1);
30249
+ sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
2884330250
rc = 1;
2884430251
}else{
2884530252
output_redir(p, pfPipe);
28846
- if( zBom ) oputz(zBom);
30253
+ if( zBom ) sqlite3_fputs(zBom, pfPipe);
2884730254
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
2884830255
}
2884930256
#endif
2885030257
}else{
28851
- FILE *pfFile = output_file_open(zFile, bTxtMode);
30258
+ FILE *pfFile = output_file_open(zFile);
2885230259
if( pfFile==0 ){
2885330260
if( cli_strcmp(zFile,"off")!=0 ){
28854
- eputf("Error: cannot write to \"%s\"\n", zFile);
30261
+ sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
2885530262
}
2885630263
rc = 1;
2885730264
} else {
2885830265
output_redir(p, pfFile);
28859
- if( zBom ) oputz(zBom);
30266
+ if( zBom ) sqlite3_fputs(zBom, pfFile);
30267
+ if( bPlain && eMode=='w' ){
30268
+ sqlite3_fputs(
30269
+ "<!DOCTYPE html>\n<BODY>\n<PLAINTEXT>\n",
30270
+ pfFile
30271
+ );
30272
+ }
2886030273
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
2886130274
}
2886230275
}
2886330276
sqlite3_free(zFile);
2886430277
}else
@@ -28895,11 +30308,12 @@
2889530308
if( len ){
2889630309
rx = sqlite3_prepare_v2(p->db,
2889730310
"SELECT key, quote(value) "
2889830311
"FROM temp.sqlite_parameters;", -1, &pStmt, 0);
2889930312
while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
28900
- oputf("%-*s %s\n", len, sqlite3_column_text(pStmt,0),
30313
+ sqlite3_fprintf(p->out,
30314
+ "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
2890130315
sqlite3_column_text(pStmt,1));
2890230316
}
2890330317
sqlite3_finalize(pStmt);
2890430318
}
2890530319
}else
@@ -28940,11 +30354,11 @@
2894030354
"VALUES(%Q,%Q);", zKey, zValue);
2894130355
shell_check_oom(zSql);
2894230356
rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2894330357
sqlite3_free(zSql);
2894430358
if( rx!=SQLITE_OK ){
28945
- oputf("Error: %s\n", sqlite3_errmsg(p->db));
30359
+ sqlite3_fprintf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
2894630360
sqlite3_finalize(pStmt);
2894730361
pStmt = 0;
2894830362
rc = 1;
2894930363
}
2895030364
}
@@ -28969,14 +30383,14 @@
2896930383
}else
2897030384
2897130385
if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
2897230386
int i;
2897330387
for(i=1; i<nArg; i++){
28974
- if( i>1 ) oputz(" ");
28975
- oputz(azArg[i]);
30388
+ if( i>1 ) sqlite3_fputs(" ", p->out);
30389
+ sqlite3_fputs(azArg[i], p->out);
2897630390
}
28977
- oputz("\n");
30391
+ sqlite3_fputs("\n", p->out);
2897830392
}else
2897930393
2898030394
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
2898130395
if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){
2898230396
int i;
@@ -29009,11 +30423,11 @@
2900930423
}else{
2901030424
p->mxProgress = (int)integerValue(azArg[++i]);
2901130425
}
2901230426
continue;
2901330427
}
29014
- eputf("Error: unknown option: \"%s\"\n", azArg[i]);
30428
+ sqlite3_fprintf(stderr,"Error: unknown option: \"%s\"\n", azArg[i]);
2901530429
rc = 1;
2901630430
goto meta_command_exit;
2901730431
}else{
2901830432
nn = (int)integerValue(z);
2901930433
}
@@ -29050,23 +30464,22 @@
2905030464
}
2905130465
if( azArg[1][0]=='|' ){
2905230466
#ifdef SQLITE_OMIT_POPEN
2905330467
eputz("Error: pipes are not supported in this OS\n");
2905430468
rc = 1;
29055
- p->out = stdout;
2905630469
#else
29057
- p->in = popen(azArg[1]+1, "r");
30470
+ p->in = sqlite3_popen(azArg[1]+1, "r");
2905830471
if( p->in==0 ){
29059
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
30472
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
2906030473
rc = 1;
2906130474
}else{
2906230475
rc = process_input(p);
2906330476
pclose(p->in);
2906430477
}
2906530478
#endif
2906630479
}else if( (p->in = openChrSource(azArg[1]))==0 ){
29067
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
30480
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
2906830481
rc = 1;
2906930482
}else{
2907030483
rc = process_input(p);
2907130484
fclose(p->in);
2907230485
}
@@ -29095,11 +30508,11 @@
2909530508
rc = 1;
2909630509
goto meta_command_exit;
2909730510
}
2909830511
rc = sqlite3_open(zSrcFile, &pSrc);
2909930512
if( rc!=SQLITE_OK ){
29100
- eputf("Error: cannot open \"%s\"\n", zSrcFile);
30513
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zSrcFile);
2910130514
close_db(pSrc);
2910230515
return 1;
2910330516
}
2910430517
open_db(p, 0);
2910530518
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
@@ -29127,11 +30540,14 @@
2912730540
}
2912830541
close_db(pSrc);
2912930542
}else
2913030543
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
2913130544
29132
- if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
30545
+ if( c=='s' &&
30546
+ (cli_strncmp(azArg[0], "scanstats", n)==0 ||
30547
+ cli_strncmp(azArg[0], "scanstatus", n)==0)
30548
+ ){
2913330549
if( nArg==2 ){
2913430550
if( cli_strcmp(azArg[1], "vm")==0 ){
2913530551
p->scanstatsOn = 3;
2913630552
}else
2913730553
if( cli_strcmp(azArg[1], "est")==0 ){
@@ -29178,11 +30594,11 @@
2917830594
}else if( optionMatch(azArg[ii],"debug") ){
2917930595
bDebug = 1;
2918030596
}else if( optionMatch(azArg[ii],"nosys") ){
2918130597
bNoSystemTabs = 1;
2918230598
}else if( azArg[ii][0]=='-' ){
29183
- eputf("Unknown option: \"%s\"\n", azArg[ii]);
30599
+ sqlite3_fprintf(stderr,"Unknown option: \"%s\"\n", azArg[ii]);
2918430600
rc = 1;
2918530601
goto meta_command_exit;
2918630602
}else if( zName==0 ){
2918730603
zName = azArg[ii];
2918830604
}else{
@@ -29279,11 +30695,11 @@
2927930695
appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
2928030696
}
2928130697
appendText(&sSelect, "sql IS NOT NULL"
2928230698
" ORDER BY snum, rowid", 0);
2928330699
if( bDebug ){
29284
- oputf("SQL: %s;\n", sSelect.z);
30700
+ sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.z);
2928530701
}else{
2928630702
rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
2928730703
}
2928830704
freeText(&sSelect);
2928930705
}
@@ -29340,11 +30756,12 @@
2934030756
session_not_open:
2934130757
eputz("ERROR: No sessions are open\n");
2934230758
}else{
2934330759
rc = sqlite3session_attach(pSession->p, azCmd[1]);
2934430760
if( rc ){
29345
- eputf("ERROR: sqlite3session_attach() returns %d\n",rc);
30761
+ sqlite3_fprintf(stderr,
30762
+ "ERROR: sqlite3session_attach() returns %d\n",rc);
2934630763
rc = 0;
2934730764
}
2934830765
}
2934930766
}else
2935030767
@@ -29357,13 +30774,13 @@
2935730774
){
2935830775
FILE *out = 0;
2935930776
failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
2936030777
if( nCmd!=2 ) goto session_syntax_error;
2936130778
if( pSession->p==0 ) goto session_not_open;
29362
- out = fopen(azCmd[1], "wb");
30779
+ out = sqlite3_fopen(azCmd[1], "wb");
2936330780
if( out==0 ){
29364
- eputf("ERROR: cannot open \"%s\" for writing\n",
30781
+ sqlite3_fprintf(stderr,"ERROR: cannot open \"%s\" for writing\n",
2936530782
azCmd[1]);
2936630783
}else{
2936730784
int szChng;
2936830785
void *pChng;
2936930786
if( azCmd[0][0]=='c' ){
@@ -29370,16 +30787,17 @@
2937030787
rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
2937130788
}else{
2937230789
rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
2937330790
}
2937430791
if( rc ){
29375
- sputf(stdout, "Error: error code %d\n", rc);
30792
+ sqlite3_fprintf(stdout, "Error: error code %d\n", rc);
2937630793
rc = 0;
2937730794
}
2937830795
if( pChng
2937930796
&& fwrite(pChng, szChng, 1, out)!=1 ){
29380
- eputf("ERROR: Failed to write entire %d-byte output\n", szChng);
30797
+ sqlite3_fprintf(stderr,
30798
+ "ERROR: Failed to write entire %d-byte output\n", szChng);
2938130799
}
2938230800
sqlite3_free(pChng);
2938330801
fclose(out);
2938430802
}
2938530803
}else
@@ -29402,11 +30820,12 @@
2940230820
int ii;
2940330821
if( nCmd>2 ) goto session_syntax_error;
2940430822
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
2940530823
if( pAuxDb->nSession ){
2940630824
ii = sqlite3session_enable(pSession->p, ii);
29407
- oputf("session %s enable flag = %d\n", pSession->zName, ii);
30825
+ sqlite3_fprintf(p->out,
30826
+ "session %s enable flag = %d\n", pSession->zName, ii);
2940830827
}
2940930828
}else
2941030829
2941130830
/* .session filter GLOB ....
2941230831
** Set a list of GLOB patterns of table names to be excluded.
@@ -29437,11 +30856,12 @@
2943730856
int ii;
2943830857
if( nCmd>2 ) goto session_syntax_error;
2943930858
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
2944030859
if( pAuxDb->nSession ){
2944130860
ii = sqlite3session_indirect(pSession->p, ii);
29442
- oputf("session %s indirect flag = %d\n", pSession->zName, ii);
30861
+ sqlite3_fprintf(p->out,
30862
+ "session %s indirect flag = %d\n", pSession->zName, ii);
2944330863
}
2944430864
}else
2944530865
2944630866
/* .session isempty
2944730867
** Determine if the session is empty
@@ -29449,20 +30869,21 @@
2944930869
if( cli_strcmp(azCmd[0], "isempty")==0 ){
2945030870
int ii;
2945130871
if( nCmd!=1 ) goto session_syntax_error;
2945230872
if( pAuxDb->nSession ){
2945330873
ii = sqlite3session_isempty(pSession->p);
29454
- oputf("session %s isempty flag = %d\n", pSession->zName, ii);
30874
+ sqlite3_fprintf(p->out,
30875
+ "session %s isempty flag = %d\n", pSession->zName, ii);
2945530876
}
2945630877
}else
2945730878
2945830879
/* .session list
2945930880
** List all currently open sessions
2946030881
*/
2946130882
if( cli_strcmp(azCmd[0],"list")==0 ){
2946230883
for(i=0; i<pAuxDb->nSession; i++){
29463
- oputf("%d %s\n", i, pAuxDb->aSession[i].zName);
30884
+ sqlite3_fprintf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
2946430885
}
2946530886
}else
2946630887
2946730888
/* .session open DB NAME
2946830889
** Open a new session called NAME on the attached database DB.
@@ -29473,22 +30894,23 @@
2947330894
if( nCmd!=3 ) goto session_syntax_error;
2947430895
zName = azCmd[2];
2947530896
if( zName[0]==0 ) goto session_syntax_error;
2947630897
for(i=0; i<pAuxDb->nSession; i++){
2947730898
if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
29478
- eputf("Session \"%s\" already exists\n", zName);
30899
+ sqlite3_fprintf(stderr,"Session \"%s\" already exists\n", zName);
2947930900
goto meta_command_exit;
2948030901
}
2948130902
}
2948230903
if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
29483
- eputf("Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
30904
+ sqlite3_fprintf(stderr,
30905
+ "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
2948430906
goto meta_command_exit;
2948530907
}
2948630908
pSession = &pAuxDb->aSession[pAuxDb->nSession];
2948730909
rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
2948830910
if( rc ){
29489
- eputf("Cannot open session: error code=%d\n", rc);
30911
+ sqlite3_fprintf(stderr,"Cannot open session: error code=%d\n", rc);
2949030912
rc = 0;
2949130913
goto meta_command_exit;
2949230914
}
2949330915
pSession->nFilter = 0;
2949430916
sqlite3session_table_filter(pSession->p, session_filter, pSession);
@@ -29508,20 +30930,20 @@
2950830930
if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){
2950930931
if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){
2951030932
int i, v;
2951130933
for(i=1; i<nArg; i++){
2951230934
v = booleanValue(azArg[i]);
29513
- oputf("%s: %d 0x%x\n", azArg[i], v, v);
30935
+ sqlite3_fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
2951430936
}
2951530937
}
2951630938
if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
2951730939
int i; sqlite3_int64 v;
2951830940
for(i=1; i<nArg; i++){
2951930941
char zBuf[200];
2952030942
v = integerValue(azArg[i]);
2952130943
sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
29522
- oputz(zBuf);
30944
+ sqlite3_fputs(zBuf, p->out);
2952330945
}
2952430946
}
2952530947
}else
2952630948
#endif
2952730949
@@ -29544,12 +30966,13 @@
2954430966
}else
2954530967
if( cli_strcmp(z,"-v")==0 ){
2954630968
bVerbose++;
2954730969
}else
2954830970
{
29549
- eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
29550
- eputz("Should be one of: --init -v\n");
30971
+ sqlite3_fprintf(stderr,
30972
+ "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
30973
+ sqlite3_fputs("Should be one of: --init -v\n", stderr);
2955130974
rc = 1;
2955230975
goto meta_command_exit;
2955330976
}
2955430977
}
2955530978
if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
@@ -29590,46 +31013,47 @@
2959031013
if( zOp==0 ) continue;
2959131014
if( zSql==0 ) continue;
2959231015
if( zAns==0 ) continue;
2959331016
k = 0;
2959431017
if( bVerbose>0 ){
29595
- sputf(stdout, "%d: %s %s\n", tno, zOp, zSql);
31018
+ sqlite3_fprintf(stdout, "%d: %s %s\n", tno, zOp, zSql);
2959631019
}
2959731020
if( cli_strcmp(zOp,"memo")==0 ){
29598
- oputf("%s\n", zSql);
31021
+ sqlite3_fprintf(p->out, "%s\n", zSql);
2959931022
}else
2960031023
if( cli_strcmp(zOp,"run")==0 ){
2960131024
char *zErrMsg = 0;
2960231025
str.n = 0;
2960331026
str.z[0] = 0;
2960431027
rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
2960531028
nTest++;
2960631029
if( bVerbose ){
29607
- oputf("Result: %s\n", str.z);
31030
+ sqlite3_fprintf(p->out, "Result: %s\n", str.z);
2960831031
}
2960931032
if( rc || zErrMsg ){
2961031033
nErr++;
2961131034
rc = 1;
29612
- oputf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
31035
+ sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg);
2961331036
sqlite3_free(zErrMsg);
2961431037
}else if( cli_strcmp(zAns,str.z)!=0 ){
2961531038
nErr++;
2961631039
rc = 1;
29617
- oputf("%d: Expected: [%s]\n", tno, zAns);
29618
- oputf("%d: Got: [%s]\n", tno, str.z);
31040
+ sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns);
31041
+ sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.z);
2961931042
}
2962031043
}
2962131044
else{
29622
- eputf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
31045
+ sqlite3_fprintf(stderr,
31046
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
2962331047
rc = 1;
2962431048
break;
2962531049
}
2962631050
} /* End loop over rows of content from SELFTEST */
2962731051
sqlite3_finalize(pStmt);
2962831052
} /* End loop over k */
2962931053
freeText(&str);
29630
- oputf("%d errors out of %d tests\n", nErr, nTest);
31054
+ sqlite3_fprintf(p->out, "%d errors out of %d tests\n", nErr, nTest);
2963131055
}else
2963231056
2963331057
if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
2963431058
if( nArg<2 || nArg>3 ){
2963531059
eputz("Usage: .separator COL ?ROW?\n");
@@ -29673,11 +31097,12 @@
2967331097
}else
2967431098
if( cli_strcmp(z,"debug")==0 ){
2967531099
bDebug = 1;
2967631100
}else
2967731101
{
29678
- eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
31102
+ sqlite3_fprintf(stderr,
31103
+ "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
2967931104
showHelp(p->out, azArg[0]);
2968031105
rc = 1;
2968131106
goto meta_command_exit;
2968231107
}
2968331108
}else if( zLike ){
@@ -29751,11 +31176,11 @@
2975131176
}
2975231177
shell_check_oom(zSql);
2975331178
freeText(&sQuery);
2975431179
freeText(&sSql);
2975531180
if( bDebug ){
29756
- oputf("%s\n", zSql);
31181
+ sqlite3_fprintf(p->out, "%s\n", zSql);
2975731182
}else{
2975831183
shell_exec(p, zSql, 0);
2975931184
}
2976031185
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE)
2976131186
{
@@ -29781,11 +31206,11 @@
2978131206
"||group_concat('CAST(CAST('||cname||' AS BLOB) AS TEXT)<>'||cname\n"
2978231207
"|| ' AND typeof('||cname||')=''text'' ',\n"
2978331208
"' OR ') as query, tname from tabcols group by tname)"
2978431209
, zRevText);
2978531210
shell_check_oom(zRevText);
29786
- if( bDebug ) oputf("%s\n", zRevText);
31211
+ if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zRevText);
2978731212
lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
2978831213
if( lrc!=SQLITE_OK ){
2978931214
/* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
2979031215
** user does cruel and unnatural things like ".limit expr_depth 0". */
2979131216
rc = 1;
@@ -29794,19 +31219,20 @@
2979431219
lrc = SQLITE_ROW==sqlite3_step(pStmt);
2979531220
if( lrc ){
2979631221
const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
2979731222
sqlite3_stmt *pCheckStmt;
2979831223
lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
29799
- if( bDebug ) oputf("%s\n", zGenQuery);
31224
+ if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zGenQuery);
2980031225
if( lrc!=SQLITE_OK ){
2980131226
rc = 1;
2980231227
}else{
2980331228
if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
2980431229
double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
2980531230
if( countIrreversible>0 ){
2980631231
int sz = (int)(countIrreversible + 0.5);
29807
- eputf("Digest includes %d invalidly encoded text field%s.\n",
31232
+ sqlite3_fprintf(stderr,
31233
+ "Digest includes %d invalidly encoded text field%s.\n",
2980831234
sz, (sz>1)? "s": "");
2980931235
}
2981031236
}
2981131237
sqlite3_finalize(pCheckStmt);
2981231238
}
@@ -29836,15 +31262,15 @@
2983631262
zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
2983731263
for(i=2; i<nArg && zCmd!=0; i++){
2983831264
zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
2983931265
zCmd, azArg[i]);
2984031266
}
29841
- consoleRestore();
31267
+ /*consoleRestore();*/
2984231268
x = zCmd!=0 ? system(zCmd) : 1;
29843
- consoleRenewSetup();
31269
+ /*consoleRenewSetup();*/
2984431270
sqlite3_free(zCmd);
29845
- if( x ) eputf("System command returns %d\n", x);
31271
+ if( x ) sqlite3_fprintf(stderr,"System command returns %d\n", x);
2984631272
}else
2984731273
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
2984831274
2984931275
if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
2985031276
static const char *azBool[] = { "off", "on", "trigger", "full"};
@@ -29853,50 +31279,52 @@
2985331279
if( nArg!=1 ){
2985431280
eputz("Usage: .show\n");
2985531281
rc = 1;
2985631282
goto meta_command_exit;
2985731283
}
29858
- oputf("%12.12s: %s\n","echo",
31284
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","echo",
2985931285
azBool[ShellHasFlag(p, SHFLG_Echo)]);
29860
- oputf("%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
29861
- oputf("%12.12s: %s\n","explain",
31286
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
31287
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","explain",
2986231288
p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
29863
- oputf("%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
31289
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","headers",
31290
+ azBool[p->showHeader!=0]);
2986431291
if( p->mode==MODE_Column
2986531292
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
2986631293
){
29867
- oputf("%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
31294
+ sqlite3_fprintf(p->out,
31295
+ "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
2986831296
modeDescr[p->mode], p->cmOpts.iWrap,
2986931297
p->cmOpts.bWordWrap ? "on" : "off",
2987031298
p->cmOpts.bQuote ? "" : "no");
2987131299
}else{
29872
- oputf("%12.12s: %s\n","mode", modeDescr[p->mode]);
31300
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
2987331301
}
29874
- oputf("%12.12s: ", "nullvalue");
29875
- output_c_string(p->nullValue);
29876
- oputz("\n");
29877
- oputf("%12.12s: %s\n","output",
31302
+ sqlite3_fprintf(p->out, "%12.12s: ", "nullvalue");
31303
+ output_c_string(p->out, p->nullValue);
31304
+ sqlite3_fputs("\n", p->out);
31305
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","output",
2987831306
strlen30(p->outfile) ? p->outfile : "stdout");
29879
- oputf("%12.12s: ", "colseparator");
29880
- output_c_string(p->colSeparator);
29881
- oputz("\n");
29882
- oputf("%12.12s: ", "rowseparator");
29883
- output_c_string(p->rowSeparator);
29884
- oputz("\n");
31307
+ sqlite3_fprintf(p->out, "%12.12s: ", "colseparator");
31308
+ output_c_string(p->out, p->colSeparator);
31309
+ sqlite3_fputs("\n", p->out);
31310
+ sqlite3_fprintf(p->out, "%12.12s: ", "rowseparator");
31311
+ output_c_string(p->out, p->rowSeparator);
31312
+ sqlite3_fputs("\n", p->out);
2988531313
switch( p->statsOn ){
2988631314
case 0: zOut = "off"; break;
2988731315
default: zOut = "on"; break;
2988831316
case 2: zOut = "stmt"; break;
2988931317
case 3: zOut = "vmstep"; break;
2989031318
}
29891
- oputf("%12.12s: %s\n","stats", zOut);
29892
- oputf("%12.12s: ", "width");
31319
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","stats", zOut);
31320
+ sqlite3_fprintf(p->out, "%12.12s: ", "width");
2989331321
for (i=0;i<p->nWidth;i++) {
29894
- oputf("%d ", p->colWidth[i]);
31322
+ sqlite3_fprintf(p->out, "%d ", p->colWidth[i]);
2989531323
}
29896
- oputz("\n");
29897
- oputf("%12.12s: %s\n", "filename",
31324
+ sqlite3_fputs("\n", p->out);
31325
+ sqlite3_fprintf(p->out, "%12.12s: %s\n", "filename",
2989831326
p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
2989931327
}else
2990031328
2990131329
if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){
2990231330
if( nArg==2 ){
@@ -30010,13 +31438,14 @@
3001031438
if( nPrintCol<1 ) nPrintCol = 1;
3001131439
nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
3001231440
for(i=0; i<nPrintRow; i++){
3001331441
for(j=i; j<nRow; j+=nPrintRow){
3001431442
char *zSp = j<nPrintRow ? "" : " ";
30015
- oputf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
31443
+ sqlite3_fprintf(p->out,
31444
+ "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
3001631445
}
30017
- oputz("\n");
31446
+ sqlite3_fputs("\n", p->out);
3001831447
}
3001931448
}
3002031449
3002131450
for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
3002231451
sqlite3_free(azResult);
@@ -30024,11 +31453,11 @@
3002431453
3002531454
#ifndef SQLITE_SHELL_FIDDLE
3002631455
/* Begin redirecting output to the file "testcase-out.txt" */
3002731456
if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
3002831457
output_reset(p);
30029
- p->out = output_file_open("testcase-out.txt", 0);
31458
+ p->out = output_file_open("testcase-out.txt");
3003031459
if( p->out==0 ){
3003131460
eputz("Error: cannot open 'testcase-out.txt'\n");
3003231461
}
3003331462
if( nArg>=2 ){
3003431463
sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
@@ -30068,11 +31497,10 @@
3006831497
{"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" },
3006931498
{"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" },
3007031499
{"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
3007131500
{"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
3007231501
{"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
30073
- {"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"},
3007431502
};
3007531503
int testctrl = -1;
3007631504
int iCtrl = -1;
3007731505
int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
3007831506
int isOk = 0;
@@ -30088,14 +31516,14 @@
3008831516
if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
3008931517
}
3009031518
3009131519
/* --help lists all test-controls */
3009231520
if( cli_strcmp(zCmd,"help")==0 ){
30093
- oputz("Available test-controls:\n");
31521
+ sqlite3_fputs("Available test-controls:\n", p->out);
3009431522
for(i=0; i<ArraySize(aCtrl); i++){
3009531523
if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
30096
- oputf(" .testctrl %s %s\n",
31524
+ sqlite3_fprintf(p->out, " .testctrl %s %s\n",
3009731525
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
3009831526
}
3009931527
rc = 1;
3010031528
goto meta_command_exit;
3010131529
}
@@ -30108,19 +31536,19 @@
3010831536
if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
3010931537
if( testctrl<0 ){
3011031538
testctrl = aCtrl[i].ctrlCode;
3011131539
iCtrl = i;
3011231540
}else{
30113
- eputf("Error: ambiguous test-control: \"%s\"\n"
31541
+ sqlite3_fprintf(stderr,"Error: ambiguous test-control: \"%s\"\n"
3011431542
"Use \".testctrl --help\" for help\n", zCmd);
3011531543
rc = 1;
3011631544
goto meta_command_exit;
3011731545
}
3011831546
}
3011931547
}
3012031548
if( testctrl<0 ){
30121
- eputf("Error: unknown test-control: %s\n"
31549
+ sqlite3_fprintf(stderr,"Error: unknown test-control: %s\n"
3012231550
"Use \".testctrl --help\" for help\n", zCmd);
3012331551
}else{
3012431552
switch(testctrl){
3012531553
3012631554
/* Special processing for .testctrl opt MASK ...
@@ -30170,11 +31598,13 @@
3017031598
{ 0x10000000, 1, "OrderBySubq" },
3017131599
{ 0xffffffff, 0, "All" },
3017231600
};
3017331601
unsigned int curOpt;
3017431602
unsigned int newOpt;
31603
+ unsigned int m;
3017531604
int ii;
31605
+ int nOff;
3017631606
sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
3017731607
newOpt = curOpt;
3017831608
for(ii=2; ii<nArg; ii++){
3017931609
const char *z = azArg[ii];
3018031610
int useLabel = 0;
@@ -30192,16 +31622,17 @@
3019231622
int jj;
3019331623
for(jj=0; jj<ArraySize(aLabel); jj++){
3019431624
if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
3019531625
}
3019631626
if( jj>=ArraySize(aLabel) ){
30197
- eputf("Error: no such optimization: \"%s\"\n", zLabel);
30198
- eputz("Should be one of:");
31627
+ sqlite3_fprintf(stderr,
31628
+ "Error: no such optimization: \"%s\"\n", zLabel);
31629
+ sqlite3_fputs("Should be one of:", stderr);
3019931630
for(jj=0; jj<ArraySize(aLabel); jj++){
30200
- eputf(" %s", aLabel[jj].zLabel);
31631
+ sqlite3_fprintf(stderr," %s", aLabel[jj].zLabel);
3020131632
}
30202
- eputz("\n");
31633
+ sqlite3_fputs("\n", stderr);
3020331634
rc = 1;
3020431635
goto meta_command_exit;
3020531636
}
3020631637
if( useLabel=='+' ){
3020731638
newOpt &= ~aLabel[jj].mask;
@@ -30210,28 +31641,32 @@
3021031641
}
3021131642
}
3021231643
}
3021331644
if( curOpt!=newOpt ){
3021431645
sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
30215
- }else if( nArg<3 ){
30216
- curOpt = ~newOpt;
31646
+ }
31647
+ for(ii=nOff=0, m=1; ii<32; ii++, m <<= 1){
31648
+ if( m & newOpt ) nOff++;
3021731649
}
30218
- if( newOpt==0 ){
30219
- oputz("+All\n");
30220
- }else if( newOpt==0xffffffff ){
30221
- oputz("-All\n");
31650
+ if( nOff<12 ){
31651
+ sqlite3_fputs("+All", p->out);
31652
+ for(ii=0; ii<ArraySize(aLabel); ii++){
31653
+ if( !aLabel[ii].bDsply ) continue;
31654
+ if( (newOpt & aLabel[ii].mask)!=0 ){
31655
+ sqlite3_fprintf(p->out, " -%s", aLabel[ii].zLabel);
31656
+ }
31657
+ }
3022231658
}else{
30223
- int jj;
30224
- for(jj=0; jj<ArraySize(aLabel); jj++){
30225
- unsigned int m = aLabel[jj].mask;
30226
- if( !aLabel[jj].bDsply ) continue;
30227
- if( (curOpt&m)!=(newOpt&m) ){
30228
- oputf("%c%s\n", (newOpt & m)==0 ? '+' : '-',
30229
- aLabel[jj].zLabel);
31659
+ sqlite3_fputs("-All", p->out);
31660
+ for(ii=0; ii<ArraySize(aLabel); ii++){
31661
+ if( !aLabel[ii].bDsply ) continue;
31662
+ if( (newOpt & aLabel[ii].mask)==0 ){
31663
+ sqlite3_fprintf(p->out, " +%s", aLabel[ii].zLabel);
3023031664
}
3023131665
}
3023231666
}
31667
+ sqlite3_fputs("\n", p->out);
3023331668
rc2 = isOk = 3;
3023431669
break;
3023531670
}
3023631671
3023731672
/* sqlite3_test_control(int, db, int) */
@@ -30267,11 +31702,11 @@
3026731702
if( nArg==3 || nArg==4 ){
3026831703
int ii = (int)integerValue(azArg[2]);
3026931704
sqlite3 *db;
3027031705
if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
3027131706
sqlite3_randomness(sizeof(ii),&ii);
30272
- sputf(stdout, "-- random seed: %d\n", ii);
31707
+ sqlite3_fprintf(stdout, "-- random seed: %d\n", ii);
3027331708
}
3027431709
if( nArg==3 ){
3027531710
db = 0;
3027631711
}else{
3027731712
db = p->db;
@@ -30301,25 +31736,10 @@
3030131736
rc2 = sqlite3_test_control(testctrl, opt);
3030231737
isOk = 3;
3030331738
}
3030431739
break;
3030531740
30306
- /* sqlite3_test_control(int, int) */
30307
- case SQLITE_TESTCTRL_USELONGDOUBLE: {
30308
- int opt = -1;
30309
- if( nArg==3 ){
30310
- if( cli_strcmp(azArg[2],"default")==0 ){
30311
- opt = 2;
30312
- }else{
30313
- opt = booleanValue(azArg[2]);
30314
- }
30315
- }
30316
- rc2 = sqlite3_test_control(testctrl, opt);
30317
- isOk = 1;
30318
- break;
30319
- }
30320
-
3032131741
/* sqlite3_test_control(sqlite3*) */
3032231742
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
3032331743
rc2 = sqlite3_test_control(testctrl, p->db);
3032431744
isOk = 3;
3032531745
break;
@@ -30335,11 +31755,11 @@
3033531755
break;
3033631756
3033731757
case SQLITE_TESTCTRL_SEEK_COUNT: {
3033831758
u64 x = 0;
3033931759
rc2 = sqlite3_test_control(testctrl, p->db, &x);
30340
- oputf("%llu\n", x);
31760
+ sqlite3_fprintf(p->out, "%llu\n", x);
3034131761
isOk = 3;
3034231762
break;
3034331763
}
3034431764
3034531765
#ifdef YYCOVERAGE
@@ -30366,15 +31786,15 @@
3036631786
int id = 1;
3036731787
while(1){
3036831788
int val = 0;
3036931789
rc2 = sqlite3_test_control(testctrl, -id, &val);
3037031790
if( rc2!=SQLITE_OK ) break;
30371
- if( id>1 ) oputz(" ");
30372
- oputf("%d: %d", id, val);
31791
+ if( id>1 ) sqlite3_fputs(" ", p->out);
31792
+ sqlite3_fprintf(p->out, "%d: %d", id, val);
3037331793
id++;
3037431794
}
30375
- if( id>1 ) oputz("\n");
31795
+ if( id>1 ) sqlite3_fputs("\n", p->out);
3037631796
isOk = 3;
3037731797
}
3037831798
break;
3037931799
}
3038031800
#endif
@@ -30412,18 +31832,26 @@
3041231832
}else if( cli_strcmp(z,"reset")==0 ){
3041331833
faultsim_state.iCnt = faultsim_state.nSkip;
3041431834
faultsim_state.nHit = 0;
3041531835
sqlite3_test_control(testctrl, faultsim_callback);
3041631836
}else if( cli_strcmp(z,"status")==0 ){
30417
- oputf("faultsim.iId: %d\n", faultsim_state.iId);
30418
- oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
30419
- oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
30420
- oputf("faultsim.nHit: %d\n", faultsim_state.nHit);
30421
- oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
30422
- oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
30423
- oputf("faultsim.nRepeat: %d\n", faultsim_state.nRepeat);
30424
- oputf("faultsim.nSkip: %d\n", faultsim_state.nSkip);
31837
+ sqlite3_fprintf(p->out, "faultsim.iId: %d\n",
31838
+ faultsim_state.iId);
31839
+ sqlite3_fprintf(p->out, "faultsim.iErr: %d\n",
31840
+ faultsim_state.iErr);
31841
+ sqlite3_fprintf(p->out, "faultsim.iCnt: %d\n",
31842
+ faultsim_state.iCnt);
31843
+ sqlite3_fprintf(p->out, "faultsim.nHit: %d\n",
31844
+ faultsim_state.nHit);
31845
+ sqlite3_fprintf(p->out, "faultsim.iInterval: %d\n",
31846
+ faultsim_state.iInterval);
31847
+ sqlite3_fprintf(p->out, "faultsim.eVerbose: %d\n",
31848
+ faultsim_state.eVerbose);
31849
+ sqlite3_fprintf(p->out, "faultsim.nRepeat: %d\n",
31850
+ faultsim_state.nRepeat);
31851
+ sqlite3_fprintf(p->out, "faultsim.nSkip: %d\n",
31852
+ faultsim_state.nSkip);
3042531853
}else if( cli_strcmp(z,"-v")==0 ){
3042631854
if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
3042731855
}else if( cli_strcmp(z,"-q")==0 ){
3042831856
if( faultsim_state.eVerbose>0 ) faultsim_state.eVerbose--;
3042931857
}else if( cli_strcmp(z,"-id")==0 && kk+1<nArg ){
@@ -30437,19 +31865,20 @@
3043731865
}else if( cli_strcmp(z,"-skip")==0 && kk+1<nArg ){
3043831866
faultsim_state.nSkip = atoi(azArg[++kk]);
3043931867
}else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
3044031868
bShowHelp = 1;
3044131869
}else{
30442
- eputf("Unrecognized fault_install argument: \"%s\"\n",
31870
+ sqlite3_fprintf(stderr,
31871
+ "Unrecognized fault_install argument: \"%s\"\n",
3044331872
azArg[kk]);
3044431873
rc = 1;
3044531874
bShowHelp = 1;
3044631875
break;
3044731876
}
3044831877
}
3044931878
if( bShowHelp ){
30450
- oputz(
31879
+ sqlite3_fputs(
3045131880
"Usage: .testctrl fault_install ARGS\n"
3045231881
"Possible arguments:\n"
3045331882
" off Disable faultsim\n"
3045431883
" on Activate faultsim\n"
3045531884
" reset Reset the trigger counter\n"
@@ -30459,23 +31888,25 @@
3045931888
" --errcode N When triggered, return N as error code\n"
3046031889
" --id ID Trigger only for the ID specified\n"
3046131890
" --interval N Trigger only after every N-th call\n"
3046231891
" --repeat N Turn off after N hits. 0 means never\n"
3046331892
" --skip N Skip the first N encounters\n"
31893
+ ,p->out
3046431894
);
3046531895
}
3046631896
break;
3046731897
}
3046831898
}
3046931899
}
3047031900
if( isOk==0 && iCtrl>=0 ){
30471
- oputf("Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
31901
+ sqlite3_fprintf(p->out,
31902
+ "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
3047231903
rc = 1;
3047331904
}else if( isOk==1 ){
30474
- oputf("%d\n", rc2);
31905
+ sqlite3_fprintf(p->out, "%d\n", rc2);
3047531906
}else if( isOk==2 ){
30476
- oputf("0x%08x\n", rc2);
31907
+ sqlite3_fprintf(p->out, "0x%08x\n", rc2);
3047731908
}
3047831909
}else
3047931910
#endif /* !defined(SQLITE_UNTESTABLE) */
3048031911
3048131912
if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){
@@ -30526,17 +31957,17 @@
3052631957
}
3052731958
else if( optionMatch(z, "close") ){
3052831959
mType |= SQLITE_TRACE_CLOSE;
3052931960
}
3053031961
else {
30531
- eputf("Unknown option \"%s\" on \".trace\"\n", z);
31962
+ sqlite3_fprintf(stderr,"Unknown option \"%s\" on \".trace\"\n", z);
3053231963
rc = 1;
3053331964
goto meta_command_exit;
3053431965
}
3053531966
}else{
3053631967
output_file_close(p->traceOut);
30537
- p->traceOut = output_file_open(z, 0);
31968
+ p->traceOut = output_file_open(z);
3053831969
}
3053931970
}
3054031971
if( p->traceOut==0 ){
3054131972
sqlite3_trace_v2(p->db, 0, 0, 0);
3054231973
}else{
@@ -30569,103 +32000,40 @@
3056932000
}
3057032001
}
3057132002
}else
3057232003
#endif
3057332004
30574
-#if SQLITE_USER_AUTHENTICATION
30575
- if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
30576
- if( nArg<2 ){
30577
- eputz("Usage: .user SUBCOMMAND ...\n");
30578
- rc = 1;
30579
- goto meta_command_exit;
30580
- }
30581
- open_db(p, 0);
30582
- if( cli_strcmp(azArg[1],"login")==0 ){
30583
- if( nArg!=4 ){
30584
- eputz("Usage: .user login USER PASSWORD\n");
30585
- rc = 1;
30586
- goto meta_command_exit;
30587
- }
30588
- rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
30589
- strlen30(azArg[3]));
30590
- if( rc ){
30591
- eputf("Authentication failed for user %s\n", azArg[2]);
30592
- rc = 1;
30593
- }
30594
- }else if( cli_strcmp(azArg[1],"add")==0 ){
30595
- if( nArg!=5 ){
30596
- eputz("Usage: .user add USER PASSWORD ISADMIN\n");
30597
- rc = 1;
30598
- goto meta_command_exit;
30599
- }
30600
- rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
30601
- booleanValue(azArg[4]));
30602
- if( rc ){
30603
- eputf("User-Add failed: %d\n", rc);
30604
- rc = 1;
30605
- }
30606
- }else if( cli_strcmp(azArg[1],"edit")==0 ){
30607
- if( nArg!=5 ){
30608
- eputz("Usage: .user edit USER PASSWORD ISADMIN\n");
30609
- rc = 1;
30610
- goto meta_command_exit;
30611
- }
30612
- rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
30613
- booleanValue(azArg[4]));
30614
- if( rc ){
30615
- eputf("User-Edit failed: %d\n", rc);
30616
- rc = 1;
30617
- }
30618
- }else if( cli_strcmp(azArg[1],"delete")==0 ){
30619
- if( nArg!=3 ){
30620
- eputz("Usage: .user delete USER\n");
30621
- rc = 1;
30622
- goto meta_command_exit;
30623
- }
30624
- rc = sqlite3_user_delete(p->db, azArg[2]);
30625
- if( rc ){
30626
- eputf("User-Delete failed: %d\n", rc);
30627
- rc = 1;
30628
- }
30629
- }else{
30630
- eputz("Usage: .user login|add|edit|delete ...\n");
30631
- rc = 1;
30632
- goto meta_command_exit;
30633
- }
30634
- }else
30635
-#endif /* SQLITE_USER_AUTHENTICATION */
30636
-
3063732005
if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
3063832006
char *zPtrSz = sizeof(void*)==8 ? "64-bit" : "32-bit";
30639
- oputf("SQLite %s %s\n" /*extra-version-info*/,
32007
+ sqlite3_fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
3064032008
sqlite3_libversion(), sqlite3_sourceid());
3064132009
#if SQLITE_HAVE_ZLIB
30642
- oputf("zlib version %s\n", zlibVersion());
32010
+ sqlite3_fprintf(p->out, "zlib version %s\n", zlibVersion());
3064332011
#endif
3064432012
#define CTIMEOPT_VAL_(opt) #opt
3064532013
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
3064632014
#if defined(__clang__) && defined(__clang_major__)
30647
- oputf("clang-" CTIMEOPT_VAL(__clang_major__) "."
32015
+ sqlite3_fprintf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
3064832016
CTIMEOPT_VAL(__clang_minor__) "."
3064932017
CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz);
3065032018
#elif defined(_MSC_VER)
30651
- oputf("msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
32019
+ sqlite3_fprintf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
3065232020
#elif defined(__GNUC__) && defined(__VERSION__)
30653
- oputf("gcc-" __VERSION__ " (%s)\n", zPtrSz);
32021
+ sqlite3_fprintf(p->out, "gcc-" __VERSION__ " (%s)\n", zPtrSz);
3065432022
#endif
3065532023
}else
3065632024
3065732025
if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){
3065832026
const char *zDbName = nArg==2 ? azArg[1] : "main";
3065932027
sqlite3_vfs *pVfs = 0;
3066032028
if( p->db ){
3066132029
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
3066232030
if( pVfs ){
30663
- oputf("vfs.zName = \"%s\"\n", pVfs->zName);
30664
- oputf("vfs.iVersion = %d\n", pVfs->iVersion);
30665
- oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
30666
- oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
32031
+ sqlite3_fprintf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
32032
+ sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
32033
+ sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
32034
+ sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
3066732035
}
3066832036
}
3066932037
}else
3067032038
3067132039
if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){
@@ -30673,17 +32041,17 @@
3067332041
sqlite3_vfs *pCurrent = 0;
3067432042
if( p->db ){
3067532043
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
3067632044
}
3067732045
for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
30678
- oputf("vfs.zName = \"%s\"%s\n", pVfs->zName,
32046
+ sqlite3_fprintf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
3067932047
pVfs==pCurrent ? " <--- CURRENT" : "");
30680
- oputf("vfs.iVersion = %d\n", pVfs->iVersion);
30681
- oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
30682
- oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
32048
+ sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
32049
+ sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
32050
+ sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
3068332051
if( pVfs->pNext ){
30684
- oputz("-----------------------------------\n");
32052
+ sqlite3_fputs("-----------------------------------\n", p->out);
3068532053
}
3068632054
}
3068732055
}else
3068832056
3068932057
if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
@@ -30690,11 +32058,11 @@
3069032058
const char *zDbName = nArg==2 ? azArg[1] : "main";
3069132059
char *zVfsName = 0;
3069232060
if( p->db ){
3069332061
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
3069432062
if( zVfsName ){
30695
- oputf("%s\n", zVfsName);
32063
+ sqlite3_fprintf(p->out, "%s\n", zVfsName);
3069632064
sqlite3_free(zVfsName);
3069732065
}
3069832066
}
3069932067
}else
3070032068
@@ -30714,11 +32082,11 @@
3071432082
p->colWidth[j-1] = (int)integerValue(azArg[j]);
3071532083
}
3071632084
}else
3071732085
3071832086
{
30719
- eputf("Error: unknown command or invalid arguments: "
32087
+ sqlite3_fprintf(stderr,"Error: unknown command or invalid arguments: "
3072032088
" \"%s\". Enter \".help\" for help\n", azArg[0]);
3072132089
rc = 1;
3072232090
}
3072332091
3072432092
meta_command_exit:
@@ -30755,11 +32123,10 @@
3075532123
SCAN_TRACKER_REFTYPE pst){
3075632124
char cin;
3075732125
char cWait = (char)qss; /* intentional narrowing loss */
3075832126
if( cWait==0 ){
3075932127
PlainScan:
30760
- assert( cWait==0 );
3076132128
while( (cin = *zLine++)!=0 ){
3076232129
if( IsSpace(cin) )
3076332130
continue;
3076432131
switch (cin){
3076532132
case '-':
@@ -30807,11 +32174,10 @@
3080732174
switch( cWait ){
3080832175
case '*':
3080932176
if( *zLine != '/' )
3081032177
continue;
3081132178
++zLine;
30812
- cWait = 0;
3081332179
CONTINUE_PROMPT_AWAITC(pst, 0);
3081432180
qss = QSS_SETV(qss, 0);
3081532181
goto PlainScan;
3081632182
case '`': case '\'': case '"':
3081732183
if(*zLine==cWait){
@@ -30819,11 +32185,10 @@
3081932185
++zLine;
3082032186
continue;
3082132187
}
3082232188
deliberate_fall_through;
3082332189
case ']':
30824
- cWait = 0;
3082532190
CONTINUE_PROMPT_AWAITC(pst, 0);
3082632191
qss = QSS_SETV(qss, 0);
3082732192
goto PlainScan;
3082832193
default: assert(0);
3082932194
}
@@ -30966,11 +32331,11 @@
3096632331
open_db(p, 0);
3096732332
if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
3096832333
if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
3096932334
BEGIN_TIMER;
3097032335
rc = shell_exec(p, zSql, &zErrMsg);
30971
- END_TIMER;
32336
+ END_TIMER(p->out);
3097232337
if( rc || zErrMsg ){
3097332338
char zPrefix[100];
3097432339
const char *zErrorTail;
3097532340
const char *zErrorType;
3097632341
if( zErrMsg==0 ){
@@ -30990,28 +32355,31 @@
3099032355
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
3099132356
"%s near line %d:", zErrorType, startline);
3099232357
}else{
3099332358
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
3099432359
}
30995
- eputf("%s %s\n", zPrefix, zErrorTail);
32360
+ sqlite3_fprintf(stderr,"%s %s\n", zPrefix, zErrorTail);
3099632361
sqlite3_free(zErrMsg);
3099732362
zErrMsg = 0;
3099832363
return 1;
3099932364
}else if( ShellHasFlag(p, SHFLG_CountChanges) ){
3100032365
char zLineBuf[2000];
3100132366
sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
3100232367
"changes: %lld total_changes: %lld",
3100332368
sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
31004
- oputf("%s\n", zLineBuf);
32369
+ sqlite3_fprintf(p->out, "%s\n", zLineBuf);
3100532370
}
3100632371
3100732372
if( doAutoDetectRestore(p, zSql) ) return 1;
3100832373
return 0;
3100932374
}
3101032375
3101132376
static void echo_group_input(ShellState *p, const char *zDo){
31012
- if( ShellHasFlag(p, SHFLG_Echo) ) oputf("%s\n", zDo);
32377
+ if( ShellHasFlag(p, SHFLG_Echo) ){
32378
+ sqlite3_fprintf(p->out, "%s\n", zDo);
32379
+ fflush(p->out);
32380
+ }
3101332381
}
3101432382
3101532383
#ifdef SQLITE_SHELL_FIDDLE
3101632384
/*
3101732385
** Alternate one_input_line() impl for wasm mode. This is not in the primary
@@ -31065,11 +32433,11 @@
3106532433
i64 startline = 0; /* Line number for start of current input */
3106632434
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
3106732435
3106832436
if( p->inputNesting==MAX_INPUT_NESTING ){
3106932437
/* This will be more informative in a later version. */
31070
- eputf("Input nesting limit (%d) reached at line %d."
32438
+ sqlite3_fprintf(stderr,"Input nesting limit (%d) reached at line %d."
3107132439
" Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
3107232440
return 1;
3107332441
}
3107432442
++p->inputNesting;
3107532443
p->lineno = 0;
@@ -31077,11 +32445,11 @@
3107732445
while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
3107832446
fflush(p->out);
3107932447
zLine = one_input_line(p->in, zLine, nSql>0);
3108032448
if( zLine==0 ){
3108132449
/* End of input */
31082
- if( p->in==0 && stdin_is_interactive ) oputz("\n");
32450
+ if( p->in==0 && stdin_is_interactive ) sqlite3_fputs("\n", p->out);
3108332451
break;
3108432452
}
3108532453
if( seenInterrupt ){
3108632454
if( p->in!=0 ) break;
3108732455
seenInterrupt = 0;
@@ -31297,19 +32665,19 @@
3129732665
}
3129832666
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
3129932667
shell_check_oom(zBuf);
3130032668
sqliterc = zBuf;
3130132669
}
31302
- p->in = fopen(sqliterc,"rb");
32670
+ p->in = sqlite3_fopen(sqliterc,"rb");
3130332671
if( p->in ){
3130432672
if( stdin_is_interactive ){
31305
- eputf("-- Loading resources from %s\n", sqliterc);
32673
+ sqlite3_fprintf(stderr,"-- Loading resources from %s\n", sqliterc);
3130632674
}
3130732675
if( process_input(p) && bail_on_error ) exit(1);
3130832676
fclose(p->in);
3130932677
}else if( sqliterc_override!=0 ){
31310
- eputf("cannot open: \"%s\"\n", sqliterc);
32678
+ sqlite3_fprintf(stderr,"cannot open: \"%s\"\n", sqliterc);
3131132679
if( bail_on_error ) exit(1);
3131232680
}
3131332681
p->in = inSaved;
3131432682
p->lineno = savedLineno;
3131532683
sqlite3_free(zBuf);
@@ -31374,23 +32742,21 @@
3137432742
" -table set output mode to 'table'\n"
3137532743
" -tabs set output mode to 'tabs'\n"
3137632744
" -unsafe-testing allow unsafe commands and modes for testing\n"
3137732745
" -version show SQLite version\n"
3137832746
" -vfs NAME use NAME as the default VFS\n"
31379
-#ifdef SQLITE_ENABLE_VFSTRACE
3138032747
" -vfstrace enable tracing of all VFS calls\n"
31381
-#endif
3138232748
#ifdef SQLITE_HAVE_ZLIB
3138332749
" -zip open the file as a ZIP Archive\n"
3138432750
#endif
3138532751
;
3138632752
static void usage(int showDetail){
31387
- eputf("Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
32753
+ sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
3138832754
"FILENAME is the name of an SQLite database. A new database is created\n"
3138932755
"if the file does not previously exist. Defaults to :memory:.\n", Argv0);
3139032756
if( showDetail ){
31391
- eputf("OPTIONS include:\n%s", zOptions);
32757
+ sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
3139232758
}else{
3139332759
eputz("Use the -help option for additional information\n");
3139432760
}
3139532761
exit(0);
3139632762
}
@@ -31411,10 +32777,13 @@
3141132777
*/
3141232778
static void main_init(ShellState *data) {
3141332779
memset(data, 0, sizeof(*data));
3141432780
data->normalMode = data->cMode = data->mode = MODE_List;
3141532781
data->autoExplain = 1;
32782
+#ifdef _WIN32
32783
+ data->crlfMode = 1;
32784
+#endif
3141632785
data->pAuxDb = &data->aAuxDb[0];
3141732786
memcpy(data->colSeparator,SEP_Column, 2);
3141832787
memcpy(data->rowSeparator,SEP_Row, 2);
3141932788
data->showHeader = 0;
3142032789
data->shellFlgs = SHFLG_Lookaside;
@@ -31446,29 +32815,39 @@
3144632815
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
3144732816
#endif
3144832817
}
3144932818
#else
3145032819
static void printBold(const char *zText){
31451
- sputf(stdout, "\033[1m%s\033[0m", zText);
32820
+ sqlite3_fprintf(stdout, "\033[1m%s\033[0m", zText);
3145232821
}
3145332822
#endif
3145432823
3145532824
/*
3145632825
** Get the argument to an --option. Throw an error and die if no argument
3145732826
** is available.
3145832827
*/
3145932828
static char *cmdline_option_value(int argc, char **argv, int i){
3146032829
if( i==argc ){
31461
- eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
32830
+ sqlite3_fprintf(stderr,
32831
+ "%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
3146232832
exit(1);
3146332833
}
3146432834
return argv[i];
3146532835
}
3146632836
3146732837
static void sayAbnormalExit(void){
3146832838
if( seenInterrupt ) eputz("Program interrupted.\n");
3146932839
}
32840
+
32841
+/* Routine to output from vfstrace
32842
+*/
32843
+static int vfstraceOut(const char *z, void *pArg){
32844
+ ShellState *p = (ShellState*)pArg;
32845
+ sqlite3_fputs(z, p->out);
32846
+ fflush(p->out);
32847
+ return 1;
32848
+}
3147032849
3147132850
#ifndef SQLITE_SHELL_IS_UTF8
3147232851
# if (defined(_WIN32) || defined(WIN32)) \
3147332852
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
3147432853
# define SQLITE_SHELL_IS_UTF8 (0)
@@ -31493,19 +32872,19 @@
3149332872
char *zErrMsg = 0;
3149432873
#ifdef SQLITE_SHELL_FIDDLE
3149532874
# define data shellState
3149632875
#else
3149732876
ShellState data;
31498
- StreamsAreConsole consStreams = SAC_NoConsole;
3149932877
#endif
3150032878
const char *zInitFile = 0;
3150132879
int i;
3150232880
int rc = 0;
3150332881
int warnInmemoryDb = 0;
3150432882
int readStdin = 1;
3150532883
int nCmd = 0;
3150632884
int nOptsEnd = argc;
32885
+ int bEnableVfstrace = 0;
3150732886
char **azCmd = 0;
3150832887
const char *zVfs = 0; /* Value of -vfs command-line option */
3150932888
#if !SQLITE_SHELL_IS_UTF8
3151032889
char **argvToFree = 0;
3151132890
int argcToFree = 0;
@@ -31515,25 +32894,29 @@
3151532894
#ifdef SQLITE_SHELL_FIDDLE
3151632895
stdin_is_interactive = 0;
3151732896
stdout_is_console = 1;
3151832897
data.wasm.zDefaultDbName = "/fiddle.sqlite3";
3151932898
#else
31520
- consStreams = consoleClassifySetup(stdin, stdout, stderr);
31521
- stdin_is_interactive = (consStreams & SAC_InConsole)!=0;
31522
- stdout_is_console = (consStreams & SAC_OutConsole)!=0;
31523
- atexit(consoleRestore);
32899
+ stdin_is_interactive = isatty(0);
32900
+ stdout_is_console = isatty(1);
3152432901
#endif
3152532902
atexit(sayAbnormalExit);
3152632903
#ifdef SQLITE_DEBUG
3152732904
mem_main_enter = sqlite3_memory_used();
3152832905
#endif
3152932906
#if !defined(_WIN32_WCE)
3153032907
if( getenv("SQLITE_DEBUG_BREAK") ){
3153132908
if( isatty(0) && isatty(2) ){
31532
- eputf("attach debugger to process %d and press any key to continue.\n",
32909
+ char zLine[100];
32910
+ sqlite3_fprintf(stderr,
32911
+ "attach debugger to process %d and press ENTER to continue...",
3153332912
GETPID());
31534
- fgetc(stdin);
32913
+ if( sqlite3_fgets(zLine, sizeof(zLine), stdin)!=0
32914
+ && cli_strcmp(zLine,"stop")==0
32915
+ ){
32916
+ exit(1);
32917
+ }
3153532918
}else{
3153632919
#if defined(_WIN32) || defined(WIN32)
3153732920
#if SQLITE_OS_WINRT
3153832921
__debugbreak();
3153932922
#else
@@ -31554,11 +32937,12 @@
3155432937
}
3155532938
#endif
3155632939
3155732940
#if USE_SYSTEM_SQLITE+0!=1
3155832941
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
31559
- eputf("SQLite header and source version mismatch\n%s\n%s\n",
32942
+ sqlite3_fprintf(stderr,
32943
+ "SQLite header and source version mismatch\n%s\n%s\n",
3156032944
sqlite3_sourceid(), SQLITE_SOURCE_ID);
3156132945
exit(1);
3156232946
}
3156332947
#endif
3156432948
main_init(&data);
@@ -31696,21 +33080,12 @@
3169633080
switch( n ){
3169733081
case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
3169833082
case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
3169933083
default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
3170033084
}
31701
-#ifdef SQLITE_ENABLE_VFSTRACE
3170233085
}else if( cli_strcmp(z,"-vfstrace")==0 ){
31703
- extern int vfstrace_register(
31704
- const char *zTraceName,
31705
- const char *zOldVfsName,
31706
- int (*xOut)(const char*,void*),
31707
- void *pOutArg,
31708
- int makeDefault
31709
- );
31710
- vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
31711
-#endif
33086
+ bEnableVfstrace = 1;
3171233087
#ifdef SQLITE_ENABLE_MULTIPLEX
3171333088
}else if( cli_strcmp(z,"-multiplex")==0 ){
3171433089
extern int sqlite3_multiplex_initialize(const char*,int);
3171533090
sqlite3_multiplex_initialize(0, 1);
3171633091
#endif
@@ -31762,11 +33137,11 @@
3176233137
}else if( cli_strcmp(z,"-safe")==0 ){
3176333138
/* no-op - catch this on the second pass */
3176433139
}
3176533140
}
3176633141
#ifndef SQLITE_SHELL_FIDDLE
31767
- verify_uninitialized();
33142
+ if( !bEnableVfstrace ) verify_uninitialized();
3176833143
#endif
3176933144
3177033145
3177133146
#ifdef SQLITE_SHELL_INIT_PROC
3177233147
{
@@ -31786,25 +33161,29 @@
3178633161
if( zVfs ){
3178733162
sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
3178833163
if( pVfs ){
3178933164
sqlite3_vfs_register(pVfs, 1);
3179033165
}else{
31791
- eputf("no such VFS: \"%s\"\n", zVfs);
33166
+ sqlite3_fprintf(stderr,"no such VFS: \"%s\"\n", zVfs);
3179233167
exit(1);
3179333168
}
3179433169
}
3179533170
3179633171
if( data.pAuxDb->zDbFilename==0 ){
3179733172
#ifndef SQLITE_OMIT_MEMORYDB
3179833173
data.pAuxDb->zDbFilename = ":memory:";
3179933174
warnInmemoryDb = argc==1;
3180033175
#else
31801
- eputf("%s: Error: no database filename specified\n", Argv0);
33176
+ sqlite3_fprintf(stderr,
33177
+ "%s: Error: no database filename specified\n", Argv0);
3180233178
return 1;
3180333179
#endif
3180433180
}
3180533181
data.out = stdout;
33182
+ if( bEnableVfstrace ){
33183
+ vfstrace_register("trace",0,vfstraceOut, &data, 1);
33184
+ }
3180633185
#ifndef SQLITE_SHELL_FIDDLE
3180733186
sqlite3_appendvfs_init(0,0,0);
3180833187
#endif
3180933188
3181033189
/* Go ahead and open the database file if it already exists. If the
@@ -31913,11 +33292,11 @@
3191333292
*/
3191433293
ShellSetFlag(&data, SHFLG_Backslash);
3191533294
}else if( cli_strcmp(z,"-bail")==0 ){
3191633295
/* No-op. The bail_on_error flag should already be set. */
3191733296
}else if( cli_strcmp(z,"-version")==0 ){
31918
- sputf(stdout, "%s %s (%d-bit)\n",
33297
+ sqlite3_fprintf(stdout, "%s %s (%d-bit)\n",
3191933298
sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
3192033299
return 0;
3192133300
}else if( cli_strcmp(z,"-interactive")==0 ){
3192233301
/* Need to check for interactive override here to so that it can
3192333302
** affect console setup (for Windows only) and testing thereof.
@@ -31951,14 +33330,12 @@
3195133330
}else if( cli_strcmp(z,"-sorterref")==0 ){
3195233331
i++;
3195333332
#endif
3195433333
}else if( cli_strcmp(z,"-vfs")==0 ){
3195533334
i++;
31956
-#ifdef SQLITE_ENABLE_VFSTRACE
3195733335
}else if( cli_strcmp(z,"-vfstrace")==0 ){
3195833336
i++;
31959
-#endif
3196033337
#ifdef SQLITE_ENABLE_MULTIPLEX
3196133338
}else if( cli_strcmp(z,"-multiplex")==0 ){
3196233339
i++;
3196333340
#endif
3196433341
}else if( cli_strcmp(z,"-help")==0 ){
@@ -31978,18 +33355,18 @@
3197833355
rc = shell_exec(&data, z, &zErrMsg);
3197933356
if( zErrMsg!=0 ){
3198033357
shellEmitError(zErrMsg);
3198133358
if( bail_on_error ) return rc!=0 ? rc : 1;
3198233359
}else if( rc!=0 ){
31983
- eputf("Error: unable to process SQL \"%s\"\n", z);
33360
+ sqlite3_fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
3198433361
if( bail_on_error ) return rc;
3198533362
}
3198633363
}
3198733364
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
3198833365
}else if( cli_strncmp(z, "-A", 2)==0 ){
3198933366
if( nCmd>0 ){
31990
- eputf("Error: cannot mix regular SQL or dot-commands"
33367
+ sqlite3_fprintf(stderr,"Error: cannot mix regular SQL or dot-commands"
3199133368
" with \"%s\"\n", z);
3199233369
return 1;
3199333370
}
3199433371
open_db(&data, OPEN_DB_ZIPFILE);
3199533372
if( z[2] ){
@@ -32004,11 +33381,11 @@
3200433381
}else if( cli_strcmp(z,"-safe")==0 ){
3200533382
data.bSafeMode = data.bSafeModePersist = 1;
3200633383
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
3200733384
/* Acted upon in first pass. */
3200833385
}else{
32009
- eputf("%s: Error: unknown option: %s\n", Argv0, z);
33386
+ sqlite3_fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
3201033387
eputz("Use -help for a list of options.\n");
3201133388
return 1;
3201233389
}
3201333390
data.cMode = data.mode;
3201433391
}
@@ -32031,11 +33408,12 @@
3203133408
rc = shell_exec(&data, azCmd[i], &zErrMsg);
3203233409
if( zErrMsg || rc ){
3203333410
if( zErrMsg!=0 ){
3203433411
shellEmitError(zErrMsg);
3203533412
}else{
32036
- eputf("Error: unable to process SQL: %s\n", azCmd[i]);
33413
+ sqlite3_fprintf(stderr,
33414
+ "Error: unable to process SQL: %s\n", azCmd[i]);
3203733415
}
3203833416
sqlite3_free(zErrMsg);
3203933417
if( rc==0 ) rc = 1;
3204033418
goto shell_main_exit;
3204133419
}
@@ -32046,18 +33424,14 @@
3204633424
*/
3204733425
if( stdin_is_interactive ){
3204833426
char *zHome;
3204933427
char *zHistory;
3205033428
int nHistory;
32051
-#if CIO_WIN_WC_XLATE
32052
-# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
32053
-#else
32054
-# define SHELL_CIO_CHAR_SET ""
32055
-#endif
32056
- sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
33429
+ sqlite3_fprintf(stdout,
33430
+ "SQLite version %s %.19s\n" /*extra-version-info*/
3205733431
"Enter \".help\" for usage hints.\n",
32058
- sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
33432
+ sqlite3_libversion(), sqlite3_sourceid());
3205933433
if( warnInmemoryDb ){
3206033434
sputz(stdout, "Connected to a ");
3206133435
printBold("transient in-memory database");
3206233436
sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
3206333437
" persistent database.\n");
@@ -32070,13 +33444,15 @@
3207033444
if( (zHistory = malloc(nHistory))!=0 ){
3207133445
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
3207233446
}
3207333447
}
3207433448
if( zHistory ){ shell_read_history(zHistory); }
32075
-#if HAVE_READLINE || HAVE_EDITLINE
33449
+#if (HAVE_READLINE || HAVE_EDITLINE) && !defined(SQLITE_OMIT_READLINE_COMPLETION)
3207633450
rl_attempted_completion_function = readline_completion;
32077
-#elif HAVE_LINENOISE
33451
+#elif HAVE_LINENOISE==1
33452
+ linenoiseSetCompletionCallback(linenoise_completion);
33453
+#elif HAVE_LINENOISE==2
3207833454
linenoiseSetCompletionCallback(linenoise_completion, NULL);
3207933455
#endif
3208033456
data.in = 0;
3208133457
rc = process_input(&data);
3208233458
if( zHistory ){
@@ -32122,13 +33498,16 @@
3212233498
free(data.colWidth);
3212333499
free(data.zNonce);
3212433500
/* Clear the global data structure so that valgrind will detect memory
3212533501
** leaks */
3212633502
memset(&data, 0, sizeof(data));
33503
+ if( bEnableVfstrace ){
33504
+ vfstrace_unregister("trace");
33505
+ }
3212733506
#ifdef SQLITE_DEBUG
3212833507
if( sqlite3_memory_used()>mem_main_enter ){
32129
- eputf("Memory leaked: %u bytes\n",
33508
+ sqlite3_fprintf(stderr,"Memory leaked: %u bytes\n",
3213033509
(unsigned int)(sqlite3_memory_used()-mem_main_enter));
3213133510
}
3213233511
#endif
3213333512
#else /* SQLITE_SHELL_FIDDLE... */
3213433513
shell_main_exit:
@@ -32164,11 +33543,11 @@
3216433543
return pVfs;
3216533544
}
3216633545
3216733546
/* Only for emcc experimentation purposes. */
3216833547
sqlite3 * fiddle_db_arg(sqlite3 *arg){
32169
- oputf("fiddle_db_arg(%p)\n", (const void*)arg);
33548
+ sqlite3_fprintf(stdout, "fiddle_db_arg(%p)\n", (const void*)arg);
3217033549
return arg;
3217133550
}
3217233551
3217333552
/*
3217433553
** Intended to be called via a SharedWorker() while a separate
@@ -32201,11 +33580,11 @@
3220133580
while( sqlite3_txn_state(globalDb,0)>0 ){
3220233581
/*
3220333582
** Resolve problem reported in
3220433583
** https://sqlite.org/forum/forumpost/0b41a25d65
3220533584
*/
32206
- oputz("Rolling back in-progress transaction.\n");
33585
+ sqlite3_fputs("Rolling back in-progress transaction.\n", stdout);
3220733586
sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0);
3220833587
}
3220933588
rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
3221033589
if( 0==rc ) sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
3221133590
sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
3221233591
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -120,13 +120,10 @@
120 #include <math.h>
121 #include "sqlite3.h"
122 typedef sqlite3_int64 i64;
123 typedef sqlite3_uint64 u64;
124 typedef unsigned char u8;
125 #if SQLITE_USER_AUTHENTICATION
126 # include "sqlite3userauth.h"
127 #endif
128 #include <ctype.h>
129 #include <stdarg.h>
130
131 #if !defined(_WIN32) && !defined(WIN32)
132 # include <signal.h>
@@ -208,12 +205,10 @@
208 # define unlink _unlink
209 # endif
210 # ifndef strdup
211 # define strdup _strdup
212 # endif
213 # undef popen
214 # define popen _popen
215 # undef pclose
216 # define pclose _pclose
217 # endif
218 #else
219 /* Make sure isatty() has a prototype. */
@@ -253,10 +248,370 @@
253 /* string conversion routines only needed on Win32 */
254 extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
255 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
256 #endif
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258 /* Use console I/O package as a direct INCLUDE. */
259 #define SQLITE_INTERNAL_LINKAGE static
260
261 #ifdef SQLITE_SHELL_FIDDLE
262 /* Deselect most features from the console I/O package for Fiddle. */
@@ -264,1118 +619,13 @@
264 # define SQLITE_CIO_NO_CLASSIFY
265 # define SQLITE_CIO_NO_TRANSLATE
266 # define SQLITE_CIO_NO_SETMODE
267 # define SQLITE_CIO_NO_FLUSH
268 #endif
269 /************************* Begin ../ext/consio/console_io.h ******************/
270 /*
271 ** 2023 November 1
272 **
273 ** The author disclaims copyright to this source code. In place of
274 ** a legal notice, here is a blessing:
275 **
276 ** May you do good and not evil.
277 ** May you find forgiveness for yourself and forgive others.
278 ** May you share freely, never taking more than you give.
279 **
280 ********************************************************************************
281 ** This file exposes various interfaces used for console and other I/O
282 ** by the SQLite project command-line tools. These interfaces are used
283 ** at either source conglomeration time, compilation time, or run time.
284 ** This source provides for either inclusion into conglomerated,
285 ** "single-source" forms or separate compilation then linking.
286 **
287 ** Platform dependencies are "hidden" here by various stratagems so
288 ** that, provided certain conditions are met, the programs using this
289 ** source or object code compiled from it need no explicit conditional
290 ** compilation in their source for their console and stream I/O.
291 **
292 ** The symbols and functionality exposed here are not a public API.
293 ** This code may change in tandem with other project code as needed.
294 **
295 ** When this .h file and its companion .c are directly incorporated into
296 ** a source conglomeration (such as shell.c), the preprocessor symbol
297 ** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
298 ** translation for Windows is effected for the build.
299 */
300 #define HAVE_CONSOLE_IO_H 1
301 #ifndef SQLITE_INTERNAL_LINKAGE
302 # define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
303 # include <stdio.h>
304 #else
305 # define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
306 #endif
307
308 #ifndef SQLITE3_H
309 /* # include "sqlite3.h" */
310 #endif
311
312 #ifndef SQLITE_CIO_NO_CLASSIFY
313
314 /* Define enum for use with following function. */
315 typedef enum StreamsAreConsole {
316 SAC_NoConsole = 0,
317 SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
318 SAC_AnyConsole = 0x7
319 } StreamsAreConsole;
320
321 /*
322 ** Classify the three standard I/O streams according to whether
323 ** they are connected to a console attached to the process.
324 **
325 ** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
326 ** or SAC_NoConsole if none of the streams reaches a console.
327 **
328 ** This function should be called before any I/O is done with
329 ** the given streams. As a side-effect, the given inputs are
330 ** recorded so that later I/O operations on them may be done
331 ** differently than the C library FILE* I/O would be done,
332 ** iff the stream is used for the I/O functions that follow,
333 ** and to support the ones that use an implicit stream.
334 **
335 ** On some platforms, stream or console mode alteration (aka
336 ** "Setup") may be made which is undone by consoleRestore().
337 */
338 SQLITE_INTERNAL_LINKAGE StreamsAreConsole
339 consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
340 /* A usual call for convenience: */
341 #define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
342
343 /*
344 ** After an initial call to consoleClassifySetup(...), renew
345 ** the same setup it effected. (A call not after is an error.)
346 ** This will restore state altered by consoleRestore();
347 **
348 ** Applications which run an inferior (child) process which
349 ** inherits the same I/O streams may call this function after
350 ** such a process exits to guard against console mode changes.
351 */
352 SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
353
354 /*
355 ** Undo any side-effects left by consoleClassifySetup(...).
356 **
357 ** This should be called after consoleClassifySetup() and
358 ** before the process terminates normally. It is suitable
359 ** for use with the atexit() C library procedure. After
360 ** this call, no console I/O should be done until one of
361 ** console{Classify or Renew}Setup(...) is called again.
362 **
363 ** Applications which run an inferior (child) process that
364 ** inherits the same I/O streams might call this procedure
365 ** before so that said process will have a console setup
366 ** however users have configured it or come to expect.
367 */
368 SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
369
370 #else /* defined(SQLITE_CIO_NO_CLASSIFY) */
371 # define consoleClassifySetup(i,o,e)
372 # define consoleRenewSetup()
373 # define consoleRestore()
374 #endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
375
376 #ifndef SQLITE_CIO_NO_REDIRECT
377 /*
378 ** Set stream to be used for the functions below which write
379 ** to "the designated X stream", where X is Output or Error.
380 ** Returns the previous value.
381 **
382 ** Alternatively, pass the special value, invalidFileStream,
383 ** to get the designated stream value without setting it.
384 **
385 ** Before the designated streams are set, they default to
386 ** those passed to consoleClassifySetup(...), and before
387 ** that is called they default to stdout and stderr.
388 **
389 ** It is error to close a stream so designated, then, without
390 ** designating another, use the corresponding {o,e}Emit(...).
391 */
392 SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
393 SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
394 # ifdef CONSIO_SET_ERROR_STREAM
395 SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
396 # endif
397 #else
398 # define setOutputStream(pf)
399 # define setErrorStream(pf)
400 #endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
401
402 #ifndef SQLITE_CIO_NO_TRANSLATE
403 /*
404 ** Emit output like fprintf(). If the output is going to the
405 ** console and translation from UTF-8 is necessary, perform
406 ** the needed translation. Otherwise, write formatted output
407 ** to the provided stream almost as-is, possibly with newline
408 ** translation as specified by set{Binary,Text}Mode().
409 */
410 SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
411 /* Like fPrintfUtf8 except stream is always the designated output. */
412 SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
413 /* Like fPrintfUtf8 except stream is always the designated error. */
414 SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
415
416 /*
417 ** Emit output like fputs(). If the output is going to the
418 ** console and translation from UTF-8 is necessary, perform
419 ** the needed translation. Otherwise, write given text to the
420 ** provided stream almost as-is, possibly with newline
421 ** translation as specified by set{Binary,Text}Mode().
422 */
423 SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
424 /* Like fPutsUtf8 except stream is always the designated output. */
425 SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
426 /* Like fPutsUtf8 except stream is always the designated error. */
427 SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
428
429 /*
430 ** Emit output like fPutsUtf8(), except that the length of the
431 ** accepted char or character sequence is limited by nAccept.
432 **
433 ** Returns the number of accepted char values.
434 */
435 #ifdef CONSIO_SPUTB
436 SQLITE_INTERNAL_LINKAGE int
437 fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
438 /* Like fPutbUtf8 except stream is always the designated output. */
439 #endif
440 SQLITE_INTERNAL_LINKAGE int
441 oPutbUtf8(const char *cBuf, int nAccept);
442 /* Like fPutbUtf8 except stream is always the designated error. */
443 #ifdef CONSIO_EPUTB
444 SQLITE_INTERNAL_LINKAGE int
445 ePutbUtf8(const char *cBuf, int nAccept);
446 #endif
447
448 /*
449 ** Flush the given output stream. Return non-zero for success, else 0.
450 */
451 #if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
452 SQLITE_INTERNAL_LINKAGE int
453 fFlushBuffer(FILE *pfOut);
454 #endif
455
456 /*
457 ** Collect input like fgets(...) with special provisions for input
458 ** from the console on such platforms as require same. Newline
459 ** translation may be done as set by set{Binary,Text}Mode().
460 ** As a convenience, pfIn==NULL is treated as stdin.
461 */
462 SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
463 /* Like fGetsUtf8 except stream is always the designated input. */
464 /* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
465
466 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
467
468 #ifndef SQLITE_CIO_NO_SETMODE
469 /*
470 ** Set given stream for binary mode, where newline translation is
471 ** not done, or for text mode where, for some platforms, newlines
472 ** are translated to the platform's conventional char sequence.
473 ** If bFlush true, flush the stream.
474 **
475 ** An additional side-effect is that if the stream is one passed
476 ** to consoleClassifySetup() as an output, it is flushed first.
477 **
478 ** Note that binary/text mode has no effect on console I/O
479 ** translation. On all platforms, newline to the console starts
480 ** a new line and CR,LF chars from the console become a newline.
481 */
482 SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
483 SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
484 #endif
485
486 #ifdef SQLITE_CIO_PROMPTED_IN
487 typedef struct Prompts {
488 int numPrompts;
489 const char **azPrompts;
490 } Prompts;
491
492 /*
493 ** Macros for use of a line editor.
494 **
495 ** The following macros define operations involving use of a
496 ** line-editing library or simple console interaction.
497 ** A "T" argument is a text (char *) buffer or filename.
498 ** A "N" argument is an integer.
499 **
500 ** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
501 ** SHELL_READ_HISTORY(T) // Read history from file named by T.
502 ** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
503 ** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
504 **
505 ** A console program which does interactive console input is
506 ** expected to call:
507 ** SHELL_READ_HISTORY(T) before collecting such input;
508 ** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
509 ** SHELL_STIFLE_HISTORY(N) after console input ceases; then
510 ** SHELL_WRITE_HISTORY(T) before the program exits.
511 */
512
513 /*
514 ** Retrieve a single line of input text from an input stream.
515 **
516 ** If pfIn is the input stream passed to consoleClassifySetup(),
517 ** and azPrompt is not NULL, then a prompt is issued before the
518 ** line is collected, as selected by the isContinuation flag.
519 ** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
520 **
521 ** If zBufPrior is not NULL then it is a buffer from a prior
522 ** call to this routine that can be reused, or will be freed.
523 **
524 ** The result is stored in space obtained from malloc() and
525 ** must either be freed by the caller or else passed back to
526 ** this function as zBufPrior for reuse.
527 **
528 ** This function may call upon services of a line-editing
529 ** library to interactively collect line edited input.
530 */
531 SQLITE_INTERNAL_LINKAGE char *
532 shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
533 short isContinuation, Prompts azPrompt);
534 #endif /* defined(SQLITE_CIO_PROMPTED_IN) */
535 /*
536 ** TBD: Define an interface for application(s) to generate
537 ** completion candidates for use by the line-editor.
538 **
539 ** This may be premature; the CLI is the only application
540 ** that does this. Yet, getting line-editing melded into
541 ** console I/O is desirable because a line-editing library
542 ** may have to establish console operating mode, possibly
543 ** in a way that interferes with the above functionality.
544 */
545
546 #if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
547 /* Skip over as much z[] input char sequence as is valid UTF-8,
548 ** limited per nAccept char's or whole characters and containing
549 ** no char cn such that ((1<<cn) & ccm)!=0. On return, the
550 ** sequence z:return (inclusive:exclusive) is validated UTF-8.
551 ** Limit: nAccept>=0 => char count, nAccept<0 => character
552 */
553 SQLITE_INTERNAL_LINKAGE const char*
554 zSkipValidUtf8(const char *z, int nAccept, long ccm);
555
556 #endif
557
558 /************************* End ../ext/consio/console_io.h ********************/
559 /************************* Begin ../ext/consio/console_io.c ******************/
560 /*
561 ** 2023 November 4
562 **
563 ** The author disclaims copyright to this source code. In place of
564 ** a legal notice, here is a blessing:
565 **
566 ** May you do good and not evil.
567 ** May you find forgiveness for yourself and forgive others.
568 ** May you share freely, never taking more than you give.
569 **
570 ********************************************************************************
571 ** This file implements various interfaces used for console and stream I/O
572 ** by the SQLite project command-line tools, as explained in console_io.h .
573 ** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
574 */
575
576 #ifndef SQLITE_CDECL
577 # define SQLITE_CDECL
578 #endif
579
580 #ifndef SHELL_NO_SYSINC
581 # include <stdarg.h>
582 # include <string.h>
583 # include <stdlib.h>
584 # include <limits.h>
585 # include <assert.h>
586 /* # include "sqlite3.h" */
587 #endif
588 #ifndef HAVE_CONSOLE_IO_H
589 # include "console_io.h"
590 #endif
591 #if defined(_MSC_VER)
592 # pragma warning(disable : 4204)
593 #endif
594
595 #ifndef SQLITE_CIO_NO_TRANSLATE
596 # if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
597 # ifndef SHELL_NO_SYSINC
598 # include <io.h>
599 # include <fcntl.h>
600 # undef WIN32_LEAN_AND_MEAN
601 # define WIN32_LEAN_AND_MEAN
602 # include <windows.h>
603 # endif
604 # define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
605 # else
606 # ifndef SHELL_NO_SYSINC
607 # include <unistd.h>
608 # endif
609 # define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
610 # endif
611 #else
612 # define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
613 #endif
614
615 #if CIO_WIN_WC_XLATE
616 static HANDLE handleOfFile(FILE *pf){
617 int fileDesc = _fileno(pf);
618 union { intptr_t osfh; HANDLE fh; } fid = {
619 (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
620 };
621 return fid.fh;
622 }
623 #endif
624
625 #ifndef SQLITE_CIO_NO_TRANSLATE
626 typedef struct PerStreamTags {
627 # if CIO_WIN_WC_XLATE
628 HANDLE hx;
629 DWORD consMode;
630 char acIncomplete[4];
631 # else
632 short reachesConsole;
633 # endif
634 FILE *pf;
635 } PerStreamTags;
636
637 /* Define NULL-like value for things which can validly be 0. */
638 # define SHELL_INVALID_FILE_PTR ((FILE *)~0)
639 # if CIO_WIN_WC_XLATE
640 # define SHELL_INVALID_CONS_MODE 0xFFFF0000
641 # endif
642
643 # if CIO_WIN_WC_XLATE
644 # define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
645 {0,0,0,0}, SHELL_INVALID_FILE_PTR }
646 # else
647 # define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
648 # endif
649
650 /* Quickly say whether a known output is going to the console. */
651 # if CIO_WIN_WC_XLATE
652 static short pstReachesConsole(PerStreamTags *ppst){
653 return (ppst->hx != INVALID_HANDLE_VALUE);
654 }
655 # else
656 # define pstReachesConsole(ppst) 0
657 # endif
658
659 # if CIO_WIN_WC_XLATE
660 static void restoreConsoleArb(PerStreamTags *ppst){
661 if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
662 }
663 # else
664 # define restoreConsoleArb(ppst)
665 # endif
666
667 /* Say whether FILE* appears to be a console, collect associated info. */
668 static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
669 # if CIO_WIN_WC_XLATE
670 short rv = 0;
671 DWORD dwCM = SHELL_INVALID_CONS_MODE;
672 HANDLE fh = handleOfFile(pf);
673 ppst->pf = pf;
674 if( INVALID_HANDLE_VALUE != fh ){
675 rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
676 }
677 ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
678 ppst->consMode = dwCM;
679 return rv;
680 # else
681 ppst->pf = pf;
682 ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
683 return ppst->reachesConsole;
684 # endif
685 }
686
687 # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
688 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4)
689 # endif
690
691 # if CIO_WIN_WC_XLATE
692 /* Define console modes for use with the Windows Console API. */
693 # define SHELL_CONI_MODE \
694 (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
695 | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
696 # define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
697 | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
698 # endif
699
700 typedef struct ConsoleInfo {
701 PerStreamTags pstSetup[3];
702 PerStreamTags pstDesignated[3];
703 StreamsAreConsole sacSetup;
704 } ConsoleInfo;
705
706 static short isValidStreamInfo(PerStreamTags *ppst){
707 return (ppst->pf != SHELL_INVALID_FILE_PTR);
708 }
709
710 static ConsoleInfo consoleInfo = {
711 { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
712 { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
713 SAC_NoConsole /* sacSetup */
714 };
715
716 SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
717
718 # if CIO_WIN_WC_XLATE
719 static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
720 if( pstReachesConsole(ppst) ){
721 DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
722 SetConsoleMode(ppst->hx, cm);
723 }
724 }
725 # else
726 # define maybeSetupAsConsole(ppst,odir)
727 # endif
728
729 SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
730 # if CIO_WIN_WC_XLATE
731 int ix = 0;
732 while( ix < 6 ){
733 PerStreamTags *ppst = (ix<3)?
734 &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
735 maybeSetupAsConsole(ppst, (ix % 3)>0);
736 ++ix;
737 }
738 # endif
739 }
740
741 SQLITE_INTERNAL_LINKAGE StreamsAreConsole
742 consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
743 StreamsAreConsole rv = SAC_NoConsole;
744 FILE* apf[3] = { pfIn, pfOut, pfErr };
745 int ix;
746 for( ix = 2; ix >= 0; --ix ){
747 PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
748 if( streamOfConsole(apf[ix], ppst) ){
749 rv |= (SAC_InConsole<<ix);
750 }
751 consoleInfo.pstDesignated[ix] = *ppst;
752 if( ix > 0 ) fflush(apf[ix]);
753 }
754 consoleInfo.sacSetup = rv;
755 consoleRenewSetup();
756 return rv;
757 }
758
759 SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
760 # if CIO_WIN_WC_XLATE
761 static ConsoleInfo *pci = &consoleInfo;
762 if( pci->sacSetup ){
763 int ix;
764 for( ix=0; ix<3; ++ix ){
765 if( pci->sacSetup & (SAC_InConsole<<ix) ){
766 PerStreamTags *ppst = &pci->pstSetup[ix];
767 SetConsoleMode(ppst->hx, ppst->consMode);
768 }
769 }
770 }
771 # endif
772 }
773 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
774
775 #ifdef SQLITE_CIO_INPUT_REDIR
776 /* Say whether given FILE* is among those known, via either
777 ** consoleClassifySetup() or set{Output,Error}Stream, as
778 ** readable, and return an associated PerStreamTags pointer
779 ** if so. Otherwise, return 0.
780 */
781 static PerStreamTags * isKnownReadable(FILE *pf){
782 static PerStreamTags *apst[] = {
783 &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
784 };
785 int ix = 0;
786 do {
787 if( apst[ix]->pf == pf ) break;
788 } while( apst[++ix] != 0 );
789 return apst[ix];
790 }
791 #endif
792
793 #ifndef SQLITE_CIO_NO_TRANSLATE
794 /* Say whether given FILE* is among those known, via either
795 ** consoleClassifySetup() or set{Output,Error}Stream, as
796 ** writable, and return an associated PerStreamTags pointer
797 ** if so. Otherwise, return 0.
798 */
799 static PerStreamTags * isKnownWritable(FILE *pf){
800 static PerStreamTags *apst[] = {
801 &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
802 &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
803 };
804 int ix = 0;
805 do {
806 if( apst[ix]->pf == pf ) break;
807 } while( apst[++ix] != 0 );
808 return apst[ix];
809 }
810
811 static FILE *designateEmitStream(FILE *pf, unsigned chix){
812 FILE *rv = consoleInfo.pstDesignated[chix].pf;
813 if( pf == invalidFileStream ) return rv;
814 else{
815 /* Setting a possibly new output stream. */
816 PerStreamTags *ppst = isKnownWritable(pf);
817 if( ppst != 0 ){
818 PerStreamTags pst = *ppst;
819 consoleInfo.pstDesignated[chix] = pst;
820 }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
821 }
822 return rv;
823 }
824
825 SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
826 return designateEmitStream(pf, 1);
827 }
828 # ifdef CONSIO_SET_ERROR_STREAM
829 SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
830 return designateEmitStream(pf, 2);
831 }
832 # endif
833 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
834
835 #ifndef SQLITE_CIO_NO_SETMODE
836 # if CIO_WIN_WC_XLATE
837 static void setModeFlushQ(FILE *pf, short bFlush, int mode){
838 if( bFlush ) fflush(pf);
839 _setmode(_fileno(pf), mode);
840 }
841 # else
842 # define setModeFlushQ(f, b, m) if(b) fflush(f)
843 # endif
844
845 SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
846 setModeFlushQ(pf, bFlush, _O_BINARY);
847 }
848 SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
849 setModeFlushQ(pf, bFlush, _O_TEXT);
850 }
851 # undef setModeFlushQ
852
853 #else /* defined(SQLITE_CIO_NO_SETMODE) */
854 # define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
855 # define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
856 #endif /* defined(SQLITE_CIO_NO_SETMODE) */
857
858 #ifndef SQLITE_CIO_NO_TRANSLATE
859 # if CIO_WIN_WC_XLATE
860 /* Write buffer cBuf as output to stream known to reach console,
861 ** limited to ncTake char's. Return ncTake on success, else 0. */
862 static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
863 int rv = 0;
864 if( z!=NULL ){
865 int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
866 if( nwc > 0 ){
867 WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
868 if( zw!=NULL ){
869 nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
870 if( nwc > 0 ){
871 /* Translation from UTF-8 to UTF-16, then WCHARs out. */
872 if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
873 rv = ncTake;
874 }
875 }
876 sqlite3_free(zw);
877 }
878 }
879 }
880 return rv;
881 }
882
883 /* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
884 static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
885 char *z = sqlite3_vmprintf(zFormat, ap);
886 if( z ){
887 int rv = conZstrEmit(ppst, z, (int)strlen(z));
888 sqlite3_free(z);
889 return rv;
890 }else return 0;
891 }
892 # endif /* CIO_WIN_WC_XLATE */
893
894 # ifdef CONSIO_GET_EMIT_STREAM
895 static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
896 PerStreamTags *ppst){
897 PerStreamTags *rv = isKnownWritable(pf);
898 short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
899 if( rv != 0 && isValid ) return rv;
900 streamOfConsole(pf, ppst);
901 return ppst;
902 }
903 # endif
904
905 /* Get stream info, either for designated output or error stream when
906 ** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
907 ** In either case, ppst references a caller-owned PerStreamTags
908 ** struct which may be filled in if none of the known writable
909 ** streams is being held by consoleInfo. The ppf parameter is a
910 ** byref output when chix!=0 and a byref input when chix==0.
911 */
912 static PerStreamTags *
913 getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
914 /* in/out */ FILE **ppf){
915 PerStreamTags *ppstTry;
916 FILE *pfEmit;
917 if( chix > 0 ){
918 ppstTry = &consoleInfo.pstDesignated[chix];
919 if( !isValidStreamInfo(ppstTry) ){
920 ppstTry = &consoleInfo.pstSetup[chix];
921 pfEmit = ppst->pf;
922 }else pfEmit = ppstTry->pf;
923 if( !isValidStreamInfo(ppstTry) ){
924 pfEmit = (chix > 1)? stderr : stdout;
925 ppstTry = ppst;
926 streamOfConsole(pfEmit, ppstTry);
927 }
928 *ppf = pfEmit;
929 }else{
930 ppstTry = isKnownWritable(*ppf);
931 if( ppstTry != 0 ) return ppstTry;
932 streamOfConsole(*ppf, ppst);
933 return ppst;
934 }
935 return ppstTry;
936 }
937
938 SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
939 va_list ap;
940 int rv;
941 FILE *pfOut;
942 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
943 # if CIO_WIN_WC_XLATE
944 PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
945 # else
946 getEmitStreamInfo(1, &pst, &pfOut);
947 # endif
948 assert(zFormat!=0);
949 va_start(ap, zFormat);
950 # if CIO_WIN_WC_XLATE
951 if( pstReachesConsole(ppst) ){
952 rv = conioVmPrintf(ppst, zFormat, ap);
953 }else{
954 # endif
955 rv = vfprintf(pfOut, zFormat, ap);
956 # if CIO_WIN_WC_XLATE
957 }
958 # endif
959 va_end(ap);
960 return rv;
961 }
962
963 SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
964 va_list ap;
965 int rv;
966 FILE *pfErr;
967 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
968 # if CIO_WIN_WC_XLATE
969 PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
970 # else
971 getEmitStreamInfo(2, &pst, &pfErr);
972 # endif
973 assert(zFormat!=0);
974 va_start(ap, zFormat);
975 # if CIO_WIN_WC_XLATE
976 if( pstReachesConsole(ppst) ){
977 rv = conioVmPrintf(ppst, zFormat, ap);
978 }else{
979 # endif
980 rv = vfprintf(pfErr, zFormat, ap);
981 # if CIO_WIN_WC_XLATE
982 }
983 # endif
984 va_end(ap);
985 return rv;
986 }
987
988 SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
989 va_list ap;
990 int rv;
991 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
992 # if CIO_WIN_WC_XLATE
993 PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
994 # else
995 getEmitStreamInfo(0, &pst, &pfO);
996 # endif
997 assert(zFormat!=0);
998 va_start(ap, zFormat);
999 # if CIO_WIN_WC_XLATE
1000 if( pstReachesConsole(ppst) ){
1001 maybeSetupAsConsole(ppst, 1);
1002 rv = conioVmPrintf(ppst, zFormat, ap);
1003 if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
1004 }else{
1005 # endif
1006 rv = vfprintf(pfO, zFormat, ap);
1007 # if CIO_WIN_WC_XLATE
1008 }
1009 # endif
1010 va_end(ap);
1011 return rv;
1012 }
1013
1014 SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
1015 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1016 # if CIO_WIN_WC_XLATE
1017 PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
1018 # else
1019 getEmitStreamInfo(0, &pst, &pfO);
1020 # endif
1021 assert(z!=0);
1022 # if CIO_WIN_WC_XLATE
1023 if( pstReachesConsole(ppst) ){
1024 int rv;
1025 maybeSetupAsConsole(ppst, 1);
1026 rv = conZstrEmit(ppst, z, (int)strlen(z));
1027 if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
1028 return rv;
1029 }else {
1030 # endif
1031 return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
1032 # if CIO_WIN_WC_XLATE
1033 }
1034 # endif
1035 }
1036
1037 SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
1038 FILE *pfErr;
1039 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1040 # if CIO_WIN_WC_XLATE
1041 PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
1042 # else
1043 getEmitStreamInfo(2, &pst, &pfErr);
1044 # endif
1045 assert(z!=0);
1046 # if CIO_WIN_WC_XLATE
1047 if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
1048 else {
1049 # endif
1050 return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
1051 # if CIO_WIN_WC_XLATE
1052 }
1053 # endif
1054 }
1055
1056 SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
1057 FILE *pfOut;
1058 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1059 # if CIO_WIN_WC_XLATE
1060 PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
1061 # else
1062 getEmitStreamInfo(1, &pst, &pfOut);
1063 # endif
1064 assert(z!=0);
1065 # if CIO_WIN_WC_XLATE
1066 if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
1067 else {
1068 # endif
1069 return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
1070 # if CIO_WIN_WC_XLATE
1071 }
1072 # endif
1073 }
1074
1075 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
1076
1077 #if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
1078 /* Skip over as much z[] input char sequence as is valid UTF-8,
1079 ** limited per nAccept char's or whole characters and containing
1080 ** no char cn such that ((1<<cn) & ccm)!=0. On return, the
1081 ** sequence z:return (inclusive:exclusive) is validated UTF-8.
1082 ** Limit: nAccept>=0 => char count, nAccept<0 => character
1083 */
1084 SQLITE_INTERNAL_LINKAGE const char*
1085 zSkipValidUtf8(const char *z, int nAccept, long ccm){
1086 int ng = (nAccept<0)? -nAccept : 0;
1087 const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
1088 assert(z!=0);
1089 while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
1090 char c = *z;
1091 if( (c & 0x80) == 0 ){
1092 if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
1093 ++z; /* ASCII */
1094 }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
1095 else{
1096 const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
1097 do{
1098 if( pcLimit && zt >= pcLimit ) return z;
1099 else{
1100 char ct = *zt++;
1101 if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
1102 /* Trailing bytes are too few, too many, or invalid. */
1103 return z;
1104 }
1105 }
1106 } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
1107 z = zt;
1108 }
1109 }
1110 return z;
1111 }
1112 #endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
1113
1114 #ifndef SQLITE_CIO_NO_TRANSLATE
1115 # ifdef CONSIO_SPUTB
1116 SQLITE_INTERNAL_LINKAGE int
1117 fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
1118 assert(pfO!=0);
1119 # if CIO_WIN_WC_XLATE
1120 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1121 PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
1122 if( pstReachesConsole(ppst) ){
1123 int rv;
1124 maybeSetupAsConsole(ppst, 1);
1125 rv = conZstrEmit(ppst, cBuf, nAccept);
1126 if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
1127 return rv;
1128 }else {
1129 # endif
1130 return (int)fwrite(cBuf, 1, nAccept, pfO);
1131 # if CIO_WIN_WC_XLATE
1132 }
1133 # endif
1134 }
1135 # endif
1136
1137 SQLITE_INTERNAL_LINKAGE int
1138 oPutbUtf8(const char *cBuf, int nAccept){
1139 FILE *pfOut;
1140 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1141 # if CIO_WIN_WC_XLATE
1142 PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
1143 # else
1144 getEmitStreamInfo(1, &pst, &pfOut);
1145 # endif
1146 # if CIO_WIN_WC_XLATE
1147 if( pstReachesConsole(ppst) ){
1148 return conZstrEmit(ppst, cBuf, nAccept);
1149 }else {
1150 # endif
1151 return (int)fwrite(cBuf, 1, nAccept, pfOut);
1152 # if CIO_WIN_WC_XLATE
1153 }
1154 # endif
1155 }
1156
1157 /*
1158 ** Flush the given output stream. Return non-zero for success, else 0.
1159 */
1160 #if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
1161 SQLITE_INTERNAL_LINKAGE int
1162 fFlushBuffer(FILE *pfOut){
1163 # if CIO_WIN_WC_XLATE && !defined(SHELL_OMIT_FIO_DUPE)
1164 return FlushFileBuffers(handleOfFile(pfOut))? 1 : 0;
1165 # else
1166 return fflush(pfOut);
1167 # endif
1168 }
1169 #endif
1170
1171 #if CIO_WIN_WC_XLATE \
1172 && !defined(SHELL_OMIT_FIO_DUPE) \
1173 && defined(SQLITE_USE_ONLY_WIN32)
1174 static struct FileAltIds {
1175 int fd;
1176 HANDLE fh;
1177 } altIdsOfFile(FILE *pf){
1178 struct FileAltIds rv = { _fileno(pf) };
1179 union { intptr_t osfh; HANDLE fh; } fid = {
1180 (rv.fd>=0)? _get_osfhandle(rv.fd) : (intptr_t)INVALID_HANDLE_VALUE
1181 };
1182 rv.fh = fid.fh;
1183 return rv;
1184 }
1185
1186 SQLITE_INTERNAL_LINKAGE size_t
1187 cfWrite(const void *buf, size_t osz, size_t ocnt, FILE *pf){
1188 size_t rv = 0;
1189 struct FileAltIds fai = altIdsOfFile(pf);
1190 int fmode = _setmode(fai.fd, _O_BINARY);
1191 _setmode(fai.fd, fmode);
1192 while( rv < ocnt ){
1193 size_t nbo = osz;
1194 while( nbo > 0 ){
1195 DWORD dwno = (nbo>(1L<<24))? 1L<<24 : (DWORD)nbo;
1196 BOOL wrc = TRUE;
1197 BOOL genCR = (fmode & _O_TEXT)!=0;
1198 if( genCR ){
1199 const char *pnl = (const char*)memchr(buf, '\n', nbo);
1200 if( pnl ) nbo = pnl - (const char*)buf;
1201 else genCR = 0;
1202 }
1203 if( dwno>0 ) wrc = WriteFile(fai.fh, buf, dwno, 0,0);
1204 if( genCR && wrc ){
1205 wrc = WriteFile(fai.fh, "\r\n", 2, 0,0);
1206 ++dwno; /* Skip over the LF */
1207 }
1208 if( !wrc ) return rv;
1209 buf = (const char*)buf + dwno;
1210 nbo += dwno;
1211 }
1212 ++rv;
1213 }
1214 return rv;
1215 }
1216
1217 SQLITE_INTERNAL_LINKAGE char *
1218 cfGets(char *cBuf, int n, FILE *pf){
1219 int nci = 0;
1220 struct FileAltIds fai = altIdsOfFile(pf);
1221 int fmode = _setmode(fai.fd, _O_BINARY);
1222 BOOL eatCR = (fmode & _O_TEXT)!=0;
1223 _setmode(fai.fd, fmode);
1224 while( nci < n-1 ){
1225 DWORD nr;
1226 if( !ReadFile(fai.fh, cBuf+nci, 1, &nr, 0) || nr==0 ) break;
1227 if( nr>0 && (!eatCR || cBuf[nci]!='\r') ) nci += nr;
1228 }
1229 if( nci < n ) cBuf[nci] = 0;
1230 return (nci>0)? cBuf : 0;
1231 }
1232 # else
1233 # define cfWrite(b,os,no,f) fwrite(b,os,no,f)
1234 # define cfGets(b,n,f) fgets(b,n,f)
1235 # endif
1236
1237 # ifdef CONSIO_EPUTB
1238 SQLITE_INTERNAL_LINKAGE int
1239 ePutbUtf8(const char *cBuf, int nAccept){
1240 FILE *pfErr;
1241 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
1242 PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
1243 # if CIO_WIN_WC_XLATE
1244 if( pstReachesConsole(ppst) ){
1245 return conZstrEmit(ppst, cBuf, nAccept);
1246 }else {
1247 # endif
1248 return (int)cfWrite(cBuf, 1, nAccept, pfErr);
1249 # if CIO_WIN_WC_XLATE
1250 }
1251 # endif
1252 }
1253 # endif /* defined(CONSIO_EPUTB) */
1254
1255 SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
1256 if( pfIn==0 ) pfIn = stdin;
1257 # if CIO_WIN_WC_XLATE
1258 if( pfIn == consoleInfo.pstSetup[0].pf
1259 && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
1260 # if CIO_WIN_WC_XLATE==1
1261 # define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
1262 WCHAR wcBuf[SHELL_GULP+1];
1263 int lend = 0, noc = 0;
1264 if( ncMax > 0 ) cBuf[0] = 0;
1265 while( noc < ncMax-8-1 && !lend ){
1266 /* There is room for at least 2 more characters and a 0-terminator. */
1267 int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
1268 # undef SHELL_GULP
1269 DWORD nbr = 0;
1270 BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
1271 if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
1272 /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
1273 DWORD nbrx;
1274 bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
1275 if( bRC ) nbr += nbrx;
1276 }
1277 if( !bRC || (noc==0 && nbr==0) ) return 0;
1278 if( nbr > 0 ){
1279 int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
1280 if( nmb != 0 && noc+nmb <= ncMax ){
1281 int iseg = noc;
1282 nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
1283 noc += nmb;
1284 /* Fixup line-ends as coded by Windows for CR (or "Enter".)
1285 ** This is done without regard for any setMode{Text,Binary}()
1286 ** call that might have been done on the interactive input.
1287 */
1288 if( noc > 0 ){
1289 if( cBuf[noc-1]=='\n' ){
1290 lend = 1;
1291 if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
1292 }
1293 }
1294 /* Check for ^Z (anywhere in line) too, to act as EOF. */
1295 while( iseg < noc ){
1296 if( cBuf[iseg]=='\x1a' ){
1297 noc = iseg; /* Chop ^Z and anything following. */
1298 lend = 1; /* Counts as end of line too. */
1299 break;
1300 }
1301 ++iseg;
1302 }
1303 }else break; /* Drop apparent garbage in. (Could assert.) */
1304 }else break;
1305 }
1306 /* If got nothing, (after ^Z chop), must be at end-of-file. */
1307 if( noc > 0 ){
1308 cBuf[noc] = 0;
1309 return cBuf;
1310 }else return 0;
1311 # endif
1312 }else{
1313 # endif
1314 return cfGets(cBuf, ncMax, pfIn);
1315 # if CIO_WIN_WC_XLATE
1316 }
1317 # endif
1318 }
1319 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
1320
1321 #if defined(_MSC_VER)
1322 # pragma warning(default : 4204)
1323 #endif
1324
1325 #undef SHELL_INVALID_FILE_PTR
1326
1327 /************************* End ../ext/consio/console_io.c ********************/
1328
1329 #ifndef SQLITE_SHELL_FIDDLE
1330
1331 /* From here onward, fgets() is redirected to the console_io library. */
1332 # define fgets(b,n,f) fGetsUtf8(b,n,f)
1333 /*
1334 * Define macros for emitting output text in various ways:
1335 * sputz(s, z) => emit 0-terminated string z to given stream s
1336 * sputf(s, f, ...) => emit varargs per format f to given stream s
1337 * oputz(z) => emit 0-terminated string z to default stream
1338 * oputf(f, ...) => emit varargs per format f to default stream
1339 * eputz(z) => emit 0-terminated string z to error stream
1340 * eputf(f, ...) => emit varargs per format f to error stream
1341 * oputb(b, n) => emit char buffer b[0..n-1] to default stream
1342 *
1343 * Note that the default stream is whatever has been last set via:
1344 * setOutputStream(FILE *pf)
1345 * This is normally the stream that CLI normal output goes to.
1346 * For the stand-alone CLI, it is stdout with no .output redirect.
1347 *
1348 * The ?putz(z) forms are required for the Fiddle builds for string literal
1349 * output, in aid of enforcing format string to argument correspondence.
1350 */
1351 # define sputz(s,z) fPutsUtf8(z,s)
1352 # define sputf fPrintfUtf8
1353 # define oputz(z) oPutsUtf8(z)
1354 # define oputf oPrintfUtf8
1355 # define eputz(z) ePutsUtf8(z)
1356 # define eputf ePrintfUtf8
1357 # define oputb(buf,na) oPutbUtf8(buf,na)
1358 # define fflush(s) fFlushBuffer(s);
1359
1360 #else
1361 /* For Fiddle, all console handling and emit redirection is omitted. */
1362 /* These next 3 macros are for emitting formatted output. When complaints
1363 * from the WASM build are issued for non-formatted output, when a mere
1364 * string literal is to be emitted, the ?putz(z) forms should be used.
1365 * (This permits compile-time checking of format string / argument mismatch.)
1366 */
1367 # define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
1368 # define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
1369 # define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
1370 /* These next 3 macros are for emitting simple string literals. */
1371 # define oputz(z) fputs(z,stdout)
1372 # define eputz(z) fputs(z,stderr)
1373 # define sputz(fp,z) fputs(z,fp)
1374 # define oputb(buf,na) fwrite(buf,1,na,stdout)
1375 # undef fflush
1376 #endif
1377
1378 /* True if the timer is enabled */
1379 static int enableTimer = 0;
1380
1381 /* A version of strcmp() that works with NULL values */
@@ -1416,10 +666,11 @@
1416 struct timeval ru_utime; /* user CPU time used */
1417 struct timeval ru_stime; /* system CPU time used */
1418 };
1419 #define getrusage(A,B) memset(B,0,sizeof(*B))
1420 #endif
 
1421
1422 /* Saved resource information for the beginning of an operation */
1423 static struct rusage sBegin; /* CPU time at start */
1424 static sqlite3_int64 iBegin; /* Wall-clock time at start */
1425
@@ -1440,24 +691,24 @@
1440 }
1441
1442 /*
1443 ** Print the timing results.
1444 */
1445 static void endTimer(void){
1446 if( enableTimer ){
1447 sqlite3_int64 iEnd = timeOfDay();
1448 struct rusage sEnd;
1449 getrusage(RUSAGE_SELF, &sEnd);
1450 sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
1451 (iEnd - iBegin)*0.001,
1452 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
1453 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
1454 }
1455 }
1456
1457 #define BEGIN_TIMER beginTimer()
1458 #define END_TIMER endTimer()
1459 #define HAS_TIMER 1
1460
1461 #elif (defined(_WIN32) || defined(WIN32))
1462
1463 /* Saved resource information for the beginning of an operation */
@@ -1519,29 +770,29 @@
1519 }
1520
1521 /*
1522 ** Print the timing results.
1523 */
1524 static void endTimer(void){
1525 if( enableTimer && getProcessTimesAddr){
1526 FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
1527 sqlite3_int64 ftWallEnd = timeOfDay();
1528 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
1529 sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
1530 (ftWallEnd - ftWallBegin)*0.001,
1531 timeDiff(&ftUserBegin, &ftUserEnd),
1532 timeDiff(&ftKernelBegin, &ftKernelEnd));
1533 }
1534 }
1535
1536 #define BEGIN_TIMER beginTimer()
1537 #define END_TIMER endTimer()
1538 #define HAS_TIMER hasTimer()
1539
1540 #else
1541 #define BEGIN_TIMER
1542 #define END_TIMER
1543 #define HAS_TIMER 0
1544 #endif
1545
1546 /*
1547 ** Used to prevent warnings about unused parameters
@@ -1738,41 +989,216 @@
1738 char *z;
1739 if( iotrace==0 ) return;
1740 va_start(ap, zFormat);
1741 z = sqlite3_vmprintf(zFormat, ap);
1742 va_end(ap);
1743 sputf(iotrace, "%s", z);
1744 sqlite3_free(z);
1745 }
1746 #endif
1747
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1748 /*
1749 ** Output string zUtf to Out stream as w characters. If w is negative,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1750 ** then right-justify the text. W is the width in UTF-8 characters, not
1751 ** in bytes. This is different from the %*.*s specification in printf
1752 ** since with %*.*s the width is measured in bytes, not characters.
 
 
 
 
1753 */
1754 static void utf8_width_print(int w, const char *zUtf){
1755 int i;
1756 int n;
 
 
1757 int aw = w<0 ? -w : w;
1758 if( zUtf==0 ) zUtf = "";
1759 for(i=n=0; zUtf[i]; i++){
1760 if( (zUtf[i]&0xc0)!=0x80 ){
 
 
 
 
 
 
 
 
 
 
 
1761 n++;
1762 if( n==aw ){
1763 do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
1764 break;
1765 }
1766 }
1767 }
1768 if( n>=aw ){
1769 oputf("%.*s", i, zUtf);
1770 }else if( w<0 ){
1771 oputf("%*s%s", aw-n, "", zUtf);
1772 }else{
1773 oputf("%s%*s", zUtf, aw-n, "");
1774 }
1775 }
1776
1777
1778 /*
@@ -1834,11 +1260,11 @@
1834 struct __stat64 x = {0};
1835 # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
1836 /* On Windows, open first, then check the stream nature. This order
1837 ** is necessary because _stat() and sibs, when checking a named pipe,
1838 ** effectively break the pipe as its supplier sees it. */
1839 FILE *rv = fopen(zFile, "rb");
1840 if( rv==0 ) return 0;
1841 if( _fstat64(_fileno(rv), &x) != 0
1842 || !STAT_CHR_SRC(x.st_mode)){
1843 fclose(rv);
1844 rv = 0;
@@ -1848,11 +1274,11 @@
1848 struct stat x = {0};
1849 int rc = stat(zFile, &x);
1850 # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
1851 if( rc!=0 ) return 0;
1852 if( STAT_CHR_SRC(x.st_mode) ){
1853 return fopen(zFile, "rb");
1854 }else{
1855 return 0;
1856 }
1857 #endif
1858 #undef STAT_CHR_SRC
@@ -1875,11 +1301,11 @@
1875 if( n+100>nLine ){
1876 nLine = nLine*2 + 100;
1877 zLine = realloc(zLine, nLine);
1878 shell_check_oom(zLine);
1879 }
1880 if( fgets(&zLine[n], nLine - n, in)==0 ){
1881 if( n==0 ){
1882 free(zLine);
1883 return 0;
1884 }
1885 zLine[n] = 0;
@@ -2941,11 +2367,11 @@
2941 **
2942 ******************************************************************************
2943 **
2944 ** This SQLite extension implements functions that compute SHA3 hashes
2945 ** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
2946 ** Two SQL functions are implemented:
2947 **
2948 ** sha3(X,SIZE)
2949 ** sha3_agg(Y,SIZE)
2950 ** sha3_query(Z,SIZE)
2951 **
@@ -3783,10 +3209,422 @@
3783 }
3784 return rc;
3785 }
3786
3787 /************************* End ../ext/misc/shathree.c ********************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3788 /************************* Begin ../ext/misc/uint.c ******************/
3789 /*
3790 ** 2020-04-14
3791 **
3792 ** The author disclaims copyright to this source code. In place of
@@ -5075,11 +4913,11 @@
5075 }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
5076 p->a[p->nUsed++] = y;
5077 }else if( p->bKeepSorted ){
5078 int i;
5079 i = percentBinarySearch(p, y, 0);
5080 if( i<p->nUsed ){
5081 memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
5082 }
5083 p->a[i] = y;
5084 p->nUsed++;
5085 }else{
@@ -5191,11 +5029,11 @@
5191
5192 /* Find and remove the row */
5193 i = percentBinarySearch(p, y, 1);
5194 if( i>=0 ){
5195 p->nUsed--;
5196 if( i<p->nUsed ){
5197 memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
5198 }
5199 }
5200 }
5201
@@ -5251,15 +5089,15 @@
5251 sqlite3 *db,
5252 char **pzErrMsg,
5253 const sqlite3_api_routines *pApi
5254 ){
5255 int rc = SQLITE_OK;
5256 int i;
5257 #if defined(SQLITE3_H) || defined(SQLITE_STATIC_PERCENTILE)
5258 (void)pApi; /* Unused parameter */
5259 #else
5260 SQLITE_EXTENSION_INIT2(pApi);
 
 
5261 #endif
5262 (void)pzErrMsg; /* Unused parameter */
5263 for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
5264 rc = sqlite3_create_window_function(db,
5265 aPercentFunc[i].zName,
@@ -7012,50 +6850,58 @@
7012 aIdx[4] = i;
7013 idxNum |= 0x40;
7014 }
7015 continue;
7016 }
7017 if( pConstraint->iColumn==SERIES_COLUMN_VALUE ){
7018 switch( op ){
7019 case SQLITE_INDEX_CONSTRAINT_EQ:
7020 case SQLITE_INDEX_CONSTRAINT_IS: {
7021 idxNum |= 0x0080;
7022 idxNum &= ~0x3300;
7023 aIdx[5] = i;
7024 aIdx[6] = -1;
7025 bStartSeen = 1;
7026 break;
7027 }
7028 case SQLITE_INDEX_CONSTRAINT_GE: {
7029 if( idxNum & 0x0080 ) break;
7030 idxNum |= 0x0100;
7031 idxNum &= ~0x0200;
7032 aIdx[5] = i;
7033 bStartSeen = 1;
7034 break;
7035 }
7036 case SQLITE_INDEX_CONSTRAINT_GT: {
7037 if( idxNum & 0x0080 ) break;
7038 idxNum |= 0x0200;
7039 idxNum &= ~0x0100;
7040 aIdx[5] = i;
7041 bStartSeen = 1;
7042 break;
7043 }
7044 case SQLITE_INDEX_CONSTRAINT_LE: {
7045 if( idxNum & 0x0080 ) break;
7046 idxNum |= 0x1000;
7047 idxNum &= ~0x2000;
7048 aIdx[6] = i;
7049 break;
7050 }
7051 case SQLITE_INDEX_CONSTRAINT_LT: {
7052 if( idxNum & 0x0080 ) break;
7053 idxNum |= 0x2000;
7054 idxNum &= ~0x1000;
7055 aIdx[6] = i;
7056 break;
 
 
 
 
 
 
 
 
7057 }
7058 }
7059 continue;
7060 }
7061 iCol = pConstraint->iColumn - SERIES_COLUMN_START;
@@ -8115,11 +7961,11 @@
8115 ** If the optional MTIME argument is present, then it is interpreted
8116 ** as an integer - the number of seconds since the unix epoch. The
8117 ** modification-time of the target file is set to this value before
8118 ** returning.
8119 **
8120 ** If three or more arguments are passed to this function and an
8121 ** error is encountered, an exception is raised.
8122 **
8123 ** READFILE(FILE):
8124 **
8125 ** Read and return the contents of file FILE (type blob) from disk.
@@ -8185,10 +8031,17 @@
8185 # define lstat(path,buf) stat(path,buf)
8186 #endif
8187 #include <time.h>
8188 #include <errno.h>
8189
 
 
 
 
 
 
 
8190
8191 /*
8192 ** Structure of the fsdir() table-valued function
8193 */
8194 /* 0 1 2 3 4 5 */
@@ -8217,11 +8070,11 @@
8217 sqlite3_int64 nIn;
8218 void *pBuf;
8219 sqlite3 *db;
8220 int mxBlob;
8221
8222 in = fopen(zName, "rb");
8223 if( in==0 ){
8224 /* File does not exist or is unreadable. Leave the result set to NULL. */
8225 return;
8226 }
8227 fseek(in, 0, SEEK_END);
@@ -8472,11 +8325,11 @@
8472 }
8473 }else{
8474 sqlite3_int64 nWrite = 0;
8475 const char *z;
8476 int rc = 0;
8477 FILE *out = fopen(zFile, "wb");
8478 if( out==0 ) return 1;
8479 z = (const char*)sqlite3_value_blob(pData);
8480 if( z ){
8481 sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
8482 nWrite = sqlite3_value_bytes(pData);
@@ -10333,10 +10186,18 @@
10333 #ifndef SQLITE_NO_STDINT
10334 # include <stdint.h>
10335 #endif
10336
10337 #include <zlib.h>
 
 
 
 
 
 
 
 
10338
10339 #ifndef SQLITE_OMIT_VIRTUALTABLE
10340
10341 #ifndef SQLITE_AMALGAMATION
10342
@@ -11590,11 +11451,11 @@
11590 }else{
11591 zFile = (const char*)sqlite3_value_text(argv[0]);
11592 }
11593
11594 if( 0==pTab->pWriteFd && 0==bInMemory ){
11595 pCsr->pFile = zFile ? fopen(zFile, "rb") : 0;
11596 if( pCsr->pFile==0 ){
11597 zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
11598 rc = SQLITE_ERROR;
11599 }else{
11600 rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
@@ -11780,11 +11641,11 @@
11780
11781 /* Open a write fd on the file. Also load the entire central directory
11782 ** structure into memory. During the transaction any new file data is
11783 ** appended to the archive file, but the central directory is accumulated
11784 ** in main-memory until the transaction is committed. */
11785 pTab->pWriteFd = fopen(pTab->zFile, "ab+");
11786 if( pTab->pWriteFd==0 ){
11787 pTab->base.zErrMsg = sqlite3_mprintf(
11788 "zipfile: failed to open file %s for writing", pTab->zFile
11789 );
11790 rc = SQLITE_ERROR;
@@ -14233,10 +14094,70 @@
14233 }
14234
14235 return rc;
14236 }
14237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14238
14239 static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
14240 int rc = idxRegisterVtab(p);
14241 sqlite3_stmt *pSchema = 0;
14242
@@ -14244,30 +14165,39 @@
14244 **
14245 ** 1) Add an entry to the p->pTable list, and
14246 ** 2) Create the equivalent virtual table in dbv.
14247 */
14248 rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
14249 "SELECT type, name, sql, 1 FROM sqlite_schema "
14250 "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
 
 
 
14251 " UNION ALL "
14252 "SELECT type, name, sql, 2 FROM sqlite_schema "
14253 "WHERE type = 'trigger'"
14254 " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
14255 "ORDER BY 4, 1"
14256 );
14257 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
14258 const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
14259 const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
14260 const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
 
 
14261
14262 if( zType==0 || zName==0 ) continue;
14263 if( zType[0]=='v' || zType[1]=='r' ){
14264 if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
 
 
 
 
14265 }else{
14266 IdxTable *pTab;
14267 rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
14268 if( rc==SQLITE_OK ){
14269 int i;
14270 char *zInner = 0;
14271 char *zOuter = 0;
14272 pTab->pNext = p->pTable;
14273 p->pTable = pTab;
@@ -14464,10 +14394,16 @@
14464 sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
14465 while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
14466 const char *zComma = zCols==0 ? "" : ", ";
14467 const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
14468 const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
 
 
 
 
 
 
14469 zCols = idxAppendText(&rc, zCols,
14470 "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
14471 zComma, zName, nCol, zName, zColl
14472 );
14473 zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
@@ -14792,16 +14728,22 @@
14792
14793 /* Copy the entire schema of database [db] into [dbm]. */
14794 if( rc==SQLITE_OK ){
14795 sqlite3_stmt *pSql = 0;
14796 rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
14797 "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
14798 " AND sql NOT LIKE 'CREATE VIRTUAL %%' ORDER BY rowid"
 
14799 );
14800 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
14801 const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
14802 if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
 
 
 
 
 
14803 }
14804 idxFinalize(&rc, pSql);
14805 }
14806
14807 /* Create the vtab schema */
@@ -16211,10 +16153,1197 @@
16211 }
16212 return rc;
16213 }
16214
16215 /************************* End ../ext/misc/stmtrand.c ********************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16216
16217 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
16218 #define SQLITE_SHELL_HAVE_RECOVER 1
16219 #else
16220 #define SQLITE_SHELL_HAVE_RECOVER 0
@@ -18241,11 +19370,11 @@
18241 }while( strstr(z,zBuf)!=0 );
18242 return zBuf;
18243 }
18244
18245 /*
18246 ** Implementation of scalar SQL function "escape_crnl". The argument passed to
18247 ** this function is the output of built-in function quote(). If the first
18248 ** character of the input is "'", indicating that the value passed to quote()
18249 ** was a text value, then this function searches the input for "\n" and "\r"
18250 ** characters and adds a wrapper similar to the following:
18251 **
@@ -18252,11 +19381,11 @@
18252 ** replace(replace(<input>, '\n', char(10), '\r', char(13));
18253 **
18254 ** Or, if the first character of the input is not "'", then a copy of the input
18255 ** is returned.
18256 */
18257 static void recoverEscapeCrnl(
18258 sqlite3_context *context,
18259 int argc,
18260 sqlite3_value **argv
18261 ){
18262 const char *zText = (const char*)sqlite3_value_text(argv[0]);
@@ -18467,11 +19596,11 @@
18467 void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
18468 } aFunc[] = {
18469 { "getpage", 1, recoverGetPage },
18470 { "page_is_used", 1, recoverPageIsUsed },
18471 { "read_i32", 2, recoverReadI32 },
18472 { "escape_crnl", 1, recoverEscapeCrnl },
18473 };
18474
18475 const int flags = SQLITE_OPEN_URI|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
18476 sqlite3 *db = 0; /* New database handle */
18477 int ii; /* For iterating through aFunc[] */
@@ -18820,11 +19949,11 @@
18820 assert( pTab->aCol[ii].iField>=0 && pTab->aCol[ii].iBind>=1 );
18821 zSql = recoverMPrintf(p, "%z%s%Q", zSql, zSep, pTab->aCol[ii].zCol);
18822
18823 if( bSql ){
18824 zBind = recoverMPrintf(p,
18825 "%z%sescape_crnl(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
18826 );
18827 zSqlSep = "||', '||";
18828 }else{
18829 zBind = recoverMPrintf(p, "%z%s?%d", zBind, zSep, pTab->aCol[ii].iBind);
18830 }
@@ -19322,10 +20451,12 @@
19322 apVal[iField] = sqlite3_value_dup( pVal );
19323 if( apVal[iField]==0 ){
19324 recoverError(p, SQLITE_NOMEM, 0);
19325 }
19326 p1->nVal = iField+1;
 
 
19327 }
19328 p1->iPrevCell = iCell;
19329 p1->iPrevPage = iPage;
19330 }
19331 }else{
@@ -20437,10 +21568,11 @@
20437 u8 nEqpLevel; /* Depth of the EQP output graph */
20438 u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
20439 u8 bSafeMode; /* True to prohibit unsafe operations */
20440 u8 bSafeModePersist; /* The long-term value of bSafeMode */
20441 u8 eRestoreState; /* See comments above doAutoDetectRestore() */
 
20442 ColModeOpts cmOpts; /* Option values affecting columnar mode output */
20443 unsigned statsOn; /* True to display memory stats before each finalize */
20444 unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
20445 int inputNesting; /* Track nesting level of .read and other redirects */
20446 int outCount; /* Revert to stdout when reaching zero */
@@ -20582,10 +21714,11 @@
20582 #define MODE_Table 15 /* MySQL-style table formatting */
20583 #define MODE_Box 16 /* Unicode box-drawing characters */
20584 #define MODE_Count 17 /* Output only a count of the rows of output */
20585 #define MODE_Off 18 /* No query output shown */
20586 #define MODE_ScanExp 19 /* Like MODE_Explain, but for ".scanstats vm" */
 
20587
20588 static const char *modeDescr[] = {
20589 "line",
20590 "column",
20591 "list",
@@ -20602,11 +21735,13 @@
20602 "json",
20603 "markdown",
20604 "table",
20605 "box",
20606 "count",
20607 "off"
 
 
20608 };
20609
20610 /*
20611 ** These are the column/row/line separators used by the various
20612 ** import/export modes.
@@ -20630,11 +21765,11 @@
20630 ** A callback for the sqlite3_log() interface.
20631 */
20632 static void shellLog(void *pArg, int iErrCode, const char *zMsg){
20633 ShellState *p = (ShellState*)pArg;
20634 if( p->pLog==0 ) return;
20635 sputf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
20636 fflush(p->pLog);
20637 }
20638
20639 /*
20640 ** SQL function: shell_putsnl(X)
@@ -20645,13 +21780,13 @@
20645 static void shellPutsFunc(
20646 sqlite3_context *pCtx,
20647 int nVal,
20648 sqlite3_value **apVal
20649 ){
20650 /* Unused: (ShellState*)sqlite3_user_data(pCtx); */
20651 (void)nVal;
20652 oputf("%s\n", sqlite3_value_text(apVal[0]));
20653 sqlite3_result_value(pCtx, apVal[0]);
20654 }
20655
20656 /*
20657 ** If in safe mode, print an error message described by the arguments
@@ -20666,11 +21801,11 @@
20666 va_list ap;
20667 char *zMsg;
20668 va_start(ap, zErrMsg);
20669 zMsg = sqlite3_vmprintf(zErrMsg, ap);
20670 va_end(ap);
20671 eputf("line %d: %s\n", p->lineno, zMsg);
20672 exit(1);
20673 }
20674 }
20675
20676 /*
@@ -20699,11 +21834,11 @@
20699 char *zTempFile = 0;
20700 sqlite3 *db;
20701 char *zCmd = 0;
20702 int bBin;
20703 int rc;
20704 int hasCRNL = 0;
20705 FILE *f = 0;
20706 sqlite3_int64 sz;
20707 sqlite3_int64 x;
20708 unsigned char *p = 0;
20709
@@ -20733,11 +21868,11 @@
20733 }
20734 }
20735 bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
20736 /* When writing the file to be edited, do \n to \r\n conversions on systems
20737 ** that want \r\n line endings */
20738 f = fopen(zTempFile, bBin ? "wb" : "w");
20739 if( f==0 ){
20740 sqlite3_result_error(context, "edit() cannot open temp file", -1);
20741 goto edit_func_end;
20742 }
20743 sz = sqlite3_value_bytes(argv[0]);
@@ -20744,11 +21879,11 @@
20744 if( bBin ){
20745 x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
20746 }else{
20747 const char *z = (const char*)sqlite3_value_text(argv[0]);
20748 /* Remember whether or not the value originally contained \r\n */
20749 if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
20750 x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
20751 }
20752 fclose(f);
20753 f = 0;
20754 if( x!=sz ){
@@ -20764,11 +21899,11 @@
20764 sqlite3_free(zCmd);
20765 if( rc ){
20766 sqlite3_result_error(context, "EDITOR returned non-zero", -1);
20767 goto edit_func_end;
20768 }
20769 f = fopen(zTempFile, "rb");
20770 if( f==0 ){
20771 sqlite3_result_error(context,
20772 "edit() cannot reopen temp file after edit", -1);
20773 goto edit_func_end;
20774 }
@@ -20789,11 +21924,11 @@
20789 }
20790 if( bBin ){
20791 sqlite3_result_blob64(context, p, sz, sqlite3_free);
20792 }else{
20793 sqlite3_int64 i, j;
20794 if( hasCRNL ){
20795 /* If the original contains \r\n then do no conversions back to \n */
20796 }else{
20797 /* If the file did not originally contain \r\n then convert any new
20798 ** \r\n back into \n */
20799 p[sz] = 0;
@@ -20830,15 +21965,30 @@
20830 p->mode = p->modePrior;
20831 p->shellFlgs = p->priorShFlgs;
20832 memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
20833 memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
20834 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20835
20836 /*
20837 ** Output the given string as a hex-encoded blob (eg. X'1234' )
20838 */
20839 static void output_hex_blob(const void *pBlob, int nBlob){
20840 int i;
20841 unsigned char *aBlob = (unsigned char*)pBlob;
20842
20843 char *zStr = sqlite3_malloc(nBlob*2 + 1);
20844 shell_check_oom(zStr);
@@ -20851,11 +22001,11 @@
20851 zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
20852 zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
20853 }
20854 zStr[i*2] = '\0';
20855
20856 oputf("X'%s'", zStr);
20857 sqlite3_free(zStr);
20858 }
20859
20860 /*
20861 ** Find a string that is not found anywhere in z[]. Return a pointer
@@ -20881,46 +22031,40 @@
20881 /*
20882 ** Output the given string as a quoted string using SQL quoting conventions.
20883 **
20884 ** See also: output_quoted_escaped_string()
20885 */
20886 static void output_quoted_string(const char *z){
20887 int i;
20888 char c;
20889 #ifndef SQLITE_SHELL_FIDDLE
20890 FILE *pfO = setOutputStream(invalidFileStream);
20891 setBinaryMode(pfO, 1);
20892 #endif
20893 if( z==0 ) return;
20894 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
20895 if( c==0 ){
20896 oputf("'%s'",z);
20897 }else{
20898 oputz("'");
20899 while( *z ){
20900 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
20901 if( c=='\'' ) i++;
20902 if( i ){
20903 oputf("%.*s", i, z);
20904 z += i;
20905 }
20906 if( c=='\'' ){
20907 oputz("'");
20908 continue;
20909 }
20910 if( c==0 ){
20911 break;
20912 }
20913 z++;
20914 }
20915 oputz("'");
20916 }
20917 #ifndef SQLITE_SHELL_FIDDLE
20918 setTextMode(pfO, 1);
20919 #else
20920 setTextMode(stdout, 1);
20921 #endif
20922 }
20923
20924 /*
20925 ** Output the given string as a quoted string using SQL quoting conventions.
20926 ** Additionallly , escape the "\n" and "\r" characters so that they do not
@@ -20928,20 +22072,18 @@
20928 ** systems.
20929 **
20930 ** This is like output_quoted_string() but with the addition of the \r\n
20931 ** escape mechanism.
20932 */
20933 static void output_quoted_escaped_string(const char *z){
20934 int i;
20935 char c;
20936 #ifndef SQLITE_SHELL_FIDDLE
20937 FILE *pfO = setOutputStream(invalidFileStream);
20938 setBinaryMode(pfO, 1);
20939 #endif
20940 for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
20941 if( c==0 ){
20942 oputf("'%s'",z);
20943 }else{
20944 const char *zNL = 0;
20945 const char *zCR = 0;
20946 int nNL = 0;
20947 int nCR = 0;
@@ -20949,52 +22091,48 @@
20949 for(i=0; z[i]; i++){
20950 if( z[i]=='\n' ) nNL++;
20951 if( z[i]=='\r' ) nCR++;
20952 }
20953 if( nNL ){
20954 oputz("replace(");
20955 zNL = unused_string(z, "\\n", "\\012", zBuf1);
20956 }
20957 if( nCR ){
20958 oputz("replace(");
20959 zCR = unused_string(z, "\\r", "\\015", zBuf2);
20960 }
20961 oputz("'");
20962 while( *z ){
20963 for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
20964 if( c=='\'' ) i++;
20965 if( i ){
20966 oputf("%.*s", i, z);
20967 z += i;
20968 }
20969 if( c=='\'' ){
20970 oputz("'");
20971 continue;
20972 }
20973 if( c==0 ){
20974 break;
20975 }
20976 z++;
20977 if( c=='\n' ){
20978 oputz(zNL);
20979 continue;
20980 }
20981 oputz(zCR);
20982 }
20983 oputz("'");
20984 if( nCR ){
20985 oputf(",'%s',char(13))", zCR);
20986 }
20987 if( nNL ){
20988 oputf(",'%s',char(10))", zNL);
20989 }
20990 }
20991 #ifndef SQLITE_SHELL_FIDDLE
20992 setTextMode(pfO, 1);
20993 #else
20994 setTextMode(stdout, 1);
20995 #endif
20996 }
20997
20998 /*
20999 ** Find earliest of chars within s specified in zAny.
21000 ** With ns == ~0, is like strpbrk(s,zAny) and s must be 0-terminated.
@@ -21010,26 +22148,64 @@
21010 }
21011 ++zAny;
21012 }
21013 return pcFirst;
21014 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21015 /*
21016 ** Output the given string as a quoted according to C or TCL quoting rules.
21017 */
21018 static void output_c_string(const char *z){
21019 char c;
21020 static const char *zq = "\"";
21021 static long ctrlMask = ~0L;
21022 static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */
21023 char ace[3] = "\\?";
21024 char cbsSay;
21025 oputz(zq);
21026 while( *z!=0 ){
21027 const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0);
21028 const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask);
21029 const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast;
21030 if( pcEnd > z ) oputb(z, (int)(pcEnd-z));
 
 
21031 if( (c = *pcEnd)==0 ) break;
21032 ++pcEnd;
21033 switch( c ){
21034 case '\\': case '"':
21035 cbsSay = (char)c;
@@ -21040,47 +22216,47 @@
21040 case '\f': cbsSay = 'f'; break;
21041 default: cbsSay = 0; break;
21042 }
21043 if( cbsSay ){
21044 ace[1] = cbsSay;
21045 oputz(ace);
21046 }else if( !isprint(c&0xff) ){
21047 oputf("\\%03o", c&0xff);
21048 }else{
21049 ace[1] = (char)c;
21050 oputz(ace+1);
21051 }
21052 z = pcEnd;
21053 }
21054 oputz(zq);
21055 }
21056
21057 /*
21058 ** Output the given string as a quoted according to JSON quoting rules.
21059 */
21060 static void output_json_string(const char *z, i64 n){
21061 char c;
21062 static const char *zq = "\"";
21063 static long ctrlMask = ~0L;
21064 static const char *zDQBS = "\"\\";
21065 const char *pcLimit;
21066 char ace[3] = "\\?";
21067 char cbsSay;
21068
21069 if( z==0 ) z = "";
21070 pcLimit = z + ((n<0)? strlen(z) : (size_t)n);
21071 oputz(zq);
21072 while( z < pcLimit ){
21073 const char *pcDQBS = anyOfInStr(z, zDQBS, pcLimit-z);
21074 const char *pcPast = zSkipValidUtf8(z, (int)(pcLimit-z), ctrlMask);
21075 const char *pcEnd = (pcDQBS && pcDQBS < pcPast)? pcDQBS : pcPast;
21076 if( pcEnd > z ){
21077 oputb(z, (int)(pcEnd-z));
21078 z = pcEnd;
21079 }
21080 if( z >= pcLimit ) break;
21081 c = *(z++);
21082 switch( c ){
21083 case '"': case '\\':
21084 cbsSay = (char)c;
21085 break;
21086 case '\b': cbsSay = 'b'; break;
@@ -21090,26 +22266,26 @@
21090 case '\t': cbsSay = 't'; break;
21091 default: cbsSay = 0; break;
21092 }
21093 if( cbsSay ){
21094 ace[1] = cbsSay;
21095 oputz(ace);
21096 }else if( c<=0x1f ){
21097 oputf("u%04x", c);
21098 }else{
21099 ace[1] = (char)c;
21100 oputz(ace+1);
21101 }
21102 }
21103 oputz(zq);
21104 }
21105
21106 /*
21107 ** Output the given string with characters that are special to
21108 ** HTML escaped.
21109 */
21110 static void output_html_string(const char *z){
21111 int i;
21112 if( z==0 ) z = "";
21113 while( *z ){
21114 for(i=0; z[i]
21115 && z[i]!='<'
@@ -21117,22 +22293,22 @@
21117 && z[i]!='>'
21118 && z[i]!='\"'
21119 && z[i]!='\'';
21120 i++){}
21121 if( i>0 ){
21122 oputf("%.*s",i,z);
21123 }
21124 if( z[i]=='<' ){
21125 oputz("&lt;");
21126 }else if( z[i]=='&' ){
21127 oputz("&amp;");
21128 }else if( z[i]=='>' ){
21129 oputz("&gt;");
21130 }else if( z[i]=='\"' ){
21131 oputz("&quot;");
21132 }else if( z[i]=='\'' ){
21133 oputz("&#39;");
21134 }else{
21135 break;
21136 }
21137 z += i + 1;
21138 }
@@ -21167,11 +22343,11 @@
21167 ** the null value. Strings are quoted if necessary. The separator
21168 ** is only issued if bSep is true.
21169 */
21170 static void output_csv(ShellState *p, const char *z, int bSep){
21171 if( z==0 ){
21172 oputf("%s",p->nullValue);
21173 }else{
21174 unsigned i;
21175 for(i=0; z[i]; i++){
21176 if( needCsvQuote[((unsigned char*)z)[i]] ){
21177 i = 0;
@@ -21179,18 +22355,18 @@
21179 }
21180 }
21181 if( i==0 || strstr(z, p->colSeparator)!=0 ){
21182 char *zQuoted = sqlite3_mprintf("\"%w\"", z);
21183 shell_check_oom(zQuoted);
21184 oputz(zQuoted);
21185 sqlite3_free(zQuoted);
21186 }else{
21187 oputz(z);
21188 }
21189 }
21190 if( bSep ){
21191 oputz(p->colSeparator);
21192 }
21193 }
21194
21195 /*
21196 ** This routine runs when the user presses Ctrl-C
@@ -21294,20 +22470,20 @@
21294 const char *az[4];
21295 az[0] = zA1;
21296 az[1] = zA2;
21297 az[2] = zA3;
21298 az[3] = zA4;
21299 oputf("authorizer: %s", azAction[op]);
21300 for(i=0; i<4; i++){
21301 oputz(" ");
21302 if( az[i] ){
21303 output_c_string(az[i]);
21304 }else{
21305 oputz("NULL");
21306 }
21307 }
21308 oputz("\n");
21309 if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
21310 return SQLITE_OK;
21311 }
21312 #endif
21313
@@ -21319,11 +22495,11 @@
21319 **
21320 ** If the schema statement in z[] contains a start-of-comment and if
21321 ** sqlite3_complete() returns false, try to terminate the comment before
21322 ** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
21323 */
21324 static void printSchemaLine(const char *z, const char *zTail){
21325 char *zToFree = 0;
21326 if( z==0 ) return;
21327 if( zTail==0 ) return;
21328 if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
21329 const char *zOrig = z;
@@ -21341,20 +22517,20 @@
21341 }
21342 sqlite3_free(zNew);
21343 }
21344 }
21345 if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
21346 oputf("CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
21347 }else{
21348 oputf("%s%s", z, zTail);
21349 }
21350 sqlite3_free(zToFree);
21351 }
21352 static void printSchemaLineN(char *z, int n, const char *zTail){
21353 char c = z[n];
21354 z[n] = 0;
21355 printSchemaLine(z, zTail);
21356 z[n] = c;
21357 }
21358
21359 /*
21360 ** Return true if string z[] has nothing but whitespace and comments to the
@@ -21378,11 +22554,11 @@
21378 EQPGraphRow *pNew;
21379 i64 nText;
21380 if( zText==0 ) return;
21381 nText = strlen(zText);
21382 if( p->autoEQPtest ){
21383 oputf("%d,%d,%s\n", iEqpId, p2, zText);
21384 }
21385 pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
21386 shell_check_oom(pNew);
21387 pNew->iEqpId = iEqpId;
21388 pNew->iParentId = p2;
@@ -21426,11 +22602,12 @@
21426 i64 n = strlen(p->sGraph.zPrefix);
21427 char *z;
21428 for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
21429 pNext = eqp_next_row(p, iEqpId, pRow);
21430 z = pRow->zText;
21431 oputf("%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z);
 
21432 if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
21433 memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
21434 eqp_render_level(p, pRow->iEqpId);
21435 p->sGraph.zPrefix[n] = 0;
21436 }
@@ -21446,17 +22623,17 @@
21446 if( pRow->zText[0]=='-' ){
21447 if( pRow->pNext==0 ){
21448 eqp_reset(p);
21449 return;
21450 }
21451 oputf("%s\n", pRow->zText+3);
21452 p->sGraph.pRow = pRow->pNext;
21453 sqlite3_free(pRow);
21454 }else if( nCycle>0 ){
21455 oputf("QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
21456 }else{
21457 oputz("QUERY PLAN\n");
21458 }
21459 p->sGraph.zPrefix[0] = 0;
21460 eqp_render_level(p, 0);
21461 eqp_reset(p);
21462 }
@@ -21468,33 +22645,33 @@
21468 */
21469 static int progress_handler(void *pClientData) {
21470 ShellState *p = (ShellState*)pClientData;
21471 p->nProgress++;
21472 if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
21473 oputf("Progress limit reached (%u)\n", p->nProgress);
21474 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
21475 if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
21476 return 1;
21477 }
21478 if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
21479 oputf("Progress %u\n", p->nProgress);
21480 }
21481 return 0;
21482 }
21483 #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
21484
21485 /*
21486 ** Print N dashes
21487 */
21488 static void print_dashes(int N){
21489 const char zDash[] = "--------------------------------------------------";
21490 const int nDash = sizeof(zDash) - 1;
21491 while( N>nDash ){
21492 oputz(zDash);
21493 N -= nDash;
21494 }
21495 oputf("%.*s", N, zDash);
21496 }
21497
21498 /*
21499 ** Print a markdown or table-style row separator using ascii-art
21500 */
@@ -21503,19 +22680,19 @@
21503 int nArg,
21504 const char *zSep
21505 ){
21506 int i;
21507 if( nArg>0 ){
21508 oputz(zSep);
21509 print_dashes(p->actualWidth[0]+2);
21510 for(i=1; i<nArg; i++){
21511 oputz(zSep);
21512 print_dashes(p->actualWidth[i]+2);
21513 }
21514 oputz(zSep);
21515 }
21516 oputz("\n");
21517 }
21518
21519 /*
21520 ** This is the callback routine that the shell
21521 ** invokes for each row of a query result.
@@ -21541,13 +22718,13 @@
21541 if( azArg==0 ) break;
21542 for(i=0; i<nArg; i++){
21543 int len = strlen30(azCol[i] ? azCol[i] : "");
21544 if( len>w ) w = len;
21545 }
21546 if( p->cnt++>0 ) oputz(p->rowSeparator);
21547 for(i=0; i<nArg; i++){
21548 oputf("%*s = %s%s", w, azCol[i],
21549 azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
21550 }
21551 break;
21552 }
21553 case MODE_ScanExp:
@@ -21571,16 +22748,16 @@
21571 if( nArg>nWidth ) nArg = nWidth;
21572
21573 /* If this is the first row seen, print out the headers */
21574 if( p->cnt++==0 ){
21575 for(i=0; i<nArg; i++){
21576 utf8_width_print(aWidth[i], azCol[ aMap[i] ]);
21577 oputz(i==nArg-1 ? "\n" : " ");
21578 }
21579 for(i=0; i<nArg; i++){
21580 print_dashes(aWidth[i]);
21581 oputz(i==nArg-1 ? "\n" : " ");
21582 }
21583 }
21584
21585 /* If there is no data, exit early. */
21586 if( azArg==0 ) break;
@@ -21594,21 +22771,21 @@
21594 w = strlenChar(zVal);
21595 zSep = " ";
21596 }
21597 if( i==iIndent && p->aiIndent && p->pStmt ){
21598 if( p->iIndent<p->nIndent ){
21599 oputf("%*.s", p->aiIndent[p->iIndent], "");
21600 }
21601 p->iIndent++;
21602 }
21603 utf8_width_print(w, zVal ? zVal : p->nullValue);
21604 oputz(i==nArg-1 ? "\n" : zSep);
21605 }
21606 break;
21607 }
21608 case MODE_Semi: { /* .schema and .fullschema output */
21609 printSchemaLine(azArg[0], ";\n");
21610 break;
21611 }
21612 case MODE_Pretty: { /* .schema and .fullschema with --indent */
21613 char *z;
21614 int j;
@@ -21619,11 +22796,11 @@
21619 assert( nArg==1 );
21620 if( azArg[0]==0 ) break;
21621 if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
21622 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
21623 ){
21624 oputf("%s;\n", azArg[0]);
21625 break;
21626 }
21627 z = sqlite3_mprintf("%s", azArg[0]);
21628 shell_check_oom(z);
21629 j = 0;
@@ -21652,255 +22829,265 @@
21652 }else if( c=='(' ){
21653 nParen++;
21654 }else if( c==')' ){
21655 nParen--;
21656 if( nLine>0 && nParen==0 && j>0 ){
21657 printSchemaLineN(z, j, "\n");
21658 j = 0;
21659 }
21660 }
21661 z[j++] = c;
21662 if( nParen==1 && cEnd==0
21663 && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
21664 ){
21665 if( c=='\n' ) j--;
21666 printSchemaLineN(z, j, "\n ");
21667 j = 0;
21668 nLine++;
21669 while( IsSpace(z[i+1]) ){ i++; }
21670 }
21671 }
21672 z[j] = 0;
21673 }
21674 printSchemaLine(z, ";\n");
21675 sqlite3_free(z);
21676 break;
21677 }
21678 case MODE_List: {
21679 if( p->cnt++==0 && p->showHeader ){
21680 for(i=0; i<nArg; i++){
21681 oputf("%s%s",azCol[i], i==nArg-1 ? p->rowSeparator : p->colSeparator);
 
21682 }
21683 }
21684 if( azArg==0 ) break;
21685 for(i=0; i<nArg; i++){
21686 char *z = azArg[i];
21687 if( z==0 ) z = p->nullValue;
21688 oputz(z);
21689 oputz((i<nArg-1)? p->colSeparator : p->rowSeparator);
21690 }
21691 break;
21692 }
 
21693 case MODE_Html: {
21694 if( p->cnt++==0 && p->showHeader ){
21695 oputz("<TR>");
 
 
 
 
 
 
 
21696 for(i=0; i<nArg; i++){
21697 oputz("<TH>");
21698 output_html_string(azCol[i]);
21699 oputz("</TH>\n");
21700 }
21701 oputz("</TR>\n");
21702 }
 
21703 if( azArg==0 ) break;
21704 oputz("<TR>");
21705 for(i=0; i<nArg; i++){
21706 oputz("<TD>");
21707 output_html_string(azArg[i] ? azArg[i] : p->nullValue);
21708 oputz("</TD>\n");
21709 }
21710 oputz("</TR>\n");
21711 break;
21712 }
21713 case MODE_Tcl: {
21714 if( p->cnt++==0 && p->showHeader ){
21715 for(i=0; i<nArg; i++){
21716 output_c_string(azCol[i] ? azCol[i] : "");
21717 if(i<nArg-1) oputz(p->colSeparator);
21718 }
21719 oputz(p->rowSeparator);
21720 }
21721 if( azArg==0 ) break;
21722 for(i=0; i<nArg; i++){
21723 output_c_string(azArg[i] ? azArg[i] : p->nullValue);
21724 if(i<nArg-1) oputz(p->colSeparator);
21725 }
21726 oputz(p->rowSeparator);
21727 break;
21728 }
21729 case MODE_Csv: {
21730 setBinaryMode(p->out, 1);
21731 if( p->cnt++==0 && p->showHeader ){
21732 for(i=0; i<nArg; i++){
21733 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
21734 }
21735 oputz(p->rowSeparator);
21736 }
21737 if( nArg>0 ){
21738 for(i=0; i<nArg; i++){
21739 output_csv(p, azArg[i], i<nArg-1);
21740 }
21741 oputz(p->rowSeparator);
21742 }
21743 setTextMode(p->out, 1);
21744 break;
21745 }
21746 case MODE_Insert: {
21747 if( azArg==0 ) break;
21748 oputf("INSERT INTO %s",p->zDestTable);
21749 if( p->showHeader ){
21750 oputz("(");
21751 for(i=0; i<nArg; i++){
21752 if( i>0 ) oputz(",");
21753 if( quoteChar(azCol[i]) ){
21754 char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
21755 shell_check_oom(z);
21756 oputz(z);
21757 sqlite3_free(z);
21758 }else{
21759 oputf("%s", azCol[i]);
21760 }
21761 }
21762 oputz(")");
21763 }
21764 p->cnt++;
21765 for(i=0; i<nArg; i++){
21766 oputz(i>0 ? "," : " VALUES(");
21767 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
21768 oputz("NULL");
21769 }else if( aiType && aiType[i]==SQLITE_TEXT ){
21770 if( ShellHasFlag(p, SHFLG_Newlines) ){
21771 output_quoted_string(azArg[i]);
21772 }else{
21773 output_quoted_escaped_string(azArg[i]);
21774 }
21775 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
21776 oputz(azArg[i]);
21777 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
21778 char z[50];
21779 double r = sqlite3_column_double(p->pStmt, i);
21780 sqlite3_uint64 ur;
21781 memcpy(&ur,&r,sizeof(r));
21782 if( ur==0x7ff0000000000000LL ){
21783 oputz("9.0e+999");
21784 }else if( ur==0xfff0000000000000LL ){
21785 oputz("-9.0e+999");
21786 }else{
21787 sqlite3_int64 ir = (sqlite3_int64)r;
21788 if( r==(double)ir ){
21789 sqlite3_snprintf(50,z,"%lld.0", ir);
21790 }else{
21791 sqlite3_snprintf(50,z,"%!.20g", r);
21792 }
21793 oputz(z);
21794 }
21795 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
21796 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
21797 int nBlob = sqlite3_column_bytes(p->pStmt, i);
21798 output_hex_blob(pBlob, nBlob);
21799 }else if( isNumber(azArg[i], 0) ){
21800 oputz(azArg[i]);
21801 }else if( ShellHasFlag(p, SHFLG_Newlines) ){
21802 output_quoted_string(azArg[i]);
21803 }else{
21804 output_quoted_escaped_string(azArg[i]);
21805 }
21806 }
21807 oputz(");\n");
21808 break;
21809 }
21810 case MODE_Json: {
21811 if( azArg==0 ) break;
21812 if( p->cnt==0 ){
21813 fputs("[{", p->out);
21814 }else{
21815 fputs(",\n{", p->out);
21816 }
21817 p->cnt++;
21818 for(i=0; i<nArg; i++){
21819 output_json_string(azCol[i], -1);
21820 oputz(":");
21821 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
21822 oputz("null");
21823 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
21824 char z[50];
21825 double r = sqlite3_column_double(p->pStmt, i);
21826 sqlite3_uint64 ur;
21827 memcpy(&ur,&r,sizeof(r));
21828 if( ur==0x7ff0000000000000LL ){
21829 oputz("9.0e+999");
21830 }else if( ur==0xfff0000000000000LL ){
21831 oputz("-9.0e+999");
21832 }else{
21833 sqlite3_snprintf(50,z,"%!.20g", r);
21834 oputz(z);
21835 }
21836 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
21837 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
21838 int nBlob = sqlite3_column_bytes(p->pStmt, i);
21839 output_json_string(pBlob, nBlob);
21840 }else if( aiType && aiType[i]==SQLITE_TEXT ){
21841 output_json_string(azArg[i], -1);
21842 }else{
21843 oputz(azArg[i]);
21844 }
21845 if( i<nArg-1 ){
21846 oputz(",");
21847 }
21848 }
21849 oputz("}");
21850 break;
21851 }
21852 case MODE_Quote: {
21853 if( azArg==0 ) break;
21854 if( p->cnt==0 && p->showHeader ){
21855 for(i=0; i<nArg; i++){
21856 if( i>0 ) fputs(p->colSeparator, p->out);
21857 output_quoted_string(azCol[i]);
21858 }
21859 fputs(p->rowSeparator, p->out);
21860 }
21861 p->cnt++;
21862 for(i=0; i<nArg; i++){
21863 if( i>0 ) fputs(p->colSeparator, p->out);
21864 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
21865 oputz("NULL");
21866 }else if( aiType && aiType[i]==SQLITE_TEXT ){
21867 output_quoted_string(azArg[i]);
21868 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
21869 oputz(azArg[i]);
21870 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
21871 char z[50];
21872 double r = sqlite3_column_double(p->pStmt, i);
21873 sqlite3_snprintf(50,z,"%!.20g", r);
21874 oputz(z);
21875 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
21876 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
21877 int nBlob = sqlite3_column_bytes(p->pStmt, i);
21878 output_hex_blob(pBlob, nBlob);
21879 }else if( isNumber(azArg[i], 0) ){
21880 oputz(azArg[i]);
21881 }else{
21882 output_quoted_string(azArg[i]);
21883 }
21884 }
21885 fputs(p->rowSeparator, p->out);
21886 break;
21887 }
21888 case MODE_Ascii: {
21889 if( p->cnt++==0 && p->showHeader ){
21890 for(i=0; i<nArg; i++){
21891 if( i>0 ) oputz(p->colSeparator);
21892 oputz(azCol[i] ? azCol[i] : "");
21893 }
21894 oputz(p->rowSeparator);
21895 }
21896 if( azArg==0 ) break;
21897 for(i=0; i<nArg; i++){
21898 if( i>0 ) oputz(p->colSeparator);
21899 oputz(azArg[i] ? azArg[i] : p->nullValue);
21900 }
21901 oputz(p->rowSeparator);
21902 break;
21903 }
21904 case MODE_EQP: {
21905 eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
21906 break;
@@ -21975,11 +23162,11 @@
21975 "INSERT INTO selftest(tno,op,cmd,ans)"
21976 " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
21977 "DROP TABLE [_shell$self];"
21978 ,0,0,&zErrMsg);
21979 if( zErrMsg ){
21980 eputf("SELFTEST initialization failure: %s\n", zErrMsg);
21981 sqlite3_free(zErrMsg);
21982 }
21983 sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
21984 }
21985
@@ -22078,36 +23265,37 @@
22078 int i;
22079 const char *z;
22080 rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
22081 if( rc!=SQLITE_OK || !pSelect ){
22082 char *zContext = shell_error_context(zSelect, p->db);
22083 oputf("/**** ERROR: (%d) %s *****/\n%s",
22084 rc, sqlite3_errmsg(p->db), zContext);
22085 sqlite3_free(zContext);
22086 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
22087 return rc;
22088 }
22089 rc = sqlite3_step(pSelect);
22090 nResult = sqlite3_column_count(pSelect);
22091 while( rc==SQLITE_ROW ){
22092 z = (const char*)sqlite3_column_text(pSelect, 0);
22093 oputf("%s", z);
22094 for(i=1; i<nResult; i++){
22095 oputf(",%s", sqlite3_column_text(pSelect, i));
22096 }
22097 if( z==0 ) z = "";
22098 while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
22099 if( z[0] ){
22100 oputz("\n;\n");
22101 }else{
22102 oputz(";\n");
22103 }
22104 rc = sqlite3_step(pSelect);
22105 }
22106 rc = sqlite3_finalize(pSelect);
22107 if( rc!=SQLITE_OK ){
22108 oputf("/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
 
22109 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
22110 }
22111 return rc;
22112 }
22113
@@ -22139,17 +23327,17 @@
22139
22140 #ifdef __linux__
22141 /*
22142 ** Attempt to display I/O stats on Linux using /proc/PID/io
22143 */
22144 static void displayLinuxIoStats(void){
22145 FILE *in;
22146 char z[200];
22147 sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
22148 in = fopen(z, "rb");
22149 if( in==0 ) return;
22150 while( fgets(z, sizeof(z), in)!=0 ){
22151 static const struct {
22152 const char *zPattern;
22153 const char *zDesc;
22154 } aTrans[] = {
22155 { "rchar: ", "Bytes received by read():" },
@@ -22162,11 +23350,11 @@
22162 };
22163 int i;
22164 for(i=0; i<ArraySize(aTrans); i++){
22165 int n = strlen30(aTrans[i].zPattern);
22166 if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
22167 oputf("%-36s %s", aTrans[i].zDesc, &z[n]);
22168 break;
22169 }
22170 }
22171 }
22172 fclose(in);
@@ -22175,10 +23363,11 @@
22175
22176 /*
22177 ** Display a single line of status using 64-bit values.
22178 */
22179 static void displayStatLine(
 
22180 char *zLabel, /* Label for this one line */
22181 char *zFormat, /* Format for the result */
22182 int iStatusCtrl, /* Which status to display */
22183 int bReset /* True to reset the stats */
22184 ){
@@ -22193,11 +23382,11 @@
22193 if( nPercent>1 ){
22194 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
22195 }else{
22196 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
22197 }
22198 oputf("%-36s %s\n", zLabel, zLine);
22199 }
22200
22201 /*
22202 ** Display memory stats.
22203 */
@@ -22206,130 +23395,152 @@
22206 ShellState *pArg, /* Pointer to ShellState */
22207 int bReset /* True to reset the stats */
22208 ){
22209 int iCur;
22210 int iHiwtr;
 
22211 if( pArg==0 || pArg->out==0 ) return 0;
 
22212
22213 if( pArg->pStmt && pArg->statsOn==2 ){
22214 int nCol, i, x;
22215 sqlite3_stmt *pStmt = pArg->pStmt;
22216 char z[100];
22217 nCol = sqlite3_column_count(pStmt);
22218 oputf("%-36s %d\n", "Number of output columns:", nCol);
22219 for(i=0; i<nCol; i++){
22220 sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
22221 oputf("%-36s %s\n", z, sqlite3_column_name(pStmt,i));
22222 #ifndef SQLITE_OMIT_DECLTYPE
22223 sqlite3_snprintf(30, z+x, "declared type:");
22224 oputf("%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
22225 #endif
22226 #ifdef SQLITE_ENABLE_COLUMN_METADATA
22227 sqlite3_snprintf(30, z+x, "database name:");
22228 oputf("%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
 
22229 sqlite3_snprintf(30, z+x, "table name:");
22230 oputf("%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
22231 sqlite3_snprintf(30, z+x, "origin name:");
22232 oputf("%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
22233 #endif
22234 }
22235 }
22236
22237 if( pArg->statsOn==3 ){
22238 if( pArg->pStmt ){
22239 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset);
22240 oputf("VM-steps: %d\n", iCur);
22241 }
22242 return 0;
22243 }
22244
22245 displayStatLine("Memory Used:",
22246 "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
22247 displayStatLine("Number of Outstanding Allocations:",
22248 "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
22249 if( pArg->shellFlgs & SHFLG_Pagecache ){
22250 displayStatLine("Number of Pcache Pages Used:",
22251 "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
22252 }
22253 displayStatLine("Number of Pcache Overflow Bytes:",
22254 "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
22255 displayStatLine("Largest Allocation:",
22256 "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
22257 displayStatLine("Largest Pcache Allocation:",
22258 "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
22259 #ifdef YYTRACKMAXSTACKDEPTH
22260 displayStatLine("Deepest Parser Stack:",
22261 "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
22262 #endif
22263
22264 if( db ){
22265 if( pArg->shellFlgs & SHFLG_Lookaside ){
22266 iHiwtr = iCur = -1;
22267 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
22268 &iCur, &iHiwtr, bReset);
22269 oputf("Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
 
22270 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
22271 &iCur, &iHiwtr, bReset);
22272 oputf("Successful lookaside attempts: %d\n", iHiwtr);
 
22273 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
22274 &iCur, &iHiwtr, bReset);
22275 oputf("Lookaside failures due to size: %d\n", iHiwtr);
 
22276 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
22277 &iCur, &iHiwtr, bReset);
22278 oputf("Lookaside failures due to OOM: %d\n", iHiwtr);
 
22279 }
22280 iHiwtr = iCur = -1;
22281 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
22282 oputf("Pager Heap Usage: %d bytes\n", iCur);
 
22283 iHiwtr = iCur = -1;
22284 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
22285 oputf("Page cache hits: %d\n", iCur);
 
22286 iHiwtr = iCur = -1;
22287 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
22288 oputf("Page cache misses: %d\n", iCur);
 
22289 iHiwtr = iCur = -1;
22290 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
22291 oputf("Page cache writes: %d\n", iCur);
 
22292 iHiwtr = iCur = -1;
22293 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
22294 oputf("Page cache spills: %d\n", iCur);
 
22295 iHiwtr = iCur = -1;
22296 sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
22297 oputf("Schema Heap Usage: %d bytes\n", iCur);
 
22298 iHiwtr = iCur = -1;
22299 sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
22300 oputf("Statement Heap/Lookaside Usage: %d bytes\n", iCur);
 
22301 }
22302
22303 if( pArg->pStmt ){
22304 int iHit, iMiss;
22305 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
22306 bReset);
22307 oputf("Fullscan Steps: %d\n", iCur);
 
22308 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
22309 oputf("Sort Operations: %d\n", iCur);
 
22310 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
22311 oputf("Autoindex Inserts: %d\n", iCur);
 
22312 iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT,
22313 bReset);
22314 iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS,
22315 bReset);
22316 if( iHit || iMiss ){
22317 oputf("Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
 
22318 }
22319 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
22320 oputf("Virtual Machine Steps: %d\n", iCur);
 
22321 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
22322 oputf("Reprepare operations: %d\n", iCur);
 
22323 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
22324 oputf("Number of times run: %d\n", iCur);
 
22325 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
22326 oputf("Memory used by prepared stmt: %d\n", iCur);
 
22327 }
22328
22329 #ifdef __linux__
22330 displayLinuxIoStats();
22331 #endif
22332
22333 /* Do not remove this machine readable comment: extra-stats-output-here */
22334
22335 return 0;
@@ -22721,21 +23932,21 @@
22721 #define BOX_1234 "\342\224\274" /* U+253c -|- */
22722
22723 /* Draw horizontal line N characters long using unicode box
22724 ** characters
22725 */
22726 static void print_box_line(int N){
22727 const char zDash[] =
22728 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
22729 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
22730 const int nDash = sizeof(zDash) - 1;
22731 N *= 3;
22732 while( N>nDash ){
22733 oputz(zDash);
22734 N -= nDash;
22735 }
22736 oputf("%.*s", N, zDash);
22737 }
22738
22739 /*
22740 ** Draw a horizontal separator for a MODE_Box table.
22741 */
@@ -22746,19 +23957,19 @@
22746 const char *zSep2,
22747 const char *zSep3
22748 ){
22749 int i;
22750 if( nArg>0 ){
22751 oputz(zSep1);
22752 print_box_line(p->actualWidth[0]+2);
22753 for(i=1; i<nArg; i++){
22754 oputz(zSep2);
22755 print_box_line(p->actualWidth[i]+2);
22756 }
22757 oputz(zSep3);
22758 }
22759 oputz("\n");
22760 }
22761
22762 /*
22763 ** z[] is a line of text that is to be displayed the .mode box or table or
22764 ** similar tabular formats. z[] might contain control characters such
@@ -22788,16 +23999,26 @@
22788 }
22789 if( mxWidth<0 ) mxWidth = -mxWidth;
22790 if( mxWidth==0 ) mxWidth = 1000000;
22791 i = j = n = 0;
22792 while( n<mxWidth ){
22793 if( z[i]>=' ' ){
 
 
 
 
 
 
 
 
 
22794 n++;
22795 do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
 
22796 continue;
22797 }
22798 if( z[i]=='\t' ){
22799 do{
22800 n++;
22801 j++;
22802 }while( (n&7)!=0 && n<mxWidth );
22803 i++;
@@ -22835,13 +24056,21 @@
22835 }
22836 zOut = malloc( j+1 );
22837 shell_check_oom(zOut);
22838 i = j = n = 0;
22839 while( i<k ){
22840 if( z[i]>=' ' ){
 
 
 
 
 
 
 
 
22841 n++;
22842 do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 );
22843 continue;
22844 }
22845 if( z[i]=='\t' ){
22846 do{
22847 n++;
@@ -23017,97 +24246,99 @@
23017 rowSep = "\n";
23018 if( p->showHeader ){
23019 for(i=0; i<nColumn; i++){
23020 w = p->actualWidth[i];
23021 if( p->colWidth[i]<0 ) w = -w;
23022 utf8_width_print(w, azData[i]);
23023 fputs(i==nColumn-1?"\n":" ", p->out);
23024 }
23025 for(i=0; i<nColumn; i++){
23026 print_dashes(p->actualWidth[i]);
23027 fputs(i==nColumn-1?"\n":" ", p->out);
23028 }
23029 }
23030 break;
23031 }
23032 case MODE_Table: {
23033 colSep = " | ";
23034 rowSep = " |\n";
23035 print_row_separator(p, nColumn, "+");
23036 fputs("| ", p->out);
23037 for(i=0; i<nColumn; i++){
23038 w = p->actualWidth[i];
23039 n = strlenChar(azData[i]);
23040 oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
23041 oputz(i==nColumn-1?" |\n":" | ");
 
23042 }
23043 print_row_separator(p, nColumn, "+");
23044 break;
23045 }
23046 case MODE_Markdown: {
23047 colSep = " | ";
23048 rowSep = " |\n";
23049 fputs("| ", p->out);
23050 for(i=0; i<nColumn; i++){
23051 w = p->actualWidth[i];
23052 n = strlenChar(azData[i]);
23053 oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
23054 oputz(i==nColumn-1?" |\n":" | ");
 
23055 }
23056 print_row_separator(p, nColumn, "|");
23057 break;
23058 }
23059 case MODE_Box: {
23060 colSep = " " BOX_13 " ";
23061 rowSep = " " BOX_13 "\n";
23062 print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
23063 oputz(BOX_13 " ");
23064 for(i=0; i<nColumn; i++){
23065 w = p->actualWidth[i];
23066 n = strlenChar(azData[i]);
23067 oputf("%*s%s%*s%s",
23068 (w-n)/2, "", azData[i], (w-n+1)/2, "",
23069 i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
23070 }
23071 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
23072 break;
23073 }
23074 }
23075 for(i=nColumn, j=0; i<nTotal; i++, j++){
23076 if( j==0 && p->cMode!=MODE_Column ){
23077 oputz(p->cMode==MODE_Box?BOX_13" ":"| ");
23078 }
23079 z = azData[i];
23080 if( z==0 ) z = p->nullValue;
23081 w = p->actualWidth[j];
23082 if( p->colWidth[j]<0 ) w = -w;
23083 utf8_width_print(w, z);
23084 if( j==nColumn-1 ){
23085 oputz(rowSep);
23086 if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
23087 if( p->cMode==MODE_Table ){
23088 print_row_separator(p, nColumn, "+");
23089 }else if( p->cMode==MODE_Box ){
23090 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
23091 }else if( p->cMode==MODE_Column ){
23092 oputz("\n");
23093 }
23094 }
23095 j = -1;
23096 if( seenInterrupt ) goto columnar_end;
23097 }else{
23098 oputz(colSep);
23099 }
23100 }
23101 if( p->cMode==MODE_Table ){
23102 print_row_separator(p, nColumn, "+");
23103 }else if( p->cMode==MODE_Box ){
23104 print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
23105 }
23106 columnar_end:
23107 if( seenInterrupt ){
23108 oputz("Interrupt\n");
23109 }
23110 nData = (nRow+1)*nColumn;
23111 for(i=0; i<nData; i++){
23112 z = azData[i];
23113 if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
@@ -23190,11 +24421,13 @@
23190 }
23191 }
23192 } while( SQLITE_ROW == rc );
23193 sqlite3_free(pData);
23194 if( pArg->cMode==MODE_Json ){
23195 fputs("]\n", pArg->out);
 
 
23196 }else if( pArg->cMode==MODE_Count ){
23197 char zBuf[200];
23198 sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
23199 nRow, nRow!=1 ? "s" : "");
23200 printf("%s", zBuf);
@@ -23239,10 +24472,11 @@
23239 int bCancel,
23240 char **pzErr
23241 ){
23242 int rc = SQLITE_OK;
23243 sqlite3expert *p = pState->expert.pExpert;
 
23244 assert( p );
23245 assert( bCancel || pzErr==0 || *pzErr==0 );
23246 if( bCancel==0 ){
23247 int bVerbose = pState->expert.bVerbose;
23248
@@ -23251,24 +24485,25 @@
23251 int nQuery = sqlite3_expert_count(p);
23252 int i;
23253
23254 if( bVerbose ){
23255 const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
23256 oputz("-- Candidates -----------------------------\n");
23257 oputf("%s\n", zCand);
23258 }
23259 for(i=0; i<nQuery; i++){
23260 const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
23261 const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
23262 const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
23263 if( zIdx==0 ) zIdx = "(no new indexes)\n";
23264 if( bVerbose ){
23265 oputf("-- Query %d --------------------------------\n",i+1);
23266 oputf("%s\n\n", zSql);
 
 
23267 }
23268 oputf("%s\n", zIdx);
23269 oputf("%s\n", zEQP);
23270 }
23271 }
23272 }
23273 sqlite3_expert_destroy(p);
23274 pState->expert.pExpert = 0;
@@ -23299,30 +24534,31 @@
23299 if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){
23300 pState->expert.bVerbose = 1;
23301 }
23302 else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
23303 if( i==(nArg-1) ){
23304 eputf("option requires an argument: %s\n", z);
23305 rc = SQLITE_ERROR;
23306 }else{
23307 iSample = (int)integerValue(azArg[++i]);
23308 if( iSample<0 || iSample>100 ){
23309 eputf("value out of range: %s\n", azArg[i]);
23310 rc = SQLITE_ERROR;
23311 }
23312 }
23313 }
23314 else{
23315 eputf("unknown option: %s\n", z);
23316 rc = SQLITE_ERROR;
23317 }
23318 }
23319
23320 if( rc==SQLITE_OK ){
23321 pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
23322 if( pState->expert.pExpert==0 ){
23323 eputf("sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
 
23324 rc = SQLITE_ERROR;
23325 }else{
23326 sqlite3_expert_config(
23327 pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
23328 );
@@ -23647,33 +24883,33 @@
23647 if( zType==0 ) return 0;
23648 dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
23649 noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
23650
23651 if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
23652 if( !dataOnly ) oputz("DELETE FROM sqlite_sequence;\n");
23653 }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
23654 if( !dataOnly ) oputz("ANALYZE sqlite_schema;\n");
23655 }else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
23656 return 0;
23657 }else if( dataOnly ){
23658 /* no-op */
23659 }else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
23660 char *zIns;
23661 if( !p->writableSchema ){
23662 oputz("PRAGMA writable_schema=ON;\n");
23663 p->writableSchema = 1;
23664 }
23665 zIns = sqlite3_mprintf(
23666 "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
23667 "VALUES('table','%q','%q',0,'%q');",
23668 zTable, zTable, zSql);
23669 shell_check_oom(zIns);
23670 oputf("%s\n", zIns);
23671 sqlite3_free(zIns);
23672 return 0;
23673 }else{
23674 printSchemaLine(zSql, ";\n");
23675 }
23676
23677 if( cli_strcmp(zType, "table")==0 ){
23678 ShellText sSelect;
23679 ShellText sTable;
@@ -23727,11 +24963,11 @@
23727 savedMode = p->mode;
23728 p->zDestTable = sTable.z;
23729 p->mode = p->cMode = MODE_Insert;
23730 rc = shell_exec(p, sSelect.z, 0);
23731 if( (rc&0xff)==SQLITE_CORRUPT ){
23732 oputz("/****** CORRUPTION ERROR *******/\n");
23733 toggleSelectOrder(p->db);
23734 shell_exec(p, sSelect.z, 0);
23735 toggleSelectOrder(p->db);
23736 }
23737 p->zDestTable = savedDestTable;
@@ -23758,28 +24994,28 @@
23758 char *zErr = 0;
23759 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
23760 if( rc==SQLITE_CORRUPT ){
23761 char *zQ2;
23762 int len = strlen30(zQuery);
23763 oputz("/****** CORRUPTION ERROR *******/\n");
23764 if( zErr ){
23765 oputf("/****** %s ******/\n", zErr);
23766 sqlite3_free(zErr);
23767 zErr = 0;
23768 }
23769 zQ2 = malloc( len+100 );
23770 if( zQ2==0 ) return rc;
23771 sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
23772 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
23773 if( rc ){
23774 oputf("/****** ERROR: %s ******/\n", zErr);
23775 }else{
23776 rc = SQLITE_CORRUPT;
23777 }
23778 sqlite3_free(zErr);
23779 free(zQ2);
23780 }
 
23781 return rc;
23782 }
23783
23784 /*
23785 ** Text of help messages.
@@ -23832,18 +25068,17 @@
23832 #ifndef SQLITE_SHELL_FIDDLE
23833 ".check GLOB Fail if output since .testcase does not match",
23834 ".clone NEWDB Clone data into NEWDB from the existing database",
23835 #endif
23836 ".connection [close] [#] Open or close an auxiliary database connection",
23837 #if defined(_WIN32) || defined(WIN32)
23838 ".crnl on|off Translate \\n to \\r\\n. Default ON",
23839 #endif
23840 ".databases List names and files of attached databases",
23841 ".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
23842 #if SQLITE_SHELL_HAVE_RECOVER
23843 ".dbinfo ?DB? Show status information about the database",
23844 #endif
 
23845 ".dump ?OBJECTS? Render database content as SQL",
23846 " Options:",
23847 " --data-only Output only INSERT statements",
23848 " --newlines Allow unescaped newline characters in output",
23849 " --nosys Omit system tables (ex: \"sqlite_stat1\")",
@@ -23940,13 +25175,15 @@
23940 #endif
23941 ".nullvalue STRING Use STRING in place of NULL values",
23942 #ifndef SQLITE_SHELL_FIDDLE
23943 ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
23944 " If FILE begins with '|' then open as a pipe",
23945 " --bom Put a UTF8 byte-order mark at the beginning",
23946 " -e Send output to the system text editor",
23947 " -x Send output as CSV to a spreadsheet (same as \".excel\")",
 
 
23948 /* Note that .open is (partially) available in WASM builds but is
23949 ** currently only intended to be used by the fiddle tool, not
23950 ** end users, so is "undocumented." */
23951 ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
23952 " Options:",
@@ -23965,10 +25202,12 @@
23965 ".output ?FILE? Send output to FILE or stdout if FILE is omitted",
23966 " If FILE begins with '|' then open it as a pipe.",
23967 " Options:",
23968 " --bom Prefix output with a UTF8 byte-order mark",
23969 " -e Send output to the system text editor",
 
 
23970 " -x Send output as CSV to a spreadsheet",
23971 #endif
23972 ".parameter CMD ... Manage SQL parameter bindings",
23973 " clear Erase all bindings",
23974 " init Initialize the TEMP table that holds bindings",
@@ -24078,10 +25317,14 @@
24078 ".vfsinfo ?AUX? Information about the top-level VFS",
24079 ".vfslist List all available VFSes",
24080 ".vfsname ?AUX? Print the name of the VFS stack",
24081 ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
24082 " Negative values right-justify",
 
 
 
 
24083 };
24084
24085 /*
24086 ** Output help text.
24087 **
@@ -24126,24 +25369,24 @@
24126 hh &= ~HH_Summary;
24127 break;
24128 }
24129 if( ((hw^hh)&HH_Undoc)==0 ){
24130 if( (hh&HH_Summary)!=0 ){
24131 sputf(out, ".%s\n", azHelp[i]+1);
24132 ++n;
24133 }else if( (hw&HW_SummaryOnly)==0 ){
24134 sputf(out, "%s\n", azHelp[i]);
24135 }
24136 }
24137 }
24138 }else{
24139 /* Seek documented commands for which zPattern is an exact prefix */
24140 zPat = sqlite3_mprintf(".%s*", zPattern);
24141 shell_check_oom(zPat);
24142 for(i=0; i<ArraySize(azHelp); i++){
24143 if( sqlite3_strglob(zPat, azHelp[i])==0 ){
24144 sputf(out, "%s\n", azHelp[i]);
24145 j = i+1;
24146 n++;
24147 }
24148 }
24149 sqlite3_free(zPat);
@@ -24150,11 +25393,11 @@
24150 if( n ){
24151 if( n==1 ){
24152 /* when zPattern is a prefix of exactly one command, then include
24153 ** the details of that command, which should begin at offset j */
24154 while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
24155 sputf(out, "%s\n", azHelp[j]);
24156 j++;
24157 }
24158 }
24159 return n;
24160 }
@@ -24167,14 +25410,14 @@
24167 while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
24168 continue;
24169 }
24170 if( azHelp[i][0]=='.' ) j = i;
24171 if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
24172 sputf(out, "%s\n", azHelp[j]);
24173 while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
24174 j++;
24175 sputf(out, "%s\n", azHelp[j]);
24176 }
24177 i = j;
24178 n++;
24179 }
24180 }
@@ -24200,35 +25443,35 @@
24200 **
24201 ** NULL is returned if any error is encountered. The final value of *pnByte
24202 ** is undefined in this case.
24203 */
24204 static char *readFile(const char *zName, int *pnByte){
24205 FILE *in = fopen(zName, "rb");
24206 long nIn;
24207 size_t nRead;
24208 char *pBuf;
24209 int rc;
24210 if( in==0 ) return 0;
24211 rc = fseek(in, 0, SEEK_END);
24212 if( rc!=0 ){
24213 eputf("Error: '%s' not seekable\n", zName);
24214 fclose(in);
24215 return 0;
24216 }
24217 nIn = ftell(in);
24218 rewind(in);
24219 pBuf = sqlite3_malloc64( nIn+1 );
24220 if( pBuf==0 ){
24221 eputz("Error: out of memory\n");
24222 fclose(in);
24223 return 0;
24224 }
24225 nRead = fread(pBuf, nIn, 1, in);
24226 fclose(in);
24227 if( nRead!=1 ){
24228 sqlite3_free(pBuf);
24229 eputf("Error: cannot read '%s'\n", zName);
24230 return 0;
24231 }
24232 pBuf[nIn] = 0;
24233 if( pnByte ) *pnByte = nIn;
24234 return pBuf;
@@ -24290,11 +25533,11 @@
24290 ** archive and the dfltZip flag is true, then assume it is a ZIP archive.
24291 ** Otherwise, assume an ordinary database regardless of the filename if
24292 ** the type cannot be determined from content.
24293 */
24294 int deduceDatabaseType(const char *zName, int dfltZip){
24295 FILE *f = fopen(zName, "rb");
24296 size_t n;
24297 int rc = SHELL_OPEN_UNSPEC;
24298 char zBuf[100];
24299 if( f==0 ){
24300 if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
@@ -24343,13 +25586,13 @@
24343 FILE *in;
24344 const char *zDbFilename = p->pAuxDb->zDbFilename;
24345 unsigned int x[16];
24346 char zLine[1000];
24347 if( zDbFilename ){
24348 in = fopen(zDbFilename, "r");
24349 if( in==0 ){
24350 eputf("cannot open \"%s\" for reading\n", zDbFilename);
24351 return 0;
24352 }
24353 nLine = 0;
24354 }else{
24355 in = p->in;
@@ -24356,24 +25599,24 @@
24356 nLine = p->lineno;
24357 if( in==0 ) in = stdin;
24358 }
24359 *pnData = 0;
24360 nLine++;
24361 if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
24362 rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
24363 if( rc!=2 ) goto readHexDb_error;
24364 if( n<0 ) goto readHexDb_error;
24365 if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
24366 n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
24367 a = sqlite3_malloc( n ? n : 1 );
24368 shell_check_oom(a);
24369 memset(a, 0, n);
24370 if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
24371 eputz("invalid pagesize\n");
24372 goto readHexDb_error;
24373 }
24374 for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
24375 rc = sscanf(zLine, "| page %d offset %d", &j, &k);
24376 if( rc==2 ){
24377 iOffset = k;
24378 continue;
24379 }
@@ -24401,18 +25644,18 @@
24401
24402 readHexDb_error:
24403 if( in!=p->in ){
24404 fclose(in);
24405 }else{
24406 while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
24407 nLine++;
24408 if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
24409 }
24410 p->lineno = nLine;
24411 }
24412 sqlite3_free(a);
24413 eputf("Error on line %d of --hexdb input\n", nLine);
24414 return 0;
24415 }
24416 #endif /* SQLITE_OMIT_DESERIALIZE */
24417
24418 /*
@@ -24483,22 +25726,24 @@
24483 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
24484 break;
24485 }
24486 }
24487 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
24488 eputf("Error: unable to open database \"%s\": %s\n",
24489 zDbFilename, sqlite3_errmsg(p->db));
24490 if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
24491 exit(1);
24492 }
24493 sqlite3_close(p->db);
24494 sqlite3_open(":memory:", &p->db);
24495 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
24496 eputz("Also: unable to open substitute in-memory database.\n");
 
24497 exit(1);
24498 }else{
24499 eputf("Notice: using substitute in-memory database instead of \"%s\"\n",
 
24500 zDbFilename);
24501 }
24502 }
24503 globalDb = p->db;
24504 sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
@@ -24511,10 +25756,11 @@
24511 }
24512
24513 #ifndef SQLITE_OMIT_LOAD_EXTENSION
24514 sqlite3_enable_load_extension(p->db, 1);
24515 #endif
 
24516 sqlite3_shathree_init(p->db, 0, 0);
24517 sqlite3_uint_init(p->db, 0, 0);
24518 sqlite3_stmtrand_init(p->db, 0, 0);
24519 sqlite3_decimal_init(p->db, 0, 0);
24520 sqlite3_percentile_init(p->db, 0, 0);
@@ -24605,11 +25851,11 @@
24605 }
24606 rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
24607 SQLITE_DESERIALIZE_RESIZEABLE |
24608 SQLITE_DESERIALIZE_FREEONCLOSE);
24609 if( rc ){
24610 eputf("Error: sqlite3_deserialize() returns %d\n", rc);
24611 }
24612 if( p->szMax>0 ){
24613 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
24614 }
24615 }
@@ -24629,15 +25875,17 @@
24629 ** Attempt to close the database connection. Report errors.
24630 */
24631 void close_db(sqlite3 *db){
24632 int rc = sqlite3_close(db);
24633 if( rc ){
24634 eputf("Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
 
24635 }
24636 }
24637
24638 #if HAVE_READLINE || HAVE_EDITLINE
 
24639 /*
24640 ** Readline completion callbacks
24641 */
24642 static char *readline_completion_generator(const char *text, int state){
24643 static sqlite3_stmt *pStmt = 0;
@@ -24671,19 +25919,26 @@
24671 #elif HAVE_LINENOISE
24672 /*
24673 ** Linenoise completion callback. Note that the 3rd argument is from
24674 ** the "msteveb" version of linenoise, not the "antirez" version.
24675 */
24676 static void linenoise_completion(const char *zLine, linenoiseCompletions *lc,
24677 void *pUserData){
 
 
 
 
 
24678 i64 nLine = strlen(zLine);
24679 i64 i, iStart;
24680 sqlite3_stmt *pStmt = 0;
24681 char *zSql;
24682 char zBuf[1000];
24683
 
24684 UNUSED_PARAMETER(pUserData);
 
24685 if( nLine>(i64)sizeof(zBuf)-30 ) return;
24686 if( zLine[0]=='.' || zLine[0]=='#') return;
24687 for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
24688 if( i==nLine-1 ) return;
24689 iStart = i+1;
@@ -24793,11 +26048,12 @@
24793 return 1;
24794 }
24795 if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
24796 return 0;
24797 }
24798 eputf("ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
 
24799 return 0;
24800 }
24801
24802 /*
24803 ** Set or clear a shell flag according to a boolean value.
@@ -24820,22 +26076,22 @@
24820 /*
24821 ** Try to open an output file. The names "stdout" and "stderr" are
24822 ** recognized and do the right thing. NULL is returned if the output
24823 ** filename is "off".
24824 */
24825 static FILE *output_file_open(const char *zFile, int bTextMode){
24826 FILE *f;
24827 if( cli_strcmp(zFile,"stdout")==0 ){
24828 f = stdout;
24829 }else if( cli_strcmp(zFile, "stderr")==0 ){
24830 f = stderr;
24831 }else if( cli_strcmp(zFile, "off")==0 ){
24832 f = 0;
24833 }else{
24834 f = fopen(zFile, bTextMode ? "w" : "wb");
24835 if( f==0 ){
24836 eputf("Error: cannot open \"%s\"\n", zFile);
24837 }
24838 }
24839 return f;
24840 }
24841
@@ -24884,16 +26140,17 @@
24884 if( nSql>1000000000 ) nSql = 1000000000;
24885 while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
24886 switch( mType ){
24887 case SQLITE_TRACE_ROW:
24888 case SQLITE_TRACE_STMT: {
24889 sputf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
24890 break;
24891 }
24892 case SQLITE_TRACE_PROFILE: {
24893 sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
24894 sputf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
 
24895 break;
24896 }
24897 }
24898 return 0;
24899 }
@@ -24996,14 +26253,15 @@
24996 do{ p->n--; }while( p->z[p->n]!=cQuote );
24997 p->cTerm = c;
24998 break;
24999 }
25000 if( pc==cQuote && c!='\r' ){
25001 eputf("%s:%d: unescaped %c character\n", p->zFile, p->nLine, cQuote);
 
25002 }
25003 if( c==EOF ){
25004 eputf("%s:%d: unterminated %c-quoted field\n",
25005 p->zFile, startLine, cQuote);
25006 p->cTerm = c;
25007 break;
25008 }
25009 import_append_char(p, c);
@@ -25098,11 +26356,11 @@
25098
25099 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
25100 shell_check_oom(zQuery);
25101 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
25102 if( rc ){
25103 eputf("Error %d: %s on [%s]\n",
25104 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
25105 goto end_data_xfer;
25106 }
25107 n = sqlite3_column_count(pQuery);
25108 zInsert = sqlite3_malloc64(200 + nTable + n*3);
@@ -25115,11 +26373,11 @@
25115 i += 2;
25116 }
25117 memcpy(zInsert+i, ");", 3);
25118 rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
25119 if( rc ){
25120 eputf("Error %d: %s on [%s]\n",
25121 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), zInsert);
25122 goto end_data_xfer;
25123 }
25124 for(k=0; k<2; k++){
25125 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
@@ -25151,11 +26409,11 @@
25151 }
25152 }
25153 } /* End for */
25154 rc = sqlite3_step(pInsert);
25155 if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
25156 eputf("Error %d: %s\n",
25157 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb));
25158 }
25159 sqlite3_reset(pInsert);
25160 cnt++;
25161 if( (cnt%spinRate)==0 ){
@@ -25169,11 +26427,11 @@
25169 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
25170 zTable);
25171 shell_check_oom(zQuery);
25172 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
25173 if( rc ){
25174 eputf("Warning: cannot step \"%s\" backwards", zTable);
25175 break;
25176 }
25177 } /* End for(k=0...) */
25178
25179 end_data_xfer:
@@ -25206,23 +26464,24 @@
25206 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
25207 " WHERE %s ORDER BY rowid ASC", zWhere);
25208 shell_check_oom(zQuery);
25209 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
25210 if( rc ){
25211 eputf("Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
 
25212 sqlite3_errmsg(p->db), zQuery);
25213 goto end_schema_xfer;
25214 }
25215 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
25216 zName = sqlite3_column_text(pQuery, 0);
25217 zSql = sqlite3_column_text(pQuery, 1);
25218 if( zName==0 || zSql==0 ) continue;
25219 if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ){
25220 sputf(stdout, "%s... ", zName); fflush(stdout);
25221 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
25222 if( zErrMsg ){
25223 eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
25224 sqlite3_free(zErrMsg);
25225 zErrMsg = 0;
25226 }
25227 }
25228 if( xForEach ){
@@ -25236,23 +26495,23 @@
25236 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
25237 " WHERE %s ORDER BY rowid DESC", zWhere);
25238 shell_check_oom(zQuery);
25239 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
25240 if( rc ){
25241 eputf("Error: (%d) %s on [%s]\n",
25242 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
25243 goto end_schema_xfer;
25244 }
25245 while( sqlite3_step(pQuery)==SQLITE_ROW ){
25246 zName = sqlite3_column_text(pQuery, 0);
25247 zSql = sqlite3_column_text(pQuery, 1);
25248 if( zName==0 || zSql==0 ) continue;
25249 if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue;
25250 sputf(stdout, "%s... ", zName); fflush(stdout);
25251 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
25252 if( zErrMsg ){
25253 eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
25254 sqlite3_free(zErrMsg);
25255 zErrMsg = 0;
25256 }
25257 if( xForEach ){
25258 xForEach(p, newDb, (const char*)zName);
@@ -25272,16 +26531,17 @@
25272 */
25273 static void tryToClone(ShellState *p, const char *zNewDb){
25274 int rc;
25275 sqlite3 *newDb = 0;
25276 if( access(zNewDb,0)==0 ){
25277 eputf("File \"%s\" already exists.\n", zNewDb);
25278 return;
25279 }
25280 rc = sqlite3_open(zNewDb, &newDb);
25281 if( rc ){
25282 eputf("Cannot create output database: %s\n", sqlite3_errmsg(newDb));
 
25283 }else{
25284 sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
25285 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
25286 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
25287 tryToCloneSchema(p, newDb, "type!='table'", 0);
@@ -25294,14 +26554,22 @@
25294 #ifndef SQLITE_SHELL_FIDDLE
25295 /*
25296 ** Change the output stream (file or pipe or console) to something else.
25297 */
25298 static void output_redir(ShellState *p, FILE *pfNew){
25299 if( p->out != stdout ) eputz("Output already redirected.\n");
25300 else{
 
25301 p->out = pfNew;
25302 setOutputStream(pfNew);
 
 
 
 
 
 
 
25303 }
25304 }
25305
25306 /*
25307 ** Change the output file back to stdout.
@@ -25314,10 +26582,13 @@
25314 if( p->outfile[0]=='|' ){
25315 #ifndef SQLITE_OMIT_POPEN
25316 pclose(p->out);
25317 #endif
25318 }else{
 
 
 
25319 output_file_close(p->out);
25320 #ifndef SQLITE_NOHAVE_SYSTEM
25321 if( p->doXdgOpen ){
25322 const char *zXdgOpenCmd =
25323 #if defined(_WIN32)
@@ -25328,11 +26599,11 @@
25328 "xdg-open";
25329 #endif
25330 char *zCmd;
25331 zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
25332 if( system(zCmd) ){
25333 eputf("Failed: [%s]\n", zCmd);
25334 }else{
25335 /* Give the start/open/xdg-open command some time to get
25336 ** going before we continue, and potential delete the
25337 ** p->zTempFile data file out from under it */
25338 sqlite3_sleep(2000);
@@ -25343,28 +26614,34 @@
25343 }
25344 #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
25345 }
25346 p->outfile[0] = 0;
25347 p->out = stdout;
25348 setOutputStream(stdout);
25349 }
25350 #else
25351 # define output_redir(SS,pfO)
25352 # define output_reset(SS)
25353 #endif
25354
25355 /*
25356 ** Run an SQL command and return the single integer result.
25357 */
25358 static int db_int(sqlite3 *db, const char *zSql){
25359 sqlite3_stmt *pStmt;
25360 int res = 0;
25361 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
 
 
 
 
 
25362 if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
25363 res = sqlite3_column_int(pStmt,0);
25364 }
25365 sqlite3_finalize(pStmt);
 
25366 return res;
25367 }
25368
25369 #if SQLITE_SHELL_HAVE_RECOVER
25370 /*
@@ -25419,11 +26696,11 @@
25419 if( p->db==0 ) return 1;
25420 rc = sqlite3_prepare_v2(p->db,
25421 "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
25422 -1, &pStmt, 0);
25423 if( rc ){
25424 eputf("error: %s\n", sqlite3_errmsg(p->db));
25425 sqlite3_finalize(pStmt);
25426 return 1;
25427 }
25428 sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
25429 if( sqlite3_step(pStmt)==SQLITE_ROW
@@ -25432,58 +26709,149 @@
25432 const u8 *pb = sqlite3_column_blob(pStmt,0);
25433 shell_check_oom(pb);
25434 memcpy(aHdr, pb, 100);
25435 sqlite3_finalize(pStmt);
25436 }else{
25437 eputz("unable to read database header\n");
25438 sqlite3_finalize(pStmt);
25439 return 1;
25440 }
25441 i = get2byteInt(aHdr+16);
25442 if( i==1 ) i = 65536;
25443 oputf("%-20s %d\n", "database page size:", i);
25444 oputf("%-20s %d\n", "write format:", aHdr[18]);
25445 oputf("%-20s %d\n", "read format:", aHdr[19]);
25446 oputf("%-20s %d\n", "reserved bytes:", aHdr[20]);
25447 for(i=0; i<ArraySize(aField); i++){
25448 int ofst = aField[i].ofst;
25449 unsigned int val = get4byteInt(aHdr + ofst);
25450 oputf("%-20s %u", aField[i].zName, val);
25451 switch( ofst ){
25452 case 56: {
25453 if( val==1 ) oputz(" (utf8)");
25454 if( val==2 ) oputz(" (utf16le)");
25455 if( val==3 ) oputz(" (utf16be)");
25456 }
25457 }
25458 oputz("\n");
25459 }
25460 if( zDb==0 ){
25461 zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
25462 }else if( cli_strcmp(zDb,"temp")==0 ){
25463 zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
25464 }else{
25465 zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
25466 }
25467 for(i=0; i<ArraySize(aQuery); i++){
25468 char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
25469 int val = db_int(p->db, zSql);
25470 sqlite3_free(zSql);
25471 oputf("%-20s %d\n", aQuery[i].zName, val);
25472 }
25473 sqlite3_free(zSchemaTab);
25474 sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
25475 oputf("%-20s %u\n", "data version", iDataVersion);
25476 return 0;
25477 }
25478 #endif /* SQLITE_SHELL_HAVE_RECOVER */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25479
25480 /*
25481 ** Print the given string as an error message.
25482 */
25483 static void shellEmitError(const char *zErr){
25484 eputf("Error: %s\n", zErr);
25485 }
25486 /*
25487 ** Print the current sqlite3_errmsg() value to stderr and return 1.
25488 */
25489 static int shellDatabaseError(sqlite3 *db){
@@ -25726,10 +27094,11 @@
25726 int bGroupByParent = 0; /* If -groupbyparent is present */
25727 int i; /* To iterate through azArg[] */
25728 const char *zIndent = ""; /* How much to indent CREATE INDEX by */
25729 int rc; /* Return code */
25730 sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
 
25731
25732 /*
25733 ** This SELECT statement returns one row for each foreign key constraint
25734 ** in the schema of the main database. The column values are:
25735 **
@@ -25801,11 +27170,12 @@
25801 else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
25802 bGroupByParent = 1;
25803 zIndent = " ";
25804 }
25805 else{
25806 eputf("Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
 
25807 return SQLITE_ERROR;
25808 }
25809 }
25810
25811 /* Register the fkey_collate_clause() SQL function */
@@ -25845,44 +27215,45 @@
25845 }
25846 rc = sqlite3_finalize(pExplain);
25847 if( rc!=SQLITE_OK ) break;
25848
25849 if( res<0 ){
25850 eputz("Error: internal error");
25851 break;
25852 }else{
25853 if( bGroupByParent
25854 && (bVerbose || res==0)
25855 && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
25856 ){
25857 oputf("-- Parent table %s\n", zParent);
25858 sqlite3_free(zPrev);
25859 zPrev = sqlite3_mprintf("%s", zParent);
25860 }
25861
25862 if( res==0 ){
25863 oputf("%s%s --> %s\n", zIndent, zCI, zTarget);
25864 }else if( bVerbose ){
25865 oputf("%s/* no extra indexes required for %s -> %s */\n",
 
25866 zIndent, zFrom, zTarget
25867 );
25868 }
25869 }
25870 }
25871 sqlite3_free(zPrev);
25872
25873 if( rc!=SQLITE_OK ){
25874 eputf("%s\n", sqlite3_errmsg(db));
25875 }
25876
25877 rc2 = sqlite3_finalize(pSql);
25878 if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
25879 rc = rc2;
25880 eputf("%s\n", sqlite3_errmsg(db));
25881 }
25882 }else{
25883 eputf("%s\n", sqlite3_errmsg(db));
25884 }
25885
25886 return rc;
25887 }
25888
@@ -25898,13 +27269,13 @@
25898 n = (nArg>=2 ? strlen30(azArg[1]) : 0);
25899 if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
25900 return lintFkeyIndexes(pState, azArg, nArg);
25901
25902 usage:
25903 eputf("Usage %s sub-command ?switches...?\n", azArg[0]);
25904 eputz("Where sub-commands are:\n");
25905 eputz(" fkey-indexes\n");
25906 return SQLITE_ERROR;
25907 }
25908
25909 static void shellPrepare(
25910 sqlite3 *db,
@@ -25914,11 +27285,12 @@
25914 ){
25915 *ppStmt = 0;
25916 if( *pRc==SQLITE_OK ){
25917 int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
25918 if( rc!=SQLITE_OK ){
25919 eputf("sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
 
25920 *pRc = rc;
25921 }
25922 }
25923 }
25924
@@ -25958,11 +27330,11 @@
25958 if( pStmt ){
25959 sqlite3 *db = sqlite3_db_handle(pStmt);
25960 int rc = sqlite3_finalize(pStmt);
25961 if( *pRc==SQLITE_OK ){
25962 if( rc!=SQLITE_OK ){
25963 eputf("SQL error: %s\n", sqlite3_errmsg(db));
25964 }
25965 *pRc = rc;
25966 }
25967 }
25968 }
@@ -25980,11 +27352,11 @@
25980 ){
25981 int rc = sqlite3_reset(pStmt);
25982 if( *pRc==SQLITE_OK ){
25983 if( rc!=SQLITE_OK ){
25984 sqlite3 *db = sqlite3_db_handle(pStmt);
25985 eputf("SQL error: %s\n", sqlite3_errmsg(db));
25986 }
25987 *pRc = rc;
25988 }
25989 }
25990 #endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
@@ -26009,10 +27381,11 @@
26009 char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
26010 const char *zFile; /* --file argument, or NULL */
26011 const char *zDir; /* --directory argument, or NULL */
26012 char **azArg; /* Array of command arguments */
26013 ShellState *p; /* Shell state */
 
26014 sqlite3 *db; /* Database containing the archive */
26015 };
26016
26017 /*
26018 ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
@@ -26032,13 +27405,13 @@
26032 va_start(ap, zFmt);
26033 z = sqlite3_vmprintf(zFmt, ap);
26034 va_end(ap);
26035 shellEmitError(z);
26036 if( pAr->fromCmdLine ){
26037 eputz("Use \"-A\" for more help\n");
26038 }else{
26039 eputz("Use \".archive --help\" for more help\n");
26040 }
26041 sqlite3_free(z);
26042 return SQLITE_ERROR;
26043 }
26044
@@ -26134,11 +27507,11 @@
26134 };
26135 int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
26136 struct ArSwitch *pEnd = &aSwitch[nSwitch];
26137
26138 if( nArg<=1 ){
26139 eputz("Wrong number of arguments. Usage:\n");
26140 return arUsage(stderr);
26141 }else{
26142 char *z = azArg[1];
26143 if( z[0]!='-' ){
26144 /* Traditional style [tar] invocation */
@@ -26240,11 +27613,11 @@
26240 }
26241 }
26242 }
26243 }
26244 if( pAr->eCmd==0 ){
26245 eputz("Required argument missing. Usage:\n");
26246 return arUsage(stderr);
26247 }
26248 return SQLITE_OK;
26249 }
26250
@@ -26283,11 +27656,11 @@
26283 if( SQLITE_ROW==sqlite3_step(pTest) ){
26284 bOk = 1;
26285 }
26286 shellReset(&rc, pTest);
26287 if( rc==SQLITE_OK && bOk==0 ){
26288 eputf("not found in archive: %s\n", z);
26289 rc = SQLITE_ERROR;
26290 }
26291 }
26292 shellFinalize(&rc, pTest);
26293 }
@@ -26350,19 +27723,19 @@
26350 arWhereClause(&rc, pAr, &zWhere);
26351
26352 shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
26353 pAr->zSrcTable, zWhere);
26354 if( pAr->bDryRun ){
26355 oputf("%s\n", sqlite3_sql(pSql));
26356 }else{
26357 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
26358 if( pAr->bVerbose ){
26359 oputf("%s % 10d %s %s\n",
26360 sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1),
26361 sqlite3_column_text(pSql, 2),sqlite3_column_text(pSql, 3));
26362 }else{
26363 oputf("%s\n", sqlite3_column_text(pSql, 0));
26364 }
26365 }
26366 }
26367 shellFinalize(&rc, pSql);
26368 sqlite3_free(zWhere);
@@ -26385,11 +27758,11 @@
26385 }
26386 if( rc==SQLITE_OK ){
26387 zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
26388 pAr->zSrcTable, zWhere);
26389 if( pAr->bDryRun ){
26390 oputf("%s\n", zSql);
26391 }else{
26392 char *zErr = 0;
26393 rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
26394 if( rc==SQLITE_OK ){
26395 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
@@ -26398,11 +27771,11 @@
26398 }else{
26399 rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0);
26400 }
26401 }
26402 if( zErr ){
26403 sputf(stdout, "ERROR: %s\n", zErr); /* stdout? */
26404 sqlite3_free(zErr);
26405 }
26406 }
26407 }
26408 sqlite3_free(zWhere);
@@ -26462,15 +27835,15 @@
26462 ** populating them changes the timestamp). */
26463 for(i=0; i<2; i++){
26464 j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
26465 sqlite3_bind_int(pSql, j, i);
26466 if( pAr->bDryRun ){
26467 oputf("%s\n", sqlite3_sql(pSql));
26468 }else{
26469 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
26470 if( i==0 && pAr->bVerbose ){
26471 oputf("%s\n", sqlite3_column_text(pSql, 0));
26472 }
26473 }
26474 }
26475 shellReset(&rc, pSql);
26476 }
@@ -26486,17 +27859,17 @@
26486 ** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out.
26487 */
26488 static int arExecSql(ArCommand *pAr, const char *zSql){
26489 int rc;
26490 if( pAr->bDryRun ){
26491 oputf("%s\n", zSql);
26492 rc = SQLITE_OK;
26493 }else{
26494 char *zErr = 0;
26495 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
26496 if( zErr ){
26497 sputf(stdout, "ERROR: %s\n", zErr);
26498 sqlite3_free(zErr);
26499 }
26500 }
26501 return rc;
26502 }
@@ -26641,10 +28014,11 @@
26641 cmd.fromCmdLine = fromCmdLine;
26642 rc = arParseCommand(azArg, nArg, &cmd);
26643 if( rc==SQLITE_OK ){
26644 int eDbType = SHELL_OPEN_UNSPEC;
26645 cmd.p = pState;
 
26646 cmd.db = pState->db;
26647 if( cmd.zFile ){
26648 eDbType = deduceDatabaseType(cmd.zFile, 1);
26649 }else{
26650 eDbType = pState->openMode;
@@ -26667,17 +28041,18 @@
26667 }else{
26668 flags = SQLITE_OPEN_READONLY;
26669 }
26670 cmd.db = 0;
26671 if( cmd.bDryRun ){
26672 oputf("-- open database '%s'%s\n", cmd.zFile,
26673 eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
26674 }
26675 rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
26676 eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
26677 if( rc!=SQLITE_OK ){
26678 eputf("cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db));
 
26679 goto end_ar_command;
26680 }
26681 sqlite3_fileio_init(cmd.db, 0, 0);
26682 sqlite3_sqlar_init(cmd.db, 0, 0);
26683 sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
@@ -26686,11 +28061,11 @@
26686 }
26687 if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
26688 if( cmd.eCmd!=AR_CMD_CREATE
26689 && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
26690 ){
26691 eputz("database does not contain an 'sqlar' table\n");
26692 rc = SQLITE_ERROR;
26693 goto end_ar_command;
26694 }
26695 cmd.zSrcTable = sqlite3_mprintf("sqlar");
26696 }
@@ -26744,11 +28119,11 @@
26744 ** This function is used as a callback by the recover extension. Simply
26745 ** print the supplied SQL statement to stdout.
26746 */
26747 static int recoverSqlCb(void *pCtx, const char *zSql){
26748 ShellState *pState = (ShellState*)pCtx;
26749 sputf(pState->out, "%s;\n", zSql);
26750 return SQLITE_OK;
26751 }
26752
26753 /*
26754 ** This function is called to recover data from the database. A script
@@ -26787,11 +28162,11 @@
26787 }else
26788 if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
26789 bRowids = 0;
26790 }
26791 else{
26792 eputf("unexpected option: %s\n", azArg[i]);
26793 showHelp(pState->out, azArg[0]);
26794 return 1;
26795 }
26796 }
26797
@@ -26806,11 +28181,11 @@
26806
26807 sqlite3_recover_run(p);
26808 if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
26809 const char *zErr = sqlite3_recover_errmsg(p);
26810 int errCode = sqlite3_recover_errcode(p);
26811 eputf("sql error: %s (%d)\n", zErr, errCode);
26812 }
26813 rc = sqlite3_recover_finish(p);
26814 return rc;
26815 }
26816 #endif /* SQLITE_SHELL_HAVE_RECOVER */
@@ -26828,25 +28203,25 @@
26828 i64 nError = 0;
26829 const char *zErr = 0;
26830 while( SQLITE_OK==sqlite3_intck_step(p) ){
26831 const char *zMsg = sqlite3_intck_message(p);
26832 if( zMsg ){
26833 oputf("%s\n", zMsg);
26834 nError++;
26835 }
26836 nStep++;
26837 if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){
26838 sqlite3_intck_unlock(p);
26839 }
26840 }
26841 rc = sqlite3_intck_error(p, &zErr);
26842 if( zErr ){
26843 eputf("%s\n", zErr);
26844 }
26845 sqlite3_intck_close(p);
26846
26847 oputf("%lld steps, %lld errors\n", nStep, nError);
26848 }
26849
26850 return rc;
26851 }
26852
@@ -26865,11 +28240,11 @@
26865 */
26866 #ifdef SHELL_DEBUG
26867 #define rc_err_oom_die(rc) \
26868 if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
26869 else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
26870 eputf("E:%d\n",rc), assert(0)
26871 #else
26872 static void rc_err_oom_die(int rc){
26873 if( rc==SQLITE_NOMEM ) shell_check_oom(0);
26874 assert(rc==SQLITE_OK||rc==SQLITE_DONE);
26875 }
@@ -27023,12 +28398,12 @@
27023 }else if( *pDb==0 ){
27024 return 0;
27025 }else{
27026 /* Formulate the columns spec, close the DB, zero *pDb. */
27027 char *zColsSpec = 0;
27028 int hasDupes = db_int(*pDb, zHasDupes);
27029 int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
27030 if( hasDupes ){
27031 #ifdef SHELL_COLUMN_RENAME_CLEAN
27032 rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
27033 rc_err_oom_die(rc);
27034 #endif
@@ -27039,11 +28414,11 @@
27039 sqlite3_bind_int(pStmt, 1, nDigits);
27040 rc = sqlite3_step(pStmt);
27041 sqlite3_finalize(pStmt);
27042 if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
27043 }
27044 assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
27045 rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
27046 rc_err_oom_die(rc);
27047 rc = sqlite3_step(pStmt);
27048 if( rc==SQLITE_ROW ){
27049 zColsSpec = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
@@ -27082,12 +28457,13 @@
27082 shellPreparePrintf(p->db, &rc, &pStmt,
27083 "SELECT 1 FROM sqlite_schema o WHERE "
27084 "sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true"
27085 );
27086 if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
27087 oputz("/* WARNING: "
27088 "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n"
 
27089 );
27090 }
27091 shellFinalize(&rc, pStmt);
27092 return rc;
27093 }
@@ -27114,16 +28490,18 @@
27114 return SQLITE_OK;
27115 }
27116 if( faultsim_state.iCnt ){
27117 if( faultsim_state.iCnt>0 ) faultsim_state.iCnt--;
27118 if( faultsim_state.eVerbose>=2 ){
27119 oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
 
27120 }
27121 return SQLITE_OK;
27122 }
27123 if( faultsim_state.eVerbose>=1 ){
27124 oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
 
27125 }
27126 faultsim_state.iCnt = faultsim_state.iInterval;
27127 faultsim_state.nHit++;
27128 if( faultsim_state.nRepeat>0 && faultsim_state.nRepeat<=faultsim_state.nHit ){
27129 faultsim_state.iCnt = -1;
@@ -27182,11 +28560,11 @@
27182 clearTempFile(p);
27183
27184 #ifndef SQLITE_OMIT_AUTHORIZATION
27185 if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
27186 if( nArg!=2 ){
27187 eputz("Usage: .auth ON|OFF\n");
27188 rc = 1;
27189 goto meta_command_exit;
27190 }
27191 open_db(p, 0);
27192 if( booleanValue(azArg[1]) ){
@@ -27229,32 +28607,32 @@
27229 }else
27230 if( cli_strcmp(z, "-async")==0 ){
27231 bAsync = 1;
27232 }else
27233 {
27234 eputf("unknown option: %s\n", azArg[j]);
27235 return 1;
27236 }
27237 }else if( zDestFile==0 ){
27238 zDestFile = azArg[j];
27239 }else if( zDb==0 ){
27240 zDb = zDestFile;
27241 zDestFile = azArg[j];
27242 }else{
27243 eputz("Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
27244 return 1;
27245 }
27246 }
27247 if( zDestFile==0 ){
27248 eputz("missing FILENAME argument on .backup\n");
27249 return 1;
27250 }
27251 if( zDb==0 ) zDb = "main";
27252 rc = sqlite3_open_v2(zDestFile, &pDest,
27253 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
27254 if( rc!=SQLITE_OK ){
27255 eputf("Error: cannot open \"%s\"\n", zDestFile);
27256 close_db(pDest);
27257 return 1;
27258 }
27259 if( bAsync ){
27260 sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
@@ -27286,23 +28664,14 @@
27286 eputz("Usage: .bail on|off\n");
27287 rc = 1;
27288 }
27289 }else
27290
27291 /* Undocumented. Legacy only. See "crnl" below */
27292 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
27293 if( nArg==2 ){
27294 if( booleanValue(azArg[1]) ){
27295 setBinaryMode(p->out, 1);
27296 }else{
27297 setTextMode(p->out, 1);
27298 }
27299 }else{
27300 eputz("The \".binary\" command is deprecated. Use \".crnl\" instead.\n"
27301 "Usage: .binary on|off\n");
27302 rc = 1;
27303 }
27304 }else
27305
27306 /* The undocumented ".breakpoint" command causes a call to the no-op
27307 ** routine named test_breakpoint().
27308 */
@@ -27320,11 +28689,11 @@
27320 sqlite3_free(z);
27321 #else
27322 rc = chdir(azArg[1]);
27323 #endif
27324 if( rc ){
27325 eputf("Cannot change to directory \"%s\"\n", azArg[1]);
27326 rc = 1;
27327 }
27328 }else{
27329 eputz("Usage: .cd DIRECTORY\n");
27330 rc = 1;
@@ -27353,15 +28722,16 @@
27353 eputz("Usage: .check GLOB-PATTERN\n");
27354 rc = 2;
27355 }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
27356 rc = 2;
27357 }else if( testcase_glob(azArg[1],zRes)==0 ){
27358 eputf("testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
 
27359 p->zTestcase, azArg[1], zRes);
27360 rc = 1;
27361 }else{
27362 oputf("testcase-%s ok\n", p->zTestcase);
27363 p->nCheck++;
27364 }
27365 sqlite3_free(zRes);
27366 }else
27367 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -27390,13 +28760,13 @@
27390 zFile = "(memory)";
27391 }else if( zFile[0]==0 ){
27392 zFile = "(temporary-file)";
27393 }
27394 if( p->pAuxDb == &p->aAuxDb[i] ){
27395 sputf(stdout, "ACTIVE %d: %s\n", i, zFile);
27396 }else if( p->aAuxDb[i].db!=0 ){
27397 sputf(stdout, " %d: %s\n", i, zFile);
27398 }
27399 }
27400 }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
27401 int i = azArg[1][0] - '0';
27402 if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
@@ -27422,24 +28792,22 @@
27422 eputz("Usage: .connection [close] [CONNECTION-NUMBER]\n");
27423 rc = 1;
27424 }
27425 }else
27426
27427 if( c=='c' && n==4 && cli_strncmp(azArg[0], "crnl", n)==0 ){
 
 
 
27428 if( nArg==2 ){
27429 if( booleanValue(azArg[1]) ){
27430 setTextMode(p->out, 1);
27431 }else{
27432 setBinaryMode(p->out, 1);
27433 }
27434 }else{
27435 #if !defined(_WIN32) && !defined(WIN32)
27436 eputz("The \".crnl\" is a no-op on non-Windows machines.\n");
27437 #endif
27438 eputz("Usage: .crnl on|off\n");
27439 rc = 1;
27440 }
 
27441 }else
27442
27443 if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
27444 char **azName = 0;
27445 int nName = 0;
@@ -27465,11 +28833,11 @@
27465 sqlite3_finalize(pStmt);
27466 for(i=0; i<nName; i++){
27467 int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
27468 int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
27469 const char *z = azName[i*2+1];
27470 oputf("%s: %s %s%s\n",
27471 azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w",
27472 eTxn==SQLITE_TXN_NONE ? "" :
27473 eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
27474 free(azName[i*2]);
27475 free(azName[i*2+1]);
@@ -27507,15 +28875,16 @@
27507 if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
27508 if( nArg>=3 ){
27509 sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
27510 }
27511 sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
27512 oputf("%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
 
27513 if( nArg>1 ) break;
27514 }
27515 if( nArg>1 && ii==ArraySize(aDbConfig) ){
27516 eputf("Error: unknown dbconfig \"%s\"\n", azArg[1]);
27517 eputz("Enter \".dbconfig\" with no arguments for a list\n");
27518 }
27519 }else
27520
27521 #if SQLITE_SHELL_HAVE_RECOVER
@@ -27561,11 +28930,12 @@
27561 }else
27562 if( cli_strcmp(z,"nosys")==0 ){
27563 ShellSetFlag(p, SHFLG_DumpNoSys);
27564 }else
27565 {
27566 eputf("Unknown option \"%s\" on \".dump\"\n", azArg[i]);
 
27567 rc = 1;
27568 sqlite3_free(zLike);
27569 goto meta_command_exit;
27570 }
27571 }else{
@@ -27596,12 +28966,12 @@
27596 outputDumpWarning(p, zLike);
27597 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
27598 /* When playing back a "dump", the content might appear in an order
27599 ** which causes immediate foreign key constraints to be violated.
27600 ** So disable foreign-key constraint enforcement to prevent problems. */
27601 oputz("PRAGMA foreign_keys=OFF;\n");
27602 oputz("BEGIN TRANSACTION;\n");
27603 }
27604 p->writableSchema = 0;
27605 p->showHeader = 0;
27606 /* Set writable_schema=ON since doing so forces SQLite to initialize
27607 ** as much of the schema as it can even if the sqlite_schema table is
@@ -27629,17 +28999,17 @@
27629 run_table_dump_query(p, zSql);
27630 sqlite3_free(zSql);
27631 }
27632 sqlite3_free(zLike);
27633 if( p->writableSchema ){
27634 oputz("PRAGMA writable_schema=OFF;\n");
27635 p->writableSchema = 0;
27636 }
27637 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
27638 sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
27639 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
27640 oputz(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
27641 }
27642 p->showHeader = savedShowHeader;
27643 p->shellFlgs = savedShellFlags;
27644 }else
27645
@@ -27649,10 +29019,14 @@
27649 }else{
27650 eputz("Usage: .echo on|off\n");
27651 rc = 1;
27652 }
27653 }else
 
 
 
 
27654
27655 if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
27656 if( nArg==2 ){
27657 p->autoEQPtest = 0;
27658 if( p->autoEQPtrace ){
@@ -27715,11 +29089,12 @@
27715 }else
27716
27717 #ifndef SQLITE_OMIT_VIRTUALTABLE
27718 if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
27719 if( p->bSafeMode ){
27720 eputf("Cannot run experimental commands such as \"%s\" in safe mode\n",
 
27721 azArg[0]);
27722 rc = 1;
27723 }else{
27724 open_db(p, 0);
27725 expertDotCommand(p, azArg, nArg);
@@ -27772,13 +29147,14 @@
27772 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
27773 }
27774
27775 /* --help lists all file-controls */
27776 if( cli_strcmp(zCmd,"help")==0 ){
27777 oputz("Available file-controls:\n");
27778 for(i=0; i<ArraySize(aCtrl); i++){
27779 oputf(" .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
 
27780 }
27781 rc = 1;
27782 goto meta_command_exit;
27783 }
27784
@@ -27789,19 +29165,19 @@
27789 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
27790 if( filectrl<0 ){
27791 filectrl = aCtrl[i].ctrlCode;
27792 iCtrl = i;
27793 }else{
27794 eputf("Error: ambiguous file-control: \"%s\"\n"
27795 "Use \".filectrl --help\" for help\n", zCmd);
27796 rc = 1;
27797 goto meta_command_exit;
27798 }
27799 }
27800 }
27801 if( filectrl<0 ){
27802 eputf("Error: unknown file-control: %s\n"
27803 "Use \".filectrl --help\" for help\n", zCmd);
27804 }else{
27805 switch(filectrl){
27806 case SQLITE_FCNTL_SIZE_LIMIT: {
27807 if( nArg!=2 && nArg!=3 ) break;
@@ -27841,11 +29217,11 @@
27841 case SQLITE_FCNTL_TEMPFILENAME: {
27842 char *z = 0;
27843 if( nArg!=2 ) break;
27844 sqlite3_file_control(p->db, zSchema, filectrl, &z);
27845 if( z ){
27846 oputf("%s\n", z);
27847 sqlite3_free(z);
27848 }
27849 isOk = 2;
27850 break;
27851 }
@@ -27855,23 +29231,24 @@
27855 x = atoi(azArg[2]);
27856 sqlite3_file_control(p->db, zSchema, filectrl, &x);
27857 }
27858 x = -1;
27859 sqlite3_file_control(p->db, zSchema, filectrl, &x);
27860 oputf("%d\n", x);
27861 isOk = 2;
27862 break;
27863 }
27864 }
27865 }
27866 if( isOk==0 && iCtrl>=0 ){
27867 oputf("Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
 
27868 rc = 1;
27869 }else if( isOk==1 ){
27870 char zBuf[100];
27871 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
27872 oputf("%s\n", zBuf);
27873 }
27874 }else
27875
27876 if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
27877 ShellState data;
@@ -27908,19 +29285,19 @@
27908 doStats = sqlite3_step(pStmt)==SQLITE_ROW;
27909 sqlite3_finalize(pStmt);
27910 }
27911 }
27912 if( doStats==0 ){
27913 oputz("/* No STAT tables available */\n");
27914 }else{
27915 oputz("ANALYZE sqlite_schema;\n");
27916 data.cMode = data.mode = MODE_Insert;
27917 data.zDestTable = "sqlite_stat1";
27918 shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
27919 data.zDestTable = "sqlite_stat4";
27920 shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
27921 oputz("ANALYZE sqlite_schema;\n");
27922 }
27923 }else
27924
27925 if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
27926 if( nArg==2 ){
@@ -27934,11 +29311,11 @@
27934
27935 if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){
27936 if( nArg>=2 ){
27937 n = showHelp(p->out, azArg[1]);
27938 if( n==0 ){
27939 oputf("Nothing matches '%s'\n", azArg[1]);
27940 }
27941 }else{
27942 showHelp(p->out, 0);
27943 }
27944 }else
@@ -27977,11 +29354,11 @@
27977 if( zFile==0 ){
27978 zFile = z;
27979 }else if( zTable==0 ){
27980 zTable = z;
27981 }else{
27982 oputf("ERROR: extra argument: \"%s\". Usage:\n", z);
27983 showHelp(p->out, "import");
27984 goto meta_command_exit;
27985 }
27986 }else if( cli_strcmp(z,"-v")==0 ){
27987 eVerbose++;
@@ -27998,17 +29375,17 @@
27998 sCtx.cColSep = ',';
27999 sCtx.cRowSep = '\n';
28000 xRead = csv_read_one_field;
28001 useOutputMode = 0;
28002 }else{
28003 oputf("ERROR: unknown option: \"%s\". Usage:\n", z);
28004 showHelp(p->out, "import");
28005 goto meta_command_exit;
28006 }
28007 }
28008 if( zTable==0 ){
28009 oputf("ERROR: missing %s argument. Usage:\n",
28010 zFile==0 ? "FILE" : "TABLE");
28011 showHelp(p->out, "import");
28012 goto meta_command_exit;
28013 }
28014 seenInterrupt = 0;
@@ -28054,32 +29431,32 @@
28054 if( sCtx.zFile[0]=='|' ){
28055 #ifdef SQLITE_OMIT_POPEN
28056 eputz("Error: pipes are not supported in this OS\n");
28057 goto meta_command_exit;
28058 #else
28059 sCtx.in = popen(sCtx.zFile+1, "r");
28060 sCtx.zFile = "<pipe>";
28061 sCtx.xCloser = pclose;
28062 #endif
28063 }else{
28064 sCtx.in = fopen(sCtx.zFile, "rb");
28065 sCtx.xCloser = fclose;
28066 }
28067 if( sCtx.in==0 ){
28068 eputf("Error: cannot open \"%s\"\n", zFile);
28069 goto meta_command_exit;
28070 }
28071 if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
28072 char zSep[2];
28073 zSep[1] = 0;
28074 zSep[0] = sCtx.cColSep;
28075 oputz("Column separator ");
28076 output_c_string(zSep);
28077 oputz(", row separator ");
28078 zSep[0] = sCtx.cRowSep;
28079 output_c_string(zSep);
28080 oputz("\n");
28081 }
28082 sCtx.z = sqlite3_malloc64(120);
28083 if( sCtx.z==0 ){
28084 import_cleanup(&sCtx);
28085 shell_out_of_memory();
@@ -28087,11 +29464,15 @@
28087 /* Below, resources must be freed before exit. */
28088 while( (nSkip--)>0 ){
28089 while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
28090 }
28091 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
28092 if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){
 
 
 
 
28093 /* Table does not exist. Create it. */
28094 sqlite3 *dbCols = 0;
28095 char *zRenames = 0;
28096 char *zColDefs;
28097 zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
@@ -28100,18 +29481,18 @@
28100 zAutoColumn(sCtx.z, &dbCols, 0);
28101 if( sCtx.cTerm!=sCtx.cColSep ) break;
28102 }
28103 zColDefs = zAutoColumn(0, &dbCols, &zRenames);
28104 if( zRenames!=0 ){
28105 sputf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
28106 "Columns renamed during .import %s due to duplicates:\n"
28107 "%s\n", sCtx.zFile, zRenames);
28108 sqlite3_free(zRenames);
28109 }
28110 assert(dbCols==0);
28111 if( zColDefs==0 ){
28112 eputf("%s: empty file\n", sCtx.zFile);
28113 import_cleanup(&sCtx);
28114 rc = 1;
28115 sqlite3_free(zCreate);
28116 goto meta_command_exit;
28117 }
@@ -28119,17 +29500,20 @@
28119 if( zCreate==0 ){
28120 import_cleanup(&sCtx);
28121 shell_out_of_memory();
28122 }
28123 if( eVerbose>=1 ){
28124 oputf("%s\n", zCreate);
28125 }
28126 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
 
 
 
 
28127 sqlite3_free(zCreate);
28128 zCreate = 0;
28129 if( rc ){
28130 eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
28131 import_cleanup(&sCtx);
28132 rc = 1;
28133 goto meta_command_exit;
28134 }
28135 }
@@ -28180,11 +29564,11 @@
28180 }
28181 zSql[j++] = ')';
28182 zSql[j] = 0;
28183 assert( j<nByte );
28184 if( eVerbose>=2 ){
28185 oputf("Insert using: %s\n", zSql);
28186 }
28187 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
28188 sqlite3_free(zSql);
28189 zSql = 0;
28190 if( rc ){
@@ -28219,11 +29603,11 @@
28219 if( z==0 && (xRead==csv_read_one_field) && i==nCol-1 && i>0 ){
28220 z = "";
28221 }
28222 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
28223 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
28224 eputf("%s:%d: expected %d columns but found %d"
28225 " - filling the rest with NULL\n",
28226 sCtx.zFile, startLine, nCol, i+1);
28227 i += 2;
28228 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
28229 }
@@ -28231,18 +29615,19 @@
28231 if( sCtx.cTerm==sCtx.cColSep ){
28232 do{
28233 xRead(&sCtx);
28234 i++;
28235 }while( sCtx.cTerm==sCtx.cColSep );
28236 eputf("%s:%d: expected %d columns but found %d - extras ignored\n",
 
28237 sCtx.zFile, startLine, nCol, i);
28238 }
28239 if( i>=nCol ){
28240 sqlite3_step(pStmt);
28241 rc = sqlite3_reset(pStmt);
28242 if( rc!=SQLITE_OK ){
28243 eputf("%s:%d: INSERT failed: %s\n",
28244 sCtx.zFile, startLine, sqlite3_errmsg(p->db));
28245 sCtx.nErr++;
28246 }else{
28247 sCtx.nRow++;
28248 }
@@ -28251,11 +29636,12 @@
28251
28252 import_cleanup(&sCtx);
28253 sqlite3_finalize(pStmt);
28254 if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
28255 if( eVerbose>0 ){
28256 oputf("Added %d rows with %d errors using %d lines of input\n",
 
28257 sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
28258 }
28259 }else
28260 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
28261
@@ -28267,11 +29653,11 @@
28267 int tnum = 0;
28268 int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
28269 int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
28270 int i;
28271 if( !ShellHasFlag(p,SHFLG_TestingMode) ){
28272 eputf(".%s unavailable without --unsafe-testing\n",
28273 "imposter");
28274 rc = 1;
28275 goto meta_command_exit;
28276 }
28277 if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
@@ -28333,11 +29719,11 @@
28333 zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
28334 }
28335 }
28336 sqlite3_finalize(pStmt);
28337 if( i==0 || tnum==0 ){
28338 eputf("no such index: \"%s\"\n", azArg[1]);
28339 rc = 1;
28340 sqlite3_free(zCollist);
28341 goto meta_command_exit;
28342 }
28343 if( lenPK==0 ) lenPK = 100000;
@@ -28348,18 +29734,20 @@
28348 rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
28349 if( rc==SQLITE_OK ){
28350 rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
28351 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
28352 if( rc ){
28353 eputf("Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
 
28354 }else{
28355 sputf(stdout, "%s;\n", zSql);
28356 sputf(stdout, "WARNING: writing to an imposter table will corrupt"
 
28357 " the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index");
28358 }
28359 }else{
28360 eputf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
28361 rc = 1;
28362 }
28363 sqlite3_free(zSql);
28364 }else
28365 #endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
@@ -28369,11 +29757,11 @@
28369 if( nArg==2 ){
28370 iArg = integerValue(azArg[1]);
28371 if( iArg==0 ) iArg = -1;
28372 }
28373 if( (nArg!=1 && nArg!=2) || iArg<0 ){
28374 eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
28375 rc = 1;
28376 goto meta_command_exit;
28377 }
28378 open_db(p, 0);
28379 rc = intckDatabaseCmd(p, iArg);
@@ -28388,13 +29776,13 @@
28388 sqlite3IoTrace = 0;
28389 }else if( cli_strcmp(azArg[1], "-")==0 ){
28390 sqlite3IoTrace = iotracePrintf;
28391 iotrace = stdout;
28392 }else{
28393 iotrace = fopen(azArg[1], "w");
28394 if( iotrace==0 ){
28395 eputf("Error: cannot open \"%s\"\n", azArg[1]);
28396 sqlite3IoTrace = 0;
28397 rc = 1;
28398 }else{
28399 sqlite3IoTrace = iotracePrintf;
28400 }
@@ -28422,11 +29810,11 @@
28422 };
28423 int i, n2;
28424 open_db(p, 0);
28425 if( nArg==1 ){
28426 for(i=0; i<ArraySize(aLimit); i++){
28427 sputf(stdout, "%20s %d\n", aLimit[i].zLimitName,
28428 sqlite3_limit(p->db, aLimit[i].limitCode, -1));
28429 }
28430 }else if( nArg>3 ){
28431 eputz("Usage: .limit NAME ?NEW-VALUE?\n");
28432 rc = 1;
@@ -28437,28 +29825,28 @@
28437 for(i=0; i<ArraySize(aLimit); i++){
28438 if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
28439 if( iLimit<0 ){
28440 iLimit = i;
28441 }else{
28442 eputf("ambiguous limit: \"%s\"\n", azArg[1]);
28443 rc = 1;
28444 goto meta_command_exit;
28445 }
28446 }
28447 }
28448 if( iLimit<0 ){
28449 eputf("unknown limit: \"%s\"\n"
28450 "enter \".limits\" with no arguments for a list.\n",
28451 azArg[1]);
28452 rc = 1;
28453 goto meta_command_exit;
28454 }
28455 if( nArg==3 ){
28456 sqlite3_limit(p->db, aLimit[iLimit].limitCode,
28457 (int)integerValue(azArg[2]));
28458 }
28459 sputf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
28460 sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
28461 }
28462 }else
28463
28464 if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){
@@ -28503,11 +29891,11 @@
28503 " than \"on\" or \"off\"\n");
28504 zFile = "off";
28505 }
28506 output_file_close(p->pLog);
28507 if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
28508 p->pLog = output_file_open(zFile, 0);
28509 }
28510 }else
28511
28512 if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
28513 const char *zMode = 0;
@@ -28537,35 +29925,37 @@
28537 cmOpts = cmo;
28538 }
28539 }else if( zTabname==0 ){
28540 zTabname = z;
28541 }else if( z[0]=='-' ){
28542 eputf("unknown option: %s\n", z);
28543 eputz("options:\n"
28544 " --noquote\n"
28545 " --quote\n"
28546 " --wordwrap on/off\n"
28547 " --wrap N\n"
28548 " --ww\n");
28549 rc = 1;
28550 goto meta_command_exit;
28551 }else{
28552 eputf("extra argument: \"%s\"\n", z);
28553 rc = 1;
28554 goto meta_command_exit;
28555 }
28556 }
28557 if( zMode==0 ){
28558 if( p->mode==MODE_Column
28559 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
28560 ){
28561 oputf("current output mode: %s --wrap %d --wordwrap %s --%squote\n",
 
28562 modeDescr[p->mode], p->cmOpts.iWrap,
28563 p->cmOpts.bWordWrap ? "on" : "off",
28564 p->cmOpts.bQuote ? "" : "no");
28565 }else{
28566 oputf("current output mode: %s\n", modeDescr[p->mode]);
 
28567 }
28568 zMode = modeDescr[p->mode];
28569 }
28570 n2 = strlen30(zMode);
28571 if( cli_strncmp(zMode,"lines",n2)==0 ){
@@ -28634,11 +30024,11 @@
28634 if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){
28635 if( nArg!=2 ){
28636 eputz("Usage: .nonce NONCE\n");
28637 rc = 1;
28638 }else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
28639 eputf("line %d: incorrect nonce: \"%s\"\n",
28640 p->lineno, azArg[1]);
28641 exit(1);
28642 }else{
28643 p->bSafeMode = 0;
28644 return 0; /* Return immediately to bypass the safe mode reset
@@ -28689,15 +30079,15 @@
28689 p->szMax = integerValue(azArg[++iName]);
28690 #endif /* SQLITE_OMIT_DESERIALIZE */
28691 }else
28692 #endif /* !SQLITE_SHELL_FIDDLE */
28693 if( z[0]=='-' ){
28694 eputf("unknown option: %s\n", z);
28695 rc = 1;
28696 goto meta_command_exit;
28697 }else if( zFN ){
28698 eputf("extra argument: \"%s\"\n", z);
28699 rc = 1;
28700 goto meta_command_exit;
28701 }else{
28702 zFN = z;
28703 }
@@ -28735,11 +30125,11 @@
28735 zNewFilename = 0;
28736 }
28737 p->pAuxDb->zDbFilename = zNewFilename;
28738 open_db(p, OPEN_DB_KEEPALIVE);
28739 if( p->db==0 ){
28740 eputf("Error: cannot open '%s'\n", zNewFilename);
28741 sqlite3_free(zNewFilename);
28742 }else{
28743 p->pAuxDb->zFreeOnClose = zNewFilename;
28744 }
28745 }
@@ -28753,22 +30143,26 @@
28753 #ifndef SQLITE_SHELL_FIDDLE
28754 if( (c=='o'
28755 && (cli_strncmp(azArg[0], "output", n)==0
28756 || cli_strncmp(azArg[0], "once", n)==0))
28757 || (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
 
28758 ){
28759 char *zFile = 0;
28760 int bTxtMode = 0;
28761 int i;
28762 int eMode = 0;
28763 int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
28764 static const char *zBomUtf8 = "\xef\xbb\xbf";
 
28765 const char *zBom = 0;
28766
28767 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
28768 if( c=='e' ){
28769 eMode = 'x';
 
 
 
28770 bOnce = 2;
28771 }else if( cli_strncmp(azArg[0],"once",n)==0 ){
28772 bOnce = 1;
28773 }
28774 for(i=1; i<nArg; i++){
@@ -28775,28 +30169,34 @@
28775 char *z = azArg[i];
28776 if( z[0]=='-' ){
28777 if( z[1]=='-' ) z++;
28778 if( cli_strcmp(z,"-bom")==0 ){
28779 zBom = zBomUtf8;
28780 }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
 
 
28781 eMode = 'x'; /* spreadsheet */
28782 }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
28783 eMode = 'e'; /* text editor */
 
 
28784 }else{
28785 oputf("ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
 
28786 showHelp(p->out, azArg[0]);
28787 rc = 1;
28788 goto meta_command_exit;
28789 }
28790 }else if( zFile==0 && eMode!='e' && eMode!='x' ){
28791 zFile = sqlite3_mprintf("%s", z);
28792 if( zFile && zFile[0]=='|' ){
28793 while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
28794 break;
28795 }
28796 }else{
28797 oputf("ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
 
28798 showHelp(p->out, azArg[0]);
28799 rc = 1;
28800 sqlite3_free(zFile);
28801 goto meta_command_exit;
28802 }
@@ -28809,24 +30209,31 @@
28809 }else{
28810 p->outCount = 0;
28811 }
28812 output_reset(p);
28813 #ifndef SQLITE_NOHAVE_SYSTEM
28814 if( eMode=='e' || eMode=='x' ){
28815 p->doXdgOpen = 1;
28816 outputModePush(p);
28817 if( eMode=='x' ){
28818 /* spreadsheet mode. Output as CSV. */
28819 newTempFile(p, "csv");
28820 ShellClearFlag(p, SHFLG_Echo);
28821 p->mode = MODE_Csv;
28822 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
28823 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
 
 
 
 
 
 
 
 
28824 }else{
28825 /* text editor mode */
28826 newTempFile(p, "txt");
28827 bTxtMode = 1;
28828 }
28829 sqlite3_free(zFile);
28830 zFile = sqlite3_mprintf("%s", p->zTempFile);
28831 }
28832 #endif /* SQLITE_NOHAVE_SYSTEM */
@@ -28835,30 +30242,36 @@
28835 #ifdef SQLITE_OMIT_POPEN
28836 eputz("Error: pipes are not supported in this OS\n");
28837 rc = 1;
28838 output_redir(p, stdout);
28839 #else
28840 FILE *pfPipe = popen(zFile + 1, "w");
28841 if( pfPipe==0 ){
28842 eputf("Error: cannot open pipe \"%s\"\n", zFile + 1);
28843 rc = 1;
28844 }else{
28845 output_redir(p, pfPipe);
28846 if( zBom ) oputz(zBom);
28847 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
28848 }
28849 #endif
28850 }else{
28851 FILE *pfFile = output_file_open(zFile, bTxtMode);
28852 if( pfFile==0 ){
28853 if( cli_strcmp(zFile,"off")!=0 ){
28854 eputf("Error: cannot write to \"%s\"\n", zFile);
28855 }
28856 rc = 1;
28857 } else {
28858 output_redir(p, pfFile);
28859 if( zBom ) oputz(zBom);
 
 
 
 
 
 
28860 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
28861 }
28862 }
28863 sqlite3_free(zFile);
28864 }else
@@ -28895,11 +30308,12 @@
28895 if( len ){
28896 rx = sqlite3_prepare_v2(p->db,
28897 "SELECT key, quote(value) "
28898 "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
28899 while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
28900 oputf("%-*s %s\n", len, sqlite3_column_text(pStmt,0),
 
28901 sqlite3_column_text(pStmt,1));
28902 }
28903 sqlite3_finalize(pStmt);
28904 }
28905 }else
@@ -28940,11 +30354,11 @@
28940 "VALUES(%Q,%Q);", zKey, zValue);
28941 shell_check_oom(zSql);
28942 rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
28943 sqlite3_free(zSql);
28944 if( rx!=SQLITE_OK ){
28945 oputf("Error: %s\n", sqlite3_errmsg(p->db));
28946 sqlite3_finalize(pStmt);
28947 pStmt = 0;
28948 rc = 1;
28949 }
28950 }
@@ -28969,14 +30383,14 @@
28969 }else
28970
28971 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
28972 int i;
28973 for(i=1; i<nArg; i++){
28974 if( i>1 ) oputz(" ");
28975 oputz(azArg[i]);
28976 }
28977 oputz("\n");
28978 }else
28979
28980 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
28981 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){
28982 int i;
@@ -29009,11 +30423,11 @@
29009 }else{
29010 p->mxProgress = (int)integerValue(azArg[++i]);
29011 }
29012 continue;
29013 }
29014 eputf("Error: unknown option: \"%s\"\n", azArg[i]);
29015 rc = 1;
29016 goto meta_command_exit;
29017 }else{
29018 nn = (int)integerValue(z);
29019 }
@@ -29050,23 +30464,22 @@
29050 }
29051 if( azArg[1][0]=='|' ){
29052 #ifdef SQLITE_OMIT_POPEN
29053 eputz("Error: pipes are not supported in this OS\n");
29054 rc = 1;
29055 p->out = stdout;
29056 #else
29057 p->in = popen(azArg[1]+1, "r");
29058 if( p->in==0 ){
29059 eputf("Error: cannot open \"%s\"\n", azArg[1]);
29060 rc = 1;
29061 }else{
29062 rc = process_input(p);
29063 pclose(p->in);
29064 }
29065 #endif
29066 }else if( (p->in = openChrSource(azArg[1]))==0 ){
29067 eputf("Error: cannot open \"%s\"\n", azArg[1]);
29068 rc = 1;
29069 }else{
29070 rc = process_input(p);
29071 fclose(p->in);
29072 }
@@ -29095,11 +30508,11 @@
29095 rc = 1;
29096 goto meta_command_exit;
29097 }
29098 rc = sqlite3_open(zSrcFile, &pSrc);
29099 if( rc!=SQLITE_OK ){
29100 eputf("Error: cannot open \"%s\"\n", zSrcFile);
29101 close_db(pSrc);
29102 return 1;
29103 }
29104 open_db(p, 0);
29105 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
@@ -29127,11 +30540,14 @@
29127 }
29128 close_db(pSrc);
29129 }else
29130 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
29131
29132 if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
 
 
 
29133 if( nArg==2 ){
29134 if( cli_strcmp(azArg[1], "vm")==0 ){
29135 p->scanstatsOn = 3;
29136 }else
29137 if( cli_strcmp(azArg[1], "est")==0 ){
@@ -29178,11 +30594,11 @@
29178 }else if( optionMatch(azArg[ii],"debug") ){
29179 bDebug = 1;
29180 }else if( optionMatch(azArg[ii],"nosys") ){
29181 bNoSystemTabs = 1;
29182 }else if( azArg[ii][0]=='-' ){
29183 eputf("Unknown option: \"%s\"\n", azArg[ii]);
29184 rc = 1;
29185 goto meta_command_exit;
29186 }else if( zName==0 ){
29187 zName = azArg[ii];
29188 }else{
@@ -29279,11 +30695,11 @@
29279 appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
29280 }
29281 appendText(&sSelect, "sql IS NOT NULL"
29282 " ORDER BY snum, rowid", 0);
29283 if( bDebug ){
29284 oputf("SQL: %s;\n", sSelect.z);
29285 }else{
29286 rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
29287 }
29288 freeText(&sSelect);
29289 }
@@ -29340,11 +30756,12 @@
29340 session_not_open:
29341 eputz("ERROR: No sessions are open\n");
29342 }else{
29343 rc = sqlite3session_attach(pSession->p, azCmd[1]);
29344 if( rc ){
29345 eputf("ERROR: sqlite3session_attach() returns %d\n",rc);
 
29346 rc = 0;
29347 }
29348 }
29349 }else
29350
@@ -29357,13 +30774,13 @@
29357 ){
29358 FILE *out = 0;
29359 failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
29360 if( nCmd!=2 ) goto session_syntax_error;
29361 if( pSession->p==0 ) goto session_not_open;
29362 out = fopen(azCmd[1], "wb");
29363 if( out==0 ){
29364 eputf("ERROR: cannot open \"%s\" for writing\n",
29365 azCmd[1]);
29366 }else{
29367 int szChng;
29368 void *pChng;
29369 if( azCmd[0][0]=='c' ){
@@ -29370,16 +30787,17 @@
29370 rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
29371 }else{
29372 rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
29373 }
29374 if( rc ){
29375 sputf(stdout, "Error: error code %d\n", rc);
29376 rc = 0;
29377 }
29378 if( pChng
29379 && fwrite(pChng, szChng, 1, out)!=1 ){
29380 eputf("ERROR: Failed to write entire %d-byte output\n", szChng);
 
29381 }
29382 sqlite3_free(pChng);
29383 fclose(out);
29384 }
29385 }else
@@ -29402,11 +30820,12 @@
29402 int ii;
29403 if( nCmd>2 ) goto session_syntax_error;
29404 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
29405 if( pAuxDb->nSession ){
29406 ii = sqlite3session_enable(pSession->p, ii);
29407 oputf("session %s enable flag = %d\n", pSession->zName, ii);
 
29408 }
29409 }else
29410
29411 /* .session filter GLOB ....
29412 ** Set a list of GLOB patterns of table names to be excluded.
@@ -29437,11 +30856,12 @@
29437 int ii;
29438 if( nCmd>2 ) goto session_syntax_error;
29439 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
29440 if( pAuxDb->nSession ){
29441 ii = sqlite3session_indirect(pSession->p, ii);
29442 oputf("session %s indirect flag = %d\n", pSession->zName, ii);
 
29443 }
29444 }else
29445
29446 /* .session isempty
29447 ** Determine if the session is empty
@@ -29449,20 +30869,21 @@
29449 if( cli_strcmp(azCmd[0], "isempty")==0 ){
29450 int ii;
29451 if( nCmd!=1 ) goto session_syntax_error;
29452 if( pAuxDb->nSession ){
29453 ii = sqlite3session_isempty(pSession->p);
29454 oputf("session %s isempty flag = %d\n", pSession->zName, ii);
 
29455 }
29456 }else
29457
29458 /* .session list
29459 ** List all currently open sessions
29460 */
29461 if( cli_strcmp(azCmd[0],"list")==0 ){
29462 for(i=0; i<pAuxDb->nSession; i++){
29463 oputf("%d %s\n", i, pAuxDb->aSession[i].zName);
29464 }
29465 }else
29466
29467 /* .session open DB NAME
29468 ** Open a new session called NAME on the attached database DB.
@@ -29473,22 +30894,23 @@
29473 if( nCmd!=3 ) goto session_syntax_error;
29474 zName = azCmd[2];
29475 if( zName[0]==0 ) goto session_syntax_error;
29476 for(i=0; i<pAuxDb->nSession; i++){
29477 if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
29478 eputf("Session \"%s\" already exists\n", zName);
29479 goto meta_command_exit;
29480 }
29481 }
29482 if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
29483 eputf("Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
 
29484 goto meta_command_exit;
29485 }
29486 pSession = &pAuxDb->aSession[pAuxDb->nSession];
29487 rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
29488 if( rc ){
29489 eputf("Cannot open session: error code=%d\n", rc);
29490 rc = 0;
29491 goto meta_command_exit;
29492 }
29493 pSession->nFilter = 0;
29494 sqlite3session_table_filter(pSession->p, session_filter, pSession);
@@ -29508,20 +30930,20 @@
29508 if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){
29509 if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){
29510 int i, v;
29511 for(i=1; i<nArg; i++){
29512 v = booleanValue(azArg[i]);
29513 oputf("%s: %d 0x%x\n", azArg[i], v, v);
29514 }
29515 }
29516 if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
29517 int i; sqlite3_int64 v;
29518 for(i=1; i<nArg; i++){
29519 char zBuf[200];
29520 v = integerValue(azArg[i]);
29521 sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
29522 oputz(zBuf);
29523 }
29524 }
29525 }else
29526 #endif
29527
@@ -29544,12 +30966,13 @@
29544 }else
29545 if( cli_strcmp(z,"-v")==0 ){
29546 bVerbose++;
29547 }else
29548 {
29549 eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
29550 eputz("Should be one of: --init -v\n");
 
29551 rc = 1;
29552 goto meta_command_exit;
29553 }
29554 }
29555 if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
@@ -29590,46 +31013,47 @@
29590 if( zOp==0 ) continue;
29591 if( zSql==0 ) continue;
29592 if( zAns==0 ) continue;
29593 k = 0;
29594 if( bVerbose>0 ){
29595 sputf(stdout, "%d: %s %s\n", tno, zOp, zSql);
29596 }
29597 if( cli_strcmp(zOp,"memo")==0 ){
29598 oputf("%s\n", zSql);
29599 }else
29600 if( cli_strcmp(zOp,"run")==0 ){
29601 char *zErrMsg = 0;
29602 str.n = 0;
29603 str.z[0] = 0;
29604 rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
29605 nTest++;
29606 if( bVerbose ){
29607 oputf("Result: %s\n", str.z);
29608 }
29609 if( rc || zErrMsg ){
29610 nErr++;
29611 rc = 1;
29612 oputf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
29613 sqlite3_free(zErrMsg);
29614 }else if( cli_strcmp(zAns,str.z)!=0 ){
29615 nErr++;
29616 rc = 1;
29617 oputf("%d: Expected: [%s]\n", tno, zAns);
29618 oputf("%d: Got: [%s]\n", tno, str.z);
29619 }
29620 }
29621 else{
29622 eputf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
 
29623 rc = 1;
29624 break;
29625 }
29626 } /* End loop over rows of content from SELFTEST */
29627 sqlite3_finalize(pStmt);
29628 } /* End loop over k */
29629 freeText(&str);
29630 oputf("%d errors out of %d tests\n", nErr, nTest);
29631 }else
29632
29633 if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
29634 if( nArg<2 || nArg>3 ){
29635 eputz("Usage: .separator COL ?ROW?\n");
@@ -29673,11 +31097,12 @@
29673 }else
29674 if( cli_strcmp(z,"debug")==0 ){
29675 bDebug = 1;
29676 }else
29677 {
29678 eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
 
29679 showHelp(p->out, azArg[0]);
29680 rc = 1;
29681 goto meta_command_exit;
29682 }
29683 }else if( zLike ){
@@ -29751,11 +31176,11 @@
29751 }
29752 shell_check_oom(zSql);
29753 freeText(&sQuery);
29754 freeText(&sSql);
29755 if( bDebug ){
29756 oputf("%s\n", zSql);
29757 }else{
29758 shell_exec(p, zSql, 0);
29759 }
29760 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE)
29761 {
@@ -29781,11 +31206,11 @@
29781 "||group_concat('CAST(CAST('||cname||' AS BLOB) AS TEXT)<>'||cname\n"
29782 "|| ' AND typeof('||cname||')=''text'' ',\n"
29783 "' OR ') as query, tname from tabcols group by tname)"
29784 , zRevText);
29785 shell_check_oom(zRevText);
29786 if( bDebug ) oputf("%s\n", zRevText);
29787 lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
29788 if( lrc!=SQLITE_OK ){
29789 /* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
29790 ** user does cruel and unnatural things like ".limit expr_depth 0". */
29791 rc = 1;
@@ -29794,19 +31219,20 @@
29794 lrc = SQLITE_ROW==sqlite3_step(pStmt);
29795 if( lrc ){
29796 const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
29797 sqlite3_stmt *pCheckStmt;
29798 lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
29799 if( bDebug ) oputf("%s\n", zGenQuery);
29800 if( lrc!=SQLITE_OK ){
29801 rc = 1;
29802 }else{
29803 if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
29804 double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
29805 if( countIrreversible>0 ){
29806 int sz = (int)(countIrreversible + 0.5);
29807 eputf("Digest includes %d invalidly encoded text field%s.\n",
 
29808 sz, (sz>1)? "s": "");
29809 }
29810 }
29811 sqlite3_finalize(pCheckStmt);
29812 }
@@ -29836,15 +31262,15 @@
29836 zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
29837 for(i=2; i<nArg && zCmd!=0; i++){
29838 zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
29839 zCmd, azArg[i]);
29840 }
29841 consoleRestore();
29842 x = zCmd!=0 ? system(zCmd) : 1;
29843 consoleRenewSetup();
29844 sqlite3_free(zCmd);
29845 if( x ) eputf("System command returns %d\n", x);
29846 }else
29847 #endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
29848
29849 if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
29850 static const char *azBool[] = { "off", "on", "trigger", "full"};
@@ -29853,50 +31279,52 @@
29853 if( nArg!=1 ){
29854 eputz("Usage: .show\n");
29855 rc = 1;
29856 goto meta_command_exit;
29857 }
29858 oputf("%12.12s: %s\n","echo",
29859 azBool[ShellHasFlag(p, SHFLG_Echo)]);
29860 oputf("%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
29861 oputf("%12.12s: %s\n","explain",
29862 p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
29863 oputf("%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
 
29864 if( p->mode==MODE_Column
29865 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
29866 ){
29867 oputf("%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
 
29868 modeDescr[p->mode], p->cmOpts.iWrap,
29869 p->cmOpts.bWordWrap ? "on" : "off",
29870 p->cmOpts.bQuote ? "" : "no");
29871 }else{
29872 oputf("%12.12s: %s\n","mode", modeDescr[p->mode]);
29873 }
29874 oputf("%12.12s: ", "nullvalue");
29875 output_c_string(p->nullValue);
29876 oputz("\n");
29877 oputf("%12.12s: %s\n","output",
29878 strlen30(p->outfile) ? p->outfile : "stdout");
29879 oputf("%12.12s: ", "colseparator");
29880 output_c_string(p->colSeparator);
29881 oputz("\n");
29882 oputf("%12.12s: ", "rowseparator");
29883 output_c_string(p->rowSeparator);
29884 oputz("\n");
29885 switch( p->statsOn ){
29886 case 0: zOut = "off"; break;
29887 default: zOut = "on"; break;
29888 case 2: zOut = "stmt"; break;
29889 case 3: zOut = "vmstep"; break;
29890 }
29891 oputf("%12.12s: %s\n","stats", zOut);
29892 oputf("%12.12s: ", "width");
29893 for (i=0;i<p->nWidth;i++) {
29894 oputf("%d ", p->colWidth[i]);
29895 }
29896 oputz("\n");
29897 oputf("%12.12s: %s\n", "filename",
29898 p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
29899 }else
29900
29901 if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){
29902 if( nArg==2 ){
@@ -30010,13 +31438,14 @@
30010 if( nPrintCol<1 ) nPrintCol = 1;
30011 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
30012 for(i=0; i<nPrintRow; i++){
30013 for(j=i; j<nRow; j+=nPrintRow){
30014 char *zSp = j<nPrintRow ? "" : " ";
30015 oputf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
 
30016 }
30017 oputz("\n");
30018 }
30019 }
30020
30021 for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
30022 sqlite3_free(azResult);
@@ -30024,11 +31453,11 @@
30024
30025 #ifndef SQLITE_SHELL_FIDDLE
30026 /* Begin redirecting output to the file "testcase-out.txt" */
30027 if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
30028 output_reset(p);
30029 p->out = output_file_open("testcase-out.txt", 0);
30030 if( p->out==0 ){
30031 eputz("Error: cannot open 'testcase-out.txt'\n");
30032 }
30033 if( nArg>=2 ){
30034 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
@@ -30068,11 +31497,10 @@
30068 {"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" },
30069 {"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" },
30070 {"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
30071 {"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
30072 {"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
30073 {"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"},
30074 };
30075 int testctrl = -1;
30076 int iCtrl = -1;
30077 int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
30078 int isOk = 0;
@@ -30088,14 +31516,14 @@
30088 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
30089 }
30090
30091 /* --help lists all test-controls */
30092 if( cli_strcmp(zCmd,"help")==0 ){
30093 oputz("Available test-controls:\n");
30094 for(i=0; i<ArraySize(aCtrl); i++){
30095 if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
30096 oputf(" .testctrl %s %s\n",
30097 aCtrl[i].zCtrlName, aCtrl[i].zUsage);
30098 }
30099 rc = 1;
30100 goto meta_command_exit;
30101 }
@@ -30108,19 +31536,19 @@
30108 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
30109 if( testctrl<0 ){
30110 testctrl = aCtrl[i].ctrlCode;
30111 iCtrl = i;
30112 }else{
30113 eputf("Error: ambiguous test-control: \"%s\"\n"
30114 "Use \".testctrl --help\" for help\n", zCmd);
30115 rc = 1;
30116 goto meta_command_exit;
30117 }
30118 }
30119 }
30120 if( testctrl<0 ){
30121 eputf("Error: unknown test-control: %s\n"
30122 "Use \".testctrl --help\" for help\n", zCmd);
30123 }else{
30124 switch(testctrl){
30125
30126 /* Special processing for .testctrl opt MASK ...
@@ -30170,11 +31598,13 @@
30170 { 0x10000000, 1, "OrderBySubq" },
30171 { 0xffffffff, 0, "All" },
30172 };
30173 unsigned int curOpt;
30174 unsigned int newOpt;
 
30175 int ii;
 
30176 sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
30177 newOpt = curOpt;
30178 for(ii=2; ii<nArg; ii++){
30179 const char *z = azArg[ii];
30180 int useLabel = 0;
@@ -30192,16 +31622,17 @@
30192 int jj;
30193 for(jj=0; jj<ArraySize(aLabel); jj++){
30194 if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
30195 }
30196 if( jj>=ArraySize(aLabel) ){
30197 eputf("Error: no such optimization: \"%s\"\n", zLabel);
30198 eputz("Should be one of:");
 
30199 for(jj=0; jj<ArraySize(aLabel); jj++){
30200 eputf(" %s", aLabel[jj].zLabel);
30201 }
30202 eputz("\n");
30203 rc = 1;
30204 goto meta_command_exit;
30205 }
30206 if( useLabel=='+' ){
30207 newOpt &= ~aLabel[jj].mask;
@@ -30210,28 +31641,32 @@
30210 }
30211 }
30212 }
30213 if( curOpt!=newOpt ){
30214 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
30215 }else if( nArg<3 ){
30216 curOpt = ~newOpt;
 
30217 }
30218 if( newOpt==0 ){
30219 oputz("+All\n");
30220 }else if( newOpt==0xffffffff ){
30221 oputz("-All\n");
 
 
 
 
30222 }else{
30223 int jj;
30224 for(jj=0; jj<ArraySize(aLabel); jj++){
30225 unsigned int m = aLabel[jj].mask;
30226 if( !aLabel[jj].bDsply ) continue;
30227 if( (curOpt&m)!=(newOpt&m) ){
30228 oputf("%c%s\n", (newOpt & m)==0 ? '+' : '-',
30229 aLabel[jj].zLabel);
30230 }
30231 }
30232 }
 
30233 rc2 = isOk = 3;
30234 break;
30235 }
30236
30237 /* sqlite3_test_control(int, db, int) */
@@ -30267,11 +31702,11 @@
30267 if( nArg==3 || nArg==4 ){
30268 int ii = (int)integerValue(azArg[2]);
30269 sqlite3 *db;
30270 if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
30271 sqlite3_randomness(sizeof(ii),&ii);
30272 sputf(stdout, "-- random seed: %d\n", ii);
30273 }
30274 if( nArg==3 ){
30275 db = 0;
30276 }else{
30277 db = p->db;
@@ -30301,25 +31736,10 @@
30301 rc2 = sqlite3_test_control(testctrl, opt);
30302 isOk = 3;
30303 }
30304 break;
30305
30306 /* sqlite3_test_control(int, int) */
30307 case SQLITE_TESTCTRL_USELONGDOUBLE: {
30308 int opt = -1;
30309 if( nArg==3 ){
30310 if( cli_strcmp(azArg[2],"default")==0 ){
30311 opt = 2;
30312 }else{
30313 opt = booleanValue(azArg[2]);
30314 }
30315 }
30316 rc2 = sqlite3_test_control(testctrl, opt);
30317 isOk = 1;
30318 break;
30319 }
30320
30321 /* sqlite3_test_control(sqlite3*) */
30322 case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
30323 rc2 = sqlite3_test_control(testctrl, p->db);
30324 isOk = 3;
30325 break;
@@ -30335,11 +31755,11 @@
30335 break;
30336
30337 case SQLITE_TESTCTRL_SEEK_COUNT: {
30338 u64 x = 0;
30339 rc2 = sqlite3_test_control(testctrl, p->db, &x);
30340 oputf("%llu\n", x);
30341 isOk = 3;
30342 break;
30343 }
30344
30345 #ifdef YYCOVERAGE
@@ -30366,15 +31786,15 @@
30366 int id = 1;
30367 while(1){
30368 int val = 0;
30369 rc2 = sqlite3_test_control(testctrl, -id, &val);
30370 if( rc2!=SQLITE_OK ) break;
30371 if( id>1 ) oputz(" ");
30372 oputf("%d: %d", id, val);
30373 id++;
30374 }
30375 if( id>1 ) oputz("\n");
30376 isOk = 3;
30377 }
30378 break;
30379 }
30380 #endif
@@ -30412,18 +31832,26 @@
30412 }else if( cli_strcmp(z,"reset")==0 ){
30413 faultsim_state.iCnt = faultsim_state.nSkip;
30414 faultsim_state.nHit = 0;
30415 sqlite3_test_control(testctrl, faultsim_callback);
30416 }else if( cli_strcmp(z,"status")==0 ){
30417 oputf("faultsim.iId: %d\n", faultsim_state.iId);
30418 oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
30419 oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
30420 oputf("faultsim.nHit: %d\n", faultsim_state.nHit);
30421 oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
30422 oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
30423 oputf("faultsim.nRepeat: %d\n", faultsim_state.nRepeat);
30424 oputf("faultsim.nSkip: %d\n", faultsim_state.nSkip);
 
 
 
 
 
 
 
 
30425 }else if( cli_strcmp(z,"-v")==0 ){
30426 if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
30427 }else if( cli_strcmp(z,"-q")==0 ){
30428 if( faultsim_state.eVerbose>0 ) faultsim_state.eVerbose--;
30429 }else if( cli_strcmp(z,"-id")==0 && kk+1<nArg ){
@@ -30437,19 +31865,20 @@
30437 }else if( cli_strcmp(z,"-skip")==0 && kk+1<nArg ){
30438 faultsim_state.nSkip = atoi(azArg[++kk]);
30439 }else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
30440 bShowHelp = 1;
30441 }else{
30442 eputf("Unrecognized fault_install argument: \"%s\"\n",
 
30443 azArg[kk]);
30444 rc = 1;
30445 bShowHelp = 1;
30446 break;
30447 }
30448 }
30449 if( bShowHelp ){
30450 oputz(
30451 "Usage: .testctrl fault_install ARGS\n"
30452 "Possible arguments:\n"
30453 " off Disable faultsim\n"
30454 " on Activate faultsim\n"
30455 " reset Reset the trigger counter\n"
@@ -30459,23 +31888,25 @@
30459 " --errcode N When triggered, return N as error code\n"
30460 " --id ID Trigger only for the ID specified\n"
30461 " --interval N Trigger only after every N-th call\n"
30462 " --repeat N Turn off after N hits. 0 means never\n"
30463 " --skip N Skip the first N encounters\n"
 
30464 );
30465 }
30466 break;
30467 }
30468 }
30469 }
30470 if( isOk==0 && iCtrl>=0 ){
30471 oputf("Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
 
30472 rc = 1;
30473 }else if( isOk==1 ){
30474 oputf("%d\n", rc2);
30475 }else if( isOk==2 ){
30476 oputf("0x%08x\n", rc2);
30477 }
30478 }else
30479 #endif /* !defined(SQLITE_UNTESTABLE) */
30480
30481 if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){
@@ -30526,17 +31957,17 @@
30526 }
30527 else if( optionMatch(z, "close") ){
30528 mType |= SQLITE_TRACE_CLOSE;
30529 }
30530 else {
30531 eputf("Unknown option \"%s\" on \".trace\"\n", z);
30532 rc = 1;
30533 goto meta_command_exit;
30534 }
30535 }else{
30536 output_file_close(p->traceOut);
30537 p->traceOut = output_file_open(z, 0);
30538 }
30539 }
30540 if( p->traceOut==0 ){
30541 sqlite3_trace_v2(p->db, 0, 0, 0);
30542 }else{
@@ -30569,103 +32000,40 @@
30569 }
30570 }
30571 }else
30572 #endif
30573
30574 #if SQLITE_USER_AUTHENTICATION
30575 if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
30576 if( nArg<2 ){
30577 eputz("Usage: .user SUBCOMMAND ...\n");
30578 rc = 1;
30579 goto meta_command_exit;
30580 }
30581 open_db(p, 0);
30582 if( cli_strcmp(azArg[1],"login")==0 ){
30583 if( nArg!=4 ){
30584 eputz("Usage: .user login USER PASSWORD\n");
30585 rc = 1;
30586 goto meta_command_exit;
30587 }
30588 rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
30589 strlen30(azArg[3]));
30590 if( rc ){
30591 eputf("Authentication failed for user %s\n", azArg[2]);
30592 rc = 1;
30593 }
30594 }else if( cli_strcmp(azArg[1],"add")==0 ){
30595 if( nArg!=5 ){
30596 eputz("Usage: .user add USER PASSWORD ISADMIN\n");
30597 rc = 1;
30598 goto meta_command_exit;
30599 }
30600 rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
30601 booleanValue(azArg[4]));
30602 if( rc ){
30603 eputf("User-Add failed: %d\n", rc);
30604 rc = 1;
30605 }
30606 }else if( cli_strcmp(azArg[1],"edit")==0 ){
30607 if( nArg!=5 ){
30608 eputz("Usage: .user edit USER PASSWORD ISADMIN\n");
30609 rc = 1;
30610 goto meta_command_exit;
30611 }
30612 rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
30613 booleanValue(azArg[4]));
30614 if( rc ){
30615 eputf("User-Edit failed: %d\n", rc);
30616 rc = 1;
30617 }
30618 }else if( cli_strcmp(azArg[1],"delete")==0 ){
30619 if( nArg!=3 ){
30620 eputz("Usage: .user delete USER\n");
30621 rc = 1;
30622 goto meta_command_exit;
30623 }
30624 rc = sqlite3_user_delete(p->db, azArg[2]);
30625 if( rc ){
30626 eputf("User-Delete failed: %d\n", rc);
30627 rc = 1;
30628 }
30629 }else{
30630 eputz("Usage: .user login|add|edit|delete ...\n");
30631 rc = 1;
30632 goto meta_command_exit;
30633 }
30634 }else
30635 #endif /* SQLITE_USER_AUTHENTICATION */
30636
30637 if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
30638 char *zPtrSz = sizeof(void*)==8 ? "64-bit" : "32-bit";
30639 oputf("SQLite %s %s\n" /*extra-version-info*/,
30640 sqlite3_libversion(), sqlite3_sourceid());
30641 #if SQLITE_HAVE_ZLIB
30642 oputf("zlib version %s\n", zlibVersion());
30643 #endif
30644 #define CTIMEOPT_VAL_(opt) #opt
30645 #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
30646 #if defined(__clang__) && defined(__clang_major__)
30647 oputf("clang-" CTIMEOPT_VAL(__clang_major__) "."
30648 CTIMEOPT_VAL(__clang_minor__) "."
30649 CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz);
30650 #elif defined(_MSC_VER)
30651 oputf("msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
30652 #elif defined(__GNUC__) && defined(__VERSION__)
30653 oputf("gcc-" __VERSION__ " (%s)\n", zPtrSz);
30654 #endif
30655 }else
30656
30657 if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){
30658 const char *zDbName = nArg==2 ? azArg[1] : "main";
30659 sqlite3_vfs *pVfs = 0;
30660 if( p->db ){
30661 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
30662 if( pVfs ){
30663 oputf("vfs.zName = \"%s\"\n", pVfs->zName);
30664 oputf("vfs.iVersion = %d\n", pVfs->iVersion);
30665 oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
30666 oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
30667 }
30668 }
30669 }else
30670
30671 if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){
@@ -30673,17 +32041,17 @@
30673 sqlite3_vfs *pCurrent = 0;
30674 if( p->db ){
30675 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
30676 }
30677 for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
30678 oputf("vfs.zName = \"%s\"%s\n", pVfs->zName,
30679 pVfs==pCurrent ? " <--- CURRENT" : "");
30680 oputf("vfs.iVersion = %d\n", pVfs->iVersion);
30681 oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
30682 oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
30683 if( pVfs->pNext ){
30684 oputz("-----------------------------------\n");
30685 }
30686 }
30687 }else
30688
30689 if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
@@ -30690,11 +32058,11 @@
30690 const char *zDbName = nArg==2 ? azArg[1] : "main";
30691 char *zVfsName = 0;
30692 if( p->db ){
30693 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
30694 if( zVfsName ){
30695 oputf("%s\n", zVfsName);
30696 sqlite3_free(zVfsName);
30697 }
30698 }
30699 }else
30700
@@ -30714,11 +32082,11 @@
30714 p->colWidth[j-1] = (int)integerValue(azArg[j]);
30715 }
30716 }else
30717
30718 {
30719 eputf("Error: unknown command or invalid arguments: "
30720 " \"%s\". Enter \".help\" for help\n", azArg[0]);
30721 rc = 1;
30722 }
30723
30724 meta_command_exit:
@@ -30755,11 +32123,10 @@
30755 SCAN_TRACKER_REFTYPE pst){
30756 char cin;
30757 char cWait = (char)qss; /* intentional narrowing loss */
30758 if( cWait==0 ){
30759 PlainScan:
30760 assert( cWait==0 );
30761 while( (cin = *zLine++)!=0 ){
30762 if( IsSpace(cin) )
30763 continue;
30764 switch (cin){
30765 case '-':
@@ -30807,11 +32174,10 @@
30807 switch( cWait ){
30808 case '*':
30809 if( *zLine != '/' )
30810 continue;
30811 ++zLine;
30812 cWait = 0;
30813 CONTINUE_PROMPT_AWAITC(pst, 0);
30814 qss = QSS_SETV(qss, 0);
30815 goto PlainScan;
30816 case '`': case '\'': case '"':
30817 if(*zLine==cWait){
@@ -30819,11 +32185,10 @@
30819 ++zLine;
30820 continue;
30821 }
30822 deliberate_fall_through;
30823 case ']':
30824 cWait = 0;
30825 CONTINUE_PROMPT_AWAITC(pst, 0);
30826 qss = QSS_SETV(qss, 0);
30827 goto PlainScan;
30828 default: assert(0);
30829 }
@@ -30966,11 +32331,11 @@
30966 open_db(p, 0);
30967 if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
30968 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
30969 BEGIN_TIMER;
30970 rc = shell_exec(p, zSql, &zErrMsg);
30971 END_TIMER;
30972 if( rc || zErrMsg ){
30973 char zPrefix[100];
30974 const char *zErrorTail;
30975 const char *zErrorType;
30976 if( zErrMsg==0 ){
@@ -30990,28 +32355,31 @@
30990 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
30991 "%s near line %d:", zErrorType, startline);
30992 }else{
30993 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
30994 }
30995 eputf("%s %s\n", zPrefix, zErrorTail);
30996 sqlite3_free(zErrMsg);
30997 zErrMsg = 0;
30998 return 1;
30999 }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
31000 char zLineBuf[2000];
31001 sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
31002 "changes: %lld total_changes: %lld",
31003 sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
31004 oputf("%s\n", zLineBuf);
31005 }
31006
31007 if( doAutoDetectRestore(p, zSql) ) return 1;
31008 return 0;
31009 }
31010
31011 static void echo_group_input(ShellState *p, const char *zDo){
31012 if( ShellHasFlag(p, SHFLG_Echo) ) oputf("%s\n", zDo);
 
 
 
31013 }
31014
31015 #ifdef SQLITE_SHELL_FIDDLE
31016 /*
31017 ** Alternate one_input_line() impl for wasm mode. This is not in the primary
@@ -31065,11 +32433,11 @@
31065 i64 startline = 0; /* Line number for start of current input */
31066 QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
31067
31068 if( p->inputNesting==MAX_INPUT_NESTING ){
31069 /* This will be more informative in a later version. */
31070 eputf("Input nesting limit (%d) reached at line %d."
31071 " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
31072 return 1;
31073 }
31074 ++p->inputNesting;
31075 p->lineno = 0;
@@ -31077,11 +32445,11 @@
31077 while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
31078 fflush(p->out);
31079 zLine = one_input_line(p->in, zLine, nSql>0);
31080 if( zLine==0 ){
31081 /* End of input */
31082 if( p->in==0 && stdin_is_interactive ) oputz("\n");
31083 break;
31084 }
31085 if( seenInterrupt ){
31086 if( p->in!=0 ) break;
31087 seenInterrupt = 0;
@@ -31297,19 +32665,19 @@
31297 }
31298 zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
31299 shell_check_oom(zBuf);
31300 sqliterc = zBuf;
31301 }
31302 p->in = fopen(sqliterc,"rb");
31303 if( p->in ){
31304 if( stdin_is_interactive ){
31305 eputf("-- Loading resources from %s\n", sqliterc);
31306 }
31307 if( process_input(p) && bail_on_error ) exit(1);
31308 fclose(p->in);
31309 }else if( sqliterc_override!=0 ){
31310 eputf("cannot open: \"%s\"\n", sqliterc);
31311 if( bail_on_error ) exit(1);
31312 }
31313 p->in = inSaved;
31314 p->lineno = savedLineno;
31315 sqlite3_free(zBuf);
@@ -31374,23 +32742,21 @@
31374 " -table set output mode to 'table'\n"
31375 " -tabs set output mode to 'tabs'\n"
31376 " -unsafe-testing allow unsafe commands and modes for testing\n"
31377 " -version show SQLite version\n"
31378 " -vfs NAME use NAME as the default VFS\n"
31379 #ifdef SQLITE_ENABLE_VFSTRACE
31380 " -vfstrace enable tracing of all VFS calls\n"
31381 #endif
31382 #ifdef SQLITE_HAVE_ZLIB
31383 " -zip open the file as a ZIP Archive\n"
31384 #endif
31385 ;
31386 static void usage(int showDetail){
31387 eputf("Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
31388 "FILENAME is the name of an SQLite database. A new database is created\n"
31389 "if the file does not previously exist. Defaults to :memory:.\n", Argv0);
31390 if( showDetail ){
31391 eputf("OPTIONS include:\n%s", zOptions);
31392 }else{
31393 eputz("Use the -help option for additional information\n");
31394 }
31395 exit(0);
31396 }
@@ -31411,10 +32777,13 @@
31411 */
31412 static void main_init(ShellState *data) {
31413 memset(data, 0, sizeof(*data));
31414 data->normalMode = data->cMode = data->mode = MODE_List;
31415 data->autoExplain = 1;
 
 
 
31416 data->pAuxDb = &data->aAuxDb[0];
31417 memcpy(data->colSeparator,SEP_Column, 2);
31418 memcpy(data->rowSeparator,SEP_Row, 2);
31419 data->showHeader = 0;
31420 data->shellFlgs = SHFLG_Lookaside;
@@ -31446,29 +32815,39 @@
31446 SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
31447 #endif
31448 }
31449 #else
31450 static void printBold(const char *zText){
31451 sputf(stdout, "\033[1m%s\033[0m", zText);
31452 }
31453 #endif
31454
31455 /*
31456 ** Get the argument to an --option. Throw an error and die if no argument
31457 ** is available.
31458 */
31459 static char *cmdline_option_value(int argc, char **argv, int i){
31460 if( i==argc ){
31461 eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
 
31462 exit(1);
31463 }
31464 return argv[i];
31465 }
31466
31467 static void sayAbnormalExit(void){
31468 if( seenInterrupt ) eputz("Program interrupted.\n");
31469 }
 
 
 
 
 
 
 
 
 
31470
31471 #ifndef SQLITE_SHELL_IS_UTF8
31472 # if (defined(_WIN32) || defined(WIN32)) \
31473 && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
31474 # define SQLITE_SHELL_IS_UTF8 (0)
@@ -31493,19 +32872,19 @@
31493 char *zErrMsg = 0;
31494 #ifdef SQLITE_SHELL_FIDDLE
31495 # define data shellState
31496 #else
31497 ShellState data;
31498 StreamsAreConsole consStreams = SAC_NoConsole;
31499 #endif
31500 const char *zInitFile = 0;
31501 int i;
31502 int rc = 0;
31503 int warnInmemoryDb = 0;
31504 int readStdin = 1;
31505 int nCmd = 0;
31506 int nOptsEnd = argc;
 
31507 char **azCmd = 0;
31508 const char *zVfs = 0; /* Value of -vfs command-line option */
31509 #if !SQLITE_SHELL_IS_UTF8
31510 char **argvToFree = 0;
31511 int argcToFree = 0;
@@ -31515,25 +32894,29 @@
31515 #ifdef SQLITE_SHELL_FIDDLE
31516 stdin_is_interactive = 0;
31517 stdout_is_console = 1;
31518 data.wasm.zDefaultDbName = "/fiddle.sqlite3";
31519 #else
31520 consStreams = consoleClassifySetup(stdin, stdout, stderr);
31521 stdin_is_interactive = (consStreams & SAC_InConsole)!=0;
31522 stdout_is_console = (consStreams & SAC_OutConsole)!=0;
31523 atexit(consoleRestore);
31524 #endif
31525 atexit(sayAbnormalExit);
31526 #ifdef SQLITE_DEBUG
31527 mem_main_enter = sqlite3_memory_used();
31528 #endif
31529 #if !defined(_WIN32_WCE)
31530 if( getenv("SQLITE_DEBUG_BREAK") ){
31531 if( isatty(0) && isatty(2) ){
31532 eputf("attach debugger to process %d and press any key to continue.\n",
 
 
31533 GETPID());
31534 fgetc(stdin);
 
 
 
 
31535 }else{
31536 #if defined(_WIN32) || defined(WIN32)
31537 #if SQLITE_OS_WINRT
31538 __debugbreak();
31539 #else
@@ -31554,11 +32937,12 @@
31554 }
31555 #endif
31556
31557 #if USE_SYSTEM_SQLITE+0!=1
31558 if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
31559 eputf("SQLite header and source version mismatch\n%s\n%s\n",
 
31560 sqlite3_sourceid(), SQLITE_SOURCE_ID);
31561 exit(1);
31562 }
31563 #endif
31564 main_init(&data);
@@ -31696,21 +33080,12 @@
31696 switch( n ){
31697 case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
31698 case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
31699 default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
31700 }
31701 #ifdef SQLITE_ENABLE_VFSTRACE
31702 }else if( cli_strcmp(z,"-vfstrace")==0 ){
31703 extern int vfstrace_register(
31704 const char *zTraceName,
31705 const char *zOldVfsName,
31706 int (*xOut)(const char*,void*),
31707 void *pOutArg,
31708 int makeDefault
31709 );
31710 vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
31711 #endif
31712 #ifdef SQLITE_ENABLE_MULTIPLEX
31713 }else if( cli_strcmp(z,"-multiplex")==0 ){
31714 extern int sqlite3_multiplex_initialize(const char*,int);
31715 sqlite3_multiplex_initialize(0, 1);
31716 #endif
@@ -31762,11 +33137,11 @@
31762 }else if( cli_strcmp(z,"-safe")==0 ){
31763 /* no-op - catch this on the second pass */
31764 }
31765 }
31766 #ifndef SQLITE_SHELL_FIDDLE
31767 verify_uninitialized();
31768 #endif
31769
31770
31771 #ifdef SQLITE_SHELL_INIT_PROC
31772 {
@@ -31786,25 +33161,29 @@
31786 if( zVfs ){
31787 sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
31788 if( pVfs ){
31789 sqlite3_vfs_register(pVfs, 1);
31790 }else{
31791 eputf("no such VFS: \"%s\"\n", zVfs);
31792 exit(1);
31793 }
31794 }
31795
31796 if( data.pAuxDb->zDbFilename==0 ){
31797 #ifndef SQLITE_OMIT_MEMORYDB
31798 data.pAuxDb->zDbFilename = ":memory:";
31799 warnInmemoryDb = argc==1;
31800 #else
31801 eputf("%s: Error: no database filename specified\n", Argv0);
 
31802 return 1;
31803 #endif
31804 }
31805 data.out = stdout;
 
 
 
31806 #ifndef SQLITE_SHELL_FIDDLE
31807 sqlite3_appendvfs_init(0,0,0);
31808 #endif
31809
31810 /* Go ahead and open the database file if it already exists. If the
@@ -31913,11 +33292,11 @@
31913 */
31914 ShellSetFlag(&data, SHFLG_Backslash);
31915 }else if( cli_strcmp(z,"-bail")==0 ){
31916 /* No-op. The bail_on_error flag should already be set. */
31917 }else if( cli_strcmp(z,"-version")==0 ){
31918 sputf(stdout, "%s %s (%d-bit)\n",
31919 sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
31920 return 0;
31921 }else if( cli_strcmp(z,"-interactive")==0 ){
31922 /* Need to check for interactive override here to so that it can
31923 ** affect console setup (for Windows only) and testing thereof.
@@ -31951,14 +33330,12 @@
31951 }else if( cli_strcmp(z,"-sorterref")==0 ){
31952 i++;
31953 #endif
31954 }else if( cli_strcmp(z,"-vfs")==0 ){
31955 i++;
31956 #ifdef SQLITE_ENABLE_VFSTRACE
31957 }else if( cli_strcmp(z,"-vfstrace")==0 ){
31958 i++;
31959 #endif
31960 #ifdef SQLITE_ENABLE_MULTIPLEX
31961 }else if( cli_strcmp(z,"-multiplex")==0 ){
31962 i++;
31963 #endif
31964 }else if( cli_strcmp(z,"-help")==0 ){
@@ -31978,18 +33355,18 @@
31978 rc = shell_exec(&data, z, &zErrMsg);
31979 if( zErrMsg!=0 ){
31980 shellEmitError(zErrMsg);
31981 if( bail_on_error ) return rc!=0 ? rc : 1;
31982 }else if( rc!=0 ){
31983 eputf("Error: unable to process SQL \"%s\"\n", z);
31984 if( bail_on_error ) return rc;
31985 }
31986 }
31987 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
31988 }else if( cli_strncmp(z, "-A", 2)==0 ){
31989 if( nCmd>0 ){
31990 eputf("Error: cannot mix regular SQL or dot-commands"
31991 " with \"%s\"\n", z);
31992 return 1;
31993 }
31994 open_db(&data, OPEN_DB_ZIPFILE);
31995 if( z[2] ){
@@ -32004,11 +33381,11 @@
32004 }else if( cli_strcmp(z,"-safe")==0 ){
32005 data.bSafeMode = data.bSafeModePersist = 1;
32006 }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
32007 /* Acted upon in first pass. */
32008 }else{
32009 eputf("%s: Error: unknown option: %s\n", Argv0, z);
32010 eputz("Use -help for a list of options.\n");
32011 return 1;
32012 }
32013 data.cMode = data.mode;
32014 }
@@ -32031,11 +33408,12 @@
32031 rc = shell_exec(&data, azCmd[i], &zErrMsg);
32032 if( zErrMsg || rc ){
32033 if( zErrMsg!=0 ){
32034 shellEmitError(zErrMsg);
32035 }else{
32036 eputf("Error: unable to process SQL: %s\n", azCmd[i]);
 
32037 }
32038 sqlite3_free(zErrMsg);
32039 if( rc==0 ) rc = 1;
32040 goto shell_main_exit;
32041 }
@@ -32046,18 +33424,14 @@
32046 */
32047 if( stdin_is_interactive ){
32048 char *zHome;
32049 char *zHistory;
32050 int nHistory;
32051 #if CIO_WIN_WC_XLATE
32052 # define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
32053 #else
32054 # define SHELL_CIO_CHAR_SET ""
32055 #endif
32056 sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
32057 "Enter \".help\" for usage hints.\n",
32058 sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
32059 if( warnInmemoryDb ){
32060 sputz(stdout, "Connected to a ");
32061 printBold("transient in-memory database");
32062 sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
32063 " persistent database.\n");
@@ -32070,13 +33444,15 @@
32070 if( (zHistory = malloc(nHistory))!=0 ){
32071 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
32072 }
32073 }
32074 if( zHistory ){ shell_read_history(zHistory); }
32075 #if HAVE_READLINE || HAVE_EDITLINE
32076 rl_attempted_completion_function = readline_completion;
32077 #elif HAVE_LINENOISE
 
 
32078 linenoiseSetCompletionCallback(linenoise_completion, NULL);
32079 #endif
32080 data.in = 0;
32081 rc = process_input(&data);
32082 if( zHistory ){
@@ -32122,13 +33498,16 @@
32122 free(data.colWidth);
32123 free(data.zNonce);
32124 /* Clear the global data structure so that valgrind will detect memory
32125 ** leaks */
32126 memset(&data, 0, sizeof(data));
 
 
 
32127 #ifdef SQLITE_DEBUG
32128 if( sqlite3_memory_used()>mem_main_enter ){
32129 eputf("Memory leaked: %u bytes\n",
32130 (unsigned int)(sqlite3_memory_used()-mem_main_enter));
32131 }
32132 #endif
32133 #else /* SQLITE_SHELL_FIDDLE... */
32134 shell_main_exit:
@@ -32164,11 +33543,11 @@
32164 return pVfs;
32165 }
32166
32167 /* Only for emcc experimentation purposes. */
32168 sqlite3 * fiddle_db_arg(sqlite3 *arg){
32169 oputf("fiddle_db_arg(%p)\n", (const void*)arg);
32170 return arg;
32171 }
32172
32173 /*
32174 ** Intended to be called via a SharedWorker() while a separate
@@ -32201,11 +33580,11 @@
32201 while( sqlite3_txn_state(globalDb,0)>0 ){
32202 /*
32203 ** Resolve problem reported in
32204 ** https://sqlite.org/forum/forumpost/0b41a25d65
32205 */
32206 oputz("Rolling back in-progress transaction.\n");
32207 sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0);
32208 }
32209 rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
32210 if( 0==rc ) sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
32211 sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
32212
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -120,13 +120,10 @@
120 #include <math.h>
121 #include "sqlite3.h"
122 typedef sqlite3_int64 i64;
123 typedef sqlite3_uint64 u64;
124 typedef unsigned char u8;
 
 
 
125 #include <ctype.h>
126 #include <stdarg.h>
127
128 #if !defined(_WIN32) && !defined(WIN32)
129 # include <signal.h>
@@ -208,12 +205,10 @@
205 # define unlink _unlink
206 # endif
207 # ifndef strdup
208 # define strdup _strdup
209 # endif
 
 
210 # undef pclose
211 # define pclose _pclose
212 # endif
213 #else
214 /* Make sure isatty() has a prototype. */
@@ -253,10 +248,370 @@
248 /* string conversion routines only needed on Win32 */
249 extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
250 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
251 #endif
252
253 /************************* Begin ../ext/misc/sqlite3_stdio.h ******************/
254 /*
255 ** 2024-09-24
256 **
257 ** The author disclaims copyright to this source code. In place of
258 ** a legal notice, here is a blessing:
259 **
260 ** May you do good and not evil.
261 ** May you find forgiveness for yourself and forgive others.
262 ** May you share freely, never taking more than you give.
263 **
264 *************************************************************************
265 **
266 ** This header file contains definitions of interfaces that provide
267 ** cross-platform I/O for UTF-8 content.
268 **
269 ** On most platforms, the interfaces definitions in this file are
270 ** just #defines. For example sqlite3_fopen() is a macro that resolves
271 ** to the standard fopen() in the C-library.
272 **
273 ** But Windows does not have a standard C-library, at least not one that
274 ** can handle UTF-8. So for windows build, the interfaces resolve to new
275 ** C-language routines contained in the separate sqlite3_stdio.c source file.
276 **
277 ** So on all non-Windows platforms, simply #include this header file and
278 ** use the interfaces defined herein. Then to run your application on Windows,
279 ** also link in the accompanying sqlite3_stdio.c source file when compiling
280 ** to get compatible interfaces.
281 */
282 #ifndef _SQLITE3_STDIO_H_
283 #define _SQLITE3_STDIO_H_ 1
284 #ifdef _WIN32
285 /**** Definitions For Windows ****/
286 #include <stdio.h>
287 #include <windows.h>
288
289 FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
290 FILE *sqlite3_popen(const char *zCommand, const char *type);
291 char *sqlite3_fgets(char *s, int size, FILE *stream);
292 int sqlite3_fputs(const char *s, FILE *stream);
293 int sqlite3_fprintf(FILE *stream, const char *format, ...);
294 void sqlite3_fsetmode(FILE *stream, int mode);
295
296
297 #else
298 /**** Definitions For All Other Platforms ****/
299 #include <stdio.h>
300 #define sqlite3_fopen fopen
301 #define sqlite3_popen popen
302 #define sqlite3_fgets fgets
303 #define sqlite3_fputs fputs
304 #define sqlite3_fprintf fprintf
305 #define sqlite3_fsetmode(F,X) /*no-op*/
306
307 #endif
308 #endif /* _SQLITE3_STDIO_H_ */
309
310 /************************* End ../ext/misc/sqlite3_stdio.h ********************/
311 /************************* Begin ../ext/misc/sqlite3_stdio.c ******************/
312 /*
313 ** 2024-09-24
314 **
315 ** The author disclaims copyright to this source code. In place of
316 ** a legal notice, here is a blessing:
317 **
318 ** May you do good and not evil.
319 ** May you find forgiveness for yourself and forgive others.
320 ** May you share freely, never taking more than you give.
321 **
322 *************************************************************************
323 **
324 ** Implementation of standard I/O interfaces for UTF-8 that are missing
325 ** on Windows.
326 */
327 #ifdef _WIN32 /* This file is a no-op on all platforms except Windows */
328 #ifndef _SQLITE3_STDIO_H_
329 /* #include "sqlite3_stdio.h" */
330 #endif
331 #undef WIN32_LEAN_AND_MEAN
332 #define WIN32_LEAN_AND_MEAN
333 #include <windows.h>
334 #include <stdlib.h>
335 #include <string.h>
336 #include <stdio.h>
337 #include <assert.h>
338 /* #include "sqlite3.h" */
339 #include <ctype.h>
340 #include <stdarg.h>
341 #include <io.h>
342 #include <fcntl.h>
343
344 /*
345 ** If the SQLITE_U8TEXT_ONLY option is defined, then use O_U8TEXT
346 ** when appropriate on all output. (Sometimes use O_BINARY when
347 ** rendering ASCII text in cases where NL-to-CRLF expansion would
348 ** not be correct.)
349 **
350 ** If the SQLITE_U8TEXT_STDIO option is defined, then use O_U8TEXT
351 ** when appropriate when writing to stdout or stderr. Use O_BINARY
352 ** or O_TEXT (depending on things like the .mode and the .crlf setting
353 ** in the CLI, or other context clues in other applications) for all
354 ** other output channels.
355 **
356 ** The default behavior, if neither of the above is defined is to
357 ** use O_U8TEXT when writing to the Windows console (or anything
358 ** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
359 ** for all other output channels.
360 */
361 #if defined(SQLITE_U8TEXT_ONLY)
362 # define UseWtextForOutput(fd) 1
363 # define UseWtextForInput(fd) 1
364 # define IsConsole(fd) _isatty(_fileno(fd))
365 #elif defined(SQLITE_U8TEXT_STDIO)
366 # define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr)
367 # define UseWtextForInput(fd) ((fd)==stdin)
368 # define IsConsole(fd) _isatty(_fileno(fd))
369 #else
370 # define UseWtextForOutput(fd) _isatty(_fileno(fd))
371 # define UseWtextForInput(fd) _isatty(_fileno(fd))
372 # define IsConsole(fd) 1
373 #endif
374
375 /*
376 ** Global variables determine if simulated O_BINARY mode is to be
377 ** used for stdout or other, respectively. Simulated O_BINARY mode
378 ** means the mode is usually O_BINARY, but switches to O_U8TEXT for
379 ** unicode characters U+0080 or greater (any character that has a
380 ** multi-byte representation in UTF-8). This is the only way we
381 ** have found to render Unicode characters on a Windows console while
382 ** at the same time avoiding undesirable \n to \r\n translation.
383 */
384 static int simBinaryStdout = 0;
385 static int simBinaryOther = 0;
386
387
388 /*
389 ** Determine if simulated binary mode should be used for output to fd
390 */
391 static int UseBinaryWText(FILE *fd){
392 if( fd==stdout || fd==stderr ){
393 return simBinaryStdout;
394 }else{
395 return simBinaryOther;
396 }
397 }
398
399
400 /*
401 ** Work-alike for the fopen() routine from the standard C library.
402 */
403 FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
404 FILE *fp = 0;
405 wchar_t *b1, *b2;
406 int sz1, sz2;
407
408 sz1 = (int)strlen(zFilename);
409 sz2 = (int)strlen(zMode);
410 b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
411 b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
412 if( b1 && b2 ){
413 sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
414 b1[sz1] = 0;
415 sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
416 b2[sz2] = 0;
417 fp = _wfopen(b1, b2);
418 }
419 sqlite3_free(b1);
420 sqlite3_free(b2);
421 simBinaryOther = 0;
422 return fp;
423 }
424
425
426 /*
427 ** Work-alike for the popen() routine from the standard C library.
428 */
429 FILE *sqlite3_popen(const char *zCommand, const char *zMode){
430 FILE *fp = 0;
431 wchar_t *b1, *b2;
432 int sz1, sz2;
433
434 sz1 = (int)strlen(zCommand);
435 sz2 = (int)strlen(zMode);
436 b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
437 b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
438 if( b1 && b2 ){
439 sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
440 b1[sz1] = 0;
441 sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
442 b2[sz2] = 0;
443 fp = _wpopen(b1, b2);
444 }
445 sqlite3_free(b1);
446 sqlite3_free(b2);
447 return fp;
448 }
449
450 /*
451 ** Work-alike for fgets() from the standard C library.
452 */
453 char *sqlite3_fgets(char *buf, int sz, FILE *in){
454 if( UseWtextForInput(in) ){
455 /* When reading from the command-prompt in Windows, it is necessary
456 ** to use _O_WTEXT input mode to read UTF-16 characters, then translate
457 ** that into UTF-8. Otherwise, non-ASCII characters all get translated
458 ** into '?'.
459 */
460 wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
461 if( b1==0 ) return 0;
462 #ifndef SQLITE_USE_STDIO_FOR_CONSOLE
463 DWORD nRead = 0;
464 if( IsConsole(in)
465 && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz, &nRead, 0)
466 ){
467 b1[nRead] = 0;
468 }else
469 #endif
470 {
471 _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
472 if( fgetws(b1, sz/4, in)==0 ){
473 sqlite3_free(b1);
474 return 0;
475 }
476 }
477 WideCharToMultiByte(CP_UTF8, 0, b1, -1, buf, sz, 0, 0);
478 sqlite3_free(b1);
479 return buf;
480 }else{
481 /* Reading from a file or other input source, just read bytes without
482 ** any translation. */
483 return fgets(buf, sz, in);
484 }
485 }
486
487 /*
488 ** Send ASCII text as O_BINARY. But for Unicode characters U+0080 and
489 ** greater, switch to O_U8TEXT.
490 */
491 static void piecemealOutput(wchar_t *b1, int sz, FILE *out){
492 int i;
493 wchar_t c;
494 while( sz>0 ){
495 for(i=0; i<sz && b1[i]>=0x80; i++){}
496 if( i>0 ){
497 c = b1[i];
498 b1[i] = 0;
499 fflush(out);
500 _setmode(_fileno(out), _O_U8TEXT);
501 fputws(b1, out);
502 fflush(out);
503 b1 += i;
504 b1[0] = c;
505 sz -= i;
506 }else{
507 fflush(out);
508 _setmode(_fileno(out), _O_TEXT);
509 _setmode(_fileno(out), _O_BINARY);
510 fwrite(&b1[0], 1, 1, out);
511 for(i=1; i<sz && b1[i]<0x80; i++){
512 fwrite(&b1[i], 1, 1, out);
513 }
514 fflush(out);
515 _setmode(_fileno(out), _O_U8TEXT);
516 b1 += i;
517 sz -= i;
518 }
519 }
520 }
521
522 /*
523 ** Work-alike for fputs() from the standard C library.
524 */
525 int sqlite3_fputs(const char *z, FILE *out){
526 if( !UseWtextForOutput(out) ){
527 /* Writing to a file or other destination, just write bytes without
528 ** any translation. */
529 return fputs(z, out);
530 }else{
531 /* One must use UTF16 in order to get unicode support when writing
532 ** to the console on Windows.
533 */
534 int sz = (int)strlen(z);
535 wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
536 if( b1==0 ) return 0;
537 sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
538 b1[sz] = 0;
539
540 #ifndef SQLITE_STDIO_FOR_CONSOLE
541 DWORD nWr = 0;
542 if( IsConsole(out)
543 && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
544 ){
545 /* If writing to the console, then the WriteConsoleW() is all we
546 ** need to do. */
547 }else
548 #endif
549 {
550 /* For non-console I/O, or if SQLITE_USE_STDIO_FOR_CONSOLE is defined
551 ** then write using the standard library. */
552 _setmode(_fileno(out), _O_U8TEXT);
553 if( UseBinaryWText(out) ){
554 piecemealOutput(b1, sz, out);
555 }else{
556 fputws(b1, out);
557 }
558 }
559 sqlite3_free(b1);
560 return 0;
561 }
562 }
563
564
565 /*
566 ** Work-alike for fprintf() from the standard C library.
567 */
568 int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
569 int rc;
570 if( UseWtextForOutput(out) ){
571 /* When writing to the command-prompt in Windows, it is necessary
572 ** to use _O_WTEXT input mode and write UTF-16 characters.
573 */
574 char *z;
575 va_list ap;
576
577 va_start(ap, zFormat);
578 z = sqlite3_vmprintf(zFormat, ap);
579 va_end(ap);
580 sqlite3_fputs(z, out);
581 rc = (int)strlen(z);
582 sqlite3_free(z);
583 }else{
584 /* Writing to a file or other destination, just write bytes without
585 ** any translation. */
586 va_list ap;
587 va_start(ap, zFormat);
588 rc = vfprintf(out, zFormat, ap);
589 va_end(ap);
590 }
591 return rc;
592 }
593
594 /*
595 ** Set the mode for an output stream. mode argument is typically _O_BINARY or
596 ** _O_TEXT.
597 */
598 void sqlite3_fsetmode(FILE *fp, int mode){
599 if( !UseWtextForOutput(fp) ){
600 fflush(fp);
601 _setmode(_fileno(fp), mode);
602 }else if( fp==stdout || fp==stderr ){
603 simBinaryStdout = (mode==_O_BINARY);
604 }else{
605 simBinaryOther = (mode==_O_BINARY);
606 }
607 }
608
609 #endif /* defined(_WIN32) */
610
611 /************************* End ../ext/misc/sqlite3_stdio.c ********************/
612
613 /* Use console I/O package as a direct INCLUDE. */
614 #define SQLITE_INTERNAL_LINKAGE static
615
616 #ifdef SQLITE_SHELL_FIDDLE
617 /* Deselect most features from the console I/O package for Fiddle. */
@@ -264,1118 +619,13 @@
619 # define SQLITE_CIO_NO_CLASSIFY
620 # define SQLITE_CIO_NO_TRANSLATE
621 # define SQLITE_CIO_NO_SETMODE
622 # define SQLITE_CIO_NO_FLUSH
623 #endif
624
625 #define eputz(z) sqlite3_fputs(z,stderr)
626 #define sputz(fp,z) sqlite3_fputs(z,fp)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
628 /* True if the timer is enabled */
629 static int enableTimer = 0;
630
631 /* A version of strcmp() that works with NULL values */
@@ -1416,10 +666,11 @@
666 struct timeval ru_utime; /* user CPU time used */
667 struct timeval ru_stime; /* system CPU time used */
668 };
669 #define getrusage(A,B) memset(B,0,sizeof(*B))
670 #endif
671
672
673 /* Saved resource information for the beginning of an operation */
674 static struct rusage sBegin; /* CPU time at start */
675 static sqlite3_int64 iBegin; /* Wall-clock time at start */
676
@@ -1440,24 +691,24 @@
691 }
692
693 /*
694 ** Print the timing results.
695 */
696 static void endTimer(FILE *out){
697 if( enableTimer ){
698 sqlite3_int64 iEnd = timeOfDay();
699 struct rusage sEnd;
700 getrusage(RUSAGE_SELF, &sEnd);
701 sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
702 (iEnd - iBegin)*0.001,
703 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
704 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
705 }
706 }
707
708 #define BEGIN_TIMER beginTimer()
709 #define END_TIMER(X) endTimer(X)
710 #define HAS_TIMER 1
711
712 #elif (defined(_WIN32) || defined(WIN32))
713
714 /* Saved resource information for the beginning of an operation */
@@ -1519,29 +770,29 @@
770 }
771
772 /*
773 ** Print the timing results.
774 */
775 static void endTimer(FILE *out){
776 if( enableTimer && getProcessTimesAddr){
777 FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
778 sqlite3_int64 ftWallEnd = timeOfDay();
779 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
780 sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
781 (ftWallEnd - ftWallBegin)*0.001,
782 timeDiff(&ftUserBegin, &ftUserEnd),
783 timeDiff(&ftKernelBegin, &ftKernelEnd));
784 }
785 }
786
787 #define BEGIN_TIMER beginTimer()
788 #define END_TIMER(X) endTimer(X)
789 #define HAS_TIMER hasTimer()
790
791 #else
792 #define BEGIN_TIMER
793 #define END_TIMER(X) /*no-op*/
794 #define HAS_TIMER 0
795 #endif
796
797 /*
798 ** Used to prevent warnings about unused parameters
@@ -1738,41 +989,216 @@
989 char *z;
990 if( iotrace==0 ) return;
991 va_start(ap, zFormat);
992 z = sqlite3_vmprintf(zFormat, ap);
993 va_end(ap);
994 sqlite3_fprintf(iotrace, "%s", z);
995 sqlite3_free(z);
996 }
997 #endif
998
999 /* Lookup table to estimate the number of columns consumed by a Unicode
1000 ** character.
1001 */
1002 static const struct {
1003 unsigned char w; /* Width of the character in columns */
1004 int iFirst; /* First character in a span having this width */
1005 } aUWidth[] = {
1006 /* {1, 0x00000}, */
1007 {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488},
1008 {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0},
1009 {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7},
1010 {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616},
1011 {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6},
1012 {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee},
1013 {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730},
1014 {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4},
1015 {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941},
1016 {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955},
1017 {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc},
1018 {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce},
1019 {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c},
1020 {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49},
1021 {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81},
1022 {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6},
1023 {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2},
1024 {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d},
1025 {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d},
1026 {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83},
1027 {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e},
1028 {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e},
1029 {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf},
1030 {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce},
1031 {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d},
1032 {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5},
1033 {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34},
1034 {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2},
1035 {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8},
1036 {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36},
1037 {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71},
1038 {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
1039 {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
1040 {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
1041 {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
1042 {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
1043 {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
1044 {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
1045 {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7},
1046 {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b},
1047 {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923},
1048 {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939},
1049 {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04},
1050 {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c},
1051 {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74},
1052 {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b},
1053 {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064},
1054 {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329},
1055 {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f},
1056 {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806},
1057 {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827},
1058 {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e},
1059 {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20},
1060 {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00},
1061 {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc},
1062 {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c},
1063 {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40},
1064 {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185},
1065 {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245},
1066 {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001},
1067 {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0}
1068 };
1069
1070 /*
1071 ** Return an estimate of the width, in columns, for the single Unicode
1072 ** character c. For normal characters, the answer is always 1. But the
1073 ** estimate might be 0 or 2 for zero-width and double-width characters.
1074 **
1075 ** Different display devices display unicode using different widths. So
1076 ** it is impossible to know that true display width with 100% accuracy.
1077 ** Inaccuracies in the width estimates might cause columns to be misaligned.
1078 ** Unfortunately, there is nothing we can do about that.
1079 */
1080 int cli_wcwidth(int c){
1081 int iFirst, iLast;
1082
1083 /* Fast path for common characters */
1084 if( c<=0x300 ) return 1;
1085
1086 /* The general case */
1087 iFirst = 0;
1088 iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1;
1089 while( iFirst<iLast-1 ){
1090 int iMid = (iFirst+iLast)/2;
1091 int cMid = aUWidth[iMid].iFirst;
1092 if( cMid < c ){
1093 iFirst = iMid;
1094 }else if( cMid > c ){
1095 iLast = iMid - 1;
1096 }else{
1097 return aUWidth[iMid].w;
1098 }
1099 }
1100 if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w;
1101 return aUWidth[iLast].w;
1102 }
1103
1104 /*
1105 ** Compute the value and length of a multi-byte UTF-8 character that
1106 ** begins at z[0]. Return the length. Write the Unicode value into *pU.
1107 **
1108 ** This routine only works for *multi-byte* UTF-8 characters.
1109 */
1110 static int decodeUtf8(const unsigned char *z, int *pU){
1111 if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){
1112 *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f);
1113 return 2;
1114 }
1115 if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){
1116 *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f);
1117 return 3;
1118 }
1119 if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80
1120 && (z[3] & 0xc0)==0x80
1121 ){
1122 *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6
1123 | (z[4] & 0x3f);
1124 return 4;
1125 }
1126 *pU = 0;
1127 return 1;
1128 }
1129
1130
1131 #if 0 /* NOT USED */
1132 /*
1133 ** Return the width, in display columns, of a UTF-8 string.
1134 **
1135 ** Each normal character counts as 1. Zero-width characters count
1136 ** as zero, and double-width characters count as 2.
1137 */
1138 int cli_wcswidth(const char *z){
1139 const unsigned char *a = (const unsigned char*)z;
1140 int n = 0;
1141 int i = 0;
1142 unsigned char c;
1143 while( (c = a[i])!=0 ){
1144 if( c>=0xc0 ){
1145 int u;
1146 int len = decodeUtf8(&a[i], &u);
1147 i += len;
1148 n += cli_wcwidth(u);
1149 }else if( c>=' ' ){
1150 n++;
1151 i++;
1152 }else{
1153 i++;
1154 }
1155 }
1156 return n;
1157 }
1158 #endif
1159
1160 /*
1161 ** Output string zUtf to stdout as w characters. If w is negative,
1162 ** then right-justify the text. W is the width in UTF-8 characters, not
1163 ** in bytes. This is different from the %*.*s specification in printf
1164 ** since with %*.*s the width is measured in bytes, not characters.
1165 **
1166 ** Take into account zero-width and double-width Unicode characters.
1167 ** In other words, a zero-width character does not count toward the
1168 ** the w limit. A double-width character counts as two.
1169 */
1170 static void utf8_width_print(FILE *out, int w, const char *zUtf){
1171 const unsigned char *a = (const unsigned char*)zUtf;
1172 unsigned char c;
1173 int i = 0;
1174 int n = 0;
1175 int aw = w<0 ? -w : w;
1176 if( zUtf==0 ) zUtf = "";
1177 while( (c = a[i])!=0 ){
1178 if( (c&0xc0)==0xc0 ){
1179 int u;
1180 int len = decodeUtf8(a+i, &u);
1181 int x = cli_wcwidth(u);
1182 if( x+n>aw ){
1183 break;
1184 }
1185 i += len;
1186 n += x;
1187 }else if( n>=aw ){
1188 break;
1189 }else{
1190 n++;
1191 i++;
 
 
 
1192 }
1193 }
1194 if( n>=aw ){
1195 sqlite3_fprintf(out, "%.*s", i, zUtf);
1196 }else if( w<0 ){
1197 sqlite3_fprintf(out, "%*s%s", aw-n, "", zUtf);
1198 }else{
1199 sqlite3_fprintf(out, "%s%*s", zUtf, aw-n, "");
1200 }
1201 }
1202
1203
1204 /*
@@ -1834,11 +1260,11 @@
1260 struct __stat64 x = {0};
1261 # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
1262 /* On Windows, open first, then check the stream nature. This order
1263 ** is necessary because _stat() and sibs, when checking a named pipe,
1264 ** effectively break the pipe as its supplier sees it. */
1265 FILE *rv = sqlite3_fopen(zFile, "rb");
1266 if( rv==0 ) return 0;
1267 if( _fstat64(_fileno(rv), &x) != 0
1268 || !STAT_CHR_SRC(x.st_mode)){
1269 fclose(rv);
1270 rv = 0;
@@ -1848,11 +1274,11 @@
1274 struct stat x = {0};
1275 int rc = stat(zFile, &x);
1276 # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
1277 if( rc!=0 ) return 0;
1278 if( STAT_CHR_SRC(x.st_mode) ){
1279 return sqlite3_fopen(zFile, "rb");
1280 }else{
1281 return 0;
1282 }
1283 #endif
1284 #undef STAT_CHR_SRC
@@ -1875,11 +1301,11 @@
1301 if( n+100>nLine ){
1302 nLine = nLine*2 + 100;
1303 zLine = realloc(zLine, nLine);
1304 shell_check_oom(zLine);
1305 }
1306 if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
1307 if( n==0 ){
1308 free(zLine);
1309 return 0;
1310 }
1311 zLine[n] = 0;
@@ -2941,11 +2367,11 @@
2367 **
2368 ******************************************************************************
2369 **
2370 ** This SQLite extension implements functions that compute SHA3 hashes
2371 ** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
2372 ** Three SQL functions are implemented:
2373 **
2374 ** sha3(X,SIZE)
2375 ** sha3_agg(Y,SIZE)
2376 ** sha3_query(Z,SIZE)
2377 **
@@ -3783,10 +3209,422 @@
3209 }
3210 return rc;
3211 }
3212
3213 /************************* End ../ext/misc/shathree.c ********************/
3214 /************************* Begin ../ext/misc/sha1.c ******************/
3215 /*
3216 ** 2017-01-27
3217 **
3218 ** The author disclaims copyright to this source code. In place of
3219 ** a legal notice, here is a blessing:
3220 **
3221 ** May you do good and not evil.
3222 ** May you find forgiveness for yourself and forgive others.
3223 ** May you share freely, never taking more than you give.
3224 **
3225 ******************************************************************************
3226 **
3227 ** This SQLite extension implements functions that compute SHA1 hashes.
3228 ** Two SQL functions are implemented:
3229 **
3230 ** sha1(X)
3231 ** sha1_query(Y)
3232 **
3233 ** The sha1(X) function computes the SHA1 hash of the input X, or NULL if
3234 ** X is NULL.
3235 **
3236 ** The sha1_query(Y) function evalutes all queries in the SQL statements of Y
3237 ** and returns a hash of their results.
3238 */
3239 /* #include "sqlite3ext.h" */
3240 SQLITE_EXTENSION_INIT1
3241 #include <assert.h>
3242 #include <string.h>
3243 #include <stdarg.h>
3244
3245 /******************************************************************************
3246 ** The Hash Engine
3247 */
3248 /* Context for the SHA1 hash */
3249 typedef struct SHA1Context SHA1Context;
3250 struct SHA1Context {
3251 unsigned int state[5];
3252 unsigned int count[2];
3253 unsigned char buffer[64];
3254 };
3255
3256 #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
3257 #define rol(x,k) SHA_ROT(x,k,32-(k))
3258 #define ror(x,k) SHA_ROT(x,32-(k),k)
3259
3260 #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
3261 |(rol(block[i],8)&0x00FF00FF))
3262 #define blk0be(i) block[i]
3263 #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
3264 ^block[(i+2)&15]^block[i&15],1))
3265
3266 /*
3267 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
3268 *
3269 * Rl0() for little-endian and Rb0() for big-endian. Endianness is
3270 * determined at run-time.
3271 */
3272 #define Rl0(v,w,x,y,z,i) \
3273 z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
3274 #define Rb0(v,w,x,y,z,i) \
3275 z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
3276 #define R1(v,w,x,y,z,i) \
3277 z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
3278 #define R2(v,w,x,y,z,i) \
3279 z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
3280 #define R3(v,w,x,y,z,i) \
3281 z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
3282 #define R4(v,w,x,y,z,i) \
3283 z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
3284
3285 /*
3286 * Hash a single 512-bit block. This is the core of the algorithm.
3287 */
3288 static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
3289 unsigned int qq[5]; /* a, b, c, d, e; */
3290 static int one = 1;
3291 unsigned int block[16];
3292 memcpy(block, buffer, 64);
3293 memcpy(qq,state,5*sizeof(unsigned int));
3294
3295 #define a qq[0]
3296 #define b qq[1]
3297 #define c qq[2]
3298 #define d qq[3]
3299 #define e qq[4]
3300
3301 /* Copy p->state[] to working vars */
3302 /*
3303 a = state[0];
3304 b = state[1];
3305 c = state[2];
3306 d = state[3];
3307 e = state[4];
3308 */
3309
3310 /* 4 rounds of 20 operations each. Loop unrolled. */
3311 if( 1 == *(unsigned char*)&one ){
3312 Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
3313 Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
3314 Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
3315 Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
3316 }else{
3317 Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
3318 Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
3319 Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
3320 Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
3321 }
3322 R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
3323 R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
3324 R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
3325 R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
3326 R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
3327 R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
3328 R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
3329 R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
3330 R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
3331 R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
3332 R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
3333 R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
3334 R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
3335 R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
3336 R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
3337 R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
3338
3339 /* Add the working vars back into context.state[] */
3340 state[0] += a;
3341 state[1] += b;
3342 state[2] += c;
3343 state[3] += d;
3344 state[4] += e;
3345
3346 #undef a
3347 #undef b
3348 #undef c
3349 #undef d
3350 #undef e
3351 }
3352
3353
3354 /* Initialize a SHA1 context */
3355 static void hash_init(SHA1Context *p){
3356 /* SHA1 initialization constants */
3357 p->state[0] = 0x67452301;
3358 p->state[1] = 0xEFCDAB89;
3359 p->state[2] = 0x98BADCFE;
3360 p->state[3] = 0x10325476;
3361 p->state[4] = 0xC3D2E1F0;
3362 p->count[0] = p->count[1] = 0;
3363 }
3364
3365 /* Add new content to the SHA1 hash */
3366 static void hash_step(
3367 SHA1Context *p, /* Add content to this context */
3368 const unsigned char *data, /* Data to be added */
3369 unsigned int len /* Number of bytes in data */
3370 ){
3371 unsigned int i, j;
3372
3373 j = p->count[0];
3374 if( (p->count[0] += len << 3) < j ){
3375 p->count[1] += (len>>29)+1;
3376 }
3377 j = (j >> 3) & 63;
3378 if( (j + len) > 63 ){
3379 (void)memcpy(&p->buffer[j], data, (i = 64-j));
3380 SHA1Transform(p->state, p->buffer);
3381 for(; i + 63 < len; i += 64){
3382 SHA1Transform(p->state, &data[i]);
3383 }
3384 j = 0;
3385 }else{
3386 i = 0;
3387 }
3388 (void)memcpy(&p->buffer[j], &data[i], len - i);
3389 }
3390
3391 /* Compute a string using sqlite3_vsnprintf() and hash it */
3392 static void hash_step_vformat(
3393 SHA1Context *p, /* Add content to this context */
3394 const char *zFormat,
3395 ...
3396 ){
3397 va_list ap;
3398 int n;
3399 char zBuf[50];
3400 va_start(ap, zFormat);
3401 sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
3402 va_end(ap);
3403 n = (int)strlen(zBuf);
3404 hash_step(p, (unsigned char*)zBuf, n);
3405 }
3406
3407
3408 /* Add padding and compute the message digest. Render the
3409 ** message digest as lower-case hexadecimal and put it into
3410 ** zOut[]. zOut[] must be at least 41 bytes long. */
3411 static void hash_finish(
3412 SHA1Context *p, /* The SHA1 context to finish and render */
3413 char *zOut, /* Store hex or binary hash here */
3414 int bAsBinary /* 1 for binary hash, 0 for hex hash */
3415 ){
3416 unsigned int i;
3417 unsigned char finalcount[8];
3418 unsigned char digest[20];
3419 static const char zEncode[] = "0123456789abcdef";
3420
3421 for (i = 0; i < 8; i++){
3422 finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
3423 >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
3424 }
3425 hash_step(p, (const unsigned char *)"\200", 1);
3426 while ((p->count[0] & 504) != 448){
3427 hash_step(p, (const unsigned char *)"\0", 1);
3428 }
3429 hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
3430 for (i = 0; i < 20; i++){
3431 digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
3432 }
3433 if( bAsBinary ){
3434 memcpy(zOut, digest, 20);
3435 }else{
3436 for(i=0; i<20; i++){
3437 zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
3438 zOut[i*2+1] = zEncode[digest[i] & 0xf];
3439 }
3440 zOut[i*2]= 0;
3441 }
3442 }
3443 /* End of the hashing logic
3444 *****************************************************************************/
3445
3446 /*
3447 ** Implementation of the sha1(X) function.
3448 **
3449 ** Return a lower-case hexadecimal rendering of the SHA1 hash of the
3450 ** argument X. If X is a BLOB, it is hashed as is. For all other
3451 ** types of input, X is converted into a UTF-8 string and the string
3452 ** is hash without the trailing 0x00 terminator. The hash of a NULL
3453 ** value is NULL.
3454 */
3455 static void sha1Func(
3456 sqlite3_context *context,
3457 int argc,
3458 sqlite3_value **argv
3459 ){
3460 SHA1Context cx;
3461 int eType = sqlite3_value_type(argv[0]);
3462 int nByte = sqlite3_value_bytes(argv[0]);
3463 char zOut[44];
3464
3465 assert( argc==1 );
3466 if( eType==SQLITE_NULL ) return;
3467 hash_init(&cx);
3468 if( eType==SQLITE_BLOB ){
3469 hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
3470 }else{
3471 hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
3472 }
3473 if( sqlite3_user_data(context)!=0 ){
3474 hash_finish(&cx, zOut, 1);
3475 sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
3476 }else{
3477 hash_finish(&cx, zOut, 0);
3478 sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
3479 }
3480 }
3481
3482 /*
3483 ** Implementation of the sha1_query(SQL) function.
3484 **
3485 ** This function compiles and runs the SQL statement(s) given in the
3486 ** argument. The results are hashed using SHA1 and that hash is returned.
3487 **
3488 ** The original SQL text is included as part of the hash.
3489 **
3490 ** The hash is not just a concatenation of the outputs. Each query
3491 ** is delimited and each row and value within the query is delimited,
3492 ** with all values being marked with their datatypes.
3493 */
3494 static void sha1QueryFunc(
3495 sqlite3_context *context,
3496 int argc,
3497 sqlite3_value **argv
3498 ){
3499 sqlite3 *db = sqlite3_context_db_handle(context);
3500 const char *zSql = (const char*)sqlite3_value_text(argv[0]);
3501 sqlite3_stmt *pStmt = 0;
3502 int nCol; /* Number of columns in the result set */
3503 int i; /* Loop counter */
3504 int rc;
3505 int n;
3506 const char *z;
3507 SHA1Context cx;
3508 char zOut[44];
3509
3510 assert( argc==1 );
3511 if( zSql==0 ) return;
3512 hash_init(&cx);
3513 while( zSql[0] ){
3514 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
3515 if( rc ){
3516 char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
3517 zSql, sqlite3_errmsg(db));
3518 sqlite3_finalize(pStmt);
3519 sqlite3_result_error(context, zMsg, -1);
3520 sqlite3_free(zMsg);
3521 return;
3522 }
3523 if( !sqlite3_stmt_readonly(pStmt) ){
3524 char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
3525 sqlite3_finalize(pStmt);
3526 sqlite3_result_error(context, zMsg, -1);
3527 sqlite3_free(zMsg);
3528 return;
3529 }
3530 nCol = sqlite3_column_count(pStmt);
3531 z = sqlite3_sql(pStmt);
3532 n = (int)strlen(z);
3533 hash_step_vformat(&cx,"S%d:",n);
3534 hash_step(&cx,(unsigned char*)z,n);
3535
3536 /* Compute a hash over the result of the query */
3537 while( SQLITE_ROW==sqlite3_step(pStmt) ){
3538 hash_step(&cx,(const unsigned char*)"R",1);
3539 for(i=0; i<nCol; i++){
3540 switch( sqlite3_column_type(pStmt,i) ){
3541 case SQLITE_NULL: {
3542 hash_step(&cx, (const unsigned char*)"N",1);
3543 break;
3544 }
3545 case SQLITE_INTEGER: {
3546 sqlite3_uint64 u;
3547 int j;
3548 unsigned char x[9];
3549 sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
3550 memcpy(&u, &v, 8);
3551 for(j=8; j>=1; j--){
3552 x[j] = u & 0xff;
3553 u >>= 8;
3554 }
3555 x[0] = 'I';
3556 hash_step(&cx, x, 9);
3557 break;
3558 }
3559 case SQLITE_FLOAT: {
3560 sqlite3_uint64 u;
3561 int j;
3562 unsigned char x[9];
3563 double r = sqlite3_column_double(pStmt,i);
3564 memcpy(&u, &r, 8);
3565 for(j=8; j>=1; j--){
3566 x[j] = u & 0xff;
3567 u >>= 8;
3568 }
3569 x[0] = 'F';
3570 hash_step(&cx,x,9);
3571 break;
3572 }
3573 case SQLITE_TEXT: {
3574 int n2 = sqlite3_column_bytes(pStmt, i);
3575 const unsigned char *z2 = sqlite3_column_text(pStmt, i);
3576 hash_step_vformat(&cx,"T%d:",n2);
3577 hash_step(&cx, z2, n2);
3578 break;
3579 }
3580 case SQLITE_BLOB: {
3581 int n2 = sqlite3_column_bytes(pStmt, i);
3582 const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
3583 hash_step_vformat(&cx,"B%d:",n2);
3584 hash_step(&cx, z2, n2);
3585 break;
3586 }
3587 }
3588 }
3589 }
3590 sqlite3_finalize(pStmt);
3591 }
3592 hash_finish(&cx, zOut, 0);
3593 sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
3594 }
3595
3596
3597 #ifdef _WIN32
3598
3599 #endif
3600 int sqlite3_sha_init(
3601 sqlite3 *db,
3602 char **pzErrMsg,
3603 const sqlite3_api_routines *pApi
3604 ){
3605 int rc = SQLITE_OK;
3606 static int one = 1;
3607 SQLITE_EXTENSION_INIT2(pApi);
3608 (void)pzErrMsg; /* Unused parameter */
3609 rc = sqlite3_create_function(db, "sha1", 1,
3610 SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
3611 0, sha1Func, 0, 0);
3612 if( rc==SQLITE_OK ){
3613 rc = sqlite3_create_function(db, "sha1b", 1,
3614 SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
3615 (void*)&one, sha1Func, 0, 0);
3616 }
3617 if( rc==SQLITE_OK ){
3618 rc = sqlite3_create_function(db, "sha1_query", 1,
3619 SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
3620 sha1QueryFunc, 0, 0);
3621 }
3622 return rc;
3623 }
3624
3625 /************************* End ../ext/misc/sha1.c ********************/
3626 /************************* Begin ../ext/misc/uint.c ******************/
3627 /*
3628 ** 2020-04-14
3629 **
3630 ** The author disclaims copyright to this source code. In place of
@@ -5075,11 +4913,11 @@
4913 }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
4914 p->a[p->nUsed++] = y;
4915 }else if( p->bKeepSorted ){
4916 int i;
4917 i = percentBinarySearch(p, y, 0);
4918 if( i<(int)p->nUsed ){
4919 memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
4920 }
4921 p->a[i] = y;
4922 p->nUsed++;
4923 }else{
@@ -5191,11 +5029,11 @@
5029
5030 /* Find and remove the row */
5031 i = percentBinarySearch(p, y, 1);
5032 if( i>=0 ){
5033 p->nUsed--;
5034 if( i<(int)p->nUsed ){
5035 memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
5036 }
5037 }
5038 }
5039
@@ -5251,15 +5089,15 @@
5089 sqlite3 *db,
5090 char **pzErrMsg,
5091 const sqlite3_api_routines *pApi
5092 ){
5093 int rc = SQLITE_OK;
5094 unsigned int i;
5095 #ifdef SQLITE3EXT_H
 
 
5096 SQLITE_EXTENSION_INIT2(pApi);
5097 #else
5098 (void)pApi; /* Unused parameter */
5099 #endif
5100 (void)pzErrMsg; /* Unused parameter */
5101 for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
5102 rc = sqlite3_create_window_function(db,
5103 aPercentFunc[i].zName,
@@ -7012,50 +6850,58 @@
6850 aIdx[4] = i;
6851 idxNum |= 0x40;
6852 }
6853 continue;
6854 }
6855 if( pConstraint->iColumn<SERIES_COLUMN_START ){
6856 if( pConstraint->iColumn==SERIES_COLUMN_VALUE && pConstraint->usable ){
6857 switch( op ){
6858 case SQLITE_INDEX_CONSTRAINT_EQ:
6859 case SQLITE_INDEX_CONSTRAINT_IS: {
6860 idxNum |= 0x0080;
6861 idxNum &= ~0x3300;
6862 aIdx[5] = i;
6863 aIdx[6] = -1;
6864 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
6865 bStartSeen = 1;
6866 #endif
6867 break;
6868 }
6869 case SQLITE_INDEX_CONSTRAINT_GE: {
6870 if( idxNum & 0x0080 ) break;
6871 idxNum |= 0x0100;
6872 idxNum &= ~0x0200;
6873 aIdx[5] = i;
6874 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
6875 bStartSeen = 1;
6876 #endif
6877 break;
6878 }
6879 case SQLITE_INDEX_CONSTRAINT_GT: {
6880 if( idxNum & 0x0080 ) break;
6881 idxNum |= 0x0200;
6882 idxNum &= ~0x0100;
6883 aIdx[5] = i;
6884 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
6885 bStartSeen = 1;
6886 #endif
6887 break;
6888 }
6889 case SQLITE_INDEX_CONSTRAINT_LE: {
6890 if( idxNum & 0x0080 ) break;
6891 idxNum |= 0x1000;
6892 idxNum &= ~0x2000;
6893 aIdx[6] = i;
6894 break;
6895 }
6896 case SQLITE_INDEX_CONSTRAINT_LT: {
6897 if( idxNum & 0x0080 ) break;
6898 idxNum |= 0x2000;
6899 idxNum &= ~0x1000;
6900 aIdx[6] = i;
6901 break;
6902 }
6903 }
6904 }
6905 continue;
6906 }
6907 iCol = pConstraint->iColumn - SERIES_COLUMN_START;
@@ -8115,11 +7961,11 @@
7961 ** If the optional MTIME argument is present, then it is interpreted
7962 ** as an integer - the number of seconds since the unix epoch. The
7963 ** modification-time of the target file is set to this value before
7964 ** returning.
7965 **
7966 ** If five or more arguments are passed to this function and an
7967 ** error is encountered, an exception is raised.
7968 **
7969 ** READFILE(FILE):
7970 **
7971 ** Read and return the contents of file FILE (type blob) from disk.
@@ -8185,10 +8031,17 @@
8031 # define lstat(path,buf) stat(path,buf)
8032 #endif
8033 #include <time.h>
8034 #include <errno.h>
8035
8036 /* When used as part of the CLI, the sqlite3_stdio.h module will have
8037 ** been included before this one. In that case use the sqlite3_stdio.h
8038 ** #defines. If not, create our own for fopen().
8039 */
8040 #ifndef _SQLITE3_STDIO_H_
8041 # define sqlite3_fopen fopen
8042 #endif
8043
8044 /*
8045 ** Structure of the fsdir() table-valued function
8046 */
8047 /* 0 1 2 3 4 5 */
@@ -8217,11 +8070,11 @@
8070 sqlite3_int64 nIn;
8071 void *pBuf;
8072 sqlite3 *db;
8073 int mxBlob;
8074
8075 in = sqlite3_fopen(zName, "rb");
8076 if( in==0 ){
8077 /* File does not exist or is unreadable. Leave the result set to NULL. */
8078 return;
8079 }
8080 fseek(in, 0, SEEK_END);
@@ -8472,11 +8325,11 @@
8325 }
8326 }else{
8327 sqlite3_int64 nWrite = 0;
8328 const char *z;
8329 int rc = 0;
8330 FILE *out = sqlite3_fopen(zFile, "wb");
8331 if( out==0 ) return 1;
8332 z = (const char*)sqlite3_value_blob(pData);
8333 if( z ){
8334 sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
8335 nWrite = sqlite3_value_bytes(pData);
@@ -10333,10 +10186,18 @@
10186 #ifndef SQLITE_NO_STDINT
10187 # include <stdint.h>
10188 #endif
10189
10190 #include <zlib.h>
10191
10192 /* When used as part of the CLI, the sqlite3_stdio.h module will have
10193 ** been included before this one. In that case use the sqlite3_stdio.h
10194 ** #defines. If not, create our own for fopen().
10195 */
10196 #ifndef _SQLITE3_STDIO_H_
10197 # define sqlite3_fopen fopen
10198 #endif
10199
10200 #ifndef SQLITE_OMIT_VIRTUALTABLE
10201
10202 #ifndef SQLITE_AMALGAMATION
10203
@@ -11590,11 +11451,11 @@
11451 }else{
11452 zFile = (const char*)sqlite3_value_text(argv[0]);
11453 }
11454
11455 if( 0==pTab->pWriteFd && 0==bInMemory ){
11456 pCsr->pFile = zFile ? sqlite3_fopen(zFile, "rb") : 0;
11457 if( pCsr->pFile==0 ){
11458 zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
11459 rc = SQLITE_ERROR;
11460 }else{
11461 rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
@@ -11780,11 +11641,11 @@
11641
11642 /* Open a write fd on the file. Also load the entire central directory
11643 ** structure into memory. During the transaction any new file data is
11644 ** appended to the archive file, but the central directory is accumulated
11645 ** in main-memory until the transaction is committed. */
11646 pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
11647 if( pTab->pWriteFd==0 ){
11648 pTab->base.zErrMsg = sqlite3_mprintf(
11649 "zipfile: failed to open file %s for writing", pTab->zFile
11650 );
11651 rc = SQLITE_ERROR;
@@ -14233,10 +14094,70 @@
14094 }
14095
14096 return rc;
14097 }
14098
14099 /*
14100 ** This function tests if the schema of the main database of database handle
14101 ** db contains an object named zTab. Assuming no error occurs, output parameter
14102 ** (*pbContains) is set to true if zTab exists, or false if it does not.
14103 **
14104 ** Or, if an error occurs, an SQLite error code is returned. The final value
14105 ** of (*pbContains) is undefined in this case.
14106 */
14107 static int expertDbContainsObject(
14108 sqlite3 *db,
14109 const char *zTab,
14110 int *pbContains /* OUT: True if object exists */
14111 ){
14112 const char *zSql = "SELECT 1 FROM sqlite_schema WHERE name = ?";
14113 sqlite3_stmt *pSql = 0;
14114 int rc = SQLITE_OK;
14115 int ret = 0;
14116
14117 rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
14118 if( rc==SQLITE_OK ){
14119 sqlite3_bind_text(pSql, 1, zTab, -1, SQLITE_STATIC);
14120 if( SQLITE_ROW==sqlite3_step(pSql) ){
14121 ret = 1;
14122 }
14123 rc = sqlite3_finalize(pSql);
14124 }
14125
14126 *pbContains = ret;
14127 return rc;
14128 }
14129
14130 /*
14131 ** Execute SQL command zSql using database handle db. If no error occurs,
14132 ** set (*pzErr) to NULL and return SQLITE_OK.
14133 **
14134 ** If an error does occur, return an SQLite error code and set (*pzErr) to
14135 ** point to a buffer containing an English language error message. Except,
14136 ** if the error message begins with "no such module:", then ignore the
14137 ** error and return as if the SQL statement had succeeded.
14138 **
14139 ** This is used to copy as much of the database schema as possible while
14140 ** ignoring any errors related to missing virtual table modules.
14141 */
14142 static int expertSchemaSql(sqlite3 *db, const char *zSql, char **pzErr){
14143 int rc = SQLITE_OK;
14144 char *zErr = 0;
14145
14146 rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
14147 if( rc!=SQLITE_OK && zErr ){
14148 int nErr = STRLEN(zErr);
14149 if( nErr>=15 && memcmp(zErr, "no such module:", 15)==0 ){
14150 sqlite3_free(zErr);
14151 rc = SQLITE_OK;
14152 zErr = 0;
14153 }
14154 }
14155
14156 *pzErr = zErr;
14157 return rc;
14158 }
14159
14160 static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
14161 int rc = idxRegisterVtab(p);
14162 sqlite3_stmt *pSchema = 0;
14163
@@ -14244,30 +14165,39 @@
14165 **
14166 ** 1) Add an entry to the p->pTable list, and
14167 ** 2) Create the equivalent virtual table in dbv.
14168 */
14169 rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
14170 "SELECT type, name, sql, 1, "
14171 " substr(sql,1,14)=='create virtual' COLLATE nocase "
14172 "FROM sqlite_schema "
14173 "WHERE type IN ('table','view') AND "
14174 " substr(name,1,7)!='sqlite_' COLLATE nocase "
14175 " UNION ALL "
14176 "SELECT type, name, sql, 2, 0 FROM sqlite_schema "
14177 "WHERE type = 'trigger'"
14178 " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
14179 "ORDER BY 4, 5 DESC, 1"
14180 );
14181 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
14182 const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
14183 const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
14184 const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
14185 int bVirtual = sqlite3_column_int(pSchema, 4);
14186 int bExists = 0;
14187
14188 if( zType==0 || zName==0 ) continue;
14189 rc = expertDbContainsObject(p->dbv, zName, &bExists);
14190 if( rc || bExists ) continue;
14191
14192 if( zType[0]=='v' || zType[1]=='r' || bVirtual ){
14193 /* A view. Or a trigger on a view. */
14194 if( zSql ) rc = expertSchemaSql(p->dbv, zSql, pzErrmsg);
14195 }else{
14196 IdxTable *pTab;
14197 rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
14198 if( rc==SQLITE_OK && ALWAYS(pTab!=0) ){
14199 int i;
14200 char *zInner = 0;
14201 char *zOuter = 0;
14202 pTab->pNext = p->pTable;
14203 p->pTable = pTab;
@@ -14464,10 +14394,16 @@
14394 sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
14395 while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
14396 const char *zComma = zCols==0 ? "" : ", ";
14397 const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
14398 const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
14399 if( zName==0 ){
14400 /* This index contains an expression. Ignore it. */
14401 sqlite3_free(zCols);
14402 sqlite3_free(zOrder);
14403 return sqlite3_reset(pIndexXInfo);
14404 }
14405 zCols = idxAppendText(&rc, zCols,
14406 "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
14407 zComma, zName, nCol, zName, zColl
14408 );
14409 zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
@@ -14792,16 +14728,22 @@
14728
14729 /* Copy the entire schema of database [db] into [dbm]. */
14730 if( rc==SQLITE_OK ){
14731 sqlite3_stmt *pSql = 0;
14732 rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
14733 "SELECT sql, name, substr(sql,1,14)=='create virtual' COLLATE nocase"
14734 " FROM sqlite_schema WHERE substr(name,1,7)!='sqlite_' COLLATE nocase"
14735 " ORDER BY 3 DESC, rowid"
14736 );
14737 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
14738 const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
14739 const char *zName = (const char*)sqlite3_column_text(pSql, 1);
14740 int bExists = 0;
14741 rc = expertDbContainsObject(pNew->dbm, zName, &bExists);
14742 if( rc==SQLITE_OK && zSql && bExists==0 ){
14743 rc = expertSchemaSql(pNew->dbm, zSql, pzErrmsg);
14744 }
14745 }
14746 idxFinalize(&rc, pSql);
14747 }
14748
14749 /* Create the vtab schema */
@@ -16211,10 +16153,1197 @@
16153 }
16154 return rc;
16155 }
16156
16157 /************************* End ../ext/misc/stmtrand.c ********************/
16158 /************************* Begin ../ext/misc/vfstrace.c ******************/
16159 /*
16160 ** 2011 March 16
16161 **
16162 ** The author disclaims copyright to this source code. In place of
16163 ** a legal notice, here is a blessing:
16164 **
16165 ** May you do good and not evil.
16166 ** May you find forgiveness for yourself and forgive others.
16167 ** May you share freely, never taking more than you give.
16168 **
16169 ******************************************************************************
16170 **
16171 ** This file contains code implements a VFS shim that writes diagnostic
16172 ** output for each VFS call, similar to "strace".
16173 **
16174 ** USAGE:
16175 **
16176 ** This source file exports a single symbol which is the name of a
16177 ** function:
16178 **
16179 ** int vfstrace_register(
16180 ** const char *zTraceName, // Name of the newly constructed VFS
16181 ** const char *zOldVfsName, // Name of the underlying VFS
16182 ** int (*xOut)(const char*,void*), // Output routine. ex: fputs
16183 ** void *pOutArg, // 2nd argument to xOut. ex: stderr
16184 ** int makeDefault // Make the new VFS the default
16185 ** );
16186 **
16187 ** Applications that want to trace their VFS usage must provide a callback
16188 ** function with this prototype:
16189 **
16190 ** int traceOutput(const char *zMessage, void *pAppData);
16191 **
16192 ** This function will "output" the trace messages, where "output" can
16193 ** mean different things to different applications. The traceOutput function
16194 ** for the command-line shell (see shell.c) is "fputs" from the standard
16195 ** library, which means that all trace output is written on the stream
16196 ** specified by the second argument. In the case of the command-line shell
16197 ** the second argument is stderr. Other applications might choose to output
16198 ** trace information to a file, over a socket, or write it into a buffer.
16199 **
16200 ** The vfstrace_register() function creates a new "shim" VFS named by
16201 ** the zTraceName parameter. A "shim" VFS is an SQLite backend that does
16202 ** not really perform the duties of a true backend, but simply filters or
16203 ** interprets VFS calls before passing them off to another VFS which does
16204 ** the actual work. In this case the other VFS - the one that does the
16205 ** real work - is identified by the second parameter, zOldVfsName. If
16206 ** the 2nd parameter is NULL then the default VFS is used. The common
16207 ** case is for the 2nd parameter to be NULL.
16208 **
16209 ** The third and fourth parameters are the pointer to the output function
16210 ** and the second argument to the output function. For the SQLite
16211 ** command-line shell, when the -vfstrace option is used, these parameters
16212 ** are fputs and stderr, respectively.
16213 **
16214 ** The fifth argument is true (non-zero) to cause the newly created VFS
16215 ** to become the default VFS. The common case is for the fifth parameter
16216 ** to be true.
16217 **
16218 ** The call to vfstrace_register() simply creates the shim VFS that does
16219 ** tracing. The application must also arrange to use the new VFS for
16220 ** all database connections that are created and for which tracing is
16221 ** desired. This can be done by specifying the trace VFS using URI filename
16222 ** notation, or by specifying the trace VFS as the 4th parameter to
16223 ** sqlite3_open_v2() or by making the trace VFS be the default (by setting
16224 ** the 5th parameter of vfstrace_register() to 1).
16225 **
16226 **
16227 ** ENABLING VFSTRACE IN A COMMAND-LINE SHELL
16228 **
16229 ** The SQLite command line shell implemented by the shell.c source file
16230 ** can be used with this module. To compile in -vfstrace support, first
16231 ** gather this file (test_vfstrace.c), the shell source file (shell.c),
16232 ** and the SQLite amalgamation source files (sqlite3.c, sqlite3.h) into
16233 ** the working directory. Then compile using a command like the following:
16234 **
16235 ** gcc -o sqlite3 -Os -I. -DSQLITE_ENABLE_VFSTRACE \
16236 ** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
16237 ** -DHAVE_READLINE -DHAVE_USLEEP=1 \
16238 ** shell.c test_vfstrace.c sqlite3.c -ldl -lreadline -lncurses
16239 **
16240 ** The gcc command above works on Linux and provides (in addition to the
16241 ** -vfstrace option) support for FTS3 and FTS4, RTREE, and command-line
16242 ** editing using the readline library. The command-line shell does not
16243 ** use threads so we added -DSQLITE_THREADSAFE=0 just to make the code
16244 ** run a little faster. For compiling on a Mac, you'll probably need
16245 ** to omit the -DHAVE_READLINE, the -lreadline, and the -lncurses options.
16246 ** The compilation could be simplified to just this:
16247 **
16248 ** gcc -DSQLITE_ENABLE_VFSTRACE \
16249 ** shell.c test_vfstrace.c sqlite3.c -ldl -lpthread
16250 **
16251 ** In this second example, all unnecessary options have been removed
16252 ** Note that since the code is now threadsafe, we had to add the -lpthread
16253 ** option to pull in the pthreads library.
16254 **
16255 ** To cross-compile for windows using MinGW, a command like this might
16256 ** work:
16257 **
16258 ** /opt/mingw/bin/i386-mingw32msvc-gcc -o sqlite3.exe -Os -I \
16259 ** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
16260 ** shell.c test_vfstrace.c sqlite3.c
16261 **
16262 ** Similar compiler commands will work on different systems. The key
16263 ** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
16264 ** the shell.c source file will know to include the -vfstrace command-line
16265 ** option and (2) you must compile and link the three source files
16266 ** shell,c, test_vfstrace.c, and sqlite3.c.
16267 **
16268 ** RUNTIME CONTROL OF VFSTRACE OUTPUT
16269 **
16270 ** The application can use the "vfstrace" pragma to control which VFS
16271 ** APIs are traced. To disable all output:
16272 **
16273 ** PRAGMA vfstrace('-all');
16274 **
16275 ** To enable all output (which is the default setting):
16276 **
16277 ** PRAGMA vfstrace('+all');
16278 **
16279 ** Individual APIs can be enabled or disabled by name, with or without
16280 ** the initial "x" character. For example, to set up for tracing lock
16281 ** primatives only:
16282 **
16283 ** PRAGMA vfstrace('-all, +Lock,Unlock,ShmLock');
16284 **
16285 ** The argument to the vfstrace pragma ignores capitalization and any
16286 ** characters other than alphabetics, '+', and '-'.
16287 */
16288 #include <stdlib.h>
16289 #include <string.h>
16290 /* #include "sqlite3.h" */
16291
16292 /*
16293 ** An instance of this structure is attached to the each trace VFS to
16294 ** provide auxiliary information.
16295 */
16296 typedef struct vfstrace_info vfstrace_info;
16297 struct vfstrace_info {
16298 sqlite3_vfs *pRootVfs; /* The underlying real VFS */
16299 int (*xOut)(const char*, void*); /* Send output here */
16300 unsigned int mTrace; /* Mask of interfaces to trace */
16301 u8 bOn; /* Tracing on/off */
16302 void *pOutArg; /* First argument to xOut */
16303 const char *zVfsName; /* Name of this trace-VFS */
16304 sqlite3_vfs *pTraceVfs; /* Pointer back to the trace VFS */
16305 };
16306
16307 /*
16308 ** The sqlite3_file object for the trace VFS
16309 */
16310 typedef struct vfstrace_file vfstrace_file;
16311 struct vfstrace_file {
16312 sqlite3_file base; /* Base class. Must be first */
16313 vfstrace_info *pInfo; /* The trace-VFS to which this file belongs */
16314 const char *zFName; /* Base name of the file */
16315 sqlite3_file *pReal; /* The real underlying file */
16316 };
16317
16318 /*
16319 ** Bit values for vfstrace_info.mTrace.
16320 */
16321 #define VTR_CLOSE 0x00000001
16322 #define VTR_READ 0x00000002
16323 #define VTR_WRITE 0x00000004
16324 #define VTR_TRUNC 0x00000008
16325 #define VTR_SYNC 0x00000010
16326 #define VTR_FSIZE 0x00000020
16327 #define VTR_LOCK 0x00000040
16328 #define VTR_UNLOCK 0x00000080
16329 #define VTR_CRL 0x00000100
16330 #define VTR_FCTRL 0x00000200
16331 #define VTR_SECSZ 0x00000400
16332 #define VTR_DEVCHAR 0x00000800
16333 #define VTR_SHMLOCK 0x00001000
16334 #define VTR_SHMMAP 0x00002000
16335 #define VTR_SHMBAR 0x00004000
16336 #define VTR_SHMUNMAP 0x00008000
16337 #define VTR_OPEN 0x00010000
16338 #define VTR_DELETE 0x00020000
16339 #define VTR_ACCESS 0x00040000
16340 #define VTR_FULLPATH 0x00080000
16341 #define VTR_DLOPEN 0x00100000
16342 #define VTR_DLERR 0x00200000
16343 #define VTR_DLSYM 0x00400000
16344 #define VTR_DLCLOSE 0x00800000
16345 #define VTR_RAND 0x01000000
16346 #define VTR_SLEEP 0x02000000
16347 #define VTR_CURTIME 0x04000000
16348 #define VTR_LASTERR 0x08000000
16349
16350 /*
16351 ** Method declarations for vfstrace_file.
16352 */
16353 static int vfstraceClose(sqlite3_file*);
16354 static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
16355 static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
16356 static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
16357 static int vfstraceSync(sqlite3_file*, int flags);
16358 static int vfstraceFileSize(sqlite3_file*, sqlite3_int64 *pSize);
16359 static int vfstraceLock(sqlite3_file*, int);
16360 static int vfstraceUnlock(sqlite3_file*, int);
16361 static int vfstraceCheckReservedLock(sqlite3_file*, int *);
16362 static int vfstraceFileControl(sqlite3_file*, int op, void *pArg);
16363 static int vfstraceSectorSize(sqlite3_file*);
16364 static int vfstraceDeviceCharacteristics(sqlite3_file*);
16365 static int vfstraceShmLock(sqlite3_file*,int,int,int);
16366 static int vfstraceShmMap(sqlite3_file*,int,int,int, void volatile **);
16367 static void vfstraceShmBarrier(sqlite3_file*);
16368 static int vfstraceShmUnmap(sqlite3_file*,int);
16369
16370 /*
16371 ** Method declarations for vfstrace_vfs.
16372 */
16373 static int vfstraceOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
16374 static int vfstraceDelete(sqlite3_vfs*, const char *zName, int syncDir);
16375 static int vfstraceAccess(sqlite3_vfs*, const char *zName, int flags, int *);
16376 static int vfstraceFullPathname(sqlite3_vfs*, const char *zName, int, char *);
16377 static void *vfstraceDlOpen(sqlite3_vfs*, const char *zFilename);
16378 static void vfstraceDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
16379 static void (*vfstraceDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
16380 static void vfstraceDlClose(sqlite3_vfs*, void*);
16381 static int vfstraceRandomness(sqlite3_vfs*, int nByte, char *zOut);
16382 static int vfstraceSleep(sqlite3_vfs*, int microseconds);
16383 static int vfstraceCurrentTime(sqlite3_vfs*, double*);
16384 static int vfstraceGetLastError(sqlite3_vfs*, int, char*);
16385 static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
16386 static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
16387 static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, const char *);
16388 static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
16389
16390 /*
16391 ** Return a pointer to the tail of the pathname. Examples:
16392 **
16393 ** /home/drh/xyzzy.txt -> xyzzy.txt
16394 ** xyzzy.txt -> xyzzy.txt
16395 */
16396 static const char *fileTail(const char *z){
16397 size_t i;
16398 if( z==0 ) return 0;
16399 i = strlen(z)-1;
16400 while( i>0 && z[i-1]!='/' ){ i--; }
16401 return &z[i];
16402 }
16403
16404 /*
16405 ** Send trace output defined by zFormat and subsequent arguments.
16406 */
16407 static void vfstrace_printf(
16408 vfstrace_info *pInfo,
16409 const char *zFormat,
16410 ...
16411 ){
16412 va_list ap;
16413 char *zMsg;
16414 if( pInfo->bOn ){
16415 va_start(ap, zFormat);
16416 zMsg = sqlite3_vmprintf(zFormat, ap);
16417 va_end(ap);
16418 pInfo->xOut(zMsg, pInfo->pOutArg);
16419 sqlite3_free(zMsg);
16420 }
16421 }
16422
16423 /*
16424 ** Try to convert an error code into a symbolic name for that error code.
16425 */
16426 static const char *vfstrace_errcode_name(int rc ){
16427 const char *zVal = 0;
16428 switch( rc ){
16429 case SQLITE_OK: zVal = "SQLITE_OK"; break;
16430 case SQLITE_INTERNAL: zVal = "SQLITE_INTERNAL"; break;
16431 case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
16432 case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
16433 case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
16434 case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
16435 case SQLITE_LOCKED: zVal = "SQLITE_LOCKED"; break;
16436 case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
16437 case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
16438 case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
16439 case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
16440 case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
16441 case SQLITE_NOTFOUND: zVal = "SQLITE_NOTFOUND"; break;
16442 case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
16443 case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
16444 case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
16445 case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
16446 case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
16447 case SQLITE_TOOBIG: zVal = "SQLITE_TOOBIG"; break;
16448 case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
16449 case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
16450 case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
16451 case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
16452 case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
16453 case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
16454 case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
16455 case SQLITE_IOERR_FSYNC: zVal = "SQLITE_IOERR_FSYNC"; break;
16456 case SQLITE_IOERR_DIR_FSYNC: zVal = "SQLITE_IOERR_DIR_FSYNC"; break;
16457 case SQLITE_IOERR_TRUNCATE: zVal = "SQLITE_IOERR_TRUNCATE"; break;
16458 case SQLITE_IOERR_FSTAT: zVal = "SQLITE_IOERR_FSTAT"; break;
16459 case SQLITE_IOERR_UNLOCK: zVal = "SQLITE_IOERR_UNLOCK"; break;
16460 case SQLITE_IOERR_RDLOCK: zVal = "SQLITE_IOERR_RDLOCK"; break;
16461 case SQLITE_IOERR_DELETE: zVal = "SQLITE_IOERR_DELETE"; break;
16462 case SQLITE_IOERR_BLOCKED: zVal = "SQLITE_IOERR_BLOCKED"; break;
16463 case SQLITE_IOERR_NOMEM: zVal = "SQLITE_IOERR_NOMEM"; break;
16464 case SQLITE_IOERR_ACCESS: zVal = "SQLITE_IOERR_ACCESS"; break;
16465 case SQLITE_IOERR_CHECKRESERVEDLOCK:
16466 zVal = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
16467 case SQLITE_IOERR_LOCK: zVal = "SQLITE_IOERR_LOCK"; break;
16468 case SQLITE_IOERR_CLOSE: zVal = "SQLITE_IOERR_CLOSE"; break;
16469 case SQLITE_IOERR_DIR_CLOSE: zVal = "SQLITE_IOERR_DIR_CLOSE"; break;
16470 case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
16471 case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
16472 case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
16473 case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
16474 case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
16475 case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
16476 case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
16477 case SQLITE_READONLY_DBMOVED: zVal = "SQLITE_READONLY_DBMOVED"; break;
16478 case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
16479 case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
16480 case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
16481 }
16482 return zVal;
16483 }
16484
16485 /*
16486 ** Convert value rc into a string and print it using zFormat. zFormat
16487 ** should have exactly one %s
16488 */
16489 static void vfstrace_print_errcode(
16490 vfstrace_info *pInfo,
16491 const char *zFormat,
16492 int rc
16493 ){
16494 const char *zVal;
16495 char zBuf[50];
16496 zVal = vfstrace_errcode_name(rc);
16497 if( zVal==0 ){
16498 zVal = vfstrace_errcode_name(rc&0xff);
16499 if( zVal ){
16500 sqlite3_snprintf(sizeof(zBuf), zBuf, "%s | 0x%x", zVal, rc&0xffff00);
16501 }else{
16502 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d (0x%x)", rc, rc);
16503 }
16504 zVal = zBuf;
16505 }
16506 vfstrace_printf(pInfo, zFormat, zVal);
16507 }
16508
16509 /*
16510 ** Append to a buffer.
16511 */
16512 static void strappend(char *z, int *pI, const char *zAppend){
16513 int i = *pI;
16514 while( zAppend[0] ){ z[i++] = *(zAppend++); }
16515 z[i] = 0;
16516 *pI = i;
16517 }
16518
16519 /*
16520 ** Turn tracing output on or off according to mMask.
16521 */
16522 static void vfstraceOnOff(vfstrace_info *pInfo, unsigned int mMask){
16523 pInfo->bOn = (pInfo->mTrace & mMask)!=0;
16524 }
16525
16526 /*
16527 ** Close an vfstrace-file.
16528 */
16529 static int vfstraceClose(sqlite3_file *pFile){
16530 vfstrace_file *p = (vfstrace_file *)pFile;
16531 vfstrace_info *pInfo = p->pInfo;
16532 int rc;
16533 vfstraceOnOff(pInfo, VTR_CLOSE);
16534 vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo->zVfsName, p->zFName);
16535 rc = p->pReal->pMethods->xClose(p->pReal);
16536 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16537 if( rc==SQLITE_OK ){
16538 sqlite3_free((void*)p->base.pMethods);
16539 p->base.pMethods = 0;
16540 }
16541 return rc;
16542 }
16543
16544 /*
16545 ** Read data from an vfstrace-file.
16546 */
16547 static int vfstraceRead(
16548 sqlite3_file *pFile,
16549 void *zBuf,
16550 int iAmt,
16551 sqlite_int64 iOfst
16552 ){
16553 vfstrace_file *p = (vfstrace_file *)pFile;
16554 vfstrace_info *pInfo = p->pInfo;
16555 int rc;
16556 vfstraceOnOff(pInfo, VTR_READ);
16557 vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
16558 pInfo->zVfsName, p->zFName, iAmt, iOfst);
16559 rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
16560 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16561 return rc;
16562 }
16563
16564 /*
16565 ** Write data to an vfstrace-file.
16566 */
16567 static int vfstraceWrite(
16568 sqlite3_file *pFile,
16569 const void *zBuf,
16570 int iAmt,
16571 sqlite_int64 iOfst
16572 ){
16573 vfstrace_file *p = (vfstrace_file *)pFile;
16574 vfstrace_info *pInfo = p->pInfo;
16575 int rc;
16576 vfstraceOnOff(pInfo, VTR_WRITE);
16577 vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
16578 pInfo->zVfsName, p->zFName, iAmt, iOfst);
16579 rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
16580 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16581 return rc;
16582 }
16583
16584 /*
16585 ** Truncate an vfstrace-file.
16586 */
16587 static int vfstraceTruncate(sqlite3_file *pFile, sqlite_int64 size){
16588 vfstrace_file *p = (vfstrace_file *)pFile;
16589 vfstrace_info *pInfo = p->pInfo;
16590 int rc;
16591 vfstraceOnOff(pInfo, VTR_TRUNC);
16592 vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo->zVfsName, p->zFName,
16593 size);
16594 rc = p->pReal->pMethods->xTruncate(p->pReal, size);
16595 vfstrace_printf(pInfo, " -> %d\n", rc);
16596 return rc;
16597 }
16598
16599 /*
16600 ** Sync an vfstrace-file.
16601 */
16602 static int vfstraceSync(sqlite3_file *pFile, int flags){
16603 vfstrace_file *p = (vfstrace_file *)pFile;
16604 vfstrace_info *pInfo = p->pInfo;
16605 int rc;
16606 int i;
16607 char zBuf[100];
16608 memcpy(zBuf, "|0", 3);
16609 i = 0;
16610 if( flags & SQLITE_SYNC_FULL ) strappend(zBuf, &i, "|FULL");
16611 else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL");
16612 if( flags & SQLITE_SYNC_DATAONLY ) strappend(zBuf, &i, "|DATAONLY");
16613 if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){
16614 sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
16615 }
16616 vfstraceOnOff(pInfo, VTR_SYNC);
16617 vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName,
16618 &zBuf[1]);
16619 rc = p->pReal->pMethods->xSync(p->pReal, flags);
16620 vfstrace_printf(pInfo, " -> %d\n", rc);
16621 return rc;
16622 }
16623
16624 /*
16625 ** Return the current file-size of an vfstrace-file.
16626 */
16627 static int vfstraceFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
16628 vfstrace_file *p = (vfstrace_file *)pFile;
16629 vfstrace_info *pInfo = p->pInfo;
16630 int rc;
16631 vfstraceOnOff(pInfo, VTR_FSIZE);
16632 vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo->zVfsName, p->zFName);
16633 rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
16634 vfstrace_print_errcode(pInfo, " -> %s,", rc);
16635 vfstrace_printf(pInfo, " size=%lld\n", *pSize);
16636 return rc;
16637 }
16638
16639 /*
16640 ** Return the name of a lock.
16641 */
16642 static const char *lockName(int eLock){
16643 const char *azLockNames[] = {
16644 "NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
16645 };
16646 if( eLock<0 || eLock>=(int)(sizeof(azLockNames)/sizeof(azLockNames[0])) ){
16647 return "???";
16648 }else{
16649 return azLockNames[eLock];
16650 }
16651 }
16652
16653 /*
16654 ** Lock an vfstrace-file.
16655 */
16656 static int vfstraceLock(sqlite3_file *pFile, int eLock){
16657 vfstrace_file *p = (vfstrace_file *)pFile;
16658 vfstrace_info *pInfo = p->pInfo;
16659 int rc;
16660 vfstraceOnOff(pInfo, VTR_LOCK);
16661 vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo->zVfsName, p->zFName,
16662 lockName(eLock));
16663 rc = p->pReal->pMethods->xLock(p->pReal, eLock);
16664 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16665 return rc;
16666 }
16667
16668 /*
16669 ** Unlock an vfstrace-file.
16670 */
16671 static int vfstraceUnlock(sqlite3_file *pFile, int eLock){
16672 vfstrace_file *p = (vfstrace_file *)pFile;
16673 vfstrace_info *pInfo = p->pInfo;
16674 int rc;
16675 vfstraceOnOff(pInfo, VTR_UNLOCK);
16676 vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo->zVfsName, p->zFName,
16677 lockName(eLock));
16678 rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
16679 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16680 return rc;
16681 }
16682
16683 /*
16684 ** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
16685 */
16686 static int vfstraceCheckReservedLock(sqlite3_file *pFile, int *pResOut){
16687 vfstrace_file *p = (vfstrace_file *)pFile;
16688 vfstrace_info *pInfo = p->pInfo;
16689 int rc;
16690 vfstraceOnOff(pInfo, VTR_CRL);
16691 vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)",
16692 pInfo->zVfsName, p->zFName);
16693 rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
16694 vfstrace_print_errcode(pInfo, " -> %s", rc);
16695 vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
16696 return rc;
16697 }
16698
16699 /*
16700 ** File control method. For custom operations on an vfstrace-file.
16701 */
16702 static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
16703 vfstrace_file *p = (vfstrace_file *)pFile;
16704 vfstrace_info *pInfo = p->pInfo;
16705 int rc;
16706 char zBuf[100];
16707 char zBuf2[100];
16708 char *zOp;
16709 char *zRVal = 0;
16710 vfstraceOnOff(pInfo, VTR_FCTRL);
16711 switch( op ){
16712 case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
16713 case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
16714 case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
16715 case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
16716 case SQLITE_FCNTL_SIZE_HINT: {
16717 sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
16718 *(sqlite3_int64*)pArg);
16719 zOp = zBuf;
16720 break;
16721 }
16722 case SQLITE_FCNTL_CHUNK_SIZE: {
16723 sqlite3_snprintf(sizeof(zBuf), zBuf, "CHUNK_SIZE,%d", *(int*)pArg);
16724 zOp = zBuf;
16725 break;
16726 }
16727 case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
16728 case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
16729 case SQLITE_FCNTL_PERSIST_WAL: {
16730 sqlite3_snprintf(sizeof(zBuf), zBuf, "PERSIST_WAL,%d", *(int*)pArg);
16731 zOp = zBuf;
16732 break;
16733 }
16734 case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
16735 case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
16736 case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break;
16737 case SQLITE_FCNTL_PRAGMA: {
16738 const char *const* a = (const char*const*)pArg;
16739 if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){
16740 const u8 *zArg = (const u8*)a[2];
16741 if( zArg[0]>='0' && zArg[0]<=9 ){
16742 pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0);
16743 }else{
16744 static const struct {
16745 const char *z;
16746 unsigned int m;
16747 } aKw[] = {
16748 { "all", 0xffffffff },
16749 { "close", VTR_CLOSE },
16750 { "read", VTR_READ },
16751 { "write", VTR_WRITE },
16752 { "truncate", VTR_TRUNC },
16753 { "sync", VTR_SYNC },
16754 { "filesize", VTR_FSIZE },
16755 { "lock", VTR_LOCK },
16756 { "unlock", VTR_UNLOCK },
16757 { "checkreservedlock", VTR_CRL },
16758 { "filecontrol", VTR_FCTRL },
16759 { "sectorsize", VTR_SECSZ },
16760 { "devicecharacteristics", VTR_DEVCHAR },
16761 { "shmlock", VTR_SHMLOCK },
16762 { "shmmap", VTR_SHMMAP },
16763 { "shmummap", VTR_SHMUNMAP },
16764 { "shmbarrier", VTR_SHMBAR },
16765 { "open", VTR_OPEN },
16766 { "delete", VTR_DELETE },
16767 { "access", VTR_ACCESS },
16768 { "fullpathname", VTR_FULLPATH },
16769 { "dlopen", VTR_DLOPEN },
16770 { "dlerror", VTR_DLERR },
16771 { "dlsym", VTR_DLSYM },
16772 { "dlclose", VTR_DLCLOSE },
16773 { "randomness", VTR_RAND },
16774 { "sleep", VTR_SLEEP },
16775 { "currenttime", VTR_CURTIME },
16776 { "currenttimeint64", VTR_CURTIME },
16777 { "getlasterror", VTR_LASTERR },
16778 };
16779 int onOff = 1;
16780 while( zArg[0] ){
16781 int jj, n;
16782 while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
16783 && !isalpha(zArg[0]) ) zArg++;
16784 if( zArg[0]==0 ) break;
16785 if( zArg[0]=='-' ){
16786 onOff = 0;
16787 zArg++;
16788 }else if( zArg[0]=='+' ){
16789 onOff = 1;
16790 zArg++;
16791 }
16792 while( !isalpha(zArg[0]) ){
16793 if( zArg[0]==0 ) break;
16794 zArg++;
16795 }
16796 if( zArg[0]=='x' && isalpha(zArg[1]) ) zArg++;
16797 for(n=0; isalpha(zArg[n]); n++){}
16798 for(jj=0; jj<(int)(sizeof(aKw)/sizeof(aKw[0])); jj++){
16799 if( sqlite3_strnicmp(aKw[jj].z,(const char*)zArg,n)==0 ){
16800 if( onOff ){
16801 pInfo->mTrace |= aKw[jj].m;
16802 }else{
16803 pInfo->mTrace &= ~aKw[jj].m;
16804 }
16805 break;
16806 }
16807 }
16808 zArg += n;
16809 }
16810 }
16811 }
16812 sqlite3_snprintf(sizeof(zBuf), zBuf, "PRAGMA,[%s,%s]",a[1],a[2]);
16813 zOp = zBuf;
16814 break;
16815 }
16816 case SQLITE_FCNTL_BUSYHANDLER: zOp = "BUSYHANDLER"; break;
16817 case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
16818 case SQLITE_FCNTL_MMAP_SIZE: {
16819 sqlite3_int64 iMMap = *(sqlite3_int64*)pArg;
16820 sqlite3_snprintf(sizeof(zBuf), zBuf, "MMAP_SIZE,%lld",iMMap);
16821 zOp = zBuf;
16822 break;
16823 }
16824 case SQLITE_FCNTL_TRACE: zOp = "TRACE"; break;
16825 case SQLITE_FCNTL_HAS_MOVED: zOp = "HAS_MOVED"; break;
16826 case SQLITE_FCNTL_SYNC: zOp = "SYNC"; break;
16827 case SQLITE_FCNTL_COMMIT_PHASETWO: zOp = "COMMIT_PHASETWO"; break;
16828 case SQLITE_FCNTL_WIN32_SET_HANDLE: zOp = "WIN32_SET_HANDLE"; break;
16829 case SQLITE_FCNTL_WAL_BLOCK: zOp = "WAL_BLOCK"; break;
16830 case SQLITE_FCNTL_ZIPVFS: zOp = "ZIPVFS"; break;
16831 case SQLITE_FCNTL_RBU: zOp = "RBU"; break;
16832 case SQLITE_FCNTL_VFS_POINTER: zOp = "VFS_POINTER"; break;
16833 case SQLITE_FCNTL_JOURNAL_POINTER: zOp = "JOURNAL_POINTER"; break;
16834 case SQLITE_FCNTL_WIN32_GET_HANDLE: zOp = "WIN32_GET_HANDLE"; break;
16835 case SQLITE_FCNTL_PDB: zOp = "PDB"; break;
16836 case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: zOp = "BEGIN_ATOMIC_WRITE"; break;
16837 case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: zOp = "COMMIT_ATOMIC_WRITE"; break;
16838 case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
16839 zOp = "ROLLBACK_ATOMIC_WRITE";
16840 break;
16841 }
16842 case SQLITE_FCNTL_LOCK_TIMEOUT: {
16843 sqlite3_snprintf(sizeof(zBuf), zBuf, "LOCK_TIMEOUT,%d", *(int*)pArg);
16844 zOp = zBuf;
16845 break;
16846 }
16847 case SQLITE_FCNTL_DATA_VERSION: zOp = "DATA_VERSION"; break;
16848 case SQLITE_FCNTL_SIZE_LIMIT: zOp = "SIZE_LIMIT"; break;
16849 case SQLITE_FCNTL_CKPT_DONE: zOp = "CKPT_DONE"; break;
16850 case SQLITE_FCNTL_RESERVE_BYTES: zOp = "RESERVED_BYTES"; break;
16851 case SQLITE_FCNTL_CKPT_START: zOp = "CKPT_START"; break;
16852 case SQLITE_FCNTL_EXTERNAL_READER: zOp = "EXTERNAL_READER"; break;
16853 case SQLITE_FCNTL_CKSM_FILE: zOp = "CKSM_FILE"; break;
16854 case SQLITE_FCNTL_RESET_CACHE: zOp = "RESET_CACHE"; break;
16855 case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
16856 default: {
16857 sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
16858 zOp = zBuf;
16859 break;
16860 }
16861 }
16862 vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
16863 pInfo->zVfsName, p->zFName, zOp);
16864 rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
16865 if( rc==SQLITE_OK ){
16866 switch( op ){
16867 case SQLITE_FCNTL_VFSNAME: {
16868 *(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
16869 pInfo->zVfsName, *(char**)pArg);
16870 zRVal = *(char**)pArg;
16871 break;
16872 }
16873 case SQLITE_FCNTL_MMAP_SIZE: {
16874 sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%lld", *(sqlite3_int64*)pArg);
16875 zRVal = zBuf2;
16876 break;
16877 }
16878 case SQLITE_FCNTL_HAS_MOVED:
16879 case SQLITE_FCNTL_PERSIST_WAL: {
16880 sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%d", *(int*)pArg);
16881 zRVal = zBuf2;
16882 break;
16883 }
16884 case SQLITE_FCNTL_PRAGMA:
16885 case SQLITE_FCNTL_TEMPFILENAME: {
16886 zRVal = *(char**)pArg;
16887 break;
16888 }
16889 }
16890 }
16891 if( zRVal ){
16892 vfstrace_print_errcode(pInfo, " -> %s", rc);
16893 vfstrace_printf(pInfo, ", %s\n", zRVal);
16894 }else{
16895 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16896 }
16897 return rc;
16898 }
16899
16900 /*
16901 ** Return the sector-size in bytes for an vfstrace-file.
16902 */
16903 static int vfstraceSectorSize(sqlite3_file *pFile){
16904 vfstrace_file *p = (vfstrace_file *)pFile;
16905 vfstrace_info *pInfo = p->pInfo;
16906 int rc;
16907 vfstraceOnOff(pInfo, VTR_SECSZ);
16908 vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo->zVfsName, p->zFName);
16909 rc = p->pReal->pMethods->xSectorSize(p->pReal);
16910 vfstrace_printf(pInfo, " -> %d\n", rc);
16911 return rc;
16912 }
16913
16914 /*
16915 ** Return the device characteristic flags supported by an vfstrace-file.
16916 */
16917 static int vfstraceDeviceCharacteristics(sqlite3_file *pFile){
16918 vfstrace_file *p = (vfstrace_file *)pFile;
16919 vfstrace_info *pInfo = p->pInfo;
16920 int rc;
16921 vfstraceOnOff(pInfo, VTR_DEVCHAR);
16922 vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
16923 pInfo->zVfsName, p->zFName);
16924 rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
16925 vfstrace_printf(pInfo, " -> 0x%08x\n", rc);
16926 return rc;
16927 }
16928
16929 /*
16930 ** Shared-memory operations.
16931 */
16932 static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
16933 static const char *azLockName[] = {
16934 "WRITE",
16935 "CKPT",
16936 "RECOVER",
16937 "READ0",
16938 "READ1",
16939 "READ2",
16940 "READ3",
16941 "READ4",
16942 };
16943 vfstrace_file *p = (vfstrace_file *)pFile;
16944 vfstrace_info *pInfo = p->pInfo;
16945 int rc;
16946 char zLck[100];
16947 int i = 0;
16948 vfstraceOnOff(pInfo, VTR_SHMLOCK);
16949 memcpy(zLck, "|0", 3);
16950 if( flags & SQLITE_SHM_UNLOCK ) strappend(zLck, &i, "|UNLOCK");
16951 if( flags & SQLITE_SHM_LOCK ) strappend(zLck, &i, "|LOCK");
16952 if( flags & SQLITE_SHM_SHARED ) strappend(zLck, &i, "|SHARED");
16953 if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE");
16954 if( flags & ~(0xf) ){
16955 sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
16956 }
16957 if( ofst>=0 && ofst<(int)(sizeof(azLockName)/sizeof(azLockName[0])) ){
16958 vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d(%s),n=%d,%s)",
16959 pInfo->zVfsName, p->zFName, ofst, azLockName[ofst],
16960 n, &zLck[1]);
16961 }else{
16962 vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=5d,n=%d,%s)",
16963 pInfo->zVfsName, p->zFName, ofst,
16964 n, &zLck[1]);
16965 }
16966 rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
16967 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16968 return rc;
16969 }
16970 static int vfstraceShmMap(
16971 sqlite3_file *pFile,
16972 int iRegion,
16973 int szRegion,
16974 int isWrite,
16975 void volatile **pp
16976 ){
16977 vfstrace_file *p = (vfstrace_file *)pFile;
16978 vfstrace_info *pInfo = p->pInfo;
16979 int rc;
16980 vfstraceOnOff(pInfo, VTR_SHMMAP);
16981 vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,*)",
16982 pInfo->zVfsName, p->zFName, iRegion, szRegion, isWrite);
16983 rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
16984 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
16985 return rc;
16986 }
16987 static void vfstraceShmBarrier(sqlite3_file *pFile){
16988 vfstrace_file *p = (vfstrace_file *)pFile;
16989 vfstrace_info *pInfo = p->pInfo;
16990 vfstraceOnOff(pInfo, VTR_SHMBAR);
16991 vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo->zVfsName, p->zFName);
16992 p->pReal->pMethods->xShmBarrier(p->pReal);
16993 }
16994 static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
16995 vfstrace_file *p = (vfstrace_file *)pFile;
16996 vfstrace_info *pInfo = p->pInfo;
16997 int rc;
16998 vfstraceOnOff(pInfo, VTR_SHMUNMAP);
16999 vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
17000 pInfo->zVfsName, p->zFName, delFlag);
17001 rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
17002 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17003 return rc;
17004 }
17005
17006
17007
17008 /*
17009 ** Open an vfstrace file handle.
17010 */
17011 static int vfstraceOpen(
17012 sqlite3_vfs *pVfs,
17013 const char *zName,
17014 sqlite3_file *pFile,
17015 int flags,
17016 int *pOutFlags
17017 ){
17018 int rc;
17019 vfstrace_file *p = (vfstrace_file *)pFile;
17020 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17021 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17022 p->pInfo = pInfo;
17023 p->zFName = zName ? fileTail(zName) : "<temp>";
17024 p->pReal = (sqlite3_file *)&p[1];
17025 rc = pRoot->xOpen(pRoot, zName, p->pReal, flags, pOutFlags);
17026 vfstraceOnOff(pInfo, VTR_OPEN);
17027 vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
17028 pInfo->zVfsName, p->zFName, flags);
17029 if( p->pReal->pMethods ){
17030 sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
17031 const sqlite3_io_methods *pSub = p->pReal->pMethods;
17032 memset(pNew, 0, sizeof(*pNew));
17033 pNew->iVersion = pSub->iVersion;
17034 pNew->xClose = vfstraceClose;
17035 pNew->xRead = vfstraceRead;
17036 pNew->xWrite = vfstraceWrite;
17037 pNew->xTruncate = vfstraceTruncate;
17038 pNew->xSync = vfstraceSync;
17039 pNew->xFileSize = vfstraceFileSize;
17040 pNew->xLock = vfstraceLock;
17041 pNew->xUnlock = vfstraceUnlock;
17042 pNew->xCheckReservedLock = vfstraceCheckReservedLock;
17043 pNew->xFileControl = vfstraceFileControl;
17044 pNew->xSectorSize = vfstraceSectorSize;
17045 pNew->xDeviceCharacteristics = vfstraceDeviceCharacteristics;
17046 if( pNew->iVersion>=2 ){
17047 pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
17048 pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
17049 pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
17050 pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
17051 }
17052 pFile->pMethods = pNew;
17053 }
17054 vfstrace_print_errcode(pInfo, " -> %s", rc);
17055 if( pOutFlags ){
17056 vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
17057 }else{
17058 vfstrace_printf(pInfo, "\n");
17059 }
17060 return rc;
17061 }
17062
17063 /*
17064 ** Delete the file located at zPath. If the dirSync argument is true,
17065 ** ensure the file-system modifications are synced to disk before
17066 ** returning.
17067 */
17068 static int vfstraceDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
17069 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17070 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17071 int rc;
17072 vfstraceOnOff(pInfo, VTR_DELETE);
17073 vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
17074 pInfo->zVfsName, zPath, dirSync);
17075 rc = pRoot->xDelete(pRoot, zPath, dirSync);
17076 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17077 return rc;
17078 }
17079
17080 /*
17081 ** Test for access permissions. Return true if the requested permission
17082 ** is available, or false otherwise.
17083 */
17084 static int vfstraceAccess(
17085 sqlite3_vfs *pVfs,
17086 const char *zPath,
17087 int flags,
17088 int *pResOut
17089 ){
17090 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17091 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17092 int rc;
17093 vfstraceOnOff(pInfo, VTR_ACCESS);
17094 vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
17095 pInfo->zVfsName, zPath, flags);
17096 rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
17097 vfstrace_print_errcode(pInfo, " -> %s", rc);
17098 vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
17099 return rc;
17100 }
17101
17102 /*
17103 ** Populate buffer zOut with the full canonical pathname corresponding
17104 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
17105 ** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
17106 */
17107 static int vfstraceFullPathname(
17108 sqlite3_vfs *pVfs,
17109 const char *zPath,
17110 int nOut,
17111 char *zOut
17112 ){
17113 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17114 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17115 int rc;
17116 vfstraceOnOff(pInfo, VTR_FULLPATH);
17117 vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
17118 pInfo->zVfsName, zPath);
17119 rc = pRoot->xFullPathname(pRoot, zPath, nOut, zOut);
17120 vfstrace_print_errcode(pInfo, " -> %s", rc);
17121 vfstrace_printf(pInfo, ", out=\"%.*s\"\n", nOut, zOut);
17122 return rc;
17123 }
17124
17125 /*
17126 ** Open the dynamic library located at zPath and return a handle.
17127 */
17128 static void *vfstraceDlOpen(sqlite3_vfs *pVfs, const char *zPath){
17129 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17130 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17131 vfstraceOnOff(pInfo, VTR_DLOPEN);
17132 vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo->zVfsName, zPath);
17133 return pRoot->xDlOpen(pRoot, zPath);
17134 }
17135
17136 /*
17137 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
17138 ** utf-8 string describing the most recent error encountered associated
17139 ** with dynamic libraries.
17140 */
17141 static void vfstraceDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
17142 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17143 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17144 vfstraceOnOff(pInfo, VTR_DLERR);
17145 vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo->zVfsName, nByte);
17146 pRoot->xDlError(pRoot, nByte, zErrMsg);
17147 vfstrace_printf(pInfo, " -> \"%s\"", zErrMsg);
17148 }
17149
17150 /*
17151 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
17152 */
17153 static void (*vfstraceDlSym(sqlite3_vfs *pVfs,void *p,const char *zSym))(void){
17154 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17155 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17156 vfstrace_printf(pInfo, "%s.xDlSym(\"%s\")\n", pInfo->zVfsName, zSym);
17157 return pRoot->xDlSym(pRoot, p, zSym);
17158 }
17159
17160 /*
17161 ** Close the dynamic library handle pHandle.
17162 */
17163 static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
17164 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17165 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17166 vfstraceOnOff(pInfo, VTR_DLCLOSE);
17167 vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
17168 pRoot->xDlClose(pRoot, pHandle);
17169 }
17170
17171 /*
17172 ** Populate the buffer pointed to by zBufOut with nByte bytes of
17173 ** random data.
17174 */
17175 static int vfstraceRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
17176 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17177 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17178 vfstraceOnOff(pInfo, VTR_RAND);
17179 vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo->zVfsName, nByte);
17180 return pRoot->xRandomness(pRoot, nByte, zBufOut);
17181 }
17182
17183 /*
17184 ** Sleep for nMicro microseconds. Return the number of microseconds
17185 ** actually slept.
17186 */
17187 static int vfstraceSleep(sqlite3_vfs *pVfs, int nMicro){
17188 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17189 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17190 vfstraceOnOff(pInfo, VTR_SLEEP);
17191 vfstrace_printf(pInfo, "%s.xSleep(%d)\n", pInfo->zVfsName, nMicro);
17192 return pRoot->xSleep(pRoot, nMicro);
17193 }
17194
17195 /*
17196 ** Return the current time as a Julian Day number in *pTimeOut.
17197 */
17198 static int vfstraceCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
17199 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17200 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17201 int rc;
17202 vfstraceOnOff(pInfo, VTR_CURTIME);
17203 vfstrace_printf(pInfo, "%s.xCurrentTime()", pInfo->zVfsName);
17204 rc = pRoot->xCurrentTime(pRoot, pTimeOut);
17205 vfstrace_printf(pInfo, " -> %.17g\n", *pTimeOut);
17206 return rc;
17207 }
17208 static int vfstraceCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
17209 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17210 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17211 int rc;
17212 vfstraceOnOff(pInfo, VTR_CURTIME);
17213 vfstrace_printf(pInfo, "%s.xCurrentTimeInt64()", pInfo->zVfsName);
17214 rc = pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
17215 vfstrace_printf(pInfo, " -> %lld\n", *pTimeOut);
17216 return rc;
17217 }
17218
17219 /*
17220 ** Return the most recent error code and message
17221 */
17222 static int vfstraceGetLastError(sqlite3_vfs *pVfs, int nErr, char *zErr){
17223 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17224 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17225 int rc;
17226 vfstraceOnOff(pInfo, VTR_LASTERR);
17227 vfstrace_printf(pInfo, "%s.xGetLastError(%d,zBuf)", pInfo->zVfsName, nErr);
17228 if( nErr ) zErr[0] = 0;
17229 rc = pRoot->xGetLastError(pRoot, nErr, zErr);
17230 vfstrace_printf(pInfo, " -> zBuf[] = \"%s\", rc = %d\n", nErr?zErr:"", rc);
17231 return rc;
17232 }
17233
17234 /*
17235 ** Override system calls.
17236 */
17237 static int vfstraceSetSystemCall(
17238 sqlite3_vfs *pVfs,
17239 const char *zName,
17240 sqlite3_syscall_ptr pFunc
17241 ){
17242 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17243 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17244 return pRoot->xSetSystemCall(pRoot, zName, pFunc);
17245 }
17246 static sqlite3_syscall_ptr vfstraceGetSystemCall(
17247 sqlite3_vfs *pVfs,
17248 const char *zName
17249 ){
17250 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17251 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17252 return pRoot->xGetSystemCall(pRoot, zName);
17253 }
17254 static const char *vfstraceNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
17255 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17256 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17257 return pRoot->xNextSystemCall(pRoot, zName);
17258 }
17259
17260
17261 /*
17262 ** Clients invoke this routine to construct a new trace-vfs shim.
17263 **
17264 ** Return SQLITE_OK on success.
17265 **
17266 ** SQLITE_NOMEM is returned in the case of a memory allocation error.
17267 ** SQLITE_NOTFOUND is returned if zOldVfsName does not exist.
17268 */
17269 int vfstrace_register(
17270 const char *zTraceName, /* Name of the newly constructed VFS */
17271 const char *zOldVfsName, /* Name of the underlying VFS */
17272 int (*xOut)(const char*,void*), /* Output routine. ex: fputs */
17273 void *pOutArg, /* 2nd argument to xOut. ex: stderr */
17274 int makeDefault /* True to make the new VFS the default */
17275 ){
17276 sqlite3_vfs *pNew;
17277 sqlite3_vfs *pRoot;
17278 vfstrace_info *pInfo;
17279 size_t nName;
17280 size_t nByte;
17281
17282 pRoot = sqlite3_vfs_find(zOldVfsName);
17283 if( pRoot==0 ) return SQLITE_NOTFOUND;
17284 nName = strlen(zTraceName);
17285 nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
17286 pNew = sqlite3_malloc64( nByte );
17287 if( pNew==0 ) return SQLITE_NOMEM;
17288 memset(pNew, 0, nByte);
17289 pInfo = (vfstrace_info*)&pNew[1];
17290 pNew->iVersion = pRoot->iVersion;
17291 pNew->szOsFile = pRoot->szOsFile + sizeof(vfstrace_file);
17292 pNew->mxPathname = pRoot->mxPathname;
17293 pNew->zName = (char*)&pInfo[1];
17294 memcpy((char*)&pInfo[1], zTraceName, nName+1);
17295 pNew->pAppData = pInfo;
17296 pNew->xOpen = vfstraceOpen;
17297 pNew->xDelete = vfstraceDelete;
17298 pNew->xAccess = vfstraceAccess;
17299 pNew->xFullPathname = vfstraceFullPathname;
17300 pNew->xDlOpen = pRoot->xDlOpen==0 ? 0 : vfstraceDlOpen;
17301 pNew->xDlError = pRoot->xDlError==0 ? 0 : vfstraceDlError;
17302 pNew->xDlSym = pRoot->xDlSym==0 ? 0 : vfstraceDlSym;
17303 pNew->xDlClose = pRoot->xDlClose==0 ? 0 : vfstraceDlClose;
17304 pNew->xRandomness = vfstraceRandomness;
17305 pNew->xSleep = vfstraceSleep;
17306 pNew->xCurrentTime = vfstraceCurrentTime;
17307 pNew->xGetLastError = pRoot->xGetLastError==0 ? 0 : vfstraceGetLastError;
17308 if( pNew->iVersion>=2 ){
17309 pNew->xCurrentTimeInt64 = pRoot->xCurrentTimeInt64==0 ? 0 :
17310 vfstraceCurrentTimeInt64;
17311 if( pNew->iVersion>=3 ){
17312 pNew->xSetSystemCall = pRoot->xSetSystemCall==0 ? 0 :
17313 vfstraceSetSystemCall;
17314 pNew->xGetSystemCall = pRoot->xGetSystemCall==0 ? 0 :
17315 vfstraceGetSystemCall;
17316 pNew->xNextSystemCall = pRoot->xNextSystemCall==0 ? 0 :
17317 vfstraceNextSystemCall;
17318 }
17319 }
17320 pInfo->pRootVfs = pRoot;
17321 pInfo->xOut = xOut;
17322 pInfo->pOutArg = pOutArg;
17323 pInfo->zVfsName = pNew->zName;
17324 pInfo->pTraceVfs = pNew;
17325 pInfo->mTrace = 0xffffffff;
17326 pInfo->bOn = 1;
17327 vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
17328 pInfo->zVfsName, pRoot->zName);
17329 return sqlite3_vfs_register(pNew, makeDefault);
17330 }
17331
17332 /*
17333 ** Look for the named VFS. If it is a TRACEVFS, then unregister it
17334 ** and delete it.
17335 */
17336 void vfstrace_unregister(const char *zTraceName){
17337 sqlite3_vfs *pVfs = sqlite3_vfs_find(zTraceName);
17338 if( pVfs==0 ) return;
17339 if( pVfs->xOpen!=vfstraceOpen ) return;
17340 sqlite3_vfs_unregister(pVfs);
17341 sqlite3_free(pVfs);
17342 }
17343
17344 /************************* End ../ext/misc/vfstrace.c ********************/
17345
17346 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
17347 #define SQLITE_SHELL_HAVE_RECOVER 1
17348 #else
17349 #define SQLITE_SHELL_HAVE_RECOVER 0
@@ -18241,11 +19370,11 @@
19370 }while( strstr(z,zBuf)!=0 );
19371 return zBuf;
19372 }
19373
19374 /*
19375 ** Implementation of scalar SQL function "escape_crlf". The argument passed to
19376 ** this function is the output of built-in function quote(). If the first
19377 ** character of the input is "'", indicating that the value passed to quote()
19378 ** was a text value, then this function searches the input for "\n" and "\r"
19379 ** characters and adds a wrapper similar to the following:
19380 **
@@ -18252,11 +19381,11 @@
19381 ** replace(replace(<input>, '\n', char(10), '\r', char(13));
19382 **
19383 ** Or, if the first character of the input is not "'", then a copy of the input
19384 ** is returned.
19385 */
19386 static void recoverEscapeCrlf(
19387 sqlite3_context *context,
19388 int argc,
19389 sqlite3_value **argv
19390 ){
19391 const char *zText = (const char*)sqlite3_value_text(argv[0]);
@@ -18467,11 +19596,11 @@
19596 void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
19597 } aFunc[] = {
19598 { "getpage", 1, recoverGetPage },
19599 { "page_is_used", 1, recoverPageIsUsed },
19600 { "read_i32", 2, recoverReadI32 },
19601 { "escape_crlf", 1, recoverEscapeCrlf },
19602 };
19603
19604 const int flags = SQLITE_OPEN_URI|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
19605 sqlite3 *db = 0; /* New database handle */
19606 int ii; /* For iterating through aFunc[] */
@@ -18820,11 +19949,11 @@
19949 assert( pTab->aCol[ii].iField>=0 && pTab->aCol[ii].iBind>=1 );
19950 zSql = recoverMPrintf(p, "%z%s%Q", zSql, zSep, pTab->aCol[ii].zCol);
19951
19952 if( bSql ){
19953 zBind = recoverMPrintf(p,
19954 "%z%sescape_crlf(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
19955 );
19956 zSqlSep = "||', '||";
19957 }else{
19958 zBind = recoverMPrintf(p, "%z%s?%d", zBind, zSep, pTab->aCol[ii].iBind);
19959 }
@@ -19322,10 +20451,12 @@
20451 apVal[iField] = sqlite3_value_dup( pVal );
20452 if( apVal[iField]==0 ){
20453 recoverError(p, SQLITE_NOMEM, 0);
20454 }
20455 p1->nVal = iField+1;
20456 }else if( pTab->nCol==0 ){
20457 p1->nVal = pTab->nCol;
20458 }
20459 p1->iPrevCell = iCell;
20460 p1->iPrevPage = iPage;
20461 }
20462 }else{
@@ -20437,10 +21568,11 @@
21568 u8 nEqpLevel; /* Depth of the EQP output graph */
21569 u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
21570 u8 bSafeMode; /* True to prohibit unsafe operations */
21571 u8 bSafeModePersist; /* The long-term value of bSafeMode */
21572 u8 eRestoreState; /* See comments above doAutoDetectRestore() */
21573 u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
21574 ColModeOpts cmOpts; /* Option values affecting columnar mode output */
21575 unsigned statsOn; /* True to display memory stats before each finalize */
21576 unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
21577 int inputNesting; /* Track nesting level of .read and other redirects */
21578 int outCount; /* Revert to stdout when reaching zero */
@@ -20582,10 +21714,11 @@
21714 #define MODE_Table 15 /* MySQL-style table formatting */
21715 #define MODE_Box 16 /* Unicode box-drawing characters */
21716 #define MODE_Count 17 /* Output only a count of the rows of output */
21717 #define MODE_Off 18 /* No query output shown */
21718 #define MODE_ScanExp 19 /* Like MODE_Explain, but for ".scanstats vm" */
21719 #define MODE_Www 20 /* Full web-page output */
21720
21721 static const char *modeDescr[] = {
21722 "line",
21723 "column",
21724 "list",
@@ -20602,11 +21735,13 @@
21735 "json",
21736 "markdown",
21737 "table",
21738 "box",
21739 "count",
21740 "off",
21741 "scanexp",
21742 "www",
21743 };
21744
21745 /*
21746 ** These are the column/row/line separators used by the various
21747 ** import/export modes.
@@ -20630,11 +21765,11 @@
21765 ** A callback for the sqlite3_log() interface.
21766 */
21767 static void shellLog(void *pArg, int iErrCode, const char *zMsg){
21768 ShellState *p = (ShellState*)pArg;
21769 if( p->pLog==0 ) return;
21770 sqlite3_fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
21771 fflush(p->pLog);
21772 }
21773
21774 /*
21775 ** SQL function: shell_putsnl(X)
@@ -20645,13 +21780,13 @@
21780 static void shellPutsFunc(
21781 sqlite3_context *pCtx,
21782 int nVal,
21783 sqlite3_value **apVal
21784 ){
21785 ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
21786 (void)nVal;
21787 sqlite3_fprintf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
21788 sqlite3_result_value(pCtx, apVal[0]);
21789 }
21790
21791 /*
21792 ** If in safe mode, print an error message described by the arguments
@@ -20666,11 +21801,11 @@
21801 va_list ap;
21802 char *zMsg;
21803 va_start(ap, zErrMsg);
21804 zMsg = sqlite3_vmprintf(zErrMsg, ap);
21805 va_end(ap);
21806 sqlite3_fprintf(stderr, "line %d: %s\n", p->lineno, zMsg);
21807 exit(1);
21808 }
21809 }
21810
21811 /*
@@ -20699,11 +21834,11 @@
21834 char *zTempFile = 0;
21835 sqlite3 *db;
21836 char *zCmd = 0;
21837 int bBin;
21838 int rc;
21839 int hasCRLF = 0;
21840 FILE *f = 0;
21841 sqlite3_int64 sz;
21842 sqlite3_int64 x;
21843 unsigned char *p = 0;
21844
@@ -20733,11 +21868,11 @@
21868 }
21869 }
21870 bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
21871 /* When writing the file to be edited, do \n to \r\n conversions on systems
21872 ** that want \r\n line endings */
21873 f = sqlite3_fopen(zTempFile, bBin ? "wb" : "w");
21874 if( f==0 ){
21875 sqlite3_result_error(context, "edit() cannot open temp file", -1);
21876 goto edit_func_end;
21877 }
21878 sz = sqlite3_value_bytes(argv[0]);
@@ -20744,11 +21879,11 @@
21879 if( bBin ){
21880 x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
21881 }else{
21882 const char *z = (const char*)sqlite3_value_text(argv[0]);
21883 /* Remember whether or not the value originally contained \r\n */
21884 if( z && strstr(z,"\r\n")!=0 ) hasCRLF = 1;
21885 x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
21886 }
21887 fclose(f);
21888 f = 0;
21889 if( x!=sz ){
@@ -20764,11 +21899,11 @@
21899 sqlite3_free(zCmd);
21900 if( rc ){
21901 sqlite3_result_error(context, "EDITOR returned non-zero", -1);
21902 goto edit_func_end;
21903 }
21904 f = sqlite3_fopen(zTempFile, "rb");
21905 if( f==0 ){
21906 sqlite3_result_error(context,
21907 "edit() cannot reopen temp file after edit", -1);
21908 goto edit_func_end;
21909 }
@@ -20789,11 +21924,11 @@
21924 }
21925 if( bBin ){
21926 sqlite3_result_blob64(context, p, sz, sqlite3_free);
21927 }else{
21928 sqlite3_int64 i, j;
21929 if( hasCRLF ){
21930 /* If the original contains \r\n then do no conversions back to \n */
21931 }else{
21932 /* If the file did not originally contain \r\n then convert any new
21933 ** \r\n back into \n */
21934 p[sz] = 0;
@@ -20830,15 +21965,30 @@
21965 p->mode = p->modePrior;
21966 p->shellFlgs = p->priorShFlgs;
21967 memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
21968 memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
21969 }
21970
21971 /*
21972 ** Set output mode to text or binary for Windows.
21973 */
21974 static void setCrlfMode(ShellState *p){
21975 #ifdef _WIN32
21976 if( p->crlfMode ){
21977 sqlite3_fsetmode(p->out, _O_TEXT);
21978 }else{
21979 sqlite3_fsetmode(p->out, _O_BINARY);
21980 }
21981 #else
21982 UNUSED_PARAMETER(p);
21983 #endif
21984 }
21985
21986 /*
21987 ** Output the given string as a hex-encoded blob (eg. X'1234' )
21988 */
21989 static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
21990 int i;
21991 unsigned char *aBlob = (unsigned char*)pBlob;
21992
21993 char *zStr = sqlite3_malloc(nBlob*2 + 1);
21994 shell_check_oom(zStr);
@@ -20851,11 +22001,11 @@
22001 zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
22002 zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
22003 }
22004 zStr[i*2] = '\0';
22005
22006 sqlite3_fprintf(out, "X'%s'", zStr);
22007 sqlite3_free(zStr);
22008 }
22009
22010 /*
22011 ** Find a string that is not found anywhere in z[]. Return a pointer
@@ -20881,46 +22031,40 @@
22031 /*
22032 ** Output the given string as a quoted string using SQL quoting conventions.
22033 **
22034 ** See also: output_quoted_escaped_string()
22035 */
22036 static void output_quoted_string(ShellState *p, const char *z){
22037 int i;
22038 char c;
22039 FILE *out = p->out;
22040 sqlite3_fsetmode(out, _O_BINARY);
 
 
22041 if( z==0 ) return;
22042 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
22043 if( c==0 ){
22044 sqlite3_fprintf(out, "'%s'",z);
22045 }else{
22046 sqlite3_fputs("'", out);
22047 while( *z ){
22048 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
22049 if( c=='\'' ) i++;
22050 if( i ){
22051 sqlite3_fprintf(out, "%.*s", i, z);
22052 z += i;
22053 }
22054 if( c=='\'' ){
22055 sqlite3_fputs("'", out);
22056 continue;
22057 }
22058 if( c==0 ){
22059 break;
22060 }
22061 z++;
22062 }
22063 sqlite3_fputs("'", out);
22064 }
22065 setCrlfMode(p);
 
 
 
 
22066 }
22067
22068 /*
22069 ** Output the given string as a quoted string using SQL quoting conventions.
22070 ** Additionallly , escape the "\n" and "\r" characters so that they do not
@@ -20928,20 +22072,18 @@
22072 ** systems.
22073 **
22074 ** This is like output_quoted_string() but with the addition of the \r\n
22075 ** escape mechanism.
22076 */
22077 static void output_quoted_escaped_string(ShellState *p, const char *z){
22078 int i;
22079 char c;
22080 FILE *out = p->out;
22081 sqlite3_fsetmode(out, _O_BINARY);
 
 
22082 for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
22083 if( c==0 ){
22084 sqlite3_fprintf(out, "'%s'",z);
22085 }else{
22086 const char *zNL = 0;
22087 const char *zCR = 0;
22088 int nNL = 0;
22089 int nCR = 0;
@@ -20949,52 +22091,48 @@
22091 for(i=0; z[i]; i++){
22092 if( z[i]=='\n' ) nNL++;
22093 if( z[i]=='\r' ) nCR++;
22094 }
22095 if( nNL ){
22096 sqlite3_fputs("replace(", out);
22097 zNL = unused_string(z, "\\n", "\\012", zBuf1);
22098 }
22099 if( nCR ){
22100 sqlite3_fputs("replace(", out);
22101 zCR = unused_string(z, "\\r", "\\015", zBuf2);
22102 }
22103 sqlite3_fputs("'", out);
22104 while( *z ){
22105 for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
22106 if( c=='\'' ) i++;
22107 if( i ){
22108 sqlite3_fprintf(out, "%.*s", i, z);
22109 z += i;
22110 }
22111 if( c=='\'' ){
22112 sqlite3_fputs("'", out);
22113 continue;
22114 }
22115 if( c==0 ){
22116 break;
22117 }
22118 z++;
22119 if( c=='\n' ){
22120 sqlite3_fputs(zNL, out);
22121 continue;
22122 }
22123 sqlite3_fputs(zCR, out);
22124 }
22125 sqlite3_fputs("'", out);
22126 if( nCR ){
22127 sqlite3_fprintf(out, ",'%s',char(13))", zCR);
22128 }
22129 if( nNL ){
22130 sqlite3_fprintf(out, ",'%s',char(10))", zNL);
22131 }
22132 }
22133 setCrlfMode(p);
 
 
 
 
22134 }
22135
22136 /*
22137 ** Find earliest of chars within s specified in zAny.
22138 ** With ns == ~0, is like strpbrk(s,zAny) and s must be 0-terminated.
@@ -21010,26 +22148,64 @@
22148 }
22149 ++zAny;
22150 }
22151 return pcFirst;
22152 }
22153
22154 /* Skip over as much z[] input char sequence as is valid UTF-8,
22155 ** limited per nAccept char's or whole characters and containing
22156 ** no char cn such that ((1<<cn) & ccm)!=0. On return, the
22157 ** sequence z:return (inclusive:exclusive) is validated UTF-8.
22158 ** Limit: nAccept>=0 => char count, nAccept<0 => character
22159 */
22160 const char *zSkipValidUtf8(const char *z, int nAccept, long ccm){
22161 int ng = (nAccept<0)? -nAccept : 0;
22162 const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
22163 assert(z!=0);
22164 while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
22165 unsigned char c = *(u8*)z;
22166 if( c<0x7f ){
22167 if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
22168 ++z; /* ASCII */
22169 }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
22170 else{
22171 const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
22172 do{
22173 if( pcLimit && zt >= pcLimit ) return z;
22174 else{
22175 char ct = *zt++;
22176 if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
22177 /* Trailing bytes are too few, too many, or invalid. */
22178 return z;
22179 }
22180 }
22181 } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
22182 z = zt;
22183 }
22184 }
22185 return z;
22186 }
22187
22188
22189 /*
22190 ** Output the given string as a quoted according to C or TCL quoting rules.
22191 */
22192 static void output_c_string(FILE *out, const char *z){
22193 char c;
22194 static const char *zq = "\"";
22195 static long ctrlMask = ~0L;
22196 static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */
22197 char ace[3] = "\\?";
22198 char cbsSay;
22199 sqlite3_fputs(zq, out);
22200 while( *z!=0 ){
22201 const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0);
22202 const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask);
22203 const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast;
22204 if( pcEnd > z ){
22205 sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
22206 }
22207 if( (c = *pcEnd)==0 ) break;
22208 ++pcEnd;
22209 switch( c ){
22210 case '\\': case '"':
22211 cbsSay = (char)c;
@@ -21040,47 +22216,47 @@
22216 case '\f': cbsSay = 'f'; break;
22217 default: cbsSay = 0; break;
22218 }
22219 if( cbsSay ){
22220 ace[1] = cbsSay;
22221 sqlite3_fputs(ace, out);
22222 }else if( !isprint(c&0xff) ){
22223 sqlite3_fprintf(out, "\\%03o", c&0xff);
22224 }else{
22225 ace[1] = (char)c;
22226 sqlite3_fputs(ace+1, out);
22227 }
22228 z = pcEnd;
22229 }
22230 sqlite3_fputs(zq, out);
22231 }
22232
22233 /*
22234 ** Output the given string as quoted according to JSON quoting rules.
22235 */
22236 static void output_json_string(FILE *out, const char *z, i64 n){
22237 unsigned char c;
22238 static const char *zq = "\"";
22239 static long ctrlMask = ~0L;
22240 static const char *zDQBS = "\"\\";
22241 const char *pcLimit;
22242 char ace[3] = "\\?";
22243 char cbsSay;
22244
22245 if( z==0 ) z = "";
22246 pcLimit = z + ((n<0)? strlen(z) : (size_t)n);
22247 sqlite3_fputs(zq, out);
22248 while( z < pcLimit ){
22249 const char *pcDQBS = anyOfInStr(z, zDQBS, pcLimit-z);
22250 const char *pcPast = zSkipValidUtf8(z, (int)(pcLimit-z), ctrlMask);
22251 const char *pcEnd = (pcDQBS && pcDQBS < pcPast)? pcDQBS : pcPast;
22252 if( pcEnd > z ){
22253 sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
22254 z = pcEnd;
22255 }
22256 if( z >= pcLimit ) break;
22257 c = (unsigned char)*(z++);
22258 switch( c ){
22259 case '"': case '\\':
22260 cbsSay = (char)c;
22261 break;
22262 case '\b': cbsSay = 'b'; break;
@@ -21090,26 +22266,26 @@
22266 case '\t': cbsSay = 't'; break;
22267 default: cbsSay = 0; break;
22268 }
22269 if( cbsSay ){
22270 ace[1] = cbsSay;
22271 sqlite3_fputs(ace, out);
22272 }else if( c<=0x1f || c>=0x7f ){
22273 sqlite3_fprintf(out, "\\u%04x", c);
22274 }else{
22275 ace[1] = (char)c;
22276 sqlite3_fputs(ace+1, out);
22277 }
22278 }
22279 sqlite3_fputs(zq, out);
22280 }
22281
22282 /*
22283 ** Output the given string with characters that are special to
22284 ** HTML escaped.
22285 */
22286 static void output_html_string(FILE *out, const char *z){
22287 int i;
22288 if( z==0 ) z = "";
22289 while( *z ){
22290 for(i=0; z[i]
22291 && z[i]!='<'
@@ -21117,22 +22293,22 @@
22293 && z[i]!='>'
22294 && z[i]!='\"'
22295 && z[i]!='\'';
22296 i++){}
22297 if( i>0 ){
22298 sqlite3_fprintf(out, "%.*s",i,z);
22299 }
22300 if( z[i]=='<' ){
22301 sqlite3_fputs("&lt;", out);
22302 }else if( z[i]=='&' ){
22303 sqlite3_fputs("&amp;", out);
22304 }else if( z[i]=='>' ){
22305 sqlite3_fputs("&gt;", out);
22306 }else if( z[i]=='\"' ){
22307 sqlite3_fputs("&quot;", out);
22308 }else if( z[i]=='\'' ){
22309 sqlite3_fputs("&#39;", out);
22310 }else{
22311 break;
22312 }
22313 z += i + 1;
22314 }
@@ -21167,11 +22343,11 @@
22343 ** the null value. Strings are quoted if necessary. The separator
22344 ** is only issued if bSep is true.
22345 */
22346 static void output_csv(ShellState *p, const char *z, int bSep){
22347 if( z==0 ){
22348 sqlite3_fprintf(p->out, "%s",p->nullValue);
22349 }else{
22350 unsigned i;
22351 for(i=0; z[i]; i++){
22352 if( needCsvQuote[((unsigned char*)z)[i]] ){
22353 i = 0;
@@ -21179,18 +22355,18 @@
22355 }
22356 }
22357 if( i==0 || strstr(z, p->colSeparator)!=0 ){
22358 char *zQuoted = sqlite3_mprintf("\"%w\"", z);
22359 shell_check_oom(zQuoted);
22360 sqlite3_fputs(zQuoted, p->out);
22361 sqlite3_free(zQuoted);
22362 }else{
22363 sqlite3_fputs(z, p->out);
22364 }
22365 }
22366 if( bSep ){
22367 sqlite3_fputs(p->colSeparator, p->out);
22368 }
22369 }
22370
22371 /*
22372 ** This routine runs when the user presses Ctrl-C
@@ -21294,20 +22470,20 @@
22470 const char *az[4];
22471 az[0] = zA1;
22472 az[1] = zA2;
22473 az[2] = zA3;
22474 az[3] = zA4;
22475 sqlite3_fprintf(p->out, "authorizer: %s", azAction[op]);
22476 for(i=0; i<4; i++){
22477 sqlite3_fputs(" ", p->out);
22478 if( az[i] ){
22479 output_c_string(p->out, az[i]);
22480 }else{
22481 sqlite3_fputs("NULL", p->out);
22482 }
22483 }
22484 sqlite3_fputs("\n", p->out);
22485 if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
22486 return SQLITE_OK;
22487 }
22488 #endif
22489
@@ -21319,11 +22495,11 @@
22495 **
22496 ** If the schema statement in z[] contains a start-of-comment and if
22497 ** sqlite3_complete() returns false, try to terminate the comment before
22498 ** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
22499 */
22500 static void printSchemaLine(FILE *out, const char *z, const char *zTail){
22501 char *zToFree = 0;
22502 if( z==0 ) return;
22503 if( zTail==0 ) return;
22504 if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
22505 const char *zOrig = z;
@@ -21341,20 +22517,20 @@
22517 }
22518 sqlite3_free(zNew);
22519 }
22520 }
22521 if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
22522 sqlite3_fprintf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
22523 }else{
22524 sqlite3_fprintf(out, "%s%s", z, zTail);
22525 }
22526 sqlite3_free(zToFree);
22527 }
22528 static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
22529 char c = z[n];
22530 z[n] = 0;
22531 printSchemaLine(out, z, zTail);
22532 z[n] = c;
22533 }
22534
22535 /*
22536 ** Return true if string z[] has nothing but whitespace and comments to the
@@ -21378,11 +22554,11 @@
22554 EQPGraphRow *pNew;
22555 i64 nText;
22556 if( zText==0 ) return;
22557 nText = strlen(zText);
22558 if( p->autoEQPtest ){
22559 sqlite3_fprintf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
22560 }
22561 pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
22562 shell_check_oom(pNew);
22563 pNew->iEqpId = iEqpId;
22564 pNew->iParentId = p2;
@@ -21426,11 +22602,12 @@
22602 i64 n = strlen(p->sGraph.zPrefix);
22603 char *z;
22604 for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
22605 pNext = eqp_next_row(p, iEqpId, pRow);
22606 z = pRow->zText;
22607 sqlite3_fprintf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
22608 pNext ? "|--" : "`--", z);
22609 if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
22610 memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
22611 eqp_render_level(p, pRow->iEqpId);
22612 p->sGraph.zPrefix[n] = 0;
22613 }
@@ -21446,17 +22623,17 @@
22623 if( pRow->zText[0]=='-' ){
22624 if( pRow->pNext==0 ){
22625 eqp_reset(p);
22626 return;
22627 }
22628 sqlite3_fprintf(p->out, "%s\n", pRow->zText+3);
22629 p->sGraph.pRow = pRow->pNext;
22630 sqlite3_free(pRow);
22631 }else if( nCycle>0 ){
22632 sqlite3_fprintf(p->out, "QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
22633 }else{
22634 sqlite3_fputs("QUERY PLAN\n", p->out);
22635 }
22636 p->sGraph.zPrefix[0] = 0;
22637 eqp_render_level(p, 0);
22638 eqp_reset(p);
22639 }
@@ -21468,33 +22645,33 @@
22645 */
22646 static int progress_handler(void *pClientData) {
22647 ShellState *p = (ShellState*)pClientData;
22648 p->nProgress++;
22649 if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
22650 sqlite3_fprintf(p->out, "Progress limit reached (%u)\n", p->nProgress);
22651 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
22652 if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
22653 return 1;
22654 }
22655 if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
22656 sqlite3_fprintf(p->out, "Progress %u\n", p->nProgress);
22657 }
22658 return 0;
22659 }
22660 #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
22661
22662 /*
22663 ** Print N dashes
22664 */
22665 static void print_dashes(FILE *out, int N){
22666 const char zDash[] = "--------------------------------------------------";
22667 const int nDash = sizeof(zDash) - 1;
22668 while( N>nDash ){
22669 sqlite3_fputs(zDash, out);
22670 N -= nDash;
22671 }
22672 sqlite3_fprintf(out, "%.*s", N, zDash);
22673 }
22674
22675 /*
22676 ** Print a markdown or table-style row separator using ascii-art
22677 */
@@ -21503,19 +22680,19 @@
22680 int nArg,
22681 const char *zSep
22682 ){
22683 int i;
22684 if( nArg>0 ){
22685 sqlite3_fputs(zSep, p->out);
22686 print_dashes(p->out, p->actualWidth[0]+2);
22687 for(i=1; i<nArg; i++){
22688 sqlite3_fputs(zSep, p->out);
22689 print_dashes(p->out, p->actualWidth[i]+2);
22690 }
22691 sqlite3_fputs(zSep, p->out);
22692 }
22693 sqlite3_fputs("\n", p->out);
22694 }
22695
22696 /*
22697 ** This is the callback routine that the shell
22698 ** invokes for each row of a query result.
@@ -21541,13 +22718,13 @@
22718 if( azArg==0 ) break;
22719 for(i=0; i<nArg; i++){
22720 int len = strlen30(azCol[i] ? azCol[i] : "");
22721 if( len>w ) w = len;
22722 }
22723 if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
22724 for(i=0; i<nArg; i++){
22725 sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
22726 azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
22727 }
22728 break;
22729 }
22730 case MODE_ScanExp:
@@ -21571,16 +22748,16 @@
22748 if( nArg>nWidth ) nArg = nWidth;
22749
22750 /* If this is the first row seen, print out the headers */
22751 if( p->cnt++==0 ){
22752 for(i=0; i<nArg; i++){
22753 utf8_width_print(p->out, aWidth[i], azCol[ aMap[i] ]);
22754 sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
22755 }
22756 for(i=0; i<nArg; i++){
22757 print_dashes(p->out, aWidth[i]);
22758 sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
22759 }
22760 }
22761
22762 /* If there is no data, exit early. */
22763 if( azArg==0 ) break;
@@ -21594,21 +22771,21 @@
22771 w = strlenChar(zVal);
22772 zSep = " ";
22773 }
22774 if( i==iIndent && p->aiIndent && p->pStmt ){
22775 if( p->iIndent<p->nIndent ){
22776 sqlite3_fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
22777 }
22778 p->iIndent++;
22779 }
22780 utf8_width_print(p->out, w, zVal ? zVal : p->nullValue);
22781 sqlite3_fputs(i==nArg-1 ? "\n" : zSep, p->out);
22782 }
22783 break;
22784 }
22785 case MODE_Semi: { /* .schema and .fullschema output */
22786 printSchemaLine(p->out, azArg[0], ";\n");
22787 break;
22788 }
22789 case MODE_Pretty: { /* .schema and .fullschema with --indent */
22790 char *z;
22791 int j;
@@ -21619,11 +22796,11 @@
22796 assert( nArg==1 );
22797 if( azArg[0]==0 ) break;
22798 if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
22799 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
22800 ){
22801 sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
22802 break;
22803 }
22804 z = sqlite3_mprintf("%s", azArg[0]);
22805 shell_check_oom(z);
22806 j = 0;
@@ -21652,255 +22829,265 @@
22829 }else if( c=='(' ){
22830 nParen++;
22831 }else if( c==')' ){
22832 nParen--;
22833 if( nLine>0 && nParen==0 && j>0 ){
22834 printSchemaLineN(p->out, z, j, "\n");
22835 j = 0;
22836 }
22837 }
22838 z[j++] = c;
22839 if( nParen==1 && cEnd==0
22840 && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
22841 ){
22842 if( c=='\n' ) j--;
22843 printSchemaLineN(p->out, z, j, "\n ");
22844 j = 0;
22845 nLine++;
22846 while( IsSpace(z[i+1]) ){ i++; }
22847 }
22848 }
22849 z[j] = 0;
22850 }
22851 printSchemaLine(p->out, z, ";\n");
22852 sqlite3_free(z);
22853 break;
22854 }
22855 case MODE_List: {
22856 if( p->cnt++==0 && p->showHeader ){
22857 for(i=0; i<nArg; i++){
22858 sqlite3_fprintf(p->out, "%s%s", azCol[i],
22859 i==nArg-1 ? p->rowSeparator : p->colSeparator);
22860 }
22861 }
22862 if( azArg==0 ) break;
22863 for(i=0; i<nArg; i++){
22864 char *z = azArg[i];
22865 if( z==0 ) z = p->nullValue;
22866 sqlite3_fputs(z, p->out);
22867 sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
22868 }
22869 break;
22870 }
22871 case MODE_Www:
22872 case MODE_Html: {
22873 if( p->cnt==0 && p->cMode==MODE_Www ){
22874 sqlite3_fputs(
22875 "</PRE>\n"
22876 "<TABLE border='1' cellspacing='0' cellpadding='2'>\n"
22877 ,p->out
22878 );
22879 }
22880 if( p->cnt==0 && (p->showHeader || p->cMode==MODE_Www) ){
22881 sqlite3_fputs("<TR>", p->out);
22882 for(i=0; i<nArg; i++){
22883 sqlite3_fputs("<TH>", p->out);
22884 output_html_string(p->out, azCol[i]);
22885 sqlite3_fputs("</TH>\n", p->out);
22886 }
22887 sqlite3_fputs("</TR>\n", p->out);
22888 }
22889 p->cnt++;
22890 if( azArg==0 ) break;
22891 sqlite3_fputs("<TR>", p->out);
22892 for(i=0; i<nArg; i++){
22893 sqlite3_fputs("<TD>", p->out);
22894 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
22895 sqlite3_fputs("</TD>\n", p->out);
22896 }
22897 sqlite3_fputs("</TR>\n", p->out);
22898 break;
22899 }
22900 case MODE_Tcl: {
22901 if( p->cnt++==0 && p->showHeader ){
22902 for(i=0; i<nArg; i++){
22903 output_c_string(p->out, azCol[i] ? azCol[i] : "");
22904 if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
22905 }
22906 sqlite3_fputs(p->rowSeparator, p->out);
22907 }
22908 if( azArg==0 ) break;
22909 for(i=0; i<nArg; i++){
22910 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
22911 if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
22912 }
22913 sqlite3_fputs(p->rowSeparator, p->out);
22914 break;
22915 }
22916 case MODE_Csv: {
22917 sqlite3_fsetmode(p->out, _O_BINARY);
22918 if( p->cnt++==0 && p->showHeader ){
22919 for(i=0; i<nArg; i++){
22920 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
22921 }
22922 sqlite3_fputs(p->rowSeparator, p->out);
22923 }
22924 if( nArg>0 ){
22925 for(i=0; i<nArg; i++){
22926 output_csv(p, azArg[i], i<nArg-1);
22927 }
22928 sqlite3_fputs(p->rowSeparator, p->out);
22929 }
22930 setCrlfMode(p);
22931 break;
22932 }
22933 case MODE_Insert: {
22934 if( azArg==0 ) break;
22935 sqlite3_fprintf(p->out, "INSERT INTO %s",p->zDestTable);
22936 if( p->showHeader ){
22937 sqlite3_fputs("(", p->out);
22938 for(i=0; i<nArg; i++){
22939 if( i>0 ) sqlite3_fputs(",", p->out);
22940 if( quoteChar(azCol[i]) ){
22941 char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
22942 shell_check_oom(z);
22943 sqlite3_fputs(z, p->out);
22944 sqlite3_free(z);
22945 }else{
22946 sqlite3_fprintf(p->out, "%s", azCol[i]);
22947 }
22948 }
22949 sqlite3_fputs(")", p->out);
22950 }
22951 p->cnt++;
22952 for(i=0; i<nArg; i++){
22953 sqlite3_fputs(i>0 ? "," : " VALUES(", p->out);
22954 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
22955 sqlite3_fputs("NULL", p->out);
22956 }else if( aiType && aiType[i]==SQLITE_TEXT ){
22957 if( ShellHasFlag(p, SHFLG_Newlines) ){
22958 output_quoted_string(p, azArg[i]);
22959 }else{
22960 output_quoted_escaped_string(p, azArg[i]);
22961 }
22962 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
22963 sqlite3_fputs(azArg[i], p->out);
22964 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
22965 char z[50];
22966 double r = sqlite3_column_double(p->pStmt, i);
22967 sqlite3_uint64 ur;
22968 memcpy(&ur,&r,sizeof(r));
22969 if( ur==0x7ff0000000000000LL ){
22970 sqlite3_fputs("9.0e+999", p->out);
22971 }else if( ur==0xfff0000000000000LL ){
22972 sqlite3_fputs("-9.0e+999", p->out);
22973 }else{
22974 sqlite3_int64 ir = (sqlite3_int64)r;
22975 if( r==(double)ir ){
22976 sqlite3_snprintf(50,z,"%lld.0", ir);
22977 }else{
22978 sqlite3_snprintf(50,z,"%!.20g", r);
22979 }
22980 sqlite3_fputs(z, p->out);
22981 }
22982 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
22983 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
22984 int nBlob = sqlite3_column_bytes(p->pStmt, i);
22985 output_hex_blob(p->out, pBlob, nBlob);
22986 }else if( isNumber(azArg[i], 0) ){
22987 sqlite3_fputs(azArg[i], p->out);
22988 }else if( ShellHasFlag(p, SHFLG_Newlines) ){
22989 output_quoted_string(p, azArg[i]);
22990 }else{
22991 output_quoted_escaped_string(p, azArg[i]);
22992 }
22993 }
22994 sqlite3_fputs(");\n", p->out);
22995 break;
22996 }
22997 case MODE_Json: {
22998 if( azArg==0 ) break;
22999 if( p->cnt==0 ){
23000 sqlite3_fputs("[{", p->out);
23001 }else{
23002 sqlite3_fputs(",\n{", p->out);
23003 }
23004 p->cnt++;
23005 for(i=0; i<nArg; i++){
23006 output_json_string(p->out, azCol[i], -1);
23007 sqlite3_fputs(":", p->out);
23008 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
23009 sqlite3_fputs("null", p->out);
23010 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
23011 char z[50];
23012 double r = sqlite3_column_double(p->pStmt, i);
23013 sqlite3_uint64 ur;
23014 memcpy(&ur,&r,sizeof(r));
23015 if( ur==0x7ff0000000000000LL ){
23016 sqlite3_fputs("9.0e+999", p->out);
23017 }else if( ur==0xfff0000000000000LL ){
23018 sqlite3_fputs("-9.0e+999", p->out);
23019 }else{
23020 sqlite3_snprintf(50,z,"%!.20g", r);
23021 sqlite3_fputs(z, p->out);
23022 }
23023 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
23024 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
23025 int nBlob = sqlite3_column_bytes(p->pStmt, i);
23026 output_json_string(p->out, pBlob, nBlob);
23027 }else if( aiType && aiType[i]==SQLITE_TEXT ){
23028 output_json_string(p->out, azArg[i], -1);
23029 }else{
23030 sqlite3_fputs(azArg[i], p->out);
23031 }
23032 if( i<nArg-1 ){
23033 sqlite3_fputs(",", p->out);
23034 }
23035 }
23036 sqlite3_fputs("}", p->out);
23037 break;
23038 }
23039 case MODE_Quote: {
23040 if( azArg==0 ) break;
23041 if( p->cnt==0 && p->showHeader ){
23042 for(i=0; i<nArg; i++){
23043 if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23044 output_quoted_string(p, azCol[i]);
23045 }
23046 sqlite3_fputs(p->rowSeparator, p->out);
23047 }
23048 p->cnt++;
23049 for(i=0; i<nArg; i++){
23050 if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23051 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
23052 sqlite3_fputs("NULL", p->out);
23053 }else if( aiType && aiType[i]==SQLITE_TEXT ){
23054 output_quoted_string(p, azArg[i]);
23055 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
23056 sqlite3_fputs(azArg[i], p->out);
23057 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
23058 char z[50];
23059 double r = sqlite3_column_double(p->pStmt, i);
23060 sqlite3_snprintf(50,z,"%!.20g", r);
23061 sqlite3_fputs(z, p->out);
23062 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
23063 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
23064 int nBlob = sqlite3_column_bytes(p->pStmt, i);
23065 output_hex_blob(p->out, pBlob, nBlob);
23066 }else if( isNumber(azArg[i], 0) ){
23067 sqlite3_fputs(azArg[i], p->out);
23068 }else{
23069 output_quoted_string(p, azArg[i]);
23070 }
23071 }
23072 sqlite3_fputs(p->rowSeparator, p->out);
23073 break;
23074 }
23075 case MODE_Ascii: {
23076 if( p->cnt++==0 && p->showHeader ){
23077 for(i=0; i<nArg; i++){
23078 if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23079 sqlite3_fputs(azCol[i] ? azCol[i] : "", p->out);
23080 }
23081 sqlite3_fputs(p->rowSeparator, p->out);
23082 }
23083 if( azArg==0 ) break;
23084 for(i=0; i<nArg; i++){
23085 if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
23086 sqlite3_fputs(azArg[i] ? azArg[i] : p->nullValue, p->out);
23087 }
23088 sqlite3_fputs(p->rowSeparator, p->out);
23089 break;
23090 }
23091 case MODE_EQP: {
23092 eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
23093 break;
@@ -21975,11 +23162,11 @@
23162 "INSERT INTO selftest(tno,op,cmd,ans)"
23163 " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
23164 "DROP TABLE [_shell$self];"
23165 ,0,0,&zErrMsg);
23166 if( zErrMsg ){
23167 sqlite3_fprintf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
23168 sqlite3_free(zErrMsg);
23169 }
23170 sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
23171 }
23172
@@ -22078,36 +23265,37 @@
23265 int i;
23266 const char *z;
23267 rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
23268 if( rc!=SQLITE_OK || !pSelect ){
23269 char *zContext = shell_error_context(zSelect, p->db);
23270 sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n%s",
23271 rc, sqlite3_errmsg(p->db), zContext);
23272 sqlite3_free(zContext);
23273 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
23274 return rc;
23275 }
23276 rc = sqlite3_step(pSelect);
23277 nResult = sqlite3_column_count(pSelect);
23278 while( rc==SQLITE_ROW ){
23279 z = (const char*)sqlite3_column_text(pSelect, 0);
23280 sqlite3_fprintf(p->out, "%s", z);
23281 for(i=1; i<nResult; i++){
23282 sqlite3_fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
23283 }
23284 if( z==0 ) z = "";
23285 while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
23286 if( z[0] ){
23287 sqlite3_fputs("\n;\n", p->out);
23288 }else{
23289 sqlite3_fputs(";\n", p->out);
23290 }
23291 rc = sqlite3_step(pSelect);
23292 }
23293 rc = sqlite3_finalize(pSelect);
23294 if( rc!=SQLITE_OK ){
23295 sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n",
23296 rc, sqlite3_errmsg(p->db));
23297 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
23298 }
23299 return rc;
23300 }
23301
@@ -22139,17 +23327,17 @@
23327
23328 #ifdef __linux__
23329 /*
23330 ** Attempt to display I/O stats on Linux using /proc/PID/io
23331 */
23332 static void displayLinuxIoStats(FILE *out){
23333 FILE *in;
23334 char z[200];
23335 sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
23336 in = sqlite3_fopen(z, "rb");
23337 if( in==0 ) return;
23338 while( sqlite3_fgets(z, sizeof(z), in)!=0 ){
23339 static const struct {
23340 const char *zPattern;
23341 const char *zDesc;
23342 } aTrans[] = {
23343 { "rchar: ", "Bytes received by read():" },
@@ -22162,11 +23350,11 @@
23350 };
23351 int i;
23352 for(i=0; i<ArraySize(aTrans); i++){
23353 int n = strlen30(aTrans[i].zPattern);
23354 if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
23355 sqlite3_fprintf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
23356 break;
23357 }
23358 }
23359 }
23360 fclose(in);
@@ -22175,10 +23363,11 @@
23363
23364 /*
23365 ** Display a single line of status using 64-bit values.
23366 */
23367 static void displayStatLine(
23368 FILE *out, /* Write to this channel */
23369 char *zLabel, /* Label for this one line */
23370 char *zFormat, /* Format for the result */
23371 int iStatusCtrl, /* Which status to display */
23372 int bReset /* True to reset the stats */
23373 ){
@@ -22193,11 +23382,11 @@
23382 if( nPercent>1 ){
23383 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
23384 }else{
23385 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
23386 }
23387 sqlite3_fprintf(out, "%-36s %s\n", zLabel, zLine);
23388 }
23389
23390 /*
23391 ** Display memory stats.
23392 */
@@ -22206,130 +23395,152 @@
23395 ShellState *pArg, /* Pointer to ShellState */
23396 int bReset /* True to reset the stats */
23397 ){
23398 int iCur;
23399 int iHiwtr;
23400 FILE *out;
23401 if( pArg==0 || pArg->out==0 ) return 0;
23402 out = pArg->out;
23403
23404 if( pArg->pStmt && pArg->statsOn==2 ){
23405 int nCol, i, x;
23406 sqlite3_stmt *pStmt = pArg->pStmt;
23407 char z[100];
23408 nCol = sqlite3_column_count(pStmt);
23409 sqlite3_fprintf(out, "%-36s %d\n", "Number of output columns:", nCol);
23410 for(i=0; i<nCol; i++){
23411 sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
23412 sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
23413 #ifndef SQLITE_OMIT_DECLTYPE
23414 sqlite3_snprintf(30, z+x, "declared type:");
23415 sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
23416 #endif
23417 #ifdef SQLITE_ENABLE_COLUMN_METADATA
23418 sqlite3_snprintf(30, z+x, "database name:");
23419 sqlite3_fprintf(out, "%-36s %s\n", z,
23420 sqlite3_column_database_name(pStmt,i));
23421 sqlite3_snprintf(30, z+x, "table name:");
23422 sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
23423 sqlite3_snprintf(30, z+x, "origin name:");
23424 sqlite3_fprintf(out, "%-36s %s\n", z,sqlite3_column_origin_name(pStmt,i));
23425 #endif
23426 }
23427 }
23428
23429 if( pArg->statsOn==3 ){
23430 if( pArg->pStmt ){
23431 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset);
23432 sqlite3_fprintf(out, "VM-steps: %d\n", iCur);
23433 }
23434 return 0;
23435 }
23436
23437 displayStatLine(out, "Memory Used:",
23438 "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
23439 displayStatLine(out, "Number of Outstanding Allocations:",
23440 "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
23441 if( pArg->shellFlgs & SHFLG_Pagecache ){
23442 displayStatLine(out, "Number of Pcache Pages Used:",
23443 "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
23444 }
23445 displayStatLine(out, "Number of Pcache Overflow Bytes:",
23446 "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
23447 displayStatLine(out, "Largest Allocation:",
23448 "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
23449 displayStatLine(out, "Largest Pcache Allocation:",
23450 "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
23451 #ifdef YYTRACKMAXSTACKDEPTH
23452 displayStatLine(out, "Deepest Parser Stack:",
23453 "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
23454 #endif
23455
23456 if( db ){
23457 if( pArg->shellFlgs & SHFLG_Lookaside ){
23458 iHiwtr = iCur = -1;
23459 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
23460 &iCur, &iHiwtr, bReset);
23461 sqlite3_fprintf(out,
23462 "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
23463 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
23464 &iCur, &iHiwtr, bReset);
23465 sqlite3_fprintf(out,
23466 "Successful lookaside attempts: %d\n", iHiwtr);
23467 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
23468 &iCur, &iHiwtr, bReset);
23469 sqlite3_fprintf(out,
23470 "Lookaside failures due to size: %d\n", iHiwtr);
23471 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
23472 &iCur, &iHiwtr, bReset);
23473 sqlite3_fprintf(out,
23474 "Lookaside failures due to OOM: %d\n", iHiwtr);
23475 }
23476 iHiwtr = iCur = -1;
23477 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
23478 sqlite3_fprintf(out,
23479 "Pager Heap Usage: %d bytes\n", iCur);
23480 iHiwtr = iCur = -1;
23481 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
23482 sqlite3_fprintf(out,
23483 "Page cache hits: %d\n", iCur);
23484 iHiwtr = iCur = -1;
23485 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
23486 sqlite3_fprintf(out,
23487 "Page cache misses: %d\n", iCur);
23488 iHiwtr = iCur = -1;
23489 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
23490 sqlite3_fprintf(out,
23491 "Page cache writes: %d\n", iCur);
23492 iHiwtr = iCur = -1;
23493 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
23494 sqlite3_fprintf(out,
23495 "Page cache spills: %d\n", iCur);
23496 iHiwtr = iCur = -1;
23497 sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
23498 sqlite3_fprintf(out,
23499 "Schema Heap Usage: %d bytes\n", iCur);
23500 iHiwtr = iCur = -1;
23501 sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
23502 sqlite3_fprintf(out,
23503 "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
23504 }
23505
23506 if( pArg->pStmt ){
23507 int iHit, iMiss;
23508 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
23509 bReset);
23510 sqlite3_fprintf(out,
23511 "Fullscan Steps: %d\n", iCur);
23512 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
23513 sqlite3_fprintf(out,
23514 "Sort Operations: %d\n", iCur);
23515 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
23516 sqlite3_fprintf(out,
23517 "Autoindex Inserts: %d\n", iCur);
23518 iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT,
23519 bReset);
23520 iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS,
23521 bReset);
23522 if( iHit || iMiss ){
23523 sqlite3_fprintf(out,
23524 "Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
23525 }
23526 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
23527 sqlite3_fprintf(out,
23528 "Virtual Machine Steps: %d\n", iCur);
23529 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
23530 sqlite3_fprintf(out,
23531 "Reprepare operations: %d\n", iCur);
23532 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
23533 sqlite3_fprintf(out,
23534 "Number of times run: %d\n", iCur);
23535 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
23536 sqlite3_fprintf(out,
23537 "Memory used by prepared stmt: %d\n", iCur);
23538 }
23539
23540 #ifdef __linux__
23541 displayLinuxIoStats(pArg->out);
23542 #endif
23543
23544 /* Do not remove this machine readable comment: extra-stats-output-here */
23545
23546 return 0;
@@ -22721,21 +23932,21 @@
23932 #define BOX_1234 "\342\224\274" /* U+253c -|- */
23933
23934 /* Draw horizontal line N characters long using unicode box
23935 ** characters
23936 */
23937 static void print_box_line(FILE *out, int N){
23938 const char zDash[] =
23939 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
23940 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
23941 const int nDash = sizeof(zDash) - 1;
23942 N *= 3;
23943 while( N>nDash ){
23944 sqlite3_fputs(zDash, out);
23945 N -= nDash;
23946 }
23947 sqlite3_fprintf(out, "%.*s", N, zDash);
23948 }
23949
23950 /*
23951 ** Draw a horizontal separator for a MODE_Box table.
23952 */
@@ -22746,19 +23957,19 @@
23957 const char *zSep2,
23958 const char *zSep3
23959 ){
23960 int i;
23961 if( nArg>0 ){
23962 sqlite3_fputs(zSep1, p->out);
23963 print_box_line(p->out, p->actualWidth[0]+2);
23964 for(i=1; i<nArg; i++){
23965 sqlite3_fputs(zSep2, p->out);
23966 print_box_line(p->out, p->actualWidth[i]+2);
23967 }
23968 sqlite3_fputs(zSep3, p->out);
23969 }
23970 sqlite3_fputs("\n", p->out);
23971 }
23972
23973 /*
23974 ** z[] is a line of text that is to be displayed the .mode box or table or
23975 ** similar tabular formats. z[] might contain control characters such
@@ -22788,16 +23999,26 @@
23999 }
24000 if( mxWidth<0 ) mxWidth = -mxWidth;
24001 if( mxWidth==0 ) mxWidth = 1000000;
24002 i = j = n = 0;
24003 while( n<mxWidth ){
24004 unsigned char c = z[i];
24005 if( c>=0xc0 ){
24006 int u;
24007 int len = decodeUtf8(&z[i], &u);
24008 i += len;
24009 j += len;
24010 n += cli_wcwidth(u);
24011 continue;
24012 }
24013 if( c>=' ' ){
24014 n++;
24015 i++;
24016 j++;
24017 continue;
24018 }
24019 if( c=='\t' ){
24020 do{
24021 n++;
24022 j++;
24023 }while( (n&7)!=0 && n<mxWidth );
24024 i++;
@@ -22835,13 +24056,21 @@
24056 }
24057 zOut = malloc( j+1 );
24058 shell_check_oom(zOut);
24059 i = j = n = 0;
24060 while( i<k ){
24061 unsigned char c = z[i];
24062 if( c>=0xc0 ){
24063 int u;
24064 int len = decodeUtf8(&z[i], &u);
24065 do{ zOut[j++] = z[i++]; }while( (--len)>0 );
24066 n += cli_wcwidth(u);
24067 continue;
24068 }
24069 if( c>=' ' ){
24070 n++;
24071 zOut[j++] = z[i++];
24072 continue;
24073 }
24074 if( z[i]=='\t' ){
24075 do{
24076 n++;
@@ -23017,97 +24246,99 @@
24246 rowSep = "\n";
24247 if( p->showHeader ){
24248 for(i=0; i<nColumn; i++){
24249 w = p->actualWidth[i];
24250 if( p->colWidth[i]<0 ) w = -w;
24251 utf8_width_print(p->out, w, azData[i]);
24252 sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
24253 }
24254 for(i=0; i<nColumn; i++){
24255 print_dashes(p->out, p->actualWidth[i]);
24256 sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
24257 }
24258 }
24259 break;
24260 }
24261 case MODE_Table: {
24262 colSep = " | ";
24263 rowSep = " |\n";
24264 print_row_separator(p, nColumn, "+");
24265 sqlite3_fputs("| ", p->out);
24266 for(i=0; i<nColumn; i++){
24267 w = p->actualWidth[i];
24268 n = strlenChar(azData[i]);
24269 sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
24270 azData[i], (w-n+1)/2, "");
24271 sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
24272 }
24273 print_row_separator(p, nColumn, "+");
24274 break;
24275 }
24276 case MODE_Markdown: {
24277 colSep = " | ";
24278 rowSep = " |\n";
24279 sqlite3_fputs("| ", p->out);
24280 for(i=0; i<nColumn; i++){
24281 w = p->actualWidth[i];
24282 n = strlenChar(azData[i]);
24283 sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
24284 azData[i], (w-n+1)/2, "");
24285 sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
24286 }
24287 print_row_separator(p, nColumn, "|");
24288 break;
24289 }
24290 case MODE_Box: {
24291 colSep = " " BOX_13 " ";
24292 rowSep = " " BOX_13 "\n";
24293 print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
24294 sqlite3_fputs(BOX_13 " ", p->out);
24295 for(i=0; i<nColumn; i++){
24296 w = p->actualWidth[i];
24297 n = strlenChar(azData[i]);
24298 sqlite3_fprintf(p->out, "%*s%s%*s%s",
24299 (w-n)/2, "", azData[i], (w-n+1)/2, "",
24300 i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
24301 }
24302 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
24303 break;
24304 }
24305 }
24306 for(i=nColumn, j=0; i<nTotal; i++, j++){
24307 if( j==0 && p->cMode!=MODE_Column ){
24308 sqlite3_fputs(p->cMode==MODE_Box?BOX_13" ":"| ", p->out);
24309 }
24310 z = azData[i];
24311 if( z==0 ) z = p->nullValue;
24312 w = p->actualWidth[j];
24313 if( p->colWidth[j]<0 ) w = -w;
24314 utf8_width_print(p->out, w, z);
24315 if( j==nColumn-1 ){
24316 sqlite3_fputs(rowSep, p->out);
24317 if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
24318 if( p->cMode==MODE_Table ){
24319 print_row_separator(p, nColumn, "+");
24320 }else if( p->cMode==MODE_Box ){
24321 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
24322 }else if( p->cMode==MODE_Column ){
24323 sqlite3_fputs("\n", p->out);
24324 }
24325 }
24326 j = -1;
24327 if( seenInterrupt ) goto columnar_end;
24328 }else{
24329 sqlite3_fputs(colSep, p->out);
24330 }
24331 }
24332 if( p->cMode==MODE_Table ){
24333 print_row_separator(p, nColumn, "+");
24334 }else if( p->cMode==MODE_Box ){
24335 print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
24336 }
24337 columnar_end:
24338 if( seenInterrupt ){
24339 sqlite3_fputs("Interrupt\n", p->out);
24340 }
24341 nData = (nRow+1)*nColumn;
24342 for(i=0; i<nData; i++){
24343 z = azData[i];
24344 if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
@@ -23190,11 +24421,13 @@
24421 }
24422 }
24423 } while( SQLITE_ROW == rc );
24424 sqlite3_free(pData);
24425 if( pArg->cMode==MODE_Json ){
24426 sqlite3_fputs("]\n", pArg->out);
24427 }else if( pArg->cMode==MODE_Www ){
24428 sqlite3_fputs("</TABLE>\n<PRE>\n", pArg->out);
24429 }else if( pArg->cMode==MODE_Count ){
24430 char zBuf[200];
24431 sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
24432 nRow, nRow!=1 ? "s" : "");
24433 printf("%s", zBuf);
@@ -23239,10 +24472,11 @@
24472 int bCancel,
24473 char **pzErr
24474 ){
24475 int rc = SQLITE_OK;
24476 sqlite3expert *p = pState->expert.pExpert;
24477 FILE *out = pState->out;
24478 assert( p );
24479 assert( bCancel || pzErr==0 || *pzErr==0 );
24480 if( bCancel==0 ){
24481 int bVerbose = pState->expert.bVerbose;
24482
@@ -23251,24 +24485,25 @@
24485 int nQuery = sqlite3_expert_count(p);
24486 int i;
24487
24488 if( bVerbose ){
24489 const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
24490 sqlite3_fputs("-- Candidates -----------------------------\n", out);
24491 sqlite3_fprintf(out, "%s\n", zCand);
24492 }
24493 for(i=0; i<nQuery; i++){
24494 const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
24495 const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
24496 const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
24497 if( zIdx==0 ) zIdx = "(no new indexes)\n";
24498 if( bVerbose ){
24499 sqlite3_fprintf(out,
24500 "-- Query %d --------------------------------\n"
24501 "%s\n\n"
24502 ,i+1, zSql);
24503 }
24504 sqlite3_fprintf(out, "%s\n%s\n", zIdx, zEQP);
 
24505 }
24506 }
24507 }
24508 sqlite3_expert_destroy(p);
24509 pState->expert.pExpert = 0;
@@ -23299,30 +24534,31 @@
24534 if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){
24535 pState->expert.bVerbose = 1;
24536 }
24537 else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
24538 if( i==(nArg-1) ){
24539 sqlite3_fprintf(stderr, "option requires an argument: %s\n", z);
24540 rc = SQLITE_ERROR;
24541 }else{
24542 iSample = (int)integerValue(azArg[++i]);
24543 if( iSample<0 || iSample>100 ){
24544 sqlite3_fprintf(stderr,"value out of range: %s\n", azArg[i]);
24545 rc = SQLITE_ERROR;
24546 }
24547 }
24548 }
24549 else{
24550 sqlite3_fprintf(stderr,"unknown option: %s\n", z);
24551 rc = SQLITE_ERROR;
24552 }
24553 }
24554
24555 if( rc==SQLITE_OK ){
24556 pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
24557 if( pState->expert.pExpert==0 ){
24558 sqlite3_fprintf(stderr,
24559 "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
24560 rc = SQLITE_ERROR;
24561 }else{
24562 sqlite3_expert_config(
24563 pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
24564 );
@@ -23647,33 +24883,33 @@
24883 if( zType==0 ) return 0;
24884 dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
24885 noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
24886
24887 if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
24888 /* no-op */
24889 }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
24890 if( !dataOnly ) sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
24891 }else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
24892 return 0;
24893 }else if( dataOnly ){
24894 /* no-op */
24895 }else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
24896 char *zIns;
24897 if( !p->writableSchema ){
24898 sqlite3_fputs("PRAGMA writable_schema=ON;\n", p->out);
24899 p->writableSchema = 1;
24900 }
24901 zIns = sqlite3_mprintf(
24902 "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
24903 "VALUES('table','%q','%q',0,'%q');",
24904 zTable, zTable, zSql);
24905 shell_check_oom(zIns);
24906 sqlite3_fprintf(p->out, "%s\n", zIns);
24907 sqlite3_free(zIns);
24908 return 0;
24909 }else{
24910 printSchemaLine(p->out, zSql, ";\n");
24911 }
24912
24913 if( cli_strcmp(zType, "table")==0 ){
24914 ShellText sSelect;
24915 ShellText sTable;
@@ -23727,11 +24963,11 @@
24963 savedMode = p->mode;
24964 p->zDestTable = sTable.z;
24965 p->mode = p->cMode = MODE_Insert;
24966 rc = shell_exec(p, sSelect.z, 0);
24967 if( (rc&0xff)==SQLITE_CORRUPT ){
24968 sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
24969 toggleSelectOrder(p->db);
24970 shell_exec(p, sSelect.z, 0);
24971 toggleSelectOrder(p->db);
24972 }
24973 p->zDestTable = savedDestTable;
@@ -23758,28 +24994,28 @@
24994 char *zErr = 0;
24995 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
24996 if( rc==SQLITE_CORRUPT ){
24997 char *zQ2;
24998 int len = strlen30(zQuery);
24999 sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
25000 if( zErr ){
25001 sqlite3_fprintf(p->out, "/****** %s ******/\n", zErr);
25002 sqlite3_free(zErr);
25003 zErr = 0;
25004 }
25005 zQ2 = malloc( len+100 );
25006 if( zQ2==0 ) return rc;
25007 sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
25008 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
25009 if( rc ){
25010 sqlite3_fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
25011 }else{
25012 rc = SQLITE_CORRUPT;
25013 }
 
25014 free(zQ2);
25015 }
25016 sqlite3_free(zErr);
25017 return rc;
25018 }
25019
25020 /*
25021 ** Text of help messages.
@@ -23832,18 +25068,17 @@
25068 #ifndef SQLITE_SHELL_FIDDLE
25069 ".check GLOB Fail if output since .testcase does not match",
25070 ".clone NEWDB Clone data into NEWDB from the existing database",
25071 #endif
25072 ".connection [close] [#] Open or close an auxiliary database connection",
25073 ".crlf ?on|off? Whether or not to use \\r\\n line endings",
 
 
25074 ".databases List names and files of attached databases",
25075 ".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
25076 #if SQLITE_SHELL_HAVE_RECOVER
25077 ".dbinfo ?DB? Show status information about the database",
25078 #endif
25079 ".dbtotxt Hex dump of the database file",
25080 ".dump ?OBJECTS? Render database content as SQL",
25081 " Options:",
25082 " --data-only Output only INSERT statements",
25083 " --newlines Allow unescaped newline characters in output",
25084 " --nosys Omit system tables (ex: \"sqlite_stat1\")",
@@ -23940,13 +25175,15 @@
25175 #endif
25176 ".nullvalue STRING Use STRING in place of NULL values",
25177 #ifndef SQLITE_SHELL_FIDDLE
25178 ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
25179 " If FILE begins with '|' then open as a pipe",
25180 " --bom Put a UTF8 byte-order mark at the beginning",
25181 " -e Send output to the system text editor",
25182 " --plain Use text/plain output instead of HTML for -w option",
25183 " -w Send output as HTML to a web browser (same as \".www\")",
25184 " -x Send output as CSV to a spreadsheet (same as \".excel\")",
25185 /* Note that .open is (partially) available in WASM builds but is
25186 ** currently only intended to be used by the fiddle tool, not
25187 ** end users, so is "undocumented." */
25188 ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
25189 " Options:",
@@ -23965,10 +25202,12 @@
25202 ".output ?FILE? Send output to FILE or stdout if FILE is omitted",
25203 " If FILE begins with '|' then open it as a pipe.",
25204 " Options:",
25205 " --bom Prefix output with a UTF8 byte-order mark",
25206 " -e Send output to the system text editor",
25207 " --plain Use text/plain for -w option",
25208 " -w Send output to a web browser",
25209 " -x Send output as CSV to a spreadsheet",
25210 #endif
25211 ".parameter CMD ... Manage SQL parameter bindings",
25212 " clear Erase all bindings",
25213 " init Initialize the TEMP table that holds bindings",
@@ -24078,10 +25317,14 @@
25317 ".vfsinfo ?AUX? Information about the top-level VFS",
25318 ".vfslist List all available VFSes",
25319 ".vfsname ?AUX? Print the name of the VFS stack",
25320 ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
25321 " Negative values right-justify",
25322 #ifndef SQLITE_SHELL_FIDDLE
25323 ".www Display output of the next command in web browser",
25324 " --plain Show results as text/plain, not as HTML",
25325 #endif
25326 };
25327
25328 /*
25329 ** Output help text.
25330 **
@@ -24126,24 +25369,24 @@
25369 hh &= ~HH_Summary;
25370 break;
25371 }
25372 if( ((hw^hh)&HH_Undoc)==0 ){
25373 if( (hh&HH_Summary)!=0 ){
25374 sqlite3_fprintf(out, ".%s\n", azHelp[i]+1);
25375 ++n;
25376 }else if( (hw&HW_SummaryOnly)==0 ){
25377 sqlite3_fprintf(out, "%s\n", azHelp[i]);
25378 }
25379 }
25380 }
25381 }else{
25382 /* Seek documented commands for which zPattern is an exact prefix */
25383 zPat = sqlite3_mprintf(".%s*", zPattern);
25384 shell_check_oom(zPat);
25385 for(i=0; i<ArraySize(azHelp); i++){
25386 if( sqlite3_strglob(zPat, azHelp[i])==0 ){
25387 sqlite3_fprintf(out, "%s\n", azHelp[i]);
25388 j = i+1;
25389 n++;
25390 }
25391 }
25392 sqlite3_free(zPat);
@@ -24150,11 +25393,11 @@
25393 if( n ){
25394 if( n==1 ){
25395 /* when zPattern is a prefix of exactly one command, then include
25396 ** the details of that command, which should begin at offset j */
25397 while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
25398 sqlite3_fprintf(out, "%s\n", azHelp[j]);
25399 j++;
25400 }
25401 }
25402 return n;
25403 }
@@ -24167,14 +25410,14 @@
25410 while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
25411 continue;
25412 }
25413 if( azHelp[i][0]=='.' ) j = i;
25414 if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
25415 sqlite3_fprintf(out, "%s\n", azHelp[j]);
25416 while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
25417 j++;
25418 sqlite3_fprintf(out, "%s\n", azHelp[j]);
25419 }
25420 i = j;
25421 n++;
25422 }
25423 }
@@ -24200,35 +25443,35 @@
25443 **
25444 ** NULL is returned if any error is encountered. The final value of *pnByte
25445 ** is undefined in this case.
25446 */
25447 static char *readFile(const char *zName, int *pnByte){
25448 FILE *in = sqlite3_fopen(zName, "rb");
25449 long nIn;
25450 size_t nRead;
25451 char *pBuf;
25452 int rc;
25453 if( in==0 ) return 0;
25454 rc = fseek(in, 0, SEEK_END);
25455 if( rc!=0 ){
25456 sqlite3_fprintf(stderr,"Error: '%s' not seekable\n", zName);
25457 fclose(in);
25458 return 0;
25459 }
25460 nIn = ftell(in);
25461 rewind(in);
25462 pBuf = sqlite3_malloc64( nIn+1 );
25463 if( pBuf==0 ){
25464 sqlite3_fputs("Error: out of memory\n", stderr);
25465 fclose(in);
25466 return 0;
25467 }
25468 nRead = fread(pBuf, nIn, 1, in);
25469 fclose(in);
25470 if( nRead!=1 ){
25471 sqlite3_free(pBuf);
25472 sqlite3_fprintf(stderr,"Error: cannot read '%s'\n", zName);
25473 return 0;
25474 }
25475 pBuf[nIn] = 0;
25476 if( pnByte ) *pnByte = nIn;
25477 return pBuf;
@@ -24290,11 +25533,11 @@
25533 ** archive and the dfltZip flag is true, then assume it is a ZIP archive.
25534 ** Otherwise, assume an ordinary database regardless of the filename if
25535 ** the type cannot be determined from content.
25536 */
25537 int deduceDatabaseType(const char *zName, int dfltZip){
25538 FILE *f = sqlite3_fopen(zName, "rb");
25539 size_t n;
25540 int rc = SHELL_OPEN_UNSPEC;
25541 char zBuf[100];
25542 if( f==0 ){
25543 if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
@@ -24343,13 +25586,13 @@
25586 FILE *in;
25587 const char *zDbFilename = p->pAuxDb->zDbFilename;
25588 unsigned int x[16];
25589 char zLine[1000];
25590 if( zDbFilename ){
25591 in = sqlite3_fopen(zDbFilename, "r");
25592 if( in==0 ){
25593 sqlite3_fprintf(stderr,"cannot open \"%s\" for reading\n", zDbFilename);
25594 return 0;
25595 }
25596 nLine = 0;
25597 }else{
25598 in = p->in;
@@ -24356,24 +25599,24 @@
25599 nLine = p->lineno;
25600 if( in==0 ) in = stdin;
25601 }
25602 *pnData = 0;
25603 nLine++;
25604 if( sqlite3_fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
25605 rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
25606 if( rc!=2 ) goto readHexDb_error;
25607 if( n<0 ) goto readHexDb_error;
25608 if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
25609 n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
25610 a = sqlite3_malloc( n ? n : 1 );
25611 shell_check_oom(a);
25612 memset(a, 0, n);
25613 if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
25614 sqlite3_fputs("invalid pagesize\n", stderr);
25615 goto readHexDb_error;
25616 }
25617 for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){
25618 rc = sscanf(zLine, "| page %d offset %d", &j, &k);
25619 if( rc==2 ){
25620 iOffset = k;
25621 continue;
25622 }
@@ -24401,18 +25644,18 @@
25644
25645 readHexDb_error:
25646 if( in!=p->in ){
25647 fclose(in);
25648 }else{
25649 while( sqlite3_fgets(zLine, sizeof(zLine), p->in)!=0 ){
25650 nLine++;
25651 if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
25652 }
25653 p->lineno = nLine;
25654 }
25655 sqlite3_free(a);
25656 sqlite3_fprintf(stderr,"Error on line %d of --hexdb input\n", nLine);
25657 return 0;
25658 }
25659 #endif /* SQLITE_OMIT_DESERIALIZE */
25660
25661 /*
@@ -24483,22 +25726,24 @@
25726 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
25727 break;
25728 }
25729 }
25730 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
25731 sqlite3_fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
25732 zDbFilename, sqlite3_errmsg(p->db));
25733 if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
25734 exit(1);
25735 }
25736 sqlite3_close(p->db);
25737 sqlite3_open(":memory:", &p->db);
25738 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
25739 sqlite3_fputs("Also: unable to open substitute in-memory database.\n",
25740 stderr);
25741 exit(1);
25742 }else{
25743 sqlite3_fprintf(stderr,
25744 "Notice: using substitute in-memory database instead of \"%s\"\n",
25745 zDbFilename);
25746 }
25747 }
25748 globalDb = p->db;
25749 sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
@@ -24511,10 +25756,11 @@
25756 }
25757
25758 #ifndef SQLITE_OMIT_LOAD_EXTENSION
25759 sqlite3_enable_load_extension(p->db, 1);
25760 #endif
25761 sqlite3_sha_init(p->db, 0, 0);
25762 sqlite3_shathree_init(p->db, 0, 0);
25763 sqlite3_uint_init(p->db, 0, 0);
25764 sqlite3_stmtrand_init(p->db, 0, 0);
25765 sqlite3_decimal_init(p->db, 0, 0);
25766 sqlite3_percentile_init(p->db, 0, 0);
@@ -24605,11 +25851,11 @@
25851 }
25852 rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
25853 SQLITE_DESERIALIZE_RESIZEABLE |
25854 SQLITE_DESERIALIZE_FREEONCLOSE);
25855 if( rc ){
25856 sqlite3_fprintf(stderr,"Error: sqlite3_deserialize() returns %d\n", rc);
25857 }
25858 if( p->szMax>0 ){
25859 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
25860 }
25861 }
@@ -24629,15 +25875,17 @@
25875 ** Attempt to close the database connection. Report errors.
25876 */
25877 void close_db(sqlite3 *db){
25878 int rc = sqlite3_close(db);
25879 if( rc ){
25880 sqlite3_fprintf(stderr,
25881 "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
25882 }
25883 }
25884
25885 #if (HAVE_READLINE || HAVE_EDITLINE) \
25886 && !defined(SQLITE_OMIT_READLINE_COMPLETION)
25887 /*
25888 ** Readline completion callbacks
25889 */
25890 static char *readline_completion_generator(const char *text, int state){
25891 static sqlite3_stmt *pStmt = 0;
@@ -24671,19 +25919,26 @@
25919 #elif HAVE_LINENOISE
25920 /*
25921 ** Linenoise completion callback. Note that the 3rd argument is from
25922 ** the "msteveb" version of linenoise, not the "antirez" version.
25923 */
25924 static void linenoise_completion(
25925 const char *zLine,
25926 linenoiseCompletions *lc
25927 #if HAVE_LINENOISE==2
25928 ,void *pUserData
25929 #endif
25930 ){
25931 i64 nLine = strlen(zLine);
25932 i64 i, iStart;
25933 sqlite3_stmt *pStmt = 0;
25934 char *zSql;
25935 char zBuf[1000];
25936
25937 #if HAVE_LINENOISE==2
25938 UNUSED_PARAMETER(pUserData);
25939 #endif
25940 if( nLine>(i64)sizeof(zBuf)-30 ) return;
25941 if( zLine[0]=='.' || zLine[0]=='#') return;
25942 for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
25943 if( i==nLine-1 ) return;
25944 iStart = i+1;
@@ -24793,11 +26048,12 @@
26048 return 1;
26049 }
26050 if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
26051 return 0;
26052 }
26053 sqlite3_fprintf(stderr,
26054 "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
26055 return 0;
26056 }
26057
26058 /*
26059 ** Set or clear a shell flag according to a boolean value.
@@ -24820,22 +26076,22 @@
26076 /*
26077 ** Try to open an output file. The names "stdout" and "stderr" are
26078 ** recognized and do the right thing. NULL is returned if the output
26079 ** filename is "off".
26080 */
26081 static FILE *output_file_open(const char *zFile){
26082 FILE *f;
26083 if( cli_strcmp(zFile,"stdout")==0 ){
26084 f = stdout;
26085 }else if( cli_strcmp(zFile, "stderr")==0 ){
26086 f = stderr;
26087 }else if( cli_strcmp(zFile, "off")==0 ){
26088 f = 0;
26089 }else{
26090 f = sqlite3_fopen(zFile, "w");
26091 if( f==0 ){
26092 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
26093 }
26094 }
26095 return f;
26096 }
26097
@@ -24884,16 +26140,17 @@
26140 if( nSql>1000000000 ) nSql = 1000000000;
26141 while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
26142 switch( mType ){
26143 case SQLITE_TRACE_ROW:
26144 case SQLITE_TRACE_STMT: {
26145 sqlite3_fprintf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
26146 break;
26147 }
26148 case SQLITE_TRACE_PROFILE: {
26149 sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
26150 sqlite3_fprintf(p->traceOut,
26151 "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
26152 break;
26153 }
26154 }
26155 return 0;
26156 }
@@ -24996,14 +26253,15 @@
26253 do{ p->n--; }while( p->z[p->n]!=cQuote );
26254 p->cTerm = c;
26255 break;
26256 }
26257 if( pc==cQuote && c!='\r' ){
26258 sqlite3_fprintf(stderr,"%s:%d: unescaped %c character\n",
26259 p->zFile, p->nLine, cQuote);
26260 }
26261 if( c==EOF ){
26262 sqlite3_fprintf(stderr,"%s:%d: unterminated %c-quoted field\n",
26263 p->zFile, startLine, cQuote);
26264 p->cTerm = c;
26265 break;
26266 }
26267 import_append_char(p, c);
@@ -25098,11 +26356,11 @@
26356
26357 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
26358 shell_check_oom(zQuery);
26359 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
26360 if( rc ){
26361 sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
26362 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
26363 goto end_data_xfer;
26364 }
26365 n = sqlite3_column_count(pQuery);
26366 zInsert = sqlite3_malloc64(200 + nTable + n*3);
@@ -25115,11 +26373,11 @@
26373 i += 2;
26374 }
26375 memcpy(zInsert+i, ");", 3);
26376 rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
26377 if( rc ){
26378 sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
26379 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), zInsert);
26380 goto end_data_xfer;
26381 }
26382 for(k=0; k<2; k++){
26383 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
@@ -25151,11 +26409,11 @@
26409 }
26410 }
26411 } /* End for */
26412 rc = sqlite3_step(pInsert);
26413 if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
26414 sqlite3_fprintf(stderr,"Error %d: %s\n",
26415 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb));
26416 }
26417 sqlite3_reset(pInsert);
26418 cnt++;
26419 if( (cnt%spinRate)==0 ){
@@ -25169,11 +26427,11 @@
26427 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
26428 zTable);
26429 shell_check_oom(zQuery);
26430 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
26431 if( rc ){
26432 sqlite3_fprintf(stderr,"Warning: cannot step \"%s\" backwards", zTable);
26433 break;
26434 }
26435 } /* End for(k=0...) */
26436
26437 end_data_xfer:
@@ -25206,23 +26464,24 @@
26464 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
26465 " WHERE %s ORDER BY rowid ASC", zWhere);
26466 shell_check_oom(zQuery);
26467 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
26468 if( rc ){
26469 sqlite3_fprintf(stderr,
26470 "Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
26471 sqlite3_errmsg(p->db), zQuery);
26472 goto end_schema_xfer;
26473 }
26474 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
26475 zName = sqlite3_column_text(pQuery, 0);
26476 zSql = sqlite3_column_text(pQuery, 1);
26477 if( zName==0 || zSql==0 ) continue;
26478 if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ){
26479 sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
26480 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
26481 if( zErrMsg ){
26482 sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
26483 sqlite3_free(zErrMsg);
26484 zErrMsg = 0;
26485 }
26486 }
26487 if( xForEach ){
@@ -25236,23 +26495,23 @@
26495 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
26496 " WHERE %s ORDER BY rowid DESC", zWhere);
26497 shell_check_oom(zQuery);
26498 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
26499 if( rc ){
26500 sqlite3_fprintf(stderr,"Error: (%d) %s on [%s]\n",
26501 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
26502 goto end_schema_xfer;
26503 }
26504 while( sqlite3_step(pQuery)==SQLITE_ROW ){
26505 zName = sqlite3_column_text(pQuery, 0);
26506 zSql = sqlite3_column_text(pQuery, 1);
26507 if( zName==0 || zSql==0 ) continue;
26508 if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue;
26509 sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
26510 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
26511 if( zErrMsg ){
26512 sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
26513 sqlite3_free(zErrMsg);
26514 zErrMsg = 0;
26515 }
26516 if( xForEach ){
26517 xForEach(p, newDb, (const char*)zName);
@@ -25272,16 +26531,17 @@
26531 */
26532 static void tryToClone(ShellState *p, const char *zNewDb){
26533 int rc;
26534 sqlite3 *newDb = 0;
26535 if( access(zNewDb,0)==0 ){
26536 sqlite3_fprintf(stderr,"File \"%s\" already exists.\n", zNewDb);
26537 return;
26538 }
26539 rc = sqlite3_open(zNewDb, &newDb);
26540 if( rc ){
26541 sqlite3_fprintf(stderr,
26542 "Cannot create output database: %s\n", sqlite3_errmsg(newDb));
26543 }else{
26544 sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
26545 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
26546 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
26547 tryToCloneSchema(p, newDb, "type!='table'", 0);
@@ -25294,14 +26554,22 @@
26554 #ifndef SQLITE_SHELL_FIDDLE
26555 /*
26556 ** Change the output stream (file or pipe or console) to something else.
26557 */
26558 static void output_redir(ShellState *p, FILE *pfNew){
26559 if( p->out != stdout ){
26560 sqlite3_fputs("Output already redirected.\n", stderr);
26561 }else{
26562 p->out = pfNew;
26563 setCrlfMode(p);
26564 if( p->mode==MODE_Www ){
26565 sqlite3_fputs(
26566 "<!DOCTYPE html>\n"
26567 "<HTML><BODY><PRE>\n",
26568 p->out
26569 );
26570 }
26571 }
26572 }
26573
26574 /*
26575 ** Change the output file back to stdout.
@@ -25314,10 +26582,13 @@
26582 if( p->outfile[0]=='|' ){
26583 #ifndef SQLITE_OMIT_POPEN
26584 pclose(p->out);
26585 #endif
26586 }else{
26587 if( p->mode==MODE_Www ){
26588 sqlite3_fputs("</PRE></BODY></HTML>\n", p->out);
26589 }
26590 output_file_close(p->out);
26591 #ifndef SQLITE_NOHAVE_SYSTEM
26592 if( p->doXdgOpen ){
26593 const char *zXdgOpenCmd =
26594 #if defined(_WIN32)
@@ -25328,11 +26599,11 @@
26599 "xdg-open";
26600 #endif
26601 char *zCmd;
26602 zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
26603 if( system(zCmd) ){
26604 sqlite3_fprintf(stderr,"Failed: [%s]\n", zCmd);
26605 }else{
26606 /* Give the start/open/xdg-open command some time to get
26607 ** going before we continue, and potential delete the
26608 ** p->zTempFile data file out from under it */
26609 sqlite3_sleep(2000);
@@ -25343,28 +26614,34 @@
26614 }
26615 #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
26616 }
26617 p->outfile[0] = 0;
26618 p->out = stdout;
26619 setCrlfMode(p);
26620 }
26621 #else
26622 # define output_redir(SS,pfO)
26623 # define output_reset(SS)
26624 #endif
26625
26626 /*
26627 ** Run an SQL command and return the single integer result.
26628 */
26629 static int db_int(sqlite3 *db, const char *zSql, ...){
26630 sqlite3_stmt *pStmt;
26631 int res = 0;
26632 char *z;
26633 va_list ap;
26634 va_start(ap, zSql);
26635 z = sqlite3_vmprintf(zSql, ap);
26636 va_end(ap);
26637 sqlite3_prepare_v2(db, z, -1, &pStmt, 0);
26638 if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
26639 res = sqlite3_column_int(pStmt,0);
26640 }
26641 sqlite3_finalize(pStmt);
26642 sqlite3_free(z);
26643 return res;
26644 }
26645
26646 #if SQLITE_SHELL_HAVE_RECOVER
26647 /*
@@ -25419,11 +26696,11 @@
26696 if( p->db==0 ) return 1;
26697 rc = sqlite3_prepare_v2(p->db,
26698 "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
26699 -1, &pStmt, 0);
26700 if( rc ){
26701 sqlite3_fprintf(stderr,"error: %s\n", sqlite3_errmsg(p->db));
26702 sqlite3_finalize(pStmt);
26703 return 1;
26704 }
26705 sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
26706 if( sqlite3_step(pStmt)==SQLITE_ROW
@@ -25432,58 +26709,149 @@
26709 const u8 *pb = sqlite3_column_blob(pStmt,0);
26710 shell_check_oom(pb);
26711 memcpy(aHdr, pb, 100);
26712 sqlite3_finalize(pStmt);
26713 }else{
26714 sqlite3_fputs("unable to read database header\n", stderr);
26715 sqlite3_finalize(pStmt);
26716 return 1;
26717 }
26718 i = get2byteInt(aHdr+16);
26719 if( i==1 ) i = 65536;
26720 sqlite3_fprintf(p->out, "%-20s %d\n", "database page size:", i);
26721 sqlite3_fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
26722 sqlite3_fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
26723 sqlite3_fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
26724 for(i=0; i<ArraySize(aField); i++){
26725 int ofst = aField[i].ofst;
26726 unsigned int val = get4byteInt(aHdr + ofst);
26727 sqlite3_fprintf(p->out, "%-20s %u", aField[i].zName, val);
26728 switch( ofst ){
26729 case 56: {
26730 if( val==1 ) sqlite3_fputs(" (utf8)", p->out);
26731 if( val==2 ) sqlite3_fputs(" (utf16le)", p->out);
26732 if( val==3 ) sqlite3_fputs(" (utf16be)", p->out);
26733 }
26734 }
26735 sqlite3_fputs("\n", p->out);
26736 }
26737 if( zDb==0 ){
26738 zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
26739 }else if( cli_strcmp(zDb,"temp")==0 ){
26740 zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
26741 }else{
26742 zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
26743 }
26744 for(i=0; i<ArraySize(aQuery); i++){
26745 int val = db_int(p->db, aQuery[i].zSql, zSchemaTab);
26746 sqlite3_fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
 
 
26747 }
26748 sqlite3_free(zSchemaTab);
26749 sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
26750 sqlite3_fprintf(p->out, "%-20s %u\n", "data version", iDataVersion);
26751 return 0;
26752 }
26753 #endif /* SQLITE_SHELL_HAVE_RECOVER */
26754
26755 /*
26756 ** Implementation of the ".dbtotxt" command.
26757 **
26758 ** Return 1 on error, 2 to exit, and 0 otherwise.
26759 */
26760 static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
26761 sqlite3_stmt *pStmt = 0;
26762 sqlite3_int64 nPage = 0;
26763 int pgSz = 0;
26764 const char *zTail;
26765 char *zName = 0;
26766 int rc, i, j;
26767 unsigned char bShow[256]; /* Characters ok to display */
26768
26769 UNUSED_PARAMETER(nArg);
26770 UNUSED_PARAMETER(azArg);
26771 memset(bShow, '.', sizeof(bShow));
26772 for(i=' '; i<='~'; i++){
26773 if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
26774 }
26775 rc = sqlite3_prepare_v2(p->db, "PRAGMA page_size", -1, &pStmt, 0);
26776 if( rc ) goto dbtotxt_error;
26777 rc = 0;
26778 if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
26779 pgSz = sqlite3_column_int(pStmt, 0);
26780 sqlite3_finalize(pStmt);
26781 pStmt = 0;
26782 if( pgSz<512 || pgSz>65536 || (pgSz&(pgSz-1))!=0 ) goto dbtotxt_error;
26783 rc = sqlite3_prepare_v2(p->db, "PRAGMA page_count", -1, &pStmt, 0);
26784 if( rc ) goto dbtotxt_error;
26785 rc = 0;
26786 if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
26787 nPage = sqlite3_column_int64(pStmt, 0);
26788 sqlite3_finalize(pStmt);
26789 pStmt = 0;
26790 if( nPage<1 ) goto dbtotxt_error;
26791 rc = sqlite3_prepare_v2(p->db, "PRAGMA databases", -1, &pStmt, 0);
26792 if( rc ) goto dbtotxt_error;
26793 if( sqlite3_step(pStmt)!=SQLITE_ROW ){
26794 zTail = "unk.db";
26795 }else{
26796 const char *zFilename = (const char*)sqlite3_column_text(pStmt, 2);
26797 if( zFilename==0 || zFilename[0]==0 ) zFilename = "unk.db";
26798 zTail = strrchr(zFilename, '/');
26799 #if defined(_WIN32)
26800 if( zTail==0 ) zTail = strrchr(zFilename, '\\');
26801 #endif
26802 }
26803 zName = strdup(zTail);
26804 shell_check_oom(zName);
26805 sqlite3_fprintf(p->out, "| size %lld pagesize %d filename %s\n",
26806 nPage*pgSz, pgSz, zName);
26807 sqlite3_finalize(pStmt);
26808 pStmt = 0;
26809 rc = sqlite3_prepare_v2(p->db,
26810 "SELECT pgno, data FROM sqlite_dbpage ORDER BY pgno", -1, &pStmt, 0);
26811 if( rc ) goto dbtotxt_error;
26812 while( sqlite3_step(pStmt)==SQLITE_ROW ){
26813 sqlite3_int64 pgno = sqlite3_column_int64(pStmt, 0);
26814 const u8 *aData = sqlite3_column_blob(pStmt, 1);
26815 int seenPageLabel = 0;
26816 for(i=0; i<pgSz; i+=16){
26817 const u8 *aLine = aData+i;
26818 for(j=0; j<16 && aLine[j]==0; j++){}
26819 if( j==16 ) continue;
26820 if( !seenPageLabel ){
26821 sqlite3_fprintf(p->out, "| page %lld offset %lld\n", pgno, pgno*pgSz);
26822 seenPageLabel = 1;
26823 }
26824 sqlite3_fprintf(p->out, "| %5d:", i);
26825 for(j=0; j<16; j++) sqlite3_fprintf(p->out, " %02x", aLine[j]);
26826 sqlite3_fprintf(p->out, " ");
26827 for(j=0; j<16; j++){
26828 unsigned char c = (unsigned char)aLine[j];
26829 sqlite3_fprintf(p->out, "%c", bShow[c]);
26830 }
26831 sqlite3_fprintf(p->out, "\n");
26832 }
26833 }
26834 sqlite3_finalize(pStmt);
26835 sqlite3_fprintf(p->out, "| end %s\n", zName);
26836 free(zName);
26837 return 0;
26838
26839 dbtotxt_error:
26840 if( rc ){
26841 sqlite3_fprintf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
26842 }
26843 sqlite3_finalize(pStmt);
26844 free(zName);
26845 return 1;
26846 }
26847
26848 /*
26849 ** Print the given string as an error message.
26850 */
26851 static void shellEmitError(const char *zErr){
26852 sqlite3_fprintf(stderr,"Error: %s\n", zErr);
26853 }
26854 /*
26855 ** Print the current sqlite3_errmsg() value to stderr and return 1.
26856 */
26857 static int shellDatabaseError(sqlite3 *db){
@@ -25726,10 +27094,11 @@
27094 int bGroupByParent = 0; /* If -groupbyparent is present */
27095 int i; /* To iterate through azArg[] */
27096 const char *zIndent = ""; /* How much to indent CREATE INDEX by */
27097 int rc; /* Return code */
27098 sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
27099 FILE *out = pState->out; /* Send output here */
27100
27101 /*
27102 ** This SELECT statement returns one row for each foreign key constraint
27103 ** in the schema of the main database. The column values are:
27104 **
@@ -25801,11 +27170,12 @@
27170 else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
27171 bGroupByParent = 1;
27172 zIndent = " ";
27173 }
27174 else{
27175 sqlite3_fprintf(stderr,
27176 "Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
27177 return SQLITE_ERROR;
27178 }
27179 }
27180
27181 /* Register the fkey_collate_clause() SQL function */
@@ -25845,44 +27215,45 @@
27215 }
27216 rc = sqlite3_finalize(pExplain);
27217 if( rc!=SQLITE_OK ) break;
27218
27219 if( res<0 ){
27220 sqlite3_fputs("Error: internal error", stderr);
27221 break;
27222 }else{
27223 if( bGroupByParent
27224 && (bVerbose || res==0)
27225 && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
27226 ){
27227 sqlite3_fprintf(out, "-- Parent table %s\n", zParent);
27228 sqlite3_free(zPrev);
27229 zPrev = sqlite3_mprintf("%s", zParent);
27230 }
27231
27232 if( res==0 ){
27233 sqlite3_fprintf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
27234 }else if( bVerbose ){
27235 sqlite3_fprintf(out,
27236 "%s/* no extra indexes required for %s -> %s */\n",
27237 zIndent, zFrom, zTarget
27238 );
27239 }
27240 }
27241 }
27242 sqlite3_free(zPrev);
27243
27244 if( rc!=SQLITE_OK ){
27245 sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
27246 }
27247
27248 rc2 = sqlite3_finalize(pSql);
27249 if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
27250 rc = rc2;
27251 sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
27252 }
27253 }else{
27254 sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
27255 }
27256
27257 return rc;
27258 }
27259
@@ -25898,13 +27269,13 @@
27269 n = (nArg>=2 ? strlen30(azArg[1]) : 0);
27270 if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
27271 return lintFkeyIndexes(pState, azArg, nArg);
27272
27273 usage:
27274 sqlite3_fprintf(stderr,"Usage %s sub-command ?switches...?\n", azArg[0]);
27275 sqlite3_fprintf(stderr, "Where sub-commands are:\n");
27276 sqlite3_fprintf(stderr, " fkey-indexes\n");
27277 return SQLITE_ERROR;
27278 }
27279
27280 static void shellPrepare(
27281 sqlite3 *db,
@@ -25914,11 +27285,12 @@
27285 ){
27286 *ppStmt = 0;
27287 if( *pRc==SQLITE_OK ){
27288 int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
27289 if( rc!=SQLITE_OK ){
27290 sqlite3_fprintf(stderr,
27291 "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
27292 *pRc = rc;
27293 }
27294 }
27295 }
27296
@@ -25958,11 +27330,11 @@
27330 if( pStmt ){
27331 sqlite3 *db = sqlite3_db_handle(pStmt);
27332 int rc = sqlite3_finalize(pStmt);
27333 if( *pRc==SQLITE_OK ){
27334 if( rc!=SQLITE_OK ){
27335 sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
27336 }
27337 *pRc = rc;
27338 }
27339 }
27340 }
@@ -25980,11 +27352,11 @@
27352 ){
27353 int rc = sqlite3_reset(pStmt);
27354 if( *pRc==SQLITE_OK ){
27355 if( rc!=SQLITE_OK ){
27356 sqlite3 *db = sqlite3_db_handle(pStmt);
27357 sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
27358 }
27359 *pRc = rc;
27360 }
27361 }
27362 #endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
@@ -26009,10 +27381,11 @@
27381 char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
27382 const char *zFile; /* --file argument, or NULL */
27383 const char *zDir; /* --directory argument, or NULL */
27384 char **azArg; /* Array of command arguments */
27385 ShellState *p; /* Shell state */
27386 FILE *out; /* Output to this stream */
27387 sqlite3 *db; /* Database containing the archive */
27388 };
27389
27390 /*
27391 ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
@@ -26032,13 +27405,13 @@
27405 va_start(ap, zFmt);
27406 z = sqlite3_vmprintf(zFmt, ap);
27407 va_end(ap);
27408 shellEmitError(z);
27409 if( pAr->fromCmdLine ){
27410 sqlite3_fputs("Use \"-A\" for more help\n", stderr);
27411 }else{
27412 sqlite3_fputs("Use \".archive --help\" for more help\n", stderr);
27413 }
27414 sqlite3_free(z);
27415 return SQLITE_ERROR;
27416 }
27417
@@ -26134,11 +27507,11 @@
27507 };
27508 int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
27509 struct ArSwitch *pEnd = &aSwitch[nSwitch];
27510
27511 if( nArg<=1 ){
27512 sqlite3_fprintf(stderr, "Wrong number of arguments. Usage:\n");
27513 return arUsage(stderr);
27514 }else{
27515 char *z = azArg[1];
27516 if( z[0]!='-' ){
27517 /* Traditional style [tar] invocation */
@@ -26240,11 +27613,11 @@
27613 }
27614 }
27615 }
27616 }
27617 if( pAr->eCmd==0 ){
27618 sqlite3_fprintf(stderr, "Required argument missing. Usage:\n");
27619 return arUsage(stderr);
27620 }
27621 return SQLITE_OK;
27622 }
27623
@@ -26283,11 +27656,11 @@
27656 if( SQLITE_ROW==sqlite3_step(pTest) ){
27657 bOk = 1;
27658 }
27659 shellReset(&rc, pTest);
27660 if( rc==SQLITE_OK && bOk==0 ){
27661 sqlite3_fprintf(stderr,"not found in archive: %s\n", z);
27662 rc = SQLITE_ERROR;
27663 }
27664 }
27665 shellFinalize(&rc, pTest);
27666 }
@@ -26350,19 +27723,19 @@
27723 arWhereClause(&rc, pAr, &zWhere);
27724
27725 shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
27726 pAr->zSrcTable, zWhere);
27727 if( pAr->bDryRun ){
27728 sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
27729 }else{
27730 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
27731 if( pAr->bVerbose ){
27732 sqlite3_fprintf(pAr->out, "%s % 10d %s %s\n",
27733 sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1),
27734 sqlite3_column_text(pSql, 2),sqlite3_column_text(pSql, 3));
27735 }else{
27736 sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
27737 }
27738 }
27739 }
27740 shellFinalize(&rc, pSql);
27741 sqlite3_free(zWhere);
@@ -26385,11 +27758,11 @@
27758 }
27759 if( rc==SQLITE_OK ){
27760 zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
27761 pAr->zSrcTable, zWhere);
27762 if( pAr->bDryRun ){
27763 sqlite3_fprintf(pAr->out, "%s\n", zSql);
27764 }else{
27765 char *zErr = 0;
27766 rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
27767 if( rc==SQLITE_OK ){
27768 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
@@ -26398,11 +27771,11 @@
27771 }else{
27772 rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0);
27773 }
27774 }
27775 if( zErr ){
27776 sqlite3_fprintf(stdout, "ERROR: %s\n", zErr); /* stdout? */
27777 sqlite3_free(zErr);
27778 }
27779 }
27780 }
27781 sqlite3_free(zWhere);
@@ -26462,15 +27835,15 @@
27835 ** populating them changes the timestamp). */
27836 for(i=0; i<2; i++){
27837 j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
27838 sqlite3_bind_int(pSql, j, i);
27839 if( pAr->bDryRun ){
27840 sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
27841 }else{
27842 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
27843 if( i==0 && pAr->bVerbose ){
27844 sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
27845 }
27846 }
27847 }
27848 shellReset(&rc, pSql);
27849 }
@@ -26486,17 +27859,17 @@
27859 ** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out.
27860 */
27861 static int arExecSql(ArCommand *pAr, const char *zSql){
27862 int rc;
27863 if( pAr->bDryRun ){
27864 sqlite3_fprintf(pAr->out, "%s\n", zSql);
27865 rc = SQLITE_OK;
27866 }else{
27867 char *zErr = 0;
27868 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
27869 if( zErr ){
27870 sqlite3_fprintf(stdout, "ERROR: %s\n", zErr);
27871 sqlite3_free(zErr);
27872 }
27873 }
27874 return rc;
27875 }
@@ -26641,10 +28014,11 @@
28014 cmd.fromCmdLine = fromCmdLine;
28015 rc = arParseCommand(azArg, nArg, &cmd);
28016 if( rc==SQLITE_OK ){
28017 int eDbType = SHELL_OPEN_UNSPEC;
28018 cmd.p = pState;
28019 cmd.out = pState->out;
28020 cmd.db = pState->db;
28021 if( cmd.zFile ){
28022 eDbType = deduceDatabaseType(cmd.zFile, 1);
28023 }else{
28024 eDbType = pState->openMode;
@@ -26667,17 +28041,18 @@
28041 }else{
28042 flags = SQLITE_OPEN_READONLY;
28043 }
28044 cmd.db = 0;
28045 if( cmd.bDryRun ){
28046 sqlite3_fprintf(cmd.out, "-- open database '%s'%s\n", cmd.zFile,
28047 eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
28048 }
28049 rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
28050 eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
28051 if( rc!=SQLITE_OK ){
28052 sqlite3_fprintf(stderr, "cannot open file: %s (%s)\n",
28053 cmd.zFile, sqlite3_errmsg(cmd.db));
28054 goto end_ar_command;
28055 }
28056 sqlite3_fileio_init(cmd.db, 0, 0);
28057 sqlite3_sqlar_init(cmd.db, 0, 0);
28058 sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
@@ -26686,11 +28061,11 @@
28061 }
28062 if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
28063 if( cmd.eCmd!=AR_CMD_CREATE
28064 && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
28065 ){
28066 sqlite3_fprintf(stderr, "database does not contain an 'sqlar' table\n");
28067 rc = SQLITE_ERROR;
28068 goto end_ar_command;
28069 }
28070 cmd.zSrcTable = sqlite3_mprintf("sqlar");
28071 }
@@ -26744,11 +28119,11 @@
28119 ** This function is used as a callback by the recover extension. Simply
28120 ** print the supplied SQL statement to stdout.
28121 */
28122 static int recoverSqlCb(void *pCtx, const char *zSql){
28123 ShellState *pState = (ShellState*)pCtx;
28124 sqlite3_fprintf(pState->out, "%s;\n", zSql);
28125 return SQLITE_OK;
28126 }
28127
28128 /*
28129 ** This function is called to recover data from the database. A script
@@ -26787,11 +28162,11 @@
28162 }else
28163 if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
28164 bRowids = 0;
28165 }
28166 else{
28167 sqlite3_fprintf(stderr,"unexpected option: %s\n", azArg[i]);
28168 showHelp(pState->out, azArg[0]);
28169 return 1;
28170 }
28171 }
28172
@@ -26806,11 +28181,11 @@
28181
28182 sqlite3_recover_run(p);
28183 if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
28184 const char *zErr = sqlite3_recover_errmsg(p);
28185 int errCode = sqlite3_recover_errcode(p);
28186 sqlite3_fprintf(stderr,"sql error: %s (%d)\n", zErr, errCode);
28187 }
28188 rc = sqlite3_recover_finish(p);
28189 return rc;
28190 }
28191 #endif /* SQLITE_SHELL_HAVE_RECOVER */
@@ -26828,25 +28203,25 @@
28203 i64 nError = 0;
28204 const char *zErr = 0;
28205 while( SQLITE_OK==sqlite3_intck_step(p) ){
28206 const char *zMsg = sqlite3_intck_message(p);
28207 if( zMsg ){
28208 sqlite3_fprintf(pState->out, "%s\n", zMsg);
28209 nError++;
28210 }
28211 nStep++;
28212 if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){
28213 sqlite3_intck_unlock(p);
28214 }
28215 }
28216 rc = sqlite3_intck_error(p, &zErr);
28217 if( zErr ){
28218 sqlite3_fprintf(stderr,"%s\n", zErr);
28219 }
28220 sqlite3_intck_close(p);
28221
28222 sqlite3_fprintf(pState->out, "%lld steps, %lld errors\n", nStep, nError);
28223 }
28224
28225 return rc;
28226 }
28227
@@ -26865,11 +28240,11 @@
28240 */
28241 #ifdef SHELL_DEBUG
28242 #define rc_err_oom_die(rc) \
28243 if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
28244 else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
28245 sqlite3_fprintf(stderr,"E:%d\n",rc), assert(0)
28246 #else
28247 static void rc_err_oom_die(int rc){
28248 if( rc==SQLITE_NOMEM ) shell_check_oom(0);
28249 assert(rc==SQLITE_OK||rc==SQLITE_DONE);
28250 }
@@ -27023,12 +28398,12 @@
28398 }else if( *pDb==0 ){
28399 return 0;
28400 }else{
28401 /* Formulate the columns spec, close the DB, zero *pDb. */
28402 char *zColsSpec = 0;
28403 int hasDupes = db_int(*pDb, "%s", zHasDupes);
28404 int nDigits = (hasDupes)? db_int(*pDb, "%s", zColDigits) : 0;
28405 if( hasDupes ){
28406 #ifdef SHELL_COLUMN_RENAME_CLEAN
28407 rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
28408 rc_err_oom_die(rc);
28409 #endif
@@ -27039,11 +28414,11 @@
28414 sqlite3_bind_int(pStmt, 1, nDigits);
28415 rc = sqlite3_step(pStmt);
28416 sqlite3_finalize(pStmt);
28417 if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
28418 }
28419 assert(db_int(*pDb, "%s", zHasDupes)==0); /* Consider: remove this */
28420 rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
28421 rc_err_oom_die(rc);
28422 rc = sqlite3_step(pStmt);
28423 if( rc==SQLITE_ROW ){
28424 zColsSpec = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
@@ -27082,12 +28457,13 @@
28457 shellPreparePrintf(p->db, &rc, &pStmt,
28458 "SELECT 1 FROM sqlite_schema o WHERE "
28459 "sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true"
28460 );
28461 if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
28462 sqlite3_fputs("/* WARNING: "
28463 "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n",
28464 p->out
28465 );
28466 }
28467 shellFinalize(&rc, pStmt);
28468 return rc;
28469 }
@@ -27114,16 +28490,18 @@
28490 return SQLITE_OK;
28491 }
28492 if( faultsim_state.iCnt ){
28493 if( faultsim_state.iCnt>0 ) faultsim_state.iCnt--;
28494 if( faultsim_state.eVerbose>=2 ){
28495 sqlite3_fprintf(stdout,
28496 "FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
28497 }
28498 return SQLITE_OK;
28499 }
28500 if( faultsim_state.eVerbose>=1 ){
28501 sqlite3_fprintf(stdout,
28502 "FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
28503 }
28504 faultsim_state.iCnt = faultsim_state.iInterval;
28505 faultsim_state.nHit++;
28506 if( faultsim_state.nRepeat>0 && faultsim_state.nRepeat<=faultsim_state.nHit ){
28507 faultsim_state.iCnt = -1;
@@ -27182,11 +28560,11 @@
28560 clearTempFile(p);
28561
28562 #ifndef SQLITE_OMIT_AUTHORIZATION
28563 if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
28564 if( nArg!=2 ){
28565 sqlite3_fprintf(stderr, "Usage: .auth ON|OFF\n");
28566 rc = 1;
28567 goto meta_command_exit;
28568 }
28569 open_db(p, 0);
28570 if( booleanValue(azArg[1]) ){
@@ -27229,32 +28607,32 @@
28607 }else
28608 if( cli_strcmp(z, "-async")==0 ){
28609 bAsync = 1;
28610 }else
28611 {
28612 sqlite3_fprintf(stderr,"unknown option: %s\n", azArg[j]);
28613 return 1;
28614 }
28615 }else if( zDestFile==0 ){
28616 zDestFile = azArg[j];
28617 }else if( zDb==0 ){
28618 zDb = zDestFile;
28619 zDestFile = azArg[j];
28620 }else{
28621 sqlite3_fprintf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
28622 return 1;
28623 }
28624 }
28625 if( zDestFile==0 ){
28626 sqlite3_fprintf(stderr, "missing FILENAME argument on .backup\n");
28627 return 1;
28628 }
28629 if( zDb==0 ) zDb = "main";
28630 rc = sqlite3_open_v2(zDestFile, &pDest,
28631 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
28632 if( rc!=SQLITE_OK ){
28633 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zDestFile);
28634 close_db(pDest);
28635 return 1;
28636 }
28637 if( bAsync ){
28638 sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
@@ -27286,23 +28664,14 @@
28664 eputz("Usage: .bail on|off\n");
28665 rc = 1;
28666 }
28667 }else
28668
28669 /* Undocumented. Legacy only. See "crlf" below */
28670 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
28671 eputz("The \".binary\" command is deprecated.\n");
28672 rc = 1;
 
 
 
 
 
 
 
 
 
28673 }else
28674
28675 /* The undocumented ".breakpoint" command causes a call to the no-op
28676 ** routine named test_breakpoint().
28677 */
@@ -27320,11 +28689,11 @@
28689 sqlite3_free(z);
28690 #else
28691 rc = chdir(azArg[1]);
28692 #endif
28693 if( rc ){
28694 sqlite3_fprintf(stderr,"Cannot change to directory \"%s\"\n", azArg[1]);
28695 rc = 1;
28696 }
28697 }else{
28698 eputz("Usage: .cd DIRECTORY\n");
28699 rc = 1;
@@ -27353,15 +28722,16 @@
28722 eputz("Usage: .check GLOB-PATTERN\n");
28723 rc = 2;
28724 }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
28725 rc = 2;
28726 }else if( testcase_glob(azArg[1],zRes)==0 ){
28727 sqlite3_fprintf(stderr,
28728 "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
28729 p->zTestcase, azArg[1], zRes);
28730 rc = 1;
28731 }else{
28732 sqlite3_fprintf(p->out, "testcase-%s ok\n", p->zTestcase);
28733 p->nCheck++;
28734 }
28735 sqlite3_free(zRes);
28736 }else
28737 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -27390,13 +28760,13 @@
28760 zFile = "(memory)";
28761 }else if( zFile[0]==0 ){
28762 zFile = "(temporary-file)";
28763 }
28764 if( p->pAuxDb == &p->aAuxDb[i] ){
28765 sqlite3_fprintf(stdout, "ACTIVE %d: %s\n", i, zFile);
28766 }else if( p->aAuxDb[i].db!=0 ){
28767 sqlite3_fprintf(stdout, " %d: %s\n", i, zFile);
28768 }
28769 }
28770 }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
28771 int i = azArg[1][0] - '0';
28772 if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
@@ -27422,24 +28792,22 @@
28792 eputz("Usage: .connection [close] [CONNECTION-NUMBER]\n");
28793 rc = 1;
28794 }
28795 }else
28796
28797 if( c=='c' && n==4
28798 && (cli_strncmp(azArg[0], "crlf", n)==0
28799 || cli_strncmp(azArg[0], "crnl",n)==0)
28800 ){
28801 if( nArg==2 ){
28802 #ifdef _WIN32
28803 p->crlfMode = booleanValue(azArg[1]);
28804 #else
28805 p->crlfMode = 0;
 
 
 
 
28806 #endif
 
 
28807 }
28808 sqlite3_fprintf(stderr, "crlf is %s\n", p->crlfMode ? "ON" : "OFF");
28809 }else
28810
28811 if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
28812 char **azName = 0;
28813 int nName = 0;
@@ -27465,11 +28833,11 @@
28833 sqlite3_finalize(pStmt);
28834 for(i=0; i<nName; i++){
28835 int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
28836 int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
28837 const char *z = azName[i*2+1];
28838 sqlite3_fprintf(p->out, "%s: %s %s%s\n",
28839 azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w",
28840 eTxn==SQLITE_TXN_NONE ? "" :
28841 eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
28842 free(azName[i*2]);
28843 free(azName[i*2+1]);
@@ -27507,15 +28875,16 @@
28875 if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
28876 if( nArg>=3 ){
28877 sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
28878 }
28879 sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
28880 sqlite3_fprintf(p->out, "%19s %s\n",
28881 aDbConfig[ii].zName, v ? "on" : "off");
28882 if( nArg>1 ) break;
28883 }
28884 if( nArg>1 && ii==ArraySize(aDbConfig) ){
28885 sqlite3_fprintf(stderr,"Error: unknown dbconfig \"%s\"\n", azArg[1]);
28886 eputz("Enter \".dbconfig\" with no arguments for a list\n");
28887 }
28888 }else
28889
28890 #if SQLITE_SHELL_HAVE_RECOVER
@@ -27561,11 +28930,12 @@
28930 }else
28931 if( cli_strcmp(z,"nosys")==0 ){
28932 ShellSetFlag(p, SHFLG_DumpNoSys);
28933 }else
28934 {
28935 sqlite3_fprintf(stderr,
28936 "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
28937 rc = 1;
28938 sqlite3_free(zLike);
28939 goto meta_command_exit;
28940 }
28941 }else{
@@ -27596,12 +28966,12 @@
28966 outputDumpWarning(p, zLike);
28967 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
28968 /* When playing back a "dump", the content might appear in an order
28969 ** which causes immediate foreign key constraints to be violated.
28970 ** So disable foreign-key constraint enforcement to prevent problems. */
28971 sqlite3_fputs("PRAGMA foreign_keys=OFF;\n", p->out);
28972 sqlite3_fputs("BEGIN TRANSACTION;\n", p->out);
28973 }
28974 p->writableSchema = 0;
28975 p->showHeader = 0;
28976 /* Set writable_schema=ON since doing so forces SQLite to initialize
28977 ** as much of the schema as it can even if the sqlite_schema table is
@@ -27629,17 +28999,17 @@
28999 run_table_dump_query(p, zSql);
29000 sqlite3_free(zSql);
29001 }
29002 sqlite3_free(zLike);
29003 if( p->writableSchema ){
29004 sqlite3_fputs("PRAGMA writable_schema=OFF;\n", p->out);
29005 p->writableSchema = 0;
29006 }
29007 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
29008 sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
29009 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
29010 sqlite3_fputs(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n", p->out);
29011 }
29012 p->showHeader = savedShowHeader;
29013 p->shellFlgs = savedShellFlags;
29014 }else
29015
@@ -27649,10 +29019,14 @@
29019 }else{
29020 eputz("Usage: .echo on|off\n");
29021 rc = 1;
29022 }
29023 }else
29024
29025 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
29026 rc = shell_dbtotxt_command(p, nArg, azArg);
29027 }else
29028
29029 if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
29030 if( nArg==2 ){
29031 p->autoEQPtest = 0;
29032 if( p->autoEQPtrace ){
@@ -27715,11 +29089,12 @@
29089 }else
29090
29091 #ifndef SQLITE_OMIT_VIRTUALTABLE
29092 if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
29093 if( p->bSafeMode ){
29094 sqlite3_fprintf(stderr,
29095 "Cannot run experimental commands such as \"%s\" in safe mode\n",
29096 azArg[0]);
29097 rc = 1;
29098 }else{
29099 open_db(p, 0);
29100 expertDotCommand(p, azArg, nArg);
@@ -27772,13 +29147,14 @@
29147 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
29148 }
29149
29150 /* --help lists all file-controls */
29151 if( cli_strcmp(zCmd,"help")==0 ){
29152 sqlite3_fputs("Available file-controls:\n", p->out);
29153 for(i=0; i<ArraySize(aCtrl); i++){
29154 sqlite3_fprintf(p->out,
29155 " .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
29156 }
29157 rc = 1;
29158 goto meta_command_exit;
29159 }
29160
@@ -27789,19 +29165,19 @@
29165 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
29166 if( filectrl<0 ){
29167 filectrl = aCtrl[i].ctrlCode;
29168 iCtrl = i;
29169 }else{
29170 sqlite3_fprintf(stderr,"Error: ambiguous file-control: \"%s\"\n"
29171 "Use \".filectrl --help\" for help\n", zCmd);
29172 rc = 1;
29173 goto meta_command_exit;
29174 }
29175 }
29176 }
29177 if( filectrl<0 ){
29178 sqlite3_fprintf(stderr,"Error: unknown file-control: %s\n"
29179 "Use \".filectrl --help\" for help\n", zCmd);
29180 }else{
29181 switch(filectrl){
29182 case SQLITE_FCNTL_SIZE_LIMIT: {
29183 if( nArg!=2 && nArg!=3 ) break;
@@ -27841,11 +29217,11 @@
29217 case SQLITE_FCNTL_TEMPFILENAME: {
29218 char *z = 0;
29219 if( nArg!=2 ) break;
29220 sqlite3_file_control(p->db, zSchema, filectrl, &z);
29221 if( z ){
29222 sqlite3_fprintf(p->out, "%s\n", z);
29223 sqlite3_free(z);
29224 }
29225 isOk = 2;
29226 break;
29227 }
@@ -27855,23 +29231,24 @@
29231 x = atoi(azArg[2]);
29232 sqlite3_file_control(p->db, zSchema, filectrl, &x);
29233 }
29234 x = -1;
29235 sqlite3_file_control(p->db, zSchema, filectrl, &x);
29236 sqlite3_fprintf(p->out, "%d\n", x);
29237 isOk = 2;
29238 break;
29239 }
29240 }
29241 }
29242 if( isOk==0 && iCtrl>=0 ){
29243 sqlite3_fprintf(p->out, "Usage: .filectrl %s %s\n",
29244 zCmd, aCtrl[iCtrl].zUsage);
29245 rc = 1;
29246 }else if( isOk==1 ){
29247 char zBuf[100];
29248 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
29249 sqlite3_fprintf(p->out, "%s\n", zBuf);
29250 }
29251 }else
29252
29253 if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
29254 ShellState data;
@@ -27908,19 +29285,19 @@
29285 doStats = sqlite3_step(pStmt)==SQLITE_ROW;
29286 sqlite3_finalize(pStmt);
29287 }
29288 }
29289 if( doStats==0 ){
29290 sqlite3_fputs("/* No STAT tables available */\n", p->out);
29291 }else{
29292 sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
29293 data.cMode = data.mode = MODE_Insert;
29294 data.zDestTable = "sqlite_stat1";
29295 shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
29296 data.zDestTable = "sqlite_stat4";
29297 shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
29298 sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
29299 }
29300 }else
29301
29302 if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
29303 if( nArg==2 ){
@@ -27934,11 +29311,11 @@
29311
29312 if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){
29313 if( nArg>=2 ){
29314 n = showHelp(p->out, azArg[1]);
29315 if( n==0 ){
29316 sqlite3_fprintf(p->out, "Nothing matches '%s'\n", azArg[1]);
29317 }
29318 }else{
29319 showHelp(p->out, 0);
29320 }
29321 }else
@@ -27977,11 +29354,11 @@
29354 if( zFile==0 ){
29355 zFile = z;
29356 }else if( zTable==0 ){
29357 zTable = z;
29358 }else{
29359 sqlite3_fprintf(p->out, "ERROR: extra argument: \"%s\". Usage:\n",z);
29360 showHelp(p->out, "import");
29361 goto meta_command_exit;
29362 }
29363 }else if( cli_strcmp(z,"-v")==0 ){
29364 eVerbose++;
@@ -27998,17 +29375,17 @@
29375 sCtx.cColSep = ',';
29376 sCtx.cRowSep = '\n';
29377 xRead = csv_read_one_field;
29378 useOutputMode = 0;
29379 }else{
29380 sqlite3_fprintf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
29381 showHelp(p->out, "import");
29382 goto meta_command_exit;
29383 }
29384 }
29385 if( zTable==0 ){
29386 sqlite3_fprintf(p->out, "ERROR: missing %s argument. Usage:\n",
29387 zFile==0 ? "FILE" : "TABLE");
29388 showHelp(p->out, "import");
29389 goto meta_command_exit;
29390 }
29391 seenInterrupt = 0;
@@ -28054,32 +29431,32 @@
29431 if( sCtx.zFile[0]=='|' ){
29432 #ifdef SQLITE_OMIT_POPEN
29433 eputz("Error: pipes are not supported in this OS\n");
29434 goto meta_command_exit;
29435 #else
29436 sCtx.in = sqlite3_popen(sCtx.zFile+1, "r");
29437 sCtx.zFile = "<pipe>";
29438 sCtx.xCloser = pclose;
29439 #endif
29440 }else{
29441 sCtx.in = sqlite3_fopen(sCtx.zFile, "rb");
29442 sCtx.xCloser = fclose;
29443 }
29444 if( sCtx.in==0 ){
29445 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
29446 goto meta_command_exit;
29447 }
29448 if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
29449 char zSep[2];
29450 zSep[1] = 0;
29451 zSep[0] = sCtx.cColSep;
29452 sqlite3_fputs("Column separator ", p->out);
29453 output_c_string(p->out, zSep);
29454 sqlite3_fputs(", row separator ", p->out);
29455 zSep[0] = sCtx.cRowSep;
29456 output_c_string(p->out, zSep);
29457 sqlite3_fputs("\n", p->out);
29458 }
29459 sCtx.z = sqlite3_malloc64(120);
29460 if( sCtx.z==0 ){
29461 import_cleanup(&sCtx);
29462 shell_out_of_memory();
@@ -28087,11 +29464,15 @@
29464 /* Below, resources must be freed before exit. */
29465 while( (nSkip--)>0 ){
29466 while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
29467 }
29468 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
29469 if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0)
29470 && 0==db_int(p->db, "SELECT count(*) FROM \"%w\".sqlite_schema"
29471 " WHERE name=%Q AND type='view'",
29472 zSchema ? zSchema : "main", zTable)
29473 ){
29474 /* Table does not exist. Create it. */
29475 sqlite3 *dbCols = 0;
29476 char *zRenames = 0;
29477 char *zColDefs;
29478 zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
@@ -28100,18 +29481,18 @@
29481 zAutoColumn(sCtx.z, &dbCols, 0);
29482 if( sCtx.cTerm!=sCtx.cColSep ) break;
29483 }
29484 zColDefs = zAutoColumn(0, &dbCols, &zRenames);
29485 if( zRenames!=0 ){
29486 sqlite3_fprintf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
29487 "Columns renamed during .import %s due to duplicates:\n"
29488 "%s\n", sCtx.zFile, zRenames);
29489 sqlite3_free(zRenames);
29490 }
29491 assert(dbCols==0);
29492 if( zColDefs==0 ){
29493 sqlite3_fprintf(stderr,"%s: empty file\n", sCtx.zFile);
29494 import_cleanup(&sCtx);
29495 rc = 1;
29496 sqlite3_free(zCreate);
29497 goto meta_command_exit;
29498 }
@@ -28119,17 +29500,20 @@
29500 if( zCreate==0 ){
29501 import_cleanup(&sCtx);
29502 shell_out_of_memory();
29503 }
29504 if( eVerbose>=1 ){
29505 sqlite3_fprintf(p->out, "%s\n", zCreate);
29506 }
29507 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
29508 if( rc ){
29509 sqlite3_fprintf(stderr,
29510 "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
29511 }
29512 sqlite3_free(zCreate);
29513 zCreate = 0;
29514 if( rc ){
 
29515 import_cleanup(&sCtx);
29516 rc = 1;
29517 goto meta_command_exit;
29518 }
29519 }
@@ -28180,11 +29564,11 @@
29564 }
29565 zSql[j++] = ')';
29566 zSql[j] = 0;
29567 assert( j<nByte );
29568 if( eVerbose>=2 ){
29569 sqlite3_fprintf(p->out, "Insert using: %s\n", zSql);
29570 }
29571 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
29572 sqlite3_free(zSql);
29573 zSql = 0;
29574 if( rc ){
@@ -28219,11 +29603,11 @@
29603 if( z==0 && (xRead==csv_read_one_field) && i==nCol-1 && i>0 ){
29604 z = "";
29605 }
29606 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
29607 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
29608 sqlite3_fprintf(stderr,"%s:%d: expected %d columns but found %d"
29609 " - filling the rest with NULL\n",
29610 sCtx.zFile, startLine, nCol, i+1);
29611 i += 2;
29612 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
29613 }
@@ -28231,18 +29615,19 @@
29615 if( sCtx.cTerm==sCtx.cColSep ){
29616 do{
29617 xRead(&sCtx);
29618 i++;
29619 }while( sCtx.cTerm==sCtx.cColSep );
29620 sqlite3_fprintf(stderr,
29621 "%s:%d: expected %d columns but found %d - extras ignored\n",
29622 sCtx.zFile, startLine, nCol, i);
29623 }
29624 if( i>=nCol ){
29625 sqlite3_step(pStmt);
29626 rc = sqlite3_reset(pStmt);
29627 if( rc!=SQLITE_OK ){
29628 sqlite3_fprintf(stderr,"%s:%d: INSERT failed: %s\n",
29629 sCtx.zFile, startLine, sqlite3_errmsg(p->db));
29630 sCtx.nErr++;
29631 }else{
29632 sCtx.nRow++;
29633 }
@@ -28251,11 +29636,12 @@
29636
29637 import_cleanup(&sCtx);
29638 sqlite3_finalize(pStmt);
29639 if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
29640 if( eVerbose>0 ){
29641 sqlite3_fprintf(p->out,
29642 "Added %d rows with %d errors using %d lines of input\n",
29643 sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
29644 }
29645 }else
29646 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
29647
@@ -28267,11 +29653,11 @@
29653 int tnum = 0;
29654 int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
29655 int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
29656 int i;
29657 if( !ShellHasFlag(p,SHFLG_TestingMode) ){
29658 sqlite3_fprintf(stderr,".%s unavailable without --unsafe-testing\n",
29659 "imposter");
29660 rc = 1;
29661 goto meta_command_exit;
29662 }
29663 if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
@@ -28333,11 +29719,11 @@
29719 zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
29720 }
29721 }
29722 sqlite3_finalize(pStmt);
29723 if( i==0 || tnum==0 ){
29724 sqlite3_fprintf(stderr,"no such index: \"%s\"\n", azArg[1]);
29725 rc = 1;
29726 sqlite3_free(zCollist);
29727 goto meta_command_exit;
29728 }
29729 if( lenPK==0 ) lenPK = 100000;
@@ -28348,18 +29734,20 @@
29734 rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
29735 if( rc==SQLITE_OK ){
29736 rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
29737 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
29738 if( rc ){
29739 sqlite3_fprintf(stderr,
29740 "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
29741 }else{
29742 sqlite3_fprintf(stdout, "%s;\n", zSql);
29743 sqlite3_fprintf(stdout,
29744 "WARNING: writing to an imposter table will corrupt"
29745 " the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index");
29746 }
29747 }else{
29748 sqlite3_fprintf(stderr,"SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
29749 rc = 1;
29750 }
29751 sqlite3_free(zSql);
29752 }else
29753 #endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
@@ -28369,11 +29757,11 @@
29757 if( nArg==2 ){
29758 iArg = integerValue(azArg[1]);
29759 if( iArg==0 ) iArg = -1;
29760 }
29761 if( (nArg!=1 && nArg!=2) || iArg<0 ){
29762 sqlite3_fprintf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n");
29763 rc = 1;
29764 goto meta_command_exit;
29765 }
29766 open_db(p, 0);
29767 rc = intckDatabaseCmd(p, iArg);
@@ -28388,13 +29776,13 @@
29776 sqlite3IoTrace = 0;
29777 }else if( cli_strcmp(azArg[1], "-")==0 ){
29778 sqlite3IoTrace = iotracePrintf;
29779 iotrace = stdout;
29780 }else{
29781 iotrace = sqlite3_fopen(azArg[1], "w");
29782 if( iotrace==0 ){
29783 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
29784 sqlite3IoTrace = 0;
29785 rc = 1;
29786 }else{
29787 sqlite3IoTrace = iotracePrintf;
29788 }
@@ -28422,11 +29810,11 @@
29810 };
29811 int i, n2;
29812 open_db(p, 0);
29813 if( nArg==1 ){
29814 for(i=0; i<ArraySize(aLimit); i++){
29815 sqlite3_fprintf(stdout, "%20s %d\n", aLimit[i].zLimitName,
29816 sqlite3_limit(p->db, aLimit[i].limitCode, -1));
29817 }
29818 }else if( nArg>3 ){
29819 eputz("Usage: .limit NAME ?NEW-VALUE?\n");
29820 rc = 1;
@@ -28437,28 +29825,28 @@
29825 for(i=0; i<ArraySize(aLimit); i++){
29826 if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
29827 if( iLimit<0 ){
29828 iLimit = i;
29829 }else{
29830 sqlite3_fprintf(stderr,"ambiguous limit: \"%s\"\n", azArg[1]);
29831 rc = 1;
29832 goto meta_command_exit;
29833 }
29834 }
29835 }
29836 if( iLimit<0 ){
29837 sqlite3_fprintf(stderr,"unknown limit: \"%s\"\n"
29838 "enter \".limits\" with no arguments for a list.\n",
29839 azArg[1]);
29840 rc = 1;
29841 goto meta_command_exit;
29842 }
29843 if( nArg==3 ){
29844 sqlite3_limit(p->db, aLimit[iLimit].limitCode,
29845 (int)integerValue(azArg[2]));
29846 }
29847 sqlite3_fprintf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
29848 sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
29849 }
29850 }else
29851
29852 if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){
@@ -28503,11 +29891,11 @@
29891 " than \"on\" or \"off\"\n");
29892 zFile = "off";
29893 }
29894 output_file_close(p->pLog);
29895 if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
29896 p->pLog = output_file_open(zFile);
29897 }
29898 }else
29899
29900 if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
29901 const char *zMode = 0;
@@ -28537,35 +29925,37 @@
29925 cmOpts = cmo;
29926 }
29927 }else if( zTabname==0 ){
29928 zTabname = z;
29929 }else if( z[0]=='-' ){
29930 sqlite3_fprintf(stderr,"unknown option: %s\n", z);
29931 eputz("options:\n"
29932 " --noquote\n"
29933 " --quote\n"
29934 " --wordwrap on/off\n"
29935 " --wrap N\n"
29936 " --ww\n");
29937 rc = 1;
29938 goto meta_command_exit;
29939 }else{
29940 sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
29941 rc = 1;
29942 goto meta_command_exit;
29943 }
29944 }
29945 if( zMode==0 ){
29946 if( p->mode==MODE_Column
29947 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
29948 ){
29949 sqlite3_fprintf(p->out,
29950 "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
29951 modeDescr[p->mode], p->cmOpts.iWrap,
29952 p->cmOpts.bWordWrap ? "on" : "off",
29953 p->cmOpts.bQuote ? "" : "no");
29954 }else{
29955 sqlite3_fprintf(p->out,
29956 "current output mode: %s\n", modeDescr[p->mode]);
29957 }
29958 zMode = modeDescr[p->mode];
29959 }
29960 n2 = strlen30(zMode);
29961 if( cli_strncmp(zMode,"lines",n2)==0 ){
@@ -28634,11 +30024,11 @@
30024 if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){
30025 if( nArg!=2 ){
30026 eputz("Usage: .nonce NONCE\n");
30027 rc = 1;
30028 }else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
30029 sqlite3_fprintf(stderr,"line %d: incorrect nonce: \"%s\"\n",
30030 p->lineno, azArg[1]);
30031 exit(1);
30032 }else{
30033 p->bSafeMode = 0;
30034 return 0; /* Return immediately to bypass the safe mode reset
@@ -28689,15 +30079,15 @@
30079 p->szMax = integerValue(azArg[++iName]);
30080 #endif /* SQLITE_OMIT_DESERIALIZE */
30081 }else
30082 #endif /* !SQLITE_SHELL_FIDDLE */
30083 if( z[0]=='-' ){
30084 sqlite3_fprintf(stderr,"unknown option: %s\n", z);
30085 rc = 1;
30086 goto meta_command_exit;
30087 }else if( zFN ){
30088 sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
30089 rc = 1;
30090 goto meta_command_exit;
30091 }else{
30092 zFN = z;
30093 }
@@ -28735,11 +30125,11 @@
30125 zNewFilename = 0;
30126 }
30127 p->pAuxDb->zDbFilename = zNewFilename;
30128 open_db(p, OPEN_DB_KEEPALIVE);
30129 if( p->db==0 ){
30130 sqlite3_fprintf(stderr,"Error: cannot open '%s'\n", zNewFilename);
30131 sqlite3_free(zNewFilename);
30132 }else{
30133 p->pAuxDb->zFreeOnClose = zNewFilename;
30134 }
30135 }
@@ -28753,22 +30143,26 @@
30143 #ifndef SQLITE_SHELL_FIDDLE
30144 if( (c=='o'
30145 && (cli_strncmp(azArg[0], "output", n)==0
30146 || cli_strncmp(azArg[0], "once", n)==0))
30147 || (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
30148 || (c=='w' && n==3 && cli_strcmp(azArg[0],"www")==0)
30149 ){
30150 char *zFile = 0;
 
30151 int i;
30152 int eMode = 0;
30153 int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */
30154 int bPlain = 0; /* --plain option */
30155 static const char *zBomUtf8 = "\357\273\277";
30156 const char *zBom = 0;
30157
30158 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
30159 if( c=='e' ){
30160 eMode = 'x';
30161 bOnce = 2;
30162 }else if( c=='w' ){
30163 eMode = 'w';
30164 bOnce = 2;
30165 }else if( cli_strncmp(azArg[0],"once",n)==0 ){
30166 bOnce = 1;
30167 }
30168 for(i=1; i<nArg; i++){
@@ -28775,28 +30169,34 @@
30169 char *z = azArg[i];
30170 if( z[0]=='-' ){
30171 if( z[1]=='-' ) z++;
30172 if( cli_strcmp(z,"-bom")==0 ){
30173 zBom = zBomUtf8;
30174 }else if( cli_strcmp(z,"-plain")==0 ){
30175 bPlain = 1;
30176 }else if( c=='o' && cli_strcmp(z,"-x")==0 ){
30177 eMode = 'x'; /* spreadsheet */
30178 }else if( c=='o' && cli_strcmp(z,"-e")==0 ){
30179 eMode = 'e'; /* text editor */
30180 }else if( c=='o' && cli_strcmp(z,"-w")==0 ){
30181 eMode = 'w'; /* Web browser */
30182 }else{
30183 sqlite3_fprintf(p->out,
30184 "ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
30185 showHelp(p->out, azArg[0]);
30186 rc = 1;
30187 goto meta_command_exit;
30188 }
30189 }else if( zFile==0 && eMode==0 ){
30190 zFile = sqlite3_mprintf("%s", z);
30191 if( zFile && zFile[0]=='|' ){
30192 while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
30193 break;
30194 }
30195 }else{
30196 sqlite3_fprintf(p->out,
30197 "ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
30198 showHelp(p->out, azArg[0]);
30199 rc = 1;
30200 sqlite3_free(zFile);
30201 goto meta_command_exit;
30202 }
@@ -28809,24 +30209,31 @@
30209 }else{
30210 p->outCount = 0;
30211 }
30212 output_reset(p);
30213 #ifndef SQLITE_NOHAVE_SYSTEM
30214 if( eMode=='e' || eMode=='x' || eMode=='w' ){
30215 p->doXdgOpen = 1;
30216 outputModePush(p);
30217 if( eMode=='x' ){
30218 /* spreadsheet mode. Output as CSV. */
30219 newTempFile(p, "csv");
30220 ShellClearFlag(p, SHFLG_Echo);
30221 p->mode = MODE_Csv;
30222 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
30223 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
30224 #ifdef _WIN32
30225 zBom = zBomUtf8; /* Always include the BOM on Windows, as Excel does
30226 ** not work without it. */
30227 #endif
30228 }else if( eMode=='w' ){
30229 /* web-browser mode. */
30230 newTempFile(p, "html");
30231 if( !bPlain ) p->mode = MODE_Www;
30232 }else{
30233 /* text editor mode */
30234 newTempFile(p, "txt");
 
30235 }
30236 sqlite3_free(zFile);
30237 zFile = sqlite3_mprintf("%s", p->zTempFile);
30238 }
30239 #endif /* SQLITE_NOHAVE_SYSTEM */
@@ -28835,30 +30242,36 @@
30242 #ifdef SQLITE_OMIT_POPEN
30243 eputz("Error: pipes are not supported in this OS\n");
30244 rc = 1;
30245 output_redir(p, stdout);
30246 #else
30247 FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
30248 if( pfPipe==0 ){
30249 sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
30250 rc = 1;
30251 }else{
30252 output_redir(p, pfPipe);
30253 if( zBom ) sqlite3_fputs(zBom, pfPipe);
30254 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
30255 }
30256 #endif
30257 }else{
30258 FILE *pfFile = output_file_open(zFile);
30259 if( pfFile==0 ){
30260 if( cli_strcmp(zFile,"off")!=0 ){
30261 sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
30262 }
30263 rc = 1;
30264 } else {
30265 output_redir(p, pfFile);
30266 if( zBom ) sqlite3_fputs(zBom, pfFile);
30267 if( bPlain && eMode=='w' ){
30268 sqlite3_fputs(
30269 "<!DOCTYPE html>\n<BODY>\n<PLAINTEXT>\n",
30270 pfFile
30271 );
30272 }
30273 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
30274 }
30275 }
30276 sqlite3_free(zFile);
30277 }else
@@ -28895,11 +30308,12 @@
30308 if( len ){
30309 rx = sqlite3_prepare_v2(p->db,
30310 "SELECT key, quote(value) "
30311 "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
30312 while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
30313 sqlite3_fprintf(p->out,
30314 "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
30315 sqlite3_column_text(pStmt,1));
30316 }
30317 sqlite3_finalize(pStmt);
30318 }
30319 }else
@@ -28940,11 +30354,11 @@
30354 "VALUES(%Q,%Q);", zKey, zValue);
30355 shell_check_oom(zSql);
30356 rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
30357 sqlite3_free(zSql);
30358 if( rx!=SQLITE_OK ){
30359 sqlite3_fprintf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
30360 sqlite3_finalize(pStmt);
30361 pStmt = 0;
30362 rc = 1;
30363 }
30364 }
@@ -28969,14 +30383,14 @@
30383 }else
30384
30385 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
30386 int i;
30387 for(i=1; i<nArg; i++){
30388 if( i>1 ) sqlite3_fputs(" ", p->out);
30389 sqlite3_fputs(azArg[i], p->out);
30390 }
30391 sqlite3_fputs("\n", p->out);
30392 }else
30393
30394 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
30395 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){
30396 int i;
@@ -29009,11 +30423,11 @@
30423 }else{
30424 p->mxProgress = (int)integerValue(azArg[++i]);
30425 }
30426 continue;
30427 }
30428 sqlite3_fprintf(stderr,"Error: unknown option: \"%s\"\n", azArg[i]);
30429 rc = 1;
30430 goto meta_command_exit;
30431 }else{
30432 nn = (int)integerValue(z);
30433 }
@@ -29050,23 +30464,22 @@
30464 }
30465 if( azArg[1][0]=='|' ){
30466 #ifdef SQLITE_OMIT_POPEN
30467 eputz("Error: pipes are not supported in this OS\n");
30468 rc = 1;
 
30469 #else
30470 p->in = sqlite3_popen(azArg[1]+1, "r");
30471 if( p->in==0 ){
30472 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
30473 rc = 1;
30474 }else{
30475 rc = process_input(p);
30476 pclose(p->in);
30477 }
30478 #endif
30479 }else if( (p->in = openChrSource(azArg[1]))==0 ){
30480 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
30481 rc = 1;
30482 }else{
30483 rc = process_input(p);
30484 fclose(p->in);
30485 }
@@ -29095,11 +30508,11 @@
30508 rc = 1;
30509 goto meta_command_exit;
30510 }
30511 rc = sqlite3_open(zSrcFile, &pSrc);
30512 if( rc!=SQLITE_OK ){
30513 sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zSrcFile);
30514 close_db(pSrc);
30515 return 1;
30516 }
30517 open_db(p, 0);
30518 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
@@ -29127,11 +30540,14 @@
30540 }
30541 close_db(pSrc);
30542 }else
30543 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
30544
30545 if( c=='s' &&
30546 (cli_strncmp(azArg[0], "scanstats", n)==0 ||
30547 cli_strncmp(azArg[0], "scanstatus", n)==0)
30548 ){
30549 if( nArg==2 ){
30550 if( cli_strcmp(azArg[1], "vm")==0 ){
30551 p->scanstatsOn = 3;
30552 }else
30553 if( cli_strcmp(azArg[1], "est")==0 ){
@@ -29178,11 +30594,11 @@
30594 }else if( optionMatch(azArg[ii],"debug") ){
30595 bDebug = 1;
30596 }else if( optionMatch(azArg[ii],"nosys") ){
30597 bNoSystemTabs = 1;
30598 }else if( azArg[ii][0]=='-' ){
30599 sqlite3_fprintf(stderr,"Unknown option: \"%s\"\n", azArg[ii]);
30600 rc = 1;
30601 goto meta_command_exit;
30602 }else if( zName==0 ){
30603 zName = azArg[ii];
30604 }else{
@@ -29279,11 +30695,11 @@
30695 appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
30696 }
30697 appendText(&sSelect, "sql IS NOT NULL"
30698 " ORDER BY snum, rowid", 0);
30699 if( bDebug ){
30700 sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.z);
30701 }else{
30702 rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
30703 }
30704 freeText(&sSelect);
30705 }
@@ -29340,11 +30756,12 @@
30756 session_not_open:
30757 eputz("ERROR: No sessions are open\n");
30758 }else{
30759 rc = sqlite3session_attach(pSession->p, azCmd[1]);
30760 if( rc ){
30761 sqlite3_fprintf(stderr,
30762 "ERROR: sqlite3session_attach() returns %d\n",rc);
30763 rc = 0;
30764 }
30765 }
30766 }else
30767
@@ -29357,13 +30774,13 @@
30774 ){
30775 FILE *out = 0;
30776 failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
30777 if( nCmd!=2 ) goto session_syntax_error;
30778 if( pSession->p==0 ) goto session_not_open;
30779 out = sqlite3_fopen(azCmd[1], "wb");
30780 if( out==0 ){
30781 sqlite3_fprintf(stderr,"ERROR: cannot open \"%s\" for writing\n",
30782 azCmd[1]);
30783 }else{
30784 int szChng;
30785 void *pChng;
30786 if( azCmd[0][0]=='c' ){
@@ -29370,16 +30787,17 @@
30787 rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
30788 }else{
30789 rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
30790 }
30791 if( rc ){
30792 sqlite3_fprintf(stdout, "Error: error code %d\n", rc);
30793 rc = 0;
30794 }
30795 if( pChng
30796 && fwrite(pChng, szChng, 1, out)!=1 ){
30797 sqlite3_fprintf(stderr,
30798 "ERROR: Failed to write entire %d-byte output\n", szChng);
30799 }
30800 sqlite3_free(pChng);
30801 fclose(out);
30802 }
30803 }else
@@ -29402,11 +30820,12 @@
30820 int ii;
30821 if( nCmd>2 ) goto session_syntax_error;
30822 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
30823 if( pAuxDb->nSession ){
30824 ii = sqlite3session_enable(pSession->p, ii);
30825 sqlite3_fprintf(p->out,
30826 "session %s enable flag = %d\n", pSession->zName, ii);
30827 }
30828 }else
30829
30830 /* .session filter GLOB ....
30831 ** Set a list of GLOB patterns of table names to be excluded.
@@ -29437,11 +30856,12 @@
30856 int ii;
30857 if( nCmd>2 ) goto session_syntax_error;
30858 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
30859 if( pAuxDb->nSession ){
30860 ii = sqlite3session_indirect(pSession->p, ii);
30861 sqlite3_fprintf(p->out,
30862 "session %s indirect flag = %d\n", pSession->zName, ii);
30863 }
30864 }else
30865
30866 /* .session isempty
30867 ** Determine if the session is empty
@@ -29449,20 +30869,21 @@
30869 if( cli_strcmp(azCmd[0], "isempty")==0 ){
30870 int ii;
30871 if( nCmd!=1 ) goto session_syntax_error;
30872 if( pAuxDb->nSession ){
30873 ii = sqlite3session_isempty(pSession->p);
30874 sqlite3_fprintf(p->out,
30875 "session %s isempty flag = %d\n", pSession->zName, ii);
30876 }
30877 }else
30878
30879 /* .session list
30880 ** List all currently open sessions
30881 */
30882 if( cli_strcmp(azCmd[0],"list")==0 ){
30883 for(i=0; i<pAuxDb->nSession; i++){
30884 sqlite3_fprintf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
30885 }
30886 }else
30887
30888 /* .session open DB NAME
30889 ** Open a new session called NAME on the attached database DB.
@@ -29473,22 +30894,23 @@
30894 if( nCmd!=3 ) goto session_syntax_error;
30895 zName = azCmd[2];
30896 if( zName[0]==0 ) goto session_syntax_error;
30897 for(i=0; i<pAuxDb->nSession; i++){
30898 if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
30899 sqlite3_fprintf(stderr,"Session \"%s\" already exists\n", zName);
30900 goto meta_command_exit;
30901 }
30902 }
30903 if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
30904 sqlite3_fprintf(stderr,
30905 "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
30906 goto meta_command_exit;
30907 }
30908 pSession = &pAuxDb->aSession[pAuxDb->nSession];
30909 rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
30910 if( rc ){
30911 sqlite3_fprintf(stderr,"Cannot open session: error code=%d\n", rc);
30912 rc = 0;
30913 goto meta_command_exit;
30914 }
30915 pSession->nFilter = 0;
30916 sqlite3session_table_filter(pSession->p, session_filter, pSession);
@@ -29508,20 +30930,20 @@
30930 if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){
30931 if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){
30932 int i, v;
30933 for(i=1; i<nArg; i++){
30934 v = booleanValue(azArg[i]);
30935 sqlite3_fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
30936 }
30937 }
30938 if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
30939 int i; sqlite3_int64 v;
30940 for(i=1; i<nArg; i++){
30941 char zBuf[200];
30942 v = integerValue(azArg[i]);
30943 sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
30944 sqlite3_fputs(zBuf, p->out);
30945 }
30946 }
30947 }else
30948 #endif
30949
@@ -29544,12 +30966,13 @@
30966 }else
30967 if( cli_strcmp(z,"-v")==0 ){
30968 bVerbose++;
30969 }else
30970 {
30971 sqlite3_fprintf(stderr,
30972 "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
30973 sqlite3_fputs("Should be one of: --init -v\n", stderr);
30974 rc = 1;
30975 goto meta_command_exit;
30976 }
30977 }
30978 if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
@@ -29590,46 +31013,47 @@
31013 if( zOp==0 ) continue;
31014 if( zSql==0 ) continue;
31015 if( zAns==0 ) continue;
31016 k = 0;
31017 if( bVerbose>0 ){
31018 sqlite3_fprintf(stdout, "%d: %s %s\n", tno, zOp, zSql);
31019 }
31020 if( cli_strcmp(zOp,"memo")==0 ){
31021 sqlite3_fprintf(p->out, "%s\n", zSql);
31022 }else
31023 if( cli_strcmp(zOp,"run")==0 ){
31024 char *zErrMsg = 0;
31025 str.n = 0;
31026 str.z[0] = 0;
31027 rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
31028 nTest++;
31029 if( bVerbose ){
31030 sqlite3_fprintf(p->out, "Result: %s\n", str.z);
31031 }
31032 if( rc || zErrMsg ){
31033 nErr++;
31034 rc = 1;
31035 sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg);
31036 sqlite3_free(zErrMsg);
31037 }else if( cli_strcmp(zAns,str.z)!=0 ){
31038 nErr++;
31039 rc = 1;
31040 sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns);
31041 sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.z);
31042 }
31043 }
31044 else{
31045 sqlite3_fprintf(stderr,
31046 "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
31047 rc = 1;
31048 break;
31049 }
31050 } /* End loop over rows of content from SELFTEST */
31051 sqlite3_finalize(pStmt);
31052 } /* End loop over k */
31053 freeText(&str);
31054 sqlite3_fprintf(p->out, "%d errors out of %d tests\n", nErr, nTest);
31055 }else
31056
31057 if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
31058 if( nArg<2 || nArg>3 ){
31059 eputz("Usage: .separator COL ?ROW?\n");
@@ -29673,11 +31097,12 @@
31097 }else
31098 if( cli_strcmp(z,"debug")==0 ){
31099 bDebug = 1;
31100 }else
31101 {
31102 sqlite3_fprintf(stderr,
31103 "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
31104 showHelp(p->out, azArg[0]);
31105 rc = 1;
31106 goto meta_command_exit;
31107 }
31108 }else if( zLike ){
@@ -29751,11 +31176,11 @@
31176 }
31177 shell_check_oom(zSql);
31178 freeText(&sQuery);
31179 freeText(&sSql);
31180 if( bDebug ){
31181 sqlite3_fprintf(p->out, "%s\n", zSql);
31182 }else{
31183 shell_exec(p, zSql, 0);
31184 }
31185 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE)
31186 {
@@ -29781,11 +31206,11 @@
31206 "||group_concat('CAST(CAST('||cname||' AS BLOB) AS TEXT)<>'||cname\n"
31207 "|| ' AND typeof('||cname||')=''text'' ',\n"
31208 "' OR ') as query, tname from tabcols group by tname)"
31209 , zRevText);
31210 shell_check_oom(zRevText);
31211 if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zRevText);
31212 lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
31213 if( lrc!=SQLITE_OK ){
31214 /* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
31215 ** user does cruel and unnatural things like ".limit expr_depth 0". */
31216 rc = 1;
@@ -29794,19 +31219,20 @@
31219 lrc = SQLITE_ROW==sqlite3_step(pStmt);
31220 if( lrc ){
31221 const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
31222 sqlite3_stmt *pCheckStmt;
31223 lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
31224 if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zGenQuery);
31225 if( lrc!=SQLITE_OK ){
31226 rc = 1;
31227 }else{
31228 if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
31229 double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
31230 if( countIrreversible>0 ){
31231 int sz = (int)(countIrreversible + 0.5);
31232 sqlite3_fprintf(stderr,
31233 "Digest includes %d invalidly encoded text field%s.\n",
31234 sz, (sz>1)? "s": "");
31235 }
31236 }
31237 sqlite3_finalize(pCheckStmt);
31238 }
@@ -29836,15 +31262,15 @@
31262 zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
31263 for(i=2; i<nArg && zCmd!=0; i++){
31264 zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
31265 zCmd, azArg[i]);
31266 }
31267 /*consoleRestore();*/
31268 x = zCmd!=0 ? system(zCmd) : 1;
31269 /*consoleRenewSetup();*/
31270 sqlite3_free(zCmd);
31271 if( x ) sqlite3_fprintf(stderr,"System command returns %d\n", x);
31272 }else
31273 #endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
31274
31275 if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
31276 static const char *azBool[] = { "off", "on", "trigger", "full"};
@@ -29853,50 +31279,52 @@
31279 if( nArg!=1 ){
31280 eputz("Usage: .show\n");
31281 rc = 1;
31282 goto meta_command_exit;
31283 }
31284 sqlite3_fprintf(p->out, "%12.12s: %s\n","echo",
31285 azBool[ShellHasFlag(p, SHFLG_Echo)]);
31286 sqlite3_fprintf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
31287 sqlite3_fprintf(p->out, "%12.12s: %s\n","explain",
31288 p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
31289 sqlite3_fprintf(p->out, "%12.12s: %s\n","headers",
31290 azBool[p->showHeader!=0]);
31291 if( p->mode==MODE_Column
31292 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
31293 ){
31294 sqlite3_fprintf(p->out,
31295 "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
31296 modeDescr[p->mode], p->cmOpts.iWrap,
31297 p->cmOpts.bWordWrap ? "on" : "off",
31298 p->cmOpts.bQuote ? "" : "no");
31299 }else{
31300 sqlite3_fprintf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
31301 }
31302 sqlite3_fprintf(p->out, "%12.12s: ", "nullvalue");
31303 output_c_string(p->out, p->nullValue);
31304 sqlite3_fputs("\n", p->out);
31305 sqlite3_fprintf(p->out, "%12.12s: %s\n","output",
31306 strlen30(p->outfile) ? p->outfile : "stdout");
31307 sqlite3_fprintf(p->out, "%12.12s: ", "colseparator");
31308 output_c_string(p->out, p->colSeparator);
31309 sqlite3_fputs("\n", p->out);
31310 sqlite3_fprintf(p->out, "%12.12s: ", "rowseparator");
31311 output_c_string(p->out, p->rowSeparator);
31312 sqlite3_fputs("\n", p->out);
31313 switch( p->statsOn ){
31314 case 0: zOut = "off"; break;
31315 default: zOut = "on"; break;
31316 case 2: zOut = "stmt"; break;
31317 case 3: zOut = "vmstep"; break;
31318 }
31319 sqlite3_fprintf(p->out, "%12.12s: %s\n","stats", zOut);
31320 sqlite3_fprintf(p->out, "%12.12s: ", "width");
31321 for (i=0;i<p->nWidth;i++) {
31322 sqlite3_fprintf(p->out, "%d ", p->colWidth[i]);
31323 }
31324 sqlite3_fputs("\n", p->out);
31325 sqlite3_fprintf(p->out, "%12.12s: %s\n", "filename",
31326 p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
31327 }else
31328
31329 if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){
31330 if( nArg==2 ){
@@ -30010,13 +31438,14 @@
31438 if( nPrintCol<1 ) nPrintCol = 1;
31439 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
31440 for(i=0; i<nPrintRow; i++){
31441 for(j=i; j<nRow; j+=nPrintRow){
31442 char *zSp = j<nPrintRow ? "" : " ";
31443 sqlite3_fprintf(p->out,
31444 "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
31445 }
31446 sqlite3_fputs("\n", p->out);
31447 }
31448 }
31449
31450 for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
31451 sqlite3_free(azResult);
@@ -30024,11 +31453,11 @@
31453
31454 #ifndef SQLITE_SHELL_FIDDLE
31455 /* Begin redirecting output to the file "testcase-out.txt" */
31456 if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
31457 output_reset(p);
31458 p->out = output_file_open("testcase-out.txt");
31459 if( p->out==0 ){
31460 eputz("Error: cannot open 'testcase-out.txt'\n");
31461 }
31462 if( nArg>=2 ){
31463 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
@@ -30068,11 +31497,10 @@
31497 {"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" },
31498 {"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" },
31499 {"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
31500 {"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
31501 {"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
 
31502 };
31503 int testctrl = -1;
31504 int iCtrl = -1;
31505 int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
31506 int isOk = 0;
@@ -30088,14 +31516,14 @@
31516 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
31517 }
31518
31519 /* --help lists all test-controls */
31520 if( cli_strcmp(zCmd,"help")==0 ){
31521 sqlite3_fputs("Available test-controls:\n", p->out);
31522 for(i=0; i<ArraySize(aCtrl); i++){
31523 if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
31524 sqlite3_fprintf(p->out, " .testctrl %s %s\n",
31525 aCtrl[i].zCtrlName, aCtrl[i].zUsage);
31526 }
31527 rc = 1;
31528 goto meta_command_exit;
31529 }
@@ -30108,19 +31536,19 @@
31536 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
31537 if( testctrl<0 ){
31538 testctrl = aCtrl[i].ctrlCode;
31539 iCtrl = i;
31540 }else{
31541 sqlite3_fprintf(stderr,"Error: ambiguous test-control: \"%s\"\n"
31542 "Use \".testctrl --help\" for help\n", zCmd);
31543 rc = 1;
31544 goto meta_command_exit;
31545 }
31546 }
31547 }
31548 if( testctrl<0 ){
31549 sqlite3_fprintf(stderr,"Error: unknown test-control: %s\n"
31550 "Use \".testctrl --help\" for help\n", zCmd);
31551 }else{
31552 switch(testctrl){
31553
31554 /* Special processing for .testctrl opt MASK ...
@@ -30170,11 +31598,13 @@
31598 { 0x10000000, 1, "OrderBySubq" },
31599 { 0xffffffff, 0, "All" },
31600 };
31601 unsigned int curOpt;
31602 unsigned int newOpt;
31603 unsigned int m;
31604 int ii;
31605 int nOff;
31606 sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
31607 newOpt = curOpt;
31608 for(ii=2; ii<nArg; ii++){
31609 const char *z = azArg[ii];
31610 int useLabel = 0;
@@ -30192,16 +31622,17 @@
31622 int jj;
31623 for(jj=0; jj<ArraySize(aLabel); jj++){
31624 if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
31625 }
31626 if( jj>=ArraySize(aLabel) ){
31627 sqlite3_fprintf(stderr,
31628 "Error: no such optimization: \"%s\"\n", zLabel);
31629 sqlite3_fputs("Should be one of:", stderr);
31630 for(jj=0; jj<ArraySize(aLabel); jj++){
31631 sqlite3_fprintf(stderr," %s", aLabel[jj].zLabel);
31632 }
31633 sqlite3_fputs("\n", stderr);
31634 rc = 1;
31635 goto meta_command_exit;
31636 }
31637 if( useLabel=='+' ){
31638 newOpt &= ~aLabel[jj].mask;
@@ -30210,28 +31641,32 @@
31641 }
31642 }
31643 }
31644 if( curOpt!=newOpt ){
31645 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
31646 }
31647 for(ii=nOff=0, m=1; ii<32; ii++, m <<= 1){
31648 if( m & newOpt ) nOff++;
31649 }
31650 if( nOff<12 ){
31651 sqlite3_fputs("+All", p->out);
31652 for(ii=0; ii<ArraySize(aLabel); ii++){
31653 if( !aLabel[ii].bDsply ) continue;
31654 if( (newOpt & aLabel[ii].mask)!=0 ){
31655 sqlite3_fprintf(p->out, " -%s", aLabel[ii].zLabel);
31656 }
31657 }
31658 }else{
31659 sqlite3_fputs("-All", p->out);
31660 for(ii=0; ii<ArraySize(aLabel); ii++){
31661 if( !aLabel[ii].bDsply ) continue;
31662 if( (newOpt & aLabel[ii].mask)==0 ){
31663 sqlite3_fprintf(p->out, " +%s", aLabel[ii].zLabel);
 
 
31664 }
31665 }
31666 }
31667 sqlite3_fputs("\n", p->out);
31668 rc2 = isOk = 3;
31669 break;
31670 }
31671
31672 /* sqlite3_test_control(int, db, int) */
@@ -30267,11 +31702,11 @@
31702 if( nArg==3 || nArg==4 ){
31703 int ii = (int)integerValue(azArg[2]);
31704 sqlite3 *db;
31705 if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
31706 sqlite3_randomness(sizeof(ii),&ii);
31707 sqlite3_fprintf(stdout, "-- random seed: %d\n", ii);
31708 }
31709 if( nArg==3 ){
31710 db = 0;
31711 }else{
31712 db = p->db;
@@ -30301,25 +31736,10 @@
31736 rc2 = sqlite3_test_control(testctrl, opt);
31737 isOk = 3;
31738 }
31739 break;
31740
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31741 /* sqlite3_test_control(sqlite3*) */
31742 case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
31743 rc2 = sqlite3_test_control(testctrl, p->db);
31744 isOk = 3;
31745 break;
@@ -30335,11 +31755,11 @@
31755 break;
31756
31757 case SQLITE_TESTCTRL_SEEK_COUNT: {
31758 u64 x = 0;
31759 rc2 = sqlite3_test_control(testctrl, p->db, &x);
31760 sqlite3_fprintf(p->out, "%llu\n", x);
31761 isOk = 3;
31762 break;
31763 }
31764
31765 #ifdef YYCOVERAGE
@@ -30366,15 +31786,15 @@
31786 int id = 1;
31787 while(1){
31788 int val = 0;
31789 rc2 = sqlite3_test_control(testctrl, -id, &val);
31790 if( rc2!=SQLITE_OK ) break;
31791 if( id>1 ) sqlite3_fputs(" ", p->out);
31792 sqlite3_fprintf(p->out, "%d: %d", id, val);
31793 id++;
31794 }
31795 if( id>1 ) sqlite3_fputs("\n", p->out);
31796 isOk = 3;
31797 }
31798 break;
31799 }
31800 #endif
@@ -30412,18 +31832,26 @@
31832 }else if( cli_strcmp(z,"reset")==0 ){
31833 faultsim_state.iCnt = faultsim_state.nSkip;
31834 faultsim_state.nHit = 0;
31835 sqlite3_test_control(testctrl, faultsim_callback);
31836 }else if( cli_strcmp(z,"status")==0 ){
31837 sqlite3_fprintf(p->out, "faultsim.iId: %d\n",
31838 faultsim_state.iId);
31839 sqlite3_fprintf(p->out, "faultsim.iErr: %d\n",
31840 faultsim_state.iErr);
31841 sqlite3_fprintf(p->out, "faultsim.iCnt: %d\n",
31842 faultsim_state.iCnt);
31843 sqlite3_fprintf(p->out, "faultsim.nHit: %d\n",
31844 faultsim_state.nHit);
31845 sqlite3_fprintf(p->out, "faultsim.iInterval: %d\n",
31846 faultsim_state.iInterval);
31847 sqlite3_fprintf(p->out, "faultsim.eVerbose: %d\n",
31848 faultsim_state.eVerbose);
31849 sqlite3_fprintf(p->out, "faultsim.nRepeat: %d\n",
31850 faultsim_state.nRepeat);
31851 sqlite3_fprintf(p->out, "faultsim.nSkip: %d\n",
31852 faultsim_state.nSkip);
31853 }else if( cli_strcmp(z,"-v")==0 ){
31854 if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
31855 }else if( cli_strcmp(z,"-q")==0 ){
31856 if( faultsim_state.eVerbose>0 ) faultsim_state.eVerbose--;
31857 }else if( cli_strcmp(z,"-id")==0 && kk+1<nArg ){
@@ -30437,19 +31865,20 @@
31865 }else if( cli_strcmp(z,"-skip")==0 && kk+1<nArg ){
31866 faultsim_state.nSkip = atoi(azArg[++kk]);
31867 }else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
31868 bShowHelp = 1;
31869 }else{
31870 sqlite3_fprintf(stderr,
31871 "Unrecognized fault_install argument: \"%s\"\n",
31872 azArg[kk]);
31873 rc = 1;
31874 bShowHelp = 1;
31875 break;
31876 }
31877 }
31878 if( bShowHelp ){
31879 sqlite3_fputs(
31880 "Usage: .testctrl fault_install ARGS\n"
31881 "Possible arguments:\n"
31882 " off Disable faultsim\n"
31883 " on Activate faultsim\n"
31884 " reset Reset the trigger counter\n"
@@ -30459,23 +31888,25 @@
31888 " --errcode N When triggered, return N as error code\n"
31889 " --id ID Trigger only for the ID specified\n"
31890 " --interval N Trigger only after every N-th call\n"
31891 " --repeat N Turn off after N hits. 0 means never\n"
31892 " --skip N Skip the first N encounters\n"
31893 ,p->out
31894 );
31895 }
31896 break;
31897 }
31898 }
31899 }
31900 if( isOk==0 && iCtrl>=0 ){
31901 sqlite3_fprintf(p->out,
31902 "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
31903 rc = 1;
31904 }else if( isOk==1 ){
31905 sqlite3_fprintf(p->out, "%d\n", rc2);
31906 }else if( isOk==2 ){
31907 sqlite3_fprintf(p->out, "0x%08x\n", rc2);
31908 }
31909 }else
31910 #endif /* !defined(SQLITE_UNTESTABLE) */
31911
31912 if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){
@@ -30526,17 +31957,17 @@
31957 }
31958 else if( optionMatch(z, "close") ){
31959 mType |= SQLITE_TRACE_CLOSE;
31960 }
31961 else {
31962 sqlite3_fprintf(stderr,"Unknown option \"%s\" on \".trace\"\n", z);
31963 rc = 1;
31964 goto meta_command_exit;
31965 }
31966 }else{
31967 output_file_close(p->traceOut);
31968 p->traceOut = output_file_open(z);
31969 }
31970 }
31971 if( p->traceOut==0 ){
31972 sqlite3_trace_v2(p->db, 0, 0, 0);
31973 }else{
@@ -30569,103 +32000,40 @@
32000 }
32001 }
32002 }else
32003 #endif
32004
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32005 if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
32006 char *zPtrSz = sizeof(void*)==8 ? "64-bit" : "32-bit";
32007 sqlite3_fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
32008 sqlite3_libversion(), sqlite3_sourceid());
32009 #if SQLITE_HAVE_ZLIB
32010 sqlite3_fprintf(p->out, "zlib version %s\n", zlibVersion());
32011 #endif
32012 #define CTIMEOPT_VAL_(opt) #opt
32013 #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
32014 #if defined(__clang__) && defined(__clang_major__)
32015 sqlite3_fprintf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
32016 CTIMEOPT_VAL(__clang_minor__) "."
32017 CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz);
32018 #elif defined(_MSC_VER)
32019 sqlite3_fprintf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
32020 #elif defined(__GNUC__) && defined(__VERSION__)
32021 sqlite3_fprintf(p->out, "gcc-" __VERSION__ " (%s)\n", zPtrSz);
32022 #endif
32023 }else
32024
32025 if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){
32026 const char *zDbName = nArg==2 ? azArg[1] : "main";
32027 sqlite3_vfs *pVfs = 0;
32028 if( p->db ){
32029 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
32030 if( pVfs ){
32031 sqlite3_fprintf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
32032 sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
32033 sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
32034 sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
32035 }
32036 }
32037 }else
32038
32039 if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){
@@ -30673,17 +32041,17 @@
32041 sqlite3_vfs *pCurrent = 0;
32042 if( p->db ){
32043 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
32044 }
32045 for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
32046 sqlite3_fprintf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
32047 pVfs==pCurrent ? " <--- CURRENT" : "");
32048 sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
32049 sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
32050 sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
32051 if( pVfs->pNext ){
32052 sqlite3_fputs("-----------------------------------\n", p->out);
32053 }
32054 }
32055 }else
32056
32057 if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
@@ -30690,11 +32058,11 @@
32058 const char *zDbName = nArg==2 ? azArg[1] : "main";
32059 char *zVfsName = 0;
32060 if( p->db ){
32061 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
32062 if( zVfsName ){
32063 sqlite3_fprintf(p->out, "%s\n", zVfsName);
32064 sqlite3_free(zVfsName);
32065 }
32066 }
32067 }else
32068
@@ -30714,11 +32082,11 @@
32082 p->colWidth[j-1] = (int)integerValue(azArg[j]);
32083 }
32084 }else
32085
32086 {
32087 sqlite3_fprintf(stderr,"Error: unknown command or invalid arguments: "
32088 " \"%s\". Enter \".help\" for help\n", azArg[0]);
32089 rc = 1;
32090 }
32091
32092 meta_command_exit:
@@ -30755,11 +32123,10 @@
32123 SCAN_TRACKER_REFTYPE pst){
32124 char cin;
32125 char cWait = (char)qss; /* intentional narrowing loss */
32126 if( cWait==0 ){
32127 PlainScan:
 
32128 while( (cin = *zLine++)!=0 ){
32129 if( IsSpace(cin) )
32130 continue;
32131 switch (cin){
32132 case '-':
@@ -30807,11 +32174,10 @@
32174 switch( cWait ){
32175 case '*':
32176 if( *zLine != '/' )
32177 continue;
32178 ++zLine;
 
32179 CONTINUE_PROMPT_AWAITC(pst, 0);
32180 qss = QSS_SETV(qss, 0);
32181 goto PlainScan;
32182 case '`': case '\'': case '"':
32183 if(*zLine==cWait){
@@ -30819,11 +32185,10 @@
32185 ++zLine;
32186 continue;
32187 }
32188 deliberate_fall_through;
32189 case ']':
 
32190 CONTINUE_PROMPT_AWAITC(pst, 0);
32191 qss = QSS_SETV(qss, 0);
32192 goto PlainScan;
32193 default: assert(0);
32194 }
@@ -30966,11 +32331,11 @@
32331 open_db(p, 0);
32332 if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
32333 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
32334 BEGIN_TIMER;
32335 rc = shell_exec(p, zSql, &zErrMsg);
32336 END_TIMER(p->out);
32337 if( rc || zErrMsg ){
32338 char zPrefix[100];
32339 const char *zErrorTail;
32340 const char *zErrorType;
32341 if( zErrMsg==0 ){
@@ -30990,28 +32355,31 @@
32355 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
32356 "%s near line %d:", zErrorType, startline);
32357 }else{
32358 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
32359 }
32360 sqlite3_fprintf(stderr,"%s %s\n", zPrefix, zErrorTail);
32361 sqlite3_free(zErrMsg);
32362 zErrMsg = 0;
32363 return 1;
32364 }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
32365 char zLineBuf[2000];
32366 sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
32367 "changes: %lld total_changes: %lld",
32368 sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
32369 sqlite3_fprintf(p->out, "%s\n", zLineBuf);
32370 }
32371
32372 if( doAutoDetectRestore(p, zSql) ) return 1;
32373 return 0;
32374 }
32375
32376 static void echo_group_input(ShellState *p, const char *zDo){
32377 if( ShellHasFlag(p, SHFLG_Echo) ){
32378 sqlite3_fprintf(p->out, "%s\n", zDo);
32379 fflush(p->out);
32380 }
32381 }
32382
32383 #ifdef SQLITE_SHELL_FIDDLE
32384 /*
32385 ** Alternate one_input_line() impl for wasm mode. This is not in the primary
@@ -31065,11 +32433,11 @@
32433 i64 startline = 0; /* Line number for start of current input */
32434 QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
32435
32436 if( p->inputNesting==MAX_INPUT_NESTING ){
32437 /* This will be more informative in a later version. */
32438 sqlite3_fprintf(stderr,"Input nesting limit (%d) reached at line %d."
32439 " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
32440 return 1;
32441 }
32442 ++p->inputNesting;
32443 p->lineno = 0;
@@ -31077,11 +32445,11 @@
32445 while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
32446 fflush(p->out);
32447 zLine = one_input_line(p->in, zLine, nSql>0);
32448 if( zLine==0 ){
32449 /* End of input */
32450 if( p->in==0 && stdin_is_interactive ) sqlite3_fputs("\n", p->out);
32451 break;
32452 }
32453 if( seenInterrupt ){
32454 if( p->in!=0 ) break;
32455 seenInterrupt = 0;
@@ -31297,19 +32665,19 @@
32665 }
32666 zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
32667 shell_check_oom(zBuf);
32668 sqliterc = zBuf;
32669 }
32670 p->in = sqlite3_fopen(sqliterc,"rb");
32671 if( p->in ){
32672 if( stdin_is_interactive ){
32673 sqlite3_fprintf(stderr,"-- Loading resources from %s\n", sqliterc);
32674 }
32675 if( process_input(p) && bail_on_error ) exit(1);
32676 fclose(p->in);
32677 }else if( sqliterc_override!=0 ){
32678 sqlite3_fprintf(stderr,"cannot open: \"%s\"\n", sqliterc);
32679 if( bail_on_error ) exit(1);
32680 }
32681 p->in = inSaved;
32682 p->lineno = savedLineno;
32683 sqlite3_free(zBuf);
@@ -31374,23 +32742,21 @@
32742 " -table set output mode to 'table'\n"
32743 " -tabs set output mode to 'tabs'\n"
32744 " -unsafe-testing allow unsafe commands and modes for testing\n"
32745 " -version show SQLite version\n"
32746 " -vfs NAME use NAME as the default VFS\n"
 
32747 " -vfstrace enable tracing of all VFS calls\n"
 
32748 #ifdef SQLITE_HAVE_ZLIB
32749 " -zip open the file as a ZIP Archive\n"
32750 #endif
32751 ;
32752 static void usage(int showDetail){
32753 sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
32754 "FILENAME is the name of an SQLite database. A new database is created\n"
32755 "if the file does not previously exist. Defaults to :memory:.\n", Argv0);
32756 if( showDetail ){
32757 sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
32758 }else{
32759 eputz("Use the -help option for additional information\n");
32760 }
32761 exit(0);
32762 }
@@ -31411,10 +32777,13 @@
32777 */
32778 static void main_init(ShellState *data) {
32779 memset(data, 0, sizeof(*data));
32780 data->normalMode = data->cMode = data->mode = MODE_List;
32781 data->autoExplain = 1;
32782 #ifdef _WIN32
32783 data->crlfMode = 1;
32784 #endif
32785 data->pAuxDb = &data->aAuxDb[0];
32786 memcpy(data->colSeparator,SEP_Column, 2);
32787 memcpy(data->rowSeparator,SEP_Row, 2);
32788 data->showHeader = 0;
32789 data->shellFlgs = SHFLG_Lookaside;
@@ -31446,29 +32815,39 @@
32815 SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
32816 #endif
32817 }
32818 #else
32819 static void printBold(const char *zText){
32820 sqlite3_fprintf(stdout, "\033[1m%s\033[0m", zText);
32821 }
32822 #endif
32823
32824 /*
32825 ** Get the argument to an --option. Throw an error and die if no argument
32826 ** is available.
32827 */
32828 static char *cmdline_option_value(int argc, char **argv, int i){
32829 if( i==argc ){
32830 sqlite3_fprintf(stderr,
32831 "%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
32832 exit(1);
32833 }
32834 return argv[i];
32835 }
32836
32837 static void sayAbnormalExit(void){
32838 if( seenInterrupt ) eputz("Program interrupted.\n");
32839 }
32840
32841 /* Routine to output from vfstrace
32842 */
32843 static int vfstraceOut(const char *z, void *pArg){
32844 ShellState *p = (ShellState*)pArg;
32845 sqlite3_fputs(z, p->out);
32846 fflush(p->out);
32847 return 1;
32848 }
32849
32850 #ifndef SQLITE_SHELL_IS_UTF8
32851 # if (defined(_WIN32) || defined(WIN32)) \
32852 && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
32853 # define SQLITE_SHELL_IS_UTF8 (0)
@@ -31493,19 +32872,19 @@
32872 char *zErrMsg = 0;
32873 #ifdef SQLITE_SHELL_FIDDLE
32874 # define data shellState
32875 #else
32876 ShellState data;
 
32877 #endif
32878 const char *zInitFile = 0;
32879 int i;
32880 int rc = 0;
32881 int warnInmemoryDb = 0;
32882 int readStdin = 1;
32883 int nCmd = 0;
32884 int nOptsEnd = argc;
32885 int bEnableVfstrace = 0;
32886 char **azCmd = 0;
32887 const char *zVfs = 0; /* Value of -vfs command-line option */
32888 #if !SQLITE_SHELL_IS_UTF8
32889 char **argvToFree = 0;
32890 int argcToFree = 0;
@@ -31515,25 +32894,29 @@
32894 #ifdef SQLITE_SHELL_FIDDLE
32895 stdin_is_interactive = 0;
32896 stdout_is_console = 1;
32897 data.wasm.zDefaultDbName = "/fiddle.sqlite3";
32898 #else
32899 stdin_is_interactive = isatty(0);
32900 stdout_is_console = isatty(1);
 
 
32901 #endif
32902 atexit(sayAbnormalExit);
32903 #ifdef SQLITE_DEBUG
32904 mem_main_enter = sqlite3_memory_used();
32905 #endif
32906 #if !defined(_WIN32_WCE)
32907 if( getenv("SQLITE_DEBUG_BREAK") ){
32908 if( isatty(0) && isatty(2) ){
32909 char zLine[100];
32910 sqlite3_fprintf(stderr,
32911 "attach debugger to process %d and press ENTER to continue...",
32912 GETPID());
32913 if( sqlite3_fgets(zLine, sizeof(zLine), stdin)!=0
32914 && cli_strcmp(zLine,"stop")==0
32915 ){
32916 exit(1);
32917 }
32918 }else{
32919 #if defined(_WIN32) || defined(WIN32)
32920 #if SQLITE_OS_WINRT
32921 __debugbreak();
32922 #else
@@ -31554,11 +32937,12 @@
32937 }
32938 #endif
32939
32940 #if USE_SYSTEM_SQLITE+0!=1
32941 if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
32942 sqlite3_fprintf(stderr,
32943 "SQLite header and source version mismatch\n%s\n%s\n",
32944 sqlite3_sourceid(), SQLITE_SOURCE_ID);
32945 exit(1);
32946 }
32947 #endif
32948 main_init(&data);
@@ -31696,21 +33080,12 @@
33080 switch( n ){
33081 case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
33082 case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
33083 default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
33084 }
 
33085 }else if( cli_strcmp(z,"-vfstrace")==0 ){
33086 bEnableVfstrace = 1;
 
 
 
 
 
 
 
 
33087 #ifdef SQLITE_ENABLE_MULTIPLEX
33088 }else if( cli_strcmp(z,"-multiplex")==0 ){
33089 extern int sqlite3_multiplex_initialize(const char*,int);
33090 sqlite3_multiplex_initialize(0, 1);
33091 #endif
@@ -31762,11 +33137,11 @@
33137 }else if( cli_strcmp(z,"-safe")==0 ){
33138 /* no-op - catch this on the second pass */
33139 }
33140 }
33141 #ifndef SQLITE_SHELL_FIDDLE
33142 if( !bEnableVfstrace ) verify_uninitialized();
33143 #endif
33144
33145
33146 #ifdef SQLITE_SHELL_INIT_PROC
33147 {
@@ -31786,25 +33161,29 @@
33161 if( zVfs ){
33162 sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
33163 if( pVfs ){
33164 sqlite3_vfs_register(pVfs, 1);
33165 }else{
33166 sqlite3_fprintf(stderr,"no such VFS: \"%s\"\n", zVfs);
33167 exit(1);
33168 }
33169 }
33170
33171 if( data.pAuxDb->zDbFilename==0 ){
33172 #ifndef SQLITE_OMIT_MEMORYDB
33173 data.pAuxDb->zDbFilename = ":memory:";
33174 warnInmemoryDb = argc==1;
33175 #else
33176 sqlite3_fprintf(stderr,
33177 "%s: Error: no database filename specified\n", Argv0);
33178 return 1;
33179 #endif
33180 }
33181 data.out = stdout;
33182 if( bEnableVfstrace ){
33183 vfstrace_register("trace",0,vfstraceOut, &data, 1);
33184 }
33185 #ifndef SQLITE_SHELL_FIDDLE
33186 sqlite3_appendvfs_init(0,0,0);
33187 #endif
33188
33189 /* Go ahead and open the database file if it already exists. If the
@@ -31913,11 +33292,11 @@
33292 */
33293 ShellSetFlag(&data, SHFLG_Backslash);
33294 }else if( cli_strcmp(z,"-bail")==0 ){
33295 /* No-op. The bail_on_error flag should already be set. */
33296 }else if( cli_strcmp(z,"-version")==0 ){
33297 sqlite3_fprintf(stdout, "%s %s (%d-bit)\n",
33298 sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
33299 return 0;
33300 }else if( cli_strcmp(z,"-interactive")==0 ){
33301 /* Need to check for interactive override here to so that it can
33302 ** affect console setup (for Windows only) and testing thereof.
@@ -31951,14 +33330,12 @@
33330 }else if( cli_strcmp(z,"-sorterref")==0 ){
33331 i++;
33332 #endif
33333 }else if( cli_strcmp(z,"-vfs")==0 ){
33334 i++;
 
33335 }else if( cli_strcmp(z,"-vfstrace")==0 ){
33336 i++;
 
33337 #ifdef SQLITE_ENABLE_MULTIPLEX
33338 }else if( cli_strcmp(z,"-multiplex")==0 ){
33339 i++;
33340 #endif
33341 }else if( cli_strcmp(z,"-help")==0 ){
@@ -31978,18 +33355,18 @@
33355 rc = shell_exec(&data, z, &zErrMsg);
33356 if( zErrMsg!=0 ){
33357 shellEmitError(zErrMsg);
33358 if( bail_on_error ) return rc!=0 ? rc : 1;
33359 }else if( rc!=0 ){
33360 sqlite3_fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
33361 if( bail_on_error ) return rc;
33362 }
33363 }
33364 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
33365 }else if( cli_strncmp(z, "-A", 2)==0 ){
33366 if( nCmd>0 ){
33367 sqlite3_fprintf(stderr,"Error: cannot mix regular SQL or dot-commands"
33368 " with \"%s\"\n", z);
33369 return 1;
33370 }
33371 open_db(&data, OPEN_DB_ZIPFILE);
33372 if( z[2] ){
@@ -32004,11 +33381,11 @@
33381 }else if( cli_strcmp(z,"-safe")==0 ){
33382 data.bSafeMode = data.bSafeModePersist = 1;
33383 }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
33384 /* Acted upon in first pass. */
33385 }else{
33386 sqlite3_fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
33387 eputz("Use -help for a list of options.\n");
33388 return 1;
33389 }
33390 data.cMode = data.mode;
33391 }
@@ -32031,11 +33408,12 @@
33408 rc = shell_exec(&data, azCmd[i], &zErrMsg);
33409 if( zErrMsg || rc ){
33410 if( zErrMsg!=0 ){
33411 shellEmitError(zErrMsg);
33412 }else{
33413 sqlite3_fprintf(stderr,
33414 "Error: unable to process SQL: %s\n", azCmd[i]);
33415 }
33416 sqlite3_free(zErrMsg);
33417 if( rc==0 ) rc = 1;
33418 goto shell_main_exit;
33419 }
@@ -32046,18 +33424,14 @@
33424 */
33425 if( stdin_is_interactive ){
33426 char *zHome;
33427 char *zHistory;
33428 int nHistory;
33429 sqlite3_fprintf(stdout,
33430 "SQLite version %s %.19s\n" /*extra-version-info*/
 
 
 
 
33431 "Enter \".help\" for usage hints.\n",
33432 sqlite3_libversion(), sqlite3_sourceid());
33433 if( warnInmemoryDb ){
33434 sputz(stdout, "Connected to a ");
33435 printBold("transient in-memory database");
33436 sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
33437 " persistent database.\n");
@@ -32070,13 +33444,15 @@
33444 if( (zHistory = malloc(nHistory))!=0 ){
33445 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
33446 }
33447 }
33448 if( zHistory ){ shell_read_history(zHistory); }
33449 #if (HAVE_READLINE || HAVE_EDITLINE) && !defined(SQLITE_OMIT_READLINE_COMPLETION)
33450 rl_attempted_completion_function = readline_completion;
33451 #elif HAVE_LINENOISE==1
33452 linenoiseSetCompletionCallback(linenoise_completion);
33453 #elif HAVE_LINENOISE==2
33454 linenoiseSetCompletionCallback(linenoise_completion, NULL);
33455 #endif
33456 data.in = 0;
33457 rc = process_input(&data);
33458 if( zHistory ){
@@ -32122,13 +33498,16 @@
33498 free(data.colWidth);
33499 free(data.zNonce);
33500 /* Clear the global data structure so that valgrind will detect memory
33501 ** leaks */
33502 memset(&data, 0, sizeof(data));
33503 if( bEnableVfstrace ){
33504 vfstrace_unregister("trace");
33505 }
33506 #ifdef SQLITE_DEBUG
33507 if( sqlite3_memory_used()>mem_main_enter ){
33508 sqlite3_fprintf(stderr,"Memory leaked: %u bytes\n",
33509 (unsigned int)(sqlite3_memory_used()-mem_main_enter));
33510 }
33511 #endif
33512 #else /* SQLITE_SHELL_FIDDLE... */
33513 shell_main_exit:
@@ -32164,11 +33543,11 @@
33543 return pVfs;
33544 }
33545
33546 /* Only for emcc experimentation purposes. */
33547 sqlite3 * fiddle_db_arg(sqlite3 *arg){
33548 sqlite3_fprintf(stdout, "fiddle_db_arg(%p)\n", (const void*)arg);
33549 return arg;
33550 }
33551
33552 /*
33553 ** Intended to be called via a SharedWorker() while a separate
@@ -32201,11 +33580,11 @@
33580 while( sqlite3_txn_state(globalDb,0)>0 ){
33581 /*
33582 ** Resolve problem reported in
33583 ** https://sqlite.org/forum/forumpost/0b41a25d65
33584 */
33585 sqlite3_fputs("Rolling back in-progress transaction.\n", stdout);
33586 sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0);
33587 }
33588 rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
33589 if( 0==rc ) sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
33590 sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
33591
+2361 -1405
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -1,8 +1,8 @@
11
/******************************************************************************
22
** This file is an amalgamation of many separate C source files from SQLite
3
-** version 3.47.0. By combining all the individual C code files into this
3
+** version 3.48.0. By combining all the individual C code files into this
44
** single large file, the entire code can be compiled as a single translation
55
** unit. This allows many compilers to do optimizations that would not be
66
** possible if the files were compiled separately. Performance improvements
77
** of 5% or more are commonly seen when SQLite is compiled as a single
88
** translation unit.
@@ -16,12 +16,15 @@
1616
** if you want a wrapper to interface SQLite with your choice of programming
1717
** language. The code for the "sqlite3" command-line shell is also in a
1818
** separate file. This file contains only code for the core SQLite library.
1919
**
2020
** The content in this amalgamation comes from Fossil check-in
21
-** 7891a266c4425722ae8b9231397ef9e42e24.
21
+** e2bae4143afd07de1ae55a6d2606a3b541a5 with changes in files:
22
+**
23
+**
2224
*/
25
+#ifndef SQLITE_AMALGAMATION
2326
#define SQLITE_CORE 1
2427
#define SQLITE_AMALGAMATION 1
2528
#ifndef SQLITE_PRIVATE
2629
# define SQLITE_PRIVATE static
2730
#endif
@@ -460,13 +463,13 @@
460463
**
461464
** See also: [sqlite3_libversion()],
462465
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
463466
** [sqlite_version()] and [sqlite_source_id()].
464467
*/
465
-#define SQLITE_VERSION "3.47.0"
466
-#define SQLITE_VERSION_NUMBER 3047000
467
-#define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
468
+#define SQLITE_VERSION "3.48.0"
469
+#define SQLITE_VERSION_NUMBER 3048000
470
+#define SQLITE_SOURCE_ID "2024-12-09 20:46:36 e2bae4143afd07de1ae55a6d2606a3b541a5b94568aa41f6a96e5d1245471653"
468471
469472
/*
470473
** CAPI3REF: Run-Time Library Version Numbers
471474
** KEYWORDS: sqlite3_version sqlite3_sourceid
472475
**
@@ -966,10 +969,17 @@
966969
**
967970
** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
968971
** filesystem supports doing multiple write operations atomically when those
969972
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
970973
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
974
+**
975
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
976
+** from the database file in amounts that are not a multiple of the
977
+** page size and that do not begin at a page boundary. Without this
978
+** property, SQLite is careful to only do full-page reads and write
979
+** on aligned pages, with the one exception that it will do a sub-page
980
+** read of the first page to access the database header.
971981
*/
972982
#define SQLITE_IOCAP_ATOMIC 0x00000001
973983
#define SQLITE_IOCAP_ATOMIC512 0x00000002
974984
#define SQLITE_IOCAP_ATOMIC1K 0x00000004
975985
#define SQLITE_IOCAP_ATOMIC2K 0x00000008
@@ -982,10 +992,11 @@
982992
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
983993
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
984994
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
985995
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
986996
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
997
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
987998
988999
/*
9891000
** CAPI3REF: File Locking Levels
9901001
**
9911002
** SQLite uses one of these integer values as the second
@@ -1128,10 +1139,11 @@
11281139
** <li> [SQLITE_IOCAP_SEQUENTIAL]
11291140
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
11301141
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
11311142
** <li> [SQLITE_IOCAP_IMMUTABLE]
11321143
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
1144
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
11331145
** </ul>
11341146
**
11351147
** The SQLITE_IOCAP_ATOMIC property means that all writes of
11361148
** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
11371149
** mean that writes of blocks that are nnn bytes in size and
@@ -1405,10 +1417,15 @@
14051417
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
14061418
** opcode causes the xFileControl method to swap the file handle with the one
14071419
** pointed to by the pArg argument. This capability is used during testing
14081420
** and only needs to be supported when SQLITE_TEST is defined.
14091421
**
1422
+** <li>[[SQLITE_FCNTL_NULL_IO]]
1423
+** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
1424
+** or file handle for the [sqlite3_file] object such that it will no longer
1425
+** read or write to the database file.
1426
+**
14101427
** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
14111428
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
14121429
** be advantageous to block on the next WAL lock if the lock is not immediately
14131430
** available. The WAL subsystem issues this signal during rare
14141431
** circumstances in order to fix a problem with priority inversion.
@@ -1558,10 +1575,11 @@
15581575
#define SQLITE_FCNTL_RESERVE_BYTES 38
15591576
#define SQLITE_FCNTL_CKPT_START 39
15601577
#define SQLITE_FCNTL_EXTERNAL_READER 40
15611578
#define SQLITE_FCNTL_CKSM_FILE 41
15621579
#define SQLITE_FCNTL_RESET_CACHE 42
1580
+#define SQLITE_FCNTL_NULL_IO 43
15631581
15641582
/* deprecated names */
15651583
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
15661584
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
15671585
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2936,14 +2954,18 @@
29362954
**
29372955
** ^These functions return the number of rows modified, inserted or
29382956
** deleted by the most recently completed INSERT, UPDATE or DELETE
29392957
** statement on the database connection specified by the only parameter.
29402958
** The two functions are identical except for the type of the return value
2941
-** and that if the number of rows modified by the most recent INSERT, UPDATE
2959
+** and that if the number of rows modified by the most recent INSERT, UPDATE,
29422960
** or DELETE is greater than the maximum value supported by type "int", then
29432961
** the return value of sqlite3_changes() is undefined. ^Executing any other
29442962
** type of SQL statement does not modify the value returned by these functions.
2963
+** For the purposes of this interface, a CREATE TABLE AS SELECT statement
2964
+** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
2965
+** added to the new table by the CREATE TABLE AS SELECT statement are not
2966
+** counted.
29452967
**
29462968
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
29472969
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
29482970
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
29492971
**
@@ -4499,15 +4521,26 @@
44994521
**
45004522
** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
45014523
** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
45024524
** to return an error (error code SQLITE_ERROR) if the statement uses
45034525
** any virtual tables.
4526
+**
4527
+** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
4528
+** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
4529
+** errors from being sent to the error log defined by
4530
+** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
4531
+** compiles to see if some SQL syntax is well-formed, without generating
4532
+** messages on the global error log when it is not. If the test compile
4533
+** fails, the sqlite3_prepare_v3() call returns the same error indications
4534
+** with or without this flag; it just omits the call to [sqlite3_log()] that
4535
+** logs the error.
45044536
** </dl>
45054537
*/
45064538
#define SQLITE_PREPARE_PERSISTENT 0x01
45074539
#define SQLITE_PREPARE_NORMALIZE 0x02
45084540
#define SQLITE_PREPARE_NO_VTAB 0x04
4541
+#define SQLITE_PREPARE_DONT_LOG 0x10
45094542
45104543
/*
45114544
** CAPI3REF: Compiling An SQL Statement
45124545
** KEYWORDS: {SQL statement compiler}
45134546
** METHOD: sqlite3
@@ -4536,17 +4569,21 @@
45364569
** and sqlite3_prepare_v3()
45374570
** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
45384571
** and sqlite3_prepare16_v3() use UTF-16.
45394572
**
45404573
** ^If the nByte argument is negative, then zSql is read up to the
4541
-** first zero terminator. ^If nByte is positive, then it is the
4542
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
4574
+** first zero terminator. ^If nByte is positive, then it is the maximum
4575
+** number of bytes read from zSql. When nByte is positive, zSql is read
4576
+** up to the first zero terminator or until the nByte bytes have been read,
4577
+** whichever comes first. ^If nByte is zero, then no prepared
45434578
** statement is generated.
45444579
** If the caller knows that the supplied string is nul-terminated, then
45454580
** there is a small performance advantage to passing an nByte parameter that
45464581
** is the number of bytes in the input string <i>including</i>
45474582
** the nul-terminator.
4583
+** Note that nByte measure the length of the input in bytes, not
4584
+** characters, even for the UTF-16 interfaces.
45484585
**
45494586
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
45504587
** past the end of the first SQL statement in zSql. These routines only
45514588
** compile the first statement in zSql, so *pzTail is left pointing to
45524589
** what remains uncompiled.
@@ -5913,11 +5950,11 @@
59135950
** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
59145951
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
59155952
** This flag instructs SQLite to omit some corner-case optimizations that
59165953
** might disrupt the operation of the [sqlite3_value_subtype()] function,
59175954
** causing it to return zero rather than the correct subtype().
5918
-** SQL functions that invokes [sqlite3_value_subtype()] should have this
5955
+** All SQL functions that invoke [sqlite3_value_subtype()] should have this
59195956
** property. If the SQLITE_SUBTYPE property is omitted, then the return
59205957
** value from [sqlite3_value_subtype()] might sometimes be zero even though
59215958
** a non-zero subtype was specified by the function argument expression.
59225959
**
59235960
** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
@@ -8678,11 +8715,11 @@
86788715
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
86798716
#define SQLITE_TESTCTRL_SEEK_COUNT 30
86808717
#define SQLITE_TESTCTRL_TRACEFLAGS 31
86818718
#define SQLITE_TESTCTRL_TUNE 32
86828719
#define SQLITE_TESTCTRL_LOGEST 33
8683
-#define SQLITE_TESTCTRL_USELONGDOUBLE 34
8720
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
86848721
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
86858722
86868723
/*
86878724
** CAPI3REF: SQL Keyword Checking
86888725
**
@@ -9654,10 +9691,20 @@
96549691
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
96559692
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
96569693
** APIs are not strictly speaking threadsafe. If they are invoked at the
96579694
** same time as another thread is invoking sqlite3_backup_step() it is
96589695
** possible that they return invalid values.
9696
+**
9697
+** <b>Alternatives To Using The Backup API</b>
9698
+**
9699
+** Other techniques for safely creating a consistent backup of an SQLite
9700
+** database include:
9701
+**
9702
+** <ul>
9703
+** <li> The [VACUUM INTO] command.
9704
+** <li> The [sqlite3_rsync] utility program.
9705
+** </ul>
96599706
*/
96609707
SQLITE_API sqlite3_backup *sqlite3_backup_init(
96619708
sqlite3 *pDest, /* Destination database handle */
96629709
const char *zDestName, /* Destination database name */
96639710
sqlite3 *pSource, /* Source database handle */
@@ -10852,10 +10899,18 @@
1085210899
** schema S in database connection D. ^On success, the
1085310900
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
1085410901
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
1085510902
** If there is not already a read-transaction open on schema S when
1085610903
** this function is called, one is opened automatically.
10904
+**
10905
+** If a read-transaction is opened by this function, then it is guaranteed
10906
+** that the returned snapshot object may not be invalidated by a database
10907
+** writer or checkpointer until after the read-transaction is closed. This
10908
+** is not guaranteed if a read-transaction is already open when this
10909
+** function is called. In that case, any subsequent write or checkpoint
10910
+** operation on the database may invalidate the returned snapshot handle,
10911
+** even while the read-transaction remains open.
1085710912
**
1085810913
** The following must be true for this function to succeed. If any of
1085910914
** the following statements are false when sqlite3_snapshot_get() is
1086010915
** called, SQLITE_ERROR is returned. The final value of *P is undefined
1086110916
** in this case.
@@ -11172,11 +11227,11 @@
1117211227
#endif
1117311228
1117411229
#if 0
1117511230
} /* End of the 'extern "C"' block */
1117611231
#endif
11177
-#endif /* SQLITE3_H */
11232
+/* #endif for SQLITE3_H will be added by mksqlite3.tcl */
1117811233
1117911234
/******** Begin file sqlite3rtree.h *********/
1118011235
/*
1118111236
** 2010 August 30
1118211237
**
@@ -13423,17 +13478,32 @@
1342313478
** This is used to access token iToken of phrase hit iIdx within the
1342413479
** current row. If iIdx is less than zero or greater than or equal to the
1342513480
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
1342613481
** output variable (*ppToken) is set to point to a buffer containing the
1342713482
** matching document token, and (*pnToken) to the size of that buffer in
13428
-** bytes. This API is not available if the specified token matches a
13429
-** prefix query term. In that case both output variables are always set
13430
-** to 0.
13483
+** bytes.
1343113484
**
1343213485
** The output text is not a copy of the document text that was tokenized.
1343313486
** It is the output of the tokenizer module. For tokendata=1 tables, this
1343413487
** includes any embedded 0x00 and trailing data.
13488
+**
13489
+** This API may be slow in some cases if the token identified by parameters
13490
+** iIdx and iToken matched a prefix token in the query. In most cases, the
13491
+** first call to this API for each prefix token in the query is forced
13492
+** to scan the portion of the full-text index that matches the prefix
13493
+** token to collect the extra data required by this API. If the prefix
13494
+** token matches a large number of token instances in the document set,
13495
+** this may be a performance problem.
13496
+**
13497
+** If the user knows in advance that a query may use this API for a
13498
+** prefix token, FTS5 may be configured to collect all required data as part
13499
+** of the initial querying of the full-text index, avoiding the second scan
13500
+** entirely. This also causes prefix queries that do not use this API to
13501
+** run more slowly and use more memory. FTS5 may be configured in this way
13502
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
13503
+** option, or on a per-query basis using the
13504
+** [fts5_insttoken | fts5_insttoken()] user function.
1343513505
**
1343613506
** This API can be quite slow if used with an FTS5 table created with the
1343713507
** "detail=none" or "detail=column" option.
1343813508
**
1343913509
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -13521,11 +13591,10 @@
1352113591
** CUSTOM TOKENIZERS
1352213592
**
1352313593
** Applications may also register custom tokenizer types. A tokenizer
1352413594
** is registered by providing fts5 with a populated instance of the
1352513595
** following structure. All structure methods must be defined, setting
13526
-**
1352713596
** any member of the fts5_tokenizer struct to NULL leads to undefined
1352813597
** behaviour. The structure methods are expected to function as follows:
1352913598
**
1353013599
** xCreate:
1353113600
** This function is used to allocate and initialize a tokenizer instance.
@@ -13865,10 +13934,11 @@
1386513934
#endif
1386613935
1386713936
#endif /* _FTS5_H */
1386813937
1386913938
/******** End of fts5.h *********/
13939
+#endif /* SQLITE3_H */
1387013940
1387113941
/************** End of sqlite3.h *********************************************/
1387213942
/************** Continuing where we left off in sqliteInt.h ******************/
1387313943
1387413944
/*
@@ -13910,10 +13980,11 @@
1391013980
** to count the size: 2^31-1 or 2147483647.
1391113981
*/
1391213982
#ifndef SQLITE_MAX_LENGTH
1391313983
# define SQLITE_MAX_LENGTH 1000000000
1391413984
#endif
13985
+#define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */
1391513986
1391613987
/*
1391713988
** This is the maximum number of
1391813989
**
1391913990
** * Columns in a table
@@ -14809,10 +14880,11 @@
1480914880
#include <stdio.h>
1481014881
#include <stdlib.h>
1481114882
#include <string.h>
1481214883
#include <assert.h>
1481314884
#include <stddef.h>
14885
+#include <ctype.h>
1481414886
1481514887
/*
1481614888
** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
1481714889
** This allows better measurements of where memcpy() is used when running
1481814890
** cachegrind. But this macro version of memcpy() is very slow so it
@@ -14831,11 +14903,10 @@
1483114903
#ifdef SQLITE_OMIT_FLOATING_POINT
1483214904
# define double sqlite_int64
1483314905
# define float sqlite_int64
1483414906
# define fabs(X) ((X)<0?-(X):(X))
1483514907
# define sqlite3IsOverflow(X) 0
14836
-# define LONGDOUBLE_TYPE sqlite_int64
1483714908
# ifndef SQLITE_BIG_DBL
1483814909
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
1483914910
# endif
1484014911
# define SQLITE_OMIT_DATETIME_FUNCS 1
1484114912
# define SQLITE_OMIT_TRACE 1
@@ -15006,13 +15077,10 @@
1500615077
# define INT8_TYPE int8_t
1500715078
# else
1500815079
# define INT8_TYPE signed char
1500915080
# endif
1501015081
#endif
15011
-#ifndef LONGDOUBLE_TYPE
15012
-# define LONGDOUBLE_TYPE long double
15013
-#endif
1501415082
typedef sqlite_int64 i64; /* 8-byte signed integer */
1501515083
typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
1501615084
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
1501715085
typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
1501815086
typedef INT16_TYPE i16; /* 2-byte signed integer */
@@ -16391,10 +16459,13 @@
1639116459
struct KeyInfo*, /* First argument to compare function */
1639216460
BtCursor *pCursor /* Space to write cursor structure */
1639316461
);
1639416462
SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
1639516463
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
16464
+#ifdef SQLITE_DEBUG
16465
+SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(Btree*,BtCursor*);
16466
+#endif
1639616467
SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
1639716468
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
1639816469
#ifdef SQLITE_ENABLE_CURSOR_HINTS
1639916470
SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
1640016471
#endif
@@ -17004,11 +17075,11 @@
1700417075
1700517076
/*
1700617077
** Additional non-public SQLITE_PREPARE_* flags
1700717078
*/
1700817079
#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */
17009
-#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */
17080
+#define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */
1701017081
1701117082
/*
1701217083
** Prototypes for the VDBE interface. See comments on the implementation
1701317084
** for a description of what each of these routines does.
1701417085
*/
@@ -17719,51 +17790,15 @@
1771917790
struct FuncDefHash {
1772017791
FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
1772117792
};
1772217793
#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
1772317794
17724
-#if defined(SQLITE_USER_AUTHENTICATION)
17725
-# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \
17726
- See ext/userauth/user-auth.txt for details."
17727
-#endif
17728
-#ifdef SQLITE_USER_AUTHENTICATION
17729
-/*
17730
-** Information held in the "sqlite3" database connection object and used
17731
-** to manage user authentication.
17732
-*/
17733
-typedef struct sqlite3_userauth sqlite3_userauth;
17734
-struct sqlite3_userauth {
17735
- u8 authLevel; /* Current authentication level */
17736
- int nAuthPW; /* Size of the zAuthPW in bytes */
17737
- char *zAuthPW; /* Password used to authenticate */
17738
- char *zAuthUser; /* User name used to authenticate */
17739
-};
17740
-
17741
-/* Allowed values for sqlite3_userauth.authLevel */
17742
-#define UAUTH_Unknown 0 /* Authentication not yet checked */
17743
-#define UAUTH_Fail 1 /* User authentication failed */
17744
-#define UAUTH_User 2 /* Authenticated as a normal user */
17745
-#define UAUTH_Admin 3 /* Authenticated as an administrator */
17746
-
17747
-/* Functions used only by user authorization logic */
17748
-SQLITE_PRIVATE int sqlite3UserAuthTable(const char*);
17749
-SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);
17750
-SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*);
17751
-SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
17752
-
17753
-#endif /* SQLITE_USER_AUTHENTICATION */
17754
-
1775517795
/*
1775617796
** typedef for the authorization callback function.
1775717797
*/
17758
-#ifdef SQLITE_USER_AUTHENTICATION
17759
- typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
17760
- const char*, const char*);
17761
-#else
17762
- typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
17763
- const char*);
17764
-#endif
17798
+typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
17799
+ const char*);
1776517800
1776617801
#ifndef SQLITE_OMIT_DEPRECATED
1776717802
/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
1776817803
** in the style of sqlite3_trace()
1776917804
*/
@@ -17920,13 +17955,10 @@
1792017955
sqlite3 *pUnlockConnection; /* Connection to watch for unlock */
1792117956
void *pUnlockArg; /* Argument to xUnlockNotify */
1792217957
void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
1792317958
sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
1792417959
#endif
17925
-#ifdef SQLITE_USER_AUTHENTICATION
17926
- sqlite3_userauth auth; /* User authentication information */
17927
-#endif
1792817960
};
1792917961
1793017962
/*
1793117963
** A macro to discover the encoding of a database.
1793217964
*/
@@ -19221,11 +19253,11 @@
1922119253
#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
1922219254
#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
1922319255
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
1922419256
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
1922519257
#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
19226
- /* 0x80000000 // Available */
19258
+#define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */
1922719259
1922819260
/* The EP_Propagate mask is a set of properties that automatically propagate
1922919261
** upwards into parent nodes.
1923019262
*/
1923119263
#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
@@ -19777,11 +19809,11 @@
1977719809
**
1977819810
** SRT_Set The result must be a single column. Store each
1977919811
** row of result as the key in table pDest->iSDParm.
1978019812
** Apply the affinity pDest->affSdst before storing
1978119813
** results. if pDest->iSDParm2 is positive, then it is
19782
-** a regsiter holding a Bloom filter for the IN operator
19814
+** a register holding a Bloom filter for the IN operator
1978319815
** that should be populated in addition to the
1978419816
** pDest->iSDParm table. This SRT is used to
1978519817
** implement "IN (SELECT ...)".
1978619818
**
1978719819
** SRT_EphemTab Create an temporary table pDest->iSDParm and store
@@ -20376,11 +20408,10 @@
2037620408
u8 bFullMutex; /* True to enable full mutexing */
2037720409
u8 bOpenUri; /* True to interpret filenames as URIs */
2037820410
u8 bUseCis; /* Use covering indices for full-scans */
2037920411
u8 bSmallMalloc; /* Avoid large memory allocations if true */
2038020412
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
20381
- u8 bUseLongDouble; /* Make use of long double */
2038220413
#ifdef SQLITE_DEBUG
2038320414
u8 bJsonSelfcheck; /* Double-check JSON parsing */
2038420415
#endif
2038520416
int mxStrlen; /* Maximum string length */
2038620417
int neverCorrupt; /* Database is always well-formed */
@@ -20751,19 +20782,10 @@
2075120782
*/
2075220783
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
2075320784
# define SQLITE_ENABLE_FTS3 1
2075420785
#endif
2075520786
20756
-/*
20757
-** The ctype.h header is needed for non-ASCII systems. It is also
20758
-** needed by FTS3 when FTS3 is included in the amalgamation.
20759
-*/
20760
-#if !defined(SQLITE_ASCII) || \
20761
- (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION))
20762
-# include <ctype.h>
20763
-#endif
20764
-
2076520787
/*
2076620788
** The following macros mimic the standard library functions toupper(),
2076720789
** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The
2076820790
** sqlite versions only work for ASCII characters, regardless of locale.
2076920791
*/
@@ -21381,11 +21403,11 @@
2138121403
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
2138221404
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
2138321405
SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
2138421406
SQLITE_PRIVATE int sqlite3Atoi(const char*);
2138521407
#ifndef SQLITE_OMIT_UTF16
21386
-SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
21408
+SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nByte, int nChar);
2138721409
#endif
2138821410
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
2138921411
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
2139021412
SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*);
2139121413
SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
@@ -22839,13 +22861,10 @@
2283922861
"UNLINK_AFTER_CLOSE",
2284022862
#endif
2284122863
#ifdef SQLITE_UNTESTABLE
2284222864
"UNTESTABLE",
2284322865
#endif
22844
-#ifdef SQLITE_USER_AUTHENTICATION
22845
- "USER_AUTHENTICATION",
22846
-#endif
2284722866
#ifdef SQLITE_USE_ALLOCA
2284822867
"USE_ALLOCA",
2284922868
#endif
2285022869
#ifdef SQLITE_USE_FCNTL_TRACE
2285122870
"USE_FCNTL_TRACE",
@@ -23117,11 +23136,10 @@
2311723136
SQLITE_THREADSAFE==1, /* bFullMutex */
2311823137
SQLITE_USE_URI, /* bOpenUri */
2311923138
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
2312023139
0, /* bSmallMalloc */
2312123140
1, /* bExtraSchemaChecks */
23122
- sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
2312323141
#ifdef SQLITE_DEBUG
2312423142
0, /* bJsonSelfcheck */
2312523143
#endif
2312623144
0x7ffffffe, /* mxStrlen */
2312723145
0, /* neverCorrupt */
@@ -23837,13 +23855,15 @@
2383723855
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
2383823856
int iNewReg; /* Register for new.* values */
2383923857
int iBlobWrite; /* Value returned by preupdate_blobwrite() */
2384023858
i64 iKey1; /* First key value passed to hook */
2384123859
i64 iKey2; /* Second key value passed to hook */
23860
+ Mem oldipk; /* Memory cell holding "old" IPK value */
2384223861
Mem *aNew; /* Array of new.* values */
2384323862
Table *pTab; /* Schema object being updated */
2384423863
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
23864
+ sqlite3_value **apDflt; /* Array of default values, if required */
2384523865
};
2384623866
2384723867
/*
2384823868
** An instance of this object is used to pass an vector of values into
2384923869
** OP_VFilter, the xFilter method of a virtual table. The vector is the
@@ -29285,20 +29305,33 @@
2928529305
2928629306
#ifndef NDEBUG
2928729307
/*
2928829308
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
2928929309
** intended for use inside assert() statements.
29310
+**
29311
+** Because these routines raise false-positive alerts in TSAN, disable
29312
+** them (make them always return 1) when compiling with TSAN.
2929029313
*/
2929129314
SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
29315
+# if defined(__has_feature)
29316
+# if __has_feature(thread_sanitizer)
29317
+ p = 0;
29318
+# endif
29319
+# endif
2929229320
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
2929329321
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
2929429322
}
2929529323
SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
29324
+# if defined(__has_feature)
29325
+# if __has_feature(thread_sanitizer)
29326
+ p = 0;
29327
+# endif
29328
+# endif
2929629329
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
2929729330
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
2929829331
}
29299
-#endif
29332
+#endif /* NDEBUG */
2930029333
2930129334
#endif /* !defined(SQLITE_MUTEX_OMIT) */
2930229335
2930329336
/************** End of mutex.c ***********************************************/
2930429337
/************** Begin file mutex_noop.c **************************************/
@@ -32272,10 +32305,11 @@
3227232305
&& (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
3227332306
){
3227432307
pExpr = pExpr->pLeft;
3227532308
}
3227632309
if( pExpr==0 ) return;
32310
+ if( ExprHasProperty(pExpr, EP_FromDDL) ) return;
3227732311
db->errByteOffset = pExpr->w.iOfst;
3227832312
}
3227932313
3228032314
/*
3228132315
** Enlarge the memory allocation on a StrAccum object so that it is
@@ -33001,11 +33035,11 @@
3300133035
}
3300233036
if( pItem->fg.isCte ){
3300333037
sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
3300433038
}
3300533039
if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
33006
- sqlite3_str_appendf(&x, " ON");
33040
+ sqlite3_str_appendf(&x, " isOn");
3300733041
}
3300833042
if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
3300933043
if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
3301033044
if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
3301133045
if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
@@ -34085,10 +34119,14 @@
3408534119
**
3408634120
** This routines are given external linkage so that they will always be
3408734121
** accessible to the debugging, and to avoid warnings about unused
3408834122
** functions. But these routines only exist in debugging builds, so they
3408934123
** do not contaminate the interface.
34124
+**
34125
+** See Also:
34126
+**
34127
+** sqlite3ShowWhereTerm() in where.c
3409034128
*/
3409134129
SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
3409234130
SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
3409334131
SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
3409434132
SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
@@ -34687,11 +34725,11 @@
3468734725
*/
3468834726
#define READ_UTF8(zIn, zTerm, c) \
3468934727
c = *(zIn++); \
3469034728
if( c>=0xc0 ){ \
3469134729
c = sqlite3Utf8Trans1[c-0xc0]; \
34692
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
34730
+ while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
3469334731
c = (c<<6) + (0x3f & *(zIn++)); \
3469434732
} \
3469534733
if( c<0x80 \
3469634734
|| (c&0xFFFFF800)==0xD800 \
3469734735
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
@@ -35065,24 +35103,26 @@
3506535103
assert( m.z || db->mallocFailed );
3506635104
return m.z;
3506735105
}
3506835106
3506935107
/*
35070
-** zIn is a UTF-16 encoded unicode string at least nChar characters long.
35108
+** zIn is a UTF-16 encoded unicode string at least nByte bytes long.
3507135109
** Return the number of bytes in the first nChar unicode characters
35072
-** in pZ. nChar must be non-negative.
35110
+** in pZ. nChar must be non-negative. Surrogate pairs count as a single
35111
+** character.
3507335112
*/
35074
-SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
35113
+SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){
3507535114
int c;
3507635115
unsigned char const *z = zIn;
35116
+ unsigned char const *zEnd = &z[nByte-1];
3507735117
int n = 0;
3507835118
3507935119
if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
35080
- while( n<nChar ){
35120
+ while( n<nChar && ALWAYS(z<=zEnd) ){
3508135121
c = z[0];
3508235122
z += 2;
35083
- if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
35123
+ if( c>=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
3508435124
n++;
3508535125
}
3508635126
return (int)(z-(unsigned char const *)zIn)
3508735127
- (SQLITE_UTF16NATIVE==SQLITE_UTF16LE);
3508835128
}
@@ -35659,10 +35699,12 @@
3565935699
int esign = 1; /* sign of exponent */
3566035700
int e = 0; /* exponent */
3566135701
int eValid = 1; /* True exponent is either not used or is well-formed */
3566235702
int nDigit = 0; /* Number of digits processed */
3566335703
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
35704
+ u64 s2; /* round-tripped significand */
35705
+ double rr[2];
3566435706
3566535707
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
3566635708
*pResult = 0.0; /* Default return value, in case of an error */
3566735709
if( length==0 ) return 0;
3566835710
@@ -35761,81 +35803,65 @@
3576135803
3576235804
/* adjust exponent by d, and update sign */
3576335805
e = (e*esign) + d;
3576435806
3576535807
/* Try to adjust the exponent to make it smaller */
35766
- while( e>0 && s<(LARGEST_UINT64/10) ){
35808
+ while( e>0 && s<((LARGEST_UINT64-0x7ff)/10) ){
3576735809
s *= 10;
3576835810
e--;
3576935811
}
3577035812
while( e<0 && (s%10)==0 ){
3577135813
s /= 10;
3577235814
e++;
3577335815
}
3577435816
35775
- if( e==0 ){
35776
- *pResult = s;
35777
- }else if( sqlite3Config.bUseLongDouble ){
35778
- LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s;
35779
- if( e>0 ){
35780
- while( e>=100 ){ e-=100; r *= 1.0e+100L; }
35781
- while( e>=10 ){ e-=10; r *= 1.0e+10L; }
35782
- while( e>=1 ){ e-=1; r *= 1.0e+01L; }
35783
- }else{
35784
- while( e<=-100 ){ e+=100; r *= 1.0e-100L; }
35785
- while( e<=-10 ){ e+=10; r *= 1.0e-10L; }
35786
- while( e<=-1 ){ e+=1; r *= 1.0e-01L; }
35787
- }
35788
- assert( r>=0.0 );
35789
- if( r>+1.7976931348623157081452742373e+308L ){
35790
-#ifdef INFINITY
35791
- *pResult = +INFINITY;
35792
-#else
35793
- *pResult = 1.0e308*10.0;
35794
-#endif
35795
- }else{
35796
- *pResult = (double)r;
35797
- }
35798
- }else{
35799
- double rr[2];
35800
- u64 s2;
35801
- rr[0] = (double)s;
35802
- s2 = (u64)rr[0];
35803
-#if defined(_MSC_VER) && _MSC_VER<1700
35804
- if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
35805
-#endif
35817
+ rr[0] = (double)s;
35818
+ assert( sizeof(s2)==sizeof(rr[0]) );
35819
+#ifdef SQLITE_DEBUG
35820
+ rr[1] = 18446744073709549568.0;
35821
+ memcpy(&s2, &rr[1], sizeof(s2));
35822
+ assert( s2==0x43efffffffffffffLL );
35823
+#endif
35824
+ /* Largest double that can be safely converted to u64
35825
+ ** vvvvvvvvvvvvvvvvvvvvvv */
35826
+ if( rr[0]<=18446744073709549568.0 ){
35827
+ s2 = (u64)rr[0];
3580635828
rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
35807
- if( e>0 ){
35808
- while( e>=100 ){
35809
- e -= 100;
35810
- dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
35811
- }
35812
- while( e>=10 ){
35813
- e -= 10;
35814
- dekkerMul2(rr, 1.0e+10, 0.0);
35815
- }
35816
- while( e>=1 ){
35817
- e -= 1;
35818
- dekkerMul2(rr, 1.0e+01, 0.0);
35819
- }
35820
- }else{
35821
- while( e<=-100 ){
35822
- e += 100;
35823
- dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
35824
- }
35825
- while( e<=-10 ){
35826
- e += 10;
35827
- dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
35828
- }
35829
- while( e<=-1 ){
35830
- e += 1;
35831
- dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
35832
- }
35833
- }
35834
- *pResult = rr[0]+rr[1];
35835
- if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
35836
- }
35829
+ }else{
35830
+ rr[1] = 0.0;
35831
+ }
35832
+ assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */
35833
+
35834
+ if( e>0 ){
35835
+ while( e>=100 ){
35836
+ e -= 100;
35837
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
35838
+ }
35839
+ while( e>=10 ){
35840
+ e -= 10;
35841
+ dekkerMul2(rr, 1.0e+10, 0.0);
35842
+ }
35843
+ while( e>=1 ){
35844
+ e -= 1;
35845
+ dekkerMul2(rr, 1.0e+01, 0.0);
35846
+ }
35847
+ }else{
35848
+ while( e<=-100 ){
35849
+ e += 100;
35850
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
35851
+ }
35852
+ while( e<=-10 ){
35853
+ e += 10;
35854
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
35855
+ }
35856
+ while( e<=-1 ){
35857
+ e += 1;
35858
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
35859
+ }
35860
+ }
35861
+ *pResult = rr[0]+rr[1];
35862
+ if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
3583735863
if( sign<0 ) *pResult = -*pResult;
3583835864
assert( !sqlite3IsNaN(*pResult) );
3583935865
3584035866
atof_return:
3584135867
/* return true if number and no extra non-whitespace characters after */
@@ -36152,13 +36178,14 @@
3615236178
*/
3615336179
SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
3615436180
int i;
3615536181
u64 v;
3615636182
int e, exp = 0;
36183
+ double rr[2];
36184
+
3615736185
p->isSpecial = 0;
3615836186
p->z = p->zBuf;
36159
-
3616036187
assert( mxRound>0 );
3616136188
3616236189
/* Convert negative numbers to positive. Deal with Infinity, 0.0, and
3616336190
** NaN. */
3616436191
if( r<0.0 ){
@@ -36182,66 +36209,49 @@
3618236209
return;
3618336210
}
3618436211
3618536212
/* Multiply r by powers of ten until it lands somewhere in between
3618636213
** 1.0e+19 and 1.0e+17.
36187
- */
36188
- if( sqlite3Config.bUseLongDouble ){
36189
- LONGDOUBLE_TYPE rr = r;
36190
- if( rr>=1.0e+19 ){
36191
- while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
36192
- while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
36193
- while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
36194
- }else{
36195
- while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
36196
- while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
36197
- while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
36198
- }
36199
- v = (u64)rr;
36200
- }else{
36201
- /* If high-precision floating point is not available using "long double",
36202
- ** then use Dekker-style double-double computation to increase the
36203
- ** precision.
36204
- **
36205
- ** The error terms on constants like 1.0e+100 computed using the
36206
- ** decimal extension, for example as follows:
36207
- **
36208
- ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
36209
- */
36210
- double rr[2];
36211
- rr[0] = r;
36212
- rr[1] = 0.0;
36213
- if( rr[0]>9.223372036854774784e+18 ){
36214
- while( rr[0]>9.223372036854774784e+118 ){
36215
- exp += 100;
36216
- dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
36217
- }
36218
- while( rr[0]>9.223372036854774784e+28 ){
36219
- exp += 10;
36220
- dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
36221
- }
36222
- while( rr[0]>9.223372036854774784e+18 ){
36223
- exp += 1;
36224
- dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
36225
- }
36226
- }else{
36227
- while( rr[0]<9.223372036854774784e-83 ){
36228
- exp -= 100;
36229
- dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
36230
- }
36231
- while( rr[0]<9.223372036854774784e+07 ){
36232
- exp -= 10;
36233
- dekkerMul2(rr, 1.0e+10, 0.0);
36234
- }
36235
- while( rr[0]<9.22337203685477478e+17 ){
36236
- exp -= 1;
36237
- dekkerMul2(rr, 1.0e+01, 0.0);
36238
- }
36239
- }
36240
- v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
36241
- }
36242
-
36214
+ **
36215
+ ** Use Dekker-style double-double computation to increase the
36216
+ ** precision.
36217
+ **
36218
+ ** The error terms on constants like 1.0e+100 computed using the
36219
+ ** decimal extension, for example as follows:
36220
+ **
36221
+ ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
36222
+ */
36223
+ rr[0] = r;
36224
+ rr[1] = 0.0;
36225
+ if( rr[0]>9.223372036854774784e+18 ){
36226
+ while( rr[0]>9.223372036854774784e+118 ){
36227
+ exp += 100;
36228
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
36229
+ }
36230
+ while( rr[0]>9.223372036854774784e+28 ){
36231
+ exp += 10;
36232
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
36233
+ }
36234
+ while( rr[0]>9.223372036854774784e+18 ){
36235
+ exp += 1;
36236
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
36237
+ }
36238
+ }else{
36239
+ while( rr[0]<9.223372036854774784e-83 ){
36240
+ exp -= 100;
36241
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
36242
+ }
36243
+ while( rr[0]<9.223372036854774784e+07 ){
36244
+ exp -= 10;
36245
+ dekkerMul2(rr, 1.0e+10, 0.0);
36246
+ }
36247
+ while( rr[0]<9.22337203685477478e+17 ){
36248
+ exp -= 1;
36249
+ dekkerMul2(rr, 1.0e+01, 0.0);
36250
+ }
36251
+ }
36252
+ v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
3624336253
3624436254
/* Extract significant digits. */
3624536255
i = sizeof(p->zBuf)-1;
3624636256
assert( v>0 );
3624736257
while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
@@ -37008,108 +37018,10 @@
3700837018
i += pIn[i+1];
3700937019
}while( i<mx );
3701037020
return 0;
3701137021
}
3701237022
37013
-/*
37014
-** High-resolution hardware timer used for debugging and testing only.
37015
-*/
37016
-#if defined(VDBE_PROFILE) \
37017
- || defined(SQLITE_PERFORMANCE_TRACE) \
37018
- || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
37019
-/************** Include hwtime.h in the middle of util.c *********************/
37020
-/************** Begin file hwtime.h ******************************************/
37021
-/*
37022
-** 2008 May 27
37023
-**
37024
-** The author disclaims copyright to this source code. In place of
37025
-** a legal notice, here is a blessing:
37026
-**
37027
-** May you do good and not evil.
37028
-** May you find forgiveness for yourself and forgive others.
37029
-** May you share freely, never taking more than you give.
37030
-**
37031
-******************************************************************************
37032
-**
37033
-** This file contains inline asm code for retrieving "high-performance"
37034
-** counters for x86 and x86_64 class CPUs.
37035
-*/
37036
-#ifndef SQLITE_HWTIME_H
37037
-#define SQLITE_HWTIME_H
37038
-
37039
-/*
37040
-** The following routine only works on Pentium-class (or newer) processors.
37041
-** It uses the RDTSC opcode to read the cycle count value out of the
37042
-** processor and returns that value. This can be used for high-res
37043
-** profiling.
37044
-*/
37045
-#if !defined(__STRICT_ANSI__) && \
37046
- (defined(__GNUC__) || defined(_MSC_VER)) && \
37047
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
37048
-
37049
- #if defined(__GNUC__)
37050
-
37051
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
37052
- unsigned int lo, hi;
37053
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
37054
- return (sqlite_uint64)hi << 32 | lo;
37055
- }
37056
-
37057
- #elif defined(_MSC_VER)
37058
-
37059
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
37060
- __asm {
37061
- rdtsc
37062
- ret ; return value at EDX:EAX
37063
- }
37064
- }
37065
-
37066
- #endif
37067
-
37068
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
37069
-
37070
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
37071
- unsigned int lo, hi;
37072
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
37073
- return (sqlite_uint64)hi << 32 | lo;
37074
- }
37075
-
37076
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
37077
-
37078
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
37079
- unsigned long long retval;
37080
- unsigned long junk;
37081
- __asm__ __volatile__ ("\n\
37082
- 1: mftbu %1\n\
37083
- mftb %L0\n\
37084
- mftbu %0\n\
37085
- cmpw %0,%1\n\
37086
- bne 1b"
37087
- : "=r" (retval), "=r" (junk));
37088
- return retval;
37089
- }
37090
-
37091
-#else
37092
-
37093
- /*
37094
- ** asm() is needed for hardware timing support. Without asm(),
37095
- ** disable the sqlite3Hwtime() routine.
37096
- **
37097
- ** sqlite3Hwtime() is only used for some obscure debugging
37098
- ** and analysis configurations, not in any deliverable, so this
37099
- ** should not be a great loss.
37100
- */
37101
-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
37102
-
37103
-#endif
37104
-
37105
-#endif /* !defined(SQLITE_HWTIME_H) */
37106
-
37107
-/************** End of hwtime.h **********************************************/
37108
-/************** Continuing where we left off in util.c ***********************/
37109
-#endif
37110
-
3711137023
/************** End of util.c ************************************************/
3711237024
/************** Begin file hash.c ********************************************/
3711337025
/*
3711437026
** 2001 September 22
3711537027
**
@@ -38787,11 +38699,11 @@
3878738699
# define F_SETLKW 7
3878838700
# endif
3878938701
# endif
3879038702
#else /* !SQLITE_WASI */
3879138703
# ifndef HAVE_FCHMOD
38792
-# define HAVE_FCHMOD
38704
+# define HAVE_FCHMOD 1
3879338705
# endif
3879438706
#endif /* SQLITE_WASI */
3879538707
3879638708
#ifdef SQLITE_WASI
3879738709
# define osGetpid(X) (pid_t)1
@@ -41038,58 +40950,37 @@
4103840950
** file by this or any other process. If such a lock is held, set *pResOut
4103940951
** to a non-zero value otherwise *pResOut is set to zero. The return value
4104040952
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
4104140953
*/
4104240954
static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
41043
- int rc = SQLITE_OK;
41044
- int reserved = 0;
40955
+#ifdef SQLITE_DEBUG
4104540956
unixFile *pFile = (unixFile*)id;
40957
+#else
40958
+ UNUSED_PARAMETER(id);
40959
+#endif
4104640960
4104740961
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
4104840962
4104940963
assert( pFile );
41050
-
41051
- /* Check if a thread in this process holds such a lock */
41052
- if( pFile->eFileLock>SHARED_LOCK ){
41053
- reserved = 1;
41054
- }
41055
-
41056
- /* Otherwise see if some other process holds it. */
41057
- if( !reserved ){
41058
- /* attempt to get the lock */
41059
- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
41060
- if( !lrc ){
41061
- /* got the lock, unlock it */
41062
- lrc = robust_flock(pFile->h, LOCK_UN);
41063
- if ( lrc ) {
41064
- int tErrno = errno;
41065
- /* unlock failed with an error */
41066
- lrc = SQLITE_IOERR_UNLOCK;
41067
- storeLastErrno(pFile, tErrno);
41068
- rc = lrc;
41069
- }
41070
- } else {
41071
- int tErrno = errno;
41072
- reserved = 1;
41073
- /* someone else might have it reserved */
41074
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
41075
- if( IS_LOCK_ERROR(lrc) ){
41076
- storeLastErrno(pFile, tErrno);
41077
- rc = lrc;
41078
- }
41079
- }
41080
- }
41081
- OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
41082
-
41083
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
41084
- if( (rc & 0xff) == SQLITE_IOERR ){
41085
- rc = SQLITE_OK;
41086
- reserved=1;
41087
- }
41088
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
41089
- *pResOut = reserved;
41090
- return rc;
40964
+ assert( pFile->eFileLock<=SHARED_LOCK );
40965
+
40966
+ /* The flock VFS only ever takes exclusive locks (see function flockLock).
40967
+ ** Therefore, if this connection is holding any lock at all, no other
40968
+ ** connection may be holding a RESERVED lock. So set *pResOut to 0
40969
+ ** in this case.
40970
+ **
40971
+ ** Or, this connection may be holding no lock. In that case, set *pResOut to
40972
+ ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the
40973
+ ** db in order to roll the hot journal back. If there is another connection
40974
+ ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to
40975
+ ** the user. With other VFS, we try to avoid this, in order to allow a reader
40976
+ ** to proceed while a writer is preparing its transaction. But that won't
40977
+ ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is
40978
+ ** not a problem in this case. */
40979
+ *pResOut = 0;
40980
+
40981
+ return SQLITE_OK;
4109140982
}
4109240983
4109340984
/*
4109440985
** Lock the file with the lock specified by parameter eFileLock - one
4109540986
** of the following:
@@ -42582,10 +42473,15 @@
4258242473
int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
4258342474
return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
4258442475
}
4258542476
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
4258642477
42478
+ case SQLITE_FCNTL_NULL_IO: {
42479
+ osClose(pFile->h);
42480
+ pFile->h = -1;
42481
+ return SQLITE_OK;
42482
+ }
4258742483
case SQLITE_FCNTL_LOCKSTATE: {
4258842484
*(int*)pArg = pFile->eFileLock;
4258942485
return SQLITE_OK;
4259042486
}
4259142487
case SQLITE_FCNTL_LAST_ERRNO: {
@@ -42723,10 +42619,11 @@
4272342619
4272442620
/* Set the POWERSAFE_OVERWRITE flag if requested. */
4272542621
if( pFd->ctrlFlags & UNIXFILE_PSOW ){
4272642622
pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
4272742623
}
42624
+ pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ;
4272842625
4272942626
pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
4273042627
}
4273142628
}
4273242629
#else
@@ -42773,19 +42670,19 @@
4277342670
0;
4277442671
}else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
4277542672
pFile->sectorSize = fsInfo.f_bsize;
4277642673
pFile->deviceCharacteristics =
4277742674
/* full bitset of atomics from max sector size and smaller */
42778
- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
42675
+ (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
4277942676
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
4278042677
** so it is ordered */
4278142678
0;
4278242679
}else if( strstr(fsInfo.f_basetype, "dos") ){
4278342680
pFile->sectorSize = fsInfo.f_bsize;
4278442681
pFile->deviceCharacteristics =
4278542682
/* full bitset of atomics from max sector size and smaller */
42786
- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
42683
+ (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
4278742684
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
4278842685
** so it is ordered */
4278942686
0;
4279042687
}else{
4279142688
pFile->deviceCharacteristics =
@@ -50462,10 +50359,15 @@
5046250359
OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
5046350360
hOldFile, pFile->h));
5046450361
return SQLITE_OK;
5046550362
}
5046650363
#endif
50364
+ case SQLITE_FCNTL_NULL_IO: {
50365
+ (void)osCloseHandle(pFile->h);
50366
+ pFile->h = NULL;
50367
+ return SQLITE_OK;
50368
+ }
5046750369
case SQLITE_FCNTL_TEMPFILENAME: {
5046850370
char *zTFile = 0;
5046950371
int rc = winGetTempname(pFile->pVfs, &zTFile);
5047050372
if( rc==SQLITE_OK ){
5047150373
*(char**)pArg = zTFile;
@@ -50523,11 +50425,11 @@
5052350425
/*
5052450426
** Return a vector of device characteristics.
5052550427
*/
5052650428
static int winDeviceCharacteristics(sqlite3_file *id){
5052750429
winFile *p = (winFile*)id;
50528
- return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
50430
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ |
5052950431
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
5053050432
}
5053150433
5053250434
/*
5053350435
** Windows will only let you create file view mappings
@@ -51911,11 +51813,11 @@
5191151813
*/
5191251814
char *zTmpname = 0; /* For temporary filename, if necessary. */
5191351815
5191451816
int rc = SQLITE_OK; /* Function Return Code */
5191551817
#if !defined(NDEBUG) || SQLITE_OS_WINCE
51916
- int eType = flags&0xFFFFFF00; /* Type of file to open */
51818
+ int eType = flags&0x0FFF00; /* Type of file to open */
5191751819
#endif
5191851820
5191951821
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
5192051822
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
5192151823
int isCreate = (flags & SQLITE_OPEN_CREATE);
@@ -58131,24 +58033,32 @@
5813158033
#ifdef SQLITE_DIRECT_OVERFLOW_READ
5813258034
/*
5813358035
** Return true if page pgno can be read directly from the database file
5813458036
** by the b-tree layer. This is the case if:
5813558037
**
58136
-** * the database file is open,
58137
-** * there are no dirty pages in the cache, and
58138
-** * the desired page is not currently in the wal file.
58038
+** (1) the database file is open
58039
+** (2) the VFS for the database is able to do unaligned sub-page reads
58040
+** (3) there are no dirty pages in the cache, and
58041
+** (4) the desired page is not currently in the wal file.
5813958042
*/
5814058043
SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
58141
- if( pPager->fd->pMethods==0 ) return 0;
58142
- if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
58044
+ assert( pPager!=0 );
58045
+ assert( pPager->fd!=0 );
58046
+ if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */
58047
+ if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */
5814358048
#ifndef SQLITE_OMIT_WAL
5814458049
if( pPager->pWal ){
5814558050
u32 iRead = 0;
5814658051
(void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
58147
- return iRead==0;
58052
+ return iRead==0; /* Condition (4) */
5814858053
}
5814958054
#endif
58055
+ assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
58056
+ if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
58057
+ & SQLITE_IOCAP_SUBPAGE_READ)==0 ){
58058
+ return 0; /* Case (2) */
58059
+ }
5815058060
return 1;
5815158061
}
5815258062
#endif
5815358063
5815458064
#ifndef SQLITE_OMIT_WAL
@@ -65171,11 +65081,11 @@
6517165081
** 20: Salt-2, a different random integer changing with each ckpt
6517265082
** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
6517365083
** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
6517465084
**
6517565085
** Immediately following the wal-header are zero or more frames. Each
65176
-** frame consists of a 24-byte frame-header followed by a <page-size> bytes
65086
+** frame consists of a 24-byte frame-header followed by <page-size> bytes
6517765087
** of page data. The frame-header is six big-endian 32-bit unsigned
6517865088
** integer values, as follows:
6517965089
**
6518065090
** 0: Page number.
6518165091
** 4: For commit records, the size of the database image in pages
@@ -65668,10 +65578,11 @@
6566865578
int nSehTry; /* Number of nested SEH_TRY{} blocks */
6566965579
u8 lockError; /* True if a locking error has occurred */
6567065580
#endif
6567165581
#ifdef SQLITE_ENABLE_SNAPSHOT
6567265582
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
65583
+ int bGetSnapshot; /* Transaction opened for sqlite3_get_snapshot() */
6567365584
#endif
6567465585
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
6567565586
sqlite3 *db;
6567665587
#endif
6567765588
};
@@ -67560,11 +67471,11 @@
6756067471
return SQLITE_IOERR_IN_PAGE;
6756167472
}
6756267473
6756367474
/*
6756467475
** Assert that the Wal.lockMask mask, which indicates the locks held
67565
-** by the connenction, is consistent with the Wal.readLock, Wal.writeLock
67476
+** by the connection, is consistent with the Wal.readLock, Wal.writeLock
6756667477
** and Wal.ckptLock variables. To be used as:
6756767478
**
6756867479
** assert( walAssertLockmask(pWal) );
6756967480
*/
6757067481
static int walAssertLockmask(Wal *pWal){
@@ -68224,11 +68135,11 @@
6822468135
assert( pWal->apWiData[0]!=0 );
6822568136
pInfo = walCkptInfo(pWal);
6822668137
SEH_INJECT_FAULT;
6822768138
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
6822868139
#ifdef SQLITE_ENABLE_SNAPSHOT
68229
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
68140
+ && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0)
6823068141
#endif
6823168142
){
6823268143
/* The WAL has been completely backfilled (or it is empty).
6823368144
** and can be safely ignored.
6823468145
*/
@@ -69624,11 +69535,24 @@
6962469535
*/
6962569536
SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
6962669537
Wal *pWal,
6962769538
sqlite3_snapshot *pSnapshot
6962869539
){
69629
- pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
69540
+ if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){
69541
+ /* iVersion==0 means that this is a call to sqlite3_snapshot_get(). In
69542
+ ** this case set the bGetSnapshot flag so that if the call to
69543
+ ** sqlite3_snapshot_get() is about to read transaction on this wal
69544
+ ** file, it does not take read-lock 0 if the wal file has been completely
69545
+ ** checkpointed. Taking read-lock 0 would work, but then it would be
69546
+ ** possible for a subsequent writer to destroy the snapshot even while
69547
+ ** this connection is holding its read-transaction open. This is contrary
69548
+ ** to user expectations, so we avoid it by not taking read-lock 0. */
69549
+ pWal->bGetSnapshot = 1;
69550
+ }else{
69551
+ pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
69552
+ pWal->bGetSnapshot = 0;
69553
+ }
6963069554
}
6963169555
6963269556
/*
6963369557
** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
6963469558
** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
@@ -75504,10 +75428,29 @@
7550475428
** this routine.
7550575429
*/
7550675430
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){
7550775431
return ROUND8(sizeof(BtCursor));
7550875432
}
75433
+
75434
+#ifdef SQLITE_DEBUG
75435
+/*
75436
+** Return true if and only if the Btree object will be automatically
75437
+** closed with the BtCursor closes. This is used within assert() statements
75438
+** only.
75439
+*/
75440
+SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(
75441
+ Btree *pBtree, /* the btree object */
75442
+ BtCursor *pCur /* Corresponding cursor */
75443
+){
75444
+ BtShared *pBt = pBtree->pBt;
75445
+ if( (pBt->openFlags & BTREE_SINGLE)==0 ) return 0;
75446
+ if( pBt->pCursor!=pCur ) return 0;
75447
+ if( pCur->pNext!=0 ) return 0;
75448
+ if( pCur->pBtree!=pBtree ) return 0;
75449
+ return 1;
75450
+}
75451
+#endif
7550975452
7551075453
/*
7551175454
** Initialize memory that will be converted into a BtCursor object.
7551275455
**
7551375456
** The simple approach here would be to memset() the entire object
@@ -84538,11 +84481,12 @@
8453884481
if( apVal==0 ){
8453984482
rc = SQLITE_NOMEM_BKPT;
8454084483
goto value_from_function_out;
8454184484
}
8454284485
for(i=0; i<nVal; i++){
84543
- rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
84486
+ rc = sqlite3Stat4ValueFromExpr(pCtx->pParse, pList->a[i].pExpr, aff,
84487
+ &apVal[i]);
8454484488
if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
8454584489
}
8454684490
}
8454784491
8454884492
pVal = valueNew(db, pCtx);
@@ -89571,11 +89515,11 @@
8957189515
/* The following two functions are used only within testcase() to prove
8957289516
** test coverage. These functions do no exist for production builds.
8957389517
** We must use separate SQLITE_NOINLINE functions here, since otherwise
8957489518
** optimizer code movement causes gcov to become very confused.
8957589519
*/
89576
-#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
89520
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
8957789521
static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
8957889522
static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
8957989523
#endif
8958089524
8958189525
/*
@@ -89586,17 +89530,10 @@
8958689530
SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
8958789531
if( sqlite3IsNaN(r) ){
8958889532
/* SQLite considers NaN to be a NULL. And all integer values are greater
8958989533
** than NULL */
8959089534
return 1;
89591
- }
89592
- if( sqlite3Config.bUseLongDouble ){
89593
- LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
89594
- testcase( x<r );
89595
- testcase( x>r );
89596
- testcase( x==r );
89597
- return (x<r) ? -1 : (x>r);
8959889535
}else{
8959989536
i64 y;
8960089537
if( r<-9223372036854775808.0 ) return +1;
8960189538
if( r>=9223372036854775808.0 ) return -1;
8960289539
y = (i64)r;
@@ -90595,17 +90532,25 @@
9059590532
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
9059690533
db->pPreUpdate = 0;
9059790534
sqlite3DbFree(db, preupdate.aRecord);
9059890535
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
9059990536
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
90537
+ sqlite3VdbeMemRelease(&preupdate.oldipk);
9060090538
if( preupdate.aNew ){
9060190539
int i;
9060290540
for(i=0; i<pCsr->nField; i++){
9060390541
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
9060490542
}
9060590543
sqlite3DbNNFreeNN(db, preupdate.aNew);
9060690544
}
90545
+ if( preupdate.apDflt ){
90546
+ int i;
90547
+ for(i=0; i<pTab->nCol; i++){
90548
+ sqlite3ValueFree(preupdate.apDflt[i]);
90549
+ }
90550
+ sqlite3DbFree(db, preupdate.apDflt);
90551
+ }
9060790552
}
9060890553
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
9060990554
9061090555
/************** End of vdbeaux.c *********************************************/
9061190556
/************** Begin file vdbeapi.c *****************************************/
@@ -92230,10 +92175,21 @@
9223092175
** A successful evaluation of this routine acquires the mutex on p.
9223192176
** the mutex is released if any kind of error occurs.
9223292177
**
9223392178
** The error code stored in database p->db is overwritten with the return
9223492179
** value in any case.
92180
+**
92181
+** (tag-20240917-01) If vdbeUnbind(p,(u32)(i-1)) returns SQLITE_OK,
92182
+** that means all of the the following will be true:
92183
+**
92184
+** p!=0
92185
+** p->pVar!=0
92186
+** i>0
92187
+** i<=p->nVar
92188
+**
92189
+** An assert() is normally added after vdbeUnbind() to help static analyzers
92190
+** realize this.
9223592191
*/
9223692192
static int vdbeUnbind(Vdbe *p, unsigned int i){
9223792193
Mem *pVar;
9223892194
if( vdbeSafetyNotNull(p) ){
9223992195
return SQLITE_MISUSE_BKPT;
@@ -92287,10 +92243,11 @@
9228792243
Mem *pVar;
9228892244
int rc;
9228992245
9229092246
rc = vdbeUnbind(p, (u32)(i-1));
9229192247
if( rc==SQLITE_OK ){
92248
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
9229292249
if( zData!=0 ){
9229392250
pVar = &p->aVar[i-1];
9229492251
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
9229592252
if( rc==SQLITE_OK && encoding!=0 ){
9229692253
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
@@ -92336,10 +92293,11 @@
9233692293
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
9233792294
int rc;
9233892295
Vdbe *p = (Vdbe *)pStmt;
9233992296
rc = vdbeUnbind(p, (u32)(i-1));
9234092297
if( rc==SQLITE_OK ){
92298
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
9234192299
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
9234292300
sqlite3_mutex_leave(p->db->mutex);
9234392301
}
9234492302
return rc;
9234592303
}
@@ -92349,10 +92307,11 @@
9234992307
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
9235092308
int rc;
9235192309
Vdbe *p = (Vdbe *)pStmt;
9235292310
rc = vdbeUnbind(p, (u32)(i-1));
9235392311
if( rc==SQLITE_OK ){
92312
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
9235492313
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
9235592314
sqlite3_mutex_leave(p->db->mutex);
9235692315
}
9235792316
return rc;
9235892317
}
@@ -92359,10 +92318,11 @@
9235992318
SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
9236092319
int rc;
9236192320
Vdbe *p = (Vdbe*)pStmt;
9236292321
rc = vdbeUnbind(p, (u32)(i-1));
9236392322
if( rc==SQLITE_OK ){
92323
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
9236492324
sqlite3_mutex_leave(p->db->mutex);
9236592325
}
9236692326
return rc;
9236792327
}
9236892328
SQLITE_API int sqlite3_bind_pointer(
@@ -92374,10 +92334,11 @@
9237492334
){
9237592335
int rc;
9237692336
Vdbe *p = (Vdbe*)pStmt;
9237792337
rc = vdbeUnbind(p, (u32)(i-1));
9237892338
if( rc==SQLITE_OK ){
92339
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
9237992340
sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
9238092341
sqlite3_mutex_leave(p->db->mutex);
9238192342
}else if( xDestructor ){
9238292343
xDestructor(pPtr);
9238392344
}
@@ -92455,10 +92416,11 @@
9245592416
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
9245692417
int rc;
9245792418
Vdbe *p = (Vdbe *)pStmt;
9245892419
rc = vdbeUnbind(p, (u32)(i-1));
9245992420
if( rc==SQLITE_OK ){
92421
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
9246092422
#ifndef SQLITE_OMIT_INCRBLOB
9246192423
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
9246292424
#else
9246392425
rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
9246492426
#endif
@@ -92789,41 +92751,68 @@
9278992751
if( iIdx>=p->pCsr->nField || iIdx<0 ){
9279092752
rc = SQLITE_RANGE;
9279192753
goto preupdate_old_out;
9279292754
}
9279392755
92794
- /* If the old.* record has not yet been loaded into memory, do so now. */
92795
- if( p->pUnpacked==0 ){
92796
- u32 nRec;
92797
- u8 *aRec;
92798
-
92799
- assert( p->pCsr->eCurType==CURTYPE_BTREE );
92800
- nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
92801
- aRec = sqlite3DbMallocRaw(db, nRec);
92802
- if( !aRec ) goto preupdate_old_out;
92803
- rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
92804
- if( rc==SQLITE_OK ){
92805
- p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
92806
- if( !p->pUnpacked ) rc = SQLITE_NOMEM;
92807
- }
92808
- if( rc!=SQLITE_OK ){
92809
- sqlite3DbFree(db, aRec);
92810
- goto preupdate_old_out;
92811
- }
92812
- p->aRecord = aRec;
92813
- }
92814
-
92815
- pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
9281692756
if( iIdx==p->pTab->iPKey ){
92757
+ *ppValue = pMem = &p->oldipk;
9281792758
sqlite3VdbeMemSetInt64(pMem, p->iKey1);
92818
- }else if( iIdx>=p->pUnpacked->nField ){
92819
- *ppValue = (sqlite3_value *)columnNullValue();
92820
- }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
92821
- if( pMem->flags & (MEM_Int|MEM_IntReal) ){
92822
- testcase( pMem->flags & MEM_Int );
92823
- testcase( pMem->flags & MEM_IntReal );
92824
- sqlite3VdbeMemRealify(pMem);
92759
+ }else{
92760
+
92761
+ /* If the old.* record has not yet been loaded into memory, do so now. */
92762
+ if( p->pUnpacked==0 ){
92763
+ u32 nRec;
92764
+ u8 *aRec;
92765
+
92766
+ assert( p->pCsr->eCurType==CURTYPE_BTREE );
92767
+ nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
92768
+ aRec = sqlite3DbMallocRaw(db, nRec);
92769
+ if( !aRec ) goto preupdate_old_out;
92770
+ rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
92771
+ if( rc==SQLITE_OK ){
92772
+ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
92773
+ if( !p->pUnpacked ) rc = SQLITE_NOMEM;
92774
+ }
92775
+ if( rc!=SQLITE_OK ){
92776
+ sqlite3DbFree(db, aRec);
92777
+ goto preupdate_old_out;
92778
+ }
92779
+ p->aRecord = aRec;
92780
+ }
92781
+
92782
+ pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
92783
+ if( iIdx>=p->pUnpacked->nField ){
92784
+ /* This occurs when the table has been extended using ALTER TABLE
92785
+ ** ADD COLUMN. The value to return is the default value of the column. */
92786
+ Column *pCol = &p->pTab->aCol[iIdx];
92787
+ if( pCol->iDflt>0 ){
92788
+ if( p->apDflt==0 ){
92789
+ int nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
92790
+ p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
92791
+ if( p->apDflt==0 ) goto preupdate_old_out;
92792
+ }
92793
+ if( p->apDflt[iIdx]==0 ){
92794
+ sqlite3_value *pVal = 0;
92795
+ Expr *pDflt;
92796
+ assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) );
92797
+ pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
92798
+ rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
92799
+ if( rc==SQLITE_OK && pVal==0 ){
92800
+ rc = SQLITE_CORRUPT_BKPT;
92801
+ }
92802
+ p->apDflt[iIdx] = pVal;
92803
+ }
92804
+ *ppValue = p->apDflt[iIdx];
92805
+ }else{
92806
+ *ppValue = (sqlite3_value *)columnNullValue();
92807
+ }
92808
+ }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
92809
+ if( pMem->flags & (MEM_Int|MEM_IntReal) ){
92810
+ testcase( pMem->flags & MEM_Int );
92811
+ testcase( pMem->flags & MEM_IntReal );
92812
+ sqlite3VdbeMemRealify(pMem);
92813
+ }
9282592814
}
9282692815
}
9282792816
9282892817
preupdate_old_out:
9282992818
sqlite3Error(db, rc);
@@ -93367,10 +93356,108 @@
9336793356
** commenting and indentation practices when changing or adding code.
9336893357
*/
9336993358
/* #include "sqliteInt.h" */
9337093359
/* #include "vdbeInt.h" */
9337193360
93361
+/*
93362
+** High-resolution hardware timer used for debugging and testing only.
93363
+*/
93364
+#if defined(VDBE_PROFILE) \
93365
+ || defined(SQLITE_PERFORMANCE_TRACE) \
93366
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
93367
+/************** Include hwtime.h in the middle of vdbe.c *********************/
93368
+/************** Begin file hwtime.h ******************************************/
93369
+/*
93370
+** 2008 May 27
93371
+**
93372
+** The author disclaims copyright to this source code. In place of
93373
+** a legal notice, here is a blessing:
93374
+**
93375
+** May you do good and not evil.
93376
+** May you find forgiveness for yourself and forgive others.
93377
+** May you share freely, never taking more than you give.
93378
+**
93379
+******************************************************************************
93380
+**
93381
+** This file contains inline asm code for retrieving "high-performance"
93382
+** counters for x86 and x86_64 class CPUs.
93383
+*/
93384
+#ifndef SQLITE_HWTIME_H
93385
+#define SQLITE_HWTIME_H
93386
+
93387
+/*
93388
+** The following routine only works on Pentium-class (or newer) processors.
93389
+** It uses the RDTSC opcode to read the cycle count value out of the
93390
+** processor and returns that value. This can be used for high-res
93391
+** profiling.
93392
+*/
93393
+#if !defined(__STRICT_ANSI__) && \
93394
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
93395
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
93396
+
93397
+ #if defined(__GNUC__)
93398
+
93399
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
93400
+ unsigned int lo, hi;
93401
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
93402
+ return (sqlite_uint64)hi << 32 | lo;
93403
+ }
93404
+
93405
+ #elif defined(_MSC_VER)
93406
+
93407
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
93408
+ __asm {
93409
+ rdtsc
93410
+ ret ; return value at EDX:EAX
93411
+ }
93412
+ }
93413
+
93414
+ #endif
93415
+
93416
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
93417
+
93418
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
93419
+ unsigned int lo, hi;
93420
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
93421
+ return (sqlite_uint64)hi << 32 | lo;
93422
+ }
93423
+
93424
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
93425
+
93426
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
93427
+ unsigned long long retval;
93428
+ unsigned long junk;
93429
+ __asm__ __volatile__ ("\n\
93430
+ 1: mftbu %1\n\
93431
+ mftb %L0\n\
93432
+ mftbu %0\n\
93433
+ cmpw %0,%1\n\
93434
+ bne 1b"
93435
+ : "=r" (retval), "=r" (junk));
93436
+ return retval;
93437
+ }
93438
+
93439
+#else
93440
+
93441
+ /*
93442
+ ** asm() is needed for hardware timing support. Without asm(),
93443
+ ** disable the sqlite3Hwtime() routine.
93444
+ **
93445
+ ** sqlite3Hwtime() is only used for some obscure debugging
93446
+ ** and analysis configurations, not in any deliverable, so this
93447
+ ** should not be a great loss.
93448
+ */
93449
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
93450
+
93451
+#endif
93452
+
93453
+#endif /* !defined(SQLITE_HWTIME_H) */
93454
+
93455
+/************** End of hwtime.h **********************************************/
93456
+/************** Continuing where we left off in vdbe.c ***********************/
93457
+#endif
93458
+
9337293459
/*
9337393460
** Invoke this macro on memory cells just prior to changing the
9337493461
** value of the cell. This macro verifies that shallow copies are
9337593462
** not misused. A shallow copy of a string or blob just copies a
9337693463
** pointer to the string or blob, not the content. If the original
@@ -97875,12 +97962,17 @@
9787597962
0, pCx->uc.pCursor);
9787697963
pCx->isTable = 1;
9787797964
}
9787897965
}
9787997966
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
97967
+ assert( p->apCsr[pOp->p1]==pCx );
9788097968
if( rc ){
97969
+ assert( !sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
9788197970
sqlite3BtreeClose(pCx->ub.pBtx);
97971
+ p->apCsr[pOp->p1] = 0; /* Not required; helps with static analysis */
97972
+ }else{
97973
+ assert( sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
9788297974
}
9788397975
}
9788497976
}
9788597977
if( rc ) goto abort_due_to_error;
9788697978
pCx->nullRow = 1;
@@ -102394,11 +102486,11 @@
102394102486
** element.
102395102487
**
102396102488
** As with all opcodes, the meanings of the parameters for OP_Explain
102397102489
** are subject to change from one release to the next. Applications
102398102490
** should not attempt to interpret or use any of the information
102399
-** contined in the OP_Explain opcode. The information provided by this
102491
+** contained in the OP_Explain opcode. The information provided by this
102400102492
** opcode is intended for testing and debugging use only.
102401102493
*/
102402102494
default: { /* This is really OP_Noop, OP_Explain */
102403102495
assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
102404102496
@@ -107490,11 +107582,11 @@
107490107582
** non-VIEW candidate plus multiple VIEW candidates. In other
107491107583
** words non-VIEW candidate terms take precedence over VIEWs.
107492107584
*/
107493107585
if( cntTab==0
107494107586
|| (cntTab==1
107495
- && ALWAYS(pMatch!=0)
107587
+ && pMatch!=0
107496107588
&& ALWAYS(pMatch->pSTab!=0)
107497107589
&& (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
107498107590
&& (pTab->tabFlags & TF_Ephemeral)==0)
107499107591
){
107500107592
cntTab = 1;
@@ -108123,12 +108215,12 @@
108123108215
}
108124108216
108125108217
/* Resolve function names
108126108218
*/
108127108219
case TK_FUNCTION: {
108128
- ExprList *pList = pExpr->x.pList; /* The argument list */
108129
- int n = pList ? pList->nExpr : 0; /* Number of arguments */
108220
+ ExprList *pList; /* The argument list */
108221
+ int n; /* Number of arguments */
108130108222
int no_such_func = 0; /* True if no such function exists */
108131108223
int wrong_num_args = 0; /* True if wrong number of arguments */
108132108224
int is_agg = 0; /* True if is an aggregate function */
108133108225
const char *zId; /* The function name. */
108134108226
FuncDef *pDef; /* Information about the function */
@@ -108137,10 +108229,12 @@
108137108229
#ifndef SQLITE_OMIT_WINDOWFUNC
108138108230
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
108139108231
#endif
108140108232
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
108141108233
assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
108234
+ pList = pExpr->x.pList;
108235
+ n = pList ? pList->nExpr : 0;
108142108236
zId = pExpr->u.zToken;
108143108237
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
108144108238
if( pDef==0 ){
108145108239
pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
108146108240
if( pDef==0 ){
@@ -108185,10 +108279,28 @@
108185108279
pExpr->op = TK_NULL;
108186108280
return WRC_Prune;
108187108281
}
108188108282
}
108189108283
#endif
108284
+
108285
+ /* If the function may call sqlite3_value_subtype(), then set the
108286
+ ** EP_SubtArg flag on all of its argument expressions. This prevents
108287
+ ** where.c from replacing the expression with a value read from an
108288
+ ** index on the same expression, which will not have the correct
108289
+ ** subtype. Also set the flag if the function expression itself is
108290
+ ** an EP_SubtArg expression. In this case subtypes are required as
108291
+ ** the function may return a value with a subtype back to its
108292
+ ** caller using sqlite3_result_value(). */
108293
+ if( (pDef->funcFlags & SQLITE_SUBTYPE)
108294
+ || ExprHasProperty(pExpr, EP_SubtArg)
108295
+ ){
108296
+ int ii;
108297
+ for(ii=0; ii<n; ii++){
108298
+ ExprSetProperty(pList->a[ii].pExpr, EP_SubtArg);
108299
+ }
108300
+ }
108301
+
108190108302
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
108191108303
/* For the purposes of the EP_ConstFunc flag, date and time
108192108304
** functions and other functions that change slowly are considered
108193108305
** constant because they are constant for the duration of one query.
108194108306
** This allows them to be factored out of inner loops. */
@@ -111951,11 +112063,11 @@
111951112063
**
111952112064
** (4) If pSrc is the right operand of a LEFT JOIN, then...
111953112065
** (4a) pExpr must come from an ON clause..
111954112066
** (4b) and specifically the ON clause associated with the LEFT JOIN.
111955112067
**
111956
-** (5) If pSrc is not the right operand of a LEFT JOIN or the left
112068
+** (5) If pSrc is the right operand of a LEFT JOIN or the left
111957112069
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
111958112070
** clause, not an ON clause.
111959112071
**
111960112072
** (6) Either:
111961112073
**
@@ -113858,10 +113970,63 @@
113858113970
}
113859113971
#endif /* !defined(SQLITE_UNTESTABLE) */
113860113972
}
113861113973
return target;
113862113974
}
113975
+
113976
+/*
113977
+** Expression Node callback for sqlite3ExprCanReturnSubtype().
113978
+**
113979
+** Only a function call is able to return a subtype. So if the node
113980
+** is not a function call, return WRC_Prune immediately.
113981
+**
113982
+** A function call is able to return a subtype if it has the
113983
+** SQLITE_RESULT_SUBTYPE property.
113984
+**
113985
+** Assume that every function is able to pass-through a subtype from
113986
+** one of its argument (using sqlite3_result_value()). Most functions
113987
+** are not this way, but we don't have a mechanism to distinguish those
113988
+** that are from those that are not, so assume they all work this way.
113989
+** That means that if one of its arguments is another function and that
113990
+** other function is able to return a subtype, then this function is
113991
+** able to return a subtype.
113992
+*/
113993
+static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
113994
+ int n;
113995
+ FuncDef *pDef;
113996
+ sqlite3 *db;
113997
+ if( pExpr->op!=TK_FUNCTION ){
113998
+ return WRC_Prune;
113999
+ }
114000
+ assert( ExprUseXList(pExpr) );
114001
+ db = pWalker->pParse->db;
114002
+ n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0;
114003
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
114004
+ if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
114005
+ pWalker->eCode = 1;
114006
+ return WRC_Prune;
114007
+ }
114008
+ return WRC_Continue;
114009
+}
114010
+
114011
+/*
114012
+** Return TRUE if expression pExpr is able to return a subtype.
114013
+**
114014
+** A TRUE return does not guarantee that a subtype will be returned.
114015
+** It only indicates that a subtype return is possible. False positives
114016
+** are acceptable as they only disable an optimization. False negatives,
114017
+** on the other hand, can lead to incorrect answers.
114018
+*/
114019
+static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
114020
+ Walker w;
114021
+ memset(&w, 0, sizeof(w));
114022
+ w.pParse = pParse;
114023
+ w.xExprCallback = exprNodeCanReturnSubtype;
114024
+ sqlite3WalkExpr(&w, pExpr);
114025
+ return w.eCode;
114026
+}
114027
+
113863114028
113864114029
/*
113865114030
** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
113866114031
** If it is, then resolve the expression by reading from the index and
113867114032
** return the register into which the value has been read. If pExpr is
@@ -113891,10 +114056,21 @@
113891114056
){
113892114057
/* Affinity mismatch on a generated column */
113893114058
continue;
113894114059
}
113895114060
114061
+
114062
+ /* Functions that might set a subtype should not be replaced by the
114063
+ ** value taken from an expression index if they are themselves an
114064
+ ** argument to another scalar function or aggregate.
114065
+ ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */
114066
+ if( ExprHasProperty(pExpr, EP_SubtArg)
114067
+ && sqlite3ExprCanReturnSubtype(pParse, pExpr)
114068
+ ){
114069
+ continue;
114070
+ }
114071
+
113896114072
v = pParse->pVdbe;
113897114073
assert( v!=0 );
113898114074
if( p->bMaybeNullRow ){
113899114075
/* If the index is on a NULL row due to an outer join, then we
113900114076
** cannot extract the value from the index. The value must be
@@ -115421,35 +115597,41 @@
115421115597
**
115422115598
** Additionally, if pExpr is a simple SQL value and the value is the
115423115599
** same as that currently bound to variable pVar, non-zero is returned.
115424115600
** Otherwise, if the values are not the same or if pExpr is not a simple
115425115601
** SQL value, zero is returned.
115602
+**
115603
+** If the SQLITE_EnableQPSG flag is set on the database connection, then
115604
+** this routine always returns false.
115426115605
*/
115427
-static int exprCompareVariable(
115606
+static SQLITE_NOINLINE int exprCompareVariable(
115428115607
const Parse *pParse,
115429115608
const Expr *pVar,
115430115609
const Expr *pExpr
115431115610
){
115432
- int res = 0;
115611
+ int res = 2;
115433115612
int iVar;
115434115613
sqlite3_value *pL, *pR = 0;
115435115614
115615
+ if( pExpr->op==TK_VARIABLE && pVar->iColumn==pExpr->iColumn ){
115616
+ return 0;
115617
+ }
115618
+ if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) return 2;
115436115619
sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
115437115620
if( pR ){
115438115621
iVar = pVar->iColumn;
115439115622
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
115440115623
pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
115441115624
if( pL ){
115442115625
if( sqlite3_value_type(pL)==SQLITE_TEXT ){
115443115626
sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
115444115627
}
115445
- res = 0==sqlite3MemCompare(pL, pR, 0);
115628
+ res = sqlite3MemCompare(pL, pR, 0) ? 2 : 0;
115446115629
}
115447115630
sqlite3ValueFree(pR);
115448115631
sqlite3ValueFree(pL);
115449115632
}
115450
-
115451115633
return res;
115452115634
}
115453115635
115454115636
/*
115455115637
** Do a deep comparison of two expression trees. Return 0 if the two
@@ -115471,16 +115653,14 @@
115471115653
** can be sure the expressions are the same. In the places where
115472115654
** this routine is used, it does not hurt to get an extra 2 - that
115473115655
** just might result in some slightly slower code. But returning
115474115656
** an incorrect 0 or 1 could lead to a malfunction.
115475115657
**
115476
-** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
115477
-** pParse->pReprepare can be matched against literals in pB. The
115478
-** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
115479
-** If pParse is NULL (the normal case) then any TK_VARIABLE term in
115480
-** Argument pParse should normally be NULL. If it is not NULL and pA or
115481
-** pB causes a return value of 2.
115658
+** If pParse is not NULL and SQLITE_EnableQPSG is off then TK_VARIABLE
115659
+** terms in pA with bindings in pParse->pReprepare can be matched against
115660
+** literals in pB. The pParse->pVdbe->expmask bitmask is updated for
115661
+** each variable referenced.
115482115662
*/
115483115663
SQLITE_PRIVATE int sqlite3ExprCompare(
115484115664
const Parse *pParse,
115485115665
const Expr *pA,
115486115666
const Expr *pB,
@@ -115488,12 +115668,12 @@
115488115668
){
115489115669
u32 combinedFlags;
115490115670
if( pA==0 || pB==0 ){
115491115671
return pB==pA ? 0 : 2;
115492115672
}
115493
- if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
115494
- return 0;
115673
+ if( pParse && pA->op==TK_VARIABLE ){
115674
+ return exprCompareVariable(pParse, pA, pB);
115495115675
}
115496115676
combinedFlags = pA->flags | pB->flags;
115497115677
if( combinedFlags & EP_IntValue ){
115498115678
if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
115499115679
return 0;
@@ -115683,23 +115863,75 @@
115683115863
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
115684115864
}
115685115865
}
115686115866
return 0;
115687115867
}
115868
+
115869
+/*
115870
+** Return true if the boolean value of the expression is always either
115871
+** FALSE or NULL.
115872
+*/
115873
+static int sqlite3ExprIsNotTrue(Expr *pExpr){
115874
+ int v;
115875
+ if( pExpr->op==TK_NULL ) return 1;
115876
+ if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1;
115877
+ v = 1;
115878
+ if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1;
115879
+ return 0;
115880
+}
115881
+
115882
+/*
115883
+** Return true if the expression is one of the following:
115884
+**
115885
+** CASE WHEN x THEN y END
115886
+** CASE WHEN x THEN y ELSE NULL END
115887
+** CASE WHEN x THEN y ELSE false END
115888
+** iif(x,y)
115889
+** iif(x,y,NULL)
115890
+** iif(x,y,false)
115891
+*/
115892
+static int sqlite3ExprIsIIF(sqlite3 *db, const Expr *pExpr){
115893
+ ExprList *pList;
115894
+ if( pExpr->op==TK_FUNCTION ){
115895
+ const char *z = pExpr->u.zToken;
115896
+ FuncDef *pDef;
115897
+ if( (z[0]!='i' && z[0]!='I') ) return 0;
115898
+ if( pExpr->x.pList==0 ) return 0;
115899
+ pDef = sqlite3FindFunction(db, z, pExpr->x.pList->nExpr, ENC(db), 0);
115900
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
115901
+ if( pDef==0 ) return 0;
115902
+#else
115903
+ if( NEVER(pDef==0) ) return 0;
115904
+#endif
115905
+ if( (pDef->funcFlags & SQLITE_FUNC_INLINE)==0 ) return 0;
115906
+ if( SQLITE_PTR_TO_INT(pDef->pUserData)!=INLINEFUNC_iif ) return 0;
115907
+ }else if( pExpr->op==TK_CASE ){
115908
+ if( pExpr->pLeft!=0 ) return 0;
115909
+ }else{
115910
+ return 0;
115911
+ }
115912
+ pList = pExpr->x.pList;
115913
+ assert( pList!=0 );
115914
+ if( pList->nExpr==2 ) return 1;
115915
+ if( pList->nExpr==3 && sqlite3ExprIsNotTrue(pList->a[2].pExpr) ) return 1;
115916
+ return 0;
115917
+}
115688115918
115689115919
/*
115690115920
** Return true if we can prove the pE2 will always be true if pE1 is
115691115921
** true. Return false if we cannot complete the proof or if pE2 might
115692115922
** be false. Examples:
115693115923
**
115694
-** pE1: x==5 pE2: x==5 Result: true
115695
-** pE1: x>0 pE2: x==5 Result: false
115696
-** pE1: x=21 pE2: x=21 OR y=43 Result: true
115697
-** pE1: x!=123 pE2: x IS NOT NULL Result: true
115698
-** pE1: x!=?1 pE2: x IS NOT NULL Result: true
115699
-** pE1: x IS NULL pE2: x IS NOT NULL Result: false
115700
-** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
115924
+** pE1: x==5 pE2: x==5 Result: true
115925
+** pE1: x>0 pE2: x==5 Result: false
115926
+** pE1: x=21 pE2: x=21 OR y=43 Result: true
115927
+** pE1: x!=123 pE2: x IS NOT NULL Result: true
115928
+** pE1: x!=?1 pE2: x IS NOT NULL Result: true
115929
+** pE1: x IS NULL pE2: x IS NOT NULL Result: false
115930
+** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
115931
+** pE1: iif(x,y) pE2: x Result: true
115932
+** PE1: iif(x,y,0) pE2: x Result: true
115701115933
**
115702115934
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
115703115935
** Expr.iTable<0 then assume a table number given by iTab.
115704115936
**
115705115937
** If pParse is not NULL, then the values of bound variables in pE1 are
@@ -115729,10 +115961,13 @@
115729115961
if( pE2->op==TK_NOTNULL
115730115962
&& exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0)
115731115963
){
115732115964
return 1;
115733115965
}
115966
+ if( sqlite3ExprIsIIF(pParse->db, pE1) ){
115967
+ return sqlite3ExprImpliesExpr(pParse,pE1->x.pList->a[0].pExpr,pE2,iTab);
115968
+ }
115734115969
return 0;
115735115970
}
115736115971
115737115972
/* This is a helper function to impliesNotNullRow(). In this routine,
115738115973
** set pWalker->eCode to one only if *both* of the input expressions
@@ -120689,12 +120924,12 @@
120689120924
int nIdxCol = 1; /* Number of columns in stat4 records */
120690120925
120691120926
char *zIndex; /* Index name */
120692120927
Index *pIdx; /* Pointer to the index object */
120693120928
int nSample; /* Number of samples */
120694
- int nByte; /* Bytes of space required */
120695
- int i; /* Bytes of space required */
120929
+ i64 nByte; /* Bytes of space required */
120930
+ i64 i; /* Bytes of space required */
120696120931
tRowcnt *pSpace; /* Available allocated memory space */
120697120932
u8 *pPtr; /* Available memory as a u8 for easier manipulation */
120698120933
120699120934
zIndex = (char *)sqlite3_column_text(pStmt, 0);
120700120935
if( zIndex==0 ) continue;
@@ -121140,19 +121375,10 @@
121140121375
rc = sqlite3Init(db, &zErrDyn);
121141121376
}
121142121377
sqlite3BtreeLeaveAll(db);
121143121378
assert( zErrDyn==0 || rc!=SQLITE_OK );
121144121379
}
121145
-#ifdef SQLITE_USER_AUTHENTICATION
121146
- if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
121147
- u8 newAuth = 0;
121148
- rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
121149
- if( newAuth<db->auth.authLevel ){
121150
- rc = SQLITE_AUTH_USER;
121151
- }
121152
- }
121153
-#endif
121154121380
if( rc ){
121155121381
if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
121156121382
int iDb = db->nDb - 1;
121157121383
assert( iDb>=2 );
121158121384
if( db->aDb[iDb].pBt ){
@@ -121646,15 +121872,11 @@
121646121872
sqlite3 *db = pParse->db; /* Database handle */
121647121873
char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
121648121874
int rc; /* Auth callback return code */
121649121875
121650121876
if( db->init.busy ) return SQLITE_OK;
121651
- rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
121652
-#ifdef SQLITE_USER_AUTHENTICATION
121653
- ,db->auth.zAuthUser
121654
-#endif
121655
- );
121877
+ rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext);
121656121878
if( rc==SQLITE_DENY ){
121657121879
char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
121658121880
if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
121659121881
sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
121660121882
pParse->rc = SQLITE_AUTH;
@@ -121757,15 +121979,11 @@
121757121979
testcase( zArg1==0 );
121758121980
testcase( zArg2==0 );
121759121981
testcase( zArg3==0 );
121760121982
testcase( pParse->zAuthContext==0 );
121761121983
121762
- rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
121763
-#ifdef SQLITE_USER_AUTHENTICATION
121764
- ,db->auth.zAuthUser
121765
-#endif
121766
- );
121984
+ rc = db->xAuth(db->pAuthArg,code,zArg1,zArg2,zArg3,pParse->zAuthContext);
121767121985
if( rc==SQLITE_DENY ){
121768121986
sqlite3ErrorMsg(pParse, "not authorized");
121769121987
pParse->rc = SQLITE_AUTH;
121770121988
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
121771121989
rc = SQLITE_DENY;
@@ -121994,21 +122212,10 @@
121994122212
sqlite3VdbeJumpHere(v, addrRewind);
121995122213
}
121996122214
}
121997122215
sqlite3VdbeAddOp0(v, OP_Halt);
121998122216
121999
-#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE)
122000
- if( pParse->nTableLock>0 && db->init.busy==0 ){
122001
- sqlite3UserAuthInit(db);
122002
- if( db->auth.authLevel<UAUTH_User ){
122003
- sqlite3ErrorMsg(pParse, "user not authenticated");
122004
- pParse->rc = SQLITE_AUTH_USER;
122005
- return;
122006
- }
122007
- }
122008
-#endif
122009
-
122010122217
/* The cookie mask contains one bit for each database file open.
122011122218
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
122012122219
** set for each database that is used. Generate code to start a
122013122220
** transaction on each used database and to verify the schema cookie
122014122221
** on each used database.
@@ -122133,20 +122340,10 @@
122133122340
sqlite3DbFree(db, zSql);
122134122341
memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
122135122342
pParse->nested--;
122136122343
}
122137122344
122138
-#if SQLITE_USER_AUTHENTICATION
122139
-/*
122140
-** Return TRUE if zTable is the name of the system table that stores the
122141
-** list of users and their access credentials.
122142
-*/
122143
-SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){
122144
- return sqlite3_stricmp(zTable, "sqlite_user")==0;
122145
-}
122146
-#endif
122147
-
122148122345
/*
122149122346
** Locate the in-memory structure that describes a particular database
122150122347
** table given the name of that table and (optionally) the name of the
122151122348
** database containing the table. Return NULL if not found.
122152122349
**
@@ -122161,17 +122358,10 @@
122161122358
Table *p = 0;
122162122359
int i;
122163122360
122164122361
/* All mutexes are required for schema access. Make sure we hold them. */
122165122362
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
122166
-#if SQLITE_USER_AUTHENTICATION
122167
- /* Only the admin user is allowed to know that the sqlite_user table
122168
- ** exists */
122169
- if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
122170
- return 0;
122171
- }
122172
-#endif
122173122363
if( zDatabase ){
122174122364
for(i=0; i<db->nDb; i++){
122175122365
if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
122176122366
}
122177122367
if( i>=db->nDb ){
@@ -125826,13 +126016,10 @@
125826126016
125827126017
assert( pTab!=0 );
125828126018
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
125829126019
&& db->init.busy==0
125830126020
&& pTblName!=0
125831
-#if SQLITE_USER_AUTHENTICATION
125832
- && sqlite3UserAuthTable(pTab->zName)==0
125833
-#endif
125834126021
){
125835126022
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
125836126023
goto exit_create_index;
125837126024
}
125838126025
#ifndef SQLITE_OMIT_VIEW
@@ -128224,10 +128411,11 @@
128224128411
** 4) The table is a shadow table, the database connection is in
128225128412
** defensive mode, and the current sqlite3_prepare()
128226128413
** is for a top-level SQL statement.
128227128414
*/
128228128415
static int vtabIsReadOnly(Parse *pParse, Table *pTab){
128416
+ assert( IsVirtual(pTab) );
128229128417
if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
128230128418
return 1;
128231128419
}
128232128420
128233128421
/* Within triggers:
@@ -131716,11 +131904,17 @@
131716131904
#ifdef SQLITE_DEBUG
131717131905
/*
131718131906
** Implementation of fpdecode(x,y,z) function.
131719131907
**
131720131908
** x is a real number that is to be decoded. y is the precision.
131721
-** z is the maximum real precision.
131909
+** z is the maximum real precision. Return a string that shows the
131910
+** results of the sqlite3FpDecode() function.
131911
+**
131912
+** Used for testing and debugging only, specifically testing and debugging
131913
+** of the sqlite3FpDecode() function. This SQL function does not appear
131914
+** in production builds. This function is not an API and is subject to
131915
+** modification or removal in future versions of SQLite.
131722131916
*/
131723131917
static void fpdecodeFunc(
131724131918
sqlite3_context *context,
131725131919
int argc,
131726131920
sqlite3_value **argv
@@ -131740,10 +131934,86 @@
131740131934
sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
131741131935
}else{
131742131936
sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
131743131937
}
131744131938
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
131939
+}
131940
+#endif /* SQLITE_DEBUG */
131941
+
131942
+#ifdef SQLITE_DEBUG
131943
+/*
131944
+** Implementation of parseuri(uri,flags) function.
131945
+**
131946
+** Required Arguments:
131947
+** "uri" The URI to parse.
131948
+** "flags" Bitmask of flags, as if to sqlite3_open_v2().
131949
+**
131950
+** Additional arguments beyond the first two make calls to
131951
+** sqlite3_uri_key() for integers and sqlite3_uri_parameter for
131952
+** anything else.
131953
+**
131954
+** The result is a string showing the results of calling sqlite3ParseUri().
131955
+**
131956
+** Used for testing and debugging only, specifically testing and debugging
131957
+** of the sqlite3ParseUri() function. This SQL function does not appear
131958
+** in production builds. This function is not an API and is subject to
131959
+** modification or removal in future versions of SQLite.
131960
+*/
131961
+static void parseuriFunc(
131962
+ sqlite3_context *ctx,
131963
+ int argc,
131964
+ sqlite3_value **argv
131965
+){
131966
+ sqlite3_str *pResult;
131967
+ const char *zVfs;
131968
+ const char *zUri;
131969
+ unsigned int flgs;
131970
+ int rc;
131971
+ sqlite3_vfs *pVfs = 0;
131972
+ char *zFile = 0;
131973
+ char *zErr = 0;
131974
+
131975
+ if( argc<2 ) return;
131976
+ pVfs = sqlite3_vfs_find(0);
131977
+ assert( pVfs );
131978
+ zVfs = pVfs->zName;
131979
+ zUri = (const char*)sqlite3_value_text(argv[0]);
131980
+ if( zUri==0 ) return;
131981
+ flgs = (unsigned int)sqlite3_value_int(argv[1]);
131982
+ rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr);
131983
+ pResult = sqlite3_str_new(0);
131984
+ if( pResult ){
131985
+ int i;
131986
+ sqlite3_str_appendf(pResult, "rc=%d", rc);
131987
+ sqlite3_str_appendf(pResult, ", flags=0x%x", flgs);
131988
+ sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0);
131989
+ sqlite3_str_appendf(pResult, ", err=%Q", zErr);
131990
+ sqlite3_str_appendf(pResult, ", file=%Q", zFile);
131991
+ if( zFile ){
131992
+ const char *z = zFile;
131993
+ z += sqlite3Strlen30(z)+1;
131994
+ while( z[0] ){
131995
+ sqlite3_str_appendf(pResult, ", %Q", z);
131996
+ z += sqlite3Strlen30(z)+1;
131997
+ }
131998
+ for(i=2; i<argc; i++){
131999
+ const char *zArg;
132000
+ if( sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
132001
+ int k = sqlite3_value_int(argv[i]);
132002
+ sqlite3_str_appendf(pResult, ", '%d:%q'",k,sqlite3_uri_key(zFile, k));
132003
+ }else if( (zArg = (const char*)sqlite3_value_text(argv[i]))!=0 ){
132004
+ sqlite3_str_appendf(pResult, ", '%q:%q'",
132005
+ zArg, sqlite3_uri_parameter(zFile,zArg));
132006
+ }else{
132007
+ sqlite3_str_appendf(pResult, ", NULL");
132008
+ }
132009
+ }
132010
+ }
132011
+ sqlite3_result_text(ctx, sqlite3_str_finish(pResult), -1, sqlite3_free);
132012
+ }
132013
+ sqlite3_free_filename(zFile);
132014
+ sqlite3_free(zErr);
131745132015
}
131746132016
#endif /* SQLITE_DEBUG */
131747132017
131748132018
/*
131749132019
** All of the FuncDef structures in the aBuiltinFunc[] array above
@@ -131777,13 +132047,10 @@
131777132047
#endif
131778132048
#ifndef SQLITE_OMIT_LOAD_EXTENSION
131779132049
SFUNCTION(load_extension, 1, 0, 0, loadExt ),
131780132050
SFUNCTION(load_extension, 2, 0, 0, loadExt ),
131781132051
#endif
131782
-#if SQLITE_USER_AUTHENTICATION
131783
- FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
131784
-#endif
131785132052
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
131786132053
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
131787132054
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
131788132055
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
131789132056
INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
@@ -131805,11 +132072,12 @@
131805132072
FUNCTION(max, -1, 1, 1, minmaxFunc ),
131806132073
FUNCTION(max, 0, 1, 1, 0 ),
131807132074
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
131808132075
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
131809132076
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
131810
- FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
132077
+ FUNCTION2(subtype, 1, 0, 0, subtypeFunc,
132078
+ SQLITE_FUNC_TYPEOF|SQLITE_SUBTYPE),
131811132079
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
131812132080
FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
131813132081
FUNCTION(instr, 2, 0, 0, instrFunc ),
131814132082
FUNCTION(printf, -1, 0, 0, printfFunc ),
131815132083
FUNCTION(format, -1, 0, 0, printfFunc ),
@@ -131816,10 +132084,11 @@
131816132084
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
131817132085
FUNCTION(char, -1, 0, 0, charFunc ),
131818132086
FUNCTION(abs, 1, 0, 0, absFunc ),
131819132087
#ifdef SQLITE_DEBUG
131820132088
FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
132089
+ FUNCTION(parseuri, -1, 0, 0, parseuriFunc ),
131821132090
#endif
131822132091
#ifndef SQLITE_OMIT_FLOATING_POINT
131823132092
FUNCTION(round, 1, 0, 0, roundFunc ),
131824132093
FUNCTION(round, 2, 0, 0, roundFunc ),
131825132094
#endif
@@ -131910,15 +132179,18 @@
131910132179
MFUNCTION(atanh, 1, atanh, math1Func ),
131911132180
#endif
131912132181
MFUNCTION(sqrt, 1, sqrt, math1Func ),
131913132182
MFUNCTION(radians, 1, degToRad, math1Func ),
131914132183
MFUNCTION(degrees, 1, radToDeg, math1Func ),
131915
- FUNCTION(pi, 0, 0, 0, piFunc ),
132184
+ MFUNCTION(pi, 0, 0, piFunc ),
131916132185
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
131917132186
FUNCTION(sign, 1, 0, 0, signFunc ),
131918132187
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
132188
+ INLINE_FUNC(iif, 2, INLINEFUNC_iif, 0 ),
131919132189
INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
132190
+ INLINE_FUNC(if, 2, INLINEFUNC_iif, 0 ),
132191
+ INLINE_FUNC(if, 3, INLINEFUNC_iif, 0 ),
131920132192
};
131921132193
#ifndef SQLITE_OMIT_ALTERTABLE
131922132194
sqlite3AlterFunctions();
131923132195
#endif
131924132196
sqlite3WindowFunctions();
@@ -140427,16 +140699,10 @@
140427140699
if( db->autoCommit==0 ){
140428140700
/* Foreign key support may not be enabled or disabled while not
140429140701
** in auto-commit mode. */
140430140702
mask &= ~(SQLITE_ForeignKeys);
140431140703
}
140432
-#if SQLITE_USER_AUTHENTICATION
140433
- if( db->auth.authLevel==UAUTH_User ){
140434
- /* Do not allow non-admin users to modify the schema arbitrarily */
140435
- mask &= ~(SQLITE_WriteSchema);
140436
- }
140437
-#endif
140438140704
140439140705
if( sqlite3GetBoolean(zRight, 0) ){
140440140706
if( (mask & SQLITE_WriteSchema)==0
140441140707
|| (db->flags & SQLITE_Defensive)==0
140442140708
){
@@ -140568,11 +140834,12 @@
140568140834
pTab = sqliteHashData(k);
140569140835
if( pTab->nCol==0 ){
140570140836
char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName);
140571140837
if( zSql ){
140572140838
sqlite3_stmt *pDummy = 0;
140573
- (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0);
140839
+ (void)sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_DONT_LOG,
140840
+ &pDummy, 0);
140574140841
(void)sqlite3_finalize(pDummy);
140575140842
sqlite3DbFree(db, zSql);
140576140843
}
140577140844
if( db->mallocFailed ){
140578140845
sqlite3ErrorMsg(db->pParse, "out of memory");
@@ -141044,10 +141311,11 @@
141044141311
}
141045141312
aRoot[0] = cnt;
141046141313
141047141314
/* Make sure sufficient number of registers have been allocated */
141048141315
sqlite3TouchRegister(pParse, 8+cnt);
141316
+ sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt);
141049141317
sqlite3ClearTempRegCache(pParse);
141050141318
141051141319
/* Do the b-tree integrity checks */
141052141320
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
141053141321
sqlite3VdbeChangeP5(v, (u8)i);
@@ -142668,18 +142936,11 @@
142668142936
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
142669142937
if( encoding==0 ) encoding = SQLITE_UTF8;
142670142938
#else
142671142939
encoding = SQLITE_UTF8;
142672142940
#endif
142673
- if( db->nVdbeActive>0 && encoding!=ENC(db)
142674
- && (db->mDbFlags & DBFLAG_Vacuum)==0
142675
- ){
142676
- rc = SQLITE_LOCKED;
142677
- goto initone_error_out;
142678
- }else{
142679
- sqlite3SetTextEncoding(db, encoding);
142680
- }
142941
+ sqlite3SetTextEncoding(db, encoding);
142681142942
}else{
142682142943
/* If opening an attached database, the encoding much match ENC(db) */
142683142944
if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
142684142945
sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
142685142946
" text encoding as main database");
@@ -143369,16 +143630,28 @@
143369143630
#endif
143370143631
*ppStmt = 0;
143371143632
if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
143372143633
return SQLITE_MISUSE_BKPT;
143373143634
}
143635
+
143636
+ /* Make sure nBytes is non-negative and correct. It should be the
143637
+ ** number of bytes until the end of the input buffer or until the first
143638
+ ** U+0000 character. If the input nBytes is odd, convert it into
143639
+ ** an even number. If the input nBytes is negative, then the input
143640
+ ** must be terminated by at least one U+0000 character */
143374143641
if( nBytes>=0 ){
143375143642
int sz;
143376143643
const char *z = (const char*)zSql;
143377143644
for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
143378143645
nBytes = sz;
143646
+ }else{
143647
+ int sz;
143648
+ const char *z = (const char*)zSql;
143649
+ for(sz=0; z[sz]!=0 || z[sz+1]!=0; sz += 2){}
143650
+ nBytes = sz;
143379143651
}
143652
+
143380143653
sqlite3_mutex_enter(db->mutex);
143381143654
zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
143382143655
if( zSql8 ){
143383143656
rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
143384143657
}
@@ -143388,11 +143661,11 @@
143388143661
** equivalent pointer into the UTF-16 string by counting the unicode
143389143662
** characters between zSql8 and zTail8, and then returning a pointer
143390143663
** the same number of characters into the UTF-16 string.
143391143664
*/
143392143665
int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
143393
- *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
143666
+ *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, nBytes, chars_parsed);
143394143667
}
143395143668
sqlite3DbFree(db, zSql8);
143396143669
rc = sqlite3ApiExit(db, rc);
143397143670
sqlite3_mutex_leave(db->mutex);
143398143671
return rc;
@@ -147361,36 +147634,36 @@
147361147634
return pExpr;
147362147635
}
147363147636
if( pSubst->isOuterJoin ){
147364147637
ExprSetProperty(pNew, EP_CanBeNull);
147365147638
}
147639
+ if( pNew->op==TK_TRUEFALSE ){
147640
+ pNew->u.iValue = sqlite3ExprTruthValue(pNew);
147641
+ pNew->op = TK_INTEGER;
147642
+ ExprSetProperty(pNew, EP_IntValue);
147643
+ }
147644
+
147645
+ /* Ensure that the expression now has an implicit collation sequence,
147646
+ ** just as it did when it was a column of a view or sub-query. */
147647
+ {
147648
+ CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pNew);
147649
+ CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
147650
+ pSubst->pCList->a[iColumn].pExpr
147651
+ );
147652
+ if( pNat!=pColl || (pNew->op!=TK_COLUMN && pNew->op!=TK_COLLATE) ){
147653
+ pNew = sqlite3ExprAddCollateString(pSubst->pParse, pNew,
147654
+ (pColl ? pColl->zName : "BINARY")
147655
+ );
147656
+ }
147657
+ }
147658
+ ExprClearProperty(pNew, EP_Collate);
147366147659
if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
147367147660
sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
147368147661
pExpr->flags & (EP_OuterON|EP_InnerON));
147369147662
}
147370147663
sqlite3ExprDelete(db, pExpr);
147371147664
pExpr = pNew;
147372
- if( pExpr->op==TK_TRUEFALSE ){
147373
- pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
147374
- pExpr->op = TK_INTEGER;
147375
- ExprSetProperty(pExpr, EP_IntValue);
147376
- }
147377
-
147378
- /* Ensure that the expression now has an implicit collation sequence,
147379
- ** just as it did when it was a column of a view or sub-query. */
147380
- {
147381
- CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
147382
- CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
147383
- pSubst->pCList->a[iColumn].pExpr
147384
- );
147385
- if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
147386
- pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
147387
- (pColl ? pColl->zName : "BINARY")
147388
- );
147389
- }
147390
- }
147391
- ExprClearProperty(pExpr, EP_Collate);
147392147665
}
147393147666
}
147394147667
}else{
147395147668
if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
147396147669
pExpr->iTable = pSubst->iNewTable;
@@ -148123,20 +148396,20 @@
148123148396
}
148124148397
148125148398
/* Transfer the FROM clause terms from the subquery into the
148126148399
** outer query.
148127148400
*/
148401
+ iNewParent = pSubSrc->a[0].iCursor;
148128148402
for(i=0; i<nSubSrc; i++){
148129148403
SrcItem *pItem = &pSrc->a[i+iFrom];
148130148404
assert( pItem->fg.isTabFunc==0 );
148131148405
assert( pItem->fg.isSubquery
148132148406
|| pItem->fg.fixedSchema
148133148407
|| pItem->u4.zDatabase==0 );
148134148408
if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
148135148409
*pItem = pSubSrc->a[i];
148136148410
pItem->fg.jointype |= ltorj;
148137
- iNewParent = pSubSrc->a[i].iCursor;
148138148411
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
148139148412
}
148140148413
pSrc->a[iFrom].fg.jointype &= JT_LTORJ;
148141148414
pSrc->a[iFrom].fg.jointype |= jointype | ltorj;
148142148415
@@ -148172,10 +148445,11 @@
148172148445
pSub->pOrderBy = 0;
148173148446
}
148174148447
pWhere = pSub->pWhere;
148175148448
pSub->pWhere = 0;
148176148449
if( isOuterJoin>0 ){
148450
+ assert( pSubSrc->nSrc==1 );
148177148451
sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
148178148452
}
148179148453
if( pWhere ){
148180148454
if( pParent->pWhere ){
148181148455
pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
@@ -151271,11 +151545,11 @@
151271151545
sqlite3TreeViewSelect(0, p, 0);
151272151546
}
151273151547
#endif
151274151548
assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
151275151549
}else{
151276
- TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
151550
+ TREETRACE(0x4000,pParse,p,("WHERE-clause push-down not possible\n"));
151277151551
}
151278151552
151279151553
/* Convert unused result columns of the subquery into simple NULL
151280151554
** expressions, to avoid unneeded searching and computation.
151281151555
** tag-select-0440
@@ -156980,10 +157254,11 @@
156980157254
assert( sParse.zErrMsg==0 );
156981157255
if( !pTab->aCol ){
156982157256
Table *pNew = sParse.pNewTable;
156983157257
Index *pIdx;
156984157258
pTab->aCol = pNew->aCol;
157259
+ assert( IsOrdinaryTable(pNew) );
156985157260
sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
156986157261
pTab->nNVCol = pTab->nCol = pNew->nCol;
156987157262
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
156988157263
pNew->nCol = 0;
156989157264
pNew->aCol = 0;
@@ -158044,13 +158319,21 @@
158044158319
SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
158045158320
const Parse *pParse, /* Parse context */
158046158321
const WhereInfo *pWInfo, /* WHERE clause */
158047158322
const WhereLevel *pLevel /* Bloom filter on this level */
158048158323
);
158324
+SQLITE_PRIVATE void sqlite3WhereAddExplainText(
158325
+ Parse *pParse, /* Parse context */
158326
+ int addr,
158327
+ SrcList *pTabList, /* Table list this loop refers to */
158328
+ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158329
+ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158330
+);
158049158331
#else
158050158332
# define sqlite3WhereExplainOneScan(u,v,w,x) 0
158051158333
# define sqlite3WhereExplainBloomFilter(u,v,w) 0
158334
+# define sqlite3WhereAddExplainText(u,v,w,x,y)
158052158335
#endif /* SQLITE_OMIT_EXPLAIN */
158053158336
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
158054158337
SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
158055158338
Vdbe *v, /* Vdbe to add scanstatus entry to */
158056158339
SrcList *pSrclist, /* FROM clause pLvl reads data from */
@@ -158248,42 +158531,42 @@
158248158531
}
158249158532
sqlite3_str_append(pStr, ")", 1);
158250158533
}
158251158534
158252158535
/*
158253
-** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
158254
-** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
158255
-** was defined at compile-time. If it is not a no-op, a single OP_Explain
158256
-** opcode is added to the output to describe the table scan strategy in pLevel.
158257
-**
158258
-** If an OP_Explain opcode is added to the VM, its address is returned.
158259
-** Otherwise, if no OP_Explain is coded, zero is returned.
158536
+** This function sets the P4 value of an existing OP_Explain opcode to
158537
+** text describing the loop in pLevel. If the OP_Explain opcode already has
158538
+** a P4 value, it is freed before it is overwritten.
158260158539
*/
158261
-SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
158540
+SQLITE_PRIVATE void sqlite3WhereAddExplainText(
158262158541
Parse *pParse, /* Parse context */
158542
+ int addr, /* Address of OP_Explain opcode */
158263158543
SrcList *pTabList, /* Table list this loop refers to */
158264158544
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158265158545
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158266158546
){
158267
- int ret = 0;
158268158547
#if !defined(SQLITE_DEBUG)
158269158548
if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
158270158549
#endif
158271158550
{
158551
+ VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe, addr);
158552
+
158272158553
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
158273
- Vdbe *v = pParse->pVdbe; /* VM being constructed */
158274158554
sqlite3 *db = pParse->db; /* Database handle */
158275158555
int isSearch; /* True for a SEARCH. False for SCAN. */
158276158556
WhereLoop *pLoop; /* The controlling WhereLoop object */
158277158557
u32 flags; /* Flags that describe this loop */
158558
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
158278158559
char *zMsg; /* Text to add to EQP output */
158560
+#endif
158279158561
StrAccum str; /* EQP output string */
158280158562
char zBuf[100]; /* Initial space for EQP output string */
158281158563
158564
+ if( db->mallocFailed ) return;
158565
+
158282158566
pLoop = pLevel->pWLoop;
158283158567
flags = pLoop->wsFlags;
158284
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
158285158568
158286158569
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
158287158570
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
158288158571
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
158289158572
@@ -158303,11 +158586,11 @@
158303158586
}
158304158587
}else if( flags & WHERE_PARTIALIDX ){
158305158588
zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
158306158589
}else if( flags & WHERE_AUTO_INDEX ){
158307158590
zFmt = "AUTOMATIC COVERING INDEX";
158308
- }else if( flags & WHERE_IDX_ONLY ){
158591
+ }else if( flags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){
158309158592
zFmt = "COVERING INDEX %s";
158310158593
}else{
158311158594
zFmt = "INDEX %s";
158312158595
}
158313158596
if( zFmt ){
@@ -158355,15 +158638,54 @@
158355158638
sqlite3LogEstToInt(pLoop->nOut));
158356158639
}else{
158357158640
sqlite3_str_append(&str, " (~1 row)", 9);
158358158641
}
158359158642
#endif
158643
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
158360158644
zMsg = sqlite3StrAccumFinish(&str);
158361158645
sqlite3ExplainBreakpoint("",zMsg);
158362
- ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
158363
- pParse->addrExplain, pLoop->rRun,
158364
- zMsg, P4_DYNAMIC);
158646
+#endif
158647
+
158648
+ assert( pOp->opcode==OP_Explain );
158649
+ assert( pOp->p4type==P4_DYNAMIC || pOp->p4.z==0 );
158650
+ sqlite3DbFree(db, pOp->p4.z);
158651
+ pOp->p4type = P4_DYNAMIC;
158652
+ pOp->p4.z = sqlite3StrAccumFinish(&str);
158653
+ }
158654
+}
158655
+
158656
+
158657
+/*
158658
+** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
158659
+** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
158660
+** was defined at compile-time. If it is not a no-op, a single OP_Explain
158661
+** opcode is added to the output to describe the table scan strategy in pLevel.
158662
+**
158663
+** If an OP_Explain opcode is added to the VM, its address is returned.
158664
+** Otherwise, if no OP_Explain is coded, zero is returned.
158665
+*/
158666
+SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
158667
+ Parse *pParse, /* Parse context */
158668
+ SrcList *pTabList, /* Table list this loop refers to */
158669
+ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158670
+ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158671
+){
158672
+ int ret = 0;
158673
+#if !defined(SQLITE_DEBUG)
158674
+ if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
158675
+#endif
158676
+ {
158677
+ if( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0
158678
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
158679
+ ){
158680
+ Vdbe *v = pParse->pVdbe;
158681
+ int addr = sqlite3VdbeCurrentAddr(v);
158682
+ ret = sqlite3VdbeAddOp3(
158683
+ v, OP_Explain, addr, pParse->addrExplain, pLevel->pWLoop->rRun
158684
+ );
158685
+ sqlite3WhereAddExplainText(pParse, addr, pTabList, pLevel, wctrlFlags);
158686
+ }
158365158687
}
158366158688
return ret;
158367158689
}
158368158690
158369158691
/*
@@ -158458,13 +158780,14 @@
158458158780
if( wsFlags & WHERE_INDEXED ){
158459158781
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
158460158782
}
158461158783
}else{
158462158784
int addr;
158785
+ VdbeOp *pOp;
158463158786
assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
158464158787
addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
158465
- VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
158788
+ pOp = sqlite3VdbeGetOp(v, addr-1);
158466158789
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
158467158790
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
158468158791
sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
158469158792
}
158470158793
}
@@ -158713,10 +159036,11 @@
158713159036
if( pOrigLhs ){
158714159037
sqlite3ExprListDelete(db, pOrigLhs);
158715159038
pNew->pLeft->x.pList = pLhs;
158716159039
}
158717159040
pSelect->pEList = pRhs;
159041
+ pSelect->selId = ++pParse->nSelect; /* Req'd for SubrtnSig validity */
158718159042
if( pLhs && pLhs->nExpr==1 ){
158719159043
/* Take care here not to generate a TK_VECTOR containing only a
158720159044
** single value. Since the parser never creates such a vector, some
158721159045
** of the subroutines do not handle this case. */
158722159046
Expr *p = pLhs->a[0].pExpr;
@@ -161260,24 +161584,29 @@
161260161584
}else if( op==TK_STRING ){
161261161585
assert( !ExprHasProperty(pRight, EP_IntValue) );
161262161586
z = (u8*)pRight->u.zToken;
161263161587
}
161264161588
if( z ){
161265
-
161266
- /* Count the number of prefix characters prior to the first wildcard.
161267
- ** If the underlying database has a UTF16LE encoding, then only consider
161268
- ** ASCII characters. Note that the encoding of z[] is UTF8 - we are
161269
- ** dealing with only UTF8 here in this code, but the database engine
161270
- ** itself might be processing content using a different encoding. */
161589
+ /* Count the number of prefix bytes prior to the first wildcard.
161590
+ ** or U+fffd character. If the underlying database has a UTF16LE
161591
+ ** encoding, then only consider ASCII characters. Note that the
161592
+ ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in
161593
+ ** this code, but the database engine itself might be processing
161594
+ ** content using a different encoding. */
161271161595
cnt = 0;
161272161596
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
161273161597
cnt++;
161274
- if( c==wc[3] && z[cnt]!=0 ){
161598
+ if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
161275161599
cnt++;
161276
- }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){
161277
- cnt--;
161278
- break;
161600
+ }else if( c>=0x80 ){
161601
+ const u8 *z2 = z+cnt-1;
161602
+ if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){
161603
+ cnt--;
161604
+ break;
161605
+ }else{
161606
+ cnt = (int)(z2-z);
161607
+ }
161279161608
}
161280161609
}
161281161610
161282161611
/* The optimization is possible only if (1) the pattern does not begin
161283161612
** with a wildcard and if (2) the non-wildcard prefix does not end with
@@ -161285,11 +161614,11 @@
161285161614
** a single escape character. The second condition is necessary so
161286161615
** that we can increment the prefix key to find an upper bound for the
161287161616
** range search. The third is because the caller assumes that the pattern
161288161617
** consists of at least one character after all escapes have been
161289161618
** removed. */
161290
- if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
161619
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){
161291161620
Expr *pPrefix;
161292161621
161293161622
/* A "complete" match if the pattern ends with "*" or "%" */
161294161623
*pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
161295161624
@@ -163780,11 +164109,11 @@
163780164109
|| pTerm->pExpr->w.iJoin != pSrc->iCursor
163781164110
){
163782164111
return 0;
163783164112
}
163784164113
if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
163785
- && ExprHasProperty(pTerm->pExpr, EP_InnerON)
164114
+ && NEVER(ExprHasProperty(pTerm->pExpr, EP_InnerON))
163786164115
){
163787164116
return 0;
163788164117
}
163789164118
return 1;
163790164119
}
@@ -164577,13 +164906,15 @@
164577164906
** Whether or not an error is returned, it is the responsibility of the
164578164907
** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
164579164908
** that this is required.
164580164909
*/
164581164910
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
164582
- sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
164583164911
int rc;
164912
+ sqlite3_vtab *pVtab;
164584164913
164914
+ assert( IsVirtual(pTab) );
164915
+ pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
164585164916
whereTraceIndexInfoInputs(p, pTab);
164586164917
pParse->db->nSchemaLock++;
164587164918
rc = pVtab->pModule->xBestIndex(pVtab, p);
164588164919
pParse->db->nSchemaLock--;
164589164920
whereTraceIndexInfoOutputs(p, pTab);
@@ -165271,11 +165602,11 @@
165271165602
return rc;
165272165603
}
165273165604
#endif /* SQLITE_ENABLE_STAT4 */
165274165605
165275165606
165276
-#ifdef WHERETRACE_ENABLED
165607
+#if defined(WHERETRACE_ENABLED) || defined(SQLITE_DEBUG)
165277165608
/*
165278165609
** Print the content of a WhereTerm object
165279165610
*/
165280165611
SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
165281165612
if( pTerm==0 ){
@@ -165314,10 +165645,13 @@
165314165645
sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
165315165646
}
165316165647
sqlite3DebugPrintf("\n");
165317165648
sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
165318165649
}
165650
+}
165651
+SQLITE_PRIVATE void sqlite3ShowWhereTerm(WhereTerm *pTerm){
165652
+ sqlite3WhereTermPrint(pTerm, 0);
165319165653
}
165320165654
#endif
165321165655
165322165656
#ifdef WHERETRACE_ENABLED
165323165657
/*
@@ -165522,11 +165856,11 @@
165522165856
** Return TRUE if X is a proper subset of Y but is of equal or less cost.
165523165857
** In other words, return true if all constraints of X are also part of Y
165524165858
** and Y has additional constraints that might speed the search that X lacks
165525165859
** but the cost of running X is not more than the cost of running Y.
165526165860
**
165527
-** In other words, return true if the cost relationwship between X and Y
165861
+** In other words, return true if the cost relationship between X and Y
165528165862
** is inverted and needs to be adjusted.
165529165863
**
165530165864
** Case 1:
165531165865
**
165532165866
** (1a) X and Y use the same index.
@@ -166500,11 +166834,10 @@
166500166834
pParse = pWC->pWInfo->pParse;
166501166835
while( pWhere->op==TK_AND ){
166502166836
if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0;
166503166837
pWhere = pWhere->pRight;
166504166838
}
166505
- if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
166506166839
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
166507166840
Expr *pExpr;
166508166841
pExpr = pTerm->pExpr;
166509166842
if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
166510166843
&& ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
@@ -169140,10 +169473,11 @@
169140169473
hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
169141169474
for(i=pWInfo->nLevel-1; i>=1; i--){
169142169475
WhereTerm *pTerm, *pEnd;
169143169476
SrcItem *pItem;
169144169477
WhereLoop *pLoop;
169478
+ Bitmask m1;
169145169479
pLoop = pWInfo->a[i].pWLoop;
169146169480
pItem = &pWInfo->pTabList->a[pLoop->iTab];
169147169481
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue;
169148169482
if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0
169149169483
&& (pLoop->wsFlags & WHERE_ONEROW)==0
@@ -169160,17 +169494,20 @@
169160169494
break;
169161169495
}
169162169496
}
169163169497
if( hasRightJoin
169164169498
&& ExprHasProperty(pTerm->pExpr, EP_InnerON)
169165
- && pTerm->pExpr->w.iJoin==pItem->iCursor
169499
+ && NEVER(pTerm->pExpr->w.iJoin==pItem->iCursor)
169166169500
){
169167169501
break; /* restriction (5) */
169168169502
}
169169169503
}
169170169504
if( pTerm<pEnd ) continue;
169171
- WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
169505
+ WHERETRACE(0xffffffff,("-> omit unused FROM-clause term %c\n",pLoop->cId));
169506
+ m1 = MASKBIT(i)-1;
169507
+ testcase( ((pWInfo->revMask>>1) & ~m1)!=0 );
169508
+ pWInfo->revMask = (m1 & pWInfo->revMask) | ((pWInfo->revMask>>1) & ~m1);
169172169509
notReady &= ~pLoop->maskSelf;
169173169510
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
169174169511
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
169175169512
pTerm->wtFlags |= TERM_CODED;
169176169513
}
@@ -169237,62 +169574,10 @@
169237169574
nSearch += pLoop->nOut;
169238169575
if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta;
169239169576
}
169240169577
}
169241169578
169242
-/*
169243
-** Expression Node callback for sqlite3ExprCanReturnSubtype().
169244
-**
169245
-** Only a function call is able to return a subtype. So if the node
169246
-** is not a function call, return WRC_Prune immediately.
169247
-**
169248
-** A function call is able to return a subtype if it has the
169249
-** SQLITE_RESULT_SUBTYPE property.
169250
-**
169251
-** Assume that every function is able to pass-through a subtype from
169252
-** one of its argument (using sqlite3_result_value()). Most functions
169253
-** are not this way, but we don't have a mechanism to distinguish those
169254
-** that are from those that are not, so assume they all work this way.
169255
-** That means that if one of its arguments is another function and that
169256
-** other function is able to return a subtype, then this function is
169257
-** able to return a subtype.
169258
-*/
169259
-static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
169260
- int n;
169261
- FuncDef *pDef;
169262
- sqlite3 *db;
169263
- if( pExpr->op!=TK_FUNCTION ){
169264
- return WRC_Prune;
169265
- }
169266
- assert( ExprUseXList(pExpr) );
169267
- db = pWalker->pParse->db;
169268
- n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
169269
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
169270
- if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
169271
- pWalker->eCode = 1;
169272
- return WRC_Prune;
169273
- }
169274
- return WRC_Continue;
169275
-}
169276
-
169277
-/*
169278
-** Return TRUE if expression pExpr is able to return a subtype.
169279
-**
169280
-** A TRUE return does not guarantee that a subtype will be returned.
169281
-** It only indicates that a subtype return is possible. False positives
169282
-** are acceptable as they only disable an optimization. False negatives,
169283
-** on the other hand, can lead to incorrect answers.
169284
-*/
169285
-static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
169286
- Walker w;
169287
- memset(&w, 0, sizeof(w));
169288
- w.pParse = pParse;
169289
- w.xExprCallback = exprNodeCanReturnSubtype;
169290
- sqlite3WalkExpr(&w, pExpr);
169291
- return w.eCode;
169292
-}
169293
-
169294169579
/*
169295169580
** The index pIdx is used by a query and contains one or more expressions.
169296169581
** In other words pIdx is an index on an expression. iIdxCur is the cursor
169297169582
** number for the index and iDataCur is the cursor number for the corresponding
169298169583
** table.
@@ -169322,16 +169607,10 @@
169322169607
pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
169323169608
}else{
169324169609
continue;
169325169610
}
169326169611
if( sqlite3ExprIsConstant(0,pExpr) ) continue;
169327
- if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){
169328
- /* Functions that might set a subtype should not be replaced by the
169329
- ** value taken from an expression index since the index omits the
169330
- ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
169331
- continue;
169332
- }
169333169612
p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
169334169613
if( p==0 ) break;
169335169614
p->pIENext = pParse->pIdxEpr;
169336169615
#ifdef WHERETRACE_ENABLED
169337169616
if( sqlite3WhereTrace & 0x200 ){
@@ -170434,18 +170713,32 @@
170434170713
x = sqlite3TableColumnToIndex(pIdx, x);
170435170714
if( x>=0 ){
170436170715
pOp->p2 = x;
170437170716
pOp->p1 = pLevel->iIdxCur;
170438170717
OpcodeRewriteTrace(db, k, pOp);
170439
- }else{
170440
- /* Unable to translate the table reference into an index
170441
- ** reference. Verify that this is harmless - that the
170442
- ** table being referenced really is open.
170443
- */
170718
+ }else if( pLoop->wsFlags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){
170444170719
if( pLoop->wsFlags & WHERE_IDX_ONLY ){
170720
+ /* An error. pLoop is supposed to be a covering index loop,
170721
+ ** and yet the VM code refers to a column of the table that
170722
+ ** is not part of the index. */
170445170723
sqlite3ErrorMsg(pParse, "internal query planner error");
170446170724
pParse->rc = SQLITE_INTERNAL;
170725
+ }else{
170726
+ /* The WHERE_EXPRIDX flag is set by the planner when it is likely
170727
+ ** that pLoop is a covering index loop, but it is not possible
170728
+ ** to be 100% sure. In this case, any OP_Explain opcode
170729
+ ** corresponding to this loop describes the index as a "COVERING
170730
+ ** INDEX". But, pOp proves that pLoop is not actually a covering
170731
+ ** index loop. So clear the WHERE_EXPRIDX flag and rewrite the
170732
+ ** text that accompanies the OP_Explain opcode, if any. */
170733
+ pLoop->wsFlags &= ~WHERE_EXPRIDX;
170734
+ sqlite3WhereAddExplainText(pParse,
170735
+ pLevel->addrBody-1,
170736
+ pTabList,
170737
+ pLevel,
170738
+ pWInfo->wctrlFlags
170739
+ );
170447170740
}
170448170741
}
170449170742
}else if( pOp->opcode==OP_Rowid ){
170450170743
pOp->p1 = pLevel->iIdxCur;
170451170744
pOp->opcode = OP_IdxRowid;
@@ -172149,10 +172442,11 @@
172149172442
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
172150172443
FuncDef *pFunc = pWin->pWFunc;
172151172444
int regArg;
172152172445
int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
172153172446
int i;
172447
+ int addrIf = 0;
172154172448
172155172449
assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
172156172450
172157172451
/* All OVER clauses in the same window function aggregate step must
172158172452
** be the same. */
@@ -172164,10 +172458,22 @@
172164172458
}else{
172165172459
sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
172166172460
}
172167172461
}
172168172462
regArg = reg;
172463
+
172464
+ if( pWin->pFilter ){
172465
+ int regTmp;
172466
+ assert( ExprUseXList(pWin->pOwner) );
172467
+ assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
172468
+ assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
172469
+ regTmp = sqlite3GetTempReg(pParse);
172470
+ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
172471
+ addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
172472
+ VdbeCoverage(v);
172473
+ sqlite3ReleaseTempReg(pParse, regTmp);
172474
+ }
172169172475
172170172476
if( pMWin->regStartRowid==0
172171172477
&& (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
172172172478
&& (pWin->eStart!=TK_UNBOUNDED)
172173172479
){
@@ -172184,29 +172490,17 @@
172184172490
sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
172185172491
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
172186172492
}
172187172493
sqlite3VdbeJumpHere(v, addrIsNull);
172188172494
}else if( pWin->regApp ){
172495
+ assert( pWin->pFilter==0 );
172189172496
assert( pFunc->zName==nth_valueName
172190172497
|| pFunc->zName==first_valueName
172191172498
);
172192172499
assert( bInverse==0 || bInverse==1 );
172193172500
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
172194172501
}else if( pFunc->xSFunc!=noopStepFunc ){
172195
- int addrIf = 0;
172196
- if( pWin->pFilter ){
172197
- int regTmp;
172198
- assert( ExprUseXList(pWin->pOwner) );
172199
- assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
172200
- assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
172201
- regTmp = sqlite3GetTempReg(pParse);
172202
- sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
172203
- addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
172204
- VdbeCoverage(v);
172205
- sqlite3ReleaseTempReg(pParse, regTmp);
172206
- }
172207
-
172208172502
if( pWin->bExprArgs ){
172209172503
int iOp = sqlite3VdbeCurrentAddr(v);
172210172504
int iEnd;
172211172505
172212172506
assert( ExprUseXList(pWin->pOwner) );
@@ -172233,12 +172527,13 @@
172233172527
sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
172234172528
sqlite3VdbeChangeP5(v, (u8)nArg);
172235172529
if( pWin->bExprArgs ){
172236172530
sqlite3ReleaseTempRange(pParse, regArg, nArg);
172237172531
}
172238
- if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
172239172532
}
172533
+
172534
+ if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
172240172535
}
172241172536
}
172242172537
172243172538
/*
172244172539
** Values that may be passed as the second argument to windowCodeOp().
@@ -173660,10 +173955,17 @@
173660173955
** Then the "b" IdList records the list "a,b,c".
173661173956
*/
173662173957
struct TrigEvent { int a; IdList * b; };
173663173958
173664173959
struct FrameBound { int eType; Expr *pExpr; };
173960
+
173961
+/*
173962
+** Generate a syntax error
173963
+*/
173964
+static void parserSyntaxError(Parse *pParse, Token *p){
173965
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", p);
173966
+}
173665173967
173666173968
/*
173667173969
** Disable lookaside memory allocation for objects that might be
173668173970
** shared across database connections.
173669173971
*/
@@ -177553,11 +177855,15 @@
177553177855
}
177554177856
break;
177555177857
case 84: /* cmd ::= select */
177556177858
{
177557177859
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
177558
- sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
177860
+ if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0
177861
+ || sqlite3ReadSchema(pParse)==SQLITE_OK
177862
+ ){
177863
+ sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
177864
+ }
177559177865
sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
177560177866
}
177561177867
break;
177562177868
case 85: /* select ::= WITH wqlist selectnowith */
177563177869
{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
@@ -178024,11 +178330,11 @@
178024178330
** that look like this: #1 #2 ... These terms refer to registers
178025178331
** in the virtual machine. #N is the N-th register. */
178026178332
Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
178027178333
assert( t.n>=2 );
178028178334
if( pParse->nested==0 ){
178029
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
178335
+ parserSyntaxError(pParse, &t);
178030178336
yymsp[0].minor.yy454 = 0;
178031178337
}else{
178032178338
yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
178033178339
if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
178034178340
}
@@ -178872,11 +179178,11 @@
178872179178
#define TOKEN yyminor
178873179179
/************ Begin %syntax_error code ****************************************/
178874179180
178875179181
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
178876179182
if( TOKEN.z[0] ){
178877
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
179183
+ parserSyntaxError(pParse, &TOKEN);
178878179184
}else{
178879179185
sqlite3ErrorMsg(pParse, "incomplete input");
178880179186
}
178881179187
/************ End %syntax_error code ******************************************/
178882179188
sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
@@ -180363,11 +180669,13 @@
180363180669
}
180364180670
if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
180365180671
if( pParse->zErrMsg==0 ){
180366180672
pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
180367180673
}
180368
- sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
180674
+ if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){
180675
+ sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
180676
+ }
180369180677
nErr++;
180370180678
}
180371180679
pParse->zTail = zSql;
180372180680
#ifndef SQLITE_OMIT_VIRTUALTABLE
180373180681
sqlite3_free(pParse->apVtabLock);
@@ -181071,36 +181379,10 @@
181071181379
** all database files specified with a relative pathname.
181072181380
**
181073181381
** See also the "PRAGMA data_store_directory" SQL command.
181074181382
*/
181075181383
SQLITE_API char *sqlite3_data_directory = 0;
181076
-
181077
-/*
181078
-** Determine whether or not high-precision (long double) floating point
181079
-** math works correctly on CPU currently running.
181080
-*/
181081
-static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){
181082
- if( sizeof(LONGDOUBLE_TYPE)<=8 ){
181083
- /* If the size of "long double" is not more than 8, then
181084
- ** high-precision math is not possible. */
181085
- return 0;
181086
- }else{
181087
- /* Just because sizeof(long double)>8 does not mean that the underlying
181088
- ** hardware actually supports high-precision floating point. For example,
181089
- ** clearing the 0x100 bit in the floating-point control word on Intel
181090
- ** processors will make long double work like double, even though long
181091
- ** double takes up more space. The only way to determine if long double
181092
- ** actually works is to run an experiment. */
181093
- LONGDOUBLE_TYPE a, b, c;
181094
- rc++;
181095
- a = 1.0+rc*0.1;
181096
- b = 1.0e+18+rc*25.0;
181097
- c = a+b;
181098
- return b!=c;
181099
- }
181100
-}
181101
-
181102181384
181103181385
/*
181104181386
** Initialize SQLite.
181105181387
**
181106181388
** This routine must be called to initialize the memory allocation,
@@ -181292,17 +181574,10 @@
181292181574
if( bRunExtraInit ){
181293181575
int SQLITE_EXTRA_INIT(const char*);
181294181576
rc = SQLITE_EXTRA_INIT(0);
181295181577
}
181296181578
#endif
181297
-
181298
- /* Experimentally determine if high-precision floating point is
181299
- ** available. */
181300
-#ifndef SQLITE_OMIT_WSD
181301
- sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc);
181302
-#endif
181303
-
181304181579
return rc;
181305181580
}
181306181581
181307181582
/*
181308181583
** Undo the effects of sqlite3_initialize(). Must not be called while
@@ -182369,14 +182644,10 @@
182369182644
#endif
182370182645
182371182646
sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
182372182647
sqlite3ValueFree(db->pErr);
182373182648
sqlite3CloseExtensions(db);
182374
-#if SQLITE_USER_AUTHENTICATION
182375
- sqlite3_free(db->auth.zAuthUser);
182376
- sqlite3_free(db->auth.zAuthPW);
182377
-#endif
182378182649
182379182650
db->eOpenState = SQLITE_STATE_ERROR;
182380182651
182381182652
/* The temp-database schema is allocated differently from the other schema
182382182653
** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
@@ -183875,12 +184146,12 @@
183875184146
}
183876184147
oldLimit = db->aLimit[limitId];
183877184148
if( newLimit>=0 ){ /* IMP: R-52476-28732 */
183878184149
if( newLimit>aHardLimit[limitId] ){
183879184150
newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
183880
- }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
183881
- newLimit = 1;
184151
+ }else if( newLimit<SQLITE_MIN_LENGTH && limitId==SQLITE_LIMIT_LENGTH ){
184152
+ newLimit = SQLITE_MIN_LENGTH;
183882184153
}
183883184154
db->aLimit[limitId] = newLimit;
183884184155
}
183885184156
return oldLimit; /* IMP: R-53341-35419 */
183886184157
}
@@ -184395,10 +184666,11 @@
184395184666
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
184396184667
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
184397184668
if( ((1<<(flags&7)) & 0x46)==0 ){
184398184669
rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
184399184670
}else{
184671
+ if( zFilename==0 ) zFilename = ":memory:";
184400184672
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
184401184673
}
184402184674
if( rc!=SQLITE_OK ){
184403184675
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
184404184676
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
@@ -185237,10 +185509,11 @@
185237185509
#ifndef SQLITE_OMIT_WINDOWFUNC
185238185510
sqlite3ShowWindow(0);
185239185511
sqlite3ShowWinFunc(0);
185240185512
#endif
185241185513
sqlite3ShowSelect(0);
185514
+ sqlite3ShowWhereTerm(0);
185242185515
}
185243185516
#endif
185244185517
break;
185245185518
}
185246185519
@@ -185549,28 +185822,10 @@
185549185822
*pI1 = rLogEst;
185550185823
*pU64 = sqlite3LogEstToInt(rLogEst);
185551185824
*pI2 = sqlite3LogEst(*pU64);
185552185825
break;
185553185826
}
185554
-
185555
-#if !defined(SQLITE_OMIT_WSD)
185556
- /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
185557
- **
185558
- ** X<0 Make no changes to the bUseLongDouble. Just report value.
185559
- ** X==0 Disable bUseLongDouble
185560
- ** X==1 Enable bUseLongDouble
185561
- ** X>=2 Set bUseLongDouble to its default value for this platform
185562
- */
185563
- case SQLITE_TESTCTRL_USELONGDOUBLE: {
185564
- int b = va_arg(ap, int);
185565
- if( b>=2 ) b = hasHighPrecisionDouble(b);
185566
- if( b>=0 ) sqlite3Config.bUseLongDouble = b>0;
185567
- rc = sqlite3Config.bUseLongDouble!=0;
185568
- break;
185569
- }
185570
-#endif
185571
-
185572185827
185573185828
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
185574185829
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
185575185830
**
185576185831
** If "id" is an integer between 1 and SQLITE_NTUNE then set the value
@@ -185875,11 +186130,15 @@
185875186130
if( db->autoCommit==0 ){
185876186131
int iDb = sqlite3FindDbName(db, zDb);
185877186132
if( iDb==0 || iDb>1 ){
185878186133
Btree *pBt = db->aDb[iDb].pBt;
185879186134
if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
186135
+ Pager *pPager = sqlite3BtreePager(pBt);
186136
+ i64 dummy = 0;
186137
+ sqlite3PagerSnapshotOpen(pPager, (sqlite3_snapshot*)&dummy);
185880186138
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
186139
+ sqlite3PagerSnapshotOpen(pPager, 0);
185881186140
if( rc==SQLITE_OK ){
185882186141
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
185883186142
}
185884186143
}
185885186144
}
@@ -189665,14 +189924,19 @@
189665189924
189666189925
assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
189667189926
if( *p1==POS_COLUMN ){
189668189927
p1++;
189669189928
p1 += fts3GetVarint32(p1, &iCol1);
189929
+ /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN
189930
+ ** entry, so this is actually end-of-doclist. */
189931
+ if( iCol1==0 ) return 0;
189670189932
}
189671189933
if( *p2==POS_COLUMN ){
189672189934
p2++;
189673189935
p2 += fts3GetVarint32(p2, &iCol2);
189936
+ /* As above, iCol2==0 indicates corruption. */
189937
+ if( iCol2==0 ) return 0;
189674189938
}
189675189939
189676189940
while( 1 ){
189677189941
if( iCol1==iCol2 ){
189678189942
char *pSave = p;
@@ -192839,11 +193103,11 @@
192839193103
for(p=pExpr; p->pLeft; p=p->pLeft){
192840193104
assert( p->pRight->pPhrase->doclist.nList>0 );
192841193105
nTmp += p->pRight->pPhrase->doclist.nList;
192842193106
}
192843193107
nTmp += p->pPhrase->doclist.nList;
192844
- aTmp = sqlite3_malloc64(nTmp*2);
193108
+ aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX);
192845193109
if( !aTmp ){
192846193110
*pRc = SQLITE_NOMEM;
192847193111
res = 0;
192848193112
}else{
192849193113
char *aPoslist = p->pPhrase->doclist.pList;
@@ -193490,11 +193754,11 @@
193490193754
SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
193491193755
return SQLITE_CORRUPT_VTAB;
193492193756
}
193493193757
#endif
193494193758
193495
-#if !SQLITE_CORE
193759
+#if !defined(SQLITE_CORE)
193496193760
/*
193497193761
** Initialize API pointer table, if required.
193498193762
*/
193499193763
#ifdef _WIN32
193500193764
__declspec(dllexport)
@@ -194392,14 +194656,15 @@
194392194656
rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
194393194657
if( rc==SQLITE_OK ){
194394194658
Fts3PhraseToken *pToken;
194395194659
194396194660
p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
194397
- if( !p ) goto no_mem;
194398
-
194399194661
zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
194400
- if( !zTemp ) goto no_mem;
194662
+ if( !zTemp || !p ){
194663
+ rc = SQLITE_NOMEM;
194664
+ goto getnextstring_out;
194665
+ }
194401194666
194402194667
assert( nToken==ii );
194403194668
pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
194404194669
memset(pToken, 0, sizeof(Fts3PhraseToken));
194405194670
@@ -194410,53 +194675,51 @@
194410194675
pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
194411194676
pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
194412194677
nToken = ii+1;
194413194678
}
194414194679
}
194415
-
194416
- pModule->xClose(pCursor);
194417
- pCursor = 0;
194418194680
}
194419194681
194420194682
if( rc==SQLITE_DONE ){
194421194683
int jj;
194422194684
char *zBuf = 0;
194423194685
194424194686
p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
194425
- if( !p ) goto no_mem;
194687
+ if( !p ){
194688
+ rc = SQLITE_NOMEM;
194689
+ goto getnextstring_out;
194690
+ }
194426194691
memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
194427194692
p->eType = FTSQUERY_PHRASE;
194428194693
p->pPhrase = (Fts3Phrase *)&p[1];
194429194694
p->pPhrase->iColumn = pParse->iDefaultCol;
194430194695
p->pPhrase->nToken = nToken;
194431194696
194432194697
zBuf = (char *)&p->pPhrase->aToken[nToken];
194698
+ assert( nTemp==0 || zTemp );
194433194699
if( zTemp ){
194434194700
memcpy(zBuf, zTemp, nTemp);
194435
- sqlite3_free(zTemp);
194436
- }else{
194437
- assert( nTemp==0 );
194438194701
}
194439194702
194440194703
for(jj=0; jj<p->pPhrase->nToken; jj++){
194441194704
p->pPhrase->aToken[jj].z = zBuf;
194442194705
zBuf += p->pPhrase->aToken[jj].n;
194443194706
}
194444194707
rc = SQLITE_OK;
194445194708
}
194446194709
194447
- *ppExpr = p;
194448
- return rc;
194449
-no_mem:
194450
-
194710
+ getnextstring_out:
194451194711
if( pCursor ){
194452194712
pModule->xClose(pCursor);
194453194713
}
194454194714
sqlite3_free(zTemp);
194455
- sqlite3_free(p);
194456
- *ppExpr = 0;
194457
- return SQLITE_NOMEM;
194715
+ if( rc!=SQLITE_OK ){
194716
+ sqlite3_free(p);
194717
+ p = 0;
194718
+ }
194719
+ *ppExpr = p;
194720
+ return rc;
194458194721
}
194459194722
194460194723
/*
194461194724
** The output variable *ppExpr is populated with an allocated Fts3Expr
194462194725
** structure, or set to 0 if the end of the input buffer is reached.
@@ -208867,11 +209130,13 @@
208867209130
int rawKey = 1;
208868209131
x = pParse->aBlob[iRoot];
208869209132
zPath++;
208870209133
if( zPath[0]=='"' ){
208871209134
zKey = zPath + 1;
208872
- for(i=1; zPath[i] && zPath[i]!='"'; i++){}
209135
+ for(i=1; zPath[i] && zPath[i]!='"'; i++){
209136
+ if( zPath[i]=='\\' && zPath[i+1]!=0 ) i++;
209137
+ }
208873209138
nKey = i-1;
208874209139
if( zPath[i] ){
208875209140
i++;
208876209141
}else{
208877209142
return JSON_LOOKUP_PATHERROR;
@@ -217779,11 +218044,11 @@
217779218044
return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
217780218045
(void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
217781218046
);
217782218047
}
217783218048
217784
-#if !SQLITE_CORE
218049
+#ifndef SQLITE_CORE
217785218050
#ifdef _WIN32
217786218051
__declspec(dllexport)
217787218052
#endif
217788218053
SQLITE_API int sqlite3_rtree_init(
217789218054
sqlite3 *db,
@@ -218370,11 +218635,11 @@
218370218635
}
218371218636
218372218637
return rc;
218373218638
}
218374218639
218375
-#if !SQLITE_CORE
218640
+#ifndef SQLITE_CORE
218376218641
#ifdef _WIN32
218377218642
__declspec(dllexport)
218378218643
#endif
218379218644
SQLITE_API int sqlite3_icu_init(
218380218645
sqlite3 *db,
@@ -219628,10 +219893,31 @@
219628219893
struct RbuFrame {
219629219894
u32 iDbPage;
219630219895
u32 iWalFrame;
219631219896
};
219632219897
219898
+#ifndef UNUSED_PARAMETER
219899
+/*
219900
+** The following macros are used to suppress compiler warnings and to
219901
+** make it clear to human readers when a function parameter is deliberately
219902
+** left unused within the body of a function. This usually happens when
219903
+** a function is called via a function pointer. For example the
219904
+** implementation of an SQL aggregate step callback may not use the
219905
+** parameter indicating the number of arguments passed to the aggregate,
219906
+** if it knows that this is enforced elsewhere.
219907
+**
219908
+** When a function parameter is not used at all within the body of a function,
219909
+** it is generally named "NotUsed" or "NotUsed2" to make things even clearer.
219910
+** However, these macros may also be used to suppress warnings related to
219911
+** parameters that may or may not be used depending on compilation options.
219912
+** For example those parameters only used in assert() statements. In these
219913
+** cases the parameters are named as per the usual conventions.
219914
+*/
219915
+#define UNUSED_PARAMETER(x) (void)(x)
219916
+#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
219917
+#endif
219918
+
219633219919
/*
219634219920
** RBU handle.
219635219921
**
219636219922
** nPhaseOneStep:
219637219923
** If the RBU database contains an rbu_count table, this value is set to
@@ -219679,11 +219965,11 @@
219679219965
char *zState; /* Path to state db (or NULL if zRbu) */
219680219966
char zStateDb[5]; /* Db name for state ("stat" or "main") */
219681219967
int rc; /* Value returned by last rbu_step() call */
219682219968
char *zErrmsg; /* Error message if rc!=SQLITE_OK */
219683219969
int nStep; /* Rows processed for current object */
219684
- int nProgress; /* Rows processed for all objects */
219970
+ sqlite3_int64 nProgress; /* Rows processed for all objects */
219685219971
RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
219686219972
const char *zVfsName; /* Name of automatically created rbu vfs */
219687219973
rbu_file *pTargetFd; /* File handle open on target db */
219688219974
int nPagePerSector; /* Pages per sector for pTargetFd */
219689219975
i64 iOalSz;
@@ -219796,11 +220082,11 @@
219796220082
unsigned char *zStart = z;
219797220083
while( (c = zValue[0x7f&*(z++)])>=0 ){
219798220084
v = (v<<6) + c;
219799220085
}
219800220086
z--;
219801
- *pLen -= z - zStart;
220087
+ *pLen -= (int)(z - zStart);
219802220088
*pz = (char*)z;
219803220089
return v;
219804220090
}
219805220091
219806220092
#if RBU_ENABLE_DELTA_CKSUM
@@ -219981,10 +220267,11 @@
219981220267
int nOut;
219982220268
int nOut2;
219983220269
char *aOut;
219984220270
219985220271
assert( argc==2 );
220272
+ UNUSED_PARAMETER(argc);
219986220273
219987220274
nOrig = sqlite3_value_bytes(argv[0]);
219988220275
aOrig = (const char*)sqlite3_value_blob(argv[0]);
219989220276
nDelta = sqlite3_value_bytes(argv[1]);
219990220277
aDelta = (const char*)sqlite3_value_blob(argv[1]);
@@ -221560,17 +221847,17 @@
221560221847
nParen++;
221561221848
}
221562221849
else if( c==')' ){
221563221850
nParen--;
221564221851
if( nParen==0 ){
221565
- int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
221852
+ int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
221566221853
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
221567221854
i++;
221568221855
break;
221569221856
}
221570221857
}else if( c==',' && nParen==1 ){
221571
- int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
221858
+ int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
221572221859
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
221573221860
pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
221574221861
}else if( c=='"' || c=='\'' || c=='`' ){
221575221862
for(i++; 1; i++){
221576221863
if( zSql[i]==c ){
@@ -222256,10 +222543,12 @@
222256222543
int i, sz;
222257222544
sz = (int)strlen(z)&0xffffff;
222258222545
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
222259222546
if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
222260222547
}
222548
+#else
222549
+ UNUSED_PARAMETER2(zBase,z);
222261222550
#endif
222262222551
}
222263222552
222264222553
/*
222265222554
** Return the current wal-index header checksum for the target database
@@ -222840,11 +223129,11 @@
222840223129
"INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
222841223130
"(%d, %d), "
222842223131
"(%d, %Q), "
222843223132
"(%d, %Q), "
222844223133
"(%d, %d), "
222845
- "(%d, %d), "
223134
+ "(%d, %lld), "
222846223135
"(%d, %lld), "
222847223136
"(%d, %lld), "
222848223137
"(%d, %lld), "
222849223138
"(%d, %lld), "
222850223139
"(%d, %Q) ",
@@ -223198,10 +223487,11 @@
223198223487
char *zErrmsg = 0;
223199223488
int rc;
223200223489
sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
223201223490
223202223491
assert( nVal==1 );
223492
+ UNUSED_PARAMETER(nVal);
223203223493
223204223494
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
223205223495
sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
223206223496
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
223207223497
);
@@ -223473,11 +223763,11 @@
223473223763
const char *zTarget,
223474223764
const char *zState
223475223765
){
223476223766
if( zTarget==0 ){ return rbuMisuseError(); }
223477223767
if( zState ){
223478
- int n = strlen(zState);
223768
+ size_t n = strlen(zState);
223479223769
if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
223480223770
return rbuMisuseError();
223481223771
}
223482223772
}
223483223773
/* TODO: Check that both arguments are non-NULL */
@@ -223690,10 +223980,11 @@
223690223980
/*
223691223981
** Default xRename callback for RBU.
223692223982
*/
223693223983
static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
223694223984
int rc = SQLITE_OK;
223985
+ UNUSED_PARAMETER(pArg);
223695223986
#if defined(_WIN32_WCE)
223696223987
{
223697223988
LPWSTR zWideOld;
223698223989
LPWSTR zWideNew;
223699223990
@@ -224594,10 +224885,13 @@
224594224885
224595224886
/*
224596224887
** No-op.
224597224888
*/
224598224889
static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
224890
+ UNUSED_PARAMETER(pVfs);
224891
+ UNUSED_PARAMETER(a);
224892
+ UNUSED_PARAMETER(b);
224599224893
return 0;
224600224894
}
224601224895
224602224896
/*
224603224897
** Deregister and destroy an RBU vfs created by an earlier call to
@@ -225650,11 +225944,17 @@
225650225944
** schema for the database file that is to be read. The default schema is
225651225945
** "main".
225652225946
**
225653225947
** The data field of sqlite_dbpage table can be updated. The new
225654225948
** value must be a BLOB which is the correct page size, otherwise the
225655
-** update fails. Rows may not be deleted or inserted.
225949
+** update fails. INSERT operations also work, and operate as if they
225950
+** where REPLACE. The size of the database can be extended by INSERT-ing
225951
+** new pages on the end.
225952
+**
225953
+** Rows may not be deleted. However, doing an INSERT to page number N
225954
+** with NULL page data causes the N-th page and all subsequent pages to be
225955
+** deleted and the database to be truncated.
225656225956
*/
225657225957
225658225958
/* #include "sqliteInt.h" ** Requires access to internal data structures ** */
225659225959
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
225660225960
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -225673,17 +225973,18 @@
225673225973
};
225674225974
225675225975
struct DbpageTable {
225676225976
sqlite3_vtab base; /* Base class. Must be first */
225677225977
sqlite3 *db; /* The database */
225978
+ int iDbTrunc; /* Database to truncate */
225979
+ Pgno pgnoTrunc; /* Size to truncate to */
225678225980
};
225679225981
225680225982
/* Columns */
225681225983
#define DBPAGE_COLUMN_PGNO 0
225682225984
#define DBPAGE_COLUMN_DATA 1
225683225985
#define DBPAGE_COLUMN_SCHEMA 2
225684
-
225685225986
225686225987
225687225988
/*
225688225989
** Connect to or create a dbpagevfs virtual table.
225689225990
*/
@@ -225943,15 +226244,15 @@
225943226244
DbpageTable *pTab = (DbpageTable *)pVtab;
225944226245
Pgno pgno;
225945226246
DbPage *pDbPage = 0;
225946226247
int rc = SQLITE_OK;
225947226248
char *zErr = 0;
225948
- const char *zSchema;
225949226249
int iDb;
225950226250
Btree *pBt;
225951226251
Pager *pPager;
225952226252
int szPage;
226253
+ int isInsert;
225953226254
225954226255
(void)pRowid;
225955226256
if( pTab->db->flags & SQLITE_Defensive ){
225956226257
zErr = "read-only";
225957226258
goto update_fail;
@@ -225958,45 +226259,62 @@
225958226259
}
225959226260
if( argc==1 ){
225960226261
zErr = "cannot delete";
225961226262
goto update_fail;
225962226263
}
225963
- pgno = sqlite3_value_int(argv[0]);
225964
- if( sqlite3_value_type(argv[0])==SQLITE_NULL
225965
- || (Pgno)sqlite3_value_int(argv[1])!=pgno
225966
- ){
225967
- zErr = "cannot insert";
225968
- goto update_fail;
225969
- }
225970
- zSchema = (const char*)sqlite3_value_text(argv[4]);
225971
- iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1;
225972
- if( NEVER(iDb<0) ){
225973
- zErr = "no such schema";
225974
- goto update_fail;
226264
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
226265
+ pgno = (Pgno)sqlite3_value_int(argv[2]);
226266
+ isInsert = 1;
226267
+ }else{
226268
+ pgno = sqlite3_value_int(argv[0]);
226269
+ if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
226270
+ zErr = "cannot insert";
226271
+ goto update_fail;
226272
+ }
226273
+ isInsert = 0;
226274
+ }
226275
+ if( sqlite3_value_type(argv[4])==SQLITE_NULL ){
226276
+ iDb = 0;
226277
+ }else{
226278
+ const char *zSchema = (const char*)sqlite3_value_text(argv[4]);
226279
+ iDb = sqlite3FindDbName(pTab->db, zSchema);
226280
+ if( iDb<0 ){
226281
+ zErr = "no such schema";
226282
+ goto update_fail;
226283
+ }
225975226284
}
225976226285
pBt = pTab->db->aDb[iDb].pBt;
225977
- if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){
226286
+ if( pgno<1 || NEVER(pBt==0) ){
225978226287
zErr = "bad page number";
225979226288
goto update_fail;
225980226289
}
225981226290
szPage = sqlite3BtreeGetPageSize(pBt);
225982226291
if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
225983226292
|| sqlite3_value_bytes(argv[3])!=szPage
225984226293
){
225985
- zErr = "bad page value";
225986
- goto update_fail;
226294
+ if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){
226295
+ /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and
226296
+ ** all subsequent pages to be deleted. */
226297
+ pTab->iDbTrunc = iDb;
226298
+ pgno--;
226299
+ pTab->pgnoTrunc = pgno;
226300
+ }else{
226301
+ zErr = "bad page value";
226302
+ goto update_fail;
226303
+ }
225987226304
}
225988226305
pPager = sqlite3BtreePager(pBt);
225989226306
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
225990226307
if( rc==SQLITE_OK ){
225991226308
const void *pData = sqlite3_value_blob(argv[3]);
225992
- assert( pData!=0 || pTab->db->mallocFailed );
225993
- if( pData
225994
- && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
225995
- ){
225996
- memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
226309
+ if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
226310
+ unsigned char *aPage = sqlite3PagerGetData(pDbPage);
226311
+ memcpy(aPage, pData, szPage);
226312
+ pTab->pgnoTrunc = 0;
225997226313
}
226314
+ }else{
226315
+ pTab->pgnoTrunc = 0;
225998226316
}
225999226317
sqlite3PagerUnref(pDbPage);
226000226318
return rc;
226001226319
226002226320
update_fail:
@@ -226015,13 +226333,35 @@
226015226333
int i;
226016226334
for(i=0; i<db->nDb; i++){
226017226335
Btree *pBt = db->aDb[i].pBt;
226018226336
if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
226019226337
}
226338
+ pTab->pgnoTrunc = 0;
226339
+ return SQLITE_OK;
226340
+}
226341
+
226342
+/* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT
226343
+*/
226344
+static int dbpageSync(sqlite3_vtab *pVtab){
226345
+ DbpageTable *pTab = (DbpageTable *)pVtab;
226346
+ if( pTab->pgnoTrunc>0 ){
226347
+ Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt;
226348
+ Pager *pPager = sqlite3BtreePager(pBt);
226349
+ sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc);
226350
+ }
226351
+ pTab->pgnoTrunc = 0;
226352
+ return SQLITE_OK;
226353
+}
226354
+
226355
+/* Cancel any pending truncate.
226356
+*/
226357
+static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){
226358
+ DbpageTable *pTab = (DbpageTable *)pVtab;
226359
+ pTab->pgnoTrunc = 0;
226360
+ (void)notUsed1;
226020226361
return SQLITE_OK;
226021226362
}
226022
-
226023226363
226024226364
/*
226025226365
** Invoke this routine to register the "dbpage" virtual table module
226026226366
*/
226027226367
SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
@@ -226039,18 +226379,18 @@
226039226379
dbpageEof, /* xEof - check for end of scan */
226040226380
dbpageColumn, /* xColumn - read data */
226041226381
dbpageRowid, /* xRowid - read data */
226042226382
dbpageUpdate, /* xUpdate */
226043226383
dbpageBegin, /* xBegin */
226044
- 0, /* xSync */
226384
+ dbpageSync, /* xSync */
226045226385
0, /* xCommit */
226046226386
0, /* xRollback */
226047226387
0, /* xFindMethod */
226048226388
0, /* xRename */
226049226389
0, /* xSavepoint */
226050226390
0, /* xRelease */
226051
- 0, /* xRollbackTo */
226391
+ dbpageRollbackTo, /* xRollbackTo */
226052226392
0, /* xShadowName */
226053226393
0 /* xIntegrity */
226054226394
};
226055226395
return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
226056226396
}
@@ -226134,10 +226474,14 @@
226134226474
/*
226135226475
** An object of this type is used internally as an abstraction for
226136226476
** input data. Input data may be supplied either as a single large buffer
226137226477
** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
226138226478
** sqlite3changeset_start_strm()).
226479
+**
226480
+** bNoDiscard:
226481
+** If true, then the only time data is discarded is as a result of explicit
226482
+** sessionDiscardData() calls. Not within every sessionInputBuffer() call.
226139226483
*/
226140226484
struct SessionInput {
226141226485
int bNoDiscard; /* If true, do not discard in InputBuffer() */
226142226486
int iCurrent; /* Offset in aData[] of current change */
226143226487
int iNext; /* Offset in aData[] of next change */
@@ -227817,20 +228161,23 @@
227817228161
/* Figure out how large an allocation is required */
227818228162
nByte = sizeof(SessionChange);
227819228163
for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
227820228164
sqlite3_value *p = 0;
227821228165
if( op!=SQLITE_INSERT ){
227822
- TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
227823
- assert( trc==SQLITE_OK );
228166
+ /* This may fail if the column has a non-NULL default and was added
228167
+ ** using ALTER TABLE ADD COLUMN after this record was created. */
228168
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
227824228169
}else if( pTab->abPK[i] ){
227825228170
TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
227826228171
assert( trc==SQLITE_OK );
227827228172
}
227828228173
227829
- /* This may fail if SQLite value p contains a utf-16 string that must
227830
- ** be converted to utf-8 and an OOM error occurs while doing so. */
227831
- rc = sessionSerializeValue(0, p, &nByte);
228174
+ if( rc==SQLITE_OK ){
228175
+ /* This may fail if SQLite value p contains a utf-16 string that must
228176
+ ** be converted to utf-8 and an OOM error occurs while doing so. */
228177
+ rc = sessionSerializeValue(0, p, &nByte);
228178
+ }
227832228179
if( rc!=SQLITE_OK ) goto error_out;
227833228180
}
227834228181
if( pTab->bRowid ){
227835228182
nByte += 9; /* Size of rowid field - an integer */
227836228183
}
@@ -231184,19 +231531,25 @@
231184231531
int rc = SQLITE_OK; /* Return code */
231185231532
const char *zTab = 0; /* Name of current table */
231186231533
int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
231187231534
SessionApplyCtx sApply; /* changeset_apply() context object */
231188231535
int bPatchset;
231536
+ u64 savedFlag = db->flags & SQLITE_FkNoAction;
231189231537
231190231538
assert( xConflict!=0 );
231539
+
231540
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
231541
+ if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
231542
+ db->flags |= ((u64)SQLITE_FkNoAction);
231543
+ db->aDb[0].pSchema->schema_cookie -= 32;
231544
+ }
231191231545
231192231546
pIter->in.bNoDiscard = 1;
231193231547
memset(&sApply, 0, sizeof(sApply));
231194231548
sApply.bRebase = (ppRebase && pnRebase);
231195231549
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
231196231550
sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
231197
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
231198231551
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
231199231552
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
231200231553
}
231201231554
if( rc==SQLITE_OK ){
231202231555
rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
@@ -231354,10 +231707,16 @@
231354231707
sqlite3_finalize(sApply.pDelete);
231355231708
sqlite3_finalize(sApply.pSelect);
231356231709
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
231357231710
sqlite3_free((char*)sApply.constraints.aBuf);
231358231711
sqlite3_free((char*)sApply.rebase.aBuf);
231712
+
231713
+ if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
231714
+ assert( db->flags & SQLITE_FkNoAction );
231715
+ db->flags &= ~((u64)SQLITE_FkNoAction);
231716
+ db->aDb[0].pSchema->schema_cookie -= 32;
231717
+ }
231359231718
sqlite3_mutex_leave(sqlite3_db_mutex(db));
231360231719
return rc;
231361231720
}
231362231721
231363231722
/*
@@ -231382,28 +231741,17 @@
231382231741
int flags
231383231742
){
231384231743
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
231385231744
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
231386231745
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
231387
- u64 savedFlag = db->flags & SQLITE_FkNoAction;
231388
-
231389
- if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
231390
- db->flags |= ((u64)SQLITE_FkNoAction);
231391
- db->aDb[0].pSchema->schema_cookie -= 32;
231392
- }
231393231746
231394231747
if( rc==SQLITE_OK ){
231395231748
rc = sessionChangesetApply(
231396231749
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
231397231750
);
231398231751
}
231399231752
231400
- if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
231401
- assert( db->flags & SQLITE_FkNoAction );
231402
- db->flags &= ~((u64)SQLITE_FkNoAction);
231403
- db->aDb[0].pSchema->schema_cookie -= 32;
231404
- }
231405231753
return rc;
231406231754
}
231407231755
231408231756
/*
231409231757
** Apply the changeset passed via pChangeset/nChangeset to the main database
@@ -231720,10 +232068,13 @@
231720232068
if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
231721232069
/* Append the missing default column values to the record. */
231722232070
sessionAppendBlob(pOut, aRec, nRec, &rc);
231723232071
if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
231724232072
rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
232073
+ if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){
232074
+ rc = sqlite3_errcode(pGrp->db);
232075
+ }
231725232076
}
231726232077
for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
231727232078
int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
231728232079
sessionAppendByte(pOut, eType, &rc);
231729232080
switch( eType ){
@@ -231736,10 +232087,11 @@
231736232087
double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
231737232088
memcpy(&iVal, &rVal, sizeof(i64));
231738232089
}
231739232090
if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
231740232091
sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
232092
+ pOut->nBuf += 8;
231741232093
}
231742232094
break;
231743232095
}
231744232096
231745232097
case SQLITE_BLOB:
@@ -231874,10 +232226,12 @@
231874232226
SessionChange *pExist = 0;
231875232227
SessionChange **pp = 0;
231876232228
SessionTable *pTab = 0;
231877232229
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
231878232230
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
232231
+
232232
+ assert( nRec>0 );
231879232233
231880232234
/* Ensure that only changesets, or only patchsets, but not a mixture
231881232235
** of both, are being combined. It is an error to try to combine a
231882232236
** changeset and a patchset. */
231883232237
if( pGrp->pList==0 ){
@@ -231952,10 +232306,11 @@
231952232306
){
231953232307
u8 *aRec;
231954232308
int nRec;
231955232309
int rc = SQLITE_OK;
231956232310
232311
+ pIter->in.bNoDiscard = 1;
231957232312
while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
231958232313
rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
231959232314
if( rc!=SQLITE_OK ) break;
231960232315
}
231961232316
@@ -232583,20 +232938,46 @@
232583232938
#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
232584232939
232585232940
/************** End of sqlite3session.c **************************************/
232586232941
/************** Begin file fts5.c ********************************************/
232587232942
232588
-
232943
+/*
232944
+** This, the "fts5.c" source file, is a composite file that is itself
232945
+** assembled from the following files:
232946
+**
232947
+** fts5.h
232948
+** fts5Int.h
232949
+** fts5parse.h <--- Generated from fts5parse.y by Lemon
232950
+** fts5parse.c <--- Generated from fts5parse.y by Lemon
232951
+** fts5_aux.c
232952
+** fts5_buffer.c
232953
+** fts5_config.c
232954
+** fts5_expr.c
232955
+** fts5_hash.c
232956
+** fts5_index.c
232957
+** fts5_main.c
232958
+** fts5_storage.c
232959
+** fts5_tokenize.c
232960
+** fts5_unicode2.c
232961
+** fts5_varint.c
232962
+** fts5_vocab.c
232963
+*/
232589232964
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
232590232965
232591232966
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
232592232967
# define NDEBUG 1
232593232968
#endif
232594232969
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
232595232970
# undef NDEBUG
232596232971
#endif
232597232972
232973
+#ifdef HAVE_STDINT_H
232974
+/* #include <stdint.h> */
232975
+#endif
232976
+#ifdef HAVE_INTTYPES_H
232977
+/* #include <inttypes.h> */
232978
+#endif
232598232979
/*
232599232980
** 2014 May 31
232600232981
**
232601232982
** The author disclaims copyright to this source code. In place of
232602232983
** a legal notice, here is a blessing:
@@ -232893,17 +233274,32 @@
232893233274
** This is used to access token iToken of phrase hit iIdx within the
232894233275
** current row. If iIdx is less than zero or greater than or equal to the
232895233276
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
232896233277
** output variable (*ppToken) is set to point to a buffer containing the
232897233278
** matching document token, and (*pnToken) to the size of that buffer in
232898
-** bytes. This API is not available if the specified token matches a
232899
-** prefix query term. In that case both output variables are always set
232900
-** to 0.
233279
+** bytes.
232901233280
**
232902233281
** The output text is not a copy of the document text that was tokenized.
232903233282
** It is the output of the tokenizer module. For tokendata=1 tables, this
232904233283
** includes any embedded 0x00 and trailing data.
233284
+**
233285
+** This API may be slow in some cases if the token identified by parameters
233286
+** iIdx and iToken matched a prefix token in the query. In most cases, the
233287
+** first call to this API for each prefix token in the query is forced
233288
+** to scan the portion of the full-text index that matches the prefix
233289
+** token to collect the extra data required by this API. If the prefix
233290
+** token matches a large number of token instances in the document set,
233291
+** this may be a performance problem.
233292
+**
233293
+** If the user knows in advance that a query may use this API for a
233294
+** prefix token, FTS5 may be configured to collect all required data as part
233295
+** of the initial querying of the full-text index, avoiding the second scan
233296
+** entirely. This also causes prefix queries that do not use this API to
233297
+** run more slowly and use more memory. FTS5 may be configured in this way
233298
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
233299
+** option, or on a per-query basis using the
233300
+** [fts5_insttoken | fts5_insttoken()] user function.
232905233301
**
232906233302
** This API can be quite slow if used with an FTS5 table created with the
232907233303
** "detail=none" or "detail=column" option.
232908233304
**
232909233305
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -232991,11 +233387,10 @@
232991233387
** CUSTOM TOKENIZERS
232992233388
**
232993233389
** Applications may also register custom tokenizer types. A tokenizer
232994233390
** is registered by providing fts5 with a populated instance of the
232995233391
** following structure. All structure methods must be defined, setting
232996
-**
232997233392
** any member of the fts5_tokenizer struct to NULL leads to undefined
232998233393
** behaviour. The structure methods are expected to function as follows:
232999233394
**
233000233395
** xCreate:
233001233396
** This function is used to allocate and initialize a tokenizer instance.
@@ -233560,10 +233955,11 @@
233560233955
u8 *abUnindexed; /* True for unindexed columns */
233561233956
int nPrefix; /* Number of prefix indexes */
233562233957
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
233563233958
int eContent; /* An FTS5_CONTENT value */
233564233959
int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
233960
+ int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */
233565233961
char *zContent; /* content table */
233566233962
char *zContentRowid; /* "content_rowid=" option value */
233567233963
int bColumnsize; /* "columnsize=" option value (dflt==1) */
233568233964
int bTokendata; /* "tokendata=" option value (dflt==0) */
233569233965
int bLocale; /* "locale=" option value (dflt==0) */
@@ -233582,11 +233978,12 @@
233582233978
int nUsermerge; /* 'usermerge' setting */
233583233979
int nHashSize; /* Bytes of memory for in-memory hash */
233584233980
char *zRank; /* Name of rank function */
233585233981
char *zRankArgs; /* Arguments to rank function */
233586233982
int bSecureDelete; /* 'secure-delete' */
233587
- int nDeleteMerge; /* 'deletemerge' */
233983
+ int nDeleteMerge; /* 'deletemerge' */
233984
+ int bPrefixInsttoken; /* 'prefix-insttoken' */
233588233985
233589233986
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
233590233987
char **pzErrmsg;
233591233988
233592233989
#ifdef SQLITE_DEBUG
@@ -233598,13 +233995,14 @@
233598233995
** the expected version if the 'secure-delete' option has ever been
233599233996
** set on the table. */
233600233997
#define FTS5_CURRENT_VERSION 4
233601233998
#define FTS5_CURRENT_VERSION_SECUREDELETE 5
233602233999
233603
-#define FTS5_CONTENT_NORMAL 0
233604
-#define FTS5_CONTENT_NONE 1
233605
-#define FTS5_CONTENT_EXTERNAL 2
234000
+#define FTS5_CONTENT_NORMAL 0
234001
+#define FTS5_CONTENT_NONE 1
234002
+#define FTS5_CONTENT_EXTERNAL 2
234003
+#define FTS5_CONTENT_UNINDEXED 3
233606234004
233607234005
#define FTS5_DETAIL_FULL 0
233608234006
#define FTS5_DETAIL_NONE 1
233609234007
#define FTS5_DETAIL_COLUMNS 2
233610234008
@@ -233838,11 +234236,18 @@
233838234236
static int sqlite3Fts5StructureTest(Fts5Index*, void*);
233839234237
233840234238
/*
233841234239
** Used by xInstToken():
233842234240
*/
233843
-static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
234241
+static int sqlite3Fts5IterToken(
234242
+ Fts5IndexIter *pIndexIter,
234243
+ const char *pToken, int nToken,
234244
+ i64 iRowid,
234245
+ int iCol,
234246
+ int iOff,
234247
+ const char **ppOut, int *pnOut
234248
+);
233844234249
233845234250
/*
233846234251
** Insert or remove data to or from the index. Each time a document is
233847234252
** added to or removed from the index, this function is called one or more
233848234253
** times.
@@ -233972,20 +234377,17 @@
233972234377
233973234378
static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
233974234379
233975234380
static int sqlite3Fts5FlushToDisk(Fts5Table*);
233976234381
233977
-static int sqlite3Fts5ExtractText(
233978
- Fts5Config *pConfig,
233979
- sqlite3_value *pVal, /* Value to extract text from */
233980
- int bContent, /* Loaded from content table */
233981
- int *pbResetTokenizer, /* OUT: True if ClearLocale() required */
233982
- const char **ppText, /* OUT: Pointer to text buffer */
233983
- int *pnText /* OUT: Size of (*ppText) in bytes */
233984
-);
233985
-
233986234382
static void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
234383
+static void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc);
234384
+
234385
+static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal);
234386
+static int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal,
234387
+ const char **ppText, int *pnText, const char **ppLoc, int *pnLoc
234388
+);
233987234389
233988234390
/*
233989234391
** End of interface to code in fts5.c.
233990234392
**************************************************************************/
233991234393
@@ -234063,11 +234465,11 @@
234063234465
234064234466
static int sqlite3Fts5DropAll(Fts5Config*);
234065234467
static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
234066234468
234067234469
static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
234068
-static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
234470
+static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, sqlite3_value**, i64*);
234069234471
static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
234070234472
234071234473
static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
234072234474
234073234475
static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
@@ -237270,10 +237672,11 @@
237270237672
const char *zArg, /* Argument to parse */
237271237673
char **pzErr /* OUT: Error message */
237272237674
){
237273237675
int rc = SQLITE_OK;
237274237676
int nCmd = (int)strlen(zCmd);
237677
+
237275237678
if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
237276237679
const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
237277237680
const char *p;
237278237681
int bFirst = 1;
237279237682
if( pConfig->aPrefix==0 ){
@@ -237388,10 +237791,20 @@
237388237791
}else{
237389237792
pConfig->bContentlessDelete = (zArg[0]=='1');
237390237793
}
237391237794
return rc;
237392237795
}
237796
+
237797
+ if( sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){
237798
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
237799
+ *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
237800
+ rc = SQLITE_ERROR;
237801
+ }else{
237802
+ pConfig->bContentlessUnindexed = (zArg[0]=='1');
237803
+ }
237804
+ return rc;
237805
+ }
237393237806
237394237807
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
237395237808
if( pConfig->zContentRowid ){
237396237809
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
237397237810
rc = SQLITE_ERROR;
@@ -237506,11 +237919,12 @@
237506237919
237507237920
static int fts5ConfigParseColumn(
237508237921
Fts5Config *p,
237509237922
char *zCol,
237510237923
char *zArg,
237511
- char **pzErr
237924
+ char **pzErr,
237925
+ int *pbUnindexed
237512237926
){
237513237927
int rc = SQLITE_OK;
237514237928
if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
237515237929
|| 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
237516237930
){
@@ -237517,10 +237931,11 @@
237517237931
*pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
237518237932
rc = SQLITE_ERROR;
237519237933
}else if( zArg ){
237520237934
if( 0==sqlite3_stricmp(zArg, "unindexed") ){
237521237935
p->abUnindexed[p->nCol] = 1;
237936
+ *pbUnindexed = 1;
237522237937
}else{
237523237938
*pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
237524237939
rc = SQLITE_ERROR;
237525237940
}
237526237941
}
@@ -237537,15 +237952,30 @@
237537237952
int rc = SQLITE_OK;
237538237953
Fts5Buffer buf = {0, 0, 0};
237539237954
237540237955
sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
237541237956
if( p->eContent!=FTS5_CONTENT_NONE ){
237957
+ assert( p->eContent==FTS5_CONTENT_EXTERNAL
237958
+ || p->eContent==FTS5_CONTENT_NORMAL
237959
+ || p->eContent==FTS5_CONTENT_UNINDEXED
237960
+ );
237542237961
for(i=0; i<p->nCol; i++){
237543237962
if( p->eContent==FTS5_CONTENT_EXTERNAL ){
237544237963
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
237545
- }else{
237964
+ }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){
237546237965
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
237966
+ }else{
237967
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
237968
+ }
237969
+ }
237970
+ }
237971
+ if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){
237972
+ for(i=0; i<p->nCol; i++){
237973
+ if( p->abUnindexed[i]==0 ){
237974
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i);
237975
+ }else{
237976
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
237547237977
}
237548237978
}
237549237979
}
237550237980
237551237981
assert( p->zContentExprlist==0 );
@@ -237575,10 +238005,11 @@
237575238005
){
237576238006
int rc = SQLITE_OK; /* Return code */
237577238007
Fts5Config *pRet; /* New object to return */
237578238008
int i;
237579238009
sqlite3_int64 nByte;
238010
+ int bUnindexed = 0; /* True if there are one or more UNINDEXED */
237580238011
237581238012
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
237582238013
if( pRet==0 ) return SQLITE_NOMEM;
237583238014
memset(pRet, 0, sizeof(Fts5Config));
237584238015
pRet->pGlobal = pGlobal;
@@ -237634,11 +238065,11 @@
237634238065
ALWAYS(zOne)?zOne:"",
237635238066
zTwo?zTwo:"",
237636238067
pzErr
237637238068
);
237638238069
}else{
237639
- rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
238070
+ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed);
237640238071
zOne = 0;
237641238072
}
237642238073
}
237643238074
}
237644238075
@@ -237665,18 +238096,34 @@
237665238096
*pzErr = sqlite3_mprintf(
237666238097
"contentless_delete=1 is incompatible with columnsize=0"
237667238098
);
237668238099
rc = SQLITE_ERROR;
237669238100
}
238101
+
238102
+ /* We only allow contentless_unindexed=1 if the table is actually a
238103
+ ** contentless one.
238104
+ */
238105
+ if( rc==SQLITE_OK
238106
+ && pRet->bContentlessUnindexed
238107
+ && pRet->eContent!=FTS5_CONTENT_NONE
238108
+ ){
238109
+ *pzErr = sqlite3_mprintf(
238110
+ "contentless_unindexed=1 requires a contentless table"
238111
+ );
238112
+ rc = SQLITE_ERROR;
238113
+ }
237670238114
237671238115
/* If no zContent option was specified, fill in the default values. */
237672238116
if( rc==SQLITE_OK && pRet->zContent==0 ){
237673238117
const char *zTail = 0;
237674238118
assert( pRet->eContent==FTS5_CONTENT_NORMAL
237675238119
|| pRet->eContent==FTS5_CONTENT_NONE
237676238120
);
237677238121
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
238122
+ zTail = "content";
238123
+ }else if( bUnindexed && pRet->bContentlessUnindexed ){
238124
+ pRet->eContent = FTS5_CONTENT_UNINDEXED;
237678238125
zTail = "content";
237679238126
}else if( pRet->bColumnsize ){
237680238127
zTail = "docsize";
237681238128
}
237682238129
@@ -238010,10 +238457,23 @@
238010238457
if( bVal<0 ){
238011238458
*pbBadkey = 1;
238012238459
}else{
238013238460
pConfig->bSecureDelete = (bVal ? 1 : 0);
238014238461
}
238462
+ }
238463
+
238464
+ else if( 0==sqlite3_stricmp(zKey, "insttoken") ){
238465
+ int bVal = -1;
238466
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
238467
+ bVal = sqlite3_value_int(pVal);
238468
+ }
238469
+ if( bVal<0 ){
238470
+ *pbBadkey = 1;
238471
+ }else{
238472
+ pConfig->bPrefixInsttoken = (bVal ? 1 : 0);
238473
+ }
238474
+
238015238475
}else{
238016238476
*pbBadkey = 1;
238017238477
}
238018238478
return rc;
238019238479
}
@@ -241145,11 +241605,11 @@
241145241605
&& memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
241146241606
){
241147241607
int rc = sqlite3Fts5PoslistWriterAppend(
241148241608
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
241149241609
);
241150
- if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
241610
+ if( rc==SQLITE_OK && (pExpr->pConfig->bTokendata || pT->bPrefix) ){
241151241611
int iCol = p->iOff>>32;
241152241612
int iTokOff = p->iOff & 0x7FFFFFFF;
241153241613
rc = sqlite3Fts5IndexIterWriteTokendata(
241154241614
pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
241155241615
);
@@ -241338,19 +241798,18 @@
241338241798
pPhrase = pExpr->apExprPhrase[iPhrase];
241339241799
if( iToken<0 || iToken>=pPhrase->nTerm ){
241340241800
return SQLITE_RANGE;
241341241801
}
241342241802
pTerm = &pPhrase->aTerm[iToken];
241343
- if( pTerm->bPrefix==0 ){
241344
- if( pExpr->pConfig->bTokendata ){
241345
- rc = sqlite3Fts5IterToken(
241346
- pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
241347
- );
241348
- }else{
241349
- *ppOut = pTerm->pTerm;
241350
- *pnOut = pTerm->nFullTerm;
241351
- }
241803
+ if( pExpr->pConfig->bTokendata || pTerm->bPrefix ){
241804
+ rc = sqlite3Fts5IterToken(
241805
+ pTerm->pIter, pTerm->pTerm, pTerm->nQueryTerm,
241806
+ iRowid, iCol, iOff+iToken, ppOut, pnOut
241807
+ );
241808
+ }else{
241809
+ *ppOut = pTerm->pTerm;
241810
+ *pnOut = pTerm->nFullTerm;
241352241811
}
241353241812
return rc;
241354241813
}
241355241814
241356241815
/*
@@ -246847,10 +247306,15 @@
246847247306
if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
246848247307
iRet = ii;
246849247308
nBest = nPercent;
246850247309
}
246851247310
}
247311
+
247312
+ /* If pLvl is already the input level to an ongoing merge, look no
247313
+ ** further for a merge candidate. The caller should be allowed to
247314
+ ** continue merging from pLvl first. */
247315
+ if( pLvl->nMerge ) break;
246852247316
}
246853247317
}
246854247318
return iRet;
246855247319
}
246856247320
@@ -248156,10 +248620,387 @@
248156248620
fts5BufferFree(&tmp);
248157248621
memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
248158248622
*p1 = out;
248159248623
}
248160248624
248625
+
248626
+/*
248627
+** Iterate through a range of entries in the FTS index, invoking the xVisit
248628
+** callback for each of them.
248629
+**
248630
+** Parameter pToken points to an nToken buffer containing an FTS index term
248631
+** (i.e. a document term with the preceding 1 byte index identifier -
248632
+** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits
248633
+** all entries for terms that have pToken/nToken as a prefix. If bPrefix
248634
+** is false, then only entries with pToken/nToken as the entire key are
248635
+** visited.
248636
+**
248637
+** If the current table is a tokendata=1 table, then if bPrefix is true then
248638
+** each index term is treated separately. However, if bPrefix is false, then
248639
+** all index terms corresponding to pToken/nToken are collapsed into a single
248640
+** term before the callback is invoked.
248641
+**
248642
+** The callback invoked for each entry visited is specified by paramter xVisit.
248643
+** Each time it is invoked, it is passed a pointer to the Fts5Index object,
248644
+** a copy of the 7th paramter to this function (pCtx) and a pointer to the
248645
+** iterator that indicates the current entry. If the current entry is the
248646
+** first with a new term (i.e. different from that of the previous entry,
248647
+** including the very first term), then the final two parameters are passed
248648
+** a pointer to the term and its size in bytes, respectively. If the current
248649
+** entry is not the first associated with its term, these two parameters
248650
+** are passed 0.
248651
+**
248652
+** If parameter pColset is not NULL, then it is used to filter entries before
248653
+** the callback is invoked.
248654
+*/
248655
+static int fts5VisitEntries(
248656
+ Fts5Index *p, /* Fts5 index object */
248657
+ Fts5Colset *pColset, /* Columns filter to apply, or NULL */
248658
+ u8 *pToken, /* Buffer containing token */
248659
+ int nToken, /* Size of buffer pToken in bytes */
248660
+ int bPrefix, /* True for a prefix scan */
248661
+ void (*xVisit)(Fts5Index*, void *pCtx, Fts5Iter *pIter, const u8*, int),
248662
+ void *pCtx /* Passed as second argument to xVisit() */
248663
+){
248664
+ const int flags = (bPrefix ? FTS5INDEX_QUERY_SCAN : 0)
248665
+ | FTS5INDEX_QUERY_SKIPEMPTY
248666
+ | FTS5INDEX_QUERY_NOOUTPUT;
248667
+ Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
248668
+ int bNewTerm = 1;
248669
+ Fts5Structure *pStruct = fts5StructureRead(p);
248670
+
248671
+ fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
248672
+ fts5IterSetOutputCb(&p->rc, p1);
248673
+ for( /* no-op */ ;
248674
+ fts5MultiIterEof(p, p1)==0;
248675
+ fts5MultiIterNext2(p, p1, &bNewTerm)
248676
+ ){
248677
+ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
248678
+ int nNew = 0;
248679
+ const u8 *pNew = 0;
248680
+
248681
+ p1->xSetOutputs(p1, pSeg);
248682
+ if( p->rc ) break;
248683
+
248684
+ if( bNewTerm ){
248685
+ nNew = pSeg->term.n;
248686
+ pNew = pSeg->term.p;
248687
+ if( nNew<nToken || memcmp(pToken, pNew, nToken) ) break;
248688
+ }
248689
+
248690
+ xVisit(p, pCtx, p1, pNew, nNew);
248691
+ }
248692
+ fts5MultiIterFree(p1);
248693
+
248694
+ fts5StructureRelease(pStruct);
248695
+ return p->rc;
248696
+}
248697
+
248698
+
248699
+/*
248700
+** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
248701
+** array of these for each row it visits (so all iRowid fields are the same).
248702
+** Or, for an iterator used by an "ORDER BY rank" query, it accumulates an
248703
+** array of these for the entire query (in which case iRowid fields may take
248704
+** a variety of values).
248705
+**
248706
+** Each instance in the array indicates the iterator (and therefore term)
248707
+** associated with position iPos of rowid iRowid. This is used by the
248708
+** xInstToken() API.
248709
+**
248710
+** iRowid:
248711
+** Rowid for the current entry.
248712
+**
248713
+** iPos:
248714
+** Position of current entry within row. In the usual ((iCol<<32)+iOff)
248715
+** format (e.g. see macros FTS5_POS2COLUMN() and FTS5_POS2OFFSET()).
248716
+**
248717
+** iIter:
248718
+** If the Fts5TokenDataIter iterator that the entry is part of is
248719
+** actually an iterator (i.e. with nIter>0, not just a container for
248720
+** Fts5TokenDataMap structures), then this variable is an index into
248721
+** the apIter[] array. The corresponding term is that which the iterator
248722
+** at apIter[iIter] currently points to.
248723
+**
248724
+** Or, if the Fts5TokenDataIter iterator is just a container object
248725
+** (nIter==0), then iIter is an index into the term.p[] buffer where
248726
+** the term is stored.
248727
+**
248728
+** nByte:
248729
+** In the case where iIter is an index into term.p[], this variable
248730
+** is the size of the term in bytes. If iIter is an index into apIter[],
248731
+** this variable is unused.
248732
+*/
248733
+struct Fts5TokenDataMap {
248734
+ i64 iRowid; /* Row this token is located in */
248735
+ i64 iPos; /* Position of token */
248736
+ int iIter; /* Iterator token was read from */
248737
+ int nByte; /* Length of token in bytes (or 0) */
248738
+};
248739
+
248740
+/*
248741
+** An object used to supplement Fts5Iter for tokendata=1 iterators.
248742
+**
248743
+** This object serves two purposes. The first is as a container for an array
248744
+** of Fts5TokenDataMap structures, which are used to find the token required
248745
+** when the xInstToken() API is used. This is done by the nMapAlloc, nMap and
248746
+** aMap[] variables.
248747
+*/
248748
+struct Fts5TokenDataIter {
248749
+ int nMapAlloc; /* Allocated size of aMap[] in entries */
248750
+ int nMap; /* Number of valid entries in aMap[] */
248751
+ Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */
248752
+
248753
+ /* The following are used for prefix-queries only. */
248754
+ Fts5Buffer terms;
248755
+
248756
+ /* The following are used for other full-token tokendata queries only. */
248757
+ int nIter;
248758
+ int nIterAlloc;
248759
+ Fts5PoslistReader *aPoslistReader;
248760
+ int *aPoslistToIter;
248761
+ Fts5Iter *apIter[1];
248762
+};
248763
+
248764
+/*
248765
+** The two input arrays - a1[] and a2[] - are in sorted order. This function
248766
+** merges the two arrays together and writes the result to output array
248767
+** aOut[]. aOut[] is guaranteed to be large enough to hold the result.
248768
+**
248769
+** Duplicate entries are copied into the output. So the size of the output
248770
+** array is always (n1+n2) entries.
248771
+*/
248772
+static void fts5TokendataMerge(
248773
+ Fts5TokenDataMap *a1, int n1, /* Input array 1 */
248774
+ Fts5TokenDataMap *a2, int n2, /* Input array 2 */
248775
+ Fts5TokenDataMap *aOut /* Output array */
248776
+){
248777
+ int i1 = 0;
248778
+ int i2 = 0;
248779
+
248780
+ assert( n1>=0 && n2>=0 );
248781
+ while( i1<n1 || i2<n2 ){
248782
+ Fts5TokenDataMap *pOut = &aOut[i1+i2];
248783
+ if( i2>=n2 || (i1<n1 && (
248784
+ a1[i1].iRowid<a2[i2].iRowid
248785
+ || (a1[i1].iRowid==a2[i2].iRowid && a1[i1].iPos<=a2[i2].iPos)
248786
+ ))){
248787
+ memcpy(pOut, &a1[i1], sizeof(Fts5TokenDataMap));
248788
+ i1++;
248789
+ }else{
248790
+ memcpy(pOut, &a2[i2], sizeof(Fts5TokenDataMap));
248791
+ i2++;
248792
+ }
248793
+ }
248794
+}
248795
+
248796
+
248797
+/*
248798
+** Append a mapping to the token-map belonging to object pT.
248799
+*/
248800
+static void fts5TokendataIterAppendMap(
248801
+ Fts5Index *p,
248802
+ Fts5TokenDataIter *pT,
248803
+ int iIter,
248804
+ int nByte,
248805
+ i64 iRowid,
248806
+ i64 iPos
248807
+){
248808
+ if( p->rc==SQLITE_OK ){
248809
+ if( pT->nMap==pT->nMapAlloc ){
248810
+ int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
248811
+ int nAlloc = nNew * sizeof(Fts5TokenDataMap);
248812
+ Fts5TokenDataMap *aNew;
248813
+
248814
+ aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
248815
+ if( aNew==0 ){
248816
+ p->rc = SQLITE_NOMEM;
248817
+ return;
248818
+ }
248819
+
248820
+ pT->aMap = aNew;
248821
+ pT->nMapAlloc = nNew;
248822
+ }
248823
+
248824
+ pT->aMap[pT->nMap].iRowid = iRowid;
248825
+ pT->aMap[pT->nMap].iPos = iPos;
248826
+ pT->aMap[pT->nMap].iIter = iIter;
248827
+ pT->aMap[pT->nMap].nByte = nByte;
248828
+ pT->nMap++;
248829
+ }
248830
+}
248831
+
248832
+/*
248833
+** Sort the contents of the pT->aMap[] array.
248834
+**
248835
+** The sorting algorithm requries a malloc(). If this fails, an error code
248836
+** is left in Fts5Index.rc before returning.
248837
+*/
248838
+static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
248839
+ Fts5TokenDataMap *aTmp = 0;
248840
+ int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
248841
+
248842
+ aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
248843
+ if( aTmp ){
248844
+ Fts5TokenDataMap *a1 = pT->aMap;
248845
+ Fts5TokenDataMap *a2 = aTmp;
248846
+ i64 nHalf;
248847
+
248848
+ for(nHalf=1; nHalf<pT->nMap; nHalf=nHalf*2){
248849
+ int i1;
248850
+ for(i1=0; i1<pT->nMap; i1+=(nHalf*2)){
248851
+ int n1 = MIN(nHalf, pT->nMap-i1);
248852
+ int n2 = MIN(nHalf, pT->nMap-i1-n1);
248853
+ fts5TokendataMerge(&a1[i1], n1, &a1[i1+n1], n2, &a2[i1]);
248854
+ }
248855
+ SWAPVAL(Fts5TokenDataMap*, a1, a2);
248856
+ }
248857
+
248858
+ if( a1!=pT->aMap ){
248859
+ memcpy(pT->aMap, a1, pT->nMap*sizeof(Fts5TokenDataMap));
248860
+ }
248861
+ sqlite3_free(aTmp);
248862
+
248863
+#ifdef SQLITE_DEBUG
248864
+ {
248865
+ int ii;
248866
+ for(ii=1; ii<pT->nMap; ii++){
248867
+ Fts5TokenDataMap *p1 = &pT->aMap[ii-1];
248868
+ Fts5TokenDataMap *p2 = &pT->aMap[ii];
248869
+ assert( p1->iRowid<p2->iRowid
248870
+ || (p1->iRowid==p2->iRowid && p1->iPos<=p2->iPos)
248871
+ );
248872
+ }
248873
+ }
248874
+#endif
248875
+ }
248876
+}
248877
+
248878
+/*
248879
+** Delete an Fts5TokenDataIter structure and its contents.
248880
+*/
248881
+static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
248882
+ if( pSet ){
248883
+ int ii;
248884
+ for(ii=0; ii<pSet->nIter; ii++){
248885
+ fts5MultiIterFree(pSet->apIter[ii]);
248886
+ }
248887
+ fts5BufferFree(&pSet->terms);
248888
+ sqlite3_free(pSet->aPoslistReader);
248889
+ sqlite3_free(pSet->aMap);
248890
+ sqlite3_free(pSet);
248891
+ }
248892
+}
248893
+
248894
+
248895
+/*
248896
+** fts5VisitEntries() context object used by fts5SetupPrefixIterTokendata()
248897
+** to pass data to prefixIterSetupTokendataCb().
248898
+*/
248899
+typedef struct TokendataSetupCtx TokendataSetupCtx;
248900
+struct TokendataSetupCtx {
248901
+ Fts5TokenDataIter *pT; /* Object being populated with mappings */
248902
+ int iTermOff; /* Offset of current term in terms.p[] */
248903
+ int nTermByte; /* Size of current term in bytes */
248904
+};
248905
+
248906
+/*
248907
+** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This
248908
+** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each
248909
+** position in the current position-list. It doesn't matter that some of
248910
+** these may be out of order - they will be sorted later.
248911
+*/
248912
+static void prefixIterSetupTokendataCb(
248913
+ Fts5Index *p,
248914
+ void *pCtx,
248915
+ Fts5Iter *p1,
248916
+ const u8 *pNew,
248917
+ int nNew
248918
+){
248919
+ TokendataSetupCtx *pSetup = (TokendataSetupCtx*)pCtx;
248920
+ int iPosOff = 0;
248921
+ i64 iPos = 0;
248922
+
248923
+ if( pNew ){
248924
+ pSetup->nTermByte = nNew-1;
248925
+ pSetup->iTermOff = pSetup->pT->terms.n;
248926
+ fts5BufferAppendBlob(&p->rc, &pSetup->pT->terms, nNew-1, pNew+1);
248927
+ }
248928
+
248929
+ while( 0==sqlite3Fts5PoslistNext64(
248930
+ p1->base.pData, p1->base.nData, &iPosOff, &iPos
248931
+ ) ){
248932
+ fts5TokendataIterAppendMap(p,
248933
+ pSetup->pT, pSetup->iTermOff, pSetup->nTermByte, p1->base.iRowid, iPos
248934
+ );
248935
+ }
248936
+}
248937
+
248938
+
248939
+/*
248940
+** Context object passed by fts5SetupPrefixIter() to fts5VisitEntries().
248941
+*/
248942
+typedef struct PrefixSetupCtx PrefixSetupCtx;
248943
+struct PrefixSetupCtx {
248944
+ void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
248945
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
248946
+ i64 iLastRowid;
248947
+ int nMerge;
248948
+ Fts5Buffer *aBuf;
248949
+ int nBuf;
248950
+ Fts5Buffer doclist;
248951
+ TokendataSetupCtx *pTokendata;
248952
+};
248953
+
248954
+/*
248955
+** fts5VisitEntries() callback used by fts5SetupPrefixIter()
248956
+*/
248957
+static void prefixIterSetupCb(
248958
+ Fts5Index *p,
248959
+ void *pCtx,
248960
+ Fts5Iter *p1,
248961
+ const u8 *pNew,
248962
+ int nNew
248963
+){
248964
+ PrefixSetupCtx *pSetup = (PrefixSetupCtx*)pCtx;
248965
+ const int nMerge = pSetup->nMerge;
248966
+
248967
+ if( p1->base.nData>0 ){
248968
+ if( p1->base.iRowid<=pSetup->iLastRowid && pSetup->doclist.n>0 ){
248969
+ int i;
248970
+ for(i=0; p->rc==SQLITE_OK && pSetup->doclist.n; i++){
248971
+ int i1 = i*nMerge;
248972
+ int iStore;
248973
+ assert( i1+nMerge<=pSetup->nBuf );
248974
+ for(iStore=i1; iStore<i1+nMerge; iStore++){
248975
+ if( pSetup->aBuf[iStore].n==0 ){
248976
+ fts5BufferSwap(&pSetup->doclist, &pSetup->aBuf[iStore]);
248977
+ fts5BufferZero(&pSetup->doclist);
248978
+ break;
248979
+ }
248980
+ }
248981
+ if( iStore==i1+nMerge ){
248982
+ pSetup->xMerge(p, &pSetup->doclist, nMerge, &pSetup->aBuf[i1]);
248983
+ for(iStore=i1; iStore<i1+nMerge; iStore++){
248984
+ fts5BufferZero(&pSetup->aBuf[iStore]);
248985
+ }
248986
+ }
248987
+ }
248988
+ pSetup->iLastRowid = 0;
248989
+ }
248990
+
248991
+ pSetup->xAppend(
248992
+ p, (u64)p1->base.iRowid-(u64)pSetup->iLastRowid, p1, &pSetup->doclist
248993
+ );
248994
+ pSetup->iLastRowid = p1->base.iRowid;
248995
+ }
248996
+
248997
+ if( pSetup->pTokendata ){
248998
+ prefixIterSetupTokendataCb(p, (void*)pSetup->pTokendata, p1, pNew, nNew);
248999
+ }
249000
+}
249001
+
248161249002
static void fts5SetupPrefixIter(
248162249003
Fts5Index *p, /* Index to read from */
248163249004
int bDesc, /* True for "ORDER BY rowid DESC" */
248164249005
int iIdx, /* Index to scan for data */
248165249006
u8 *pToken, /* Buffer containing prefix to match */
@@ -248166,137 +249007,89 @@
248166249007
int nToken, /* Size of buffer pToken in bytes */
248167249008
Fts5Colset *pColset, /* Restrict matches to these columns */
248168249009
Fts5Iter **ppIter /* OUT: New iterator */
248169249010
){
248170249011
Fts5Structure *pStruct;
248171
- Fts5Buffer *aBuf;
248172
- int nBuf = 32;
248173
- int nMerge = 1;
249012
+ PrefixSetupCtx s;
249013
+ TokendataSetupCtx s2;
248174249014
248175
- void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
248176
- void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
249015
+ memset(&s, 0, sizeof(s));
249016
+ memset(&s2, 0, sizeof(s2));
249017
+
249018
+ s.nMerge = 1;
249019
+ s.iLastRowid = 0;
249020
+ s.nBuf = 32;
249021
+ if( iIdx==0
249022
+ && p->pConfig->eDetail==FTS5_DETAIL_FULL
249023
+ && p->pConfig->bPrefixInsttoken
249024
+ ){
249025
+ s.pTokendata = &s2;
249026
+ s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT));
249027
+ }
249028
+
248177249029
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
248178
- xMerge = fts5MergeRowidLists;
248179
- xAppend = fts5AppendRowid;
249030
+ s.xMerge = fts5MergeRowidLists;
249031
+ s.xAppend = fts5AppendRowid;
248180249032
}else{
248181
- nMerge = FTS5_MERGE_NLIST-1;
248182
- nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
248183
- xMerge = fts5MergePrefixLists;
248184
- xAppend = fts5AppendPoslist;
249033
+ s.nMerge = FTS5_MERGE_NLIST-1;
249034
+ s.nBuf = s.nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
249035
+ s.xMerge = fts5MergePrefixLists;
249036
+ s.xAppend = fts5AppendPoslist;
248185249037
}
248186249038
248187
- aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
249039
+ s.aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*s.nBuf);
248188249040
pStruct = fts5StructureRead(p);
248189
- assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
249041
+ assert( p->rc!=SQLITE_OK || (s.aBuf && pStruct) );
248190249042
248191249043
if( p->rc==SQLITE_OK ){
248192
- const int flags = FTS5INDEX_QUERY_SCAN
248193
- | FTS5INDEX_QUERY_SKIPEMPTY
248194
- | FTS5INDEX_QUERY_NOOUTPUT;
249044
+ void *pCtx = (void*)&s;
248195249045
int i;
248196
- i64 iLastRowid = 0;
248197
- Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
248198249046
Fts5Data *pData;
248199
- Fts5Buffer doclist;
248200
- int bNewTerm = 1;
248201
-
248202
- memset(&doclist, 0, sizeof(doclist));
248203249047
248204249048
/* If iIdx is non-zero, then it is the number of a prefix-index for
248205249049
** prefixes 1 character longer than the prefix being queried for. That
248206249050
** index contains all the doclists required, except for the one
248207249051
** corresponding to the prefix itself. That one is extracted from the
248208249052
** main term index here. */
248209249053
if( iIdx!=0 ){
248210
- int dummy = 0;
248211
- const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
248212249054
pToken[0] = FTS5_MAIN_PREFIX;
248213
- fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
248214
- fts5IterSetOutputCb(&p->rc, p1);
248215
- for(;
248216
- fts5MultiIterEof(p, p1)==0;
248217
- fts5MultiIterNext2(p, p1, &dummy)
248218
- ){
248219
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
248220
- p1->xSetOutputs(p1, pSeg);
248221
- if( p1->base.nData ){
248222
- xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
248223
- iLastRowid = p1->base.iRowid;
248224
- }
248225
- }
248226
- fts5MultiIterFree(p1);
249055
+ fts5VisitEntries(p, pColset, pToken, nToken, 0, prefixIterSetupCb, pCtx);
248227249056
}
248228249057
248229249058
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
248230
- fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
248231
- fts5IterSetOutputCb(&p->rc, p1);
248232
-
248233
- for( /* no-op */ ;
248234
- fts5MultiIterEof(p, p1)==0;
248235
- fts5MultiIterNext2(p, p1, &bNewTerm)
248236
- ){
248237
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
248238
- int nTerm = pSeg->term.n;
248239
- const u8 *pTerm = pSeg->term.p;
248240
- p1->xSetOutputs(p1, pSeg);
248241
-
248242
- assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
248243
- if( bNewTerm ){
248244
- if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
248245
- }
248246
-
248247
- if( p1->base.nData==0 ) continue;
248248
- if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
248249
- for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
248250
- int i1 = i*nMerge;
248251
- int iStore;
248252
- assert( i1+nMerge<=nBuf );
248253
- for(iStore=i1; iStore<i1+nMerge; iStore++){
248254
- if( aBuf[iStore].n==0 ){
248255
- fts5BufferSwap(&doclist, &aBuf[iStore]);
248256
- fts5BufferZero(&doclist);
248257
- break;
248258
- }
248259
- }
248260
- if( iStore==i1+nMerge ){
248261
- xMerge(p, &doclist, nMerge, &aBuf[i1]);
248262
- for(iStore=i1; iStore<i1+nMerge; iStore++){
248263
- fts5BufferZero(&aBuf[iStore]);
248264
- }
248265
- }
248266
- }
248267
- iLastRowid = 0;
248268
- }
248269
-
248270
- xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
248271
- iLastRowid = p1->base.iRowid;
248272
- }
248273
-
248274
- assert( (nBuf%nMerge)==0 );
248275
- for(i=0; i<nBuf; i+=nMerge){
249059
+ fts5VisitEntries(p, pColset, pToken, nToken, 1, prefixIterSetupCb, pCtx);
249060
+
249061
+ assert( (s.nBuf%s.nMerge)==0 );
249062
+ for(i=0; i<s.nBuf; i+=s.nMerge){
248276249063
int iFree;
248277249064
if( p->rc==SQLITE_OK ){
248278
- xMerge(p, &doclist, nMerge, &aBuf[i]);
249065
+ s.xMerge(p, &s.doclist, s.nMerge, &s.aBuf[i]);
248279249066
}
248280
- for(iFree=i; iFree<i+nMerge; iFree++){
248281
- fts5BufferFree(&aBuf[iFree]);
249067
+ for(iFree=i; iFree<i+s.nMerge; iFree++){
249068
+ fts5BufferFree(&s.aBuf[iFree]);
248282249069
}
248283249070
}
248284
- fts5MultiIterFree(p1);
248285249071
248286
- pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
249072
+ pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING);
248287249073
if( pData ){
248288249074
pData->p = (u8*)&pData[1];
248289
- pData->nn = pData->szLeaf = doclist.n;
248290
- if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
249075
+ pData->nn = pData->szLeaf = s.doclist.n;
249076
+ if( s.doclist.n ) memcpy(pData->p, s.doclist.p, s.doclist.n);
248291249077
fts5MultiIterNew2(p, pData, bDesc, ppIter);
248292249078
}
248293
- fts5BufferFree(&doclist);
249079
+
249080
+ if( p->rc==SQLITE_OK && s.pTokendata ){
249081
+ fts5TokendataIterSortMap(p, s2.pT);
249082
+ (*ppIter)->pTokenDataIter = s2.pT;
249083
+ s2.pT = 0;
249084
+ }
248294249085
}
248295249086
249087
+ fts5TokendataIterDelete(s2.pT);
249088
+ fts5BufferFree(&s.doclist);
248296249089
fts5StructureRelease(pStruct);
248297
- sqlite3_free(aBuf);
249090
+ sqlite3_free(s.aBuf);
248298249091
}
248299249092
248300249093
248301249094
/*
248302249095
** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
@@ -248546,42 +249339,10 @@
248546249339
static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
248547249340
fts5DataRelease(pSeg->pLeaf);
248548249341
pSeg->pLeaf = 0;
248549249342
}
248550249343
248551
-/*
248552
-** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
248553
-** array of these for each row it visits. Or, for an iterator used by an
248554
-** "ORDER BY rank" query, it accumulates an array of these for the entire
248555
-** query.
248556
-**
248557
-** Each instance in the array indicates the iterator (and therefore term)
248558
-** associated with position iPos of rowid iRowid. This is used by the
248559
-** xInstToken() API.
248560
-*/
248561
-struct Fts5TokenDataMap {
248562
- i64 iRowid; /* Row this token is located in */
248563
- i64 iPos; /* Position of token */
248564
- int iIter; /* Iterator token was read from */
248565
-};
248566
-
248567
-/*
248568
-** An object used to supplement Fts5Iter for tokendata=1 iterators.
248569
-*/
248570
-struct Fts5TokenDataIter {
248571
- int nIter;
248572
- int nIterAlloc;
248573
-
248574
- int nMap;
248575
- int nMapAlloc;
248576
- Fts5TokenDataMap *aMap;
248577
-
248578
- Fts5PoslistReader *aPoslistReader;
248579
- int *aPoslistToIter;
248580
- Fts5Iter *apIter[1];
248581
-};
248582
-
248583249344
/*
248584249345
** This function appends iterator pAppend to Fts5TokenDataIter pIn and
248585249346
** returns the result.
248586249347
*/
248587249348
static Fts5TokenDataIter *fts5AppendTokendataIter(
@@ -248614,58 +249375,10 @@
248614249375
assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
248615249376
248616249377
return pRet;
248617249378
}
248618249379
248619
-/*
248620
-** Delete an Fts5TokenDataIter structure and its contents.
248621
-*/
248622
-static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
248623
- if( pSet ){
248624
- int ii;
248625
- for(ii=0; ii<pSet->nIter; ii++){
248626
- fts5MultiIterFree(pSet->apIter[ii]);
248627
- }
248628
- sqlite3_free(pSet->aPoslistReader);
248629
- sqlite3_free(pSet->aMap);
248630
- sqlite3_free(pSet);
248631
- }
248632
-}
248633
-
248634
-/*
248635
-** Append a mapping to the token-map belonging to object pT.
248636
-*/
248637
-static void fts5TokendataIterAppendMap(
248638
- Fts5Index *p,
248639
- Fts5TokenDataIter *pT,
248640
- int iIter,
248641
- i64 iRowid,
248642
- i64 iPos
248643
-){
248644
- if( p->rc==SQLITE_OK ){
248645
- if( pT->nMap==pT->nMapAlloc ){
248646
- int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
248647
- int nByte = nNew * sizeof(Fts5TokenDataMap);
248648
- Fts5TokenDataMap *aNew;
248649
-
248650
- aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte);
248651
- if( aNew==0 ){
248652
- p->rc = SQLITE_NOMEM;
248653
- return;
248654
- }
248655
-
248656
- pT->aMap = aNew;
248657
- pT->nMapAlloc = nNew;
248658
- }
248659
-
248660
- pT->aMap[pT->nMap].iRowid = iRowid;
248661
- pT->aMap[pT->nMap].iPos = iPos;
248662
- pT->aMap[pT->nMap].iIter = iIter;
248663
- pT->nMap++;
248664
- }
248665
-}
248666
-
248667249380
/*
248668249381
** The iterator passed as the only argument must be a tokendata=1 iterator
248669249382
** (pIter->pTokenDataIter!=0). This function sets the iterator output
248670249383
** variables (pIter->base.*) according to the contents of the current
248671249384
** row.
@@ -248702,11 +249415,11 @@
248702249415
int eDetail = pIter->pIndex->pConfig->eDetail;
248703249416
pIter->base.bEof = 0;
248704249417
pIter->base.iRowid = iRowid;
248705249418
248706249419
if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
248707
- fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
249420
+ fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, 0, iRowid, -1);
248708249421
}else
248709249422
if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
248710249423
int nReader = 0;
248711249424
int nByte = 0;
248712249425
i64 iPrev = 0;
@@ -248955,10 +249668,11 @@
248955249668
248956249669
if( p->rc==SQLITE_OK ){
248957249670
pRet = fts5MultiIterAlloc(p, 0);
248958249671
}
248959249672
if( pRet ){
249673
+ pRet->nSeg = 0;
248960249674
pRet->pTokenDataIter = pSet;
248961249675
if( pSet ){
248962249676
fts5IterSetOutputsTokendata(pRet);
248963249677
}else{
248964249678
pRet->base.bEof = 1;
@@ -248969,11 +249683,10 @@
248969249683
248970249684
fts5StructureRelease(pStruct);
248971249685
fts5BufferFree(&bSeek);
248972249686
return pRet;
248973249687
}
248974
-
248975249688
248976249689
/*
248977249690
** Open a new iterator to iterate though all rowid that match the
248978249691
** specified token or token prefix.
248979249692
*/
@@ -248995,10 +249708,15 @@
248995249708
int iIdx = 0; /* Index to search */
248996249709
int iPrefixIdx = 0; /* +1 prefix index */
248997249710
int bTokendata = pConfig->bTokendata;
248998249711
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
248999249712
249713
+ /* The NOTOKENDATA flag is set when each token in a tokendata=1 table
249714
+ ** should be treated individually, instead of merging all those with
249715
+ ** a common prefix into a single entry. This is used, for example, by
249716
+ ** queries performed as part of an integrity-check, or by the fts5vocab
249717
+ ** module. */
249000249718
if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
249001249719
bTokendata = 0;
249002249720
}
249003249721
249004249722
/* Figure out which index to search and set iIdx accordingly. If this
@@ -249025,11 +249743,11 @@
249025249743
if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
249026249744
}
249027249745
}
249028249746
249029249747
if( bTokendata && iIdx==0 ){
249030
- buf.p[0] = '0';
249748
+ buf.p[0] = FTS5_MAIN_PREFIX;
249031249749
pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
249032249750
}else if( iIdx<=pConfig->nPrefix ){
249033249751
/* Straight index lookup */
249034249752
Fts5Structure *pStruct = fts5StructureRead(p);
249035249753
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -249038,11 +249756,11 @@
249038249756
pColset, buf.p, nToken+1, -1, 0, &pRet
249039249757
);
249040249758
fts5StructureRelease(pStruct);
249041249759
}
249042249760
}else{
249043
- /* Scan multiple terms in the main index */
249761
+ /* Scan multiple terms in the main index for a prefix query. */
249044249762
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
249045249763
fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
249046249764
if( pRet==0 ){
249047249765
assert( p->rc!=SQLITE_OK );
249048249766
}else{
@@ -249074,11 +249792,12 @@
249074249792
** Move to the next matching rowid.
249075249793
*/
249076249794
static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
249077249795
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249078249796
assert( pIter->pIndex->rc==SQLITE_OK );
249079
- if( pIter->pTokenDataIter ){
249797
+ if( pIter->nSeg==0 ){
249798
+ assert( pIter->pTokenDataIter );
249080249799
fts5TokendataIterNext(pIter, 0, 0);
249081249800
}else{
249082249801
fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
249083249802
}
249084249803
return fts5IndexReturn(pIter->pIndex);
@@ -249111,11 +249830,12 @@
249111249830
** definition of "at or after" depends on whether this iterator iterates
249112249831
** in ascending or descending rowid order.
249113249832
*/
249114249833
static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
249115249834
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249116
- if( pIter->pTokenDataIter ){
249835
+ if( pIter->nSeg==0 ){
249836
+ assert( pIter->pTokenDataIter );
249117249837
fts5TokendataIterNext(pIter, 1, iMatch);
249118249838
}else{
249119249839
fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
249120249840
}
249121249841
return fts5IndexReturn(pIter->pIndex);
@@ -249129,32 +249849,87 @@
249129249849
const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
249130249850
assert_nc( z || n<=1 );
249131249851
*pn = n-1;
249132249852
return (z ? &z[1] : 0);
249133249853
}
249854
+
249855
+/*
249856
+** pIter is a prefix query. This function populates pIter->pTokenDataIter
249857
+** with an Fts5TokenDataIter object containing mappings for all rows
249858
+** matched by the query.
249859
+*/
249860
+static int fts5SetupPrefixIterTokendata(
249861
+ Fts5Iter *pIter,
249862
+ const char *pToken, /* Token prefix to search for */
249863
+ int nToken /* Size of pToken in bytes */
249864
+){
249865
+ Fts5Index *p = pIter->pIndex;
249866
+ Fts5Buffer token = {0, 0, 0};
249867
+ TokendataSetupCtx ctx;
249868
+
249869
+ memset(&ctx, 0, sizeof(ctx));
249870
+
249871
+ fts5BufferGrow(&p->rc, &token, nToken+1);
249872
+ ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));
249873
+
249874
+ if( p->rc==SQLITE_OK ){
249875
+
249876
+ /* Fill in the token prefix to search for */
249877
+ token.p[0] = FTS5_MAIN_PREFIX;
249878
+ memcpy(&token.p[1], pToken, nToken);
249879
+ token.n = nToken+1;
249880
+
249881
+ fts5VisitEntries(
249882
+ p, 0, token.p, token.n, 1, prefixIterSetupTokendataCb, (void*)&ctx
249883
+ );
249884
+
249885
+ fts5TokendataIterSortMap(p, ctx.pT);
249886
+ }
249887
+
249888
+ if( p->rc==SQLITE_OK ){
249889
+ pIter->pTokenDataIter = ctx.pT;
249890
+ }else{
249891
+ fts5TokendataIterDelete(ctx.pT);
249892
+ }
249893
+ fts5BufferFree(&token);
249894
+
249895
+ return fts5IndexReturn(p);
249896
+}
249134249897
249135249898
/*
249136249899
** This is used by xInstToken() to access the token at offset iOff, column
249137249900
** iCol of row iRowid. The token is returned via output variables *ppOut
249138249901
** and *pnOut. The iterator passed as the first argument must be a tokendata=1
249139249902
** iterator (pIter->pTokenDataIter!=0).
249903
+**
249904
+** pToken/nToken:
249140249905
*/
249141249906
static int sqlite3Fts5IterToken(
249142249907
Fts5IndexIter *pIndexIter,
249908
+ const char *pToken, int nToken,
249143249909
i64 iRowid,
249144249910
int iCol,
249145249911
int iOff,
249146249912
const char **ppOut, int *pnOut
249147249913
){
249148249914
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249149249915
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
249150
- Fts5TokenDataMap *aMap = pT->aMap;
249151249916
i64 iPos = (((i64)iCol)<<32) + iOff;
249152
-
249917
+ Fts5TokenDataMap *aMap = 0;
249153249918
int i1 = 0;
249154
- int i2 = pT->nMap;
249919
+ int i2 = 0;
249155249920
int iTest = 0;
249921
+
249922
+ assert( pT || (pToken && pIter->nSeg>0) );
249923
+ if( pT==0 ){
249924
+ int rc = fts5SetupPrefixIterTokendata(pIter, pToken, nToken);
249925
+ if( rc!=SQLITE_OK ) return rc;
249926
+ pT = pIter->pTokenDataIter;
249927
+ }
249928
+
249929
+ i2 = pT->nMap;
249930
+ aMap = pT->aMap;
249156249931
249157249932
while( i2>i1 ){
249158249933
iTest = (i1 + i2) / 2;
249159249934
249160249935
if( aMap[iTest].iRowid<iRowid ){
@@ -249174,13 +249949,19 @@
249174249949
}
249175249950
}
249176249951
}
249177249952
249178249953
if( i2>i1 ){
249179
- Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
249180
- *ppOut = (const char*)pMap->aSeg[0].term.p+1;
249181
- *pnOut = pMap->aSeg[0].term.n-1;
249954
+ if( pIter->nSeg==0 ){
249955
+ Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
249956
+ *ppOut = (const char*)pMap->aSeg[0].term.p+1;
249957
+ *pnOut = pMap->aSeg[0].term.n-1;
249958
+ }else{
249959
+ Fts5TokenDataMap *p = &aMap[iTest];
249960
+ *ppOut = (const char*)&pT->terms.p[p->iIter];
249961
+ *pnOut = aMap[iTest].nByte;
249962
+ }
249182249963
}
249183249964
249184249965
return SQLITE_OK;
249185249966
}
249186249967
@@ -249188,11 +249969,13 @@
249188249969
** Clear any existing entries from the token-map associated with the
249189249970
** iterator passed as the only argument.
249190249971
*/
249191249972
static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
249192249973
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249193
- if( pIter && pIter->pTokenDataIter ){
249974
+ if( pIter && pIter->pTokenDataIter
249975
+ && (pIter->nSeg==0 || pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_FULL)
249976
+ ){
249194249977
pIter->pTokenDataIter->nMap = 0;
249195249978
}
249196249979
}
249197249980
249198249981
/*
@@ -249208,21 +249991,33 @@
249208249991
i64 iRowid, int iCol, int iOff
249209249992
){
249210249993
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249211249994
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
249212249995
Fts5Index *p = pIter->pIndex;
249213
- int ii;
249996
+ i64 iPos = (((i64)iCol)<<32) + iOff;
249214249997
249215249998
assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
249216
- assert( pIter->pTokenDataIter );
249217
-
249218
- for(ii=0; ii<pT->nIter; ii++){
249219
- Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
249220
- if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
249221
- }
249222
- if( ii<pT->nIter ){
249223
- fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
249999
+ assert( pIter->pTokenDataIter || pIter->nSeg>0 );
250000
+ if( pIter->nSeg>0 ){
250001
+ /* This is a prefix term iterator. */
250002
+ if( pT==0 ){
250003
+ pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT));
250004
+ pIter->pTokenDataIter = pT;
250005
+ }
250006
+ if( pT ){
250007
+ fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos);
250008
+ fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken);
250009
+ }
250010
+ }else{
250011
+ int ii;
250012
+ for(ii=0; ii<pT->nIter; ii++){
250013
+ Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
250014
+ if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
250015
+ }
250016
+ if( ii<pT->nIter ){
250017
+ fts5TokendataIterAppendMap(p, pT, ii, 0, iRowid, iPos);
250018
+ }
249224250019
}
249225250020
return fts5IndexReturn(p);
249226250021
}
249227250022
249228250023
/*
@@ -250771,11 +251566,11 @@
250771251566
return rc;
250772251567
}
250773251568
250774251569
/*
250775251570
** We must have a single struct=? constraint that will be passed through
250776
-** into the xFilter method. If there is no valid stmt=? constraint,
251571
+** into the xFilter method. If there is no valid struct=? constraint,
250777251572
** then return an SQLITE_CONSTRAINT error.
250778251573
*/
250779251574
static int fts5structBestIndexMethod(
250780251575
sqlite3_vtab *tab,
250781251576
sqlite3_index_info *pIdxInfo
@@ -251113,12 +251908,22 @@
251113251908
i64 iNextId; /* Used to allocate unique cursor ids */
251114251909
Fts5Auxiliary *pAux; /* First in list of all aux. functions */
251115251910
Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
251116251911
Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
251117251912
Fts5Cursor *pCsr; /* First in list of all open cursors */
251913
+ u32 aLocaleHdr[4];
251118251914
};
251119251915
251916
+/*
251917
+** Size of header on fts5_locale() values. And macro to access a buffer
251918
+** containing a copy of the header from an Fts5Config pointer.
251919
+*/
251920
+#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr ))
251921
+#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr))
251922
+
251923
+#define FTS5_INSTTOKEN_SUBTYPE 73
251924
+
251120251925
/*
251121251926
** Each auxiliary function registered with the FTS5 module is represented
251122251927
** by an object of the following type. All such objects are stored as part
251123251928
** of the Fts5Global.pAux list.
251124251929
*/
@@ -251277,16 +252082,10 @@
251277252082
#define FTS5CSR_REQUIRE_POSLIST 0x40
251278252083
251279252084
#define BitFlagAllTest(x,y) (((x) & (y))==(y))
251280252085
#define BitFlagTest(x,y) (((x) & (y))!=0)
251281252086
251282
-/*
251283
-** The subtype value and header bytes used by fts5_locale().
251284
-*/
251285
-#define FTS5_LOCALE_SUBTYPE ((unsigned int)'L')
251286
-#define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB"
251287
-
251288252087
251289252088
/*
251290252089
** Macros to Set(), Clear() and Test() cursor flags.
251291252090
*/
251292252091
#define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
@@ -251359,14 +252158,20 @@
251359252158
#else
251360252159
# define fts5CheckTransactionState(x,y,z)
251361252160
#endif
251362252161
251363252162
/*
251364
-** Return true if pTab is a contentless table.
252163
+** Return true if pTab is a contentless table. If parameter bIncludeUnindexed
252164
+** is true, this includes contentless tables that store UNINDEXED columns
252165
+** only.
251365252166
*/
251366
-static int fts5IsContentless(Fts5FullTable *pTab){
251367
- return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
252167
+static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){
252168
+ int eContent = pTab->p.pConfig->eContent;
252169
+ return (
252170
+ eContent==FTS5_CONTENT_NONE
252171
+ || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED)
252172
+ );
251368252173
}
251369252174
251370252175
/*
251371252176
** Delete a virtual table handle allocated by fts5InitVtab().
251372252177
*/
@@ -251653,10 +252458,11 @@
251653252458
){
251654252459
/* A MATCH operator or equivalent */
251655252460
if( p->usable==0 || iCol<0 ){
251656252461
/* As there exists an unusable MATCH constraint this is an
251657252462
** unusable plan. Return SQLITE_CONSTRAINT. */
252463
+ idxStr[iIdxStr] = 0;
251658252464
return SQLITE_CONSTRAINT;
251659252465
}else{
251660252466
if( iCol==nCol+1 ){
251661252467
if( bSeenRank ) continue;
251662252468
idxStr[iIdxStr++] = 'r';
@@ -252286,11 +253092,11 @@
252286253092
** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
252287253093
** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
252288253094
** valid until after the final call to sqlite3Fts5Tokenize() that will use
252289253095
** the locale.
252290253096
*/
252291
-static void fts5SetLocale(
253097
+static void sqlite3Fts5SetLocale(
252292253098
Fts5Config *pConfig,
252293253099
const char *zLocale,
252294253100
int nLocale
252295253101
){
252296253102
Fts5TokenizerConfig *pT = &pConfig->t;
@@ -252297,141 +253103,88 @@
252297253103
pT->pLocale = zLocale;
252298253104
pT->nLocale = nLocale;
252299253105
}
252300253106
252301253107
/*
252302
-** Clear any locale configured by an earlier call to fts5SetLocale() or
252303
-** sqlite3Fts5ExtractText().
253108
+** Clear any locale configured by an earlier call to sqlite3Fts5SetLocale().
252304253109
*/
252305253110
static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
252306
- fts5SetLocale(pConfig, 0, 0);
253111
+ sqlite3Fts5SetLocale(pConfig, 0, 0);
252307253112
}
252308253113
252309253114
/*
252310
-** This function is used to extract utf-8 text from an sqlite3_value. This
252311
-** is usually done in order to tokenize it. For example, when:
252312
-**
252313
-** * a value is written to an fts5 table,
252314
-** * a value is deleted from an FTS5_CONTENT_NORMAL table,
252315
-** * a value containing a query expression is passed to xFilter()
252316
-**
252317
-** and so on.
252318
-**
252319
-** This function handles 2 cases:
252320
-**
252321
-** 1) Ordinary values. The text can be extracted from these using
252322
-** sqlite3_value_text().
252323
-**
252324
-** 2) Combination text/locale blobs created by fts5_locale(). There
252325
-** are several cases for these:
252326
-**
252327
-** * Blobs tagged with FTS5_LOCALE_SUBTYPE.
252328
-** * Blobs read from the content table of a locale=1 external-content
252329
-** table, and
252330
-** * Blobs read from the content table of a locale=1 regular
252331
-** content table.
252332
-**
252333
-** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER
252334
-** header. It is an error if a blob with the subtype or a blob read
252335
-** from the content table of an external content table does not have
252336
-** the required header. A blob read from the content table of a regular
252337
-** locale=1 table does not have the header. This is to save space.
252338
-**
252339
-** If successful, SQLITE_OK is returned and output parameters (*ppText)
252340
-** and (*pnText) are set to point to a buffer containing the extracted utf-8
252341
-** text and its length in bytes, respectively. The buffer is not
252342
-** nul-terminated. It has the same lifetime as the sqlite3_value object
252343
-** from which it is extracted.
252344
-**
252345
-** Parameter bContent must be true if the value was read from an indexed
252346
-** column (i.e. not UNINDEXED) of the on disk content.
252347
-**
252348
-** If pbResetTokenizer is not NULL and if case (2) is used, then
252349
-** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls
252350
-** use the locale. In this case (*pbResetTokenizer) is set to true before
252351
-** returning, to indicate that the caller must call sqlite3Fts5ClearLocale()
252352
-** to clear the locale after tokenizing the text.
253115
+** Return true if the value passed as the only argument is an
253116
+** fts5_locale() value.
252353253117
*/
252354
-static int sqlite3Fts5ExtractText(
252355
- Fts5Config *pConfig,
252356
- sqlite3_value *pVal, /* Value to extract text from */
252357
- int bContent, /* True if indexed table content */
252358
- int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */
252359
- const char **ppText, /* OUT: Pointer to text buffer */
252360
- int *pnText /* OUT: Size of (*ppText) in bytes */
252361
-){
252362
- const char *pText = 0;
252363
- int nText = 0;
252364
- int rc = SQLITE_OK;
252365
- int bDecodeBlob = 0;
252366
-
252367
- assert( pbResetTokenizer==0 || *pbResetTokenizer==0 );
252368
- assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE );
252369
- assert( bContent==0 || sqlite3_value_subtype(pVal)==0 );
252370
-
253118
+static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal){
253119
+ int ret = 0;
252371253120
if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
252372
- if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE
252373
- || (bContent && pConfig->bLocale)
252374
- ){
252375
- bDecodeBlob = 1;
252376
- }
252377
- }
252378
-
252379
- if( bDecodeBlob ){
252380
- const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
253121
+ /* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case.
253122
+ ** If the blob was created using zeroblob(), then sqlite3_value_blob()
253123
+ ** may call malloc(). If this malloc() fails, then the values returned
253124
+ ** by both value_blob() and value_bytes() will be 0. If value_bytes() were
253125
+ ** called first, then the NULL pointer returned by value_blob() might
253126
+ ** be dereferenced. */
252381253127
const u8 *pBlob = sqlite3_value_blob(pVal);
252382253128
int nBlob = sqlite3_value_bytes(pVal);
252383
-
252384
- /* Unless this blob was read from the %_content table of an
252385
- ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale()
252386
- ** header. Check for this. If it is not found, return an error. */
252387
- if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){
252388
- if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
252389
- rc = SQLITE_ERROR;
252390
- }else{
252391
- pBlob += 4;
252392
- nBlob -= 4;
252393
- }
252394
- }
252395
-
252396
- if( rc==SQLITE_OK ){
252397
- int nLocale = 0;
252398
-
252399
- for(nLocale=0; nLocale<nBlob; nLocale++){
252400
- if( pBlob[nLocale]==0x00 ) break;
252401
- }
252402
- if( nLocale==nBlob || nLocale==0 ){
252403
- rc = SQLITE_ERROR;
252404
- }else{
252405
- pText = (const char*)&pBlob[nLocale+1];
252406
- nText = nBlob-nLocale-1;
252407
-
252408
- if( pbResetTokenizer ){
252409
- fts5SetLocale(pConfig, (const char*)pBlob, nLocale);
252410
- *pbResetTokenizer = 1;
252411
- }
252412
- }
252413
- }
252414
-
252415
- }else{
252416
- pText = (const char*)sqlite3_value_text(pVal);
252417
- nText = sqlite3_value_bytes(pVal);
252418
- }
252419
-
252420
- *ppText = pText;
252421
- *pnText = nText;
252422
- return rc;
253129
+ if( nBlob>FTS5_LOCALE_HDR_SIZE
253130
+ && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE)
253131
+ ){
253132
+ ret = 1;
253133
+ }
253134
+ }
253135
+ return ret;
253136
+}
253137
+
253138
+/*
253139
+** Value pVal is guaranteed to be an fts5_locale() value, according to
253140
+** sqlite3Fts5IsLocaleValue(). This function extracts the text and locale
253141
+** from the value and returns them separately.
253142
+**
253143
+** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set
253144
+** to point to buffers containing the text and locale, as utf-8,
253145
+** respectively. In this case output parameters (*pnText) and (*pnLoc) are
253146
+** set to the sizes in bytes of these two buffers.
253147
+**
253148
+** Or, if an error occurs, then an SQLite error code is returned. The final
253149
+** value of the four output parameters is undefined in this case.
253150
+*/
253151
+static int sqlite3Fts5DecodeLocaleValue(
253152
+ sqlite3_value *pVal,
253153
+ const char **ppText,
253154
+ int *pnText,
253155
+ const char **ppLoc,
253156
+ int *pnLoc
253157
+){
253158
+ const char *p = sqlite3_value_blob(pVal);
253159
+ int n = sqlite3_value_bytes(pVal);
253160
+ int nLoc = 0;
253161
+
253162
+ assert( sqlite3_value_type(pVal)==SQLITE_BLOB );
253163
+ assert( n>FTS5_LOCALE_HDR_SIZE );
253164
+
253165
+ for(nLoc=FTS5_LOCALE_HDR_SIZE; p[nLoc]; nLoc++){
253166
+ if( nLoc==(n-1) ){
253167
+ return SQLITE_MISMATCH;
253168
+ }
253169
+ }
253170
+ *ppLoc = &p[FTS5_LOCALE_HDR_SIZE];
253171
+ *pnLoc = nLoc - FTS5_LOCALE_HDR_SIZE;
253172
+
253173
+ *ppText = &p[nLoc+1];
253174
+ *pnText = n - nLoc - 1;
253175
+ return SQLITE_OK;
252423253176
}
252424253177
252425253178
/*
252426253179
** Argument pVal is the text of a full-text search expression. It may or
252427253180
** may not have been wrapped by fts5_locale(). This function extracts
252428253181
** the text of the expression, and sets output variable (*pzText) to
252429253182
** point to a nul-terminated buffer containing the expression.
252430253183
**
252431
-** If pVal was an fts5_locale() value, then fts5SetLocale() is called to
252432
-** set the tokenizer to use the specified locale.
253184
+** If pVal was an fts5_locale() value, then sqlite3Fts5SetLocale() is called
253185
+** to set the tokenizer to use the specified locale.
252433253186
**
252434253187
** If output variable (*pbFreeAndReset) is set to true, then the caller
252435253188
** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
252436253189
** locale, and (b) call sqlite3_free() to free (*pzText).
252437253190
*/
@@ -252439,28 +253192,26 @@
252439253192
Fts5Config *pConfig, /* Fts5 configuration */
252440253193
sqlite3_value *pVal, /* Value to extract expression text from */
252441253194
char **pzText, /* OUT: nul-terminated buffer of text */
252442253195
int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
252443253196
){
252444
- const char *zText = 0;
252445
- int nText = 0;
252446253197
int rc = SQLITE_OK;
252447
- int bReset = 0;
252448
-
252449
- *pbFreeAndReset = 0;
252450
- rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, &bReset, &zText, &nText);
252451
- if( rc==SQLITE_OK ){
252452
- if( bReset ){
252453
- *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, zText);
252454
- if( rc!=SQLITE_OK ){
252455
- sqlite3Fts5ClearLocale(pConfig);
252456
- }else{
252457
- *pbFreeAndReset = 1;
252458
- }
252459
- }else{
252460
- *pzText = (char*)zText;
252461
- }
253198
+
253199
+ if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
253200
+ const char *pText = 0;
253201
+ int nText = 0;
253202
+ const char *pLoc = 0;
253203
+ int nLoc = 0;
253204
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
253205
+ *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, pText);
253206
+ if( rc==SQLITE_OK ){
253207
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
253208
+ }
253209
+ *pbFreeAndReset = 1;
253210
+ }else{
253211
+ *pzText = (char*)sqlite3_value_text(pVal);
253212
+ *pbFreeAndReset = 0;
252462253213
}
252463253214
252464253215
return rc;
252465253216
}
252466253217
@@ -252493,10 +253244,11 @@
252493253244
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
252494253245
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
252495253246
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
252496253247
int iCol; /* Column on LHS of MATCH operator */
252497253248
char **pzErrmsg = pConfig->pzErrmsg;
253249
+ int bPrefixInsttoken = pConfig->bPrefixInsttoken;
252498253250
int i;
252499253251
int iIdxStr = 0;
252500253252
Fts5Expr *pExpr = 0;
252501253253
252502253254
assert( pConfig->bLock==0 );
@@ -252528,10 +253280,13 @@
252528253280
int bInternal = 0;
252529253281
252530253282
rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
252531253283
if( rc!=SQLITE_OK ) goto filter_out;
252532253284
if( zText==0 ) zText = "";
253285
+ if( sqlite3_value_subtype(apVal[i])==FTS5_INSTTOKEN_SUBTYPE ){
253286
+ pConfig->bPrefixInsttoken = 1;
253287
+ }
252533253288
252534253289
iCol = 0;
252535253290
do{
252536253291
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
252537253292
iIdxStr++;
@@ -252668,10 +253423,11 @@
252668253423
}
252669253424
252670253425
filter_out:
252671253426
sqlite3Fts5ExprFree(pExpr);
252672253427
pConfig->pzErrmsg = pzErrmsg;
253428
+ pConfig->bPrefixInsttoken = bPrefixInsttoken;
252673253429
return rc;
252674253430
}
252675253431
252676253432
/*
252677253433
** This is the xEof method of the virtual table. SQLite calls this
@@ -252808,11 +253564,11 @@
252808253564
}else{
252809253565
rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
252810253566
}
252811253567
bLoadConfig = 1;
252812253568
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
252813
- if( pConfig->eContent==FTS5_CONTENT_NONE ){
253569
+ if( fts5IsContentless(pTab, 1) ){
252814253570
fts5SetVtabError(pTab,
252815253571
"'rebuild' may not be used with a contentless fts5 table"
252816253572
);
252817253573
rc = SQLITE_ERROR;
252818253574
}else{
@@ -252877,17 +253633,78 @@
252877253633
sqlite3_value **apVal,
252878253634
i64 *piRowid
252879253635
){
252880253636
int rc = *pRc;
252881253637
if( rc==SQLITE_OK ){
252882
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
253638
+ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid);
252883253639
}
252884253640
if( rc==SQLITE_OK ){
252885253641
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
252886253642
}
252887253643
*pRc = rc;
252888253644
}
253645
+
253646
+/*
253647
+**
253648
+** This function is called when the user attempts an UPDATE on a contentless
253649
+** table. Parameter bRowidModified is true if the UPDATE statement modifies
253650
+** the rowid value. Parameter apVal[] contains the new values for each user
253651
+** defined column of the fts5 table. pConfig is the configuration object of the
253652
+** table being updated (guaranteed to be contentless). The contentless_delete=1
253653
+** and contentless_unindexed=1 options may or may not be set.
253654
+**
253655
+** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite
253656
+** error code if it cannot. In this case an error message is also loaded into
253657
+** pConfig. Output parameter (*pbContent) is set to true if the caller should
253658
+** update the %_content table only - not the FTS index or any other shadow
253659
+** table. This occurs when an UPDATE modifies only UNINDEXED columns of the
253660
+** table.
253661
+**
253662
+** An UPDATE may proceed if:
253663
+**
253664
+** * The only columns modified are UNINDEXED columns, or
253665
+**
253666
+** * The contentless_delete=1 option was specified and all of the indexed
253667
+** columns (not a subset) have been modified.
253668
+*/
253669
+static int fts5ContentlessUpdate(
253670
+ Fts5Config *pConfig,
253671
+ sqlite3_value **apVal,
253672
+ int bRowidModified,
253673
+ int *pbContent
253674
+){
253675
+ int ii;
253676
+ int bSeenIndex = 0; /* Have seen modified indexed column */
253677
+ int bSeenIndexNC = 0; /* Have seen unmodified indexed column */
253678
+ int rc = SQLITE_OK;
253679
+
253680
+ for(ii=0; ii<pConfig->nCol; ii++){
253681
+ if( pConfig->abUnindexed[ii]==0 ){
253682
+ if( sqlite3_value_nochange(apVal[ii]) ){
253683
+ bSeenIndexNC++;
253684
+ }else{
253685
+ bSeenIndex++;
253686
+ }
253687
+ }
253688
+ }
253689
+
253690
+ if( bSeenIndex==0 && bRowidModified==0 ){
253691
+ *pbContent = 1;
253692
+ }else{
253693
+ if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){
253694
+ rc = SQLITE_ERROR;
253695
+ sqlite3Fts5ConfigErrmsg(pConfig,
253696
+ (pConfig->bContentlessDelete ?
253697
+ "%s a subset of columns on fts5 contentless-delete table: %s" :
253698
+ "%s contentless fts5 table: %s")
253699
+ , "cannot UPDATE", pConfig->zName
253700
+ );
253701
+ }
253702
+ }
253703
+
253704
+ return rc;
253705
+}
252889253706
252890253707
/*
252891253708
** This function is the implementation of the xUpdate callback used by
252892253709
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
252893253710
** inserted, updated or deleted.
@@ -252971,48 +253788,38 @@
252971253788
}
252972253789
252973253790
assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
252974253791
assert( nArg!=1 || eType0==SQLITE_INTEGER );
252975253792
252976
- /* Filter out attempts to run UPDATE or DELETE on contentless tables.
252977
- ** This is not suported. Except - they are both supported if the CREATE
252978
- ** VIRTUAL TABLE statement contained "contentless_delete=1". */
252979
- if( eType0==SQLITE_INTEGER
252980
- && pConfig->eContent==FTS5_CONTENT_NONE
252981
- && pConfig->bContentlessDelete==0
252982
- ){
252983
- pTab->p.base.zErrMsg = sqlite3_mprintf(
252984
- "cannot %s contentless fts5 table: %s",
252985
- (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
252986
- );
252987
- rc = SQLITE_ERROR;
252988
- }
252989
-
252990253793
/* DELETE */
252991
- else if( nArg==1 ){
252992
- i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
252993
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
252994
- bUpdateOrDelete = 1;
253794
+ if( nArg==1 ){
253795
+ /* It is only possible to DELETE from a contentless table if the
253796
+ ** contentless_delete=1 flag is set. */
253797
+ if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){
253798
+ fts5SetVtabError(pTab,
253799
+ "cannot DELETE from contentless fts5 table: %s", pConfig->zName
253800
+ );
253801
+ rc = SQLITE_ERROR;
253802
+ }else{
253803
+ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
253804
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
253805
+ bUpdateOrDelete = 1;
253806
+ }
252995253807
}
252996253808
252997253809
/* INSERT or UPDATE */
252998253810
else{
252999253811
int eType1 = sqlite3_value_numeric_type(apVal[1]);
253000253812
253001
- /* Ensure that no fts5_locale() values are written to locale=0 tables.
253002
- ** And that no blobs except fts5_locale() blobs are written to indexed
253003
- ** (i.e. not UNINDEXED) columns of locale=1 tables. */
253004
- int ii;
253005
- for(ii=0; ii<pConfig->nCol; ii++){
253006
- if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){
253007
- int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE);
253008
- if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0)
253009
- || (pConfig->bLocale==0 && bSub)
253010
- ){
253011
- if( pConfig->bLocale==0 ){
253012
- fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
253013
- }
253813
+ /* It is an error to write an fts5_locale() value to a table without
253814
+ ** the locale=1 option. */
253815
+ if( pConfig->bLocale==0 ){
253816
+ int ii;
253817
+ for(ii=0; ii<pConfig->nCol; ii++){
253818
+ sqlite3_value *pVal = apVal[ii+2];
253819
+ if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
253820
+ fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
253014253821
rc = SQLITE_MISMATCH;
253015253822
goto update_out;
253016253823
}
253017253824
}
253018253825
}
@@ -253028,39 +253835,59 @@
253028253835
fts5StorageInsert(&rc, pTab, apVal, pRowid);
253029253836
}
253030253837
253031253838
/* UPDATE */
253032253839
else{
253033
- i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
253034
- i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
253035
- if( eType1!=SQLITE_INTEGER ){
253036
- rc = SQLITE_MISMATCH;
253037
- }else if( iOld!=iNew ){
253038
- if( eConflict==SQLITE_REPLACE ){
253039
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253040
- if( rc==SQLITE_OK ){
253041
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
253042
- }
253043
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
253044
- }else{
253045
- rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld);
253046
- if( rc==SQLITE_OK ){
253047
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid);
253048
- }
253049
- if( rc==SQLITE_OK ){
253050
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253051
- }
253052
- if( rc==SQLITE_OK ){
253053
- rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
253054
- }
253055
- }
253056
- }else{
253057
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253058
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
253059
- }
253060
- bUpdateOrDelete = 1;
253061
- sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage);
253840
+ Fts5Storage *pStorage = pTab->pStorage;
253841
+ i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
253842
+ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
253843
+ int bContent = 0; /* Content only update */
253844
+
253845
+ /* If this is a contentless table (including contentless_unindexed=1
253846
+ ** tables), check if the UPDATE may proceed. */
253847
+ if( fts5IsContentless(pTab, 1) ){
253848
+ rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent);
253849
+ if( rc!=SQLITE_OK ) goto update_out;
253850
+ }
253851
+
253852
+ if( eType1!=SQLITE_INTEGER ){
253853
+ rc = SQLITE_MISMATCH;
253854
+ }else if( iOld!=iNew ){
253855
+ assert( bContent==0 );
253856
+ if( eConflict==SQLITE_REPLACE ){
253857
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
253858
+ if( rc==SQLITE_OK ){
253859
+ rc = sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0);
253860
+ }
253861
+ fts5StorageInsert(&rc, pTab, apVal, pRowid);
253862
+ }else{
253863
+ rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
253864
+ if( rc==SQLITE_OK ){
253865
+ rc = sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid);
253866
+ }
253867
+ if( rc==SQLITE_OK ){
253868
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0);
253869
+ }
253870
+ if( rc==SQLITE_OK ){
253871
+ rc = sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid);
253872
+ }
253873
+ }
253874
+ }else if( bContent ){
253875
+ /* This occurs when an UPDATE on a contentless table affects *only*
253876
+ ** UNINDEXED columns. This is a no-op for contentless_unindexed=0
253877
+ ** tables, or a write to the %_content table only for =1 tables. */
253878
+ assert( fts5IsContentless(pTab, 1) );
253879
+ rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
253880
+ if( rc==SQLITE_OK ){
253881
+ rc = sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid);
253882
+ }
253883
+ }else{
253884
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
253885
+ fts5StorageInsert(&rc, pTab, apVal, pRowid);
253886
+ }
253887
+ bUpdateOrDelete = 1;
253888
+ sqlite3Fts5StorageReleaseDeleteRow(pStorage);
253062253889
}
253063253890
253064253891
}
253065253892
}
253066253893
@@ -253169,15 +253996,15 @@
253169253996
){
253170253997
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253171253998
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253172253999
int rc = SQLITE_OK;
253173254000
253174
- fts5SetLocale(pTab->pConfig, pLoc, nLoc);
254001
+ sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc);
253175254002
rc = sqlite3Fts5Tokenize(pTab->pConfig,
253176254003
FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
253177254004
);
253178
- fts5SetLocale(pTab->pConfig, 0, 0);
254005
+ sqlite3Fts5SetLocale(pTab->pConfig, 0, 0);
253179254006
253180254007
return rc;
253181254008
}
253182254009
253183254010
/*
@@ -253200,10 +254027,53 @@
253200254027
253201254028
static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
253202254029
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253203254030
return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
253204254031
}
254032
+
254033
+/*
254034
+** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This
254035
+** function extracts the text value of column iCol of the current row.
254036
+** Additionally, if there is an associated locale, it invokes
254037
+** sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller
254038
+** should invoke sqlite3Fts5ClearLocale() to clear the locale at some point
254039
+** after this function returns.
254040
+**
254041
+** If successful, (*ppText) is set to point to a buffer containing the text
254042
+** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that
254043
+** buffer in bytes. It is not guaranteed to be nul-terminated. If an error
254044
+** occurs, an SQLite error code is returned. The final values of the two
254045
+** output parameters are undefined in this case.
254046
+*/
254047
+static int fts5TextFromStmt(
254048
+ Fts5Config *pConfig,
254049
+ sqlite3_stmt *pStmt,
254050
+ int iCol,
254051
+ const char **ppText,
254052
+ int *pnText
254053
+){
254054
+ sqlite3_value *pVal = sqlite3_column_value(pStmt, iCol+1);
254055
+ const char *pLoc = 0;
254056
+ int nLoc = 0;
254057
+ int rc = SQLITE_OK;
254058
+
254059
+ if( pConfig->bLocale
254060
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
254061
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
254062
+ ){
254063
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc);
254064
+ }else{
254065
+ *ppText = (const char*)sqlite3_value_text(pVal);
254066
+ *pnText = sqlite3_value_bytes(pVal);
254067
+ if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){
254068
+ pLoc = (const char*)sqlite3_column_text(pStmt, iCol+1+pConfig->nCol);
254069
+ nLoc = sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol);
254070
+ }
254071
+ }
254072
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
254073
+ return rc;
254074
+}
253205254075
253206254076
static int fts5ApiColumnText(
253207254077
Fts5Context *pCtx,
253208254078
int iCol,
253209254079
const char **pz,
@@ -253214,20 +254084,18 @@
253214254084
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253215254085
253216254086
assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253217254087
if( iCol<0 || iCol>=pTab->pConfig->nCol ){
253218254088
rc = SQLITE_RANGE;
253219
- }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){
254089
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){
253220254090
*pz = 0;
253221254091
*pn = 0;
253222254092
}else{
253223254093
rc = fts5SeekCursor(pCsr, 0);
253224254094
if( rc==SQLITE_OK ){
253225
- Fts5Config *pConfig = pTab->pConfig;
253226
- int bContent = (pConfig->abUnindexed[iCol]==0);
253227
- sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253228
- sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn);
254095
+ rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn);
254096
+ sqlite3Fts5ClearLocale(pTab->pConfig);
253229254097
}
253230254098
}
253231254099
return rc;
253232254100
}
253233254101
@@ -253249,11 +254117,11 @@
253249254117
int bLive = (pCsr->pSorter==0);
253250254118
253251254119
if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
253252254120
rc = SQLITE_RANGE;
253253254121
}else if( pConfig->eDetail!=FTS5_DETAIL_FULL
253254
- && pConfig->eContent==FTS5_CONTENT_NONE
254122
+ && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
253255254123
){
253256254124
*pa = 0;
253257254125
*pn = 0;
253258254126
return SQLITE_OK;
253259254127
}else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
@@ -253265,21 +254133,19 @@
253265254133
if( aPopulator==0 ) rc = SQLITE_NOMEM;
253266254134
if( rc==SQLITE_OK ){
253267254135
rc = fts5SeekCursor(pCsr, 0);
253268254136
}
253269254137
for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
253270
- sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253271254138
const char *z = 0;
253272254139
int n = 0;
253273
- int bReset = 0;
253274
- rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
254140
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
253275254141
if( rc==SQLITE_OK ){
253276254142
rc = sqlite3Fts5ExprPopulatePoslists(
253277254143
pConfig, pCsr->pExpr, aPopulator, i, z, n
253278254144
);
253279254145
}
253280
- if( bReset ) sqlite3Fts5ClearLocale(pConfig);
254146
+ sqlite3Fts5ClearLocale(pConfig);
253281254147
}
253282254148
sqlite3_free(aPopulator);
253283254149
253284254150
if( pCsr->pSorter ){
253285254151
sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
@@ -253447,11 +254313,11 @@
253447254313
253448254314
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
253449254315
if( pConfig->bColumnsize ){
253450254316
i64 iRowid = fts5CursorRowid(pCsr);
253451254317
rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
253452
- }else if( pConfig->zContent==0 ){
254318
+ }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
253453254319
int i;
253454254320
for(i=0; i<pConfig->nCol; i++){
253455254321
if( pConfig->abUnindexed[i]==0 ){
253456254322
pCsr->aColumnSize[i] = -1;
253457254323
}
@@ -253461,21 +254327,18 @@
253461254327
rc = fts5SeekCursor(pCsr, 0);
253462254328
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
253463254329
if( pConfig->abUnindexed[i]==0 ){
253464254330
const char *z = 0;
253465254331
int n = 0;
253466
- int bReset = 0;
253467
- sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253468
-
253469254332
pCsr->aColumnSize[i] = 0;
253470
- rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
254333
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
253471254334
if( rc==SQLITE_OK ){
253472254335
rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
253473254336
z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
253474254337
);
253475
- if( bReset ) sqlite3Fts5ClearLocale(pConfig);
253476254338
}
254339
+ sqlite3Fts5ClearLocale(pConfig);
253477254340
}
253478254341
}
253479254342
}
253480254343
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
253481254344
}
@@ -253738,46 +254601,23 @@
253738254601
assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253739254602
if( iCol<0 || iCol>=pConfig->nCol ){
253740254603
rc = SQLITE_RANGE;
253741254604
}else if(
253742254605
pConfig->abUnindexed[iCol]==0
253743
- && pConfig->eContent!=FTS5_CONTENT_NONE
254606
+ && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
253744254607
&& pConfig->bLocale
253745254608
){
253746254609
rc = fts5SeekCursor(pCsr, 0);
253747254610
if( rc==SQLITE_OK ){
253748
- /* Load the value into pVal. pVal is a locale/text pair iff:
253749
- **
253750
- ** 1) It is an SQLITE_BLOB, and
253751
- ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the
253752
- ** value was loaded from an FTS5_CONTENT_NORMAL table, and
253753
- ** 3) It does not begin with an 0x00 byte.
253754
- */
253755
- sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253756
- if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
253757
- const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
253758
- int nBlob = sqlite3_value_bytes(pVal);
253759
- if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
253760
- const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
253761
- if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
253762
- rc = SQLITE_ERROR;
253763
- }
253764
- pBlob += 4;
253765
- nBlob -= 4;
253766
- }
253767
- if( rc==SQLITE_OK ){
253768
- int nLocale = 0;
253769
- for(nLocale=0; nLocale<nBlob && pBlob[nLocale]!=0x00; nLocale++);
253770
- if( nLocale==nBlob || nLocale==0 ){
253771
- rc = SQLITE_ERROR;
253772
- }else{
253773
- /* A locale/text pair */
253774
- *pzLocale = (const char*)pBlob;
253775
- *pnLocale = nLocale;
253776
- }
253777
- }
253778
- }
254611
+ const char *zDummy = 0;
254612
+ int nDummy = 0;
254613
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy);
254614
+ if( rc==SQLITE_OK ){
254615
+ *pzLocale = pConfig->t.pLocale;
254616
+ *pnLocale = pConfig->t.nLocale;
254617
+ }
254618
+ sqlite3Fts5ClearLocale(pConfig);
253779254619
}
253780254620
}
253781254621
253782254622
return rc;
253783254623
}
@@ -253994,61 +254834,10 @@
253994254834
253995254835
sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
253996254836
return rc;
253997254837
}
253998254838
253999
-/*
254000
-** Value pVal was read from column iCol of the FTS5 table. This function
254001
-** returns it to the owner of pCtx via a call to an sqlite3_result_xxx()
254002
-** function. This function deals with the same cases as
254003
-** sqlite3Fts5ExtractText():
254004
-**
254005
-** 1) Ordinary values. These can be returned using sqlite3_result_value().
254006
-**
254007
-** 2) Blobs from fts5_locale(). The text is extracted from these and
254008
-** returned via sqlite3_result_text(). The locale is discarded.
254009
-*/
254010
-static void fts5ExtractValueFromColumn(
254011
- sqlite3_context *pCtx,
254012
- Fts5Config *pConfig,
254013
- int iCol,
254014
- sqlite3_value *pVal
254015
-){
254016
- assert( pConfig->eContent!=FTS5_CONTENT_NONE );
254017
-
254018
- if( pConfig->bLocale
254019
- && sqlite3_value_type(pVal)==SQLITE_BLOB
254020
- && pConfig->abUnindexed[iCol]==0
254021
- ){
254022
- const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
254023
- const u8 *pBlob = sqlite3_value_blob(pVal);
254024
- int nBlob = sqlite3_value_bytes(pVal);
254025
- int ii;
254026
-
254027
- if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
254028
- if( nBlob<SZHDR || memcmp(pBlob, FTS5_LOCALE_HEADER, SZHDR) ){
254029
- sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254030
- return;
254031
- }else{
254032
- pBlob += 4;
254033
- nBlob -= 4;
254034
- }
254035
- }
254036
-
254037
- for(ii=0; ii<nBlob && pBlob[ii]; ii++);
254038
- if( ii==0 || ii==nBlob ){
254039
- sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254040
- }else{
254041
- const char *pText = (const char*)&pBlob[ii+1];
254042
- sqlite3_result_text(pCtx, pText, nBlob-ii-1, SQLITE_TRANSIENT);
254043
- }
254044
- return;
254045
- }
254046
-
254047
- sqlite3_result_value(pCtx, pVal);
254048
-}
254049
-
254050254839
/*
254051254840
** This is the xColumn method, called by SQLite to request a value from
254052254841
** the row that the supplied cursor currently points to.
254053254842
*/
254054254843
static int fts5ColumnMethod(
@@ -254087,26 +254876,31 @@
254087254876
if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
254088254877
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
254089254878
}
254090254879
}
254091254880
}else{
254092
- /* A column created by the user containing values. */
254093
- int bNochange = sqlite3_vtab_nochange(pCtx);
254094
-
254095
- if( fts5IsContentless(pTab) ){
254096
- if( bNochange && pConfig->bContentlessDelete ){
254097
- fts5ResultError(pCtx, "cannot UPDATE a subset of "
254098
- "columns on fts5 contentless-delete table: %s", pConfig->zName
254099
- );
254100
- }
254101
- }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){
254881
+ if( !sqlite3_vtab_nochange(pCtx) && pConfig->eContent!=FTS5_CONTENT_NONE ){
254102254882
pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
254103254883
rc = fts5SeekCursor(pCsr, 1);
254104254884
if( rc==SQLITE_OK ){
254105254885
sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
254106
- fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal);
254886
+ if( pConfig->bLocale
254887
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
254888
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
254889
+ ){
254890
+ const char *z = 0;
254891
+ int n = 0;
254892
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n);
254893
+ if( rc==SQLITE_OK ){
254894
+ sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT);
254895
+ }
254896
+ sqlite3Fts5ClearLocale(pConfig);
254897
+ }else{
254898
+ sqlite3_result_value(pCtx, pVal);
254899
+ }
254107254900
}
254901
+
254108254902
pConfig->pzErrmsg = 0;
254109254903
}
254110254904
}
254111254905
254112254906
return rc;
@@ -254625,11 +255419,11 @@
254625255419
int nArg, /* Number of args */
254626255420
sqlite3_value **apUnused /* Function arguments */
254627255421
){
254628255422
assert( nArg==0 );
254629255423
UNUSED_PARAM2(nArg, apUnused);
254630
- sqlite3_result_text(pCtx, "fts5: 2024-09-02 18:41:59 e6bec37ea1ca51e1d048941ce4c5211d8fc5c5e3556a1441f9c79b036843f9e3", -1, SQLITE_TRANSIENT);
255424
+ sqlite3_result_text(pCtx, "fts5: 2024-12-09 20:46:36 e2bae4143afd07de1ae55a6d2606a3b541a5b94568aa41f6a96e5d1245471653", -1, SQLITE_TRANSIENT);
254631255425
}
254632255426
254633255427
/*
254634255428
** Implementation of fts5_locale(LOCALE, TEXT) function.
254635255429
**
@@ -254664,36 +255458,48 @@
254664255458
nText = sqlite3_value_bytes(apArg[1]);
254665255459
254666255460
if( zLocale==0 || zLocale[0]=='\0' ){
254667255461
sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
254668255462
}else{
255463
+ Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx);
254669255464
u8 *pBlob = 0;
254670255465
u8 *pCsr = 0;
254671255466
int nBlob = 0;
254672
- const int nHdr = 4;
254673
- assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 );
254674255467
254675
- nBlob = nHdr + nLocale + 1 + nText;
255468
+ nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText;
254676255469
pBlob = (u8*)sqlite3_malloc(nBlob);
254677255470
if( pBlob==0 ){
254678255471
sqlite3_result_error_nomem(pCtx);
254679255472
return;
254680255473
}
254681255474
254682255475
pCsr = pBlob;
254683
- memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr);
254684
- pCsr += nHdr;
255476
+ memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE);
255477
+ pCsr += FTS5_LOCALE_HDR_SIZE;
254685255478
memcpy(pCsr, zLocale, nLocale);
254686255479
pCsr += nLocale;
254687255480
(*pCsr++) = 0x00;
254688255481
if( zText ) memcpy(pCsr, zText, nText);
254689255482
assert( &pCsr[nText]==&pBlob[nBlob] );
254690255483
254691255484
sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
254692
- sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE);
254693255485
}
254694255486
}
255487
+
255488
+/*
255489
+** Implementation of fts5_insttoken() function.
255490
+*/
255491
+static void fts5InsttokenFunc(
255492
+ sqlite3_context *pCtx, /* Function call context */
255493
+ int nArg, /* Number of args */
255494
+ sqlite3_value **apArg /* Function arguments */
255495
+){
255496
+ assert( nArg==1 );
255497
+ (void)nArg;
255498
+ sqlite3_result_value(pCtx, apArg[0]);
255499
+ sqlite3_result_subtype(pCtx, FTS5_INSTTOKEN_SUBTYPE);
255500
+}
254695255501
254696255502
/*
254697255503
** Return true if zName is the extension on one of the shadow tables used
254698255504
** by this module.
254699255505
*/
@@ -254789,10 +255595,20 @@
254789255595
pGlobal->api.xCreateFunction = fts5CreateAux;
254790255596
pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
254791255597
pGlobal->api.xFindTokenizer = fts5FindTokenizer;
254792255598
pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
254793255599
pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
255600
+
255601
+ /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector.
255602
+ ** The constants below were generated randomly. */
255603
+ sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr);
255604
+ pGlobal->aLocaleHdr[0] ^= 0xF924976D;
255605
+ pGlobal->aLocaleHdr[1] ^= 0x16596E13;
255606
+ pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA;
255607
+ pGlobal->aLocaleHdr[3] ^= 0x9B03A67F;
255608
+ assert( sizeof(pGlobal->aLocaleHdr)==16 );
255609
+
254794255610
rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
254795255611
if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
254796255612
if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
254797255613
if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
254798255614
if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
@@ -254810,13 +255626,20 @@
254810255626
);
254811255627
}
254812255628
if( rc==SQLITE_OK ){
254813255629
rc = sqlite3_create_function(
254814255630
db, "fts5_locale", 2,
254815
- SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
255631
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE|SQLITE_SUBTYPE,
254816255632
p, fts5LocaleFunc, 0, 0
254817255633
);
255634
+ }
255635
+ if( rc==SQLITE_OK ){
255636
+ rc = sqlite3_create_function(
255637
+ db, "fts5_insttoken", 1,
255638
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
255639
+ p, fts5InsttokenFunc, 0, 0
255640
+ );
254818255641
}
254819255642
}
254820255643
254821255644
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
254822255645
** fts5_test_mi.c is compiled and linked into the executable. And call
@@ -255015,24 +255838,39 @@
255015255838
);
255016255839
break;
255017255840
255018255841
case FTS5_STMT_INSERT_CONTENT:
255019255842
case FTS5_STMT_REPLACE_CONTENT: {
255020
- int nCol = pC->nCol + 1;
255021
- char *zBind;
255843
+ char *zBind = 0;
255022255844
int i;
255023255845
255024
- zBind = sqlite3_malloc64(1 + nCol*2);
255025
- if( zBind ){
255026
- for(i=0; i<nCol; i++){
255027
- zBind[i*2] = '?';
255028
- zBind[i*2 + 1] = ',';
255029
- }
255030
- zBind[i*2-1] = '\0';
255031
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
255032
- sqlite3_free(zBind);
255033
- }
255846
+ assert( pC->eContent==FTS5_CONTENT_NORMAL
255847
+ || pC->eContent==FTS5_CONTENT_UNINDEXED
255848
+ );
255849
+
255850
+ /* Add bindings for the "c*" columns - those that store the actual
255851
+ ** table content. If eContent==NORMAL, then there is one binding
255852
+ ** for each column. Or, if eContent==UNINDEXED, then there are only
255853
+ ** bindings for the UNINDEXED columns. */
255854
+ for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){
255855
+ if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){
255856
+ zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1);
255857
+ }
255858
+ }
255859
+
255860
+ /* Add bindings for any "l*" columns. Only non-UNINDEXED columns
255861
+ ** require these. */
255862
+ if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){
255863
+ for(i=0; rc==SQLITE_OK && i<pC->nCol; i++){
255864
+ if( pC->abUnindexed[i]==0 ){
255865
+ zBind = sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2);
255866
+ }
255867
+ }
255868
+ }
255869
+
255870
+ zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind);
255871
+ sqlite3_free(zBind);
255034255872
break;
255035255873
}
255036255874
255037255875
case FTS5_STMT_REPLACE_DOCSIZE:
255038255876
zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
@@ -255214,23 +256052,37 @@
255214256052
p->aTotalSize = (i64*)&p[1];
255215256053
p->pConfig = pConfig;
255216256054
p->pIndex = pIndex;
255217256055
255218256056
if( bCreate ){
255219
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
256057
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
256058
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
256059
+ ){
255220256060
int nDefn = 32 + pConfig->nCol*10;
255221
- char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
256061
+ char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
255222256062
if( zDefn==0 ){
255223256063
rc = SQLITE_NOMEM;
255224256064
}else{
255225256065
int i;
255226256066
int iOff;
255227256067
sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
255228256068
iOff = (int)strlen(zDefn);
255229256069
for(i=0; i<pConfig->nCol; i++){
255230
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
255231
- iOff += (int)strlen(&zDefn[iOff]);
256070
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
256071
+ || pConfig->abUnindexed[i]
256072
+ ){
256073
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
256074
+ iOff += (int)strlen(&zDefn[iOff]);
256075
+ }
256076
+ }
256077
+ if( pConfig->bLocale ){
256078
+ for(i=0; i<pConfig->nCol; i++){
256079
+ if( pConfig->abUnindexed[i]==0 ){
256080
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
256081
+ iOff += (int)strlen(&zDefn[iOff]);
256082
+ }
256083
+ }
255232256084
}
255233256085
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
255234256086
}
255235256087
sqlite3_free(zDefn);
255236256088
}
@@ -255379,33 +256231,43 @@
255379256231
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
255380256232
if( pConfig->abUnindexed[iCol-1]==0 ){
255381256233
sqlite3_value *pVal = 0;
255382256234
const char *pText = 0;
255383256235
int nText = 0;
255384
- int bReset = 0;
256236
+ const char *pLoc = 0;
256237
+ int nLoc = 0;
255385256238
255386256239
assert( pSeek==0 || apVal==0 );
255387256240
assert( pSeek!=0 || apVal!=0 );
255388256241
if( pSeek ){
255389256242
pVal = sqlite3_column_value(pSeek, iCol);
255390256243
}else{
255391256244
pVal = apVal[iCol-1];
255392256245
}
255393256246
255394
- rc = sqlite3Fts5ExtractText(
255395
- pConfig, pVal, pSeek!=0, &bReset, &pText, &nText
255396
- );
256247
+ if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
256248
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256249
+ }else{
256250
+ pText = (const char*)sqlite3_value_text(pVal);
256251
+ nText = sqlite3_value_bytes(pVal);
256252
+ if( pConfig->bLocale && pSeek ){
256253
+ pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol);
256254
+ nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
256255
+ }
256256
+ }
256257
+
255397256258
if( rc==SQLITE_OK ){
256259
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
255398256260
ctx.szCol = 0;
255399256261
rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
255400256262
pText, nText, (void*)&ctx, fts5StorageInsertCallback
255401256263
);
255402256264
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
255403256265
if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
255404256266
rc = FTS5_CORRUPT;
255405256267
}
255406
- if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256268
+ sqlite3Fts5ClearLocale(pConfig);
255407256269
}
255408256270
}
255409256271
}
255410256272
if( rc==SQLITE_OK && p->nTotalRow<1 ){
255411256273
rc = FTS5_CORRUPT;
@@ -255446,11 +256308,13 @@
255446256308
i64 iOrigin = 0;
255447256309
sqlite3_stmt *pLookup = 0;
255448256310
int rc = SQLITE_OK;
255449256311
255450256312
assert( p->pConfig->bContentlessDelete );
255451
- assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
256313
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE
256314
+ || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
256315
+ );
255452256316
255453256317
/* Look up the origin of the document in the %_docsize table. Store
255454256318
** this in stack variable iOrigin. */
255455256319
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
255456256320
if( rc==SQLITE_OK ){
@@ -255570,10 +256434,16 @@
255570256434
}
255571256435
255572256436
if( rc==SQLITE_OK ){
255573256437
if( p->pConfig->bContentlessDelete ){
255574256438
rc = fts5StorageContentlessDelete(p, iDel);
256439
+ if( rc==SQLITE_OK
256440
+ && bSaveRow
256441
+ && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
256442
+ ){
256443
+ rc = sqlite3Fts5StorageFindDeleteRow(p, iDel);
256444
+ }
255575256445
}else{
255576256446
rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
255577256447
}
255578256448
}
255579256449
@@ -255586,11 +256456,13 @@
255586256456
rc = sqlite3_reset(pDel);
255587256457
}
255588256458
}
255589256459
255590256460
/* Delete the %_content record */
255591
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
256461
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
256462
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
256463
+ ){
255592256464
if( rc==SQLITE_OK ){
255593256465
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
255594256466
}
255595256467
if( rc==SQLITE_OK ){
255596256468
sqlite3_bind_int64(pDel, 1, iDel);
@@ -255618,12 +256490,17 @@
255618256490
pConfig->zDb, pConfig->zName,
255619256491
pConfig->zDb, pConfig->zName
255620256492
);
255621256493
if( rc==SQLITE_OK && pConfig->bColumnsize ){
255622256494
rc = fts5ExecPrintf(pConfig->db, 0,
255623
- "DELETE FROM %Q.'%q_docsize';",
255624
- pConfig->zDb, pConfig->zName
256495
+ "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName
256496
+ );
256497
+ }
256498
+
256499
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
256500
+ rc = fts5ExecPrintf(pConfig->db, 0,
256501
+ "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName
255625256502
);
255626256503
}
255627256504
255628256505
/* Reinitialize the %_data table. This call creates the initial structure
255629256506
** and averages records. */
@@ -255660,24 +256537,39 @@
255660256537
sqlite3Fts5BufferZero(&buf);
255661256538
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
255662256539
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
255663256540
ctx.szCol = 0;
255664256541
if( pConfig->abUnindexed[ctx.iCol]==0 ){
255665
- int bReset = 0; /* True if tokenizer locale must be reset */
255666256542
int nText = 0; /* Size of pText in bytes */
255667256543
const char *pText = 0; /* Pointer to buffer containing text value */
256544
+ int nLoc = 0; /* Size of pLoc in bytes */
256545
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
256546
+
255668256547
sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
256548
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
256549
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
256550
+ ){
256551
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256552
+ }else{
256553
+ pText = (const char*)sqlite3_value_text(pVal);
256554
+ nText = sqlite3_value_bytes(pVal);
256555
+ if( pConfig->bLocale ){
256556
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
256557
+ pLoc = (const char*)sqlite3_column_text(pScan, iCol);
256558
+ nLoc = sqlite3_column_bytes(pScan, iCol);
256559
+ }
256560
+ }
255669256561
255670
- rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText);
255671256562
if( rc==SQLITE_OK ){
256563
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
255672256564
rc = sqlite3Fts5Tokenize(pConfig,
255673256565
FTS5_TOKENIZE_DOCUMENT,
255674256566
pText, nText,
255675256567
(void*)&ctx,
255676256568
fts5StorageInsertCallback
255677256569
);
255678
- if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256570
+ sqlite3Fts5ClearLocale(pConfig);
255679256571
}
255680256572
}
255681256573
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
255682256574
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
255683256575
}
@@ -255740,53 +256632,75 @@
255740256632
/*
255741256633
** Insert a new row into the FTS content table.
255742256634
*/
255743256635
static int sqlite3Fts5StorageContentInsert(
255744256636
Fts5Storage *p,
256637
+ int bReplace, /* True to use REPLACE instead of INSERT */
255745256638
sqlite3_value **apVal,
255746256639
i64 *piRowid
255747256640
){
255748256641
Fts5Config *pConfig = p->pConfig;
255749256642
int rc = SQLITE_OK;
255750256643
255751256644
/* Insert the new row into the %_content table. */
255752
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
256645
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
256646
+ && pConfig->eContent!=FTS5_CONTENT_UNINDEXED
256647
+ ){
255753256648
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
255754256649
*piRowid = sqlite3_value_int64(apVal[1]);
255755256650
}else{
255756256651
rc = fts5StorageNewRowid(p, piRowid);
255757256652
}
255758256653
}else{
255759256654
sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
255760256655
int i; /* Counter variable */
255761
- rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
255762
- for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
255763
- sqlite3_value *pVal = apVal[i];
255764
- if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
255765
- /* This is an UPDATE statement, and column (i-2) was not modified.
255766
- ** Retrieve the value from Fts5Storage.pSavedRow instead. */
255767
- pVal = sqlite3_column_value(p->pSavedRow, i-1);
255768
- }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){
255769
- assert( pConfig->bLocale );
255770
- assert( i>1 );
255771
- if( pConfig->abUnindexed[i-2] ){
255772
- /* At attempt to insert an fts5_locale() value into an UNINDEXED
255773
- ** column. Strip the locale away and just bind the text. */
256656
+
256657
+ assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT );
256658
+ assert( bReplace==0 || bReplace==1 );
256659
+ rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0);
256660
+ if( pInsert ) sqlite3_clear_bindings(pInsert);
256661
+
256662
+ /* Bind the rowid value */
256663
+ sqlite3_bind_value(pInsert, 1, apVal[1]);
256664
+
256665
+ /* Loop through values for user-defined columns. i=2 is the leftmost
256666
+ ** user-defined column. As is column 1 of pSavedRow. */
256667
+ for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
256668
+ int bUnindexed = pConfig->abUnindexed[i-2];
256669
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){
256670
+ sqlite3_value *pVal = apVal[i];
256671
+
256672
+ if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
256673
+ /* This is an UPDATE statement, and user-defined column (i-2) was not
256674
+ ** modified. Retrieve the value from Fts5Storage.pSavedRow. */
256675
+ pVal = sqlite3_column_value(p->pSavedRow, i-1);
256676
+ if( pConfig->bLocale && bUnindexed==0 ){
256677
+ sqlite3_bind_value(pInsert, pConfig->nCol + i,
256678
+ sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1)
256679
+ );
256680
+ }
256681
+ }else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
255774256682
const char *pText = 0;
256683
+ const char *pLoc = 0;
255775256684
int nText = 0;
255776
- rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText);
255777
- sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
255778
- }else{
255779
- const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
255780
- int nBlob = sqlite3_value_bytes(pVal);
255781
- assert( nBlob>4 );
255782
- sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT);
255783
- }
255784
- continue;
255785
- }
255786
-
255787
- rc = sqlite3_bind_value(pInsert, i, pVal);
256685
+ int nLoc = 0;
256686
+ assert( pConfig->bLocale );
256687
+
256688
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256689
+ if( rc==SQLITE_OK ){
256690
+ sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
256691
+ if( bUnindexed==0 ){
256692
+ int iLoc = pConfig->nCol + i;
256693
+ sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT);
256694
+ }
256695
+ }
256696
+
256697
+ continue;
256698
+ }
256699
+
256700
+ rc = sqlite3_bind_value(pInsert, i, pVal);
256701
+ }
255788256702
}
255789256703
if( rc==SQLITE_OK ){
255790256704
sqlite3_step(pInsert);
255791256705
rc = sqlite3_reset(pInsert);
255792256706
}
@@ -255817,27 +256731,41 @@
255817256731
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
255818256732
}
255819256733
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
255820256734
ctx.szCol = 0;
255821256735
if( pConfig->abUnindexed[ctx.iCol]==0 ){
255822
- int bReset = 0; /* True if tokenizer locale must be reset */
255823256736
int nText = 0; /* Size of pText in bytes */
255824256737
const char *pText = 0; /* Pointer to buffer containing text value */
256738
+ int nLoc = 0; /* Size of pText in bytes */
256739
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
256740
+
255825256741
sqlite3_value *pVal = apVal[ctx.iCol+2];
255826
- int bDisk = 0;
255827256742
if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
255828256743
pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
255829
- bDisk = 1;
256744
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
256745
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
256746
+ pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol);
256747
+ nLoc = sqlite3_column_bytes(p->pSavedRow, iCol);
256748
+ }
256749
+ }else{
256750
+ pVal = apVal[ctx.iCol+2];
256751
+ }
256752
+
256753
+ if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
256754
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256755
+ }else{
256756
+ pText = (const char*)sqlite3_value_text(pVal);
256757
+ nText = sqlite3_value_bytes(pVal);
255830256758
}
255831
- rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText);
256759
+
255832256760
if( rc==SQLITE_OK ){
255833
- assert( bReset==0 || pConfig->bLocale );
256761
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
255834256762
rc = sqlite3Fts5Tokenize(pConfig,
255835256763
FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
255836256764
fts5StorageInsertCallback
255837256765
);
255838
- if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256766
+ sqlite3Fts5ClearLocale(pConfig);
255839256767
}
255840256768
}
255841256769
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
255842256770
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
255843256771
}
@@ -255998,41 +256926,65 @@
255998256926
}
255999256927
if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
256000256928
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256001256929
}
256002256930
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
256003
- if( pConfig->abUnindexed[i] ) continue;
256004
- ctx.iCol = i;
256005
- ctx.szCol = 0;
256006
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256007
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256008
- }
256009
- if( rc==SQLITE_OK ){
256010
- int bReset = 0; /* True if tokenizer locale must be reset */
256011
- int nText = 0; /* Size of pText in bytes */
256012
- const char *pText = 0; /* Pointer to buffer containing text value */
256013
-
256014
- rc = sqlite3Fts5ExtractText(pConfig,
256015
- sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText
256016
- );
256017
- if( rc==SQLITE_OK ){
256931
+ if( pConfig->abUnindexed[i]==0 ){
256932
+ const char *pText = 0;
256933
+ int nText = 0;
256934
+ const char *pLoc = 0;
256935
+ int nLoc = 0;
256936
+ sqlite3_value *pVal = sqlite3_column_value(pScan, i+1);
256937
+
256938
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
256939
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
256940
+ ){
256941
+ rc = sqlite3Fts5DecodeLocaleValue(
256942
+ pVal, &pText, &nText, &pLoc, &nLoc
256943
+ );
256944
+ }else{
256945
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
256946
+ int iCol = i + 1 + pConfig->nCol;
256947
+ pLoc = (const char*)sqlite3_column_text(pScan, iCol);
256948
+ nLoc = sqlite3_column_bytes(pScan, iCol);
256949
+ }
256950
+ pText = (const char*)sqlite3_value_text(pVal);
256951
+ nText = sqlite3_value_bytes(pVal);
256952
+ }
256953
+
256954
+ ctx.iCol = i;
256955
+ ctx.szCol = 0;
256956
+
256957
+ if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256958
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256959
+ }
256960
+
256961
+ if( rc==SQLITE_OK ){
256962
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
256018256963
rc = sqlite3Fts5Tokenize(pConfig,
256019256964
FTS5_TOKENIZE_DOCUMENT,
256020256965
pText, nText,
256021256966
(void*)&ctx,
256022256967
fts5StorageIntegrityCallback
256023256968
);
256024
- if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256025
- }
256026
- }
256027
- if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
256028
- rc = FTS5_CORRUPT;
256029
- }
256030
- aTotalSize[i] += ctx.szCol;
256031
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256032
- sqlite3Fts5TermsetFree(ctx.pTermset);
256033
- ctx.pTermset = 0;
256969
+ sqlite3Fts5ClearLocale(pConfig);
256970
+ }
256971
+
256972
+ /* If this is not a columnsize=0 database, check that the number
256973
+ ** of tokens in the value matches the aColSize[] value read from
256974
+ ** the %_docsize table. */
256975
+ if( rc==SQLITE_OK
256976
+ && pConfig->bColumnsize
256977
+ && ctx.szCol!=aColSize[i]
256978
+ ){
256979
+ rc = FTS5_CORRUPT;
256980
+ }
256981
+ aTotalSize[i] += ctx.szCol;
256982
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256983
+ sqlite3Fts5TermsetFree(ctx.pTermset);
256984
+ ctx.pTermset = 0;
256985
+ }
256034256986
}
256035256987
}
256036256988
sqlite3Fts5TermsetFree(ctx.pTermset);
256037256989
ctx.pTermset = 0;
256038256990
@@ -256454,11 +257406,11 @@
256454257406
256455257407
#define READ_UTF8(zIn, zTerm, c) \
256456257408
c = *(zIn++); \
256457257409
if( c>=0xc0 ){ \
256458257410
c = sqlite3Utf8Trans1[c-0xc0]; \
256459
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
257411
+ while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
256460257412
c = (c<<6) + (0x3f & *(zIn++)); \
256461257413
} \
256462257414
if( c<0x80 \
256463257415
|| (c&0xFFFFF800)==0xD800 \
256464257416
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
@@ -257609,22 +258561,22 @@
257609258561
int rc = SQLITE_OK;
257610258562
char aBuf[32];
257611258563
char *zOut = aBuf;
257612258564
int ii;
257613258565
const unsigned char *zIn = (const unsigned char*)pText;
257614
- const unsigned char *zEof = &zIn[nText];
257615
- u32 iCode;
258566
+ const unsigned char *zEof = (zIn ? &zIn[nText] : 0);
258567
+ u32 iCode = 0;
257616258568
int aStart[3]; /* Input offset of each character in aBuf[] */
257617258569
257618258570
UNUSED_PARAM(unusedFlags);
257619258571
257620258572
/* Populate aBuf[] with the characters for the first trigram. */
257621258573
for(ii=0; ii<3; ii++){
257622258574
do {
257623258575
aStart[ii] = zIn - (const unsigned char*)pText;
258576
+ if( zIn>=zEof ) return SQLITE_OK;
257624258577
READ_UTF8(zIn, zEof, iCode);
257625
- if( iCode==0 ) return SQLITE_OK;
257626258578
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
257627258579
}while( iCode==0 );
257628258580
WRITE_UTF8(zOut, iCode);
257629258581
}
257630258582
@@ -257641,12 +258593,15 @@
257641258593
const char *z1;
257642258594
257643258595
/* Read characters from the input up until the first non-diacritic */
257644258596
do {
257645258597
iNext = zIn - (const unsigned char*)pText;
258598
+ if( zIn>=zEof ){
258599
+ iCode = 0;
258600
+ break;
258601
+ }
257646258602
READ_UTF8(zIn, zEof, iCode);
257647
- if( iCode==0 ) break;
257648258603
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
257649258604
}while( iCode==0 );
257650258605
257651258606
/* Pass the current trigram back to fts5 */
257652258607
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
@@ -259679,11 +260634,11 @@
259679260634
259680260635
return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
259681260636
}
259682260637
259683260638
259684
-
260639
+/* Here ends the fts5.c composite file. */
259685260640
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
259686260641
259687260642
/************** End of fts5.c ************************************************/
259688260643
/************** Begin file stmt.c ********************************************/
259689260644
/*
@@ -260035,6 +260990,7 @@
260035260990
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
260036260991
260037260992
/************** End of stmt.c ************************************************/
260038260993
/* Return the source-id for this library */
260039260994
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
260995
+#endif /* SQLITE_AMALGAMATION */
260040260996
/************************** End of sqlite3.c ******************************/
260041260997
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.47.0. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -16,12 +16,15 @@
16 ** if you want a wrapper to interface SQLite with your choice of programming
17 ** language. The code for the "sqlite3" command-line shell is also in a
18 ** separate file. This file contains only code for the core SQLite library.
19 **
20 ** The content in this amalgamation comes from Fossil check-in
21 ** 7891a266c4425722ae8b9231397ef9e42e24.
 
 
22 */
 
23 #define SQLITE_CORE 1
24 #define SQLITE_AMALGAMATION 1
25 #ifndef SQLITE_PRIVATE
26 # define SQLITE_PRIVATE static
27 #endif
@@ -460,13 +463,13 @@
460 **
461 ** See also: [sqlite3_libversion()],
462 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
463 ** [sqlite_version()] and [sqlite_source_id()].
464 */
465 #define SQLITE_VERSION "3.47.0"
466 #define SQLITE_VERSION_NUMBER 3047000
467 #define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
468
469 /*
470 ** CAPI3REF: Run-Time Library Version Numbers
471 ** KEYWORDS: sqlite3_version sqlite3_sourceid
472 **
@@ -966,10 +969,17 @@
966 **
967 ** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
968 ** filesystem supports doing multiple write operations atomically when those
969 ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
970 ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
 
 
 
 
 
 
 
971 */
972 #define SQLITE_IOCAP_ATOMIC 0x00000001
973 #define SQLITE_IOCAP_ATOMIC512 0x00000002
974 #define SQLITE_IOCAP_ATOMIC1K 0x00000004
975 #define SQLITE_IOCAP_ATOMIC2K 0x00000008
@@ -982,10 +992,11 @@
982 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400
983 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
984 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
985 #define SQLITE_IOCAP_IMMUTABLE 0x00002000
986 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
 
987
988 /*
989 ** CAPI3REF: File Locking Levels
990 **
991 ** SQLite uses one of these integer values as the second
@@ -1128,10 +1139,11 @@
1128 ** <li> [SQLITE_IOCAP_SEQUENTIAL]
1129 ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
1130 ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
1131 ** <li> [SQLITE_IOCAP_IMMUTABLE]
1132 ** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
 
1133 ** </ul>
1134 **
1135 ** The SQLITE_IOCAP_ATOMIC property means that all writes of
1136 ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
1137 ** mean that writes of blocks that are nnn bytes in size and
@@ -1405,10 +1417,15 @@
1405 ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
1406 ** opcode causes the xFileControl method to swap the file handle with the one
1407 ** pointed to by the pArg argument. This capability is used during testing
1408 ** and only needs to be supported when SQLITE_TEST is defined.
1409 **
 
 
 
 
 
1410 ** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
1411 ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
1412 ** be advantageous to block on the next WAL lock if the lock is not immediately
1413 ** available. The WAL subsystem issues this signal during rare
1414 ** circumstances in order to fix a problem with priority inversion.
@@ -1558,10 +1575,11 @@
1558 #define SQLITE_FCNTL_RESERVE_BYTES 38
1559 #define SQLITE_FCNTL_CKPT_START 39
1560 #define SQLITE_FCNTL_EXTERNAL_READER 40
1561 #define SQLITE_FCNTL_CKSM_FILE 41
1562 #define SQLITE_FCNTL_RESET_CACHE 42
 
1563
1564 /* deprecated names */
1565 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1566 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1567 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2936,14 +2954,18 @@
2936 **
2937 ** ^These functions return the number of rows modified, inserted or
2938 ** deleted by the most recently completed INSERT, UPDATE or DELETE
2939 ** statement on the database connection specified by the only parameter.
2940 ** The two functions are identical except for the type of the return value
2941 ** and that if the number of rows modified by the most recent INSERT, UPDATE
2942 ** or DELETE is greater than the maximum value supported by type "int", then
2943 ** the return value of sqlite3_changes() is undefined. ^Executing any other
2944 ** type of SQL statement does not modify the value returned by these functions.
 
 
 
 
2945 **
2946 ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
2947 ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
2948 ** [foreign key actions] or [REPLACE] constraint resolution are not counted.
2949 **
@@ -4499,15 +4521,26 @@
4499 **
4500 ** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
4501 ** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
4502 ** to return an error (error code SQLITE_ERROR) if the statement uses
4503 ** any virtual tables.
 
 
 
 
 
 
 
 
 
 
4504 ** </dl>
4505 */
4506 #define SQLITE_PREPARE_PERSISTENT 0x01
4507 #define SQLITE_PREPARE_NORMALIZE 0x02
4508 #define SQLITE_PREPARE_NO_VTAB 0x04
 
4509
4510 /*
4511 ** CAPI3REF: Compiling An SQL Statement
4512 ** KEYWORDS: {SQL statement compiler}
4513 ** METHOD: sqlite3
@@ -4536,17 +4569,21 @@
4536 ** and sqlite3_prepare_v3()
4537 ** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
4538 ** and sqlite3_prepare16_v3() use UTF-16.
4539 **
4540 ** ^If the nByte argument is negative, then zSql is read up to the
4541 ** first zero terminator. ^If nByte is positive, then it is the
4542 ** number of bytes read from zSql. ^If nByte is zero, then no prepared
 
 
4543 ** statement is generated.
4544 ** If the caller knows that the supplied string is nul-terminated, then
4545 ** there is a small performance advantage to passing an nByte parameter that
4546 ** is the number of bytes in the input string <i>including</i>
4547 ** the nul-terminator.
 
 
4548 **
4549 ** ^If pzTail is not NULL then *pzTail is made to point to the first byte
4550 ** past the end of the first SQL statement in zSql. These routines only
4551 ** compile the first statement in zSql, so *pzTail is left pointing to
4552 ** what remains uncompiled.
@@ -5913,11 +5950,11 @@
5913 ** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
5914 ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
5915 ** This flag instructs SQLite to omit some corner-case optimizations that
5916 ** might disrupt the operation of the [sqlite3_value_subtype()] function,
5917 ** causing it to return zero rather than the correct subtype().
5918 ** SQL functions that invokes [sqlite3_value_subtype()] should have this
5919 ** property. If the SQLITE_SUBTYPE property is omitted, then the return
5920 ** value from [sqlite3_value_subtype()] might sometimes be zero even though
5921 ** a non-zero subtype was specified by the function argument expression.
5922 **
5923 ** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
@@ -8678,11 +8715,11 @@
8678 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8679 #define SQLITE_TESTCTRL_SEEK_COUNT 30
8680 #define SQLITE_TESTCTRL_TRACEFLAGS 31
8681 #define SQLITE_TESTCTRL_TUNE 32
8682 #define SQLITE_TESTCTRL_LOGEST 33
8683 #define SQLITE_TESTCTRL_USELONGDOUBLE 34
8684 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
8685
8686 /*
8687 ** CAPI3REF: SQL Keyword Checking
8688 **
@@ -9654,10 +9691,20 @@
9654 ** threads may safely make multiple concurrent calls to sqlite3_backup_step().
9655 ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
9656 ** APIs are not strictly speaking threadsafe. If they are invoked at the
9657 ** same time as another thread is invoking sqlite3_backup_step() it is
9658 ** possible that they return invalid values.
 
 
 
 
 
 
 
 
 
 
9659 */
9660 SQLITE_API sqlite3_backup *sqlite3_backup_init(
9661 sqlite3 *pDest, /* Destination database handle */
9662 const char *zDestName, /* Destination database name */
9663 sqlite3 *pSource, /* Source database handle */
@@ -10852,10 +10899,18 @@
10852 ** schema S in database connection D. ^On success, the
10853 ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
10854 ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
10855 ** If there is not already a read-transaction open on schema S when
10856 ** this function is called, one is opened automatically.
 
 
 
 
 
 
 
 
10857 **
10858 ** The following must be true for this function to succeed. If any of
10859 ** the following statements are false when sqlite3_snapshot_get() is
10860 ** called, SQLITE_ERROR is returned. The final value of *P is undefined
10861 ** in this case.
@@ -11172,11 +11227,11 @@
11172 #endif
11173
11174 #if 0
11175 } /* End of the 'extern "C"' block */
11176 #endif
11177 #endif /* SQLITE3_H */
11178
11179 /******** Begin file sqlite3rtree.h *********/
11180 /*
11181 ** 2010 August 30
11182 **
@@ -13423,17 +13478,32 @@
13423 ** This is used to access token iToken of phrase hit iIdx within the
13424 ** current row. If iIdx is less than zero or greater than or equal to the
13425 ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
13426 ** output variable (*ppToken) is set to point to a buffer containing the
13427 ** matching document token, and (*pnToken) to the size of that buffer in
13428 ** bytes. This API is not available if the specified token matches a
13429 ** prefix query term. In that case both output variables are always set
13430 ** to 0.
13431 **
13432 ** The output text is not a copy of the document text that was tokenized.
13433 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13434 ** includes any embedded 0x00 and trailing data.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13435 **
13436 ** This API can be quite slow if used with an FTS5 table created with the
13437 ** "detail=none" or "detail=column" option.
13438 **
13439 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -13521,11 +13591,10 @@
13521 ** CUSTOM TOKENIZERS
13522 **
13523 ** Applications may also register custom tokenizer types. A tokenizer
13524 ** is registered by providing fts5 with a populated instance of the
13525 ** following structure. All structure methods must be defined, setting
13526 **
13527 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13528 ** behaviour. The structure methods are expected to function as follows:
13529 **
13530 ** xCreate:
13531 ** This function is used to allocate and initialize a tokenizer instance.
@@ -13865,10 +13934,11 @@
13865 #endif
13866
13867 #endif /* _FTS5_H */
13868
13869 /******** End of fts5.h *********/
 
13870
13871 /************** End of sqlite3.h *********************************************/
13872 /************** Continuing where we left off in sqliteInt.h ******************/
13873
13874 /*
@@ -13910,10 +13980,11 @@
13910 ** to count the size: 2^31-1 or 2147483647.
13911 */
13912 #ifndef SQLITE_MAX_LENGTH
13913 # define SQLITE_MAX_LENGTH 1000000000
13914 #endif
 
13915
13916 /*
13917 ** This is the maximum number of
13918 **
13919 ** * Columns in a table
@@ -14809,10 +14880,11 @@
14809 #include <stdio.h>
14810 #include <stdlib.h>
14811 #include <string.h>
14812 #include <assert.h>
14813 #include <stddef.h>
 
14814
14815 /*
14816 ** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
14817 ** This allows better measurements of where memcpy() is used when running
14818 ** cachegrind. But this macro version of memcpy() is very slow so it
@@ -14831,11 +14903,10 @@
14831 #ifdef SQLITE_OMIT_FLOATING_POINT
14832 # define double sqlite_int64
14833 # define float sqlite_int64
14834 # define fabs(X) ((X)<0?-(X):(X))
14835 # define sqlite3IsOverflow(X) 0
14836 # define LONGDOUBLE_TYPE sqlite_int64
14837 # ifndef SQLITE_BIG_DBL
14838 # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
14839 # endif
14840 # define SQLITE_OMIT_DATETIME_FUNCS 1
14841 # define SQLITE_OMIT_TRACE 1
@@ -15006,13 +15077,10 @@
15006 # define INT8_TYPE int8_t
15007 # else
15008 # define INT8_TYPE signed char
15009 # endif
15010 #endif
15011 #ifndef LONGDOUBLE_TYPE
15012 # define LONGDOUBLE_TYPE long double
15013 #endif
15014 typedef sqlite_int64 i64; /* 8-byte signed integer */
15015 typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
15016 typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
15017 typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
15018 typedef INT16_TYPE i16; /* 2-byte signed integer */
@@ -16391,10 +16459,13 @@
16391 struct KeyInfo*, /* First argument to compare function */
16392 BtCursor *pCursor /* Space to write cursor structure */
16393 );
16394 SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
16395 SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
 
 
 
16396 SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
16397 SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
16398 #ifdef SQLITE_ENABLE_CURSOR_HINTS
16399 SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
16400 #endif
@@ -17004,11 +17075,11 @@
17004
17005 /*
17006 ** Additional non-public SQLITE_PREPARE_* flags
17007 */
17008 #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */
17009 #define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */
17010
17011 /*
17012 ** Prototypes for the VDBE interface. See comments on the implementation
17013 ** for a description of what each of these routines does.
17014 */
@@ -17719,51 +17790,15 @@
17719 struct FuncDefHash {
17720 FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
17721 };
17722 #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
17723
17724 #if defined(SQLITE_USER_AUTHENTICATION)
17725 # warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \
17726 See ext/userauth/user-auth.txt for details."
17727 #endif
17728 #ifdef SQLITE_USER_AUTHENTICATION
17729 /*
17730 ** Information held in the "sqlite3" database connection object and used
17731 ** to manage user authentication.
17732 */
17733 typedef struct sqlite3_userauth sqlite3_userauth;
17734 struct sqlite3_userauth {
17735 u8 authLevel; /* Current authentication level */
17736 int nAuthPW; /* Size of the zAuthPW in bytes */
17737 char *zAuthPW; /* Password used to authenticate */
17738 char *zAuthUser; /* User name used to authenticate */
17739 };
17740
17741 /* Allowed values for sqlite3_userauth.authLevel */
17742 #define UAUTH_Unknown 0 /* Authentication not yet checked */
17743 #define UAUTH_Fail 1 /* User authentication failed */
17744 #define UAUTH_User 2 /* Authenticated as a normal user */
17745 #define UAUTH_Admin 3 /* Authenticated as an administrator */
17746
17747 /* Functions used only by user authorization logic */
17748 SQLITE_PRIVATE int sqlite3UserAuthTable(const char*);
17749 SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);
17750 SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*);
17751 SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
17752
17753 #endif /* SQLITE_USER_AUTHENTICATION */
17754
17755 /*
17756 ** typedef for the authorization callback function.
17757 */
17758 #ifdef SQLITE_USER_AUTHENTICATION
17759 typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
17760 const char*, const char*);
17761 #else
17762 typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
17763 const char*);
17764 #endif
17765
17766 #ifndef SQLITE_OMIT_DEPRECATED
17767 /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
17768 ** in the style of sqlite3_trace()
17769 */
@@ -17920,13 +17955,10 @@
17920 sqlite3 *pUnlockConnection; /* Connection to watch for unlock */
17921 void *pUnlockArg; /* Argument to xUnlockNotify */
17922 void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
17923 sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
17924 #endif
17925 #ifdef SQLITE_USER_AUTHENTICATION
17926 sqlite3_userauth auth; /* User authentication information */
17927 #endif
17928 };
17929
17930 /*
17931 ** A macro to discover the encoding of a database.
17932 */
@@ -19221,11 +19253,11 @@
19221 #define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
19222 #define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
19223 #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
19224 #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
19225 #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
19226 /* 0x80000000 // Available */
19227
19228 /* The EP_Propagate mask is a set of properties that automatically propagate
19229 ** upwards into parent nodes.
19230 */
19231 #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
@@ -19777,11 +19809,11 @@
19777 **
19778 ** SRT_Set The result must be a single column. Store each
19779 ** row of result as the key in table pDest->iSDParm.
19780 ** Apply the affinity pDest->affSdst before storing
19781 ** results. if pDest->iSDParm2 is positive, then it is
19782 ** a regsiter holding a Bloom filter for the IN operator
19783 ** that should be populated in addition to the
19784 ** pDest->iSDParm table. This SRT is used to
19785 ** implement "IN (SELECT ...)".
19786 **
19787 ** SRT_EphemTab Create an temporary table pDest->iSDParm and store
@@ -20376,11 +20408,10 @@
20376 u8 bFullMutex; /* True to enable full mutexing */
20377 u8 bOpenUri; /* True to interpret filenames as URIs */
20378 u8 bUseCis; /* Use covering indices for full-scans */
20379 u8 bSmallMalloc; /* Avoid large memory allocations if true */
20380 u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
20381 u8 bUseLongDouble; /* Make use of long double */
20382 #ifdef SQLITE_DEBUG
20383 u8 bJsonSelfcheck; /* Double-check JSON parsing */
20384 #endif
20385 int mxStrlen; /* Maximum string length */
20386 int neverCorrupt; /* Database is always well-formed */
@@ -20751,19 +20782,10 @@
20751 */
20752 #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
20753 # define SQLITE_ENABLE_FTS3 1
20754 #endif
20755
20756 /*
20757 ** The ctype.h header is needed for non-ASCII systems. It is also
20758 ** needed by FTS3 when FTS3 is included in the amalgamation.
20759 */
20760 #if !defined(SQLITE_ASCII) || \
20761 (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION))
20762 # include <ctype.h>
20763 #endif
20764
20765 /*
20766 ** The following macros mimic the standard library functions toupper(),
20767 ** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The
20768 ** sqlite versions only work for ASCII characters, regardless of locale.
20769 */
@@ -21381,11 +21403,11 @@
21381 SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
21382 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
21383 SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
21384 SQLITE_PRIVATE int sqlite3Atoi(const char*);
21385 #ifndef SQLITE_OMIT_UTF16
21386 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
21387 #endif
21388 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
21389 SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
21390 SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*);
21391 SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
@@ -22839,13 +22861,10 @@
22839 "UNLINK_AFTER_CLOSE",
22840 #endif
22841 #ifdef SQLITE_UNTESTABLE
22842 "UNTESTABLE",
22843 #endif
22844 #ifdef SQLITE_USER_AUTHENTICATION
22845 "USER_AUTHENTICATION",
22846 #endif
22847 #ifdef SQLITE_USE_ALLOCA
22848 "USE_ALLOCA",
22849 #endif
22850 #ifdef SQLITE_USE_FCNTL_TRACE
22851 "USE_FCNTL_TRACE",
@@ -23117,11 +23136,10 @@
23117 SQLITE_THREADSAFE==1, /* bFullMutex */
23118 SQLITE_USE_URI, /* bOpenUri */
23119 SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
23120 0, /* bSmallMalloc */
23121 1, /* bExtraSchemaChecks */
23122 sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
23123 #ifdef SQLITE_DEBUG
23124 0, /* bJsonSelfcheck */
23125 #endif
23126 0x7ffffffe, /* mxStrlen */
23127 0, /* neverCorrupt */
@@ -23837,13 +23855,15 @@
23837 UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
23838 int iNewReg; /* Register for new.* values */
23839 int iBlobWrite; /* Value returned by preupdate_blobwrite() */
23840 i64 iKey1; /* First key value passed to hook */
23841 i64 iKey2; /* Second key value passed to hook */
 
23842 Mem *aNew; /* Array of new.* values */
23843 Table *pTab; /* Schema object being updated */
23844 Index *pPk; /* PK index if pTab is WITHOUT ROWID */
 
23845 };
23846
23847 /*
23848 ** An instance of this object is used to pass an vector of values into
23849 ** OP_VFilter, the xFilter method of a virtual table. The vector is the
@@ -29285,20 +29305,33 @@
29285
29286 #ifndef NDEBUG
29287 /*
29288 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
29289 ** intended for use inside assert() statements.
 
 
 
29290 */
29291 SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
 
 
 
 
 
29292 assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
29293 return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
29294 }
29295 SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
 
 
 
 
 
29296 assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
29297 return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
29298 }
29299 #endif
29300
29301 #endif /* !defined(SQLITE_MUTEX_OMIT) */
29302
29303 /************** End of mutex.c ***********************************************/
29304 /************** Begin file mutex_noop.c **************************************/
@@ -32272,10 +32305,11 @@
32272 && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
32273 ){
32274 pExpr = pExpr->pLeft;
32275 }
32276 if( pExpr==0 ) return;
 
32277 db->errByteOffset = pExpr->w.iOfst;
32278 }
32279
32280 /*
32281 ** Enlarge the memory allocation on a StrAccum object so that it is
@@ -33001,11 +33035,11 @@
33001 }
33002 if( pItem->fg.isCte ){
33003 sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
33004 }
33005 if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
33006 sqlite3_str_appendf(&x, " ON");
33007 }
33008 if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
33009 if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
33010 if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
33011 if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
@@ -34085,10 +34119,14 @@
34085 **
34086 ** This routines are given external linkage so that they will always be
34087 ** accessible to the debugging, and to avoid warnings about unused
34088 ** functions. But these routines only exist in debugging builds, so they
34089 ** do not contaminate the interface.
 
 
 
 
34090 */
34091 SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
34092 SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
34093 SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
34094 SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
@@ -34687,11 +34725,11 @@
34687 */
34688 #define READ_UTF8(zIn, zTerm, c) \
34689 c = *(zIn++); \
34690 if( c>=0xc0 ){ \
34691 c = sqlite3Utf8Trans1[c-0xc0]; \
34692 while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
34693 c = (c<<6) + (0x3f & *(zIn++)); \
34694 } \
34695 if( c<0x80 \
34696 || (c&0xFFFFF800)==0xD800 \
34697 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
@@ -35065,24 +35103,26 @@
35065 assert( m.z || db->mallocFailed );
35066 return m.z;
35067 }
35068
35069 /*
35070 ** zIn is a UTF-16 encoded unicode string at least nChar characters long.
35071 ** Return the number of bytes in the first nChar unicode characters
35072 ** in pZ. nChar must be non-negative.
 
35073 */
35074 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
35075 int c;
35076 unsigned char const *z = zIn;
 
35077 int n = 0;
35078
35079 if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
35080 while( n<nChar ){
35081 c = z[0];
35082 z += 2;
35083 if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
35084 n++;
35085 }
35086 return (int)(z-(unsigned char const *)zIn)
35087 - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE);
35088 }
@@ -35659,10 +35699,12 @@
35659 int esign = 1; /* sign of exponent */
35660 int e = 0; /* exponent */
35661 int eValid = 1; /* True exponent is either not used or is well-formed */
35662 int nDigit = 0; /* Number of digits processed */
35663 int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
 
 
35664
35665 assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
35666 *pResult = 0.0; /* Default return value, in case of an error */
35667 if( length==0 ) return 0;
35668
@@ -35761,81 +35803,65 @@
35761
35762 /* adjust exponent by d, and update sign */
35763 e = (e*esign) + d;
35764
35765 /* Try to adjust the exponent to make it smaller */
35766 while( e>0 && s<(LARGEST_UINT64/10) ){
35767 s *= 10;
35768 e--;
35769 }
35770 while( e<0 && (s%10)==0 ){
35771 s /= 10;
35772 e++;
35773 }
35774
35775 if( e==0 ){
35776 *pResult = s;
35777 }else if( sqlite3Config.bUseLongDouble ){
35778 LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s;
35779 if( e>0 ){
35780 while( e>=100 ){ e-=100; r *= 1.0e+100L; }
35781 while( e>=10 ){ e-=10; r *= 1.0e+10L; }
35782 while( e>=1 ){ e-=1; r *= 1.0e+01L; }
35783 }else{
35784 while( e<=-100 ){ e+=100; r *= 1.0e-100L; }
35785 while( e<=-10 ){ e+=10; r *= 1.0e-10L; }
35786 while( e<=-1 ){ e+=1; r *= 1.0e-01L; }
35787 }
35788 assert( r>=0.0 );
35789 if( r>+1.7976931348623157081452742373e+308L ){
35790 #ifdef INFINITY
35791 *pResult = +INFINITY;
35792 #else
35793 *pResult = 1.0e308*10.0;
35794 #endif
35795 }else{
35796 *pResult = (double)r;
35797 }
35798 }else{
35799 double rr[2];
35800 u64 s2;
35801 rr[0] = (double)s;
35802 s2 = (u64)rr[0];
35803 #if defined(_MSC_VER) && _MSC_VER<1700
35804 if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
35805 #endif
35806 rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
35807 if( e>0 ){
35808 while( e>=100 ){
35809 e -= 100;
35810 dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
35811 }
35812 while( e>=10 ){
35813 e -= 10;
35814 dekkerMul2(rr, 1.0e+10, 0.0);
35815 }
35816 while( e>=1 ){
35817 e -= 1;
35818 dekkerMul2(rr, 1.0e+01, 0.0);
35819 }
35820 }else{
35821 while( e<=-100 ){
35822 e += 100;
35823 dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
35824 }
35825 while( e<=-10 ){
35826 e += 10;
35827 dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
35828 }
35829 while( e<=-1 ){
35830 e += 1;
35831 dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
35832 }
35833 }
35834 *pResult = rr[0]+rr[1];
35835 if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
35836 }
 
 
 
 
35837 if( sign<0 ) *pResult = -*pResult;
35838 assert( !sqlite3IsNaN(*pResult) );
35839
35840 atof_return:
35841 /* return true if number and no extra non-whitespace characters after */
@@ -36152,13 +36178,14 @@
36152 */
36153 SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
36154 int i;
36155 u64 v;
36156 int e, exp = 0;
 
 
36157 p->isSpecial = 0;
36158 p->z = p->zBuf;
36159
36160 assert( mxRound>0 );
36161
36162 /* Convert negative numbers to positive. Deal with Infinity, 0.0, and
36163 ** NaN. */
36164 if( r<0.0 ){
@@ -36182,66 +36209,49 @@
36182 return;
36183 }
36184
36185 /* Multiply r by powers of ten until it lands somewhere in between
36186 ** 1.0e+19 and 1.0e+17.
36187 */
36188 if( sqlite3Config.bUseLongDouble ){
36189 LONGDOUBLE_TYPE rr = r;
36190 if( rr>=1.0e+19 ){
36191 while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
36192 while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
36193 while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
36194 }else{
36195 while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
36196 while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
36197 while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
36198 }
36199 v = (u64)rr;
36200 }else{
36201 /* If high-precision floating point is not available using "long double",
36202 ** then use Dekker-style double-double computation to increase the
36203 ** precision.
36204 **
36205 ** The error terms on constants like 1.0e+100 computed using the
36206 ** decimal extension, for example as follows:
36207 **
36208 ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
36209 */
36210 double rr[2];
36211 rr[0] = r;
36212 rr[1] = 0.0;
36213 if( rr[0]>9.223372036854774784e+18 ){
36214 while( rr[0]>9.223372036854774784e+118 ){
36215 exp += 100;
36216 dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
36217 }
36218 while( rr[0]>9.223372036854774784e+28 ){
36219 exp += 10;
36220 dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
36221 }
36222 while( rr[0]>9.223372036854774784e+18 ){
36223 exp += 1;
36224 dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
36225 }
36226 }else{
36227 while( rr[0]<9.223372036854774784e-83 ){
36228 exp -= 100;
36229 dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
36230 }
36231 while( rr[0]<9.223372036854774784e+07 ){
36232 exp -= 10;
36233 dekkerMul2(rr, 1.0e+10, 0.0);
36234 }
36235 while( rr[0]<9.22337203685477478e+17 ){
36236 exp -= 1;
36237 dekkerMul2(rr, 1.0e+01, 0.0);
36238 }
36239 }
36240 v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
36241 }
36242
36243
36244 /* Extract significant digits. */
36245 i = sizeof(p->zBuf)-1;
36246 assert( v>0 );
36247 while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
@@ -37008,108 +37018,10 @@
37008 i += pIn[i+1];
37009 }while( i<mx );
37010 return 0;
37011 }
37012
37013 /*
37014 ** High-resolution hardware timer used for debugging and testing only.
37015 */
37016 #if defined(VDBE_PROFILE) \
37017 || defined(SQLITE_PERFORMANCE_TRACE) \
37018 || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
37019 /************** Include hwtime.h in the middle of util.c *********************/
37020 /************** Begin file hwtime.h ******************************************/
37021 /*
37022 ** 2008 May 27
37023 **
37024 ** The author disclaims copyright to this source code. In place of
37025 ** a legal notice, here is a blessing:
37026 **
37027 ** May you do good and not evil.
37028 ** May you find forgiveness for yourself and forgive others.
37029 ** May you share freely, never taking more than you give.
37030 **
37031 ******************************************************************************
37032 **
37033 ** This file contains inline asm code for retrieving "high-performance"
37034 ** counters for x86 and x86_64 class CPUs.
37035 */
37036 #ifndef SQLITE_HWTIME_H
37037 #define SQLITE_HWTIME_H
37038
37039 /*
37040 ** The following routine only works on Pentium-class (or newer) processors.
37041 ** It uses the RDTSC opcode to read the cycle count value out of the
37042 ** processor and returns that value. This can be used for high-res
37043 ** profiling.
37044 */
37045 #if !defined(__STRICT_ANSI__) && \
37046 (defined(__GNUC__) || defined(_MSC_VER)) && \
37047 (defined(i386) || defined(__i386__) || defined(_M_IX86))
37048
37049 #if defined(__GNUC__)
37050
37051 __inline__ sqlite_uint64 sqlite3Hwtime(void){
37052 unsigned int lo, hi;
37053 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
37054 return (sqlite_uint64)hi << 32 | lo;
37055 }
37056
37057 #elif defined(_MSC_VER)
37058
37059 __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
37060 __asm {
37061 rdtsc
37062 ret ; return value at EDX:EAX
37063 }
37064 }
37065
37066 #endif
37067
37068 #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
37069
37070 __inline__ sqlite_uint64 sqlite3Hwtime(void){
37071 unsigned int lo, hi;
37072 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
37073 return (sqlite_uint64)hi << 32 | lo;
37074 }
37075
37076 #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
37077
37078 __inline__ sqlite_uint64 sqlite3Hwtime(void){
37079 unsigned long long retval;
37080 unsigned long junk;
37081 __asm__ __volatile__ ("\n\
37082 1: mftbu %1\n\
37083 mftb %L0\n\
37084 mftbu %0\n\
37085 cmpw %0,%1\n\
37086 bne 1b"
37087 : "=r" (retval), "=r" (junk));
37088 return retval;
37089 }
37090
37091 #else
37092
37093 /*
37094 ** asm() is needed for hardware timing support. Without asm(),
37095 ** disable the sqlite3Hwtime() routine.
37096 **
37097 ** sqlite3Hwtime() is only used for some obscure debugging
37098 ** and analysis configurations, not in any deliverable, so this
37099 ** should not be a great loss.
37100 */
37101 SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
37102
37103 #endif
37104
37105 #endif /* !defined(SQLITE_HWTIME_H) */
37106
37107 /************** End of hwtime.h **********************************************/
37108 /************** Continuing where we left off in util.c ***********************/
37109 #endif
37110
37111 /************** End of util.c ************************************************/
37112 /************** Begin file hash.c ********************************************/
37113 /*
37114 ** 2001 September 22
37115 **
@@ -38787,11 +38699,11 @@
38787 # define F_SETLKW 7
38788 # endif
38789 # endif
38790 #else /* !SQLITE_WASI */
38791 # ifndef HAVE_FCHMOD
38792 # define HAVE_FCHMOD
38793 # endif
38794 #endif /* SQLITE_WASI */
38795
38796 #ifdef SQLITE_WASI
38797 # define osGetpid(X) (pid_t)1
@@ -41038,58 +40950,37 @@
41038 ** file by this or any other process. If such a lock is held, set *pResOut
41039 ** to a non-zero value otherwise *pResOut is set to zero. The return value
41040 ** is set to SQLITE_OK unless an I/O error occurs during lock checking.
41041 */
41042 static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
41043 int rc = SQLITE_OK;
41044 int reserved = 0;
41045 unixFile *pFile = (unixFile*)id;
 
 
 
41046
41047 SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
41048
41049 assert( pFile );
41050
41051 /* Check if a thread in this process holds such a lock */
41052 if( pFile->eFileLock>SHARED_LOCK ){
41053 reserved = 1;
41054 }
41055
41056 /* Otherwise see if some other process holds it. */
41057 if( !reserved ){
41058 /* attempt to get the lock */
41059 int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
41060 if( !lrc ){
41061 /* got the lock, unlock it */
41062 lrc = robust_flock(pFile->h, LOCK_UN);
41063 if ( lrc ) {
41064 int tErrno = errno;
41065 /* unlock failed with an error */
41066 lrc = SQLITE_IOERR_UNLOCK;
41067 storeLastErrno(pFile, tErrno);
41068 rc = lrc;
41069 }
41070 } else {
41071 int tErrno = errno;
41072 reserved = 1;
41073 /* someone else might have it reserved */
41074 lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
41075 if( IS_LOCK_ERROR(lrc) ){
41076 storeLastErrno(pFile, tErrno);
41077 rc = lrc;
41078 }
41079 }
41080 }
41081 OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
41082
41083 #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
41084 if( (rc & 0xff) == SQLITE_IOERR ){
41085 rc = SQLITE_OK;
41086 reserved=1;
41087 }
41088 #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
41089 *pResOut = reserved;
41090 return rc;
41091 }
41092
41093 /*
41094 ** Lock the file with the lock specified by parameter eFileLock - one
41095 ** of the following:
@@ -42582,10 +42473,15 @@
42582 int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
42583 return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
42584 }
42585 #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
42586
 
 
 
 
 
42587 case SQLITE_FCNTL_LOCKSTATE: {
42588 *(int*)pArg = pFile->eFileLock;
42589 return SQLITE_OK;
42590 }
42591 case SQLITE_FCNTL_LAST_ERRNO: {
@@ -42723,10 +42619,11 @@
42723
42724 /* Set the POWERSAFE_OVERWRITE flag if requested. */
42725 if( pFd->ctrlFlags & UNIXFILE_PSOW ){
42726 pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
42727 }
 
42728
42729 pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
42730 }
42731 }
42732 #else
@@ -42773,19 +42670,19 @@
42773 0;
42774 }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
42775 pFile->sectorSize = fsInfo.f_bsize;
42776 pFile->deviceCharacteristics =
42777 /* full bitset of atomics from max sector size and smaller */
42778 ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
42779 SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
42780 ** so it is ordered */
42781 0;
42782 }else if( strstr(fsInfo.f_basetype, "dos") ){
42783 pFile->sectorSize = fsInfo.f_bsize;
42784 pFile->deviceCharacteristics =
42785 /* full bitset of atomics from max sector size and smaller */
42786 ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
42787 SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
42788 ** so it is ordered */
42789 0;
42790 }else{
42791 pFile->deviceCharacteristics =
@@ -50462,10 +50359,15 @@
50462 OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
50463 hOldFile, pFile->h));
50464 return SQLITE_OK;
50465 }
50466 #endif
 
 
 
 
 
50467 case SQLITE_FCNTL_TEMPFILENAME: {
50468 char *zTFile = 0;
50469 int rc = winGetTempname(pFile->pVfs, &zTFile);
50470 if( rc==SQLITE_OK ){
50471 *(char**)pArg = zTFile;
@@ -50523,11 +50425,11 @@
50523 /*
50524 ** Return a vector of device characteristics.
50525 */
50526 static int winDeviceCharacteristics(sqlite3_file *id){
50527 winFile *p = (winFile*)id;
50528 return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
50529 ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
50530 }
50531
50532 /*
50533 ** Windows will only let you create file view mappings
@@ -51911,11 +51813,11 @@
51911 */
51912 char *zTmpname = 0; /* For temporary filename, if necessary. */
51913
51914 int rc = SQLITE_OK; /* Function Return Code */
51915 #if !defined(NDEBUG) || SQLITE_OS_WINCE
51916 int eType = flags&0xFFFFFF00; /* Type of file to open */
51917 #endif
51918
51919 int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
51920 int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
51921 int isCreate = (flags & SQLITE_OPEN_CREATE);
@@ -58131,24 +58033,32 @@
58131 #ifdef SQLITE_DIRECT_OVERFLOW_READ
58132 /*
58133 ** Return true if page pgno can be read directly from the database file
58134 ** by the b-tree layer. This is the case if:
58135 **
58136 ** * the database file is open,
58137 ** * there are no dirty pages in the cache, and
58138 ** * the desired page is not currently in the wal file.
 
58139 */
58140 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
58141 if( pPager->fd->pMethods==0 ) return 0;
58142 if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
 
 
58143 #ifndef SQLITE_OMIT_WAL
58144 if( pPager->pWal ){
58145 u32 iRead = 0;
58146 (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
58147 return iRead==0;
58148 }
58149 #endif
 
 
 
 
 
58150 return 1;
58151 }
58152 #endif
58153
58154 #ifndef SQLITE_OMIT_WAL
@@ -65171,11 +65081,11 @@
65171 ** 20: Salt-2, a different random integer changing with each ckpt
65172 ** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
65173 ** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
65174 **
65175 ** Immediately following the wal-header are zero or more frames. Each
65176 ** frame consists of a 24-byte frame-header followed by a <page-size> bytes
65177 ** of page data. The frame-header is six big-endian 32-bit unsigned
65178 ** integer values, as follows:
65179 **
65180 ** 0: Page number.
65181 ** 4: For commit records, the size of the database image in pages
@@ -65668,10 +65578,11 @@
65668 int nSehTry; /* Number of nested SEH_TRY{} blocks */
65669 u8 lockError; /* True if a locking error has occurred */
65670 #endif
65671 #ifdef SQLITE_ENABLE_SNAPSHOT
65672 WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
 
65673 #endif
65674 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
65675 sqlite3 *db;
65676 #endif
65677 };
@@ -67560,11 +67471,11 @@
67560 return SQLITE_IOERR_IN_PAGE;
67561 }
67562
67563 /*
67564 ** Assert that the Wal.lockMask mask, which indicates the locks held
67565 ** by the connenction, is consistent with the Wal.readLock, Wal.writeLock
67566 ** and Wal.ckptLock variables. To be used as:
67567 **
67568 ** assert( walAssertLockmask(pWal) );
67569 */
67570 static int walAssertLockmask(Wal *pWal){
@@ -68224,11 +68135,11 @@
68224 assert( pWal->apWiData[0]!=0 );
68225 pInfo = walCkptInfo(pWal);
68226 SEH_INJECT_FAULT;
68227 if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
68228 #ifdef SQLITE_ENABLE_SNAPSHOT
68229 && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
68230 #endif
68231 ){
68232 /* The WAL has been completely backfilled (or it is empty).
68233 ** and can be safely ignored.
68234 */
@@ -69624,11 +69535,24 @@
69624 */
69625 SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
69626 Wal *pWal,
69627 sqlite3_snapshot *pSnapshot
69628 ){
69629 pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
 
 
 
 
 
 
 
 
 
 
 
 
 
69630 }
69631
69632 /*
69633 ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
69634 ** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
@@ -75504,10 +75428,29 @@
75504 ** this routine.
75505 */
75506 SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){
75507 return ROUND8(sizeof(BtCursor));
75508 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75509
75510 /*
75511 ** Initialize memory that will be converted into a BtCursor object.
75512 **
75513 ** The simple approach here would be to memset() the entire object
@@ -84538,11 +84481,12 @@
84538 if( apVal==0 ){
84539 rc = SQLITE_NOMEM_BKPT;
84540 goto value_from_function_out;
84541 }
84542 for(i=0; i<nVal; i++){
84543 rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
 
84544 if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
84545 }
84546 }
84547
84548 pVal = valueNew(db, pCtx);
@@ -89571,11 +89515,11 @@
89571 /* The following two functions are used only within testcase() to prove
89572 ** test coverage. These functions do no exist for production builds.
89573 ** We must use separate SQLITE_NOINLINE functions here, since otherwise
89574 ** optimizer code movement causes gcov to become very confused.
89575 */
89576 #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
89577 static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
89578 static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
89579 #endif
89580
89581 /*
@@ -89586,17 +89530,10 @@
89586 SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
89587 if( sqlite3IsNaN(r) ){
89588 /* SQLite considers NaN to be a NULL. And all integer values are greater
89589 ** than NULL */
89590 return 1;
89591 }
89592 if( sqlite3Config.bUseLongDouble ){
89593 LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
89594 testcase( x<r );
89595 testcase( x>r );
89596 testcase( x==r );
89597 return (x<r) ? -1 : (x>r);
89598 }else{
89599 i64 y;
89600 if( r<-9223372036854775808.0 ) return +1;
89601 if( r>=9223372036854775808.0 ) return -1;
89602 y = (i64)r;
@@ -90595,17 +90532,25 @@
90595 db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
90596 db->pPreUpdate = 0;
90597 sqlite3DbFree(db, preupdate.aRecord);
90598 vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
90599 vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
 
90600 if( preupdate.aNew ){
90601 int i;
90602 for(i=0; i<pCsr->nField; i++){
90603 sqlite3VdbeMemRelease(&preupdate.aNew[i]);
90604 }
90605 sqlite3DbNNFreeNN(db, preupdate.aNew);
90606 }
 
 
 
 
 
 
 
90607 }
90608 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
90609
90610 /************** End of vdbeaux.c *********************************************/
90611 /************** Begin file vdbeapi.c *****************************************/
@@ -92230,10 +92175,21 @@
92230 ** A successful evaluation of this routine acquires the mutex on p.
92231 ** the mutex is released if any kind of error occurs.
92232 **
92233 ** The error code stored in database p->db is overwritten with the return
92234 ** value in any case.
 
 
 
 
 
 
 
 
 
 
 
92235 */
92236 static int vdbeUnbind(Vdbe *p, unsigned int i){
92237 Mem *pVar;
92238 if( vdbeSafetyNotNull(p) ){
92239 return SQLITE_MISUSE_BKPT;
@@ -92287,10 +92243,11 @@
92287 Mem *pVar;
92288 int rc;
92289
92290 rc = vdbeUnbind(p, (u32)(i-1));
92291 if( rc==SQLITE_OK ){
 
92292 if( zData!=0 ){
92293 pVar = &p->aVar[i-1];
92294 rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
92295 if( rc==SQLITE_OK && encoding!=0 ){
92296 rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
@@ -92336,10 +92293,11 @@
92336 SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
92337 int rc;
92338 Vdbe *p = (Vdbe *)pStmt;
92339 rc = vdbeUnbind(p, (u32)(i-1));
92340 if( rc==SQLITE_OK ){
 
92341 sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
92342 sqlite3_mutex_leave(p->db->mutex);
92343 }
92344 return rc;
92345 }
@@ -92349,10 +92307,11 @@
92349 SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
92350 int rc;
92351 Vdbe *p = (Vdbe *)pStmt;
92352 rc = vdbeUnbind(p, (u32)(i-1));
92353 if( rc==SQLITE_OK ){
 
92354 sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
92355 sqlite3_mutex_leave(p->db->mutex);
92356 }
92357 return rc;
92358 }
@@ -92359,10 +92318,11 @@
92359 SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
92360 int rc;
92361 Vdbe *p = (Vdbe*)pStmt;
92362 rc = vdbeUnbind(p, (u32)(i-1));
92363 if( rc==SQLITE_OK ){
 
92364 sqlite3_mutex_leave(p->db->mutex);
92365 }
92366 return rc;
92367 }
92368 SQLITE_API int sqlite3_bind_pointer(
@@ -92374,10 +92334,11 @@
92374 ){
92375 int rc;
92376 Vdbe *p = (Vdbe*)pStmt;
92377 rc = vdbeUnbind(p, (u32)(i-1));
92378 if( rc==SQLITE_OK ){
 
92379 sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
92380 sqlite3_mutex_leave(p->db->mutex);
92381 }else if( xDestructor ){
92382 xDestructor(pPtr);
92383 }
@@ -92455,10 +92416,11 @@
92455 SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
92456 int rc;
92457 Vdbe *p = (Vdbe *)pStmt;
92458 rc = vdbeUnbind(p, (u32)(i-1));
92459 if( rc==SQLITE_OK ){
 
92460 #ifndef SQLITE_OMIT_INCRBLOB
92461 sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
92462 #else
92463 rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
92464 #endif
@@ -92789,41 +92751,68 @@
92789 if( iIdx>=p->pCsr->nField || iIdx<0 ){
92790 rc = SQLITE_RANGE;
92791 goto preupdate_old_out;
92792 }
92793
92794 /* If the old.* record has not yet been loaded into memory, do so now. */
92795 if( p->pUnpacked==0 ){
92796 u32 nRec;
92797 u8 *aRec;
92798
92799 assert( p->pCsr->eCurType==CURTYPE_BTREE );
92800 nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
92801 aRec = sqlite3DbMallocRaw(db, nRec);
92802 if( !aRec ) goto preupdate_old_out;
92803 rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
92804 if( rc==SQLITE_OK ){
92805 p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
92806 if( !p->pUnpacked ) rc = SQLITE_NOMEM;
92807 }
92808 if( rc!=SQLITE_OK ){
92809 sqlite3DbFree(db, aRec);
92810 goto preupdate_old_out;
92811 }
92812 p->aRecord = aRec;
92813 }
92814
92815 pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
92816 if( iIdx==p->pTab->iPKey ){
 
92817 sqlite3VdbeMemSetInt64(pMem, p->iKey1);
92818 }else if( iIdx>=p->pUnpacked->nField ){
92819 *ppValue = (sqlite3_value *)columnNullValue();
92820 }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
92821 if( pMem->flags & (MEM_Int|MEM_IntReal) ){
92822 testcase( pMem->flags & MEM_Int );
92823 testcase( pMem->flags & MEM_IntReal );
92824 sqlite3VdbeMemRealify(pMem);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92825 }
92826 }
92827
92828 preupdate_old_out:
92829 sqlite3Error(db, rc);
@@ -93367,10 +93356,108 @@
93367 ** commenting and indentation practices when changing or adding code.
93368 */
93369 /* #include "sqliteInt.h" */
93370 /* #include "vdbeInt.h" */
93371
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93372 /*
93373 ** Invoke this macro on memory cells just prior to changing the
93374 ** value of the cell. This macro verifies that shallow copies are
93375 ** not misused. A shallow copy of a string or blob just copies a
93376 ** pointer to the string or blob, not the content. If the original
@@ -97875,12 +97962,17 @@
97875 0, pCx->uc.pCursor);
97876 pCx->isTable = 1;
97877 }
97878 }
97879 pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
 
97880 if( rc ){
 
97881 sqlite3BtreeClose(pCx->ub.pBtx);
 
 
 
97882 }
97883 }
97884 }
97885 if( rc ) goto abort_due_to_error;
97886 pCx->nullRow = 1;
@@ -102394,11 +102486,11 @@
102394 ** element.
102395 **
102396 ** As with all opcodes, the meanings of the parameters for OP_Explain
102397 ** are subject to change from one release to the next. Applications
102398 ** should not attempt to interpret or use any of the information
102399 ** contined in the OP_Explain opcode. The information provided by this
102400 ** opcode is intended for testing and debugging use only.
102401 */
102402 default: { /* This is really OP_Noop, OP_Explain */
102403 assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
102404
@@ -107490,11 +107582,11 @@
107490 ** non-VIEW candidate plus multiple VIEW candidates. In other
107491 ** words non-VIEW candidate terms take precedence over VIEWs.
107492 */
107493 if( cntTab==0
107494 || (cntTab==1
107495 && ALWAYS(pMatch!=0)
107496 && ALWAYS(pMatch->pSTab!=0)
107497 && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
107498 && (pTab->tabFlags & TF_Ephemeral)==0)
107499 ){
107500 cntTab = 1;
@@ -108123,12 +108215,12 @@
108123 }
108124
108125 /* Resolve function names
108126 */
108127 case TK_FUNCTION: {
108128 ExprList *pList = pExpr->x.pList; /* The argument list */
108129 int n = pList ? pList->nExpr : 0; /* Number of arguments */
108130 int no_such_func = 0; /* True if no such function exists */
108131 int wrong_num_args = 0; /* True if wrong number of arguments */
108132 int is_agg = 0; /* True if is an aggregate function */
108133 const char *zId; /* The function name. */
108134 FuncDef *pDef; /* Information about the function */
@@ -108137,10 +108229,12 @@
108137 #ifndef SQLITE_OMIT_WINDOWFUNC
108138 Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
108139 #endif
108140 assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
108141 assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
 
 
108142 zId = pExpr->u.zToken;
108143 pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
108144 if( pDef==0 ){
108145 pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
108146 if( pDef==0 ){
@@ -108185,10 +108279,28 @@
108185 pExpr->op = TK_NULL;
108186 return WRC_Prune;
108187 }
108188 }
108189 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108190 if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
108191 /* For the purposes of the EP_ConstFunc flag, date and time
108192 ** functions and other functions that change slowly are considered
108193 ** constant because they are constant for the duration of one query.
108194 ** This allows them to be factored out of inner loops. */
@@ -111951,11 +112063,11 @@
111951 **
111952 ** (4) If pSrc is the right operand of a LEFT JOIN, then...
111953 ** (4a) pExpr must come from an ON clause..
111954 ** (4b) and specifically the ON clause associated with the LEFT JOIN.
111955 **
111956 ** (5) If pSrc is not the right operand of a LEFT JOIN or the left
111957 ** operand of a RIGHT JOIN, then pExpr must be from the WHERE
111958 ** clause, not an ON clause.
111959 **
111960 ** (6) Either:
111961 **
@@ -113858,10 +113970,63 @@
113858 }
113859 #endif /* !defined(SQLITE_UNTESTABLE) */
113860 }
113861 return target;
113862 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113863
113864 /*
113865 ** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
113866 ** If it is, then resolve the expression by reading from the index and
113867 ** return the register into which the value has been read. If pExpr is
@@ -113891,10 +114056,21 @@
113891 ){
113892 /* Affinity mismatch on a generated column */
113893 continue;
113894 }
113895
 
 
 
 
 
 
 
 
 
 
 
113896 v = pParse->pVdbe;
113897 assert( v!=0 );
113898 if( p->bMaybeNullRow ){
113899 /* If the index is on a NULL row due to an outer join, then we
113900 ** cannot extract the value from the index. The value must be
@@ -115421,35 +115597,41 @@
115421 **
115422 ** Additionally, if pExpr is a simple SQL value and the value is the
115423 ** same as that currently bound to variable pVar, non-zero is returned.
115424 ** Otherwise, if the values are not the same or if pExpr is not a simple
115425 ** SQL value, zero is returned.
 
 
 
115426 */
115427 static int exprCompareVariable(
115428 const Parse *pParse,
115429 const Expr *pVar,
115430 const Expr *pExpr
115431 ){
115432 int res = 0;
115433 int iVar;
115434 sqlite3_value *pL, *pR = 0;
115435
 
 
 
 
115436 sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
115437 if( pR ){
115438 iVar = pVar->iColumn;
115439 sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
115440 pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
115441 if( pL ){
115442 if( sqlite3_value_type(pL)==SQLITE_TEXT ){
115443 sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
115444 }
115445 res = 0==sqlite3MemCompare(pL, pR, 0);
115446 }
115447 sqlite3ValueFree(pR);
115448 sqlite3ValueFree(pL);
115449 }
115450
115451 return res;
115452 }
115453
115454 /*
115455 ** Do a deep comparison of two expression trees. Return 0 if the two
@@ -115471,16 +115653,14 @@
115471 ** can be sure the expressions are the same. In the places where
115472 ** this routine is used, it does not hurt to get an extra 2 - that
115473 ** just might result in some slightly slower code. But returning
115474 ** an incorrect 0 or 1 could lead to a malfunction.
115475 **
115476 ** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
115477 ** pParse->pReprepare can be matched against literals in pB. The
115478 ** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
115479 ** If pParse is NULL (the normal case) then any TK_VARIABLE term in
115480 ** Argument pParse should normally be NULL. If it is not NULL and pA or
115481 ** pB causes a return value of 2.
115482 */
115483 SQLITE_PRIVATE int sqlite3ExprCompare(
115484 const Parse *pParse,
115485 const Expr *pA,
115486 const Expr *pB,
@@ -115488,12 +115668,12 @@
115488 ){
115489 u32 combinedFlags;
115490 if( pA==0 || pB==0 ){
115491 return pB==pA ? 0 : 2;
115492 }
115493 if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
115494 return 0;
115495 }
115496 combinedFlags = pA->flags | pB->flags;
115497 if( combinedFlags & EP_IntValue ){
115498 if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
115499 return 0;
@@ -115683,23 +115863,75 @@
115683 return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
115684 }
115685 }
115686 return 0;
115687 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115688
115689 /*
115690 ** Return true if we can prove the pE2 will always be true if pE1 is
115691 ** true. Return false if we cannot complete the proof or if pE2 might
115692 ** be false. Examples:
115693 **
115694 ** pE1: x==5 pE2: x==5 Result: true
115695 ** pE1: x>0 pE2: x==5 Result: false
115696 ** pE1: x=21 pE2: x=21 OR y=43 Result: true
115697 ** pE1: x!=123 pE2: x IS NOT NULL Result: true
115698 ** pE1: x!=?1 pE2: x IS NOT NULL Result: true
115699 ** pE1: x IS NULL pE2: x IS NOT NULL Result: false
115700 ** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
 
 
115701 **
115702 ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
115703 ** Expr.iTable<0 then assume a table number given by iTab.
115704 **
115705 ** If pParse is not NULL, then the values of bound variables in pE1 are
@@ -115729,10 +115961,13 @@
115729 if( pE2->op==TK_NOTNULL
115730 && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0)
115731 ){
115732 return 1;
115733 }
 
 
 
115734 return 0;
115735 }
115736
115737 /* This is a helper function to impliesNotNullRow(). In this routine,
115738 ** set pWalker->eCode to one only if *both* of the input expressions
@@ -120689,12 +120924,12 @@
120689 int nIdxCol = 1; /* Number of columns in stat4 records */
120690
120691 char *zIndex; /* Index name */
120692 Index *pIdx; /* Pointer to the index object */
120693 int nSample; /* Number of samples */
120694 int nByte; /* Bytes of space required */
120695 int i; /* Bytes of space required */
120696 tRowcnt *pSpace; /* Available allocated memory space */
120697 u8 *pPtr; /* Available memory as a u8 for easier manipulation */
120698
120699 zIndex = (char *)sqlite3_column_text(pStmt, 0);
120700 if( zIndex==0 ) continue;
@@ -121140,19 +121375,10 @@
121140 rc = sqlite3Init(db, &zErrDyn);
121141 }
121142 sqlite3BtreeLeaveAll(db);
121143 assert( zErrDyn==0 || rc!=SQLITE_OK );
121144 }
121145 #ifdef SQLITE_USER_AUTHENTICATION
121146 if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
121147 u8 newAuth = 0;
121148 rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
121149 if( newAuth<db->auth.authLevel ){
121150 rc = SQLITE_AUTH_USER;
121151 }
121152 }
121153 #endif
121154 if( rc ){
121155 if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
121156 int iDb = db->nDb - 1;
121157 assert( iDb>=2 );
121158 if( db->aDb[iDb].pBt ){
@@ -121646,15 +121872,11 @@
121646 sqlite3 *db = pParse->db; /* Database handle */
121647 char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
121648 int rc; /* Auth callback return code */
121649
121650 if( db->init.busy ) return SQLITE_OK;
121651 rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
121652 #ifdef SQLITE_USER_AUTHENTICATION
121653 ,db->auth.zAuthUser
121654 #endif
121655 );
121656 if( rc==SQLITE_DENY ){
121657 char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
121658 if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
121659 sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
121660 pParse->rc = SQLITE_AUTH;
@@ -121757,15 +121979,11 @@
121757 testcase( zArg1==0 );
121758 testcase( zArg2==0 );
121759 testcase( zArg3==0 );
121760 testcase( pParse->zAuthContext==0 );
121761
121762 rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
121763 #ifdef SQLITE_USER_AUTHENTICATION
121764 ,db->auth.zAuthUser
121765 #endif
121766 );
121767 if( rc==SQLITE_DENY ){
121768 sqlite3ErrorMsg(pParse, "not authorized");
121769 pParse->rc = SQLITE_AUTH;
121770 }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
121771 rc = SQLITE_DENY;
@@ -121994,21 +122212,10 @@
121994 sqlite3VdbeJumpHere(v, addrRewind);
121995 }
121996 }
121997 sqlite3VdbeAddOp0(v, OP_Halt);
121998
121999 #if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE)
122000 if( pParse->nTableLock>0 && db->init.busy==0 ){
122001 sqlite3UserAuthInit(db);
122002 if( db->auth.authLevel<UAUTH_User ){
122003 sqlite3ErrorMsg(pParse, "user not authenticated");
122004 pParse->rc = SQLITE_AUTH_USER;
122005 return;
122006 }
122007 }
122008 #endif
122009
122010 /* The cookie mask contains one bit for each database file open.
122011 ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
122012 ** set for each database that is used. Generate code to start a
122013 ** transaction on each used database and to verify the schema cookie
122014 ** on each used database.
@@ -122133,20 +122340,10 @@
122133 sqlite3DbFree(db, zSql);
122134 memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
122135 pParse->nested--;
122136 }
122137
122138 #if SQLITE_USER_AUTHENTICATION
122139 /*
122140 ** Return TRUE if zTable is the name of the system table that stores the
122141 ** list of users and their access credentials.
122142 */
122143 SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){
122144 return sqlite3_stricmp(zTable, "sqlite_user")==0;
122145 }
122146 #endif
122147
122148 /*
122149 ** Locate the in-memory structure that describes a particular database
122150 ** table given the name of that table and (optionally) the name of the
122151 ** database containing the table. Return NULL if not found.
122152 **
@@ -122161,17 +122358,10 @@
122161 Table *p = 0;
122162 int i;
122163
122164 /* All mutexes are required for schema access. Make sure we hold them. */
122165 assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
122166 #if SQLITE_USER_AUTHENTICATION
122167 /* Only the admin user is allowed to know that the sqlite_user table
122168 ** exists */
122169 if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
122170 return 0;
122171 }
122172 #endif
122173 if( zDatabase ){
122174 for(i=0; i<db->nDb; i++){
122175 if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
122176 }
122177 if( i>=db->nDb ){
@@ -125826,13 +126016,10 @@
125826
125827 assert( pTab!=0 );
125828 if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
125829 && db->init.busy==0
125830 && pTblName!=0
125831 #if SQLITE_USER_AUTHENTICATION
125832 && sqlite3UserAuthTable(pTab->zName)==0
125833 #endif
125834 ){
125835 sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
125836 goto exit_create_index;
125837 }
125838 #ifndef SQLITE_OMIT_VIEW
@@ -128224,10 +128411,11 @@
128224 ** 4) The table is a shadow table, the database connection is in
128225 ** defensive mode, and the current sqlite3_prepare()
128226 ** is for a top-level SQL statement.
128227 */
128228 static int vtabIsReadOnly(Parse *pParse, Table *pTab){
 
128229 if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
128230 return 1;
128231 }
128232
128233 /* Within triggers:
@@ -131716,11 +131904,17 @@
131716 #ifdef SQLITE_DEBUG
131717 /*
131718 ** Implementation of fpdecode(x,y,z) function.
131719 **
131720 ** x is a real number that is to be decoded. y is the precision.
131721 ** z is the maximum real precision.
 
 
 
 
 
 
131722 */
131723 static void fpdecodeFunc(
131724 sqlite3_context *context,
131725 int argc,
131726 sqlite3_value **argv
@@ -131740,10 +131934,86 @@
131740 sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
131741 }else{
131742 sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
131743 }
131744 sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131745 }
131746 #endif /* SQLITE_DEBUG */
131747
131748 /*
131749 ** All of the FuncDef structures in the aBuiltinFunc[] array above
@@ -131777,13 +132047,10 @@
131777 #endif
131778 #ifndef SQLITE_OMIT_LOAD_EXTENSION
131779 SFUNCTION(load_extension, 1, 0, 0, loadExt ),
131780 SFUNCTION(load_extension, 2, 0, 0, loadExt ),
131781 #endif
131782 #if SQLITE_USER_AUTHENTICATION
131783 FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
131784 #endif
131785 #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
131786 DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
131787 DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
131788 #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
131789 INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
@@ -131805,11 +132072,12 @@
131805 FUNCTION(max, -1, 1, 1, minmaxFunc ),
131806 FUNCTION(max, 0, 1, 1, 0 ),
131807 WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
131808 SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
131809 FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
131810 FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
 
131811 FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
131812 FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
131813 FUNCTION(instr, 2, 0, 0, instrFunc ),
131814 FUNCTION(printf, -1, 0, 0, printfFunc ),
131815 FUNCTION(format, -1, 0, 0, printfFunc ),
@@ -131816,10 +132084,11 @@
131816 FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
131817 FUNCTION(char, -1, 0, 0, charFunc ),
131818 FUNCTION(abs, 1, 0, 0, absFunc ),
131819 #ifdef SQLITE_DEBUG
131820 FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
 
131821 #endif
131822 #ifndef SQLITE_OMIT_FLOATING_POINT
131823 FUNCTION(round, 1, 0, 0, roundFunc ),
131824 FUNCTION(round, 2, 0, 0, roundFunc ),
131825 #endif
@@ -131910,15 +132179,18 @@
131910 MFUNCTION(atanh, 1, atanh, math1Func ),
131911 #endif
131912 MFUNCTION(sqrt, 1, sqrt, math1Func ),
131913 MFUNCTION(radians, 1, degToRad, math1Func ),
131914 MFUNCTION(degrees, 1, radToDeg, math1Func ),
131915 FUNCTION(pi, 0, 0, 0, piFunc ),
131916 #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
131917 FUNCTION(sign, 1, 0, 0, signFunc ),
131918 INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
 
131919 INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
 
 
131920 };
131921 #ifndef SQLITE_OMIT_ALTERTABLE
131922 sqlite3AlterFunctions();
131923 #endif
131924 sqlite3WindowFunctions();
@@ -140427,16 +140699,10 @@
140427 if( db->autoCommit==0 ){
140428 /* Foreign key support may not be enabled or disabled while not
140429 ** in auto-commit mode. */
140430 mask &= ~(SQLITE_ForeignKeys);
140431 }
140432 #if SQLITE_USER_AUTHENTICATION
140433 if( db->auth.authLevel==UAUTH_User ){
140434 /* Do not allow non-admin users to modify the schema arbitrarily */
140435 mask &= ~(SQLITE_WriteSchema);
140436 }
140437 #endif
140438
140439 if( sqlite3GetBoolean(zRight, 0) ){
140440 if( (mask & SQLITE_WriteSchema)==0
140441 || (db->flags & SQLITE_Defensive)==0
140442 ){
@@ -140568,11 +140834,12 @@
140568 pTab = sqliteHashData(k);
140569 if( pTab->nCol==0 ){
140570 char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName);
140571 if( zSql ){
140572 sqlite3_stmt *pDummy = 0;
140573 (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0);
 
140574 (void)sqlite3_finalize(pDummy);
140575 sqlite3DbFree(db, zSql);
140576 }
140577 if( db->mallocFailed ){
140578 sqlite3ErrorMsg(db->pParse, "out of memory");
@@ -141044,10 +141311,11 @@
141044 }
141045 aRoot[0] = cnt;
141046
141047 /* Make sure sufficient number of registers have been allocated */
141048 sqlite3TouchRegister(pParse, 8+cnt);
 
141049 sqlite3ClearTempRegCache(pParse);
141050
141051 /* Do the b-tree integrity checks */
141052 sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
141053 sqlite3VdbeChangeP5(v, (u8)i);
@@ -142668,18 +142936,11 @@
142668 encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
142669 if( encoding==0 ) encoding = SQLITE_UTF8;
142670 #else
142671 encoding = SQLITE_UTF8;
142672 #endif
142673 if( db->nVdbeActive>0 && encoding!=ENC(db)
142674 && (db->mDbFlags & DBFLAG_Vacuum)==0
142675 ){
142676 rc = SQLITE_LOCKED;
142677 goto initone_error_out;
142678 }else{
142679 sqlite3SetTextEncoding(db, encoding);
142680 }
142681 }else{
142682 /* If opening an attached database, the encoding much match ENC(db) */
142683 if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
142684 sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
142685 " text encoding as main database");
@@ -143369,16 +143630,28 @@
143369 #endif
143370 *ppStmt = 0;
143371 if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
143372 return SQLITE_MISUSE_BKPT;
143373 }
 
 
 
 
 
 
143374 if( nBytes>=0 ){
143375 int sz;
143376 const char *z = (const char*)zSql;
143377 for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
143378 nBytes = sz;
 
 
 
 
 
143379 }
 
143380 sqlite3_mutex_enter(db->mutex);
143381 zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
143382 if( zSql8 ){
143383 rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
143384 }
@@ -143388,11 +143661,11 @@
143388 ** equivalent pointer into the UTF-16 string by counting the unicode
143389 ** characters between zSql8 and zTail8, and then returning a pointer
143390 ** the same number of characters into the UTF-16 string.
143391 */
143392 int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
143393 *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
143394 }
143395 sqlite3DbFree(db, zSql8);
143396 rc = sqlite3ApiExit(db, rc);
143397 sqlite3_mutex_leave(db->mutex);
143398 return rc;
@@ -147361,36 +147634,36 @@
147361 return pExpr;
147362 }
147363 if( pSubst->isOuterJoin ){
147364 ExprSetProperty(pNew, EP_CanBeNull);
147365 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147366 if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
147367 sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
147368 pExpr->flags & (EP_OuterON|EP_InnerON));
147369 }
147370 sqlite3ExprDelete(db, pExpr);
147371 pExpr = pNew;
147372 if( pExpr->op==TK_TRUEFALSE ){
147373 pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
147374 pExpr->op = TK_INTEGER;
147375 ExprSetProperty(pExpr, EP_IntValue);
147376 }
147377
147378 /* Ensure that the expression now has an implicit collation sequence,
147379 ** just as it did when it was a column of a view or sub-query. */
147380 {
147381 CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
147382 CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
147383 pSubst->pCList->a[iColumn].pExpr
147384 );
147385 if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
147386 pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
147387 (pColl ? pColl->zName : "BINARY")
147388 );
147389 }
147390 }
147391 ExprClearProperty(pExpr, EP_Collate);
147392 }
147393 }
147394 }else{
147395 if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
147396 pExpr->iTable = pSubst->iNewTable;
@@ -148123,20 +148396,20 @@
148123 }
148124
148125 /* Transfer the FROM clause terms from the subquery into the
148126 ** outer query.
148127 */
 
148128 for(i=0; i<nSubSrc; i++){
148129 SrcItem *pItem = &pSrc->a[i+iFrom];
148130 assert( pItem->fg.isTabFunc==0 );
148131 assert( pItem->fg.isSubquery
148132 || pItem->fg.fixedSchema
148133 || pItem->u4.zDatabase==0 );
148134 if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
148135 *pItem = pSubSrc->a[i];
148136 pItem->fg.jointype |= ltorj;
148137 iNewParent = pSubSrc->a[i].iCursor;
148138 memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
148139 }
148140 pSrc->a[iFrom].fg.jointype &= JT_LTORJ;
148141 pSrc->a[iFrom].fg.jointype |= jointype | ltorj;
148142
@@ -148172,10 +148445,11 @@
148172 pSub->pOrderBy = 0;
148173 }
148174 pWhere = pSub->pWhere;
148175 pSub->pWhere = 0;
148176 if( isOuterJoin>0 ){
 
148177 sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
148178 }
148179 if( pWhere ){
148180 if( pParent->pWhere ){
148181 pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
@@ -151271,11 +151545,11 @@
151271 sqlite3TreeViewSelect(0, p, 0);
151272 }
151273 #endif
151274 assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
151275 }else{
151276 TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
151277 }
151278
151279 /* Convert unused result columns of the subquery into simple NULL
151280 ** expressions, to avoid unneeded searching and computation.
151281 ** tag-select-0440
@@ -156980,10 +157254,11 @@
156980 assert( sParse.zErrMsg==0 );
156981 if( !pTab->aCol ){
156982 Table *pNew = sParse.pNewTable;
156983 Index *pIdx;
156984 pTab->aCol = pNew->aCol;
 
156985 sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
156986 pTab->nNVCol = pTab->nCol = pNew->nCol;
156987 pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
156988 pNew->nCol = 0;
156989 pNew->aCol = 0;
@@ -158044,13 +158319,21 @@
158044 SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
158045 const Parse *pParse, /* Parse context */
158046 const WhereInfo *pWInfo, /* WHERE clause */
158047 const WhereLevel *pLevel /* Bloom filter on this level */
158048 );
 
 
 
 
 
 
 
158049 #else
158050 # define sqlite3WhereExplainOneScan(u,v,w,x) 0
158051 # define sqlite3WhereExplainBloomFilter(u,v,w) 0
 
158052 #endif /* SQLITE_OMIT_EXPLAIN */
158053 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
158054 SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
158055 Vdbe *v, /* Vdbe to add scanstatus entry to */
158056 SrcList *pSrclist, /* FROM clause pLvl reads data from */
@@ -158248,42 +158531,42 @@
158248 }
158249 sqlite3_str_append(pStr, ")", 1);
158250 }
158251
158252 /*
158253 ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
158254 ** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
158255 ** was defined at compile-time. If it is not a no-op, a single OP_Explain
158256 ** opcode is added to the output to describe the table scan strategy in pLevel.
158257 **
158258 ** If an OP_Explain opcode is added to the VM, its address is returned.
158259 ** Otherwise, if no OP_Explain is coded, zero is returned.
158260 */
158261 SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
158262 Parse *pParse, /* Parse context */
 
158263 SrcList *pTabList, /* Table list this loop refers to */
158264 WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158265 u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158266 ){
158267 int ret = 0;
158268 #if !defined(SQLITE_DEBUG)
158269 if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
158270 #endif
158271 {
 
 
158272 SrcItem *pItem = &pTabList->a[pLevel->iFrom];
158273 Vdbe *v = pParse->pVdbe; /* VM being constructed */
158274 sqlite3 *db = pParse->db; /* Database handle */
158275 int isSearch; /* True for a SEARCH. False for SCAN. */
158276 WhereLoop *pLoop; /* The controlling WhereLoop object */
158277 u32 flags; /* Flags that describe this loop */
 
158278 char *zMsg; /* Text to add to EQP output */
 
158279 StrAccum str; /* EQP output string */
158280 char zBuf[100]; /* Initial space for EQP output string */
158281
 
 
158282 pLoop = pLevel->pWLoop;
158283 flags = pLoop->wsFlags;
158284 if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
158285
158286 isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
158287 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
158288 || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
158289
@@ -158303,11 +158586,11 @@
158303 }
158304 }else if( flags & WHERE_PARTIALIDX ){
158305 zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
158306 }else if( flags & WHERE_AUTO_INDEX ){
158307 zFmt = "AUTOMATIC COVERING INDEX";
158308 }else if( flags & WHERE_IDX_ONLY ){
158309 zFmt = "COVERING INDEX %s";
158310 }else{
158311 zFmt = "INDEX %s";
158312 }
158313 if( zFmt ){
@@ -158355,15 +158638,54 @@
158355 sqlite3LogEstToInt(pLoop->nOut));
158356 }else{
158357 sqlite3_str_append(&str, " (~1 row)", 9);
158358 }
158359 #endif
 
158360 zMsg = sqlite3StrAccumFinish(&str);
158361 sqlite3ExplainBreakpoint("",zMsg);
158362 ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
158363 pParse->addrExplain, pLoop->rRun,
158364 zMsg, P4_DYNAMIC);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158365 }
158366 return ret;
158367 }
158368
158369 /*
@@ -158458,13 +158780,14 @@
158458 if( wsFlags & WHERE_INDEXED ){
158459 sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
158460 }
158461 }else{
158462 int addr;
 
158463 assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
158464 addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
158465 VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
158466 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
158467 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
158468 sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
158469 }
158470 }
@@ -158713,10 +159036,11 @@
158713 if( pOrigLhs ){
158714 sqlite3ExprListDelete(db, pOrigLhs);
158715 pNew->pLeft->x.pList = pLhs;
158716 }
158717 pSelect->pEList = pRhs;
 
158718 if( pLhs && pLhs->nExpr==1 ){
158719 /* Take care here not to generate a TK_VECTOR containing only a
158720 ** single value. Since the parser never creates such a vector, some
158721 ** of the subroutines do not handle this case. */
158722 Expr *p = pLhs->a[0].pExpr;
@@ -161260,24 +161584,29 @@
161260 }else if( op==TK_STRING ){
161261 assert( !ExprHasProperty(pRight, EP_IntValue) );
161262 z = (u8*)pRight->u.zToken;
161263 }
161264 if( z ){
161265
161266 /* Count the number of prefix characters prior to the first wildcard.
161267 ** If the underlying database has a UTF16LE encoding, then only consider
161268 ** ASCII characters. Note that the encoding of z[] is UTF8 - we are
161269 ** dealing with only UTF8 here in this code, but the database engine
161270 ** itself might be processing content using a different encoding. */
161271 cnt = 0;
161272 while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
161273 cnt++;
161274 if( c==wc[3] && z[cnt]!=0 ){
161275 cnt++;
161276 }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){
161277 cnt--;
161278 break;
 
 
 
 
 
161279 }
161280 }
161281
161282 /* The optimization is possible only if (1) the pattern does not begin
161283 ** with a wildcard and if (2) the non-wildcard prefix does not end with
@@ -161285,11 +161614,11 @@
161285 ** a single escape character. The second condition is necessary so
161286 ** that we can increment the prefix key to find an upper bound for the
161287 ** range search. The third is because the caller assumes that the pattern
161288 ** consists of at least one character after all escapes have been
161289 ** removed. */
161290 if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
161291 Expr *pPrefix;
161292
161293 /* A "complete" match if the pattern ends with "*" or "%" */
161294 *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
161295
@@ -163780,11 +164109,11 @@
163780 || pTerm->pExpr->w.iJoin != pSrc->iCursor
163781 ){
163782 return 0;
163783 }
163784 if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
163785 && ExprHasProperty(pTerm->pExpr, EP_InnerON)
163786 ){
163787 return 0;
163788 }
163789 return 1;
163790 }
@@ -164577,13 +164906,15 @@
164577 ** Whether or not an error is returned, it is the responsibility of the
164578 ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
164579 ** that this is required.
164580 */
164581 static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
164582 sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
164583 int rc;
 
164584
 
 
164585 whereTraceIndexInfoInputs(p, pTab);
164586 pParse->db->nSchemaLock++;
164587 rc = pVtab->pModule->xBestIndex(pVtab, p);
164588 pParse->db->nSchemaLock--;
164589 whereTraceIndexInfoOutputs(p, pTab);
@@ -165271,11 +165602,11 @@
165271 return rc;
165272 }
165273 #endif /* SQLITE_ENABLE_STAT4 */
165274
165275
165276 #ifdef WHERETRACE_ENABLED
165277 /*
165278 ** Print the content of a WhereTerm object
165279 */
165280 SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
165281 if( pTerm==0 ){
@@ -165314,10 +165645,13 @@
165314 sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
165315 }
165316 sqlite3DebugPrintf("\n");
165317 sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
165318 }
 
 
 
165319 }
165320 #endif
165321
165322 #ifdef WHERETRACE_ENABLED
165323 /*
@@ -165522,11 +165856,11 @@
165522 ** Return TRUE if X is a proper subset of Y but is of equal or less cost.
165523 ** In other words, return true if all constraints of X are also part of Y
165524 ** and Y has additional constraints that might speed the search that X lacks
165525 ** but the cost of running X is not more than the cost of running Y.
165526 **
165527 ** In other words, return true if the cost relationwship between X and Y
165528 ** is inverted and needs to be adjusted.
165529 **
165530 ** Case 1:
165531 **
165532 ** (1a) X and Y use the same index.
@@ -166500,11 +166834,10 @@
166500 pParse = pWC->pWInfo->pParse;
166501 while( pWhere->op==TK_AND ){
166502 if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0;
166503 pWhere = pWhere->pRight;
166504 }
166505 if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
166506 for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
166507 Expr *pExpr;
166508 pExpr = pTerm->pExpr;
166509 if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
166510 && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
@@ -169140,10 +169473,11 @@
169140 hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
169141 for(i=pWInfo->nLevel-1; i>=1; i--){
169142 WhereTerm *pTerm, *pEnd;
169143 SrcItem *pItem;
169144 WhereLoop *pLoop;
 
169145 pLoop = pWInfo->a[i].pWLoop;
169146 pItem = &pWInfo->pTabList->a[pLoop->iTab];
169147 if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue;
169148 if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0
169149 && (pLoop->wsFlags & WHERE_ONEROW)==0
@@ -169160,17 +169494,20 @@
169160 break;
169161 }
169162 }
169163 if( hasRightJoin
169164 && ExprHasProperty(pTerm->pExpr, EP_InnerON)
169165 && pTerm->pExpr->w.iJoin==pItem->iCursor
169166 ){
169167 break; /* restriction (5) */
169168 }
169169 }
169170 if( pTerm<pEnd ) continue;
169171 WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
 
 
 
169172 notReady &= ~pLoop->maskSelf;
169173 for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
169174 if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
169175 pTerm->wtFlags |= TERM_CODED;
169176 }
@@ -169237,62 +169574,10 @@
169237 nSearch += pLoop->nOut;
169238 if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta;
169239 }
169240 }
169241
169242 /*
169243 ** Expression Node callback for sqlite3ExprCanReturnSubtype().
169244 **
169245 ** Only a function call is able to return a subtype. So if the node
169246 ** is not a function call, return WRC_Prune immediately.
169247 **
169248 ** A function call is able to return a subtype if it has the
169249 ** SQLITE_RESULT_SUBTYPE property.
169250 **
169251 ** Assume that every function is able to pass-through a subtype from
169252 ** one of its argument (using sqlite3_result_value()). Most functions
169253 ** are not this way, but we don't have a mechanism to distinguish those
169254 ** that are from those that are not, so assume they all work this way.
169255 ** That means that if one of its arguments is another function and that
169256 ** other function is able to return a subtype, then this function is
169257 ** able to return a subtype.
169258 */
169259 static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
169260 int n;
169261 FuncDef *pDef;
169262 sqlite3 *db;
169263 if( pExpr->op!=TK_FUNCTION ){
169264 return WRC_Prune;
169265 }
169266 assert( ExprUseXList(pExpr) );
169267 db = pWalker->pParse->db;
169268 n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
169269 pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
169270 if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
169271 pWalker->eCode = 1;
169272 return WRC_Prune;
169273 }
169274 return WRC_Continue;
169275 }
169276
169277 /*
169278 ** Return TRUE if expression pExpr is able to return a subtype.
169279 **
169280 ** A TRUE return does not guarantee that a subtype will be returned.
169281 ** It only indicates that a subtype return is possible. False positives
169282 ** are acceptable as they only disable an optimization. False negatives,
169283 ** on the other hand, can lead to incorrect answers.
169284 */
169285 static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
169286 Walker w;
169287 memset(&w, 0, sizeof(w));
169288 w.pParse = pParse;
169289 w.xExprCallback = exprNodeCanReturnSubtype;
169290 sqlite3WalkExpr(&w, pExpr);
169291 return w.eCode;
169292 }
169293
169294 /*
169295 ** The index pIdx is used by a query and contains one or more expressions.
169296 ** In other words pIdx is an index on an expression. iIdxCur is the cursor
169297 ** number for the index and iDataCur is the cursor number for the corresponding
169298 ** table.
@@ -169322,16 +169607,10 @@
169322 pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
169323 }else{
169324 continue;
169325 }
169326 if( sqlite3ExprIsConstant(0,pExpr) ) continue;
169327 if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){
169328 /* Functions that might set a subtype should not be replaced by the
169329 ** value taken from an expression index since the index omits the
169330 ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
169331 continue;
169332 }
169333 p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
169334 if( p==0 ) break;
169335 p->pIENext = pParse->pIdxEpr;
169336 #ifdef WHERETRACE_ENABLED
169337 if( sqlite3WhereTrace & 0x200 ){
@@ -170434,18 +170713,32 @@
170434 x = sqlite3TableColumnToIndex(pIdx, x);
170435 if( x>=0 ){
170436 pOp->p2 = x;
170437 pOp->p1 = pLevel->iIdxCur;
170438 OpcodeRewriteTrace(db, k, pOp);
170439 }else{
170440 /* Unable to translate the table reference into an index
170441 ** reference. Verify that this is harmless - that the
170442 ** table being referenced really is open.
170443 */
170444 if( pLoop->wsFlags & WHERE_IDX_ONLY ){
 
 
 
170445 sqlite3ErrorMsg(pParse, "internal query planner error");
170446 pParse->rc = SQLITE_INTERNAL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170447 }
170448 }
170449 }else if( pOp->opcode==OP_Rowid ){
170450 pOp->p1 = pLevel->iIdxCur;
170451 pOp->opcode = OP_IdxRowid;
@@ -172149,10 +172442,11 @@
172149 for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
172150 FuncDef *pFunc = pWin->pWFunc;
172151 int regArg;
172152 int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
172153 int i;
 
172154
172155 assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
172156
172157 /* All OVER clauses in the same window function aggregate step must
172158 ** be the same. */
@@ -172164,10 +172458,22 @@
172164 }else{
172165 sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
172166 }
172167 }
172168 regArg = reg;
 
 
 
 
 
 
 
 
 
 
 
 
172169
172170 if( pMWin->regStartRowid==0
172171 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
172172 && (pWin->eStart!=TK_UNBOUNDED)
172173 ){
@@ -172184,29 +172490,17 @@
172184 sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
172185 sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
172186 }
172187 sqlite3VdbeJumpHere(v, addrIsNull);
172188 }else if( pWin->regApp ){
 
172189 assert( pFunc->zName==nth_valueName
172190 || pFunc->zName==first_valueName
172191 );
172192 assert( bInverse==0 || bInverse==1 );
172193 sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
172194 }else if( pFunc->xSFunc!=noopStepFunc ){
172195 int addrIf = 0;
172196 if( pWin->pFilter ){
172197 int regTmp;
172198 assert( ExprUseXList(pWin->pOwner) );
172199 assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
172200 assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
172201 regTmp = sqlite3GetTempReg(pParse);
172202 sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
172203 addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
172204 VdbeCoverage(v);
172205 sqlite3ReleaseTempReg(pParse, regTmp);
172206 }
172207
172208 if( pWin->bExprArgs ){
172209 int iOp = sqlite3VdbeCurrentAddr(v);
172210 int iEnd;
172211
172212 assert( ExprUseXList(pWin->pOwner) );
@@ -172233,12 +172527,13 @@
172233 sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
172234 sqlite3VdbeChangeP5(v, (u8)nArg);
172235 if( pWin->bExprArgs ){
172236 sqlite3ReleaseTempRange(pParse, regArg, nArg);
172237 }
172238 if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
172239 }
 
 
172240 }
172241 }
172242
172243 /*
172244 ** Values that may be passed as the second argument to windowCodeOp().
@@ -173660,10 +173955,17 @@
173660 ** Then the "b" IdList records the list "a,b,c".
173661 */
173662 struct TrigEvent { int a; IdList * b; };
173663
173664 struct FrameBound { int eType; Expr *pExpr; };
 
 
 
 
 
 
 
173665
173666 /*
173667 ** Disable lookaside memory allocation for objects that might be
173668 ** shared across database connections.
173669 */
@@ -177553,11 +177855,15 @@
177553 }
177554 break;
177555 case 84: /* cmd ::= select */
177556 {
177557 SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
177558 sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
 
 
 
 
177559 sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
177560 }
177561 break;
177562 case 85: /* select ::= WITH wqlist selectnowith */
177563 {yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
@@ -178024,11 +178330,11 @@
178024 ** that look like this: #1 #2 ... These terms refer to registers
178025 ** in the virtual machine. #N is the N-th register. */
178026 Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
178027 assert( t.n>=2 );
178028 if( pParse->nested==0 ){
178029 sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
178030 yymsp[0].minor.yy454 = 0;
178031 }else{
178032 yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
178033 if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
178034 }
@@ -178872,11 +179178,11 @@
178872 #define TOKEN yyminor
178873 /************ Begin %syntax_error code ****************************************/
178874
178875 UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
178876 if( TOKEN.z[0] ){
178877 sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
178878 }else{
178879 sqlite3ErrorMsg(pParse, "incomplete input");
178880 }
178881 /************ End %syntax_error code ******************************************/
178882 sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
@@ -180363,11 +180669,13 @@
180363 }
180364 if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
180365 if( pParse->zErrMsg==0 ){
180366 pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
180367 }
180368 sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
 
 
180369 nErr++;
180370 }
180371 pParse->zTail = zSql;
180372 #ifndef SQLITE_OMIT_VIRTUALTABLE
180373 sqlite3_free(pParse->apVtabLock);
@@ -181071,36 +181379,10 @@
181071 ** all database files specified with a relative pathname.
181072 **
181073 ** See also the "PRAGMA data_store_directory" SQL command.
181074 */
181075 SQLITE_API char *sqlite3_data_directory = 0;
181076
181077 /*
181078 ** Determine whether or not high-precision (long double) floating point
181079 ** math works correctly on CPU currently running.
181080 */
181081 static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){
181082 if( sizeof(LONGDOUBLE_TYPE)<=8 ){
181083 /* If the size of "long double" is not more than 8, then
181084 ** high-precision math is not possible. */
181085 return 0;
181086 }else{
181087 /* Just because sizeof(long double)>8 does not mean that the underlying
181088 ** hardware actually supports high-precision floating point. For example,
181089 ** clearing the 0x100 bit in the floating-point control word on Intel
181090 ** processors will make long double work like double, even though long
181091 ** double takes up more space. The only way to determine if long double
181092 ** actually works is to run an experiment. */
181093 LONGDOUBLE_TYPE a, b, c;
181094 rc++;
181095 a = 1.0+rc*0.1;
181096 b = 1.0e+18+rc*25.0;
181097 c = a+b;
181098 return b!=c;
181099 }
181100 }
181101
181102
181103 /*
181104 ** Initialize SQLite.
181105 **
181106 ** This routine must be called to initialize the memory allocation,
@@ -181292,17 +181574,10 @@
181292 if( bRunExtraInit ){
181293 int SQLITE_EXTRA_INIT(const char*);
181294 rc = SQLITE_EXTRA_INIT(0);
181295 }
181296 #endif
181297
181298 /* Experimentally determine if high-precision floating point is
181299 ** available. */
181300 #ifndef SQLITE_OMIT_WSD
181301 sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc);
181302 #endif
181303
181304 return rc;
181305 }
181306
181307 /*
181308 ** Undo the effects of sqlite3_initialize(). Must not be called while
@@ -182369,14 +182644,10 @@
182369 #endif
182370
182371 sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
182372 sqlite3ValueFree(db->pErr);
182373 sqlite3CloseExtensions(db);
182374 #if SQLITE_USER_AUTHENTICATION
182375 sqlite3_free(db->auth.zAuthUser);
182376 sqlite3_free(db->auth.zAuthPW);
182377 #endif
182378
182379 db->eOpenState = SQLITE_STATE_ERROR;
182380
182381 /* The temp-database schema is allocated differently from the other schema
182382 ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
@@ -183875,12 +184146,12 @@
183875 }
183876 oldLimit = db->aLimit[limitId];
183877 if( newLimit>=0 ){ /* IMP: R-52476-28732 */
183878 if( newLimit>aHardLimit[limitId] ){
183879 newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
183880 }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
183881 newLimit = 1;
183882 }
183883 db->aLimit[limitId] = newLimit;
183884 }
183885 return oldLimit; /* IMP: R-53341-35419 */
183886 }
@@ -184395,10 +184666,11 @@
184395 testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
184396 testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
184397 if( ((1<<(flags&7)) & 0x46)==0 ){
184398 rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
184399 }else{
 
184400 rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
184401 }
184402 if( rc!=SQLITE_OK ){
184403 if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
184404 sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
@@ -185237,10 +185509,11 @@
185237 #ifndef SQLITE_OMIT_WINDOWFUNC
185238 sqlite3ShowWindow(0);
185239 sqlite3ShowWinFunc(0);
185240 #endif
185241 sqlite3ShowSelect(0);
 
185242 }
185243 #endif
185244 break;
185245 }
185246
@@ -185549,28 +185822,10 @@
185549 *pI1 = rLogEst;
185550 *pU64 = sqlite3LogEstToInt(rLogEst);
185551 *pI2 = sqlite3LogEst(*pU64);
185552 break;
185553 }
185554
185555 #if !defined(SQLITE_OMIT_WSD)
185556 /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
185557 **
185558 ** X<0 Make no changes to the bUseLongDouble. Just report value.
185559 ** X==0 Disable bUseLongDouble
185560 ** X==1 Enable bUseLongDouble
185561 ** X>=2 Set bUseLongDouble to its default value for this platform
185562 */
185563 case SQLITE_TESTCTRL_USELONGDOUBLE: {
185564 int b = va_arg(ap, int);
185565 if( b>=2 ) b = hasHighPrecisionDouble(b);
185566 if( b>=0 ) sqlite3Config.bUseLongDouble = b>0;
185567 rc = sqlite3Config.bUseLongDouble!=0;
185568 break;
185569 }
185570 #endif
185571
185572
185573 #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
185574 /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
185575 **
185576 ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value
@@ -185875,11 +186130,15 @@
185875 if( db->autoCommit==0 ){
185876 int iDb = sqlite3FindDbName(db, zDb);
185877 if( iDb==0 || iDb>1 ){
185878 Btree *pBt = db->aDb[iDb].pBt;
185879 if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
 
 
 
185880 rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
 
185881 if( rc==SQLITE_OK ){
185882 rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
185883 }
185884 }
185885 }
@@ -189665,14 +189924,19 @@
189665
189666 assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
189667 if( *p1==POS_COLUMN ){
189668 p1++;
189669 p1 += fts3GetVarint32(p1, &iCol1);
 
 
 
189670 }
189671 if( *p2==POS_COLUMN ){
189672 p2++;
189673 p2 += fts3GetVarint32(p2, &iCol2);
 
 
189674 }
189675
189676 while( 1 ){
189677 if( iCol1==iCol2 ){
189678 char *pSave = p;
@@ -192839,11 +193103,11 @@
192839 for(p=pExpr; p->pLeft; p=p->pLeft){
192840 assert( p->pRight->pPhrase->doclist.nList>0 );
192841 nTmp += p->pRight->pPhrase->doclist.nList;
192842 }
192843 nTmp += p->pPhrase->doclist.nList;
192844 aTmp = sqlite3_malloc64(nTmp*2);
192845 if( !aTmp ){
192846 *pRc = SQLITE_NOMEM;
192847 res = 0;
192848 }else{
192849 char *aPoslist = p->pPhrase->doclist.pList;
@@ -193490,11 +193754,11 @@
193490 SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
193491 return SQLITE_CORRUPT_VTAB;
193492 }
193493 #endif
193494
193495 #if !SQLITE_CORE
193496 /*
193497 ** Initialize API pointer table, if required.
193498 */
193499 #ifdef _WIN32
193500 __declspec(dllexport)
@@ -194392,14 +194656,15 @@
194392 rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
194393 if( rc==SQLITE_OK ){
194394 Fts3PhraseToken *pToken;
194395
194396 p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
194397 if( !p ) goto no_mem;
194398
194399 zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
194400 if( !zTemp ) goto no_mem;
 
 
 
194401
194402 assert( nToken==ii );
194403 pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
194404 memset(pToken, 0, sizeof(Fts3PhraseToken));
194405
@@ -194410,53 +194675,51 @@
194410 pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
194411 pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
194412 nToken = ii+1;
194413 }
194414 }
194415
194416 pModule->xClose(pCursor);
194417 pCursor = 0;
194418 }
194419
194420 if( rc==SQLITE_DONE ){
194421 int jj;
194422 char *zBuf = 0;
194423
194424 p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
194425 if( !p ) goto no_mem;
 
 
 
194426 memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
194427 p->eType = FTSQUERY_PHRASE;
194428 p->pPhrase = (Fts3Phrase *)&p[1];
194429 p->pPhrase->iColumn = pParse->iDefaultCol;
194430 p->pPhrase->nToken = nToken;
194431
194432 zBuf = (char *)&p->pPhrase->aToken[nToken];
 
194433 if( zTemp ){
194434 memcpy(zBuf, zTemp, nTemp);
194435 sqlite3_free(zTemp);
194436 }else{
194437 assert( nTemp==0 );
194438 }
194439
194440 for(jj=0; jj<p->pPhrase->nToken; jj++){
194441 p->pPhrase->aToken[jj].z = zBuf;
194442 zBuf += p->pPhrase->aToken[jj].n;
194443 }
194444 rc = SQLITE_OK;
194445 }
194446
194447 *ppExpr = p;
194448 return rc;
194449 no_mem:
194450
194451 if( pCursor ){
194452 pModule->xClose(pCursor);
194453 }
194454 sqlite3_free(zTemp);
194455 sqlite3_free(p);
194456 *ppExpr = 0;
194457 return SQLITE_NOMEM;
 
 
 
194458 }
194459
194460 /*
194461 ** The output variable *ppExpr is populated with an allocated Fts3Expr
194462 ** structure, or set to 0 if the end of the input buffer is reached.
@@ -208867,11 +209130,13 @@
208867 int rawKey = 1;
208868 x = pParse->aBlob[iRoot];
208869 zPath++;
208870 if( zPath[0]=='"' ){
208871 zKey = zPath + 1;
208872 for(i=1; zPath[i] && zPath[i]!='"'; i++){}
 
 
208873 nKey = i-1;
208874 if( zPath[i] ){
208875 i++;
208876 }else{
208877 return JSON_LOOKUP_PATHERROR;
@@ -217779,11 +218044,11 @@
217779 return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
217780 (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
217781 );
217782 }
217783
217784 #if !SQLITE_CORE
217785 #ifdef _WIN32
217786 __declspec(dllexport)
217787 #endif
217788 SQLITE_API int sqlite3_rtree_init(
217789 sqlite3 *db,
@@ -218370,11 +218635,11 @@
218370 }
218371
218372 return rc;
218373 }
218374
218375 #if !SQLITE_CORE
218376 #ifdef _WIN32
218377 __declspec(dllexport)
218378 #endif
218379 SQLITE_API int sqlite3_icu_init(
218380 sqlite3 *db,
@@ -219628,10 +219893,31 @@
219628 struct RbuFrame {
219629 u32 iDbPage;
219630 u32 iWalFrame;
219631 };
219632
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219633 /*
219634 ** RBU handle.
219635 **
219636 ** nPhaseOneStep:
219637 ** If the RBU database contains an rbu_count table, this value is set to
@@ -219679,11 +219965,11 @@
219679 char *zState; /* Path to state db (or NULL if zRbu) */
219680 char zStateDb[5]; /* Db name for state ("stat" or "main") */
219681 int rc; /* Value returned by last rbu_step() call */
219682 char *zErrmsg; /* Error message if rc!=SQLITE_OK */
219683 int nStep; /* Rows processed for current object */
219684 int nProgress; /* Rows processed for all objects */
219685 RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
219686 const char *zVfsName; /* Name of automatically created rbu vfs */
219687 rbu_file *pTargetFd; /* File handle open on target db */
219688 int nPagePerSector; /* Pages per sector for pTargetFd */
219689 i64 iOalSz;
@@ -219796,11 +220082,11 @@
219796 unsigned char *zStart = z;
219797 while( (c = zValue[0x7f&*(z++)])>=0 ){
219798 v = (v<<6) + c;
219799 }
219800 z--;
219801 *pLen -= z - zStart;
219802 *pz = (char*)z;
219803 return v;
219804 }
219805
219806 #if RBU_ENABLE_DELTA_CKSUM
@@ -219981,10 +220267,11 @@
219981 int nOut;
219982 int nOut2;
219983 char *aOut;
219984
219985 assert( argc==2 );
 
219986
219987 nOrig = sqlite3_value_bytes(argv[0]);
219988 aOrig = (const char*)sqlite3_value_blob(argv[0]);
219989 nDelta = sqlite3_value_bytes(argv[1]);
219990 aDelta = (const char*)sqlite3_value_blob(argv[1]);
@@ -221560,17 +221847,17 @@
221560 nParen++;
221561 }
221562 else if( c==')' ){
221563 nParen--;
221564 if( nParen==0 ){
221565 int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
221566 pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
221567 i++;
221568 break;
221569 }
221570 }else if( c==',' && nParen==1 ){
221571 int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
221572 pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
221573 pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
221574 }else if( c=='"' || c=='\'' || c=='`' ){
221575 for(i++; 1; i++){
221576 if( zSql[i]==c ){
@@ -222256,10 +222543,12 @@
222256 int i, sz;
222257 sz = (int)strlen(z)&0xffffff;
222258 for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
222259 if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
222260 }
 
 
222261 #endif
222262 }
222263
222264 /*
222265 ** Return the current wal-index header checksum for the target database
@@ -222840,11 +223129,11 @@
222840 "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
222841 "(%d, %d), "
222842 "(%d, %Q), "
222843 "(%d, %Q), "
222844 "(%d, %d), "
222845 "(%d, %d), "
222846 "(%d, %lld), "
222847 "(%d, %lld), "
222848 "(%d, %lld), "
222849 "(%d, %lld), "
222850 "(%d, %Q) ",
@@ -223198,10 +223487,11 @@
223198 char *zErrmsg = 0;
223199 int rc;
223200 sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
223201
223202 assert( nVal==1 );
 
223203
223204 rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
223205 sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
223206 "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
223207 );
@@ -223473,11 +223763,11 @@
223473 const char *zTarget,
223474 const char *zState
223475 ){
223476 if( zTarget==0 ){ return rbuMisuseError(); }
223477 if( zState ){
223478 int n = strlen(zState);
223479 if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
223480 return rbuMisuseError();
223481 }
223482 }
223483 /* TODO: Check that both arguments are non-NULL */
@@ -223690,10 +223980,11 @@
223690 /*
223691 ** Default xRename callback for RBU.
223692 */
223693 static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
223694 int rc = SQLITE_OK;
 
223695 #if defined(_WIN32_WCE)
223696 {
223697 LPWSTR zWideOld;
223698 LPWSTR zWideNew;
223699
@@ -224594,10 +224885,13 @@
224594
224595 /*
224596 ** No-op.
224597 */
224598 static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
 
 
 
224599 return 0;
224600 }
224601
224602 /*
224603 ** Deregister and destroy an RBU vfs created by an earlier call to
@@ -225650,11 +225944,17 @@
225650 ** schema for the database file that is to be read. The default schema is
225651 ** "main".
225652 **
225653 ** The data field of sqlite_dbpage table can be updated. The new
225654 ** value must be a BLOB which is the correct page size, otherwise the
225655 ** update fails. Rows may not be deleted or inserted.
 
 
 
 
 
 
225656 */
225657
225658 /* #include "sqliteInt.h" ** Requires access to internal data structures ** */
225659 #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
225660 && !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -225673,17 +225973,18 @@
225673 };
225674
225675 struct DbpageTable {
225676 sqlite3_vtab base; /* Base class. Must be first */
225677 sqlite3 *db; /* The database */
 
 
225678 };
225679
225680 /* Columns */
225681 #define DBPAGE_COLUMN_PGNO 0
225682 #define DBPAGE_COLUMN_DATA 1
225683 #define DBPAGE_COLUMN_SCHEMA 2
225684
225685
225686
225687 /*
225688 ** Connect to or create a dbpagevfs virtual table.
225689 */
@@ -225943,15 +226244,15 @@
225943 DbpageTable *pTab = (DbpageTable *)pVtab;
225944 Pgno pgno;
225945 DbPage *pDbPage = 0;
225946 int rc = SQLITE_OK;
225947 char *zErr = 0;
225948 const char *zSchema;
225949 int iDb;
225950 Btree *pBt;
225951 Pager *pPager;
225952 int szPage;
 
225953
225954 (void)pRowid;
225955 if( pTab->db->flags & SQLITE_Defensive ){
225956 zErr = "read-only";
225957 goto update_fail;
@@ -225958,45 +226259,62 @@
225958 }
225959 if( argc==1 ){
225960 zErr = "cannot delete";
225961 goto update_fail;
225962 }
225963 pgno = sqlite3_value_int(argv[0]);
225964 if( sqlite3_value_type(argv[0])==SQLITE_NULL
225965 || (Pgno)sqlite3_value_int(argv[1])!=pgno
225966 ){
225967 zErr = "cannot insert";
225968 goto update_fail;
225969 }
225970 zSchema = (const char*)sqlite3_value_text(argv[4]);
225971 iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1;
225972 if( NEVER(iDb<0) ){
225973 zErr = "no such schema";
225974 goto update_fail;
 
 
 
 
 
 
 
 
225975 }
225976 pBt = pTab->db->aDb[iDb].pBt;
225977 if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){
225978 zErr = "bad page number";
225979 goto update_fail;
225980 }
225981 szPage = sqlite3BtreeGetPageSize(pBt);
225982 if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
225983 || sqlite3_value_bytes(argv[3])!=szPage
225984 ){
225985 zErr = "bad page value";
225986 goto update_fail;
 
 
 
 
 
 
 
 
225987 }
225988 pPager = sqlite3BtreePager(pBt);
225989 rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
225990 if( rc==SQLITE_OK ){
225991 const void *pData = sqlite3_value_blob(argv[3]);
225992 assert( pData!=0 || pTab->db->mallocFailed );
225993 if( pData
225994 && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
225995 ){
225996 memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
225997 }
 
 
225998 }
225999 sqlite3PagerUnref(pDbPage);
226000 return rc;
226001
226002 update_fail:
@@ -226015,13 +226333,35 @@
226015 int i;
226016 for(i=0; i<db->nDb; i++){
226017 Btree *pBt = db->aDb[i].pBt;
226018 if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
226019 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226020 return SQLITE_OK;
226021 }
226022
226023
226024 /*
226025 ** Invoke this routine to register the "dbpage" virtual table module
226026 */
226027 SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
@@ -226039,18 +226379,18 @@
226039 dbpageEof, /* xEof - check for end of scan */
226040 dbpageColumn, /* xColumn - read data */
226041 dbpageRowid, /* xRowid - read data */
226042 dbpageUpdate, /* xUpdate */
226043 dbpageBegin, /* xBegin */
226044 0, /* xSync */
226045 0, /* xCommit */
226046 0, /* xRollback */
226047 0, /* xFindMethod */
226048 0, /* xRename */
226049 0, /* xSavepoint */
226050 0, /* xRelease */
226051 0, /* xRollbackTo */
226052 0, /* xShadowName */
226053 0 /* xIntegrity */
226054 };
226055 return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
226056 }
@@ -226134,10 +226474,14 @@
226134 /*
226135 ** An object of this type is used internally as an abstraction for
226136 ** input data. Input data may be supplied either as a single large buffer
226137 ** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
226138 ** sqlite3changeset_start_strm()).
 
 
 
 
226139 */
226140 struct SessionInput {
226141 int bNoDiscard; /* If true, do not discard in InputBuffer() */
226142 int iCurrent; /* Offset in aData[] of current change */
226143 int iNext; /* Offset in aData[] of next change */
@@ -227817,20 +228161,23 @@
227817 /* Figure out how large an allocation is required */
227818 nByte = sizeof(SessionChange);
227819 for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
227820 sqlite3_value *p = 0;
227821 if( op!=SQLITE_INSERT ){
227822 TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
227823 assert( trc==SQLITE_OK );
 
227824 }else if( pTab->abPK[i] ){
227825 TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
227826 assert( trc==SQLITE_OK );
227827 }
227828
227829 /* This may fail if SQLite value p contains a utf-16 string that must
227830 ** be converted to utf-8 and an OOM error occurs while doing so. */
227831 rc = sessionSerializeValue(0, p, &nByte);
 
 
227832 if( rc!=SQLITE_OK ) goto error_out;
227833 }
227834 if( pTab->bRowid ){
227835 nByte += 9; /* Size of rowid field - an integer */
227836 }
@@ -231184,19 +231531,25 @@
231184 int rc = SQLITE_OK; /* Return code */
231185 const char *zTab = 0; /* Name of current table */
231186 int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
231187 SessionApplyCtx sApply; /* changeset_apply() context object */
231188 int bPatchset;
 
231189
231190 assert( xConflict!=0 );
 
 
 
 
 
 
231191
231192 pIter->in.bNoDiscard = 1;
231193 memset(&sApply, 0, sizeof(sApply));
231194 sApply.bRebase = (ppRebase && pnRebase);
231195 sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
231196 sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
231197 sqlite3_mutex_enter(sqlite3_db_mutex(db));
231198 if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
231199 rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
231200 }
231201 if( rc==SQLITE_OK ){
231202 rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
@@ -231354,10 +231707,16 @@
231354 sqlite3_finalize(sApply.pDelete);
231355 sqlite3_finalize(sApply.pSelect);
231356 sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
231357 sqlite3_free((char*)sApply.constraints.aBuf);
231358 sqlite3_free((char*)sApply.rebase.aBuf);
 
 
 
 
 
 
231359 sqlite3_mutex_leave(sqlite3_db_mutex(db));
231360 return rc;
231361 }
231362
231363 /*
@@ -231382,28 +231741,17 @@
231382 int flags
231383 ){
231384 sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
231385 int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
231386 int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
231387 u64 savedFlag = db->flags & SQLITE_FkNoAction;
231388
231389 if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
231390 db->flags |= ((u64)SQLITE_FkNoAction);
231391 db->aDb[0].pSchema->schema_cookie -= 32;
231392 }
231393
231394 if( rc==SQLITE_OK ){
231395 rc = sessionChangesetApply(
231396 db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
231397 );
231398 }
231399
231400 if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
231401 assert( db->flags & SQLITE_FkNoAction );
231402 db->flags &= ~((u64)SQLITE_FkNoAction);
231403 db->aDb[0].pSchema->schema_cookie -= 32;
231404 }
231405 return rc;
231406 }
231407
231408 /*
231409 ** Apply the changeset passed via pChangeset/nChangeset to the main database
@@ -231720,10 +232068,13 @@
231720 if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
231721 /* Append the missing default column values to the record. */
231722 sessionAppendBlob(pOut, aRec, nRec, &rc);
231723 if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
231724 rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
 
 
 
231725 }
231726 for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
231727 int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
231728 sessionAppendByte(pOut, eType, &rc);
231729 switch( eType ){
@@ -231736,10 +232087,11 @@
231736 double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
231737 memcpy(&iVal, &rVal, sizeof(i64));
231738 }
231739 if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
231740 sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
 
231741 }
231742 break;
231743 }
231744
231745 case SQLITE_BLOB:
@@ -231874,10 +232226,12 @@
231874 SessionChange *pExist = 0;
231875 SessionChange **pp = 0;
231876 SessionTable *pTab = 0;
231877 u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
231878 int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
 
 
231879
231880 /* Ensure that only changesets, or only patchsets, but not a mixture
231881 ** of both, are being combined. It is an error to try to combine a
231882 ** changeset and a patchset. */
231883 if( pGrp->pList==0 ){
@@ -231952,10 +232306,11 @@
231952 ){
231953 u8 *aRec;
231954 int nRec;
231955 int rc = SQLITE_OK;
231956
 
231957 while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
231958 rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
231959 if( rc!=SQLITE_OK ) break;
231960 }
231961
@@ -232583,20 +232938,46 @@
232583 #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
232584
232585 /************** End of sqlite3session.c **************************************/
232586 /************** Begin file fts5.c ********************************************/
232587
232588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232589 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
232590
232591 #if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
232592 # define NDEBUG 1
232593 #endif
232594 #if defined(NDEBUG) && defined(SQLITE_DEBUG)
232595 # undef NDEBUG
232596 #endif
232597
 
 
 
 
 
 
232598 /*
232599 ** 2014 May 31
232600 **
232601 ** The author disclaims copyright to this source code. In place of
232602 ** a legal notice, here is a blessing:
@@ -232893,17 +233274,32 @@
232893 ** This is used to access token iToken of phrase hit iIdx within the
232894 ** current row. If iIdx is less than zero or greater than or equal to the
232895 ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
232896 ** output variable (*ppToken) is set to point to a buffer containing the
232897 ** matching document token, and (*pnToken) to the size of that buffer in
232898 ** bytes. This API is not available if the specified token matches a
232899 ** prefix query term. In that case both output variables are always set
232900 ** to 0.
232901 **
232902 ** The output text is not a copy of the document text that was tokenized.
232903 ** It is the output of the tokenizer module. For tokendata=1 tables, this
232904 ** includes any embedded 0x00 and trailing data.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232905 **
232906 ** This API can be quite slow if used with an FTS5 table created with the
232907 ** "detail=none" or "detail=column" option.
232908 **
232909 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -232991,11 +233387,10 @@
232991 ** CUSTOM TOKENIZERS
232992 **
232993 ** Applications may also register custom tokenizer types. A tokenizer
232994 ** is registered by providing fts5 with a populated instance of the
232995 ** following structure. All structure methods must be defined, setting
232996 **
232997 ** any member of the fts5_tokenizer struct to NULL leads to undefined
232998 ** behaviour. The structure methods are expected to function as follows:
232999 **
233000 ** xCreate:
233001 ** This function is used to allocate and initialize a tokenizer instance.
@@ -233560,10 +233955,11 @@
233560 u8 *abUnindexed; /* True for unindexed columns */
233561 int nPrefix; /* Number of prefix indexes */
233562 int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
233563 int eContent; /* An FTS5_CONTENT value */
233564 int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
 
233565 char *zContent; /* content table */
233566 char *zContentRowid; /* "content_rowid=" option value */
233567 int bColumnsize; /* "columnsize=" option value (dflt==1) */
233568 int bTokendata; /* "tokendata=" option value (dflt==0) */
233569 int bLocale; /* "locale=" option value (dflt==0) */
@@ -233582,11 +233978,12 @@
233582 int nUsermerge; /* 'usermerge' setting */
233583 int nHashSize; /* Bytes of memory for in-memory hash */
233584 char *zRank; /* Name of rank function */
233585 char *zRankArgs; /* Arguments to rank function */
233586 int bSecureDelete; /* 'secure-delete' */
233587 int nDeleteMerge; /* 'deletemerge' */
 
233588
233589 /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
233590 char **pzErrmsg;
233591
233592 #ifdef SQLITE_DEBUG
@@ -233598,13 +233995,14 @@
233598 ** the expected version if the 'secure-delete' option has ever been
233599 ** set on the table. */
233600 #define FTS5_CURRENT_VERSION 4
233601 #define FTS5_CURRENT_VERSION_SECUREDELETE 5
233602
233603 #define FTS5_CONTENT_NORMAL 0
233604 #define FTS5_CONTENT_NONE 1
233605 #define FTS5_CONTENT_EXTERNAL 2
 
233606
233607 #define FTS5_DETAIL_FULL 0
233608 #define FTS5_DETAIL_NONE 1
233609 #define FTS5_DETAIL_COLUMNS 2
233610
@@ -233838,11 +234236,18 @@
233838 static int sqlite3Fts5StructureTest(Fts5Index*, void*);
233839
233840 /*
233841 ** Used by xInstToken():
233842 */
233843 static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
 
 
 
 
 
 
 
233844
233845 /*
233846 ** Insert or remove data to or from the index. Each time a document is
233847 ** added to or removed from the index, this function is called one or more
233848 ** times.
@@ -233972,20 +234377,17 @@
233972
233973 static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
233974
233975 static int sqlite3Fts5FlushToDisk(Fts5Table*);
233976
233977 static int sqlite3Fts5ExtractText(
233978 Fts5Config *pConfig,
233979 sqlite3_value *pVal, /* Value to extract text from */
233980 int bContent, /* Loaded from content table */
233981 int *pbResetTokenizer, /* OUT: True if ClearLocale() required */
233982 const char **ppText, /* OUT: Pointer to text buffer */
233983 int *pnText /* OUT: Size of (*ppText) in bytes */
233984 );
233985
233986 static void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
 
 
 
 
 
 
233987
233988 /*
233989 ** End of interface to code in fts5.c.
233990 **************************************************************************/
233991
@@ -234063,11 +234465,11 @@
234063
234064 static int sqlite3Fts5DropAll(Fts5Config*);
234065 static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
234066
234067 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
234068 static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
234069 static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
234070
234071 static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
234072
234073 static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
@@ -237270,10 +237672,11 @@
237270 const char *zArg, /* Argument to parse */
237271 char **pzErr /* OUT: Error message */
237272 ){
237273 int rc = SQLITE_OK;
237274 int nCmd = (int)strlen(zCmd);
 
237275 if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
237276 const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
237277 const char *p;
237278 int bFirst = 1;
237279 if( pConfig->aPrefix==0 ){
@@ -237388,10 +237791,20 @@
237388 }else{
237389 pConfig->bContentlessDelete = (zArg[0]=='1');
237390 }
237391 return rc;
237392 }
 
 
 
 
 
 
 
 
 
 
237393
237394 if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
237395 if( pConfig->zContentRowid ){
237396 *pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
237397 rc = SQLITE_ERROR;
@@ -237506,11 +237919,12 @@
237506
237507 static int fts5ConfigParseColumn(
237508 Fts5Config *p,
237509 char *zCol,
237510 char *zArg,
237511 char **pzErr
 
237512 ){
237513 int rc = SQLITE_OK;
237514 if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
237515 || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
237516 ){
@@ -237517,10 +237931,11 @@
237517 *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
237518 rc = SQLITE_ERROR;
237519 }else if( zArg ){
237520 if( 0==sqlite3_stricmp(zArg, "unindexed") ){
237521 p->abUnindexed[p->nCol] = 1;
 
237522 }else{
237523 *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
237524 rc = SQLITE_ERROR;
237525 }
237526 }
@@ -237537,15 +237952,30 @@
237537 int rc = SQLITE_OK;
237538 Fts5Buffer buf = {0, 0, 0};
237539
237540 sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
237541 if( p->eContent!=FTS5_CONTENT_NONE ){
 
 
 
 
237542 for(i=0; i<p->nCol; i++){
237543 if( p->eContent==FTS5_CONTENT_EXTERNAL ){
237544 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
237545 }else{
237546 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
 
 
 
 
 
 
 
 
 
 
 
237547 }
237548 }
237549 }
237550
237551 assert( p->zContentExprlist==0 );
@@ -237575,10 +238005,11 @@
237575 ){
237576 int rc = SQLITE_OK; /* Return code */
237577 Fts5Config *pRet; /* New object to return */
237578 int i;
237579 sqlite3_int64 nByte;
 
237580
237581 *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
237582 if( pRet==0 ) return SQLITE_NOMEM;
237583 memset(pRet, 0, sizeof(Fts5Config));
237584 pRet->pGlobal = pGlobal;
@@ -237634,11 +238065,11 @@
237634 ALWAYS(zOne)?zOne:"",
237635 zTwo?zTwo:"",
237636 pzErr
237637 );
237638 }else{
237639 rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
237640 zOne = 0;
237641 }
237642 }
237643 }
237644
@@ -237665,18 +238096,34 @@
237665 *pzErr = sqlite3_mprintf(
237666 "contentless_delete=1 is incompatible with columnsize=0"
237667 );
237668 rc = SQLITE_ERROR;
237669 }
 
 
 
 
 
 
 
 
 
 
 
 
 
237670
237671 /* If no zContent option was specified, fill in the default values. */
237672 if( rc==SQLITE_OK && pRet->zContent==0 ){
237673 const char *zTail = 0;
237674 assert( pRet->eContent==FTS5_CONTENT_NORMAL
237675 || pRet->eContent==FTS5_CONTENT_NONE
237676 );
237677 if( pRet->eContent==FTS5_CONTENT_NORMAL ){
 
 
 
237678 zTail = "content";
237679 }else if( pRet->bColumnsize ){
237680 zTail = "docsize";
237681 }
237682
@@ -238010,10 +238457,23 @@
238010 if( bVal<0 ){
238011 *pbBadkey = 1;
238012 }else{
238013 pConfig->bSecureDelete = (bVal ? 1 : 0);
238014 }
 
 
 
 
 
 
 
 
 
 
 
 
 
238015 }else{
238016 *pbBadkey = 1;
238017 }
238018 return rc;
238019 }
@@ -241145,11 +241605,11 @@
241145 && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
241146 ){
241147 int rc = sqlite3Fts5PoslistWriterAppend(
241148 &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
241149 );
241150 if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
241151 int iCol = p->iOff>>32;
241152 int iTokOff = p->iOff & 0x7FFFFFFF;
241153 rc = sqlite3Fts5IndexIterWriteTokendata(
241154 pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
241155 );
@@ -241338,19 +241798,18 @@
241338 pPhrase = pExpr->apExprPhrase[iPhrase];
241339 if( iToken<0 || iToken>=pPhrase->nTerm ){
241340 return SQLITE_RANGE;
241341 }
241342 pTerm = &pPhrase->aTerm[iToken];
241343 if( pTerm->bPrefix==0 ){
241344 if( pExpr->pConfig->bTokendata ){
241345 rc = sqlite3Fts5IterToken(
241346 pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
241347 );
241348 }else{
241349 *ppOut = pTerm->pTerm;
241350 *pnOut = pTerm->nFullTerm;
241351 }
241352 }
241353 return rc;
241354 }
241355
241356 /*
@@ -246847,10 +247306,15 @@
246847 if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
246848 iRet = ii;
246849 nBest = nPercent;
246850 }
246851 }
 
 
 
 
 
246852 }
246853 }
246854 return iRet;
246855 }
246856
@@ -248156,10 +248620,387 @@
248156 fts5BufferFree(&tmp);
248157 memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
248158 *p1 = out;
248159 }
248160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248161 static void fts5SetupPrefixIter(
248162 Fts5Index *p, /* Index to read from */
248163 int bDesc, /* True for "ORDER BY rowid DESC" */
248164 int iIdx, /* Index to scan for data */
248165 u8 *pToken, /* Buffer containing prefix to match */
@@ -248166,137 +249007,89 @@
248166 int nToken, /* Size of buffer pToken in bytes */
248167 Fts5Colset *pColset, /* Restrict matches to these columns */
248168 Fts5Iter **ppIter /* OUT: New iterator */
248169 ){
248170 Fts5Structure *pStruct;
248171 Fts5Buffer *aBuf;
248172 int nBuf = 32;
248173 int nMerge = 1;
248174
248175 void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
248176 void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
 
 
 
 
 
 
 
 
 
 
 
 
248177 if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
248178 xMerge = fts5MergeRowidLists;
248179 xAppend = fts5AppendRowid;
248180 }else{
248181 nMerge = FTS5_MERGE_NLIST-1;
248182 nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
248183 xMerge = fts5MergePrefixLists;
248184 xAppend = fts5AppendPoslist;
248185 }
248186
248187 aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
248188 pStruct = fts5StructureRead(p);
248189 assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
248190
248191 if( p->rc==SQLITE_OK ){
248192 const int flags = FTS5INDEX_QUERY_SCAN
248193 | FTS5INDEX_QUERY_SKIPEMPTY
248194 | FTS5INDEX_QUERY_NOOUTPUT;
248195 int i;
248196 i64 iLastRowid = 0;
248197 Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
248198 Fts5Data *pData;
248199 Fts5Buffer doclist;
248200 int bNewTerm = 1;
248201
248202 memset(&doclist, 0, sizeof(doclist));
248203
248204 /* If iIdx is non-zero, then it is the number of a prefix-index for
248205 ** prefixes 1 character longer than the prefix being queried for. That
248206 ** index contains all the doclists required, except for the one
248207 ** corresponding to the prefix itself. That one is extracted from the
248208 ** main term index here. */
248209 if( iIdx!=0 ){
248210 int dummy = 0;
248211 const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
248212 pToken[0] = FTS5_MAIN_PREFIX;
248213 fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
248214 fts5IterSetOutputCb(&p->rc, p1);
248215 for(;
248216 fts5MultiIterEof(p, p1)==0;
248217 fts5MultiIterNext2(p, p1, &dummy)
248218 ){
248219 Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
248220 p1->xSetOutputs(p1, pSeg);
248221 if( p1->base.nData ){
248222 xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
248223 iLastRowid = p1->base.iRowid;
248224 }
248225 }
248226 fts5MultiIterFree(p1);
248227 }
248228
248229 pToken[0] = FTS5_MAIN_PREFIX + iIdx;
248230 fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
248231 fts5IterSetOutputCb(&p->rc, p1);
248232
248233 for( /* no-op */ ;
248234 fts5MultiIterEof(p, p1)==0;
248235 fts5MultiIterNext2(p, p1, &bNewTerm)
248236 ){
248237 Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
248238 int nTerm = pSeg->term.n;
248239 const u8 *pTerm = pSeg->term.p;
248240 p1->xSetOutputs(p1, pSeg);
248241
248242 assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
248243 if( bNewTerm ){
248244 if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
248245 }
248246
248247 if( p1->base.nData==0 ) continue;
248248 if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
248249 for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
248250 int i1 = i*nMerge;
248251 int iStore;
248252 assert( i1+nMerge<=nBuf );
248253 for(iStore=i1; iStore<i1+nMerge; iStore++){
248254 if( aBuf[iStore].n==0 ){
248255 fts5BufferSwap(&doclist, &aBuf[iStore]);
248256 fts5BufferZero(&doclist);
248257 break;
248258 }
248259 }
248260 if( iStore==i1+nMerge ){
248261 xMerge(p, &doclist, nMerge, &aBuf[i1]);
248262 for(iStore=i1; iStore<i1+nMerge; iStore++){
248263 fts5BufferZero(&aBuf[iStore]);
248264 }
248265 }
248266 }
248267 iLastRowid = 0;
248268 }
248269
248270 xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
248271 iLastRowid = p1->base.iRowid;
248272 }
248273
248274 assert( (nBuf%nMerge)==0 );
248275 for(i=0; i<nBuf; i+=nMerge){
248276 int iFree;
248277 if( p->rc==SQLITE_OK ){
248278 xMerge(p, &doclist, nMerge, &aBuf[i]);
248279 }
248280 for(iFree=i; iFree<i+nMerge; iFree++){
248281 fts5BufferFree(&aBuf[iFree]);
248282 }
248283 }
248284 fts5MultiIterFree(p1);
248285
248286 pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
248287 if( pData ){
248288 pData->p = (u8*)&pData[1];
248289 pData->nn = pData->szLeaf = doclist.n;
248290 if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
248291 fts5MultiIterNew2(p, pData, bDesc, ppIter);
248292 }
248293 fts5BufferFree(&doclist);
 
 
 
 
 
248294 }
248295
 
 
248296 fts5StructureRelease(pStruct);
248297 sqlite3_free(aBuf);
248298 }
248299
248300
248301 /*
248302 ** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
@@ -248546,42 +249339,10 @@
248546 static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
248547 fts5DataRelease(pSeg->pLeaf);
248548 pSeg->pLeaf = 0;
248549 }
248550
248551 /*
248552 ** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
248553 ** array of these for each row it visits. Or, for an iterator used by an
248554 ** "ORDER BY rank" query, it accumulates an array of these for the entire
248555 ** query.
248556 **
248557 ** Each instance in the array indicates the iterator (and therefore term)
248558 ** associated with position iPos of rowid iRowid. This is used by the
248559 ** xInstToken() API.
248560 */
248561 struct Fts5TokenDataMap {
248562 i64 iRowid; /* Row this token is located in */
248563 i64 iPos; /* Position of token */
248564 int iIter; /* Iterator token was read from */
248565 };
248566
248567 /*
248568 ** An object used to supplement Fts5Iter for tokendata=1 iterators.
248569 */
248570 struct Fts5TokenDataIter {
248571 int nIter;
248572 int nIterAlloc;
248573
248574 int nMap;
248575 int nMapAlloc;
248576 Fts5TokenDataMap *aMap;
248577
248578 Fts5PoslistReader *aPoslistReader;
248579 int *aPoslistToIter;
248580 Fts5Iter *apIter[1];
248581 };
248582
248583 /*
248584 ** This function appends iterator pAppend to Fts5TokenDataIter pIn and
248585 ** returns the result.
248586 */
248587 static Fts5TokenDataIter *fts5AppendTokendataIter(
@@ -248614,58 +249375,10 @@
248614 assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
248615
248616 return pRet;
248617 }
248618
248619 /*
248620 ** Delete an Fts5TokenDataIter structure and its contents.
248621 */
248622 static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
248623 if( pSet ){
248624 int ii;
248625 for(ii=0; ii<pSet->nIter; ii++){
248626 fts5MultiIterFree(pSet->apIter[ii]);
248627 }
248628 sqlite3_free(pSet->aPoslistReader);
248629 sqlite3_free(pSet->aMap);
248630 sqlite3_free(pSet);
248631 }
248632 }
248633
248634 /*
248635 ** Append a mapping to the token-map belonging to object pT.
248636 */
248637 static void fts5TokendataIterAppendMap(
248638 Fts5Index *p,
248639 Fts5TokenDataIter *pT,
248640 int iIter,
248641 i64 iRowid,
248642 i64 iPos
248643 ){
248644 if( p->rc==SQLITE_OK ){
248645 if( pT->nMap==pT->nMapAlloc ){
248646 int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
248647 int nByte = nNew * sizeof(Fts5TokenDataMap);
248648 Fts5TokenDataMap *aNew;
248649
248650 aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte);
248651 if( aNew==0 ){
248652 p->rc = SQLITE_NOMEM;
248653 return;
248654 }
248655
248656 pT->aMap = aNew;
248657 pT->nMapAlloc = nNew;
248658 }
248659
248660 pT->aMap[pT->nMap].iRowid = iRowid;
248661 pT->aMap[pT->nMap].iPos = iPos;
248662 pT->aMap[pT->nMap].iIter = iIter;
248663 pT->nMap++;
248664 }
248665 }
248666
248667 /*
248668 ** The iterator passed as the only argument must be a tokendata=1 iterator
248669 ** (pIter->pTokenDataIter!=0). This function sets the iterator output
248670 ** variables (pIter->base.*) according to the contents of the current
248671 ** row.
@@ -248702,11 +249415,11 @@
248702 int eDetail = pIter->pIndex->pConfig->eDetail;
248703 pIter->base.bEof = 0;
248704 pIter->base.iRowid = iRowid;
248705
248706 if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
248707 fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
248708 }else
248709 if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
248710 int nReader = 0;
248711 int nByte = 0;
248712 i64 iPrev = 0;
@@ -248955,10 +249668,11 @@
248955
248956 if( p->rc==SQLITE_OK ){
248957 pRet = fts5MultiIterAlloc(p, 0);
248958 }
248959 if( pRet ){
 
248960 pRet->pTokenDataIter = pSet;
248961 if( pSet ){
248962 fts5IterSetOutputsTokendata(pRet);
248963 }else{
248964 pRet->base.bEof = 1;
@@ -248969,11 +249683,10 @@
248969
248970 fts5StructureRelease(pStruct);
248971 fts5BufferFree(&bSeek);
248972 return pRet;
248973 }
248974
248975
248976 /*
248977 ** Open a new iterator to iterate though all rowid that match the
248978 ** specified token or token prefix.
248979 */
@@ -248995,10 +249708,15 @@
248995 int iIdx = 0; /* Index to search */
248996 int iPrefixIdx = 0; /* +1 prefix index */
248997 int bTokendata = pConfig->bTokendata;
248998 if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
248999
 
 
 
 
 
249000 if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
249001 bTokendata = 0;
249002 }
249003
249004 /* Figure out which index to search and set iIdx accordingly. If this
@@ -249025,11 +249743,11 @@
249025 if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
249026 }
249027 }
249028
249029 if( bTokendata && iIdx==0 ){
249030 buf.p[0] = '0';
249031 pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
249032 }else if( iIdx<=pConfig->nPrefix ){
249033 /* Straight index lookup */
249034 Fts5Structure *pStruct = fts5StructureRead(p);
249035 buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -249038,11 +249756,11 @@
249038 pColset, buf.p, nToken+1, -1, 0, &pRet
249039 );
249040 fts5StructureRelease(pStruct);
249041 }
249042 }else{
249043 /* Scan multiple terms in the main index */
249044 int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
249045 fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
249046 if( pRet==0 ){
249047 assert( p->rc!=SQLITE_OK );
249048 }else{
@@ -249074,11 +249792,12 @@
249074 ** Move to the next matching rowid.
249075 */
249076 static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
249077 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249078 assert( pIter->pIndex->rc==SQLITE_OK );
249079 if( pIter->pTokenDataIter ){
 
249080 fts5TokendataIterNext(pIter, 0, 0);
249081 }else{
249082 fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
249083 }
249084 return fts5IndexReturn(pIter->pIndex);
@@ -249111,11 +249830,12 @@
249111 ** definition of "at or after" depends on whether this iterator iterates
249112 ** in ascending or descending rowid order.
249113 */
249114 static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
249115 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249116 if( pIter->pTokenDataIter ){
 
249117 fts5TokendataIterNext(pIter, 1, iMatch);
249118 }else{
249119 fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
249120 }
249121 return fts5IndexReturn(pIter->pIndex);
@@ -249129,32 +249849,87 @@
249129 const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
249130 assert_nc( z || n<=1 );
249131 *pn = n-1;
249132 return (z ? &z[1] : 0);
249133 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249134
249135 /*
249136 ** This is used by xInstToken() to access the token at offset iOff, column
249137 ** iCol of row iRowid. The token is returned via output variables *ppOut
249138 ** and *pnOut. The iterator passed as the first argument must be a tokendata=1
249139 ** iterator (pIter->pTokenDataIter!=0).
 
 
249140 */
249141 static int sqlite3Fts5IterToken(
249142 Fts5IndexIter *pIndexIter,
 
249143 i64 iRowid,
249144 int iCol,
249145 int iOff,
249146 const char **ppOut, int *pnOut
249147 ){
249148 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249149 Fts5TokenDataIter *pT = pIter->pTokenDataIter;
249150 Fts5TokenDataMap *aMap = pT->aMap;
249151 i64 iPos = (((i64)iCol)<<32) + iOff;
249152
249153 int i1 = 0;
249154 int i2 = pT->nMap;
249155 int iTest = 0;
 
 
 
 
 
 
 
 
 
 
249156
249157 while( i2>i1 ){
249158 iTest = (i1 + i2) / 2;
249159
249160 if( aMap[iTest].iRowid<iRowid ){
@@ -249174,13 +249949,19 @@
249174 }
249175 }
249176 }
249177
249178 if( i2>i1 ){
249179 Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
249180 *ppOut = (const char*)pMap->aSeg[0].term.p+1;
249181 *pnOut = pMap->aSeg[0].term.n-1;
 
 
 
 
 
 
249182 }
249183
249184 return SQLITE_OK;
249185 }
249186
@@ -249188,11 +249969,13 @@
249188 ** Clear any existing entries from the token-map associated with the
249189 ** iterator passed as the only argument.
249190 */
249191 static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
249192 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249193 if( pIter && pIter->pTokenDataIter ){
 
 
249194 pIter->pTokenDataIter->nMap = 0;
249195 }
249196 }
249197
249198 /*
@@ -249208,21 +249991,33 @@
249208 i64 iRowid, int iCol, int iOff
249209 ){
249210 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249211 Fts5TokenDataIter *pT = pIter->pTokenDataIter;
249212 Fts5Index *p = pIter->pIndex;
249213 int ii;
249214
249215 assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
249216 assert( pIter->pTokenDataIter );
249217
249218 for(ii=0; ii<pT->nIter; ii++){
249219 Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
249220 if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
249221 }
249222 if( ii<pT->nIter ){
249223 fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
 
 
 
 
 
 
 
 
 
 
 
 
249224 }
249225 return fts5IndexReturn(p);
249226 }
249227
249228 /*
@@ -250771,11 +251566,11 @@
250771 return rc;
250772 }
250773
250774 /*
250775 ** We must have a single struct=? constraint that will be passed through
250776 ** into the xFilter method. If there is no valid stmt=? constraint,
250777 ** then return an SQLITE_CONSTRAINT error.
250778 */
250779 static int fts5structBestIndexMethod(
250780 sqlite3_vtab *tab,
250781 sqlite3_index_info *pIdxInfo
@@ -251113,12 +251908,22 @@
251113 i64 iNextId; /* Used to allocate unique cursor ids */
251114 Fts5Auxiliary *pAux; /* First in list of all aux. functions */
251115 Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
251116 Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
251117 Fts5Cursor *pCsr; /* First in list of all open cursors */
 
251118 };
251119
 
 
 
 
 
 
 
 
 
251120 /*
251121 ** Each auxiliary function registered with the FTS5 module is represented
251122 ** by an object of the following type. All such objects are stored as part
251123 ** of the Fts5Global.pAux list.
251124 */
@@ -251277,16 +252082,10 @@
251277 #define FTS5CSR_REQUIRE_POSLIST 0x40
251278
251279 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
251280 #define BitFlagTest(x,y) (((x) & (y))!=0)
251281
251282 /*
251283 ** The subtype value and header bytes used by fts5_locale().
251284 */
251285 #define FTS5_LOCALE_SUBTYPE ((unsigned int)'L')
251286 #define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB"
251287
251288
251289 /*
251290 ** Macros to Set(), Clear() and Test() cursor flags.
251291 */
251292 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
@@ -251359,14 +252158,20 @@
251359 #else
251360 # define fts5CheckTransactionState(x,y,z)
251361 #endif
251362
251363 /*
251364 ** Return true if pTab is a contentless table.
 
 
251365 */
251366 static int fts5IsContentless(Fts5FullTable *pTab){
251367 return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
 
 
 
 
251368 }
251369
251370 /*
251371 ** Delete a virtual table handle allocated by fts5InitVtab().
251372 */
@@ -251653,10 +252458,11 @@
251653 ){
251654 /* A MATCH operator or equivalent */
251655 if( p->usable==0 || iCol<0 ){
251656 /* As there exists an unusable MATCH constraint this is an
251657 ** unusable plan. Return SQLITE_CONSTRAINT. */
 
251658 return SQLITE_CONSTRAINT;
251659 }else{
251660 if( iCol==nCol+1 ){
251661 if( bSeenRank ) continue;
251662 idxStr[iIdxStr++] = 'r';
@@ -252286,11 +253092,11 @@
252286 ** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
252287 ** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
252288 ** valid until after the final call to sqlite3Fts5Tokenize() that will use
252289 ** the locale.
252290 */
252291 static void fts5SetLocale(
252292 Fts5Config *pConfig,
252293 const char *zLocale,
252294 int nLocale
252295 ){
252296 Fts5TokenizerConfig *pT = &pConfig->t;
@@ -252297,141 +253103,88 @@
252297 pT->pLocale = zLocale;
252298 pT->nLocale = nLocale;
252299 }
252300
252301 /*
252302 ** Clear any locale configured by an earlier call to fts5SetLocale() or
252303 ** sqlite3Fts5ExtractText().
252304 */
252305 static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
252306 fts5SetLocale(pConfig, 0, 0);
252307 }
252308
252309 /*
252310 ** This function is used to extract utf-8 text from an sqlite3_value. This
252311 ** is usually done in order to tokenize it. For example, when:
252312 **
252313 ** * a value is written to an fts5 table,
252314 ** * a value is deleted from an FTS5_CONTENT_NORMAL table,
252315 ** * a value containing a query expression is passed to xFilter()
252316 **
252317 ** and so on.
252318 **
252319 ** This function handles 2 cases:
252320 **
252321 ** 1) Ordinary values. The text can be extracted from these using
252322 ** sqlite3_value_text().
252323 **
252324 ** 2) Combination text/locale blobs created by fts5_locale(). There
252325 ** are several cases for these:
252326 **
252327 ** * Blobs tagged with FTS5_LOCALE_SUBTYPE.
252328 ** * Blobs read from the content table of a locale=1 external-content
252329 ** table, and
252330 ** * Blobs read from the content table of a locale=1 regular
252331 ** content table.
252332 **
252333 ** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER
252334 ** header. It is an error if a blob with the subtype or a blob read
252335 ** from the content table of an external content table does not have
252336 ** the required header. A blob read from the content table of a regular
252337 ** locale=1 table does not have the header. This is to save space.
252338 **
252339 ** If successful, SQLITE_OK is returned and output parameters (*ppText)
252340 ** and (*pnText) are set to point to a buffer containing the extracted utf-8
252341 ** text and its length in bytes, respectively. The buffer is not
252342 ** nul-terminated. It has the same lifetime as the sqlite3_value object
252343 ** from which it is extracted.
252344 **
252345 ** Parameter bContent must be true if the value was read from an indexed
252346 ** column (i.e. not UNINDEXED) of the on disk content.
252347 **
252348 ** If pbResetTokenizer is not NULL and if case (2) is used, then
252349 ** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls
252350 ** use the locale. In this case (*pbResetTokenizer) is set to true before
252351 ** returning, to indicate that the caller must call sqlite3Fts5ClearLocale()
252352 ** to clear the locale after tokenizing the text.
252353 */
252354 static int sqlite3Fts5ExtractText(
252355 Fts5Config *pConfig,
252356 sqlite3_value *pVal, /* Value to extract text from */
252357 int bContent, /* True if indexed table content */
252358 int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */
252359 const char **ppText, /* OUT: Pointer to text buffer */
252360 int *pnText /* OUT: Size of (*ppText) in bytes */
252361 ){
252362 const char *pText = 0;
252363 int nText = 0;
252364 int rc = SQLITE_OK;
252365 int bDecodeBlob = 0;
252366
252367 assert( pbResetTokenizer==0 || *pbResetTokenizer==0 );
252368 assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE );
252369 assert( bContent==0 || sqlite3_value_subtype(pVal)==0 );
252370
252371 if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
252372 if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE
252373 || (bContent && pConfig->bLocale)
252374 ){
252375 bDecodeBlob = 1;
252376 }
252377 }
252378
252379 if( bDecodeBlob ){
252380 const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
252381 const u8 *pBlob = sqlite3_value_blob(pVal);
252382 int nBlob = sqlite3_value_bytes(pVal);
252383
252384 /* Unless this blob was read from the %_content table of an
252385 ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale()
252386 ** header. Check for this. If it is not found, return an error. */
252387 if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){
252388 if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
252389 rc = SQLITE_ERROR;
252390 }else{
252391 pBlob += 4;
252392 nBlob -= 4;
252393 }
252394 }
252395
252396 if( rc==SQLITE_OK ){
252397 int nLocale = 0;
252398
252399 for(nLocale=0; nLocale<nBlob; nLocale++){
252400 if( pBlob[nLocale]==0x00 ) break;
252401 }
252402 if( nLocale==nBlob || nLocale==0 ){
252403 rc = SQLITE_ERROR;
252404 }else{
252405 pText = (const char*)&pBlob[nLocale+1];
252406 nText = nBlob-nLocale-1;
252407
252408 if( pbResetTokenizer ){
252409 fts5SetLocale(pConfig, (const char*)pBlob, nLocale);
252410 *pbResetTokenizer = 1;
252411 }
252412 }
252413 }
252414
252415 }else{
252416 pText = (const char*)sqlite3_value_text(pVal);
252417 nText = sqlite3_value_bytes(pVal);
252418 }
252419
252420 *ppText = pText;
252421 *pnText = nText;
252422 return rc;
 
 
 
 
 
 
 
252423 }
252424
252425 /*
252426 ** Argument pVal is the text of a full-text search expression. It may or
252427 ** may not have been wrapped by fts5_locale(). This function extracts
252428 ** the text of the expression, and sets output variable (*pzText) to
252429 ** point to a nul-terminated buffer containing the expression.
252430 **
252431 ** If pVal was an fts5_locale() value, then fts5SetLocale() is called to
252432 ** set the tokenizer to use the specified locale.
252433 **
252434 ** If output variable (*pbFreeAndReset) is set to true, then the caller
252435 ** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
252436 ** locale, and (b) call sqlite3_free() to free (*pzText).
252437 */
@@ -252439,28 +253192,26 @@
252439 Fts5Config *pConfig, /* Fts5 configuration */
252440 sqlite3_value *pVal, /* Value to extract expression text from */
252441 char **pzText, /* OUT: nul-terminated buffer of text */
252442 int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
252443 ){
252444 const char *zText = 0;
252445 int nText = 0;
252446 int rc = SQLITE_OK;
252447 int bReset = 0;
252448
252449 *pbFreeAndReset = 0;
252450 rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, &bReset, &zText, &nText);
252451 if( rc==SQLITE_OK ){
252452 if( bReset ){
252453 *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, zText);
252454 if( rc!=SQLITE_OK ){
252455 sqlite3Fts5ClearLocale(pConfig);
252456 }else{
252457 *pbFreeAndReset = 1;
252458 }
252459 }else{
252460 *pzText = (char*)zText;
252461 }
252462 }
252463
252464 return rc;
252465 }
252466
@@ -252493,10 +253244,11 @@
252493 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
252494 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
252495 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
252496 int iCol; /* Column on LHS of MATCH operator */
252497 char **pzErrmsg = pConfig->pzErrmsg;
 
252498 int i;
252499 int iIdxStr = 0;
252500 Fts5Expr *pExpr = 0;
252501
252502 assert( pConfig->bLock==0 );
@@ -252528,10 +253280,13 @@
252528 int bInternal = 0;
252529
252530 rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
252531 if( rc!=SQLITE_OK ) goto filter_out;
252532 if( zText==0 ) zText = "";
 
 
 
252533
252534 iCol = 0;
252535 do{
252536 iCol = iCol*10 + (idxStr[iIdxStr]-'0');
252537 iIdxStr++;
@@ -252668,10 +253423,11 @@
252668 }
252669
252670 filter_out:
252671 sqlite3Fts5ExprFree(pExpr);
252672 pConfig->pzErrmsg = pzErrmsg;
 
252673 return rc;
252674 }
252675
252676 /*
252677 ** This is the xEof method of the virtual table. SQLite calls this
@@ -252808,11 +253564,11 @@
252808 }else{
252809 rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
252810 }
252811 bLoadConfig = 1;
252812 }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
252813 if( pConfig->eContent==FTS5_CONTENT_NONE ){
252814 fts5SetVtabError(pTab,
252815 "'rebuild' may not be used with a contentless fts5 table"
252816 );
252817 rc = SQLITE_ERROR;
252818 }else{
@@ -252877,17 +253633,78 @@
252877 sqlite3_value **apVal,
252878 i64 *piRowid
252879 ){
252880 int rc = *pRc;
252881 if( rc==SQLITE_OK ){
252882 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
252883 }
252884 if( rc==SQLITE_OK ){
252885 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
252886 }
252887 *pRc = rc;
252888 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252889
252890 /*
252891 ** This function is the implementation of the xUpdate callback used by
252892 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
252893 ** inserted, updated or deleted.
@@ -252971,48 +253788,38 @@
252971 }
252972
252973 assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
252974 assert( nArg!=1 || eType0==SQLITE_INTEGER );
252975
252976 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
252977 ** This is not suported. Except - they are both supported if the CREATE
252978 ** VIRTUAL TABLE statement contained "contentless_delete=1". */
252979 if( eType0==SQLITE_INTEGER
252980 && pConfig->eContent==FTS5_CONTENT_NONE
252981 && pConfig->bContentlessDelete==0
252982 ){
252983 pTab->p.base.zErrMsg = sqlite3_mprintf(
252984 "cannot %s contentless fts5 table: %s",
252985 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
252986 );
252987 rc = SQLITE_ERROR;
252988 }
252989
252990 /* DELETE */
252991 else if( nArg==1 ){
252992 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
252993 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
252994 bUpdateOrDelete = 1;
 
 
 
 
 
 
 
 
 
252995 }
252996
252997 /* INSERT or UPDATE */
252998 else{
252999 int eType1 = sqlite3_value_numeric_type(apVal[1]);
253000
253001 /* Ensure that no fts5_locale() values are written to locale=0 tables.
253002 ** And that no blobs except fts5_locale() blobs are written to indexed
253003 ** (i.e. not UNINDEXED) columns of locale=1 tables. */
253004 int ii;
253005 for(ii=0; ii<pConfig->nCol; ii++){
253006 if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){
253007 int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE);
253008 if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0)
253009 || (pConfig->bLocale==0 && bSub)
253010 ){
253011 if( pConfig->bLocale==0 ){
253012 fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
253013 }
253014 rc = SQLITE_MISMATCH;
253015 goto update_out;
253016 }
253017 }
253018 }
@@ -253028,39 +253835,59 @@
253028 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253029 }
253030
253031 /* UPDATE */
253032 else{
253033 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
253034 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
253035 if( eType1!=SQLITE_INTEGER ){
253036 rc = SQLITE_MISMATCH;
253037 }else if( iOld!=iNew ){
253038 if( eConflict==SQLITE_REPLACE ){
253039 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253040 if( rc==SQLITE_OK ){
253041 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
253042 }
253043 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253044 }else{
253045 rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld);
253046 if( rc==SQLITE_OK ){
253047 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid);
253048 }
253049 if( rc==SQLITE_OK ){
253050 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253051 }
253052 if( rc==SQLITE_OK ){
253053 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
253054 }
253055 }
253056 }else{
253057 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253058 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253059 }
253060 bUpdateOrDelete = 1;
253061 sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253062 }
253063
253064 }
253065 }
253066
@@ -253169,15 +253996,15 @@
253169 ){
253170 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253171 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253172 int rc = SQLITE_OK;
253173
253174 fts5SetLocale(pTab->pConfig, pLoc, nLoc);
253175 rc = sqlite3Fts5Tokenize(pTab->pConfig,
253176 FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
253177 );
253178 fts5SetLocale(pTab->pConfig, 0, 0);
253179
253180 return rc;
253181 }
253182
253183 /*
@@ -253200,10 +254027,53 @@
253200
253201 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
253202 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253203 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
253204 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253205
253206 static int fts5ApiColumnText(
253207 Fts5Context *pCtx,
253208 int iCol,
253209 const char **pz,
@@ -253214,20 +254084,18 @@
253214 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253215
253216 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253217 if( iCol<0 || iCol>=pTab->pConfig->nCol ){
253218 rc = SQLITE_RANGE;
253219 }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){
253220 *pz = 0;
253221 *pn = 0;
253222 }else{
253223 rc = fts5SeekCursor(pCsr, 0);
253224 if( rc==SQLITE_OK ){
253225 Fts5Config *pConfig = pTab->pConfig;
253226 int bContent = (pConfig->abUnindexed[iCol]==0);
253227 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253228 sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn);
253229 }
253230 }
253231 return rc;
253232 }
253233
@@ -253249,11 +254117,11 @@
253249 int bLive = (pCsr->pSorter==0);
253250
253251 if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
253252 rc = SQLITE_RANGE;
253253 }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
253254 && pConfig->eContent==FTS5_CONTENT_NONE
253255 ){
253256 *pa = 0;
253257 *pn = 0;
253258 return SQLITE_OK;
253259 }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
@@ -253265,21 +254133,19 @@
253265 if( aPopulator==0 ) rc = SQLITE_NOMEM;
253266 if( rc==SQLITE_OK ){
253267 rc = fts5SeekCursor(pCsr, 0);
253268 }
253269 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
253270 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253271 const char *z = 0;
253272 int n = 0;
253273 int bReset = 0;
253274 rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
253275 if( rc==SQLITE_OK ){
253276 rc = sqlite3Fts5ExprPopulatePoslists(
253277 pConfig, pCsr->pExpr, aPopulator, i, z, n
253278 );
253279 }
253280 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
253281 }
253282 sqlite3_free(aPopulator);
253283
253284 if( pCsr->pSorter ){
253285 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
@@ -253447,11 +254313,11 @@
253447
253448 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
253449 if( pConfig->bColumnsize ){
253450 i64 iRowid = fts5CursorRowid(pCsr);
253451 rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
253452 }else if( pConfig->zContent==0 ){
253453 int i;
253454 for(i=0; i<pConfig->nCol; i++){
253455 if( pConfig->abUnindexed[i]==0 ){
253456 pCsr->aColumnSize[i] = -1;
253457 }
@@ -253461,21 +254327,18 @@
253461 rc = fts5SeekCursor(pCsr, 0);
253462 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
253463 if( pConfig->abUnindexed[i]==0 ){
253464 const char *z = 0;
253465 int n = 0;
253466 int bReset = 0;
253467 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253468
253469 pCsr->aColumnSize[i] = 0;
253470 rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
253471 if( rc==SQLITE_OK ){
253472 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
253473 z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
253474 );
253475 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
253476 }
 
253477 }
253478 }
253479 }
253480 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
253481 }
@@ -253738,46 +254601,23 @@
253738 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253739 if( iCol<0 || iCol>=pConfig->nCol ){
253740 rc = SQLITE_RANGE;
253741 }else if(
253742 pConfig->abUnindexed[iCol]==0
253743 && pConfig->eContent!=FTS5_CONTENT_NONE
253744 && pConfig->bLocale
253745 ){
253746 rc = fts5SeekCursor(pCsr, 0);
253747 if( rc==SQLITE_OK ){
253748 /* Load the value into pVal. pVal is a locale/text pair iff:
253749 **
253750 ** 1) It is an SQLITE_BLOB, and
253751 ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the
253752 ** value was loaded from an FTS5_CONTENT_NORMAL table, and
253753 ** 3) It does not begin with an 0x00 byte.
253754 */
253755 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253756 if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
253757 const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
253758 int nBlob = sqlite3_value_bytes(pVal);
253759 if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
253760 const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
253761 if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
253762 rc = SQLITE_ERROR;
253763 }
253764 pBlob += 4;
253765 nBlob -= 4;
253766 }
253767 if( rc==SQLITE_OK ){
253768 int nLocale = 0;
253769 for(nLocale=0; nLocale<nBlob && pBlob[nLocale]!=0x00; nLocale++);
253770 if( nLocale==nBlob || nLocale==0 ){
253771 rc = SQLITE_ERROR;
253772 }else{
253773 /* A locale/text pair */
253774 *pzLocale = (const char*)pBlob;
253775 *pnLocale = nLocale;
253776 }
253777 }
253778 }
253779 }
253780 }
253781
253782 return rc;
253783 }
@@ -253994,61 +254834,10 @@
253994
253995 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
253996 return rc;
253997 }
253998
253999 /*
254000 ** Value pVal was read from column iCol of the FTS5 table. This function
254001 ** returns it to the owner of pCtx via a call to an sqlite3_result_xxx()
254002 ** function. This function deals with the same cases as
254003 ** sqlite3Fts5ExtractText():
254004 **
254005 ** 1) Ordinary values. These can be returned using sqlite3_result_value().
254006 **
254007 ** 2) Blobs from fts5_locale(). The text is extracted from these and
254008 ** returned via sqlite3_result_text(). The locale is discarded.
254009 */
254010 static void fts5ExtractValueFromColumn(
254011 sqlite3_context *pCtx,
254012 Fts5Config *pConfig,
254013 int iCol,
254014 sqlite3_value *pVal
254015 ){
254016 assert( pConfig->eContent!=FTS5_CONTENT_NONE );
254017
254018 if( pConfig->bLocale
254019 && sqlite3_value_type(pVal)==SQLITE_BLOB
254020 && pConfig->abUnindexed[iCol]==0
254021 ){
254022 const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
254023 const u8 *pBlob = sqlite3_value_blob(pVal);
254024 int nBlob = sqlite3_value_bytes(pVal);
254025 int ii;
254026
254027 if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
254028 if( nBlob<SZHDR || memcmp(pBlob, FTS5_LOCALE_HEADER, SZHDR) ){
254029 sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254030 return;
254031 }else{
254032 pBlob += 4;
254033 nBlob -= 4;
254034 }
254035 }
254036
254037 for(ii=0; ii<nBlob && pBlob[ii]; ii++);
254038 if( ii==0 || ii==nBlob ){
254039 sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254040 }else{
254041 const char *pText = (const char*)&pBlob[ii+1];
254042 sqlite3_result_text(pCtx, pText, nBlob-ii-1, SQLITE_TRANSIENT);
254043 }
254044 return;
254045 }
254046
254047 sqlite3_result_value(pCtx, pVal);
254048 }
254049
254050 /*
254051 ** This is the xColumn method, called by SQLite to request a value from
254052 ** the row that the supplied cursor currently points to.
254053 */
254054 static int fts5ColumnMethod(
@@ -254087,26 +254876,31 @@
254087 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
254088 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
254089 }
254090 }
254091 }else{
254092 /* A column created by the user containing values. */
254093 int bNochange = sqlite3_vtab_nochange(pCtx);
254094
254095 if( fts5IsContentless(pTab) ){
254096 if( bNochange && pConfig->bContentlessDelete ){
254097 fts5ResultError(pCtx, "cannot UPDATE a subset of "
254098 "columns on fts5 contentless-delete table: %s", pConfig->zName
254099 );
254100 }
254101 }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){
254102 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
254103 rc = fts5SeekCursor(pCsr, 1);
254104 if( rc==SQLITE_OK ){
254105 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
254106 fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal);
 
 
 
 
 
 
 
 
 
 
 
 
 
254107 }
 
254108 pConfig->pzErrmsg = 0;
254109 }
254110 }
254111
254112 return rc;
@@ -254625,11 +255419,11 @@
254625 int nArg, /* Number of args */
254626 sqlite3_value **apUnused /* Function arguments */
254627 ){
254628 assert( nArg==0 );
254629 UNUSED_PARAM2(nArg, apUnused);
254630 sqlite3_result_text(pCtx, "fts5: 2024-09-02 18:41:59 e6bec37ea1ca51e1d048941ce4c5211d8fc5c5e3556a1441f9c79b036843f9e3", -1, SQLITE_TRANSIENT);
254631 }
254632
254633 /*
254634 ** Implementation of fts5_locale(LOCALE, TEXT) function.
254635 **
@@ -254664,36 +255458,48 @@
254664 nText = sqlite3_value_bytes(apArg[1]);
254665
254666 if( zLocale==0 || zLocale[0]=='\0' ){
254667 sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
254668 }else{
 
254669 u8 *pBlob = 0;
254670 u8 *pCsr = 0;
254671 int nBlob = 0;
254672 const int nHdr = 4;
254673 assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 );
254674
254675 nBlob = nHdr + nLocale + 1 + nText;
254676 pBlob = (u8*)sqlite3_malloc(nBlob);
254677 if( pBlob==0 ){
254678 sqlite3_result_error_nomem(pCtx);
254679 return;
254680 }
254681
254682 pCsr = pBlob;
254683 memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr);
254684 pCsr += nHdr;
254685 memcpy(pCsr, zLocale, nLocale);
254686 pCsr += nLocale;
254687 (*pCsr++) = 0x00;
254688 if( zText ) memcpy(pCsr, zText, nText);
254689 assert( &pCsr[nText]==&pBlob[nBlob] );
254690
254691 sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
254692 sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE);
254693 }
254694 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254695
254696 /*
254697 ** Return true if zName is the extension on one of the shadow tables used
254698 ** by this module.
254699 */
@@ -254789,10 +255595,20 @@
254789 pGlobal->api.xCreateFunction = fts5CreateAux;
254790 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
254791 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
254792 pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
254793 pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
 
 
 
 
 
 
 
 
 
 
254794 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
254795 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
254796 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
254797 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
254798 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
@@ -254810,13 +255626,20 @@
254810 );
254811 }
254812 if( rc==SQLITE_OK ){
254813 rc = sqlite3_create_function(
254814 db, "fts5_locale", 2,
254815 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
254816 p, fts5LocaleFunc, 0, 0
254817 );
 
 
 
 
 
 
 
254818 }
254819 }
254820
254821 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
254822 ** fts5_test_mi.c is compiled and linked into the executable. And call
@@ -255015,24 +255838,39 @@
255015 );
255016 break;
255017
255018 case FTS5_STMT_INSERT_CONTENT:
255019 case FTS5_STMT_REPLACE_CONTENT: {
255020 int nCol = pC->nCol + 1;
255021 char *zBind;
255022 int i;
255023
255024 zBind = sqlite3_malloc64(1 + nCol*2);
255025 if( zBind ){
255026 for(i=0; i<nCol; i++){
255027 zBind[i*2] = '?';
255028 zBind[i*2 + 1] = ',';
255029 }
255030 zBind[i*2-1] = '\0';
255031 zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
255032 sqlite3_free(zBind);
255033 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255034 break;
255035 }
255036
255037 case FTS5_STMT_REPLACE_DOCSIZE:
255038 zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
@@ -255214,23 +256052,37 @@
255214 p->aTotalSize = (i64*)&p[1];
255215 p->pConfig = pConfig;
255216 p->pIndex = pIndex;
255217
255218 if( bCreate ){
255219 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
 
 
255220 int nDefn = 32 + pConfig->nCol*10;
255221 char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
255222 if( zDefn==0 ){
255223 rc = SQLITE_NOMEM;
255224 }else{
255225 int i;
255226 int iOff;
255227 sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
255228 iOff = (int)strlen(zDefn);
255229 for(i=0; i<pConfig->nCol; i++){
255230 sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
255231 iOff += (int)strlen(&zDefn[iOff]);
 
 
 
 
 
 
 
 
 
 
 
 
255232 }
255233 rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
255234 }
255235 sqlite3_free(zDefn);
255236 }
@@ -255379,33 +256231,43 @@
255379 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
255380 if( pConfig->abUnindexed[iCol-1]==0 ){
255381 sqlite3_value *pVal = 0;
255382 const char *pText = 0;
255383 int nText = 0;
255384 int bReset = 0;
 
255385
255386 assert( pSeek==0 || apVal==0 );
255387 assert( pSeek!=0 || apVal!=0 );
255388 if( pSeek ){
255389 pVal = sqlite3_column_value(pSeek, iCol);
255390 }else{
255391 pVal = apVal[iCol-1];
255392 }
255393
255394 rc = sqlite3Fts5ExtractText(
255395 pConfig, pVal, pSeek!=0, &bReset, &pText, &nText
255396 );
 
 
 
 
 
 
 
 
255397 if( rc==SQLITE_OK ){
 
255398 ctx.szCol = 0;
255399 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
255400 pText, nText, (void*)&ctx, fts5StorageInsertCallback
255401 );
255402 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
255403 if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
255404 rc = FTS5_CORRUPT;
255405 }
255406 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255407 }
255408 }
255409 }
255410 if( rc==SQLITE_OK && p->nTotalRow<1 ){
255411 rc = FTS5_CORRUPT;
@@ -255446,11 +256308,13 @@
255446 i64 iOrigin = 0;
255447 sqlite3_stmt *pLookup = 0;
255448 int rc = SQLITE_OK;
255449
255450 assert( p->pConfig->bContentlessDelete );
255451 assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
 
 
255452
255453 /* Look up the origin of the document in the %_docsize table. Store
255454 ** this in stack variable iOrigin. */
255455 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
255456 if( rc==SQLITE_OK ){
@@ -255570,10 +256434,16 @@
255570 }
255571
255572 if( rc==SQLITE_OK ){
255573 if( p->pConfig->bContentlessDelete ){
255574 rc = fts5StorageContentlessDelete(p, iDel);
 
 
 
 
 
 
255575 }else{
255576 rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
255577 }
255578 }
255579
@@ -255586,11 +256456,13 @@
255586 rc = sqlite3_reset(pDel);
255587 }
255588 }
255589
255590 /* Delete the %_content record */
255591 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
 
 
255592 if( rc==SQLITE_OK ){
255593 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
255594 }
255595 if( rc==SQLITE_OK ){
255596 sqlite3_bind_int64(pDel, 1, iDel);
@@ -255618,12 +256490,17 @@
255618 pConfig->zDb, pConfig->zName,
255619 pConfig->zDb, pConfig->zName
255620 );
255621 if( rc==SQLITE_OK && pConfig->bColumnsize ){
255622 rc = fts5ExecPrintf(pConfig->db, 0,
255623 "DELETE FROM %Q.'%q_docsize';",
255624 pConfig->zDb, pConfig->zName
 
 
 
 
 
255625 );
255626 }
255627
255628 /* Reinitialize the %_data table. This call creates the initial structure
255629 ** and averages records. */
@@ -255660,24 +256537,39 @@
255660 sqlite3Fts5BufferZero(&buf);
255661 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
255662 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
255663 ctx.szCol = 0;
255664 if( pConfig->abUnindexed[ctx.iCol]==0 ){
255665 int bReset = 0; /* True if tokenizer locale must be reset */
255666 int nText = 0; /* Size of pText in bytes */
255667 const char *pText = 0; /* Pointer to buffer containing text value */
 
 
 
255668 sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
 
 
 
 
 
 
 
 
 
 
 
 
 
255669
255670 rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText);
255671 if( rc==SQLITE_OK ){
 
255672 rc = sqlite3Fts5Tokenize(pConfig,
255673 FTS5_TOKENIZE_DOCUMENT,
255674 pText, nText,
255675 (void*)&ctx,
255676 fts5StorageInsertCallback
255677 );
255678 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255679 }
255680 }
255681 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
255682 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
255683 }
@@ -255740,53 +256632,75 @@
255740 /*
255741 ** Insert a new row into the FTS content table.
255742 */
255743 static int sqlite3Fts5StorageContentInsert(
255744 Fts5Storage *p,
 
255745 sqlite3_value **apVal,
255746 i64 *piRowid
255747 ){
255748 Fts5Config *pConfig = p->pConfig;
255749 int rc = SQLITE_OK;
255750
255751 /* Insert the new row into the %_content table. */
255752 if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
 
 
255753 if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
255754 *piRowid = sqlite3_value_int64(apVal[1]);
255755 }else{
255756 rc = fts5StorageNewRowid(p, piRowid);
255757 }
255758 }else{
255759 sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
255760 int i; /* Counter variable */
255761 rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
255762 for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
255763 sqlite3_value *pVal = apVal[i];
255764 if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
255765 /* This is an UPDATE statement, and column (i-2) was not modified.
255766 ** Retrieve the value from Fts5Storage.pSavedRow instead. */
255767 pVal = sqlite3_column_value(p->pSavedRow, i-1);
255768 }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){
255769 assert( pConfig->bLocale );
255770 assert( i>1 );
255771 if( pConfig->abUnindexed[i-2] ){
255772 /* At attempt to insert an fts5_locale() value into an UNINDEXED
255773 ** column. Strip the locale away and just bind the text. */
 
 
 
 
 
 
 
 
 
 
 
 
 
255774 const char *pText = 0;
 
255775 int nText = 0;
255776 rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText);
255777 sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
255778 }else{
255779 const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
255780 int nBlob = sqlite3_value_bytes(pVal);
255781 assert( nBlob>4 );
255782 sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT);
255783 }
255784 continue;
255785 }
255786
255787 rc = sqlite3_bind_value(pInsert, i, pVal);
 
 
 
 
 
255788 }
255789 if( rc==SQLITE_OK ){
255790 sqlite3_step(pInsert);
255791 rc = sqlite3_reset(pInsert);
255792 }
@@ -255817,27 +256731,41 @@
255817 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
255818 }
255819 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
255820 ctx.szCol = 0;
255821 if( pConfig->abUnindexed[ctx.iCol]==0 ){
255822 int bReset = 0; /* True if tokenizer locale must be reset */
255823 int nText = 0; /* Size of pText in bytes */
255824 const char *pText = 0; /* Pointer to buffer containing text value */
 
 
 
255825 sqlite3_value *pVal = apVal[ctx.iCol+2];
255826 int bDisk = 0;
255827 if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
255828 pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
255829 bDisk = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
255830 }
255831 rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText);
255832 if( rc==SQLITE_OK ){
255833 assert( bReset==0 || pConfig->bLocale );
255834 rc = sqlite3Fts5Tokenize(pConfig,
255835 FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
255836 fts5StorageInsertCallback
255837 );
255838 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255839 }
255840 }
255841 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
255842 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
255843 }
@@ -255998,41 +256926,65 @@
255998 }
255999 if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
256000 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256001 }
256002 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
256003 if( pConfig->abUnindexed[i] ) continue;
256004 ctx.iCol = i;
256005 ctx.szCol = 0;
256006 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256007 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256008 }
256009 if( rc==SQLITE_OK ){
256010 int bReset = 0; /* True if tokenizer locale must be reset */
256011 int nText = 0; /* Size of pText in bytes */
256012 const char *pText = 0; /* Pointer to buffer containing text value */
256013
256014 rc = sqlite3Fts5ExtractText(pConfig,
256015 sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText
256016 );
256017 if( rc==SQLITE_OK ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256018 rc = sqlite3Fts5Tokenize(pConfig,
256019 FTS5_TOKENIZE_DOCUMENT,
256020 pText, nText,
256021 (void*)&ctx,
256022 fts5StorageIntegrityCallback
256023 );
256024 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256025 }
256026 }
256027 if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
256028 rc = FTS5_CORRUPT;
256029 }
256030 aTotalSize[i] += ctx.szCol;
256031 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256032 sqlite3Fts5TermsetFree(ctx.pTermset);
256033 ctx.pTermset = 0;
 
 
 
 
 
 
 
256034 }
256035 }
256036 sqlite3Fts5TermsetFree(ctx.pTermset);
256037 ctx.pTermset = 0;
256038
@@ -256454,11 +257406,11 @@
256454
256455 #define READ_UTF8(zIn, zTerm, c) \
256456 c = *(zIn++); \
256457 if( c>=0xc0 ){ \
256458 c = sqlite3Utf8Trans1[c-0xc0]; \
256459 while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
256460 c = (c<<6) + (0x3f & *(zIn++)); \
256461 } \
256462 if( c<0x80 \
256463 || (c&0xFFFFF800)==0xD800 \
256464 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
@@ -257609,22 +258561,22 @@
257609 int rc = SQLITE_OK;
257610 char aBuf[32];
257611 char *zOut = aBuf;
257612 int ii;
257613 const unsigned char *zIn = (const unsigned char*)pText;
257614 const unsigned char *zEof = &zIn[nText];
257615 u32 iCode;
257616 int aStart[3]; /* Input offset of each character in aBuf[] */
257617
257618 UNUSED_PARAM(unusedFlags);
257619
257620 /* Populate aBuf[] with the characters for the first trigram. */
257621 for(ii=0; ii<3; ii++){
257622 do {
257623 aStart[ii] = zIn - (const unsigned char*)pText;
 
257624 READ_UTF8(zIn, zEof, iCode);
257625 if( iCode==0 ) return SQLITE_OK;
257626 if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
257627 }while( iCode==0 );
257628 WRITE_UTF8(zOut, iCode);
257629 }
257630
@@ -257641,12 +258593,15 @@
257641 const char *z1;
257642
257643 /* Read characters from the input up until the first non-diacritic */
257644 do {
257645 iNext = zIn - (const unsigned char*)pText;
 
 
 
 
257646 READ_UTF8(zIn, zEof, iCode);
257647 if( iCode==0 ) break;
257648 if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
257649 }while( iCode==0 );
257650
257651 /* Pass the current trigram back to fts5 */
257652 rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
@@ -259679,11 +260634,11 @@
259679
259680 return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
259681 }
259682
259683
259684
259685 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
259686
259687 /************** End of fts5.c ************************************************/
259688 /************** Begin file stmt.c ********************************************/
259689 /*
@@ -260035,6 +260990,7 @@
260035 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
260036
260037 /************** End of stmt.c ************************************************/
260038 /* Return the source-id for this library */
260039 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
 
260040 /************************** End of sqlite3.c ******************************/
260041
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.48.0. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -16,12 +16,15 @@
16 ** if you want a wrapper to interface SQLite with your choice of programming
17 ** language. The code for the "sqlite3" command-line shell is also in a
18 ** separate file. This file contains only code for the core SQLite library.
19 **
20 ** The content in this amalgamation comes from Fossil check-in
21 ** e2bae4143afd07de1ae55a6d2606a3b541a5 with changes in files:
22 **
23 **
24 */
25 #ifndef SQLITE_AMALGAMATION
26 #define SQLITE_CORE 1
27 #define SQLITE_AMALGAMATION 1
28 #ifndef SQLITE_PRIVATE
29 # define SQLITE_PRIVATE static
30 #endif
@@ -460,13 +463,13 @@
463 **
464 ** See also: [sqlite3_libversion()],
465 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
466 ** [sqlite_version()] and [sqlite_source_id()].
467 */
468 #define SQLITE_VERSION "3.48.0"
469 #define SQLITE_VERSION_NUMBER 3048000
470 #define SQLITE_SOURCE_ID "2024-12-09 20:46:36 e2bae4143afd07de1ae55a6d2606a3b541a5b94568aa41f6a96e5d1245471653"
471
472 /*
473 ** CAPI3REF: Run-Time Library Version Numbers
474 ** KEYWORDS: sqlite3_version sqlite3_sourceid
475 **
@@ -966,10 +969,17 @@
969 **
970 ** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
971 ** filesystem supports doing multiple write operations atomically when those
972 ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
973 ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
974 **
975 ** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
976 ** from the database file in amounts that are not a multiple of the
977 ** page size and that do not begin at a page boundary. Without this
978 ** property, SQLite is careful to only do full-page reads and write
979 ** on aligned pages, with the one exception that it will do a sub-page
980 ** read of the first page to access the database header.
981 */
982 #define SQLITE_IOCAP_ATOMIC 0x00000001
983 #define SQLITE_IOCAP_ATOMIC512 0x00000002
984 #define SQLITE_IOCAP_ATOMIC1K 0x00000004
985 #define SQLITE_IOCAP_ATOMIC2K 0x00000008
@@ -982,10 +992,11 @@
992 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400
993 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
994 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
995 #define SQLITE_IOCAP_IMMUTABLE 0x00002000
996 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
997 #define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
998
999 /*
1000 ** CAPI3REF: File Locking Levels
1001 **
1002 ** SQLite uses one of these integer values as the second
@@ -1128,10 +1139,11 @@
1139 ** <li> [SQLITE_IOCAP_SEQUENTIAL]
1140 ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
1141 ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
1142 ** <li> [SQLITE_IOCAP_IMMUTABLE]
1143 ** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
1144 ** <li> [SQLITE_IOCAP_SUBPAGE_READ]
1145 ** </ul>
1146 **
1147 ** The SQLITE_IOCAP_ATOMIC property means that all writes of
1148 ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
1149 ** mean that writes of blocks that are nnn bytes in size and
@@ -1405,10 +1417,15 @@
1417 ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
1418 ** opcode causes the xFileControl method to swap the file handle with the one
1419 ** pointed to by the pArg argument. This capability is used during testing
1420 ** and only needs to be supported when SQLITE_TEST is defined.
1421 **
1422 ** <li>[[SQLITE_FCNTL_NULL_IO]]
1423 ** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
1424 ** or file handle for the [sqlite3_file] object such that it will no longer
1425 ** read or write to the database file.
1426 **
1427 ** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
1428 ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
1429 ** be advantageous to block on the next WAL lock if the lock is not immediately
1430 ** available. The WAL subsystem issues this signal during rare
1431 ** circumstances in order to fix a problem with priority inversion.
@@ -1558,10 +1575,11 @@
1575 #define SQLITE_FCNTL_RESERVE_BYTES 38
1576 #define SQLITE_FCNTL_CKPT_START 39
1577 #define SQLITE_FCNTL_EXTERNAL_READER 40
1578 #define SQLITE_FCNTL_CKSM_FILE 41
1579 #define SQLITE_FCNTL_RESET_CACHE 42
1580 #define SQLITE_FCNTL_NULL_IO 43
1581
1582 /* deprecated names */
1583 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1584 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1585 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2936,14 +2954,18 @@
2954 **
2955 ** ^These functions return the number of rows modified, inserted or
2956 ** deleted by the most recently completed INSERT, UPDATE or DELETE
2957 ** statement on the database connection specified by the only parameter.
2958 ** The two functions are identical except for the type of the return value
2959 ** and that if the number of rows modified by the most recent INSERT, UPDATE,
2960 ** or DELETE is greater than the maximum value supported by type "int", then
2961 ** the return value of sqlite3_changes() is undefined. ^Executing any other
2962 ** type of SQL statement does not modify the value returned by these functions.
2963 ** For the purposes of this interface, a CREATE TABLE AS SELECT statement
2964 ** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
2965 ** added to the new table by the CREATE TABLE AS SELECT statement are not
2966 ** counted.
2967 **
2968 ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
2969 ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
2970 ** [foreign key actions] or [REPLACE] constraint resolution are not counted.
2971 **
@@ -4499,15 +4521,26 @@
4521 **
4522 ** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
4523 ** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
4524 ** to return an error (error code SQLITE_ERROR) if the statement uses
4525 ** any virtual tables.
4526 **
4527 ** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
4528 ** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
4529 ** errors from being sent to the error log defined by
4530 ** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
4531 ** compiles to see if some SQL syntax is well-formed, without generating
4532 ** messages on the global error log when it is not. If the test compile
4533 ** fails, the sqlite3_prepare_v3() call returns the same error indications
4534 ** with or without this flag; it just omits the call to [sqlite3_log()] that
4535 ** logs the error.
4536 ** </dl>
4537 */
4538 #define SQLITE_PREPARE_PERSISTENT 0x01
4539 #define SQLITE_PREPARE_NORMALIZE 0x02
4540 #define SQLITE_PREPARE_NO_VTAB 0x04
4541 #define SQLITE_PREPARE_DONT_LOG 0x10
4542
4543 /*
4544 ** CAPI3REF: Compiling An SQL Statement
4545 ** KEYWORDS: {SQL statement compiler}
4546 ** METHOD: sqlite3
@@ -4536,17 +4569,21 @@
4569 ** and sqlite3_prepare_v3()
4570 ** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
4571 ** and sqlite3_prepare16_v3() use UTF-16.
4572 **
4573 ** ^If the nByte argument is negative, then zSql is read up to the
4574 ** first zero terminator. ^If nByte is positive, then it is the maximum
4575 ** number of bytes read from zSql. When nByte is positive, zSql is read
4576 ** up to the first zero terminator or until the nByte bytes have been read,
4577 ** whichever comes first. ^If nByte is zero, then no prepared
4578 ** statement is generated.
4579 ** If the caller knows that the supplied string is nul-terminated, then
4580 ** there is a small performance advantage to passing an nByte parameter that
4581 ** is the number of bytes in the input string <i>including</i>
4582 ** the nul-terminator.
4583 ** Note that nByte measure the length of the input in bytes, not
4584 ** characters, even for the UTF-16 interfaces.
4585 **
4586 ** ^If pzTail is not NULL then *pzTail is made to point to the first byte
4587 ** past the end of the first SQL statement in zSql. These routines only
4588 ** compile the first statement in zSql, so *pzTail is left pointing to
4589 ** what remains uncompiled.
@@ -5913,11 +5950,11 @@
5950 ** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
5951 ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
5952 ** This flag instructs SQLite to omit some corner-case optimizations that
5953 ** might disrupt the operation of the [sqlite3_value_subtype()] function,
5954 ** causing it to return zero rather than the correct subtype().
5955 ** All SQL functions that invoke [sqlite3_value_subtype()] should have this
5956 ** property. If the SQLITE_SUBTYPE property is omitted, then the return
5957 ** value from [sqlite3_value_subtype()] might sometimes be zero even though
5958 ** a non-zero subtype was specified by the function argument expression.
5959 **
5960 ** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
@@ -8678,11 +8715,11 @@
8715 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8716 #define SQLITE_TESTCTRL_SEEK_COUNT 30
8717 #define SQLITE_TESTCTRL_TRACEFLAGS 31
8718 #define SQLITE_TESTCTRL_TUNE 32
8719 #define SQLITE_TESTCTRL_LOGEST 33
8720 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
8721 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
8722
8723 /*
8724 ** CAPI3REF: SQL Keyword Checking
8725 **
@@ -9654,10 +9691,20 @@
9691 ** threads may safely make multiple concurrent calls to sqlite3_backup_step().
9692 ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
9693 ** APIs are not strictly speaking threadsafe. If they are invoked at the
9694 ** same time as another thread is invoking sqlite3_backup_step() it is
9695 ** possible that they return invalid values.
9696 **
9697 ** <b>Alternatives To Using The Backup API</b>
9698 **
9699 ** Other techniques for safely creating a consistent backup of an SQLite
9700 ** database include:
9701 **
9702 ** <ul>
9703 ** <li> The [VACUUM INTO] command.
9704 ** <li> The [sqlite3_rsync] utility program.
9705 ** </ul>
9706 */
9707 SQLITE_API sqlite3_backup *sqlite3_backup_init(
9708 sqlite3 *pDest, /* Destination database handle */
9709 const char *zDestName, /* Destination database name */
9710 sqlite3 *pSource, /* Source database handle */
@@ -10852,10 +10899,18 @@
10899 ** schema S in database connection D. ^On success, the
10900 ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
10901 ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
10902 ** If there is not already a read-transaction open on schema S when
10903 ** this function is called, one is opened automatically.
10904 **
10905 ** If a read-transaction is opened by this function, then it is guaranteed
10906 ** that the returned snapshot object may not be invalidated by a database
10907 ** writer or checkpointer until after the read-transaction is closed. This
10908 ** is not guaranteed if a read-transaction is already open when this
10909 ** function is called. In that case, any subsequent write or checkpoint
10910 ** operation on the database may invalidate the returned snapshot handle,
10911 ** even while the read-transaction remains open.
10912 **
10913 ** The following must be true for this function to succeed. If any of
10914 ** the following statements are false when sqlite3_snapshot_get() is
10915 ** called, SQLITE_ERROR is returned. The final value of *P is undefined
10916 ** in this case.
@@ -11172,11 +11227,11 @@
11227 #endif
11228
11229 #if 0
11230 } /* End of the 'extern "C"' block */
11231 #endif
11232 /* #endif for SQLITE3_H will be added by mksqlite3.tcl */
11233
11234 /******** Begin file sqlite3rtree.h *********/
11235 /*
11236 ** 2010 August 30
11237 **
@@ -13423,17 +13478,32 @@
13478 ** This is used to access token iToken of phrase hit iIdx within the
13479 ** current row. If iIdx is less than zero or greater than or equal to the
13480 ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
13481 ** output variable (*ppToken) is set to point to a buffer containing the
13482 ** matching document token, and (*pnToken) to the size of that buffer in
13483 ** bytes.
 
 
13484 **
13485 ** The output text is not a copy of the document text that was tokenized.
13486 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13487 ** includes any embedded 0x00 and trailing data.
13488 **
13489 ** This API may be slow in some cases if the token identified by parameters
13490 ** iIdx and iToken matched a prefix token in the query. In most cases, the
13491 ** first call to this API for each prefix token in the query is forced
13492 ** to scan the portion of the full-text index that matches the prefix
13493 ** token to collect the extra data required by this API. If the prefix
13494 ** token matches a large number of token instances in the document set,
13495 ** this may be a performance problem.
13496 **
13497 ** If the user knows in advance that a query may use this API for a
13498 ** prefix token, FTS5 may be configured to collect all required data as part
13499 ** of the initial querying of the full-text index, avoiding the second scan
13500 ** entirely. This also causes prefix queries that do not use this API to
13501 ** run more slowly and use more memory. FTS5 may be configured in this way
13502 ** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
13503 ** option, or on a per-query basis using the
13504 ** [fts5_insttoken | fts5_insttoken()] user function.
13505 **
13506 ** This API can be quite slow if used with an FTS5 table created with the
13507 ** "detail=none" or "detail=column" option.
13508 **
13509 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -13521,11 +13591,10 @@
13591 ** CUSTOM TOKENIZERS
13592 **
13593 ** Applications may also register custom tokenizer types. A tokenizer
13594 ** is registered by providing fts5 with a populated instance of the
13595 ** following structure. All structure methods must be defined, setting
 
13596 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13597 ** behaviour. The structure methods are expected to function as follows:
13598 **
13599 ** xCreate:
13600 ** This function is used to allocate and initialize a tokenizer instance.
@@ -13865,10 +13934,11 @@
13934 #endif
13935
13936 #endif /* _FTS5_H */
13937
13938 /******** End of fts5.h *********/
13939 #endif /* SQLITE3_H */
13940
13941 /************** End of sqlite3.h *********************************************/
13942 /************** Continuing where we left off in sqliteInt.h ******************/
13943
13944 /*
@@ -13910,10 +13980,11 @@
13980 ** to count the size: 2^31-1 or 2147483647.
13981 */
13982 #ifndef SQLITE_MAX_LENGTH
13983 # define SQLITE_MAX_LENGTH 1000000000
13984 #endif
13985 #define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */
13986
13987 /*
13988 ** This is the maximum number of
13989 **
13990 ** * Columns in a table
@@ -14809,10 +14880,11 @@
14880 #include <stdio.h>
14881 #include <stdlib.h>
14882 #include <string.h>
14883 #include <assert.h>
14884 #include <stddef.h>
14885 #include <ctype.h>
14886
14887 /*
14888 ** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
14889 ** This allows better measurements of where memcpy() is used when running
14890 ** cachegrind. But this macro version of memcpy() is very slow so it
@@ -14831,11 +14903,10 @@
14903 #ifdef SQLITE_OMIT_FLOATING_POINT
14904 # define double sqlite_int64
14905 # define float sqlite_int64
14906 # define fabs(X) ((X)<0?-(X):(X))
14907 # define sqlite3IsOverflow(X) 0
 
14908 # ifndef SQLITE_BIG_DBL
14909 # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
14910 # endif
14911 # define SQLITE_OMIT_DATETIME_FUNCS 1
14912 # define SQLITE_OMIT_TRACE 1
@@ -15006,13 +15077,10 @@
15077 # define INT8_TYPE int8_t
15078 # else
15079 # define INT8_TYPE signed char
15080 # endif
15081 #endif
 
 
 
15082 typedef sqlite_int64 i64; /* 8-byte signed integer */
15083 typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
15084 typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
15085 typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
15086 typedef INT16_TYPE i16; /* 2-byte signed integer */
@@ -16391,10 +16459,13 @@
16459 struct KeyInfo*, /* First argument to compare function */
16460 BtCursor *pCursor /* Space to write cursor structure */
16461 );
16462 SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
16463 SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
16464 #ifdef SQLITE_DEBUG
16465 SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(Btree*,BtCursor*);
16466 #endif
16467 SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
16468 SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
16469 #ifdef SQLITE_ENABLE_CURSOR_HINTS
16470 SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
16471 #endif
@@ -17004,11 +17075,11 @@
17075
17076 /*
17077 ** Additional non-public SQLITE_PREPARE_* flags
17078 */
17079 #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */
17080 #define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */
17081
17082 /*
17083 ** Prototypes for the VDBE interface. See comments on the implementation
17084 ** for a description of what each of these routines does.
17085 */
@@ -17719,51 +17790,15 @@
17790 struct FuncDefHash {
17791 FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
17792 };
17793 #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
17794
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17795 /*
17796 ** typedef for the authorization callback function.
17797 */
17798 typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
17799 const char*);
 
 
 
 
 
17800
17801 #ifndef SQLITE_OMIT_DEPRECATED
17802 /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
17803 ** in the style of sqlite3_trace()
17804 */
@@ -17920,13 +17955,10 @@
17955 sqlite3 *pUnlockConnection; /* Connection to watch for unlock */
17956 void *pUnlockArg; /* Argument to xUnlockNotify */
17957 void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
17958 sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
17959 #endif
 
 
 
17960 };
17961
17962 /*
17963 ** A macro to discover the encoding of a database.
17964 */
@@ -19221,11 +19253,11 @@
19253 #define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
19254 #define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
19255 #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
19256 #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
19257 #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
19258 #define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */
19259
19260 /* The EP_Propagate mask is a set of properties that automatically propagate
19261 ** upwards into parent nodes.
19262 */
19263 #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
@@ -19777,11 +19809,11 @@
19809 **
19810 ** SRT_Set The result must be a single column. Store each
19811 ** row of result as the key in table pDest->iSDParm.
19812 ** Apply the affinity pDest->affSdst before storing
19813 ** results. if pDest->iSDParm2 is positive, then it is
19814 ** a register holding a Bloom filter for the IN operator
19815 ** that should be populated in addition to the
19816 ** pDest->iSDParm table. This SRT is used to
19817 ** implement "IN (SELECT ...)".
19818 **
19819 ** SRT_EphemTab Create an temporary table pDest->iSDParm and store
@@ -20376,11 +20408,10 @@
20408 u8 bFullMutex; /* True to enable full mutexing */
20409 u8 bOpenUri; /* True to interpret filenames as URIs */
20410 u8 bUseCis; /* Use covering indices for full-scans */
20411 u8 bSmallMalloc; /* Avoid large memory allocations if true */
20412 u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
 
20413 #ifdef SQLITE_DEBUG
20414 u8 bJsonSelfcheck; /* Double-check JSON parsing */
20415 #endif
20416 int mxStrlen; /* Maximum string length */
20417 int neverCorrupt; /* Database is always well-formed */
@@ -20751,19 +20782,10 @@
20782 */
20783 #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
20784 # define SQLITE_ENABLE_FTS3 1
20785 #endif
20786
 
 
 
 
 
 
 
 
 
20787 /*
20788 ** The following macros mimic the standard library functions toupper(),
20789 ** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The
20790 ** sqlite versions only work for ASCII characters, regardless of locale.
20791 */
@@ -21381,11 +21403,11 @@
21403 SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
21404 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
21405 SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
21406 SQLITE_PRIVATE int sqlite3Atoi(const char*);
21407 #ifndef SQLITE_OMIT_UTF16
21408 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nByte, int nChar);
21409 #endif
21410 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
21411 SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
21412 SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*);
21413 SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
@@ -22839,13 +22861,10 @@
22861 "UNLINK_AFTER_CLOSE",
22862 #endif
22863 #ifdef SQLITE_UNTESTABLE
22864 "UNTESTABLE",
22865 #endif
 
 
 
22866 #ifdef SQLITE_USE_ALLOCA
22867 "USE_ALLOCA",
22868 #endif
22869 #ifdef SQLITE_USE_FCNTL_TRACE
22870 "USE_FCNTL_TRACE",
@@ -23117,11 +23136,10 @@
23136 SQLITE_THREADSAFE==1, /* bFullMutex */
23137 SQLITE_USE_URI, /* bOpenUri */
23138 SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
23139 0, /* bSmallMalloc */
23140 1, /* bExtraSchemaChecks */
 
23141 #ifdef SQLITE_DEBUG
23142 0, /* bJsonSelfcheck */
23143 #endif
23144 0x7ffffffe, /* mxStrlen */
23145 0, /* neverCorrupt */
@@ -23837,13 +23855,15 @@
23855 UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
23856 int iNewReg; /* Register for new.* values */
23857 int iBlobWrite; /* Value returned by preupdate_blobwrite() */
23858 i64 iKey1; /* First key value passed to hook */
23859 i64 iKey2; /* Second key value passed to hook */
23860 Mem oldipk; /* Memory cell holding "old" IPK value */
23861 Mem *aNew; /* Array of new.* values */
23862 Table *pTab; /* Schema object being updated */
23863 Index *pPk; /* PK index if pTab is WITHOUT ROWID */
23864 sqlite3_value **apDflt; /* Array of default values, if required */
23865 };
23866
23867 /*
23868 ** An instance of this object is used to pass an vector of values into
23869 ** OP_VFilter, the xFilter method of a virtual table. The vector is the
@@ -29285,20 +29305,33 @@
29305
29306 #ifndef NDEBUG
29307 /*
29308 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
29309 ** intended for use inside assert() statements.
29310 **
29311 ** Because these routines raise false-positive alerts in TSAN, disable
29312 ** them (make them always return 1) when compiling with TSAN.
29313 */
29314 SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
29315 # if defined(__has_feature)
29316 # if __has_feature(thread_sanitizer)
29317 p = 0;
29318 # endif
29319 # endif
29320 assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
29321 return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
29322 }
29323 SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
29324 # if defined(__has_feature)
29325 # if __has_feature(thread_sanitizer)
29326 p = 0;
29327 # endif
29328 # endif
29329 assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
29330 return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
29331 }
29332 #endif /* NDEBUG */
29333
29334 #endif /* !defined(SQLITE_MUTEX_OMIT) */
29335
29336 /************** End of mutex.c ***********************************************/
29337 /************** Begin file mutex_noop.c **************************************/
@@ -32272,10 +32305,11 @@
32305 && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
32306 ){
32307 pExpr = pExpr->pLeft;
32308 }
32309 if( pExpr==0 ) return;
32310 if( ExprHasProperty(pExpr, EP_FromDDL) ) return;
32311 db->errByteOffset = pExpr->w.iOfst;
32312 }
32313
32314 /*
32315 ** Enlarge the memory allocation on a StrAccum object so that it is
@@ -33001,11 +33035,11 @@
33035 }
33036 if( pItem->fg.isCte ){
33037 sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
33038 }
33039 if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
33040 sqlite3_str_appendf(&x, " isOn");
33041 }
33042 if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
33043 if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
33044 if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
33045 if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
@@ -34085,10 +34119,14 @@
34119 **
34120 ** This routines are given external linkage so that they will always be
34121 ** accessible to the debugging, and to avoid warnings about unused
34122 ** functions. But these routines only exist in debugging builds, so they
34123 ** do not contaminate the interface.
34124 **
34125 ** See Also:
34126 **
34127 ** sqlite3ShowWhereTerm() in where.c
34128 */
34129 SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
34130 SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
34131 SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
34132 SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
@@ -34687,11 +34725,11 @@
34725 */
34726 #define READ_UTF8(zIn, zTerm, c) \
34727 c = *(zIn++); \
34728 if( c>=0xc0 ){ \
34729 c = sqlite3Utf8Trans1[c-0xc0]; \
34730 while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
34731 c = (c<<6) + (0x3f & *(zIn++)); \
34732 } \
34733 if( c<0x80 \
34734 || (c&0xFFFFF800)==0xD800 \
34735 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
@@ -35065,24 +35103,26 @@
35103 assert( m.z || db->mallocFailed );
35104 return m.z;
35105 }
35106
35107 /*
35108 ** zIn is a UTF-16 encoded unicode string at least nByte bytes long.
35109 ** Return the number of bytes in the first nChar unicode characters
35110 ** in pZ. nChar must be non-negative. Surrogate pairs count as a single
35111 ** character.
35112 */
35113 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){
35114 int c;
35115 unsigned char const *z = zIn;
35116 unsigned char const *zEnd = &z[nByte-1];
35117 int n = 0;
35118
35119 if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
35120 while( n<nChar && ALWAYS(z<=zEnd) ){
35121 c = z[0];
35122 z += 2;
35123 if( c>=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
35124 n++;
35125 }
35126 return (int)(z-(unsigned char const *)zIn)
35127 - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE);
35128 }
@@ -35659,10 +35699,12 @@
35699 int esign = 1; /* sign of exponent */
35700 int e = 0; /* exponent */
35701 int eValid = 1; /* True exponent is either not used or is well-formed */
35702 int nDigit = 0; /* Number of digits processed */
35703 int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
35704 u64 s2; /* round-tripped significand */
35705 double rr[2];
35706
35707 assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
35708 *pResult = 0.0; /* Default return value, in case of an error */
35709 if( length==0 ) return 0;
35710
@@ -35761,81 +35803,65 @@
35803
35804 /* adjust exponent by d, and update sign */
35805 e = (e*esign) + d;
35806
35807 /* Try to adjust the exponent to make it smaller */
35808 while( e>0 && s<((LARGEST_UINT64-0x7ff)/10) ){
35809 s *= 10;
35810 e--;
35811 }
35812 while( e<0 && (s%10)==0 ){
35813 s /= 10;
35814 e++;
35815 }
35816
35817 rr[0] = (double)s;
35818 assert( sizeof(s2)==sizeof(rr[0]) );
35819 #ifdef SQLITE_DEBUG
35820 rr[1] = 18446744073709549568.0;
35821 memcpy(&s2, &rr[1], sizeof(s2));
35822 assert( s2==0x43efffffffffffffLL );
35823 #endif
35824 /* Largest double that can be safely converted to u64
35825 ** vvvvvvvvvvvvvvvvvvvvvv */
35826 if( rr[0]<=18446744073709549568.0 ){
35827 s2 = (u64)rr[0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35828 rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
35829 }else{
35830 rr[1] = 0.0;
35831 }
35832 assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */
35833
35834 if( e>0 ){
35835 while( e>=100 ){
35836 e -= 100;
35837 dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
35838 }
35839 while( e>=10 ){
35840 e -= 10;
35841 dekkerMul2(rr, 1.0e+10, 0.0);
35842 }
35843 while( e>=1 ){
35844 e -= 1;
35845 dekkerMul2(rr, 1.0e+01, 0.0);
35846 }
35847 }else{
35848 while( e<=-100 ){
35849 e += 100;
35850 dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
35851 }
35852 while( e<=-10 ){
35853 e += 10;
35854 dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
35855 }
35856 while( e<=-1 ){
35857 e += 1;
35858 dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
35859 }
35860 }
35861 *pResult = rr[0]+rr[1];
35862 if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
35863 if( sign<0 ) *pResult = -*pResult;
35864 assert( !sqlite3IsNaN(*pResult) );
35865
35866 atof_return:
35867 /* return true if number and no extra non-whitespace characters after */
@@ -36152,13 +36178,14 @@
36178 */
36179 SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
36180 int i;
36181 u64 v;
36182 int e, exp = 0;
36183 double rr[2];
36184
36185 p->isSpecial = 0;
36186 p->z = p->zBuf;
 
36187 assert( mxRound>0 );
36188
36189 /* Convert negative numbers to positive. Deal with Infinity, 0.0, and
36190 ** NaN. */
36191 if( r<0.0 ){
@@ -36182,66 +36209,49 @@
36209 return;
36210 }
36211
36212 /* Multiply r by powers of ten until it lands somewhere in between
36213 ** 1.0e+19 and 1.0e+17.
36214 **
36215 ** Use Dekker-style double-double computation to increase the
36216 ** precision.
36217 **
36218 ** The error terms on constants like 1.0e+100 computed using the
36219 ** decimal extension, for example as follows:
36220 **
36221 ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
36222 */
36223 rr[0] = r;
36224 rr[1] = 0.0;
36225 if( rr[0]>9.223372036854774784e+18 ){
36226 while( rr[0]>9.223372036854774784e+118 ){
36227 exp += 100;
36228 dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
36229 }
36230 while( rr[0]>9.223372036854774784e+28 ){
36231 exp += 10;
36232 dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
36233 }
36234 while( rr[0]>9.223372036854774784e+18 ){
36235 exp += 1;
36236 dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
36237 }
36238 }else{
36239 while( rr[0]<9.223372036854774784e-83 ){
36240 exp -= 100;
36241 dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
36242 }
36243 while( rr[0]<9.223372036854774784e+07 ){
36244 exp -= 10;
36245 dekkerMul2(rr, 1.0e+10, 0.0);
36246 }
36247 while( rr[0]<9.22337203685477478e+17 ){
36248 exp -= 1;
36249 dekkerMul2(rr, 1.0e+01, 0.0);
36250 }
36251 }
36252 v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36253
36254 /* Extract significant digits. */
36255 i = sizeof(p->zBuf)-1;
36256 assert( v>0 );
36257 while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
@@ -37008,108 +37018,10 @@
37018 i += pIn[i+1];
37019 }while( i<mx );
37020 return 0;
37021 }
37022
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37023 /************** End of util.c ************************************************/
37024 /************** Begin file hash.c ********************************************/
37025 /*
37026 ** 2001 September 22
37027 **
@@ -38787,11 +38699,11 @@
38699 # define F_SETLKW 7
38700 # endif
38701 # endif
38702 #else /* !SQLITE_WASI */
38703 # ifndef HAVE_FCHMOD
38704 # define HAVE_FCHMOD 1
38705 # endif
38706 #endif /* SQLITE_WASI */
38707
38708 #ifdef SQLITE_WASI
38709 # define osGetpid(X) (pid_t)1
@@ -41038,58 +40950,37 @@
40950 ** file by this or any other process. If such a lock is held, set *pResOut
40951 ** to a non-zero value otherwise *pResOut is set to zero. The return value
40952 ** is set to SQLITE_OK unless an I/O error occurs during lock checking.
40953 */
40954 static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
40955 #ifdef SQLITE_DEBUG
 
40956 unixFile *pFile = (unixFile*)id;
40957 #else
40958 UNUSED_PARAMETER(id);
40959 #endif
40960
40961 SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
40962
40963 assert( pFile );
40964 assert( pFile->eFileLock<=SHARED_LOCK );
40965
40966 /* The flock VFS only ever takes exclusive locks (see function flockLock).
40967 ** Therefore, if this connection is holding any lock at all, no other
40968 ** connection may be holding a RESERVED lock. So set *pResOut to 0
40969 ** in this case.
40970 **
40971 ** Or, this connection may be holding no lock. In that case, set *pResOut to
40972 ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the
40973 ** db in order to roll the hot journal back. If there is another connection
40974 ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to
40975 ** the user. With other VFS, we try to avoid this, in order to allow a reader
40976 ** to proceed while a writer is preparing its transaction. But that won't
40977 ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is
40978 ** not a problem in this case. */
40979 *pResOut = 0;
40980
40981 return SQLITE_OK;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40982 }
40983
40984 /*
40985 ** Lock the file with the lock specified by parameter eFileLock - one
40986 ** of the following:
@@ -42582,10 +42473,15 @@
42473 int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
42474 return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
42475 }
42476 #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
42477
42478 case SQLITE_FCNTL_NULL_IO: {
42479 osClose(pFile->h);
42480 pFile->h = -1;
42481 return SQLITE_OK;
42482 }
42483 case SQLITE_FCNTL_LOCKSTATE: {
42484 *(int*)pArg = pFile->eFileLock;
42485 return SQLITE_OK;
42486 }
42487 case SQLITE_FCNTL_LAST_ERRNO: {
@@ -42723,10 +42619,11 @@
42619
42620 /* Set the POWERSAFE_OVERWRITE flag if requested. */
42621 if( pFd->ctrlFlags & UNIXFILE_PSOW ){
42622 pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
42623 }
42624 pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ;
42625
42626 pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
42627 }
42628 }
42629 #else
@@ -42773,19 +42670,19 @@
42670 0;
42671 }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
42672 pFile->sectorSize = fsInfo.f_bsize;
42673 pFile->deviceCharacteristics =
42674 /* full bitset of atomics from max sector size and smaller */
42675 (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
42676 SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
42677 ** so it is ordered */
42678 0;
42679 }else if( strstr(fsInfo.f_basetype, "dos") ){
42680 pFile->sectorSize = fsInfo.f_bsize;
42681 pFile->deviceCharacteristics =
42682 /* full bitset of atomics from max sector size and smaller */
42683 (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
42684 SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
42685 ** so it is ordered */
42686 0;
42687 }else{
42688 pFile->deviceCharacteristics =
@@ -50462,10 +50359,15 @@
50359 OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
50360 hOldFile, pFile->h));
50361 return SQLITE_OK;
50362 }
50363 #endif
50364 case SQLITE_FCNTL_NULL_IO: {
50365 (void)osCloseHandle(pFile->h);
50366 pFile->h = NULL;
50367 return SQLITE_OK;
50368 }
50369 case SQLITE_FCNTL_TEMPFILENAME: {
50370 char *zTFile = 0;
50371 int rc = winGetTempname(pFile->pVfs, &zTFile);
50372 if( rc==SQLITE_OK ){
50373 *(char**)pArg = zTFile;
@@ -50523,11 +50425,11 @@
50425 /*
50426 ** Return a vector of device characteristics.
50427 */
50428 static int winDeviceCharacteristics(sqlite3_file *id){
50429 winFile *p = (winFile*)id;
50430 return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ |
50431 ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
50432 }
50433
50434 /*
50435 ** Windows will only let you create file view mappings
@@ -51911,11 +51813,11 @@
51813 */
51814 char *zTmpname = 0; /* For temporary filename, if necessary. */
51815
51816 int rc = SQLITE_OK; /* Function Return Code */
51817 #if !defined(NDEBUG) || SQLITE_OS_WINCE
51818 int eType = flags&0x0FFF00; /* Type of file to open */
51819 #endif
51820
51821 int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
51822 int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
51823 int isCreate = (flags & SQLITE_OPEN_CREATE);
@@ -58131,24 +58033,32 @@
58033 #ifdef SQLITE_DIRECT_OVERFLOW_READ
58034 /*
58035 ** Return true if page pgno can be read directly from the database file
58036 ** by the b-tree layer. This is the case if:
58037 **
58038 ** (1) the database file is open
58039 ** (2) the VFS for the database is able to do unaligned sub-page reads
58040 ** (3) there are no dirty pages in the cache, and
58041 ** (4) the desired page is not currently in the wal file.
58042 */
58043 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
58044 assert( pPager!=0 );
58045 assert( pPager->fd!=0 );
58046 if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */
58047 if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */
58048 #ifndef SQLITE_OMIT_WAL
58049 if( pPager->pWal ){
58050 u32 iRead = 0;
58051 (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
58052 return iRead==0; /* Condition (4) */
58053 }
58054 #endif
58055 assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
58056 if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
58057 & SQLITE_IOCAP_SUBPAGE_READ)==0 ){
58058 return 0; /* Case (2) */
58059 }
58060 return 1;
58061 }
58062 #endif
58063
58064 #ifndef SQLITE_OMIT_WAL
@@ -65171,11 +65081,11 @@
65081 ** 20: Salt-2, a different random integer changing with each ckpt
65082 ** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
65083 ** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
65084 **
65085 ** Immediately following the wal-header are zero or more frames. Each
65086 ** frame consists of a 24-byte frame-header followed by <page-size> bytes
65087 ** of page data. The frame-header is six big-endian 32-bit unsigned
65088 ** integer values, as follows:
65089 **
65090 ** 0: Page number.
65091 ** 4: For commit records, the size of the database image in pages
@@ -65668,10 +65578,11 @@
65578 int nSehTry; /* Number of nested SEH_TRY{} blocks */
65579 u8 lockError; /* True if a locking error has occurred */
65580 #endif
65581 #ifdef SQLITE_ENABLE_SNAPSHOT
65582 WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
65583 int bGetSnapshot; /* Transaction opened for sqlite3_get_snapshot() */
65584 #endif
65585 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
65586 sqlite3 *db;
65587 #endif
65588 };
@@ -67560,11 +67471,11 @@
67471 return SQLITE_IOERR_IN_PAGE;
67472 }
67473
67474 /*
67475 ** Assert that the Wal.lockMask mask, which indicates the locks held
67476 ** by the connection, is consistent with the Wal.readLock, Wal.writeLock
67477 ** and Wal.ckptLock variables. To be used as:
67478 **
67479 ** assert( walAssertLockmask(pWal) );
67480 */
67481 static int walAssertLockmask(Wal *pWal){
@@ -68224,11 +68135,11 @@
68135 assert( pWal->apWiData[0]!=0 );
68136 pInfo = walCkptInfo(pWal);
68137 SEH_INJECT_FAULT;
68138 if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
68139 #ifdef SQLITE_ENABLE_SNAPSHOT
68140 && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0)
68141 #endif
68142 ){
68143 /* The WAL has been completely backfilled (or it is empty).
68144 ** and can be safely ignored.
68145 */
@@ -69624,11 +69535,24 @@
69535 */
69536 SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
69537 Wal *pWal,
69538 sqlite3_snapshot *pSnapshot
69539 ){
69540 if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){
69541 /* iVersion==0 means that this is a call to sqlite3_snapshot_get(). In
69542 ** this case set the bGetSnapshot flag so that if the call to
69543 ** sqlite3_snapshot_get() is about to read transaction on this wal
69544 ** file, it does not take read-lock 0 if the wal file has been completely
69545 ** checkpointed. Taking read-lock 0 would work, but then it would be
69546 ** possible for a subsequent writer to destroy the snapshot even while
69547 ** this connection is holding its read-transaction open. This is contrary
69548 ** to user expectations, so we avoid it by not taking read-lock 0. */
69549 pWal->bGetSnapshot = 1;
69550 }else{
69551 pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
69552 pWal->bGetSnapshot = 0;
69553 }
69554 }
69555
69556 /*
69557 ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
69558 ** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
@@ -75504,10 +75428,29 @@
75428 ** this routine.
75429 */
75430 SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){
75431 return ROUND8(sizeof(BtCursor));
75432 }
75433
75434 #ifdef SQLITE_DEBUG
75435 /*
75436 ** Return true if and only if the Btree object will be automatically
75437 ** closed with the BtCursor closes. This is used within assert() statements
75438 ** only.
75439 */
75440 SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(
75441 Btree *pBtree, /* the btree object */
75442 BtCursor *pCur /* Corresponding cursor */
75443 ){
75444 BtShared *pBt = pBtree->pBt;
75445 if( (pBt->openFlags & BTREE_SINGLE)==0 ) return 0;
75446 if( pBt->pCursor!=pCur ) return 0;
75447 if( pCur->pNext!=0 ) return 0;
75448 if( pCur->pBtree!=pBtree ) return 0;
75449 return 1;
75450 }
75451 #endif
75452
75453 /*
75454 ** Initialize memory that will be converted into a BtCursor object.
75455 **
75456 ** The simple approach here would be to memset() the entire object
@@ -84538,11 +84481,12 @@
84481 if( apVal==0 ){
84482 rc = SQLITE_NOMEM_BKPT;
84483 goto value_from_function_out;
84484 }
84485 for(i=0; i<nVal; i++){
84486 rc = sqlite3Stat4ValueFromExpr(pCtx->pParse, pList->a[i].pExpr, aff,
84487 &apVal[i]);
84488 if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
84489 }
84490 }
84491
84492 pVal = valueNew(db, pCtx);
@@ -89571,11 +89515,11 @@
89515 /* The following two functions are used only within testcase() to prove
89516 ** test coverage. These functions do no exist for production builds.
89517 ** We must use separate SQLITE_NOINLINE functions here, since otherwise
89518 ** optimizer code movement causes gcov to become very confused.
89519 */
89520 #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
89521 static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
89522 static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
89523 #endif
89524
89525 /*
@@ -89586,17 +89530,10 @@
89530 SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
89531 if( sqlite3IsNaN(r) ){
89532 /* SQLite considers NaN to be a NULL. And all integer values are greater
89533 ** than NULL */
89534 return 1;
 
 
 
 
 
 
 
89535 }else{
89536 i64 y;
89537 if( r<-9223372036854775808.0 ) return +1;
89538 if( r>=9223372036854775808.0 ) return -1;
89539 y = (i64)r;
@@ -90595,17 +90532,25 @@
90532 db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
90533 db->pPreUpdate = 0;
90534 sqlite3DbFree(db, preupdate.aRecord);
90535 vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
90536 vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
90537 sqlite3VdbeMemRelease(&preupdate.oldipk);
90538 if( preupdate.aNew ){
90539 int i;
90540 for(i=0; i<pCsr->nField; i++){
90541 sqlite3VdbeMemRelease(&preupdate.aNew[i]);
90542 }
90543 sqlite3DbNNFreeNN(db, preupdate.aNew);
90544 }
90545 if( preupdate.apDflt ){
90546 int i;
90547 for(i=0; i<pTab->nCol; i++){
90548 sqlite3ValueFree(preupdate.apDflt[i]);
90549 }
90550 sqlite3DbFree(db, preupdate.apDflt);
90551 }
90552 }
90553 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
90554
90555 /************** End of vdbeaux.c *********************************************/
90556 /************** Begin file vdbeapi.c *****************************************/
@@ -92230,10 +92175,21 @@
92175 ** A successful evaluation of this routine acquires the mutex on p.
92176 ** the mutex is released if any kind of error occurs.
92177 **
92178 ** The error code stored in database p->db is overwritten with the return
92179 ** value in any case.
92180 **
92181 ** (tag-20240917-01) If vdbeUnbind(p,(u32)(i-1)) returns SQLITE_OK,
92182 ** that means all of the the following will be true:
92183 **
92184 ** p!=0
92185 ** p->pVar!=0
92186 ** i>0
92187 ** i<=p->nVar
92188 **
92189 ** An assert() is normally added after vdbeUnbind() to help static analyzers
92190 ** realize this.
92191 */
92192 static int vdbeUnbind(Vdbe *p, unsigned int i){
92193 Mem *pVar;
92194 if( vdbeSafetyNotNull(p) ){
92195 return SQLITE_MISUSE_BKPT;
@@ -92287,10 +92243,11 @@
92243 Mem *pVar;
92244 int rc;
92245
92246 rc = vdbeUnbind(p, (u32)(i-1));
92247 if( rc==SQLITE_OK ){
92248 assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
92249 if( zData!=0 ){
92250 pVar = &p->aVar[i-1];
92251 rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
92252 if( rc==SQLITE_OK && encoding!=0 ){
92253 rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
@@ -92336,10 +92293,11 @@
92293 SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
92294 int rc;
92295 Vdbe *p = (Vdbe *)pStmt;
92296 rc = vdbeUnbind(p, (u32)(i-1));
92297 if( rc==SQLITE_OK ){
92298 assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
92299 sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
92300 sqlite3_mutex_leave(p->db->mutex);
92301 }
92302 return rc;
92303 }
@@ -92349,10 +92307,11 @@
92307 SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
92308 int rc;
92309 Vdbe *p = (Vdbe *)pStmt;
92310 rc = vdbeUnbind(p, (u32)(i-1));
92311 if( rc==SQLITE_OK ){
92312 assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
92313 sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
92314 sqlite3_mutex_leave(p->db->mutex);
92315 }
92316 return rc;
92317 }
@@ -92359,10 +92318,11 @@
92318 SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
92319 int rc;
92320 Vdbe *p = (Vdbe*)pStmt;
92321 rc = vdbeUnbind(p, (u32)(i-1));
92322 if( rc==SQLITE_OK ){
92323 assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
92324 sqlite3_mutex_leave(p->db->mutex);
92325 }
92326 return rc;
92327 }
92328 SQLITE_API int sqlite3_bind_pointer(
@@ -92374,10 +92334,11 @@
92334 ){
92335 int rc;
92336 Vdbe *p = (Vdbe*)pStmt;
92337 rc = vdbeUnbind(p, (u32)(i-1));
92338 if( rc==SQLITE_OK ){
92339 assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
92340 sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
92341 sqlite3_mutex_leave(p->db->mutex);
92342 }else if( xDestructor ){
92343 xDestructor(pPtr);
92344 }
@@ -92455,10 +92416,11 @@
92416 SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
92417 int rc;
92418 Vdbe *p = (Vdbe *)pStmt;
92419 rc = vdbeUnbind(p, (u32)(i-1));
92420 if( rc==SQLITE_OK ){
92421 assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
92422 #ifndef SQLITE_OMIT_INCRBLOB
92423 sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
92424 #else
92425 rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
92426 #endif
@@ -92789,41 +92751,68 @@
92751 if( iIdx>=p->pCsr->nField || iIdx<0 ){
92752 rc = SQLITE_RANGE;
92753 goto preupdate_old_out;
92754 }
92755
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92756 if( iIdx==p->pTab->iPKey ){
92757 *ppValue = pMem = &p->oldipk;
92758 sqlite3VdbeMemSetInt64(pMem, p->iKey1);
92759 }else{
92760
92761 /* If the old.* record has not yet been loaded into memory, do so now. */
92762 if( p->pUnpacked==0 ){
92763 u32 nRec;
92764 u8 *aRec;
92765
92766 assert( p->pCsr->eCurType==CURTYPE_BTREE );
92767 nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
92768 aRec = sqlite3DbMallocRaw(db, nRec);
92769 if( !aRec ) goto preupdate_old_out;
92770 rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
92771 if( rc==SQLITE_OK ){
92772 p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
92773 if( !p->pUnpacked ) rc = SQLITE_NOMEM;
92774 }
92775 if( rc!=SQLITE_OK ){
92776 sqlite3DbFree(db, aRec);
92777 goto preupdate_old_out;
92778 }
92779 p->aRecord = aRec;
92780 }
92781
92782 pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
92783 if( iIdx>=p->pUnpacked->nField ){
92784 /* This occurs when the table has been extended using ALTER TABLE
92785 ** ADD COLUMN. The value to return is the default value of the column. */
92786 Column *pCol = &p->pTab->aCol[iIdx];
92787 if( pCol->iDflt>0 ){
92788 if( p->apDflt==0 ){
92789 int nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
92790 p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
92791 if( p->apDflt==0 ) goto preupdate_old_out;
92792 }
92793 if( p->apDflt[iIdx]==0 ){
92794 sqlite3_value *pVal = 0;
92795 Expr *pDflt;
92796 assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) );
92797 pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
92798 rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
92799 if( rc==SQLITE_OK && pVal==0 ){
92800 rc = SQLITE_CORRUPT_BKPT;
92801 }
92802 p->apDflt[iIdx] = pVal;
92803 }
92804 *ppValue = p->apDflt[iIdx];
92805 }else{
92806 *ppValue = (sqlite3_value *)columnNullValue();
92807 }
92808 }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
92809 if( pMem->flags & (MEM_Int|MEM_IntReal) ){
92810 testcase( pMem->flags & MEM_Int );
92811 testcase( pMem->flags & MEM_IntReal );
92812 sqlite3VdbeMemRealify(pMem);
92813 }
92814 }
92815 }
92816
92817 preupdate_old_out:
92818 sqlite3Error(db, rc);
@@ -93367,10 +93356,108 @@
93356 ** commenting and indentation practices when changing or adding code.
93357 */
93358 /* #include "sqliteInt.h" */
93359 /* #include "vdbeInt.h" */
93360
93361 /*
93362 ** High-resolution hardware timer used for debugging and testing only.
93363 */
93364 #if defined(VDBE_PROFILE) \
93365 || defined(SQLITE_PERFORMANCE_TRACE) \
93366 || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
93367 /************** Include hwtime.h in the middle of vdbe.c *********************/
93368 /************** Begin file hwtime.h ******************************************/
93369 /*
93370 ** 2008 May 27
93371 **
93372 ** The author disclaims copyright to this source code. In place of
93373 ** a legal notice, here is a blessing:
93374 **
93375 ** May you do good and not evil.
93376 ** May you find forgiveness for yourself and forgive others.
93377 ** May you share freely, never taking more than you give.
93378 **
93379 ******************************************************************************
93380 **
93381 ** This file contains inline asm code for retrieving "high-performance"
93382 ** counters for x86 and x86_64 class CPUs.
93383 */
93384 #ifndef SQLITE_HWTIME_H
93385 #define SQLITE_HWTIME_H
93386
93387 /*
93388 ** The following routine only works on Pentium-class (or newer) processors.
93389 ** It uses the RDTSC opcode to read the cycle count value out of the
93390 ** processor and returns that value. This can be used for high-res
93391 ** profiling.
93392 */
93393 #if !defined(__STRICT_ANSI__) && \
93394 (defined(__GNUC__) || defined(_MSC_VER)) && \
93395 (defined(i386) || defined(__i386__) || defined(_M_IX86))
93396
93397 #if defined(__GNUC__)
93398
93399 __inline__ sqlite_uint64 sqlite3Hwtime(void){
93400 unsigned int lo, hi;
93401 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
93402 return (sqlite_uint64)hi << 32 | lo;
93403 }
93404
93405 #elif defined(_MSC_VER)
93406
93407 __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
93408 __asm {
93409 rdtsc
93410 ret ; return value at EDX:EAX
93411 }
93412 }
93413
93414 #endif
93415
93416 #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
93417
93418 __inline__ sqlite_uint64 sqlite3Hwtime(void){
93419 unsigned int lo, hi;
93420 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
93421 return (sqlite_uint64)hi << 32 | lo;
93422 }
93423
93424 #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
93425
93426 __inline__ sqlite_uint64 sqlite3Hwtime(void){
93427 unsigned long long retval;
93428 unsigned long junk;
93429 __asm__ __volatile__ ("\n\
93430 1: mftbu %1\n\
93431 mftb %L0\n\
93432 mftbu %0\n\
93433 cmpw %0,%1\n\
93434 bne 1b"
93435 : "=r" (retval), "=r" (junk));
93436 return retval;
93437 }
93438
93439 #else
93440
93441 /*
93442 ** asm() is needed for hardware timing support. Without asm(),
93443 ** disable the sqlite3Hwtime() routine.
93444 **
93445 ** sqlite3Hwtime() is only used for some obscure debugging
93446 ** and analysis configurations, not in any deliverable, so this
93447 ** should not be a great loss.
93448 */
93449 SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
93450
93451 #endif
93452
93453 #endif /* !defined(SQLITE_HWTIME_H) */
93454
93455 /************** End of hwtime.h **********************************************/
93456 /************** Continuing where we left off in vdbe.c ***********************/
93457 #endif
93458
93459 /*
93460 ** Invoke this macro on memory cells just prior to changing the
93461 ** value of the cell. This macro verifies that shallow copies are
93462 ** not misused. A shallow copy of a string or blob just copies a
93463 ** pointer to the string or blob, not the content. If the original
@@ -97875,12 +97962,17 @@
97962 0, pCx->uc.pCursor);
97963 pCx->isTable = 1;
97964 }
97965 }
97966 pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
97967 assert( p->apCsr[pOp->p1]==pCx );
97968 if( rc ){
97969 assert( !sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
97970 sqlite3BtreeClose(pCx->ub.pBtx);
97971 p->apCsr[pOp->p1] = 0; /* Not required; helps with static analysis */
97972 }else{
97973 assert( sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
97974 }
97975 }
97976 }
97977 if( rc ) goto abort_due_to_error;
97978 pCx->nullRow = 1;
@@ -102394,11 +102486,11 @@
102486 ** element.
102487 **
102488 ** As with all opcodes, the meanings of the parameters for OP_Explain
102489 ** are subject to change from one release to the next. Applications
102490 ** should not attempt to interpret or use any of the information
102491 ** contained in the OP_Explain opcode. The information provided by this
102492 ** opcode is intended for testing and debugging use only.
102493 */
102494 default: { /* This is really OP_Noop, OP_Explain */
102495 assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
102496
@@ -107490,11 +107582,11 @@
107582 ** non-VIEW candidate plus multiple VIEW candidates. In other
107583 ** words non-VIEW candidate terms take precedence over VIEWs.
107584 */
107585 if( cntTab==0
107586 || (cntTab==1
107587 && pMatch!=0
107588 && ALWAYS(pMatch->pSTab!=0)
107589 && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
107590 && (pTab->tabFlags & TF_Ephemeral)==0)
107591 ){
107592 cntTab = 1;
@@ -108123,12 +108215,12 @@
108215 }
108216
108217 /* Resolve function names
108218 */
108219 case TK_FUNCTION: {
108220 ExprList *pList; /* The argument list */
108221 int n; /* Number of arguments */
108222 int no_such_func = 0; /* True if no such function exists */
108223 int wrong_num_args = 0; /* True if wrong number of arguments */
108224 int is_agg = 0; /* True if is an aggregate function */
108225 const char *zId; /* The function name. */
108226 FuncDef *pDef; /* Information about the function */
@@ -108137,10 +108229,12 @@
108229 #ifndef SQLITE_OMIT_WINDOWFUNC
108230 Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
108231 #endif
108232 assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
108233 assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
108234 pList = pExpr->x.pList;
108235 n = pList ? pList->nExpr : 0;
108236 zId = pExpr->u.zToken;
108237 pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
108238 if( pDef==0 ){
108239 pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
108240 if( pDef==0 ){
@@ -108185,10 +108279,28 @@
108279 pExpr->op = TK_NULL;
108280 return WRC_Prune;
108281 }
108282 }
108283 #endif
108284
108285 /* If the function may call sqlite3_value_subtype(), then set the
108286 ** EP_SubtArg flag on all of its argument expressions. This prevents
108287 ** where.c from replacing the expression with a value read from an
108288 ** index on the same expression, which will not have the correct
108289 ** subtype. Also set the flag if the function expression itself is
108290 ** an EP_SubtArg expression. In this case subtypes are required as
108291 ** the function may return a value with a subtype back to its
108292 ** caller using sqlite3_result_value(). */
108293 if( (pDef->funcFlags & SQLITE_SUBTYPE)
108294 || ExprHasProperty(pExpr, EP_SubtArg)
108295 ){
108296 int ii;
108297 for(ii=0; ii<n; ii++){
108298 ExprSetProperty(pList->a[ii].pExpr, EP_SubtArg);
108299 }
108300 }
108301
108302 if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
108303 /* For the purposes of the EP_ConstFunc flag, date and time
108304 ** functions and other functions that change slowly are considered
108305 ** constant because they are constant for the duration of one query.
108306 ** This allows them to be factored out of inner loops. */
@@ -111951,11 +112063,11 @@
112063 **
112064 ** (4) If pSrc is the right operand of a LEFT JOIN, then...
112065 ** (4a) pExpr must come from an ON clause..
112066 ** (4b) and specifically the ON clause associated with the LEFT JOIN.
112067 **
112068 ** (5) If pSrc is the right operand of a LEFT JOIN or the left
112069 ** operand of a RIGHT JOIN, then pExpr must be from the WHERE
112070 ** clause, not an ON clause.
112071 **
112072 ** (6) Either:
112073 **
@@ -113858,10 +113970,63 @@
113970 }
113971 #endif /* !defined(SQLITE_UNTESTABLE) */
113972 }
113973 return target;
113974 }
113975
113976 /*
113977 ** Expression Node callback for sqlite3ExprCanReturnSubtype().
113978 **
113979 ** Only a function call is able to return a subtype. So if the node
113980 ** is not a function call, return WRC_Prune immediately.
113981 **
113982 ** A function call is able to return a subtype if it has the
113983 ** SQLITE_RESULT_SUBTYPE property.
113984 **
113985 ** Assume that every function is able to pass-through a subtype from
113986 ** one of its argument (using sqlite3_result_value()). Most functions
113987 ** are not this way, but we don't have a mechanism to distinguish those
113988 ** that are from those that are not, so assume they all work this way.
113989 ** That means that if one of its arguments is another function and that
113990 ** other function is able to return a subtype, then this function is
113991 ** able to return a subtype.
113992 */
113993 static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
113994 int n;
113995 FuncDef *pDef;
113996 sqlite3 *db;
113997 if( pExpr->op!=TK_FUNCTION ){
113998 return WRC_Prune;
113999 }
114000 assert( ExprUseXList(pExpr) );
114001 db = pWalker->pParse->db;
114002 n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0;
114003 pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
114004 if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
114005 pWalker->eCode = 1;
114006 return WRC_Prune;
114007 }
114008 return WRC_Continue;
114009 }
114010
114011 /*
114012 ** Return TRUE if expression pExpr is able to return a subtype.
114013 **
114014 ** A TRUE return does not guarantee that a subtype will be returned.
114015 ** It only indicates that a subtype return is possible. False positives
114016 ** are acceptable as they only disable an optimization. False negatives,
114017 ** on the other hand, can lead to incorrect answers.
114018 */
114019 static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
114020 Walker w;
114021 memset(&w, 0, sizeof(w));
114022 w.pParse = pParse;
114023 w.xExprCallback = exprNodeCanReturnSubtype;
114024 sqlite3WalkExpr(&w, pExpr);
114025 return w.eCode;
114026 }
114027
114028
114029 /*
114030 ** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
114031 ** If it is, then resolve the expression by reading from the index and
114032 ** return the register into which the value has been read. If pExpr is
@@ -113891,10 +114056,21 @@
114056 ){
114057 /* Affinity mismatch on a generated column */
114058 continue;
114059 }
114060
114061
114062 /* Functions that might set a subtype should not be replaced by the
114063 ** value taken from an expression index if they are themselves an
114064 ** argument to another scalar function or aggregate.
114065 ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */
114066 if( ExprHasProperty(pExpr, EP_SubtArg)
114067 && sqlite3ExprCanReturnSubtype(pParse, pExpr)
114068 ){
114069 continue;
114070 }
114071
114072 v = pParse->pVdbe;
114073 assert( v!=0 );
114074 if( p->bMaybeNullRow ){
114075 /* If the index is on a NULL row due to an outer join, then we
114076 ** cannot extract the value from the index. The value must be
@@ -115421,35 +115597,41 @@
115597 **
115598 ** Additionally, if pExpr is a simple SQL value and the value is the
115599 ** same as that currently bound to variable pVar, non-zero is returned.
115600 ** Otherwise, if the values are not the same or if pExpr is not a simple
115601 ** SQL value, zero is returned.
115602 **
115603 ** If the SQLITE_EnableQPSG flag is set on the database connection, then
115604 ** this routine always returns false.
115605 */
115606 static SQLITE_NOINLINE int exprCompareVariable(
115607 const Parse *pParse,
115608 const Expr *pVar,
115609 const Expr *pExpr
115610 ){
115611 int res = 2;
115612 int iVar;
115613 sqlite3_value *pL, *pR = 0;
115614
115615 if( pExpr->op==TK_VARIABLE && pVar->iColumn==pExpr->iColumn ){
115616 return 0;
115617 }
115618 if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) return 2;
115619 sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
115620 if( pR ){
115621 iVar = pVar->iColumn;
115622 sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
115623 pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
115624 if( pL ){
115625 if( sqlite3_value_type(pL)==SQLITE_TEXT ){
115626 sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
115627 }
115628 res = sqlite3MemCompare(pL, pR, 0) ? 2 : 0;
115629 }
115630 sqlite3ValueFree(pR);
115631 sqlite3ValueFree(pL);
115632 }
 
115633 return res;
115634 }
115635
115636 /*
115637 ** Do a deep comparison of two expression trees. Return 0 if the two
@@ -115471,16 +115653,14 @@
115653 ** can be sure the expressions are the same. In the places where
115654 ** this routine is used, it does not hurt to get an extra 2 - that
115655 ** just might result in some slightly slower code. But returning
115656 ** an incorrect 0 or 1 could lead to a malfunction.
115657 **
115658 ** If pParse is not NULL and SQLITE_EnableQPSG is off then TK_VARIABLE
115659 ** terms in pA with bindings in pParse->pReprepare can be matched against
115660 ** literals in pB. The pParse->pVdbe->expmask bitmask is updated for
115661 ** each variable referenced.
 
 
115662 */
115663 SQLITE_PRIVATE int sqlite3ExprCompare(
115664 const Parse *pParse,
115665 const Expr *pA,
115666 const Expr *pB,
@@ -115488,12 +115668,12 @@
115668 ){
115669 u32 combinedFlags;
115670 if( pA==0 || pB==0 ){
115671 return pB==pA ? 0 : 2;
115672 }
115673 if( pParse && pA->op==TK_VARIABLE ){
115674 return exprCompareVariable(pParse, pA, pB);
115675 }
115676 combinedFlags = pA->flags | pB->flags;
115677 if( combinedFlags & EP_IntValue ){
115678 if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
115679 return 0;
@@ -115683,23 +115863,75 @@
115863 return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
115864 }
115865 }
115866 return 0;
115867 }
115868
115869 /*
115870 ** Return true if the boolean value of the expression is always either
115871 ** FALSE or NULL.
115872 */
115873 static int sqlite3ExprIsNotTrue(Expr *pExpr){
115874 int v;
115875 if( pExpr->op==TK_NULL ) return 1;
115876 if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1;
115877 v = 1;
115878 if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1;
115879 return 0;
115880 }
115881
115882 /*
115883 ** Return true if the expression is one of the following:
115884 **
115885 ** CASE WHEN x THEN y END
115886 ** CASE WHEN x THEN y ELSE NULL END
115887 ** CASE WHEN x THEN y ELSE false END
115888 ** iif(x,y)
115889 ** iif(x,y,NULL)
115890 ** iif(x,y,false)
115891 */
115892 static int sqlite3ExprIsIIF(sqlite3 *db, const Expr *pExpr){
115893 ExprList *pList;
115894 if( pExpr->op==TK_FUNCTION ){
115895 const char *z = pExpr->u.zToken;
115896 FuncDef *pDef;
115897 if( (z[0]!='i' && z[0]!='I') ) return 0;
115898 if( pExpr->x.pList==0 ) return 0;
115899 pDef = sqlite3FindFunction(db, z, pExpr->x.pList->nExpr, ENC(db), 0);
115900 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
115901 if( pDef==0 ) return 0;
115902 #else
115903 if( NEVER(pDef==0) ) return 0;
115904 #endif
115905 if( (pDef->funcFlags & SQLITE_FUNC_INLINE)==0 ) return 0;
115906 if( SQLITE_PTR_TO_INT(pDef->pUserData)!=INLINEFUNC_iif ) return 0;
115907 }else if( pExpr->op==TK_CASE ){
115908 if( pExpr->pLeft!=0 ) return 0;
115909 }else{
115910 return 0;
115911 }
115912 pList = pExpr->x.pList;
115913 assert( pList!=0 );
115914 if( pList->nExpr==2 ) return 1;
115915 if( pList->nExpr==3 && sqlite3ExprIsNotTrue(pList->a[2].pExpr) ) return 1;
115916 return 0;
115917 }
115918
115919 /*
115920 ** Return true if we can prove the pE2 will always be true if pE1 is
115921 ** true. Return false if we cannot complete the proof or if pE2 might
115922 ** be false. Examples:
115923 **
115924 ** pE1: x==5 pE2: x==5 Result: true
115925 ** pE1: x>0 pE2: x==5 Result: false
115926 ** pE1: x=21 pE2: x=21 OR y=43 Result: true
115927 ** pE1: x!=123 pE2: x IS NOT NULL Result: true
115928 ** pE1: x!=?1 pE2: x IS NOT NULL Result: true
115929 ** pE1: x IS NULL pE2: x IS NOT NULL Result: false
115930 ** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
115931 ** pE1: iif(x,y) pE2: x Result: true
115932 ** PE1: iif(x,y,0) pE2: x Result: true
115933 **
115934 ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
115935 ** Expr.iTable<0 then assume a table number given by iTab.
115936 **
115937 ** If pParse is not NULL, then the values of bound variables in pE1 are
@@ -115729,10 +115961,13 @@
115961 if( pE2->op==TK_NOTNULL
115962 && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0)
115963 ){
115964 return 1;
115965 }
115966 if( sqlite3ExprIsIIF(pParse->db, pE1) ){
115967 return sqlite3ExprImpliesExpr(pParse,pE1->x.pList->a[0].pExpr,pE2,iTab);
115968 }
115969 return 0;
115970 }
115971
115972 /* This is a helper function to impliesNotNullRow(). In this routine,
115973 ** set pWalker->eCode to one only if *both* of the input expressions
@@ -120689,12 +120924,12 @@
120924 int nIdxCol = 1; /* Number of columns in stat4 records */
120925
120926 char *zIndex; /* Index name */
120927 Index *pIdx; /* Pointer to the index object */
120928 int nSample; /* Number of samples */
120929 i64 nByte; /* Bytes of space required */
120930 i64 i; /* Bytes of space required */
120931 tRowcnt *pSpace; /* Available allocated memory space */
120932 u8 *pPtr; /* Available memory as a u8 for easier manipulation */
120933
120934 zIndex = (char *)sqlite3_column_text(pStmt, 0);
120935 if( zIndex==0 ) continue;
@@ -121140,19 +121375,10 @@
121375 rc = sqlite3Init(db, &zErrDyn);
121376 }
121377 sqlite3BtreeLeaveAll(db);
121378 assert( zErrDyn==0 || rc!=SQLITE_OK );
121379 }
 
 
 
 
 
 
 
 
 
121380 if( rc ){
121381 if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
121382 int iDb = db->nDb - 1;
121383 assert( iDb>=2 );
121384 if( db->aDb[iDb].pBt ){
@@ -121646,15 +121872,11 @@
121872 sqlite3 *db = pParse->db; /* Database handle */
121873 char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
121874 int rc; /* Auth callback return code */
121875
121876 if( db->init.busy ) return SQLITE_OK;
121877 rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext);
 
 
 
 
121878 if( rc==SQLITE_DENY ){
121879 char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
121880 if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
121881 sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
121882 pParse->rc = SQLITE_AUTH;
@@ -121757,15 +121979,11 @@
121979 testcase( zArg1==0 );
121980 testcase( zArg2==0 );
121981 testcase( zArg3==0 );
121982 testcase( pParse->zAuthContext==0 );
121983
121984 rc = db->xAuth(db->pAuthArg,code,zArg1,zArg2,zArg3,pParse->zAuthContext);
 
 
 
 
121985 if( rc==SQLITE_DENY ){
121986 sqlite3ErrorMsg(pParse, "not authorized");
121987 pParse->rc = SQLITE_AUTH;
121988 }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
121989 rc = SQLITE_DENY;
@@ -121994,21 +122212,10 @@
122212 sqlite3VdbeJumpHere(v, addrRewind);
122213 }
122214 }
122215 sqlite3VdbeAddOp0(v, OP_Halt);
122216
 
 
 
 
 
 
 
 
 
 
 
122217 /* The cookie mask contains one bit for each database file open.
122218 ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
122219 ** set for each database that is used. Generate code to start a
122220 ** transaction on each used database and to verify the schema cookie
122221 ** on each used database.
@@ -122133,20 +122340,10 @@
122340 sqlite3DbFree(db, zSql);
122341 memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
122342 pParse->nested--;
122343 }
122344
 
 
 
 
 
 
 
 
 
 
122345 /*
122346 ** Locate the in-memory structure that describes a particular database
122347 ** table given the name of that table and (optionally) the name of the
122348 ** database containing the table. Return NULL if not found.
122349 **
@@ -122161,17 +122358,10 @@
122358 Table *p = 0;
122359 int i;
122360
122361 /* All mutexes are required for schema access. Make sure we hold them. */
122362 assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
 
 
 
 
 
 
 
122363 if( zDatabase ){
122364 for(i=0; i<db->nDb; i++){
122365 if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
122366 }
122367 if( i>=db->nDb ){
@@ -125826,13 +126016,10 @@
126016
126017 assert( pTab!=0 );
126018 if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
126019 && db->init.busy==0
126020 && pTblName!=0
 
 
 
126021 ){
126022 sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
126023 goto exit_create_index;
126024 }
126025 #ifndef SQLITE_OMIT_VIEW
@@ -128224,10 +128411,11 @@
128411 ** 4) The table is a shadow table, the database connection is in
128412 ** defensive mode, and the current sqlite3_prepare()
128413 ** is for a top-level SQL statement.
128414 */
128415 static int vtabIsReadOnly(Parse *pParse, Table *pTab){
128416 assert( IsVirtual(pTab) );
128417 if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
128418 return 1;
128419 }
128420
128421 /* Within triggers:
@@ -131716,11 +131904,17 @@
131904 #ifdef SQLITE_DEBUG
131905 /*
131906 ** Implementation of fpdecode(x,y,z) function.
131907 **
131908 ** x is a real number that is to be decoded. y is the precision.
131909 ** z is the maximum real precision. Return a string that shows the
131910 ** results of the sqlite3FpDecode() function.
131911 **
131912 ** Used for testing and debugging only, specifically testing and debugging
131913 ** of the sqlite3FpDecode() function. This SQL function does not appear
131914 ** in production builds. This function is not an API and is subject to
131915 ** modification or removal in future versions of SQLite.
131916 */
131917 static void fpdecodeFunc(
131918 sqlite3_context *context,
131919 int argc,
131920 sqlite3_value **argv
@@ -131740,10 +131934,86 @@
131934 sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
131935 }else{
131936 sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
131937 }
131938 sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
131939 }
131940 #endif /* SQLITE_DEBUG */
131941
131942 #ifdef SQLITE_DEBUG
131943 /*
131944 ** Implementation of parseuri(uri,flags) function.
131945 **
131946 ** Required Arguments:
131947 ** "uri" The URI to parse.
131948 ** "flags" Bitmask of flags, as if to sqlite3_open_v2().
131949 **
131950 ** Additional arguments beyond the first two make calls to
131951 ** sqlite3_uri_key() for integers and sqlite3_uri_parameter for
131952 ** anything else.
131953 **
131954 ** The result is a string showing the results of calling sqlite3ParseUri().
131955 **
131956 ** Used for testing and debugging only, specifically testing and debugging
131957 ** of the sqlite3ParseUri() function. This SQL function does not appear
131958 ** in production builds. This function is not an API and is subject to
131959 ** modification or removal in future versions of SQLite.
131960 */
131961 static void parseuriFunc(
131962 sqlite3_context *ctx,
131963 int argc,
131964 sqlite3_value **argv
131965 ){
131966 sqlite3_str *pResult;
131967 const char *zVfs;
131968 const char *zUri;
131969 unsigned int flgs;
131970 int rc;
131971 sqlite3_vfs *pVfs = 0;
131972 char *zFile = 0;
131973 char *zErr = 0;
131974
131975 if( argc<2 ) return;
131976 pVfs = sqlite3_vfs_find(0);
131977 assert( pVfs );
131978 zVfs = pVfs->zName;
131979 zUri = (const char*)sqlite3_value_text(argv[0]);
131980 if( zUri==0 ) return;
131981 flgs = (unsigned int)sqlite3_value_int(argv[1]);
131982 rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr);
131983 pResult = sqlite3_str_new(0);
131984 if( pResult ){
131985 int i;
131986 sqlite3_str_appendf(pResult, "rc=%d", rc);
131987 sqlite3_str_appendf(pResult, ", flags=0x%x", flgs);
131988 sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0);
131989 sqlite3_str_appendf(pResult, ", err=%Q", zErr);
131990 sqlite3_str_appendf(pResult, ", file=%Q", zFile);
131991 if( zFile ){
131992 const char *z = zFile;
131993 z += sqlite3Strlen30(z)+1;
131994 while( z[0] ){
131995 sqlite3_str_appendf(pResult, ", %Q", z);
131996 z += sqlite3Strlen30(z)+1;
131997 }
131998 for(i=2; i<argc; i++){
131999 const char *zArg;
132000 if( sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
132001 int k = sqlite3_value_int(argv[i]);
132002 sqlite3_str_appendf(pResult, ", '%d:%q'",k,sqlite3_uri_key(zFile, k));
132003 }else if( (zArg = (const char*)sqlite3_value_text(argv[i]))!=0 ){
132004 sqlite3_str_appendf(pResult, ", '%q:%q'",
132005 zArg, sqlite3_uri_parameter(zFile,zArg));
132006 }else{
132007 sqlite3_str_appendf(pResult, ", NULL");
132008 }
132009 }
132010 }
132011 sqlite3_result_text(ctx, sqlite3_str_finish(pResult), -1, sqlite3_free);
132012 }
132013 sqlite3_free_filename(zFile);
132014 sqlite3_free(zErr);
132015 }
132016 #endif /* SQLITE_DEBUG */
132017
132018 /*
132019 ** All of the FuncDef structures in the aBuiltinFunc[] array above
@@ -131777,13 +132047,10 @@
132047 #endif
132048 #ifndef SQLITE_OMIT_LOAD_EXTENSION
132049 SFUNCTION(load_extension, 1, 0, 0, loadExt ),
132050 SFUNCTION(load_extension, 2, 0, 0, loadExt ),
132051 #endif
 
 
 
132052 #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
132053 DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
132054 DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
132055 #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
132056 INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
@@ -131805,11 +132072,12 @@
132072 FUNCTION(max, -1, 1, 1, minmaxFunc ),
132073 FUNCTION(max, 0, 1, 1, 0 ),
132074 WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
132075 SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
132076 FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
132077 FUNCTION2(subtype, 1, 0, 0, subtypeFunc,
132078 SQLITE_FUNC_TYPEOF|SQLITE_SUBTYPE),
132079 FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
132080 FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
132081 FUNCTION(instr, 2, 0, 0, instrFunc ),
132082 FUNCTION(printf, -1, 0, 0, printfFunc ),
132083 FUNCTION(format, -1, 0, 0, printfFunc ),
@@ -131816,10 +132084,11 @@
132084 FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
132085 FUNCTION(char, -1, 0, 0, charFunc ),
132086 FUNCTION(abs, 1, 0, 0, absFunc ),
132087 #ifdef SQLITE_DEBUG
132088 FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
132089 FUNCTION(parseuri, -1, 0, 0, parseuriFunc ),
132090 #endif
132091 #ifndef SQLITE_OMIT_FLOATING_POINT
132092 FUNCTION(round, 1, 0, 0, roundFunc ),
132093 FUNCTION(round, 2, 0, 0, roundFunc ),
132094 #endif
@@ -131910,15 +132179,18 @@
132179 MFUNCTION(atanh, 1, atanh, math1Func ),
132180 #endif
132181 MFUNCTION(sqrt, 1, sqrt, math1Func ),
132182 MFUNCTION(radians, 1, degToRad, math1Func ),
132183 MFUNCTION(degrees, 1, radToDeg, math1Func ),
132184 MFUNCTION(pi, 0, 0, piFunc ),
132185 #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
132186 FUNCTION(sign, 1, 0, 0, signFunc ),
132187 INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
132188 INLINE_FUNC(iif, 2, INLINEFUNC_iif, 0 ),
132189 INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
132190 INLINE_FUNC(if, 2, INLINEFUNC_iif, 0 ),
132191 INLINE_FUNC(if, 3, INLINEFUNC_iif, 0 ),
132192 };
132193 #ifndef SQLITE_OMIT_ALTERTABLE
132194 sqlite3AlterFunctions();
132195 #endif
132196 sqlite3WindowFunctions();
@@ -140427,16 +140699,10 @@
140699 if( db->autoCommit==0 ){
140700 /* Foreign key support may not be enabled or disabled while not
140701 ** in auto-commit mode. */
140702 mask &= ~(SQLITE_ForeignKeys);
140703 }
 
 
 
 
 
 
140704
140705 if( sqlite3GetBoolean(zRight, 0) ){
140706 if( (mask & SQLITE_WriteSchema)==0
140707 || (db->flags & SQLITE_Defensive)==0
140708 ){
@@ -140568,11 +140834,12 @@
140834 pTab = sqliteHashData(k);
140835 if( pTab->nCol==0 ){
140836 char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName);
140837 if( zSql ){
140838 sqlite3_stmt *pDummy = 0;
140839 (void)sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_DONT_LOG,
140840 &pDummy, 0);
140841 (void)sqlite3_finalize(pDummy);
140842 sqlite3DbFree(db, zSql);
140843 }
140844 if( db->mallocFailed ){
140845 sqlite3ErrorMsg(db->pParse, "out of memory");
@@ -141044,10 +141311,11 @@
141311 }
141312 aRoot[0] = cnt;
141313
141314 /* Make sure sufficient number of registers have been allocated */
141315 sqlite3TouchRegister(pParse, 8+cnt);
141316 sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt);
141317 sqlite3ClearTempRegCache(pParse);
141318
141319 /* Do the b-tree integrity checks */
141320 sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
141321 sqlite3VdbeChangeP5(v, (u8)i);
@@ -142668,18 +142936,11 @@
142936 encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
142937 if( encoding==0 ) encoding = SQLITE_UTF8;
142938 #else
142939 encoding = SQLITE_UTF8;
142940 #endif
142941 sqlite3SetTextEncoding(db, encoding);
 
 
 
 
 
 
 
142942 }else{
142943 /* If opening an attached database, the encoding much match ENC(db) */
142944 if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
142945 sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
142946 " text encoding as main database");
@@ -143369,16 +143630,28 @@
143630 #endif
143631 *ppStmt = 0;
143632 if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
143633 return SQLITE_MISUSE_BKPT;
143634 }
143635
143636 /* Make sure nBytes is non-negative and correct. It should be the
143637 ** number of bytes until the end of the input buffer or until the first
143638 ** U+0000 character. If the input nBytes is odd, convert it into
143639 ** an even number. If the input nBytes is negative, then the input
143640 ** must be terminated by at least one U+0000 character */
143641 if( nBytes>=0 ){
143642 int sz;
143643 const char *z = (const char*)zSql;
143644 for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
143645 nBytes = sz;
143646 }else{
143647 int sz;
143648 const char *z = (const char*)zSql;
143649 for(sz=0; z[sz]!=0 || z[sz+1]!=0; sz += 2){}
143650 nBytes = sz;
143651 }
143652
143653 sqlite3_mutex_enter(db->mutex);
143654 zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
143655 if( zSql8 ){
143656 rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
143657 }
@@ -143388,11 +143661,11 @@
143661 ** equivalent pointer into the UTF-16 string by counting the unicode
143662 ** characters between zSql8 and zTail8, and then returning a pointer
143663 ** the same number of characters into the UTF-16 string.
143664 */
143665 int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
143666 *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, nBytes, chars_parsed);
143667 }
143668 sqlite3DbFree(db, zSql8);
143669 rc = sqlite3ApiExit(db, rc);
143670 sqlite3_mutex_leave(db->mutex);
143671 return rc;
@@ -147361,36 +147634,36 @@
147634 return pExpr;
147635 }
147636 if( pSubst->isOuterJoin ){
147637 ExprSetProperty(pNew, EP_CanBeNull);
147638 }
147639 if( pNew->op==TK_TRUEFALSE ){
147640 pNew->u.iValue = sqlite3ExprTruthValue(pNew);
147641 pNew->op = TK_INTEGER;
147642 ExprSetProperty(pNew, EP_IntValue);
147643 }
147644
147645 /* Ensure that the expression now has an implicit collation sequence,
147646 ** just as it did when it was a column of a view or sub-query. */
147647 {
147648 CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pNew);
147649 CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
147650 pSubst->pCList->a[iColumn].pExpr
147651 );
147652 if( pNat!=pColl || (pNew->op!=TK_COLUMN && pNew->op!=TK_COLLATE) ){
147653 pNew = sqlite3ExprAddCollateString(pSubst->pParse, pNew,
147654 (pColl ? pColl->zName : "BINARY")
147655 );
147656 }
147657 }
147658 ExprClearProperty(pNew, EP_Collate);
147659 if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
147660 sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
147661 pExpr->flags & (EP_OuterON|EP_InnerON));
147662 }
147663 sqlite3ExprDelete(db, pExpr);
147664 pExpr = pNew;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147665 }
147666 }
147667 }else{
147668 if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
147669 pExpr->iTable = pSubst->iNewTable;
@@ -148123,20 +148396,20 @@
148396 }
148397
148398 /* Transfer the FROM clause terms from the subquery into the
148399 ** outer query.
148400 */
148401 iNewParent = pSubSrc->a[0].iCursor;
148402 for(i=0; i<nSubSrc; i++){
148403 SrcItem *pItem = &pSrc->a[i+iFrom];
148404 assert( pItem->fg.isTabFunc==0 );
148405 assert( pItem->fg.isSubquery
148406 || pItem->fg.fixedSchema
148407 || pItem->u4.zDatabase==0 );
148408 if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
148409 *pItem = pSubSrc->a[i];
148410 pItem->fg.jointype |= ltorj;
 
148411 memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
148412 }
148413 pSrc->a[iFrom].fg.jointype &= JT_LTORJ;
148414 pSrc->a[iFrom].fg.jointype |= jointype | ltorj;
148415
@@ -148172,10 +148445,11 @@
148445 pSub->pOrderBy = 0;
148446 }
148447 pWhere = pSub->pWhere;
148448 pSub->pWhere = 0;
148449 if( isOuterJoin>0 ){
148450 assert( pSubSrc->nSrc==1 );
148451 sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
148452 }
148453 if( pWhere ){
148454 if( pParent->pWhere ){
148455 pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
@@ -151271,11 +151545,11 @@
151545 sqlite3TreeViewSelect(0, p, 0);
151546 }
151547 #endif
151548 assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
151549 }else{
151550 TREETRACE(0x4000,pParse,p,("WHERE-clause push-down not possible\n"));
151551 }
151552
151553 /* Convert unused result columns of the subquery into simple NULL
151554 ** expressions, to avoid unneeded searching and computation.
151555 ** tag-select-0440
@@ -156980,10 +157254,11 @@
157254 assert( sParse.zErrMsg==0 );
157255 if( !pTab->aCol ){
157256 Table *pNew = sParse.pNewTable;
157257 Index *pIdx;
157258 pTab->aCol = pNew->aCol;
157259 assert( IsOrdinaryTable(pNew) );
157260 sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
157261 pTab->nNVCol = pTab->nCol = pNew->nCol;
157262 pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
157263 pNew->nCol = 0;
157264 pNew->aCol = 0;
@@ -158044,13 +158319,21 @@
158319 SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
158320 const Parse *pParse, /* Parse context */
158321 const WhereInfo *pWInfo, /* WHERE clause */
158322 const WhereLevel *pLevel /* Bloom filter on this level */
158323 );
158324 SQLITE_PRIVATE void sqlite3WhereAddExplainText(
158325 Parse *pParse, /* Parse context */
158326 int addr,
158327 SrcList *pTabList, /* Table list this loop refers to */
158328 WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158329 u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158330 );
158331 #else
158332 # define sqlite3WhereExplainOneScan(u,v,w,x) 0
158333 # define sqlite3WhereExplainBloomFilter(u,v,w) 0
158334 # define sqlite3WhereAddExplainText(u,v,w,x,y)
158335 #endif /* SQLITE_OMIT_EXPLAIN */
158336 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
158337 SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
158338 Vdbe *v, /* Vdbe to add scanstatus entry to */
158339 SrcList *pSrclist, /* FROM clause pLvl reads data from */
@@ -158248,42 +158531,42 @@
158531 }
158532 sqlite3_str_append(pStr, ")", 1);
158533 }
158534
158535 /*
158536 ** This function sets the P4 value of an existing OP_Explain opcode to
158537 ** text describing the loop in pLevel. If the OP_Explain opcode already has
158538 ** a P4 value, it is freed before it is overwritten.
 
 
 
 
158539 */
158540 SQLITE_PRIVATE void sqlite3WhereAddExplainText(
158541 Parse *pParse, /* Parse context */
158542 int addr, /* Address of OP_Explain opcode */
158543 SrcList *pTabList, /* Table list this loop refers to */
158544 WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158545 u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158546 ){
 
158547 #if !defined(SQLITE_DEBUG)
158548 if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
158549 #endif
158550 {
158551 VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe, addr);
158552
158553 SrcItem *pItem = &pTabList->a[pLevel->iFrom];
 
158554 sqlite3 *db = pParse->db; /* Database handle */
158555 int isSearch; /* True for a SEARCH. False for SCAN. */
158556 WhereLoop *pLoop; /* The controlling WhereLoop object */
158557 u32 flags; /* Flags that describe this loop */
158558 #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
158559 char *zMsg; /* Text to add to EQP output */
158560 #endif
158561 StrAccum str; /* EQP output string */
158562 char zBuf[100]; /* Initial space for EQP output string */
158563
158564 if( db->mallocFailed ) return;
158565
158566 pLoop = pLevel->pWLoop;
158567 flags = pLoop->wsFlags;
 
158568
158569 isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
158570 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
158571 || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
158572
@@ -158303,11 +158586,11 @@
158586 }
158587 }else if( flags & WHERE_PARTIALIDX ){
158588 zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
158589 }else if( flags & WHERE_AUTO_INDEX ){
158590 zFmt = "AUTOMATIC COVERING INDEX";
158591 }else if( flags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){
158592 zFmt = "COVERING INDEX %s";
158593 }else{
158594 zFmt = "INDEX %s";
158595 }
158596 if( zFmt ){
@@ -158355,15 +158638,54 @@
158638 sqlite3LogEstToInt(pLoop->nOut));
158639 }else{
158640 sqlite3_str_append(&str, " (~1 row)", 9);
158641 }
158642 #endif
158643 #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
158644 zMsg = sqlite3StrAccumFinish(&str);
158645 sqlite3ExplainBreakpoint("",zMsg);
158646 #endif
158647
158648 assert( pOp->opcode==OP_Explain );
158649 assert( pOp->p4type==P4_DYNAMIC || pOp->p4.z==0 );
158650 sqlite3DbFree(db, pOp->p4.z);
158651 pOp->p4type = P4_DYNAMIC;
158652 pOp->p4.z = sqlite3StrAccumFinish(&str);
158653 }
158654 }
158655
158656
158657 /*
158658 ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
158659 ** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
158660 ** was defined at compile-time. If it is not a no-op, a single OP_Explain
158661 ** opcode is added to the output to describe the table scan strategy in pLevel.
158662 **
158663 ** If an OP_Explain opcode is added to the VM, its address is returned.
158664 ** Otherwise, if no OP_Explain is coded, zero is returned.
158665 */
158666 SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
158667 Parse *pParse, /* Parse context */
158668 SrcList *pTabList, /* Table list this loop refers to */
158669 WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
158670 u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
158671 ){
158672 int ret = 0;
158673 #if !defined(SQLITE_DEBUG)
158674 if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
158675 #endif
158676 {
158677 if( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0
158678 && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
158679 ){
158680 Vdbe *v = pParse->pVdbe;
158681 int addr = sqlite3VdbeCurrentAddr(v);
158682 ret = sqlite3VdbeAddOp3(
158683 v, OP_Explain, addr, pParse->addrExplain, pLevel->pWLoop->rRun
158684 );
158685 sqlite3WhereAddExplainText(pParse, addr, pTabList, pLevel, wctrlFlags);
158686 }
158687 }
158688 return ret;
158689 }
158690
158691 /*
@@ -158458,13 +158780,14 @@
158780 if( wsFlags & WHERE_INDEXED ){
158781 sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
158782 }
158783 }else{
158784 int addr;
158785 VdbeOp *pOp;
158786 assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
158787 addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
158788 pOp = sqlite3VdbeGetOp(v, addr-1);
158789 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
158790 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
158791 sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
158792 }
158793 }
@@ -158713,10 +159036,11 @@
159036 if( pOrigLhs ){
159037 sqlite3ExprListDelete(db, pOrigLhs);
159038 pNew->pLeft->x.pList = pLhs;
159039 }
159040 pSelect->pEList = pRhs;
159041 pSelect->selId = ++pParse->nSelect; /* Req'd for SubrtnSig validity */
159042 if( pLhs && pLhs->nExpr==1 ){
159043 /* Take care here not to generate a TK_VECTOR containing only a
159044 ** single value. Since the parser never creates such a vector, some
159045 ** of the subroutines do not handle this case. */
159046 Expr *p = pLhs->a[0].pExpr;
@@ -161260,24 +161584,29 @@
161584 }else if( op==TK_STRING ){
161585 assert( !ExprHasProperty(pRight, EP_IntValue) );
161586 z = (u8*)pRight->u.zToken;
161587 }
161588 if( z ){
161589 /* Count the number of prefix bytes prior to the first wildcard.
161590 ** or U+fffd character. If the underlying database has a UTF16LE
161591 ** encoding, then only consider ASCII characters. Note that the
161592 ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in
161593 ** this code, but the database engine itself might be processing
161594 ** content using a different encoding. */
161595 cnt = 0;
161596 while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
161597 cnt++;
161598 if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
161599 cnt++;
161600 }else if( c>=0x80 ){
161601 const u8 *z2 = z+cnt-1;
161602 if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){
161603 cnt--;
161604 break;
161605 }else{
161606 cnt = (int)(z2-z);
161607 }
161608 }
161609 }
161610
161611 /* The optimization is possible only if (1) the pattern does not begin
161612 ** with a wildcard and if (2) the non-wildcard prefix does not end with
@@ -161285,11 +161614,11 @@
161614 ** a single escape character. The second condition is necessary so
161615 ** that we can increment the prefix key to find an upper bound for the
161616 ** range search. The third is because the caller assumes that the pattern
161617 ** consists of at least one character after all escapes have been
161618 ** removed. */
161619 if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){
161620 Expr *pPrefix;
161621
161622 /* A "complete" match if the pattern ends with "*" or "%" */
161623 *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
161624
@@ -163780,11 +164109,11 @@
164109 || pTerm->pExpr->w.iJoin != pSrc->iCursor
164110 ){
164111 return 0;
164112 }
164113 if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
164114 && NEVER(ExprHasProperty(pTerm->pExpr, EP_InnerON))
164115 ){
164116 return 0;
164117 }
164118 return 1;
164119 }
@@ -164577,13 +164906,15 @@
164906 ** Whether or not an error is returned, it is the responsibility of the
164907 ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
164908 ** that this is required.
164909 */
164910 static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
 
164911 int rc;
164912 sqlite3_vtab *pVtab;
164913
164914 assert( IsVirtual(pTab) );
164915 pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
164916 whereTraceIndexInfoInputs(p, pTab);
164917 pParse->db->nSchemaLock++;
164918 rc = pVtab->pModule->xBestIndex(pVtab, p);
164919 pParse->db->nSchemaLock--;
164920 whereTraceIndexInfoOutputs(p, pTab);
@@ -165271,11 +165602,11 @@
165602 return rc;
165603 }
165604 #endif /* SQLITE_ENABLE_STAT4 */
165605
165606
165607 #if defined(WHERETRACE_ENABLED) || defined(SQLITE_DEBUG)
165608 /*
165609 ** Print the content of a WhereTerm object
165610 */
165611 SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
165612 if( pTerm==0 ){
@@ -165314,10 +165645,13 @@
165645 sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
165646 }
165647 sqlite3DebugPrintf("\n");
165648 sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
165649 }
165650 }
165651 SQLITE_PRIVATE void sqlite3ShowWhereTerm(WhereTerm *pTerm){
165652 sqlite3WhereTermPrint(pTerm, 0);
165653 }
165654 #endif
165655
165656 #ifdef WHERETRACE_ENABLED
165657 /*
@@ -165522,11 +165856,11 @@
165856 ** Return TRUE if X is a proper subset of Y but is of equal or less cost.
165857 ** In other words, return true if all constraints of X are also part of Y
165858 ** and Y has additional constraints that might speed the search that X lacks
165859 ** but the cost of running X is not more than the cost of running Y.
165860 **
165861 ** In other words, return true if the cost relationship between X and Y
165862 ** is inverted and needs to be adjusted.
165863 **
165864 ** Case 1:
165865 **
165866 ** (1a) X and Y use the same index.
@@ -166500,11 +166834,10 @@
166834 pParse = pWC->pWInfo->pParse;
166835 while( pWhere->op==TK_AND ){
166836 if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0;
166837 pWhere = pWhere->pRight;
166838 }
 
166839 for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
166840 Expr *pExpr;
166841 pExpr = pTerm->pExpr;
166842 if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
166843 && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
@@ -169140,10 +169473,11 @@
169473 hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
169474 for(i=pWInfo->nLevel-1; i>=1; i--){
169475 WhereTerm *pTerm, *pEnd;
169476 SrcItem *pItem;
169477 WhereLoop *pLoop;
169478 Bitmask m1;
169479 pLoop = pWInfo->a[i].pWLoop;
169480 pItem = &pWInfo->pTabList->a[pLoop->iTab];
169481 if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue;
169482 if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0
169483 && (pLoop->wsFlags & WHERE_ONEROW)==0
@@ -169160,17 +169494,20 @@
169494 break;
169495 }
169496 }
169497 if( hasRightJoin
169498 && ExprHasProperty(pTerm->pExpr, EP_InnerON)
169499 && NEVER(pTerm->pExpr->w.iJoin==pItem->iCursor)
169500 ){
169501 break; /* restriction (5) */
169502 }
169503 }
169504 if( pTerm<pEnd ) continue;
169505 WHERETRACE(0xffffffff,("-> omit unused FROM-clause term %c\n",pLoop->cId));
169506 m1 = MASKBIT(i)-1;
169507 testcase( ((pWInfo->revMask>>1) & ~m1)!=0 );
169508 pWInfo->revMask = (m1 & pWInfo->revMask) | ((pWInfo->revMask>>1) & ~m1);
169509 notReady &= ~pLoop->maskSelf;
169510 for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
169511 if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
169512 pTerm->wtFlags |= TERM_CODED;
169513 }
@@ -169237,62 +169574,10 @@
169574 nSearch += pLoop->nOut;
169575 if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta;
169576 }
169577 }
169578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169579 /*
169580 ** The index pIdx is used by a query and contains one or more expressions.
169581 ** In other words pIdx is an index on an expression. iIdxCur is the cursor
169582 ** number for the index and iDataCur is the cursor number for the corresponding
169583 ** table.
@@ -169322,16 +169607,10 @@
169607 pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
169608 }else{
169609 continue;
169610 }
169611 if( sqlite3ExprIsConstant(0,pExpr) ) continue;
 
 
 
 
 
 
169612 p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
169613 if( p==0 ) break;
169614 p->pIENext = pParse->pIdxEpr;
169615 #ifdef WHERETRACE_ENABLED
169616 if( sqlite3WhereTrace & 0x200 ){
@@ -170434,18 +170713,32 @@
170713 x = sqlite3TableColumnToIndex(pIdx, x);
170714 if( x>=0 ){
170715 pOp->p2 = x;
170716 pOp->p1 = pLevel->iIdxCur;
170717 OpcodeRewriteTrace(db, k, pOp);
170718 }else if( pLoop->wsFlags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){
 
 
 
 
170719 if( pLoop->wsFlags & WHERE_IDX_ONLY ){
170720 /* An error. pLoop is supposed to be a covering index loop,
170721 ** and yet the VM code refers to a column of the table that
170722 ** is not part of the index. */
170723 sqlite3ErrorMsg(pParse, "internal query planner error");
170724 pParse->rc = SQLITE_INTERNAL;
170725 }else{
170726 /* The WHERE_EXPRIDX flag is set by the planner when it is likely
170727 ** that pLoop is a covering index loop, but it is not possible
170728 ** to be 100% sure. In this case, any OP_Explain opcode
170729 ** corresponding to this loop describes the index as a "COVERING
170730 ** INDEX". But, pOp proves that pLoop is not actually a covering
170731 ** index loop. So clear the WHERE_EXPRIDX flag and rewrite the
170732 ** text that accompanies the OP_Explain opcode, if any. */
170733 pLoop->wsFlags &= ~WHERE_EXPRIDX;
170734 sqlite3WhereAddExplainText(pParse,
170735 pLevel->addrBody-1,
170736 pTabList,
170737 pLevel,
170738 pWInfo->wctrlFlags
170739 );
170740 }
170741 }
170742 }else if( pOp->opcode==OP_Rowid ){
170743 pOp->p1 = pLevel->iIdxCur;
170744 pOp->opcode = OP_IdxRowid;
@@ -172149,10 +172442,11 @@
172442 for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
172443 FuncDef *pFunc = pWin->pWFunc;
172444 int regArg;
172445 int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
172446 int i;
172447 int addrIf = 0;
172448
172449 assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
172450
172451 /* All OVER clauses in the same window function aggregate step must
172452 ** be the same. */
@@ -172164,10 +172458,22 @@
172458 }else{
172459 sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
172460 }
172461 }
172462 regArg = reg;
172463
172464 if( pWin->pFilter ){
172465 int regTmp;
172466 assert( ExprUseXList(pWin->pOwner) );
172467 assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
172468 assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
172469 regTmp = sqlite3GetTempReg(pParse);
172470 sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
172471 addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
172472 VdbeCoverage(v);
172473 sqlite3ReleaseTempReg(pParse, regTmp);
172474 }
172475
172476 if( pMWin->regStartRowid==0
172477 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
172478 && (pWin->eStart!=TK_UNBOUNDED)
172479 ){
@@ -172184,29 +172490,17 @@
172490 sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
172491 sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
172492 }
172493 sqlite3VdbeJumpHere(v, addrIsNull);
172494 }else if( pWin->regApp ){
172495 assert( pWin->pFilter==0 );
172496 assert( pFunc->zName==nth_valueName
172497 || pFunc->zName==first_valueName
172498 );
172499 assert( bInverse==0 || bInverse==1 );
172500 sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
172501 }else if( pFunc->xSFunc!=noopStepFunc ){
 
 
 
 
 
 
 
 
 
 
 
 
 
172502 if( pWin->bExprArgs ){
172503 int iOp = sqlite3VdbeCurrentAddr(v);
172504 int iEnd;
172505
172506 assert( ExprUseXList(pWin->pOwner) );
@@ -172233,12 +172527,13 @@
172527 sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
172528 sqlite3VdbeChangeP5(v, (u8)nArg);
172529 if( pWin->bExprArgs ){
172530 sqlite3ReleaseTempRange(pParse, regArg, nArg);
172531 }
 
172532 }
172533
172534 if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
172535 }
172536 }
172537
172538 /*
172539 ** Values that may be passed as the second argument to windowCodeOp().
@@ -173660,10 +173955,17 @@
173955 ** Then the "b" IdList records the list "a,b,c".
173956 */
173957 struct TrigEvent { int a; IdList * b; };
173958
173959 struct FrameBound { int eType; Expr *pExpr; };
173960
173961 /*
173962 ** Generate a syntax error
173963 */
173964 static void parserSyntaxError(Parse *pParse, Token *p){
173965 sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", p);
173966 }
173967
173968 /*
173969 ** Disable lookaside memory allocation for objects that might be
173970 ** shared across database connections.
173971 */
@@ -177553,11 +177855,15 @@
177855 }
177856 break;
177857 case 84: /* cmd ::= select */
177858 {
177859 SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
177860 if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0
177861 || sqlite3ReadSchema(pParse)==SQLITE_OK
177862 ){
177863 sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
177864 }
177865 sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
177866 }
177867 break;
177868 case 85: /* select ::= WITH wqlist selectnowith */
177869 {yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
@@ -178024,11 +178330,11 @@
178330 ** that look like this: #1 #2 ... These terms refer to registers
178331 ** in the virtual machine. #N is the N-th register. */
178332 Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
178333 assert( t.n>=2 );
178334 if( pParse->nested==0 ){
178335 parserSyntaxError(pParse, &t);
178336 yymsp[0].minor.yy454 = 0;
178337 }else{
178338 yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
178339 if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
178340 }
@@ -178872,11 +179178,11 @@
179178 #define TOKEN yyminor
179179 /************ Begin %syntax_error code ****************************************/
179180
179181 UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
179182 if( TOKEN.z[0] ){
179183 parserSyntaxError(pParse, &TOKEN);
179184 }else{
179185 sqlite3ErrorMsg(pParse, "incomplete input");
179186 }
179187 /************ End %syntax_error code ******************************************/
179188 sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
@@ -180363,11 +180669,13 @@
180669 }
180670 if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
180671 if( pParse->zErrMsg==0 ){
180672 pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
180673 }
180674 if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){
180675 sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
180676 }
180677 nErr++;
180678 }
180679 pParse->zTail = zSql;
180680 #ifndef SQLITE_OMIT_VIRTUALTABLE
180681 sqlite3_free(pParse->apVtabLock);
@@ -181071,36 +181379,10 @@
181379 ** all database files specified with a relative pathname.
181380 **
181381 ** See also the "PRAGMA data_store_directory" SQL command.
181382 */
181383 SQLITE_API char *sqlite3_data_directory = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181384
181385 /*
181386 ** Initialize SQLite.
181387 **
181388 ** This routine must be called to initialize the memory allocation,
@@ -181292,17 +181574,10 @@
181574 if( bRunExtraInit ){
181575 int SQLITE_EXTRA_INIT(const char*);
181576 rc = SQLITE_EXTRA_INIT(0);
181577 }
181578 #endif
 
 
 
 
 
 
 
181579 return rc;
181580 }
181581
181582 /*
181583 ** Undo the effects of sqlite3_initialize(). Must not be called while
@@ -182369,14 +182644,10 @@
182644 #endif
182645
182646 sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
182647 sqlite3ValueFree(db->pErr);
182648 sqlite3CloseExtensions(db);
 
 
 
 
182649
182650 db->eOpenState = SQLITE_STATE_ERROR;
182651
182652 /* The temp-database schema is allocated differently from the other schema
182653 ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
@@ -183875,12 +184146,12 @@
184146 }
184147 oldLimit = db->aLimit[limitId];
184148 if( newLimit>=0 ){ /* IMP: R-52476-28732 */
184149 if( newLimit>aHardLimit[limitId] ){
184150 newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
184151 }else if( newLimit<SQLITE_MIN_LENGTH && limitId==SQLITE_LIMIT_LENGTH ){
184152 newLimit = SQLITE_MIN_LENGTH;
184153 }
184154 db->aLimit[limitId] = newLimit;
184155 }
184156 return oldLimit; /* IMP: R-53341-35419 */
184157 }
@@ -184395,10 +184666,11 @@
184666 testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
184667 testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
184668 if( ((1<<(flags&7)) & 0x46)==0 ){
184669 rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
184670 }else{
184671 if( zFilename==0 ) zFilename = ":memory:";
184672 rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
184673 }
184674 if( rc!=SQLITE_OK ){
184675 if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
184676 sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
@@ -185237,10 +185509,11 @@
185509 #ifndef SQLITE_OMIT_WINDOWFUNC
185510 sqlite3ShowWindow(0);
185511 sqlite3ShowWinFunc(0);
185512 #endif
185513 sqlite3ShowSelect(0);
185514 sqlite3ShowWhereTerm(0);
185515 }
185516 #endif
185517 break;
185518 }
185519
@@ -185549,28 +185822,10 @@
185822 *pI1 = rLogEst;
185823 *pU64 = sqlite3LogEstToInt(rLogEst);
185824 *pI2 = sqlite3LogEst(*pU64);
185825 break;
185826 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185827
185828 #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
185829 /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
185830 **
185831 ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value
@@ -185875,11 +186130,15 @@
186130 if( db->autoCommit==0 ){
186131 int iDb = sqlite3FindDbName(db, zDb);
186132 if( iDb==0 || iDb>1 ){
186133 Btree *pBt = db->aDb[iDb].pBt;
186134 if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
186135 Pager *pPager = sqlite3BtreePager(pBt);
186136 i64 dummy = 0;
186137 sqlite3PagerSnapshotOpen(pPager, (sqlite3_snapshot*)&dummy);
186138 rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
186139 sqlite3PagerSnapshotOpen(pPager, 0);
186140 if( rc==SQLITE_OK ){
186141 rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
186142 }
186143 }
186144 }
@@ -189665,14 +189924,19 @@
189924
189925 assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
189926 if( *p1==POS_COLUMN ){
189927 p1++;
189928 p1 += fts3GetVarint32(p1, &iCol1);
189929 /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN
189930 ** entry, so this is actually end-of-doclist. */
189931 if( iCol1==0 ) return 0;
189932 }
189933 if( *p2==POS_COLUMN ){
189934 p2++;
189935 p2 += fts3GetVarint32(p2, &iCol2);
189936 /* As above, iCol2==0 indicates corruption. */
189937 if( iCol2==0 ) return 0;
189938 }
189939
189940 while( 1 ){
189941 if( iCol1==iCol2 ){
189942 char *pSave = p;
@@ -192839,11 +193103,11 @@
193103 for(p=pExpr; p->pLeft; p=p->pLeft){
193104 assert( p->pRight->pPhrase->doclist.nList>0 );
193105 nTmp += p->pRight->pPhrase->doclist.nList;
193106 }
193107 nTmp += p->pPhrase->doclist.nList;
193108 aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX);
193109 if( !aTmp ){
193110 *pRc = SQLITE_NOMEM;
193111 res = 0;
193112 }else{
193113 char *aPoslist = p->pPhrase->doclist.pList;
@@ -193490,11 +193754,11 @@
193754 SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
193755 return SQLITE_CORRUPT_VTAB;
193756 }
193757 #endif
193758
193759 #if !defined(SQLITE_CORE)
193760 /*
193761 ** Initialize API pointer table, if required.
193762 */
193763 #ifdef _WIN32
193764 __declspec(dllexport)
@@ -194392,14 +194656,15 @@
194656 rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
194657 if( rc==SQLITE_OK ){
194658 Fts3PhraseToken *pToken;
194659
194660 p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
 
 
194661 zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
194662 if( !zTemp || !p ){
194663 rc = SQLITE_NOMEM;
194664 goto getnextstring_out;
194665 }
194666
194667 assert( nToken==ii );
194668 pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
194669 memset(pToken, 0, sizeof(Fts3PhraseToken));
194670
@@ -194410,53 +194675,51 @@
194675 pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
194676 pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
194677 nToken = ii+1;
194678 }
194679 }
 
 
 
194680 }
194681
194682 if( rc==SQLITE_DONE ){
194683 int jj;
194684 char *zBuf = 0;
194685
194686 p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
194687 if( !p ){
194688 rc = SQLITE_NOMEM;
194689 goto getnextstring_out;
194690 }
194691 memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
194692 p->eType = FTSQUERY_PHRASE;
194693 p->pPhrase = (Fts3Phrase *)&p[1];
194694 p->pPhrase->iColumn = pParse->iDefaultCol;
194695 p->pPhrase->nToken = nToken;
194696
194697 zBuf = (char *)&p->pPhrase->aToken[nToken];
194698 assert( nTemp==0 || zTemp );
194699 if( zTemp ){
194700 memcpy(zBuf, zTemp, nTemp);
 
 
 
194701 }
194702
194703 for(jj=0; jj<p->pPhrase->nToken; jj++){
194704 p->pPhrase->aToken[jj].z = zBuf;
194705 zBuf += p->pPhrase->aToken[jj].n;
194706 }
194707 rc = SQLITE_OK;
194708 }
194709
194710 getnextstring_out:
 
 
 
194711 if( pCursor ){
194712 pModule->xClose(pCursor);
194713 }
194714 sqlite3_free(zTemp);
194715 if( rc!=SQLITE_OK ){
194716 sqlite3_free(p);
194717 p = 0;
194718 }
194719 *ppExpr = p;
194720 return rc;
194721 }
194722
194723 /*
194724 ** The output variable *ppExpr is populated with an allocated Fts3Expr
194725 ** structure, or set to 0 if the end of the input buffer is reached.
@@ -208867,11 +209130,13 @@
209130 int rawKey = 1;
209131 x = pParse->aBlob[iRoot];
209132 zPath++;
209133 if( zPath[0]=='"' ){
209134 zKey = zPath + 1;
209135 for(i=1; zPath[i] && zPath[i]!='"'; i++){
209136 if( zPath[i]=='\\' && zPath[i+1]!=0 ) i++;
209137 }
209138 nKey = i-1;
209139 if( zPath[i] ){
209140 i++;
209141 }else{
209142 return JSON_LOOKUP_PATHERROR;
@@ -217779,11 +218044,11 @@
218044 return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
218045 (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
218046 );
218047 }
218048
218049 #ifndef SQLITE_CORE
218050 #ifdef _WIN32
218051 __declspec(dllexport)
218052 #endif
218053 SQLITE_API int sqlite3_rtree_init(
218054 sqlite3 *db,
@@ -218370,11 +218635,11 @@
218635 }
218636
218637 return rc;
218638 }
218639
218640 #ifndef SQLITE_CORE
218641 #ifdef _WIN32
218642 __declspec(dllexport)
218643 #endif
218644 SQLITE_API int sqlite3_icu_init(
218645 sqlite3 *db,
@@ -219628,10 +219893,31 @@
219893 struct RbuFrame {
219894 u32 iDbPage;
219895 u32 iWalFrame;
219896 };
219897
219898 #ifndef UNUSED_PARAMETER
219899 /*
219900 ** The following macros are used to suppress compiler warnings and to
219901 ** make it clear to human readers when a function parameter is deliberately
219902 ** left unused within the body of a function. This usually happens when
219903 ** a function is called via a function pointer. For example the
219904 ** implementation of an SQL aggregate step callback may not use the
219905 ** parameter indicating the number of arguments passed to the aggregate,
219906 ** if it knows that this is enforced elsewhere.
219907 **
219908 ** When a function parameter is not used at all within the body of a function,
219909 ** it is generally named "NotUsed" or "NotUsed2" to make things even clearer.
219910 ** However, these macros may also be used to suppress warnings related to
219911 ** parameters that may or may not be used depending on compilation options.
219912 ** For example those parameters only used in assert() statements. In these
219913 ** cases the parameters are named as per the usual conventions.
219914 */
219915 #define UNUSED_PARAMETER(x) (void)(x)
219916 #define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
219917 #endif
219918
219919 /*
219920 ** RBU handle.
219921 **
219922 ** nPhaseOneStep:
219923 ** If the RBU database contains an rbu_count table, this value is set to
@@ -219679,11 +219965,11 @@
219965 char *zState; /* Path to state db (or NULL if zRbu) */
219966 char zStateDb[5]; /* Db name for state ("stat" or "main") */
219967 int rc; /* Value returned by last rbu_step() call */
219968 char *zErrmsg; /* Error message if rc!=SQLITE_OK */
219969 int nStep; /* Rows processed for current object */
219970 sqlite3_int64 nProgress; /* Rows processed for all objects */
219971 RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
219972 const char *zVfsName; /* Name of automatically created rbu vfs */
219973 rbu_file *pTargetFd; /* File handle open on target db */
219974 int nPagePerSector; /* Pages per sector for pTargetFd */
219975 i64 iOalSz;
@@ -219796,11 +220082,11 @@
220082 unsigned char *zStart = z;
220083 while( (c = zValue[0x7f&*(z++)])>=0 ){
220084 v = (v<<6) + c;
220085 }
220086 z--;
220087 *pLen -= (int)(z - zStart);
220088 *pz = (char*)z;
220089 return v;
220090 }
220091
220092 #if RBU_ENABLE_DELTA_CKSUM
@@ -219981,10 +220267,11 @@
220267 int nOut;
220268 int nOut2;
220269 char *aOut;
220270
220271 assert( argc==2 );
220272 UNUSED_PARAMETER(argc);
220273
220274 nOrig = sqlite3_value_bytes(argv[0]);
220275 aOrig = (const char*)sqlite3_value_blob(argv[0]);
220276 nDelta = sqlite3_value_bytes(argv[1]);
220277 aDelta = (const char*)sqlite3_value_blob(argv[1]);
@@ -221560,17 +221847,17 @@
221847 nParen++;
221848 }
221849 else if( c==')' ){
221850 nParen--;
221851 if( nParen==0 ){
221852 int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
221853 pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
221854 i++;
221855 break;
221856 }
221857 }else if( c==',' && nParen==1 ){
221858 int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
221859 pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
221860 pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
221861 }else if( c=='"' || c=='\'' || c=='`' ){
221862 for(i++; 1; i++){
221863 if( zSql[i]==c ){
@@ -222256,10 +222543,12 @@
222543 int i, sz;
222544 sz = (int)strlen(z)&0xffffff;
222545 for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
222546 if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
222547 }
222548 #else
222549 UNUSED_PARAMETER2(zBase,z);
222550 #endif
222551 }
222552
222553 /*
222554 ** Return the current wal-index header checksum for the target database
@@ -222840,11 +223129,11 @@
223129 "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
223130 "(%d, %d), "
223131 "(%d, %Q), "
223132 "(%d, %Q), "
223133 "(%d, %d), "
223134 "(%d, %lld), "
223135 "(%d, %lld), "
223136 "(%d, %lld), "
223137 "(%d, %lld), "
223138 "(%d, %lld), "
223139 "(%d, %Q) ",
@@ -223198,10 +223487,11 @@
223487 char *zErrmsg = 0;
223488 int rc;
223489 sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
223490
223491 assert( nVal==1 );
223492 UNUSED_PARAMETER(nVal);
223493
223494 rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
223495 sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
223496 "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
223497 );
@@ -223473,11 +223763,11 @@
223763 const char *zTarget,
223764 const char *zState
223765 ){
223766 if( zTarget==0 ){ return rbuMisuseError(); }
223767 if( zState ){
223768 size_t n = strlen(zState);
223769 if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
223770 return rbuMisuseError();
223771 }
223772 }
223773 /* TODO: Check that both arguments are non-NULL */
@@ -223690,10 +223980,11 @@
223980 /*
223981 ** Default xRename callback for RBU.
223982 */
223983 static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
223984 int rc = SQLITE_OK;
223985 UNUSED_PARAMETER(pArg);
223986 #if defined(_WIN32_WCE)
223987 {
223988 LPWSTR zWideOld;
223989 LPWSTR zWideNew;
223990
@@ -224594,10 +224885,13 @@
224885
224886 /*
224887 ** No-op.
224888 */
224889 static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
224890 UNUSED_PARAMETER(pVfs);
224891 UNUSED_PARAMETER(a);
224892 UNUSED_PARAMETER(b);
224893 return 0;
224894 }
224895
224896 /*
224897 ** Deregister and destroy an RBU vfs created by an earlier call to
@@ -225650,11 +225944,17 @@
225944 ** schema for the database file that is to be read. The default schema is
225945 ** "main".
225946 **
225947 ** The data field of sqlite_dbpage table can be updated. The new
225948 ** value must be a BLOB which is the correct page size, otherwise the
225949 ** update fails. INSERT operations also work, and operate as if they
225950 ** where REPLACE. The size of the database can be extended by INSERT-ing
225951 ** new pages on the end.
225952 **
225953 ** Rows may not be deleted. However, doing an INSERT to page number N
225954 ** with NULL page data causes the N-th page and all subsequent pages to be
225955 ** deleted and the database to be truncated.
225956 */
225957
225958 /* #include "sqliteInt.h" ** Requires access to internal data structures ** */
225959 #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
225960 && !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -225673,17 +225973,18 @@
225973 };
225974
225975 struct DbpageTable {
225976 sqlite3_vtab base; /* Base class. Must be first */
225977 sqlite3 *db; /* The database */
225978 int iDbTrunc; /* Database to truncate */
225979 Pgno pgnoTrunc; /* Size to truncate to */
225980 };
225981
225982 /* Columns */
225983 #define DBPAGE_COLUMN_PGNO 0
225984 #define DBPAGE_COLUMN_DATA 1
225985 #define DBPAGE_COLUMN_SCHEMA 2
 
225986
225987
225988 /*
225989 ** Connect to or create a dbpagevfs virtual table.
225990 */
@@ -225943,15 +226244,15 @@
226244 DbpageTable *pTab = (DbpageTable *)pVtab;
226245 Pgno pgno;
226246 DbPage *pDbPage = 0;
226247 int rc = SQLITE_OK;
226248 char *zErr = 0;
 
226249 int iDb;
226250 Btree *pBt;
226251 Pager *pPager;
226252 int szPage;
226253 int isInsert;
226254
226255 (void)pRowid;
226256 if( pTab->db->flags & SQLITE_Defensive ){
226257 zErr = "read-only";
226258 goto update_fail;
@@ -225958,45 +226259,62 @@
226259 }
226260 if( argc==1 ){
226261 zErr = "cannot delete";
226262 goto update_fail;
226263 }
226264 if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
226265 pgno = (Pgno)sqlite3_value_int(argv[2]);
226266 isInsert = 1;
226267 }else{
226268 pgno = sqlite3_value_int(argv[0]);
226269 if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
226270 zErr = "cannot insert";
226271 goto update_fail;
226272 }
226273 isInsert = 0;
226274 }
226275 if( sqlite3_value_type(argv[4])==SQLITE_NULL ){
226276 iDb = 0;
226277 }else{
226278 const char *zSchema = (const char*)sqlite3_value_text(argv[4]);
226279 iDb = sqlite3FindDbName(pTab->db, zSchema);
226280 if( iDb<0 ){
226281 zErr = "no such schema";
226282 goto update_fail;
226283 }
226284 }
226285 pBt = pTab->db->aDb[iDb].pBt;
226286 if( pgno<1 || NEVER(pBt==0) ){
226287 zErr = "bad page number";
226288 goto update_fail;
226289 }
226290 szPage = sqlite3BtreeGetPageSize(pBt);
226291 if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
226292 || sqlite3_value_bytes(argv[3])!=szPage
226293 ){
226294 if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){
226295 /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and
226296 ** all subsequent pages to be deleted. */
226297 pTab->iDbTrunc = iDb;
226298 pgno--;
226299 pTab->pgnoTrunc = pgno;
226300 }else{
226301 zErr = "bad page value";
226302 goto update_fail;
226303 }
226304 }
226305 pPager = sqlite3BtreePager(pBt);
226306 rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
226307 if( rc==SQLITE_OK ){
226308 const void *pData = sqlite3_value_blob(argv[3]);
226309 if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
226310 unsigned char *aPage = sqlite3PagerGetData(pDbPage);
226311 memcpy(aPage, pData, szPage);
226312 pTab->pgnoTrunc = 0;
 
226313 }
226314 }else{
226315 pTab->pgnoTrunc = 0;
226316 }
226317 sqlite3PagerUnref(pDbPage);
226318 return rc;
226319
226320 update_fail:
@@ -226015,13 +226333,35 @@
226333 int i;
226334 for(i=0; i<db->nDb; i++){
226335 Btree *pBt = db->aDb[i].pBt;
226336 if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
226337 }
226338 pTab->pgnoTrunc = 0;
226339 return SQLITE_OK;
226340 }
226341
226342 /* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT
226343 */
226344 static int dbpageSync(sqlite3_vtab *pVtab){
226345 DbpageTable *pTab = (DbpageTable *)pVtab;
226346 if( pTab->pgnoTrunc>0 ){
226347 Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt;
226348 Pager *pPager = sqlite3BtreePager(pBt);
226349 sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc);
226350 }
226351 pTab->pgnoTrunc = 0;
226352 return SQLITE_OK;
226353 }
226354
226355 /* Cancel any pending truncate.
226356 */
226357 static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){
226358 DbpageTable *pTab = (DbpageTable *)pVtab;
226359 pTab->pgnoTrunc = 0;
226360 (void)notUsed1;
226361 return SQLITE_OK;
226362 }
 
226363
226364 /*
226365 ** Invoke this routine to register the "dbpage" virtual table module
226366 */
226367 SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
@@ -226039,18 +226379,18 @@
226379 dbpageEof, /* xEof - check for end of scan */
226380 dbpageColumn, /* xColumn - read data */
226381 dbpageRowid, /* xRowid - read data */
226382 dbpageUpdate, /* xUpdate */
226383 dbpageBegin, /* xBegin */
226384 dbpageSync, /* xSync */
226385 0, /* xCommit */
226386 0, /* xRollback */
226387 0, /* xFindMethod */
226388 0, /* xRename */
226389 0, /* xSavepoint */
226390 0, /* xRelease */
226391 dbpageRollbackTo, /* xRollbackTo */
226392 0, /* xShadowName */
226393 0 /* xIntegrity */
226394 };
226395 return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
226396 }
@@ -226134,10 +226474,14 @@
226474 /*
226475 ** An object of this type is used internally as an abstraction for
226476 ** input data. Input data may be supplied either as a single large buffer
226477 ** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
226478 ** sqlite3changeset_start_strm()).
226479 **
226480 ** bNoDiscard:
226481 ** If true, then the only time data is discarded is as a result of explicit
226482 ** sessionDiscardData() calls. Not within every sessionInputBuffer() call.
226483 */
226484 struct SessionInput {
226485 int bNoDiscard; /* If true, do not discard in InputBuffer() */
226486 int iCurrent; /* Offset in aData[] of current change */
226487 int iNext; /* Offset in aData[] of next change */
@@ -227817,20 +228161,23 @@
228161 /* Figure out how large an allocation is required */
228162 nByte = sizeof(SessionChange);
228163 for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
228164 sqlite3_value *p = 0;
228165 if( op!=SQLITE_INSERT ){
228166 /* This may fail if the column has a non-NULL default and was added
228167 ** using ALTER TABLE ADD COLUMN after this record was created. */
228168 rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
228169 }else if( pTab->abPK[i] ){
228170 TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
228171 assert( trc==SQLITE_OK );
228172 }
228173
228174 if( rc==SQLITE_OK ){
228175 /* This may fail if SQLite value p contains a utf-16 string that must
228176 ** be converted to utf-8 and an OOM error occurs while doing so. */
228177 rc = sessionSerializeValue(0, p, &nByte);
228178 }
228179 if( rc!=SQLITE_OK ) goto error_out;
228180 }
228181 if( pTab->bRowid ){
228182 nByte += 9; /* Size of rowid field - an integer */
228183 }
@@ -231184,19 +231531,25 @@
231531 int rc = SQLITE_OK; /* Return code */
231532 const char *zTab = 0; /* Name of current table */
231533 int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
231534 SessionApplyCtx sApply; /* changeset_apply() context object */
231535 int bPatchset;
231536 u64 savedFlag = db->flags & SQLITE_FkNoAction;
231537
231538 assert( xConflict!=0 );
231539
231540 sqlite3_mutex_enter(sqlite3_db_mutex(db));
231541 if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
231542 db->flags |= ((u64)SQLITE_FkNoAction);
231543 db->aDb[0].pSchema->schema_cookie -= 32;
231544 }
231545
231546 pIter->in.bNoDiscard = 1;
231547 memset(&sApply, 0, sizeof(sApply));
231548 sApply.bRebase = (ppRebase && pnRebase);
231549 sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
231550 sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
 
231551 if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
231552 rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
231553 }
231554 if( rc==SQLITE_OK ){
231555 rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
@@ -231354,10 +231707,16 @@
231707 sqlite3_finalize(sApply.pDelete);
231708 sqlite3_finalize(sApply.pSelect);
231709 sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
231710 sqlite3_free((char*)sApply.constraints.aBuf);
231711 sqlite3_free((char*)sApply.rebase.aBuf);
231712
231713 if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
231714 assert( db->flags & SQLITE_FkNoAction );
231715 db->flags &= ~((u64)SQLITE_FkNoAction);
231716 db->aDb[0].pSchema->schema_cookie -= 32;
231717 }
231718 sqlite3_mutex_leave(sqlite3_db_mutex(db));
231719 return rc;
231720 }
231721
231722 /*
@@ -231382,28 +231741,17 @@
231741 int flags
231742 ){
231743 sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
231744 int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
231745 int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
 
 
 
 
 
 
231746
231747 if( rc==SQLITE_OK ){
231748 rc = sessionChangesetApply(
231749 db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
231750 );
231751 }
231752
 
 
 
 
 
231753 return rc;
231754 }
231755
231756 /*
231757 ** Apply the changeset passed via pChangeset/nChangeset to the main database
@@ -231720,10 +232068,13 @@
232068 if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
232069 /* Append the missing default column values to the record. */
232070 sessionAppendBlob(pOut, aRec, nRec, &rc);
232071 if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
232072 rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
232073 if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){
232074 rc = sqlite3_errcode(pGrp->db);
232075 }
232076 }
232077 for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
232078 int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
232079 sessionAppendByte(pOut, eType, &rc);
232080 switch( eType ){
@@ -231736,10 +232087,11 @@
232087 double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
232088 memcpy(&iVal, &rVal, sizeof(i64));
232089 }
232090 if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
232091 sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
232092 pOut->nBuf += 8;
232093 }
232094 break;
232095 }
232096
232097 case SQLITE_BLOB:
@@ -231874,10 +232226,12 @@
232226 SessionChange *pExist = 0;
232227 SessionChange **pp = 0;
232228 SessionTable *pTab = 0;
232229 u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
232230 int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
232231
232232 assert( nRec>0 );
232233
232234 /* Ensure that only changesets, or only patchsets, but not a mixture
232235 ** of both, are being combined. It is an error to try to combine a
232236 ** changeset and a patchset. */
232237 if( pGrp->pList==0 ){
@@ -231952,10 +232306,11 @@
232306 ){
232307 u8 *aRec;
232308 int nRec;
232309 int rc = SQLITE_OK;
232310
232311 pIter->in.bNoDiscard = 1;
232312 while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
232313 rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
232314 if( rc!=SQLITE_OK ) break;
232315 }
232316
@@ -232583,20 +232938,46 @@
232938 #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
232939
232940 /************** End of sqlite3session.c **************************************/
232941 /************** Begin file fts5.c ********************************************/
232942
232943 /*
232944 ** This, the "fts5.c" source file, is a composite file that is itself
232945 ** assembled from the following files:
232946 **
232947 ** fts5.h
232948 ** fts5Int.h
232949 ** fts5parse.h <--- Generated from fts5parse.y by Lemon
232950 ** fts5parse.c <--- Generated from fts5parse.y by Lemon
232951 ** fts5_aux.c
232952 ** fts5_buffer.c
232953 ** fts5_config.c
232954 ** fts5_expr.c
232955 ** fts5_hash.c
232956 ** fts5_index.c
232957 ** fts5_main.c
232958 ** fts5_storage.c
232959 ** fts5_tokenize.c
232960 ** fts5_unicode2.c
232961 ** fts5_varint.c
232962 ** fts5_vocab.c
232963 */
232964 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
232965
232966 #if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
232967 # define NDEBUG 1
232968 #endif
232969 #if defined(NDEBUG) && defined(SQLITE_DEBUG)
232970 # undef NDEBUG
232971 #endif
232972
232973 #ifdef HAVE_STDINT_H
232974 /* #include <stdint.h> */
232975 #endif
232976 #ifdef HAVE_INTTYPES_H
232977 /* #include <inttypes.h> */
232978 #endif
232979 /*
232980 ** 2014 May 31
232981 **
232982 ** The author disclaims copyright to this source code. In place of
232983 ** a legal notice, here is a blessing:
@@ -232893,17 +233274,32 @@
233274 ** This is used to access token iToken of phrase hit iIdx within the
233275 ** current row. If iIdx is less than zero or greater than or equal to the
233276 ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
233277 ** output variable (*ppToken) is set to point to a buffer containing the
233278 ** matching document token, and (*pnToken) to the size of that buffer in
233279 ** bytes.
 
 
233280 **
233281 ** The output text is not a copy of the document text that was tokenized.
233282 ** It is the output of the tokenizer module. For tokendata=1 tables, this
233283 ** includes any embedded 0x00 and trailing data.
233284 **
233285 ** This API may be slow in some cases if the token identified by parameters
233286 ** iIdx and iToken matched a prefix token in the query. In most cases, the
233287 ** first call to this API for each prefix token in the query is forced
233288 ** to scan the portion of the full-text index that matches the prefix
233289 ** token to collect the extra data required by this API. If the prefix
233290 ** token matches a large number of token instances in the document set,
233291 ** this may be a performance problem.
233292 **
233293 ** If the user knows in advance that a query may use this API for a
233294 ** prefix token, FTS5 may be configured to collect all required data as part
233295 ** of the initial querying of the full-text index, avoiding the second scan
233296 ** entirely. This also causes prefix queries that do not use this API to
233297 ** run more slowly and use more memory. FTS5 may be configured in this way
233298 ** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
233299 ** option, or on a per-query basis using the
233300 ** [fts5_insttoken | fts5_insttoken()] user function.
233301 **
233302 ** This API can be quite slow if used with an FTS5 table created with the
233303 ** "detail=none" or "detail=column" option.
233304 **
233305 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -232991,11 +233387,10 @@
233387 ** CUSTOM TOKENIZERS
233388 **
233389 ** Applications may also register custom tokenizer types. A tokenizer
233390 ** is registered by providing fts5 with a populated instance of the
233391 ** following structure. All structure methods must be defined, setting
 
233392 ** any member of the fts5_tokenizer struct to NULL leads to undefined
233393 ** behaviour. The structure methods are expected to function as follows:
233394 **
233395 ** xCreate:
233396 ** This function is used to allocate and initialize a tokenizer instance.
@@ -233560,10 +233955,11 @@
233955 u8 *abUnindexed; /* True for unindexed columns */
233956 int nPrefix; /* Number of prefix indexes */
233957 int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
233958 int eContent; /* An FTS5_CONTENT value */
233959 int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
233960 int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */
233961 char *zContent; /* content table */
233962 char *zContentRowid; /* "content_rowid=" option value */
233963 int bColumnsize; /* "columnsize=" option value (dflt==1) */
233964 int bTokendata; /* "tokendata=" option value (dflt==0) */
233965 int bLocale; /* "locale=" option value (dflt==0) */
@@ -233582,11 +233978,12 @@
233978 int nUsermerge; /* 'usermerge' setting */
233979 int nHashSize; /* Bytes of memory for in-memory hash */
233980 char *zRank; /* Name of rank function */
233981 char *zRankArgs; /* Arguments to rank function */
233982 int bSecureDelete; /* 'secure-delete' */
233983 int nDeleteMerge; /* 'deletemerge' */
233984 int bPrefixInsttoken; /* 'prefix-insttoken' */
233985
233986 /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
233987 char **pzErrmsg;
233988
233989 #ifdef SQLITE_DEBUG
@@ -233598,13 +233995,14 @@
233995 ** the expected version if the 'secure-delete' option has ever been
233996 ** set on the table. */
233997 #define FTS5_CURRENT_VERSION 4
233998 #define FTS5_CURRENT_VERSION_SECUREDELETE 5
233999
234000 #define FTS5_CONTENT_NORMAL 0
234001 #define FTS5_CONTENT_NONE 1
234002 #define FTS5_CONTENT_EXTERNAL 2
234003 #define FTS5_CONTENT_UNINDEXED 3
234004
234005 #define FTS5_DETAIL_FULL 0
234006 #define FTS5_DETAIL_NONE 1
234007 #define FTS5_DETAIL_COLUMNS 2
234008
@@ -233838,11 +234236,18 @@
234236 static int sqlite3Fts5StructureTest(Fts5Index*, void*);
234237
234238 /*
234239 ** Used by xInstToken():
234240 */
234241 static int sqlite3Fts5IterToken(
234242 Fts5IndexIter *pIndexIter,
234243 const char *pToken, int nToken,
234244 i64 iRowid,
234245 int iCol,
234246 int iOff,
234247 const char **ppOut, int *pnOut
234248 );
234249
234250 /*
234251 ** Insert or remove data to or from the index. Each time a document is
234252 ** added to or removed from the index, this function is called one or more
234253 ** times.
@@ -233972,20 +234377,17 @@
234377
234378 static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
234379
234380 static int sqlite3Fts5FlushToDisk(Fts5Table*);
234381
 
 
 
 
 
 
 
 
 
234382 static void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
234383 static void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc);
234384
234385 static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal);
234386 static int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal,
234387 const char **ppText, int *pnText, const char **ppLoc, int *pnLoc
234388 );
234389
234390 /*
234391 ** End of interface to code in fts5.c.
234392 **************************************************************************/
234393
@@ -234063,11 +234465,11 @@
234465
234466 static int sqlite3Fts5DropAll(Fts5Config*);
234467 static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
234468
234469 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
234470 static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, sqlite3_value**, i64*);
234471 static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
234472
234473 static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
234474
234475 static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
@@ -237270,10 +237672,11 @@
237672 const char *zArg, /* Argument to parse */
237673 char **pzErr /* OUT: Error message */
237674 ){
237675 int rc = SQLITE_OK;
237676 int nCmd = (int)strlen(zCmd);
237677
237678 if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
237679 const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
237680 const char *p;
237681 int bFirst = 1;
237682 if( pConfig->aPrefix==0 ){
@@ -237388,10 +237791,20 @@
237791 }else{
237792 pConfig->bContentlessDelete = (zArg[0]=='1');
237793 }
237794 return rc;
237795 }
237796
237797 if( sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){
237798 if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
237799 *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
237800 rc = SQLITE_ERROR;
237801 }else{
237802 pConfig->bContentlessUnindexed = (zArg[0]=='1');
237803 }
237804 return rc;
237805 }
237806
237807 if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
237808 if( pConfig->zContentRowid ){
237809 *pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
237810 rc = SQLITE_ERROR;
@@ -237506,11 +237919,12 @@
237919
237920 static int fts5ConfigParseColumn(
237921 Fts5Config *p,
237922 char *zCol,
237923 char *zArg,
237924 char **pzErr,
237925 int *pbUnindexed
237926 ){
237927 int rc = SQLITE_OK;
237928 if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
237929 || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
237930 ){
@@ -237517,10 +237931,11 @@
237931 *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
237932 rc = SQLITE_ERROR;
237933 }else if( zArg ){
237934 if( 0==sqlite3_stricmp(zArg, "unindexed") ){
237935 p->abUnindexed[p->nCol] = 1;
237936 *pbUnindexed = 1;
237937 }else{
237938 *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
237939 rc = SQLITE_ERROR;
237940 }
237941 }
@@ -237537,15 +237952,30 @@
237952 int rc = SQLITE_OK;
237953 Fts5Buffer buf = {0, 0, 0};
237954
237955 sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
237956 if( p->eContent!=FTS5_CONTENT_NONE ){
237957 assert( p->eContent==FTS5_CONTENT_EXTERNAL
237958 || p->eContent==FTS5_CONTENT_NORMAL
237959 || p->eContent==FTS5_CONTENT_UNINDEXED
237960 );
237961 for(i=0; i<p->nCol; i++){
237962 if( p->eContent==FTS5_CONTENT_EXTERNAL ){
237963 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
237964 }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){
237965 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
237966 }else{
237967 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
237968 }
237969 }
237970 }
237971 if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){
237972 for(i=0; i<p->nCol; i++){
237973 if( p->abUnindexed[i]==0 ){
237974 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i);
237975 }else{
237976 sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
237977 }
237978 }
237979 }
237980
237981 assert( p->zContentExprlist==0 );
@@ -237575,10 +238005,11 @@
238005 ){
238006 int rc = SQLITE_OK; /* Return code */
238007 Fts5Config *pRet; /* New object to return */
238008 int i;
238009 sqlite3_int64 nByte;
238010 int bUnindexed = 0; /* True if there are one or more UNINDEXED */
238011
238012 *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
238013 if( pRet==0 ) return SQLITE_NOMEM;
238014 memset(pRet, 0, sizeof(Fts5Config));
238015 pRet->pGlobal = pGlobal;
@@ -237634,11 +238065,11 @@
238065 ALWAYS(zOne)?zOne:"",
238066 zTwo?zTwo:"",
238067 pzErr
238068 );
238069 }else{
238070 rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed);
238071 zOne = 0;
238072 }
238073 }
238074 }
238075
@@ -237665,18 +238096,34 @@
238096 *pzErr = sqlite3_mprintf(
238097 "contentless_delete=1 is incompatible with columnsize=0"
238098 );
238099 rc = SQLITE_ERROR;
238100 }
238101
238102 /* We only allow contentless_unindexed=1 if the table is actually a
238103 ** contentless one.
238104 */
238105 if( rc==SQLITE_OK
238106 && pRet->bContentlessUnindexed
238107 && pRet->eContent!=FTS5_CONTENT_NONE
238108 ){
238109 *pzErr = sqlite3_mprintf(
238110 "contentless_unindexed=1 requires a contentless table"
238111 );
238112 rc = SQLITE_ERROR;
238113 }
238114
238115 /* If no zContent option was specified, fill in the default values. */
238116 if( rc==SQLITE_OK && pRet->zContent==0 ){
238117 const char *zTail = 0;
238118 assert( pRet->eContent==FTS5_CONTENT_NORMAL
238119 || pRet->eContent==FTS5_CONTENT_NONE
238120 );
238121 if( pRet->eContent==FTS5_CONTENT_NORMAL ){
238122 zTail = "content";
238123 }else if( bUnindexed && pRet->bContentlessUnindexed ){
238124 pRet->eContent = FTS5_CONTENT_UNINDEXED;
238125 zTail = "content";
238126 }else if( pRet->bColumnsize ){
238127 zTail = "docsize";
238128 }
238129
@@ -238010,10 +238457,23 @@
238457 if( bVal<0 ){
238458 *pbBadkey = 1;
238459 }else{
238460 pConfig->bSecureDelete = (bVal ? 1 : 0);
238461 }
238462 }
238463
238464 else if( 0==sqlite3_stricmp(zKey, "insttoken") ){
238465 int bVal = -1;
238466 if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
238467 bVal = sqlite3_value_int(pVal);
238468 }
238469 if( bVal<0 ){
238470 *pbBadkey = 1;
238471 }else{
238472 pConfig->bPrefixInsttoken = (bVal ? 1 : 0);
238473 }
238474
238475 }else{
238476 *pbBadkey = 1;
238477 }
238478 return rc;
238479 }
@@ -241145,11 +241605,11 @@
241605 && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
241606 ){
241607 int rc = sqlite3Fts5PoslistWriterAppend(
241608 &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
241609 );
241610 if( rc==SQLITE_OK && (pExpr->pConfig->bTokendata || pT->bPrefix) ){
241611 int iCol = p->iOff>>32;
241612 int iTokOff = p->iOff & 0x7FFFFFFF;
241613 rc = sqlite3Fts5IndexIterWriteTokendata(
241614 pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
241615 );
@@ -241338,19 +241798,18 @@
241798 pPhrase = pExpr->apExprPhrase[iPhrase];
241799 if( iToken<0 || iToken>=pPhrase->nTerm ){
241800 return SQLITE_RANGE;
241801 }
241802 pTerm = &pPhrase->aTerm[iToken];
241803 if( pExpr->pConfig->bTokendata || pTerm->bPrefix ){
241804 rc = sqlite3Fts5IterToken(
241805 pTerm->pIter, pTerm->pTerm, pTerm->nQueryTerm,
241806 iRowid, iCol, iOff+iToken, ppOut, pnOut
241807 );
241808 }else{
241809 *ppOut = pTerm->pTerm;
241810 *pnOut = pTerm->nFullTerm;
 
241811 }
241812 return rc;
241813 }
241814
241815 /*
@@ -246847,10 +247306,15 @@
247306 if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
247307 iRet = ii;
247308 nBest = nPercent;
247309 }
247310 }
247311
247312 /* If pLvl is already the input level to an ongoing merge, look no
247313 ** further for a merge candidate. The caller should be allowed to
247314 ** continue merging from pLvl first. */
247315 if( pLvl->nMerge ) break;
247316 }
247317 }
247318 return iRet;
247319 }
247320
@@ -248156,10 +248620,387 @@
248620 fts5BufferFree(&tmp);
248621 memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
248622 *p1 = out;
248623 }
248624
248625
248626 /*
248627 ** Iterate through a range of entries in the FTS index, invoking the xVisit
248628 ** callback for each of them.
248629 **
248630 ** Parameter pToken points to an nToken buffer containing an FTS index term
248631 ** (i.e. a document term with the preceding 1 byte index identifier -
248632 ** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits
248633 ** all entries for terms that have pToken/nToken as a prefix. If bPrefix
248634 ** is false, then only entries with pToken/nToken as the entire key are
248635 ** visited.
248636 **
248637 ** If the current table is a tokendata=1 table, then if bPrefix is true then
248638 ** each index term is treated separately. However, if bPrefix is false, then
248639 ** all index terms corresponding to pToken/nToken are collapsed into a single
248640 ** term before the callback is invoked.
248641 **
248642 ** The callback invoked for each entry visited is specified by paramter xVisit.
248643 ** Each time it is invoked, it is passed a pointer to the Fts5Index object,
248644 ** a copy of the 7th paramter to this function (pCtx) and a pointer to the
248645 ** iterator that indicates the current entry. If the current entry is the
248646 ** first with a new term (i.e. different from that of the previous entry,
248647 ** including the very first term), then the final two parameters are passed
248648 ** a pointer to the term and its size in bytes, respectively. If the current
248649 ** entry is not the first associated with its term, these two parameters
248650 ** are passed 0.
248651 **
248652 ** If parameter pColset is not NULL, then it is used to filter entries before
248653 ** the callback is invoked.
248654 */
248655 static int fts5VisitEntries(
248656 Fts5Index *p, /* Fts5 index object */
248657 Fts5Colset *pColset, /* Columns filter to apply, or NULL */
248658 u8 *pToken, /* Buffer containing token */
248659 int nToken, /* Size of buffer pToken in bytes */
248660 int bPrefix, /* True for a prefix scan */
248661 void (*xVisit)(Fts5Index*, void *pCtx, Fts5Iter *pIter, const u8*, int),
248662 void *pCtx /* Passed as second argument to xVisit() */
248663 ){
248664 const int flags = (bPrefix ? FTS5INDEX_QUERY_SCAN : 0)
248665 | FTS5INDEX_QUERY_SKIPEMPTY
248666 | FTS5INDEX_QUERY_NOOUTPUT;
248667 Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
248668 int bNewTerm = 1;
248669 Fts5Structure *pStruct = fts5StructureRead(p);
248670
248671 fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
248672 fts5IterSetOutputCb(&p->rc, p1);
248673 for( /* no-op */ ;
248674 fts5MultiIterEof(p, p1)==0;
248675 fts5MultiIterNext2(p, p1, &bNewTerm)
248676 ){
248677 Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
248678 int nNew = 0;
248679 const u8 *pNew = 0;
248680
248681 p1->xSetOutputs(p1, pSeg);
248682 if( p->rc ) break;
248683
248684 if( bNewTerm ){
248685 nNew = pSeg->term.n;
248686 pNew = pSeg->term.p;
248687 if( nNew<nToken || memcmp(pToken, pNew, nToken) ) break;
248688 }
248689
248690 xVisit(p, pCtx, p1, pNew, nNew);
248691 }
248692 fts5MultiIterFree(p1);
248693
248694 fts5StructureRelease(pStruct);
248695 return p->rc;
248696 }
248697
248698
248699 /*
248700 ** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
248701 ** array of these for each row it visits (so all iRowid fields are the same).
248702 ** Or, for an iterator used by an "ORDER BY rank" query, it accumulates an
248703 ** array of these for the entire query (in which case iRowid fields may take
248704 ** a variety of values).
248705 **
248706 ** Each instance in the array indicates the iterator (and therefore term)
248707 ** associated with position iPos of rowid iRowid. This is used by the
248708 ** xInstToken() API.
248709 **
248710 ** iRowid:
248711 ** Rowid for the current entry.
248712 **
248713 ** iPos:
248714 ** Position of current entry within row. In the usual ((iCol<<32)+iOff)
248715 ** format (e.g. see macros FTS5_POS2COLUMN() and FTS5_POS2OFFSET()).
248716 **
248717 ** iIter:
248718 ** If the Fts5TokenDataIter iterator that the entry is part of is
248719 ** actually an iterator (i.e. with nIter>0, not just a container for
248720 ** Fts5TokenDataMap structures), then this variable is an index into
248721 ** the apIter[] array. The corresponding term is that which the iterator
248722 ** at apIter[iIter] currently points to.
248723 **
248724 ** Or, if the Fts5TokenDataIter iterator is just a container object
248725 ** (nIter==0), then iIter is an index into the term.p[] buffer where
248726 ** the term is stored.
248727 **
248728 ** nByte:
248729 ** In the case where iIter is an index into term.p[], this variable
248730 ** is the size of the term in bytes. If iIter is an index into apIter[],
248731 ** this variable is unused.
248732 */
248733 struct Fts5TokenDataMap {
248734 i64 iRowid; /* Row this token is located in */
248735 i64 iPos; /* Position of token */
248736 int iIter; /* Iterator token was read from */
248737 int nByte; /* Length of token in bytes (or 0) */
248738 };
248739
248740 /*
248741 ** An object used to supplement Fts5Iter for tokendata=1 iterators.
248742 **
248743 ** This object serves two purposes. The first is as a container for an array
248744 ** of Fts5TokenDataMap structures, which are used to find the token required
248745 ** when the xInstToken() API is used. This is done by the nMapAlloc, nMap and
248746 ** aMap[] variables.
248747 */
248748 struct Fts5TokenDataIter {
248749 int nMapAlloc; /* Allocated size of aMap[] in entries */
248750 int nMap; /* Number of valid entries in aMap[] */
248751 Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */
248752
248753 /* The following are used for prefix-queries only. */
248754 Fts5Buffer terms;
248755
248756 /* The following are used for other full-token tokendata queries only. */
248757 int nIter;
248758 int nIterAlloc;
248759 Fts5PoslistReader *aPoslistReader;
248760 int *aPoslistToIter;
248761 Fts5Iter *apIter[1];
248762 };
248763
248764 /*
248765 ** The two input arrays - a1[] and a2[] - are in sorted order. This function
248766 ** merges the two arrays together and writes the result to output array
248767 ** aOut[]. aOut[] is guaranteed to be large enough to hold the result.
248768 **
248769 ** Duplicate entries are copied into the output. So the size of the output
248770 ** array is always (n1+n2) entries.
248771 */
248772 static void fts5TokendataMerge(
248773 Fts5TokenDataMap *a1, int n1, /* Input array 1 */
248774 Fts5TokenDataMap *a2, int n2, /* Input array 2 */
248775 Fts5TokenDataMap *aOut /* Output array */
248776 ){
248777 int i1 = 0;
248778 int i2 = 0;
248779
248780 assert( n1>=0 && n2>=0 );
248781 while( i1<n1 || i2<n2 ){
248782 Fts5TokenDataMap *pOut = &aOut[i1+i2];
248783 if( i2>=n2 || (i1<n1 && (
248784 a1[i1].iRowid<a2[i2].iRowid
248785 || (a1[i1].iRowid==a2[i2].iRowid && a1[i1].iPos<=a2[i2].iPos)
248786 ))){
248787 memcpy(pOut, &a1[i1], sizeof(Fts5TokenDataMap));
248788 i1++;
248789 }else{
248790 memcpy(pOut, &a2[i2], sizeof(Fts5TokenDataMap));
248791 i2++;
248792 }
248793 }
248794 }
248795
248796
248797 /*
248798 ** Append a mapping to the token-map belonging to object pT.
248799 */
248800 static void fts5TokendataIterAppendMap(
248801 Fts5Index *p,
248802 Fts5TokenDataIter *pT,
248803 int iIter,
248804 int nByte,
248805 i64 iRowid,
248806 i64 iPos
248807 ){
248808 if( p->rc==SQLITE_OK ){
248809 if( pT->nMap==pT->nMapAlloc ){
248810 int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
248811 int nAlloc = nNew * sizeof(Fts5TokenDataMap);
248812 Fts5TokenDataMap *aNew;
248813
248814 aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
248815 if( aNew==0 ){
248816 p->rc = SQLITE_NOMEM;
248817 return;
248818 }
248819
248820 pT->aMap = aNew;
248821 pT->nMapAlloc = nNew;
248822 }
248823
248824 pT->aMap[pT->nMap].iRowid = iRowid;
248825 pT->aMap[pT->nMap].iPos = iPos;
248826 pT->aMap[pT->nMap].iIter = iIter;
248827 pT->aMap[pT->nMap].nByte = nByte;
248828 pT->nMap++;
248829 }
248830 }
248831
248832 /*
248833 ** Sort the contents of the pT->aMap[] array.
248834 **
248835 ** The sorting algorithm requries a malloc(). If this fails, an error code
248836 ** is left in Fts5Index.rc before returning.
248837 */
248838 static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
248839 Fts5TokenDataMap *aTmp = 0;
248840 int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
248841
248842 aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
248843 if( aTmp ){
248844 Fts5TokenDataMap *a1 = pT->aMap;
248845 Fts5TokenDataMap *a2 = aTmp;
248846 i64 nHalf;
248847
248848 for(nHalf=1; nHalf<pT->nMap; nHalf=nHalf*2){
248849 int i1;
248850 for(i1=0; i1<pT->nMap; i1+=(nHalf*2)){
248851 int n1 = MIN(nHalf, pT->nMap-i1);
248852 int n2 = MIN(nHalf, pT->nMap-i1-n1);
248853 fts5TokendataMerge(&a1[i1], n1, &a1[i1+n1], n2, &a2[i1]);
248854 }
248855 SWAPVAL(Fts5TokenDataMap*, a1, a2);
248856 }
248857
248858 if( a1!=pT->aMap ){
248859 memcpy(pT->aMap, a1, pT->nMap*sizeof(Fts5TokenDataMap));
248860 }
248861 sqlite3_free(aTmp);
248862
248863 #ifdef SQLITE_DEBUG
248864 {
248865 int ii;
248866 for(ii=1; ii<pT->nMap; ii++){
248867 Fts5TokenDataMap *p1 = &pT->aMap[ii-1];
248868 Fts5TokenDataMap *p2 = &pT->aMap[ii];
248869 assert( p1->iRowid<p2->iRowid
248870 || (p1->iRowid==p2->iRowid && p1->iPos<=p2->iPos)
248871 );
248872 }
248873 }
248874 #endif
248875 }
248876 }
248877
248878 /*
248879 ** Delete an Fts5TokenDataIter structure and its contents.
248880 */
248881 static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
248882 if( pSet ){
248883 int ii;
248884 for(ii=0; ii<pSet->nIter; ii++){
248885 fts5MultiIterFree(pSet->apIter[ii]);
248886 }
248887 fts5BufferFree(&pSet->terms);
248888 sqlite3_free(pSet->aPoslistReader);
248889 sqlite3_free(pSet->aMap);
248890 sqlite3_free(pSet);
248891 }
248892 }
248893
248894
248895 /*
248896 ** fts5VisitEntries() context object used by fts5SetupPrefixIterTokendata()
248897 ** to pass data to prefixIterSetupTokendataCb().
248898 */
248899 typedef struct TokendataSetupCtx TokendataSetupCtx;
248900 struct TokendataSetupCtx {
248901 Fts5TokenDataIter *pT; /* Object being populated with mappings */
248902 int iTermOff; /* Offset of current term in terms.p[] */
248903 int nTermByte; /* Size of current term in bytes */
248904 };
248905
248906 /*
248907 ** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This
248908 ** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each
248909 ** position in the current position-list. It doesn't matter that some of
248910 ** these may be out of order - they will be sorted later.
248911 */
248912 static void prefixIterSetupTokendataCb(
248913 Fts5Index *p,
248914 void *pCtx,
248915 Fts5Iter *p1,
248916 const u8 *pNew,
248917 int nNew
248918 ){
248919 TokendataSetupCtx *pSetup = (TokendataSetupCtx*)pCtx;
248920 int iPosOff = 0;
248921 i64 iPos = 0;
248922
248923 if( pNew ){
248924 pSetup->nTermByte = nNew-1;
248925 pSetup->iTermOff = pSetup->pT->terms.n;
248926 fts5BufferAppendBlob(&p->rc, &pSetup->pT->terms, nNew-1, pNew+1);
248927 }
248928
248929 while( 0==sqlite3Fts5PoslistNext64(
248930 p1->base.pData, p1->base.nData, &iPosOff, &iPos
248931 ) ){
248932 fts5TokendataIterAppendMap(p,
248933 pSetup->pT, pSetup->iTermOff, pSetup->nTermByte, p1->base.iRowid, iPos
248934 );
248935 }
248936 }
248937
248938
248939 /*
248940 ** Context object passed by fts5SetupPrefixIter() to fts5VisitEntries().
248941 */
248942 typedef struct PrefixSetupCtx PrefixSetupCtx;
248943 struct PrefixSetupCtx {
248944 void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
248945 void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
248946 i64 iLastRowid;
248947 int nMerge;
248948 Fts5Buffer *aBuf;
248949 int nBuf;
248950 Fts5Buffer doclist;
248951 TokendataSetupCtx *pTokendata;
248952 };
248953
248954 /*
248955 ** fts5VisitEntries() callback used by fts5SetupPrefixIter()
248956 */
248957 static void prefixIterSetupCb(
248958 Fts5Index *p,
248959 void *pCtx,
248960 Fts5Iter *p1,
248961 const u8 *pNew,
248962 int nNew
248963 ){
248964 PrefixSetupCtx *pSetup = (PrefixSetupCtx*)pCtx;
248965 const int nMerge = pSetup->nMerge;
248966
248967 if( p1->base.nData>0 ){
248968 if( p1->base.iRowid<=pSetup->iLastRowid && pSetup->doclist.n>0 ){
248969 int i;
248970 for(i=0; p->rc==SQLITE_OK && pSetup->doclist.n; i++){
248971 int i1 = i*nMerge;
248972 int iStore;
248973 assert( i1+nMerge<=pSetup->nBuf );
248974 for(iStore=i1; iStore<i1+nMerge; iStore++){
248975 if( pSetup->aBuf[iStore].n==0 ){
248976 fts5BufferSwap(&pSetup->doclist, &pSetup->aBuf[iStore]);
248977 fts5BufferZero(&pSetup->doclist);
248978 break;
248979 }
248980 }
248981 if( iStore==i1+nMerge ){
248982 pSetup->xMerge(p, &pSetup->doclist, nMerge, &pSetup->aBuf[i1]);
248983 for(iStore=i1; iStore<i1+nMerge; iStore++){
248984 fts5BufferZero(&pSetup->aBuf[iStore]);
248985 }
248986 }
248987 }
248988 pSetup->iLastRowid = 0;
248989 }
248990
248991 pSetup->xAppend(
248992 p, (u64)p1->base.iRowid-(u64)pSetup->iLastRowid, p1, &pSetup->doclist
248993 );
248994 pSetup->iLastRowid = p1->base.iRowid;
248995 }
248996
248997 if( pSetup->pTokendata ){
248998 prefixIterSetupTokendataCb(p, (void*)pSetup->pTokendata, p1, pNew, nNew);
248999 }
249000 }
249001
249002 static void fts5SetupPrefixIter(
249003 Fts5Index *p, /* Index to read from */
249004 int bDesc, /* True for "ORDER BY rowid DESC" */
249005 int iIdx, /* Index to scan for data */
249006 u8 *pToken, /* Buffer containing prefix to match */
@@ -248166,137 +249007,89 @@
249007 int nToken, /* Size of buffer pToken in bytes */
249008 Fts5Colset *pColset, /* Restrict matches to these columns */
249009 Fts5Iter **ppIter /* OUT: New iterator */
249010 ){
249011 Fts5Structure *pStruct;
249012 PrefixSetupCtx s;
249013 TokendataSetupCtx s2;
 
249014
249015 memset(&s, 0, sizeof(s));
249016 memset(&s2, 0, sizeof(s2));
249017
249018 s.nMerge = 1;
249019 s.iLastRowid = 0;
249020 s.nBuf = 32;
249021 if( iIdx==0
249022 && p->pConfig->eDetail==FTS5_DETAIL_FULL
249023 && p->pConfig->bPrefixInsttoken
249024 ){
249025 s.pTokendata = &s2;
249026 s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT));
249027 }
249028
249029 if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
249030 s.xMerge = fts5MergeRowidLists;
249031 s.xAppend = fts5AppendRowid;
249032 }else{
249033 s.nMerge = FTS5_MERGE_NLIST-1;
249034 s.nBuf = s.nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
249035 s.xMerge = fts5MergePrefixLists;
249036 s.xAppend = fts5AppendPoslist;
249037 }
249038
249039 s.aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*s.nBuf);
249040 pStruct = fts5StructureRead(p);
249041 assert( p->rc!=SQLITE_OK || (s.aBuf && pStruct) );
249042
249043 if( p->rc==SQLITE_OK ){
249044 void *pCtx = (void*)&s;
 
 
249045 int i;
 
 
249046 Fts5Data *pData;
 
 
 
 
249047
249048 /* If iIdx is non-zero, then it is the number of a prefix-index for
249049 ** prefixes 1 character longer than the prefix being queried for. That
249050 ** index contains all the doclists required, except for the one
249051 ** corresponding to the prefix itself. That one is extracted from the
249052 ** main term index here. */
249053 if( iIdx!=0 ){
 
 
249054 pToken[0] = FTS5_MAIN_PREFIX;
249055 fts5VisitEntries(p, pColset, pToken, nToken, 0, prefixIterSetupCb, pCtx);
 
 
 
 
 
 
 
 
 
 
 
 
 
249056 }
249057
249058 pToken[0] = FTS5_MAIN_PREFIX + iIdx;
249059 fts5VisitEntries(p, pColset, pToken, nToken, 1, prefixIterSetupCb, pCtx);
249060
249061 assert( (s.nBuf%s.nMerge)==0 );
249062 for(i=0; i<s.nBuf; i+=s.nMerge){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249063 int iFree;
249064 if( p->rc==SQLITE_OK ){
249065 s.xMerge(p, &s.doclist, s.nMerge, &s.aBuf[i]);
249066 }
249067 for(iFree=i; iFree<i+s.nMerge; iFree++){
249068 fts5BufferFree(&s.aBuf[iFree]);
249069 }
249070 }
 
249071
249072 pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING);
249073 if( pData ){
249074 pData->p = (u8*)&pData[1];
249075 pData->nn = pData->szLeaf = s.doclist.n;
249076 if( s.doclist.n ) memcpy(pData->p, s.doclist.p, s.doclist.n);
249077 fts5MultiIterNew2(p, pData, bDesc, ppIter);
249078 }
249079
249080 if( p->rc==SQLITE_OK && s.pTokendata ){
249081 fts5TokendataIterSortMap(p, s2.pT);
249082 (*ppIter)->pTokenDataIter = s2.pT;
249083 s2.pT = 0;
249084 }
249085 }
249086
249087 fts5TokendataIterDelete(s2.pT);
249088 fts5BufferFree(&s.doclist);
249089 fts5StructureRelease(pStruct);
249090 sqlite3_free(s.aBuf);
249091 }
249092
249093
249094 /*
249095 ** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
@@ -248546,42 +249339,10 @@
249339 static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
249340 fts5DataRelease(pSeg->pLeaf);
249341 pSeg->pLeaf = 0;
249342 }
249343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249344 /*
249345 ** This function appends iterator pAppend to Fts5TokenDataIter pIn and
249346 ** returns the result.
249347 */
249348 static Fts5TokenDataIter *fts5AppendTokendataIter(
@@ -248614,58 +249375,10 @@
249375 assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
249376
249377 return pRet;
249378 }
249379
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249380 /*
249381 ** The iterator passed as the only argument must be a tokendata=1 iterator
249382 ** (pIter->pTokenDataIter!=0). This function sets the iterator output
249383 ** variables (pIter->base.*) according to the contents of the current
249384 ** row.
@@ -248702,11 +249415,11 @@
249415 int eDetail = pIter->pIndex->pConfig->eDetail;
249416 pIter->base.bEof = 0;
249417 pIter->base.iRowid = iRowid;
249418
249419 if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
249420 fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, 0, iRowid, -1);
249421 }else
249422 if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
249423 int nReader = 0;
249424 int nByte = 0;
249425 i64 iPrev = 0;
@@ -248955,10 +249668,11 @@
249668
249669 if( p->rc==SQLITE_OK ){
249670 pRet = fts5MultiIterAlloc(p, 0);
249671 }
249672 if( pRet ){
249673 pRet->nSeg = 0;
249674 pRet->pTokenDataIter = pSet;
249675 if( pSet ){
249676 fts5IterSetOutputsTokendata(pRet);
249677 }else{
249678 pRet->base.bEof = 1;
@@ -248969,11 +249683,10 @@
249683
249684 fts5StructureRelease(pStruct);
249685 fts5BufferFree(&bSeek);
249686 return pRet;
249687 }
 
249688
249689 /*
249690 ** Open a new iterator to iterate though all rowid that match the
249691 ** specified token or token prefix.
249692 */
@@ -248995,10 +249708,15 @@
249708 int iIdx = 0; /* Index to search */
249709 int iPrefixIdx = 0; /* +1 prefix index */
249710 int bTokendata = pConfig->bTokendata;
249711 if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
249712
249713 /* The NOTOKENDATA flag is set when each token in a tokendata=1 table
249714 ** should be treated individually, instead of merging all those with
249715 ** a common prefix into a single entry. This is used, for example, by
249716 ** queries performed as part of an integrity-check, or by the fts5vocab
249717 ** module. */
249718 if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
249719 bTokendata = 0;
249720 }
249721
249722 /* Figure out which index to search and set iIdx accordingly. If this
@@ -249025,11 +249743,11 @@
249743 if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
249744 }
249745 }
249746
249747 if( bTokendata && iIdx==0 ){
249748 buf.p[0] = FTS5_MAIN_PREFIX;
249749 pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
249750 }else if( iIdx<=pConfig->nPrefix ){
249751 /* Straight index lookup */
249752 Fts5Structure *pStruct = fts5StructureRead(p);
249753 buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -249038,11 +249756,11 @@
249756 pColset, buf.p, nToken+1, -1, 0, &pRet
249757 );
249758 fts5StructureRelease(pStruct);
249759 }
249760 }else{
249761 /* Scan multiple terms in the main index for a prefix query. */
249762 int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
249763 fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
249764 if( pRet==0 ){
249765 assert( p->rc!=SQLITE_OK );
249766 }else{
@@ -249074,11 +249792,12 @@
249792 ** Move to the next matching rowid.
249793 */
249794 static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
249795 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249796 assert( pIter->pIndex->rc==SQLITE_OK );
249797 if( pIter->nSeg==0 ){
249798 assert( pIter->pTokenDataIter );
249799 fts5TokendataIterNext(pIter, 0, 0);
249800 }else{
249801 fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
249802 }
249803 return fts5IndexReturn(pIter->pIndex);
@@ -249111,11 +249830,12 @@
249830 ** definition of "at or after" depends on whether this iterator iterates
249831 ** in ascending or descending rowid order.
249832 */
249833 static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
249834 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249835 if( pIter->nSeg==0 ){
249836 assert( pIter->pTokenDataIter );
249837 fts5TokendataIterNext(pIter, 1, iMatch);
249838 }else{
249839 fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
249840 }
249841 return fts5IndexReturn(pIter->pIndex);
@@ -249129,32 +249849,87 @@
249849 const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
249850 assert_nc( z || n<=1 );
249851 *pn = n-1;
249852 return (z ? &z[1] : 0);
249853 }
249854
249855 /*
249856 ** pIter is a prefix query. This function populates pIter->pTokenDataIter
249857 ** with an Fts5TokenDataIter object containing mappings for all rows
249858 ** matched by the query.
249859 */
249860 static int fts5SetupPrefixIterTokendata(
249861 Fts5Iter *pIter,
249862 const char *pToken, /* Token prefix to search for */
249863 int nToken /* Size of pToken in bytes */
249864 ){
249865 Fts5Index *p = pIter->pIndex;
249866 Fts5Buffer token = {0, 0, 0};
249867 TokendataSetupCtx ctx;
249868
249869 memset(&ctx, 0, sizeof(ctx));
249870
249871 fts5BufferGrow(&p->rc, &token, nToken+1);
249872 ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));
249873
249874 if( p->rc==SQLITE_OK ){
249875
249876 /* Fill in the token prefix to search for */
249877 token.p[0] = FTS5_MAIN_PREFIX;
249878 memcpy(&token.p[1], pToken, nToken);
249879 token.n = nToken+1;
249880
249881 fts5VisitEntries(
249882 p, 0, token.p, token.n, 1, prefixIterSetupTokendataCb, (void*)&ctx
249883 );
249884
249885 fts5TokendataIterSortMap(p, ctx.pT);
249886 }
249887
249888 if( p->rc==SQLITE_OK ){
249889 pIter->pTokenDataIter = ctx.pT;
249890 }else{
249891 fts5TokendataIterDelete(ctx.pT);
249892 }
249893 fts5BufferFree(&token);
249894
249895 return fts5IndexReturn(p);
249896 }
249897
249898 /*
249899 ** This is used by xInstToken() to access the token at offset iOff, column
249900 ** iCol of row iRowid. The token is returned via output variables *ppOut
249901 ** and *pnOut. The iterator passed as the first argument must be a tokendata=1
249902 ** iterator (pIter->pTokenDataIter!=0).
249903 **
249904 ** pToken/nToken:
249905 */
249906 static int sqlite3Fts5IterToken(
249907 Fts5IndexIter *pIndexIter,
249908 const char *pToken, int nToken,
249909 i64 iRowid,
249910 int iCol,
249911 int iOff,
249912 const char **ppOut, int *pnOut
249913 ){
249914 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249915 Fts5TokenDataIter *pT = pIter->pTokenDataIter;
 
249916 i64 iPos = (((i64)iCol)<<32) + iOff;
249917 Fts5TokenDataMap *aMap = 0;
249918 int i1 = 0;
249919 int i2 = 0;
249920 int iTest = 0;
249921
249922 assert( pT || (pToken && pIter->nSeg>0) );
249923 if( pT==0 ){
249924 int rc = fts5SetupPrefixIterTokendata(pIter, pToken, nToken);
249925 if( rc!=SQLITE_OK ) return rc;
249926 pT = pIter->pTokenDataIter;
249927 }
249928
249929 i2 = pT->nMap;
249930 aMap = pT->aMap;
249931
249932 while( i2>i1 ){
249933 iTest = (i1 + i2) / 2;
249934
249935 if( aMap[iTest].iRowid<iRowid ){
@@ -249174,13 +249949,19 @@
249949 }
249950 }
249951 }
249952
249953 if( i2>i1 ){
249954 if( pIter->nSeg==0 ){
249955 Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
249956 *ppOut = (const char*)pMap->aSeg[0].term.p+1;
249957 *pnOut = pMap->aSeg[0].term.n-1;
249958 }else{
249959 Fts5TokenDataMap *p = &aMap[iTest];
249960 *ppOut = (const char*)&pT->terms.p[p->iIter];
249961 *pnOut = aMap[iTest].nByte;
249962 }
249963 }
249964
249965 return SQLITE_OK;
249966 }
249967
@@ -249188,11 +249969,13 @@
249969 ** Clear any existing entries from the token-map associated with the
249970 ** iterator passed as the only argument.
249971 */
249972 static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
249973 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249974 if( pIter && pIter->pTokenDataIter
249975 && (pIter->nSeg==0 || pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_FULL)
249976 ){
249977 pIter->pTokenDataIter->nMap = 0;
249978 }
249979 }
249980
249981 /*
@@ -249208,21 +249991,33 @@
249991 i64 iRowid, int iCol, int iOff
249992 ){
249993 Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
249994 Fts5TokenDataIter *pT = pIter->pTokenDataIter;
249995 Fts5Index *p = pIter->pIndex;
249996 i64 iPos = (((i64)iCol)<<32) + iOff;
249997
249998 assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
249999 assert( pIter->pTokenDataIter || pIter->nSeg>0 );
250000 if( pIter->nSeg>0 ){
250001 /* This is a prefix term iterator. */
250002 if( pT==0 ){
250003 pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT));
250004 pIter->pTokenDataIter = pT;
250005 }
250006 if( pT ){
250007 fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos);
250008 fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken);
250009 }
250010 }else{
250011 int ii;
250012 for(ii=0; ii<pT->nIter; ii++){
250013 Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
250014 if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
250015 }
250016 if( ii<pT->nIter ){
250017 fts5TokendataIterAppendMap(p, pT, ii, 0, iRowid, iPos);
250018 }
250019 }
250020 return fts5IndexReturn(p);
250021 }
250022
250023 /*
@@ -250771,11 +251566,11 @@
251566 return rc;
251567 }
251568
251569 /*
251570 ** We must have a single struct=? constraint that will be passed through
251571 ** into the xFilter method. If there is no valid struct=? constraint,
251572 ** then return an SQLITE_CONSTRAINT error.
251573 */
251574 static int fts5structBestIndexMethod(
251575 sqlite3_vtab *tab,
251576 sqlite3_index_info *pIdxInfo
@@ -251113,12 +251908,22 @@
251908 i64 iNextId; /* Used to allocate unique cursor ids */
251909 Fts5Auxiliary *pAux; /* First in list of all aux. functions */
251910 Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
251911 Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
251912 Fts5Cursor *pCsr; /* First in list of all open cursors */
251913 u32 aLocaleHdr[4];
251914 };
251915
251916 /*
251917 ** Size of header on fts5_locale() values. And macro to access a buffer
251918 ** containing a copy of the header from an Fts5Config pointer.
251919 */
251920 #define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr ))
251921 #define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr))
251922
251923 #define FTS5_INSTTOKEN_SUBTYPE 73
251924
251925 /*
251926 ** Each auxiliary function registered with the FTS5 module is represented
251927 ** by an object of the following type. All such objects are stored as part
251928 ** of the Fts5Global.pAux list.
251929 */
@@ -251277,16 +252082,10 @@
252082 #define FTS5CSR_REQUIRE_POSLIST 0x40
252083
252084 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
252085 #define BitFlagTest(x,y) (((x) & (y))!=0)
252086
 
 
 
 
 
 
252087
252088 /*
252089 ** Macros to Set(), Clear() and Test() cursor flags.
252090 */
252091 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
@@ -251359,14 +252158,20 @@
252158 #else
252159 # define fts5CheckTransactionState(x,y,z)
252160 #endif
252161
252162 /*
252163 ** Return true if pTab is a contentless table. If parameter bIncludeUnindexed
252164 ** is true, this includes contentless tables that store UNINDEXED columns
252165 ** only.
252166 */
252167 static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){
252168 int eContent = pTab->p.pConfig->eContent;
252169 return (
252170 eContent==FTS5_CONTENT_NONE
252171 || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED)
252172 );
252173 }
252174
252175 /*
252176 ** Delete a virtual table handle allocated by fts5InitVtab().
252177 */
@@ -251653,10 +252458,11 @@
252458 ){
252459 /* A MATCH operator or equivalent */
252460 if( p->usable==0 || iCol<0 ){
252461 /* As there exists an unusable MATCH constraint this is an
252462 ** unusable plan. Return SQLITE_CONSTRAINT. */
252463 idxStr[iIdxStr] = 0;
252464 return SQLITE_CONSTRAINT;
252465 }else{
252466 if( iCol==nCol+1 ){
252467 if( bSeenRank ) continue;
252468 idxStr[iIdxStr++] = 'r';
@@ -252286,11 +253092,11 @@
253092 ** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
253093 ** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
253094 ** valid until after the final call to sqlite3Fts5Tokenize() that will use
253095 ** the locale.
253096 */
253097 static void sqlite3Fts5SetLocale(
253098 Fts5Config *pConfig,
253099 const char *zLocale,
253100 int nLocale
253101 ){
253102 Fts5TokenizerConfig *pT = &pConfig->t;
@@ -252297,141 +253103,88 @@
253103 pT->pLocale = zLocale;
253104 pT->nLocale = nLocale;
253105 }
253106
253107 /*
253108 ** Clear any locale configured by an earlier call to sqlite3Fts5SetLocale().
 
253109 */
253110 static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
253111 sqlite3Fts5SetLocale(pConfig, 0, 0);
253112 }
253113
253114 /*
253115 ** Return true if the value passed as the only argument is an
253116 ** fts5_locale() value.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253117 */
253118 static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal){
253119 int ret = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253120 if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
253121 /* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case.
253122 ** If the blob was created using zeroblob(), then sqlite3_value_blob()
253123 ** may call malloc(). If this malloc() fails, then the values returned
253124 ** by both value_blob() and value_bytes() will be 0. If value_bytes() were
253125 ** called first, then the NULL pointer returned by value_blob() might
253126 ** be dereferenced. */
 
 
 
253127 const u8 *pBlob = sqlite3_value_blob(pVal);
253128 int nBlob = sqlite3_value_bytes(pVal);
253129 if( nBlob>FTS5_LOCALE_HDR_SIZE
253130 && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE)
253131 ){
253132 ret = 1;
253133 }
253134 }
253135 return ret;
253136 }
253137
253138 /*
253139 ** Value pVal is guaranteed to be an fts5_locale() value, according to
253140 ** sqlite3Fts5IsLocaleValue(). This function extracts the text and locale
253141 ** from the value and returns them separately.
253142 **
253143 ** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set
253144 ** to point to buffers containing the text and locale, as utf-8,
253145 ** respectively. In this case output parameters (*pnText) and (*pnLoc) are
253146 ** set to the sizes in bytes of these two buffers.
253147 **
253148 ** Or, if an error occurs, then an SQLite error code is returned. The final
253149 ** value of the four output parameters is undefined in this case.
253150 */
253151 static int sqlite3Fts5DecodeLocaleValue(
253152 sqlite3_value *pVal,
253153 const char **ppText,
253154 int *pnText,
253155 const char **ppLoc,
253156 int *pnLoc
253157 ){
253158 const char *p = sqlite3_value_blob(pVal);
253159 int n = sqlite3_value_bytes(pVal);
253160 int nLoc = 0;
253161
253162 assert( sqlite3_value_type(pVal)==SQLITE_BLOB );
253163 assert( n>FTS5_LOCALE_HDR_SIZE );
253164
253165 for(nLoc=FTS5_LOCALE_HDR_SIZE; p[nLoc]; nLoc++){
253166 if( nLoc==(n-1) ){
253167 return SQLITE_MISMATCH;
253168 }
253169 }
253170 *ppLoc = &p[FTS5_LOCALE_HDR_SIZE];
253171 *pnLoc = nLoc - FTS5_LOCALE_HDR_SIZE;
253172
253173 *ppText = &p[nLoc+1];
253174 *pnText = n - nLoc - 1;
253175 return SQLITE_OK;
253176 }
253177
253178 /*
253179 ** Argument pVal is the text of a full-text search expression. It may or
253180 ** may not have been wrapped by fts5_locale(). This function extracts
253181 ** the text of the expression, and sets output variable (*pzText) to
253182 ** point to a nul-terminated buffer containing the expression.
253183 **
253184 ** If pVal was an fts5_locale() value, then sqlite3Fts5SetLocale() is called
253185 ** to set the tokenizer to use the specified locale.
253186 **
253187 ** If output variable (*pbFreeAndReset) is set to true, then the caller
253188 ** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
253189 ** locale, and (b) call sqlite3_free() to free (*pzText).
253190 */
@@ -252439,28 +253192,26 @@
253192 Fts5Config *pConfig, /* Fts5 configuration */
253193 sqlite3_value *pVal, /* Value to extract expression text from */
253194 char **pzText, /* OUT: nul-terminated buffer of text */
253195 int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
253196 ){
 
 
253197 int rc = SQLITE_OK;
253198
253199 if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
253200 const char *pText = 0;
253201 int nText = 0;
253202 const char *pLoc = 0;
253203 int nLoc = 0;
253204 rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
253205 *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, pText);
253206 if( rc==SQLITE_OK ){
253207 sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
253208 }
253209 *pbFreeAndReset = 1;
253210 }else{
253211 *pzText = (char*)sqlite3_value_text(pVal);
253212 *pbFreeAndReset = 0;
253213 }
253214
253215 return rc;
253216 }
253217
@@ -252493,10 +253244,11 @@
253244 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
253245 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
253246 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
253247 int iCol; /* Column on LHS of MATCH operator */
253248 char **pzErrmsg = pConfig->pzErrmsg;
253249 int bPrefixInsttoken = pConfig->bPrefixInsttoken;
253250 int i;
253251 int iIdxStr = 0;
253252 Fts5Expr *pExpr = 0;
253253
253254 assert( pConfig->bLock==0 );
@@ -252528,10 +253280,13 @@
253280 int bInternal = 0;
253281
253282 rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
253283 if( rc!=SQLITE_OK ) goto filter_out;
253284 if( zText==0 ) zText = "";
253285 if( sqlite3_value_subtype(apVal[i])==FTS5_INSTTOKEN_SUBTYPE ){
253286 pConfig->bPrefixInsttoken = 1;
253287 }
253288
253289 iCol = 0;
253290 do{
253291 iCol = iCol*10 + (idxStr[iIdxStr]-'0');
253292 iIdxStr++;
@@ -252668,10 +253423,11 @@
253423 }
253424
253425 filter_out:
253426 sqlite3Fts5ExprFree(pExpr);
253427 pConfig->pzErrmsg = pzErrmsg;
253428 pConfig->bPrefixInsttoken = bPrefixInsttoken;
253429 return rc;
253430 }
253431
253432 /*
253433 ** This is the xEof method of the virtual table. SQLite calls this
@@ -252808,11 +253564,11 @@
253564 }else{
253565 rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
253566 }
253567 bLoadConfig = 1;
253568 }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
253569 if( fts5IsContentless(pTab, 1) ){
253570 fts5SetVtabError(pTab,
253571 "'rebuild' may not be used with a contentless fts5 table"
253572 );
253573 rc = SQLITE_ERROR;
253574 }else{
@@ -252877,17 +253633,78 @@
253633 sqlite3_value **apVal,
253634 i64 *piRowid
253635 ){
253636 int rc = *pRc;
253637 if( rc==SQLITE_OK ){
253638 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid);
253639 }
253640 if( rc==SQLITE_OK ){
253641 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
253642 }
253643 *pRc = rc;
253644 }
253645
253646 /*
253647 **
253648 ** This function is called when the user attempts an UPDATE on a contentless
253649 ** table. Parameter bRowidModified is true if the UPDATE statement modifies
253650 ** the rowid value. Parameter apVal[] contains the new values for each user
253651 ** defined column of the fts5 table. pConfig is the configuration object of the
253652 ** table being updated (guaranteed to be contentless). The contentless_delete=1
253653 ** and contentless_unindexed=1 options may or may not be set.
253654 **
253655 ** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite
253656 ** error code if it cannot. In this case an error message is also loaded into
253657 ** pConfig. Output parameter (*pbContent) is set to true if the caller should
253658 ** update the %_content table only - not the FTS index or any other shadow
253659 ** table. This occurs when an UPDATE modifies only UNINDEXED columns of the
253660 ** table.
253661 **
253662 ** An UPDATE may proceed if:
253663 **
253664 ** * The only columns modified are UNINDEXED columns, or
253665 **
253666 ** * The contentless_delete=1 option was specified and all of the indexed
253667 ** columns (not a subset) have been modified.
253668 */
253669 static int fts5ContentlessUpdate(
253670 Fts5Config *pConfig,
253671 sqlite3_value **apVal,
253672 int bRowidModified,
253673 int *pbContent
253674 ){
253675 int ii;
253676 int bSeenIndex = 0; /* Have seen modified indexed column */
253677 int bSeenIndexNC = 0; /* Have seen unmodified indexed column */
253678 int rc = SQLITE_OK;
253679
253680 for(ii=0; ii<pConfig->nCol; ii++){
253681 if( pConfig->abUnindexed[ii]==0 ){
253682 if( sqlite3_value_nochange(apVal[ii]) ){
253683 bSeenIndexNC++;
253684 }else{
253685 bSeenIndex++;
253686 }
253687 }
253688 }
253689
253690 if( bSeenIndex==0 && bRowidModified==0 ){
253691 *pbContent = 1;
253692 }else{
253693 if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){
253694 rc = SQLITE_ERROR;
253695 sqlite3Fts5ConfigErrmsg(pConfig,
253696 (pConfig->bContentlessDelete ?
253697 "%s a subset of columns on fts5 contentless-delete table: %s" :
253698 "%s contentless fts5 table: %s")
253699 , "cannot UPDATE", pConfig->zName
253700 );
253701 }
253702 }
253703
253704 return rc;
253705 }
253706
253707 /*
253708 ** This function is the implementation of the xUpdate callback used by
253709 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
253710 ** inserted, updated or deleted.
@@ -252971,48 +253788,38 @@
253788 }
253789
253790 assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
253791 assert( nArg!=1 || eType0==SQLITE_INTEGER );
253792
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253793 /* DELETE */
253794 if( nArg==1 ){
253795 /* It is only possible to DELETE from a contentless table if the
253796 ** contentless_delete=1 flag is set. */
253797 if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){
253798 fts5SetVtabError(pTab,
253799 "cannot DELETE from contentless fts5 table: %s", pConfig->zName
253800 );
253801 rc = SQLITE_ERROR;
253802 }else{
253803 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
253804 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
253805 bUpdateOrDelete = 1;
253806 }
253807 }
253808
253809 /* INSERT or UPDATE */
253810 else{
253811 int eType1 = sqlite3_value_numeric_type(apVal[1]);
253812
253813 /* It is an error to write an fts5_locale() value to a table without
253814 ** the locale=1 option. */
253815 if( pConfig->bLocale==0 ){
253816 int ii;
253817 for(ii=0; ii<pConfig->nCol; ii++){
253818 sqlite3_value *pVal = apVal[ii+2];
253819 if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
253820 fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
 
 
 
 
 
253821 rc = SQLITE_MISMATCH;
253822 goto update_out;
253823 }
253824 }
253825 }
@@ -253028,39 +253835,59 @@
253835 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253836 }
253837
253838 /* UPDATE */
253839 else{
253840 Fts5Storage *pStorage = pTab->pStorage;
253841 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
253842 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
253843 int bContent = 0; /* Content only update */
253844
253845 /* If this is a contentless table (including contentless_unindexed=1
253846 ** tables), check if the UPDATE may proceed. */
253847 if( fts5IsContentless(pTab, 1) ){
253848 rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent);
253849 if( rc!=SQLITE_OK ) goto update_out;
253850 }
253851
253852 if( eType1!=SQLITE_INTEGER ){
253853 rc = SQLITE_MISMATCH;
253854 }else if( iOld!=iNew ){
253855 assert( bContent==0 );
253856 if( eConflict==SQLITE_REPLACE ){
253857 rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
253858 if( rc==SQLITE_OK ){
253859 rc = sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0);
253860 }
253861 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253862 }else{
253863 rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
253864 if( rc==SQLITE_OK ){
253865 rc = sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid);
253866 }
253867 if( rc==SQLITE_OK ){
253868 rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0);
253869 }
253870 if( rc==SQLITE_OK ){
253871 rc = sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid);
253872 }
253873 }
253874 }else if( bContent ){
253875 /* This occurs when an UPDATE on a contentless table affects *only*
253876 ** UNINDEXED columns. This is a no-op for contentless_unindexed=0
253877 ** tables, or a write to the %_content table only for =1 tables. */
253878 assert( fts5IsContentless(pTab, 1) );
253879 rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
253880 if( rc==SQLITE_OK ){
253881 rc = sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid);
253882 }
253883 }else{
253884 rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
253885 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253886 }
253887 bUpdateOrDelete = 1;
253888 sqlite3Fts5StorageReleaseDeleteRow(pStorage);
253889 }
253890
253891 }
253892 }
253893
@@ -253169,15 +253996,15 @@
253996 ){
253997 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253998 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253999 int rc = SQLITE_OK;
254000
254001 sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc);
254002 rc = sqlite3Fts5Tokenize(pTab->pConfig,
254003 FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
254004 );
254005 sqlite3Fts5SetLocale(pTab->pConfig, 0, 0);
254006
254007 return rc;
254008 }
254009
254010 /*
@@ -253200,10 +254027,53 @@
254027
254028 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
254029 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
254030 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
254031 }
254032
254033 /*
254034 ** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This
254035 ** function extracts the text value of column iCol of the current row.
254036 ** Additionally, if there is an associated locale, it invokes
254037 ** sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller
254038 ** should invoke sqlite3Fts5ClearLocale() to clear the locale at some point
254039 ** after this function returns.
254040 **
254041 ** If successful, (*ppText) is set to point to a buffer containing the text
254042 ** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that
254043 ** buffer in bytes. It is not guaranteed to be nul-terminated. If an error
254044 ** occurs, an SQLite error code is returned. The final values of the two
254045 ** output parameters are undefined in this case.
254046 */
254047 static int fts5TextFromStmt(
254048 Fts5Config *pConfig,
254049 sqlite3_stmt *pStmt,
254050 int iCol,
254051 const char **ppText,
254052 int *pnText
254053 ){
254054 sqlite3_value *pVal = sqlite3_column_value(pStmt, iCol+1);
254055 const char *pLoc = 0;
254056 int nLoc = 0;
254057 int rc = SQLITE_OK;
254058
254059 if( pConfig->bLocale
254060 && pConfig->eContent==FTS5_CONTENT_EXTERNAL
254061 && sqlite3Fts5IsLocaleValue(pConfig, pVal)
254062 ){
254063 rc = sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc);
254064 }else{
254065 *ppText = (const char*)sqlite3_value_text(pVal);
254066 *pnText = sqlite3_value_bytes(pVal);
254067 if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){
254068 pLoc = (const char*)sqlite3_column_text(pStmt, iCol+1+pConfig->nCol);
254069 nLoc = sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol);
254070 }
254071 }
254072 sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
254073 return rc;
254074 }
254075
254076 static int fts5ApiColumnText(
254077 Fts5Context *pCtx,
254078 int iCol,
254079 const char **pz,
@@ -253214,20 +254084,18 @@
254084 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
254085
254086 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
254087 if( iCol<0 || iCol>=pTab->pConfig->nCol ){
254088 rc = SQLITE_RANGE;
254089 }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){
254090 *pz = 0;
254091 *pn = 0;
254092 }else{
254093 rc = fts5SeekCursor(pCsr, 0);
254094 if( rc==SQLITE_OK ){
254095 rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn);
254096 sqlite3Fts5ClearLocale(pTab->pConfig);
 
 
254097 }
254098 }
254099 return rc;
254100 }
254101
@@ -253249,11 +254117,11 @@
254117 int bLive = (pCsr->pSorter==0);
254118
254119 if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
254120 rc = SQLITE_RANGE;
254121 }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
254122 && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
254123 ){
254124 *pa = 0;
254125 *pn = 0;
254126 return SQLITE_OK;
254127 }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
@@ -253265,21 +254133,19 @@
254133 if( aPopulator==0 ) rc = SQLITE_NOMEM;
254134 if( rc==SQLITE_OK ){
254135 rc = fts5SeekCursor(pCsr, 0);
254136 }
254137 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
 
254138 const char *z = 0;
254139 int n = 0;
254140 rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
 
254141 if( rc==SQLITE_OK ){
254142 rc = sqlite3Fts5ExprPopulatePoslists(
254143 pConfig, pCsr->pExpr, aPopulator, i, z, n
254144 );
254145 }
254146 sqlite3Fts5ClearLocale(pConfig);
254147 }
254148 sqlite3_free(aPopulator);
254149
254150 if( pCsr->pSorter ){
254151 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
@@ -253447,11 +254313,11 @@
254313
254314 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
254315 if( pConfig->bColumnsize ){
254316 i64 iRowid = fts5CursorRowid(pCsr);
254317 rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
254318 }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
254319 int i;
254320 for(i=0; i<pConfig->nCol; i++){
254321 if( pConfig->abUnindexed[i]==0 ){
254322 pCsr->aColumnSize[i] = -1;
254323 }
@@ -253461,21 +254327,18 @@
254327 rc = fts5SeekCursor(pCsr, 0);
254328 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
254329 if( pConfig->abUnindexed[i]==0 ){
254330 const char *z = 0;
254331 int n = 0;
 
 
 
254332 pCsr->aColumnSize[i] = 0;
254333 rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
254334 if( rc==SQLITE_OK ){
254335 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
254336 z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
254337 );
 
254338 }
254339 sqlite3Fts5ClearLocale(pConfig);
254340 }
254341 }
254342 }
254343 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
254344 }
@@ -253738,46 +254601,23 @@
254601 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
254602 if( iCol<0 || iCol>=pConfig->nCol ){
254603 rc = SQLITE_RANGE;
254604 }else if(
254605 pConfig->abUnindexed[iCol]==0
254606 && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
254607 && pConfig->bLocale
254608 ){
254609 rc = fts5SeekCursor(pCsr, 0);
254610 if( rc==SQLITE_OK ){
254611 const char *zDummy = 0;
254612 int nDummy = 0;
254613 rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy);
254614 if( rc==SQLITE_OK ){
254615 *pzLocale = pConfig->t.pLocale;
254616 *pnLocale = pConfig->t.nLocale;
254617 }
254618 sqlite3Fts5ClearLocale(pConfig);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254619 }
254620 }
254621
254622 return rc;
254623 }
@@ -253994,61 +254834,10 @@
254834
254835 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
254836 return rc;
254837 }
254838
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254839 /*
254840 ** This is the xColumn method, called by SQLite to request a value from
254841 ** the row that the supplied cursor currently points to.
254842 */
254843 static int fts5ColumnMethod(
@@ -254087,26 +254876,31 @@
254876 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
254877 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
254878 }
254879 }
254880 }else{
254881 if( !sqlite3_vtab_nochange(pCtx) && pConfig->eContent!=FTS5_CONTENT_NONE ){
 
 
 
 
 
 
 
 
 
254882 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
254883 rc = fts5SeekCursor(pCsr, 1);
254884 if( rc==SQLITE_OK ){
254885 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
254886 if( pConfig->bLocale
254887 && pConfig->eContent==FTS5_CONTENT_EXTERNAL
254888 && sqlite3Fts5IsLocaleValue(pConfig, pVal)
254889 ){
254890 const char *z = 0;
254891 int n = 0;
254892 rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n);
254893 if( rc==SQLITE_OK ){
254894 sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT);
254895 }
254896 sqlite3Fts5ClearLocale(pConfig);
254897 }else{
254898 sqlite3_result_value(pCtx, pVal);
254899 }
254900 }
254901
254902 pConfig->pzErrmsg = 0;
254903 }
254904 }
254905
254906 return rc;
@@ -254625,11 +255419,11 @@
255419 int nArg, /* Number of args */
255420 sqlite3_value **apUnused /* Function arguments */
255421 ){
255422 assert( nArg==0 );
255423 UNUSED_PARAM2(nArg, apUnused);
255424 sqlite3_result_text(pCtx, "fts5: 2024-12-09 20:46:36 e2bae4143afd07de1ae55a6d2606a3b541a5b94568aa41f6a96e5d1245471653", -1, SQLITE_TRANSIENT);
255425 }
255426
255427 /*
255428 ** Implementation of fts5_locale(LOCALE, TEXT) function.
255429 **
@@ -254664,36 +255458,48 @@
255458 nText = sqlite3_value_bytes(apArg[1]);
255459
255460 if( zLocale==0 || zLocale[0]=='\0' ){
255461 sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
255462 }else{
255463 Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx);
255464 u8 *pBlob = 0;
255465 u8 *pCsr = 0;
255466 int nBlob = 0;
 
 
255467
255468 nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText;
255469 pBlob = (u8*)sqlite3_malloc(nBlob);
255470 if( pBlob==0 ){
255471 sqlite3_result_error_nomem(pCtx);
255472 return;
255473 }
255474
255475 pCsr = pBlob;
255476 memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE);
255477 pCsr += FTS5_LOCALE_HDR_SIZE;
255478 memcpy(pCsr, zLocale, nLocale);
255479 pCsr += nLocale;
255480 (*pCsr++) = 0x00;
255481 if( zText ) memcpy(pCsr, zText, nText);
255482 assert( &pCsr[nText]==&pBlob[nBlob] );
255483
255484 sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
 
255485 }
255486 }
255487
255488 /*
255489 ** Implementation of fts5_insttoken() function.
255490 */
255491 static void fts5InsttokenFunc(
255492 sqlite3_context *pCtx, /* Function call context */
255493 int nArg, /* Number of args */
255494 sqlite3_value **apArg /* Function arguments */
255495 ){
255496 assert( nArg==1 );
255497 (void)nArg;
255498 sqlite3_result_value(pCtx, apArg[0]);
255499 sqlite3_result_subtype(pCtx, FTS5_INSTTOKEN_SUBTYPE);
255500 }
255501
255502 /*
255503 ** Return true if zName is the extension on one of the shadow tables used
255504 ** by this module.
255505 */
@@ -254789,10 +255595,20 @@
255595 pGlobal->api.xCreateFunction = fts5CreateAux;
255596 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
255597 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
255598 pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
255599 pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
255600
255601 /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector.
255602 ** The constants below were generated randomly. */
255603 sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr);
255604 pGlobal->aLocaleHdr[0] ^= 0xF924976D;
255605 pGlobal->aLocaleHdr[1] ^= 0x16596E13;
255606 pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA;
255607 pGlobal->aLocaleHdr[3] ^= 0x9B03A67F;
255608 assert( sizeof(pGlobal->aLocaleHdr)==16 );
255609
255610 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
255611 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
255612 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
255613 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
255614 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
@@ -254810,13 +255626,20 @@
255626 );
255627 }
255628 if( rc==SQLITE_OK ){
255629 rc = sqlite3_create_function(
255630 db, "fts5_locale", 2,
255631 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE|SQLITE_SUBTYPE,
255632 p, fts5LocaleFunc, 0, 0
255633 );
255634 }
255635 if( rc==SQLITE_OK ){
255636 rc = sqlite3_create_function(
255637 db, "fts5_insttoken", 1,
255638 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
255639 p, fts5InsttokenFunc, 0, 0
255640 );
255641 }
255642 }
255643
255644 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
255645 ** fts5_test_mi.c is compiled and linked into the executable. And call
@@ -255015,24 +255838,39 @@
255838 );
255839 break;
255840
255841 case FTS5_STMT_INSERT_CONTENT:
255842 case FTS5_STMT_REPLACE_CONTENT: {
255843 char *zBind = 0;
 
255844 int i;
255845
255846 assert( pC->eContent==FTS5_CONTENT_NORMAL
255847 || pC->eContent==FTS5_CONTENT_UNINDEXED
255848 );
255849
255850 /* Add bindings for the "c*" columns - those that store the actual
255851 ** table content. If eContent==NORMAL, then there is one binding
255852 ** for each column. Or, if eContent==UNINDEXED, then there are only
255853 ** bindings for the UNINDEXED columns. */
255854 for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){
255855 if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){
255856 zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1);
255857 }
255858 }
255859
255860 /* Add bindings for any "l*" columns. Only non-UNINDEXED columns
255861 ** require these. */
255862 if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){
255863 for(i=0; rc==SQLITE_OK && i<pC->nCol; i++){
255864 if( pC->abUnindexed[i]==0 ){
255865 zBind = sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2);
255866 }
255867 }
255868 }
255869
255870 zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind);
255871 sqlite3_free(zBind);
255872 break;
255873 }
255874
255875 case FTS5_STMT_REPLACE_DOCSIZE:
255876 zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
@@ -255214,23 +256052,37 @@
256052 p->aTotalSize = (i64*)&p[1];
256053 p->pConfig = pConfig;
256054 p->pIndex = pIndex;
256055
256056 if( bCreate ){
256057 if( pConfig->eContent==FTS5_CONTENT_NORMAL
256058 || pConfig->eContent==FTS5_CONTENT_UNINDEXED
256059 ){
256060 int nDefn = 32 + pConfig->nCol*10;
256061 char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
256062 if( zDefn==0 ){
256063 rc = SQLITE_NOMEM;
256064 }else{
256065 int i;
256066 int iOff;
256067 sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
256068 iOff = (int)strlen(zDefn);
256069 for(i=0; i<pConfig->nCol; i++){
256070 if( pConfig->eContent==FTS5_CONTENT_NORMAL
256071 || pConfig->abUnindexed[i]
256072 ){
256073 sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
256074 iOff += (int)strlen(&zDefn[iOff]);
256075 }
256076 }
256077 if( pConfig->bLocale ){
256078 for(i=0; i<pConfig->nCol; i++){
256079 if( pConfig->abUnindexed[i]==0 ){
256080 sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
256081 iOff += (int)strlen(&zDefn[iOff]);
256082 }
256083 }
256084 }
256085 rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
256086 }
256087 sqlite3_free(zDefn);
256088 }
@@ -255379,33 +256231,43 @@
256231 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
256232 if( pConfig->abUnindexed[iCol-1]==0 ){
256233 sqlite3_value *pVal = 0;
256234 const char *pText = 0;
256235 int nText = 0;
256236 const char *pLoc = 0;
256237 int nLoc = 0;
256238
256239 assert( pSeek==0 || apVal==0 );
256240 assert( pSeek!=0 || apVal!=0 );
256241 if( pSeek ){
256242 pVal = sqlite3_column_value(pSeek, iCol);
256243 }else{
256244 pVal = apVal[iCol-1];
256245 }
256246
256247 if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
256248 rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256249 }else{
256250 pText = (const char*)sqlite3_value_text(pVal);
256251 nText = sqlite3_value_bytes(pVal);
256252 if( pConfig->bLocale && pSeek ){
256253 pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol);
256254 nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
256255 }
256256 }
256257
256258 if( rc==SQLITE_OK ){
256259 sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
256260 ctx.szCol = 0;
256261 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
256262 pText, nText, (void*)&ctx, fts5StorageInsertCallback
256263 );
256264 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
256265 if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
256266 rc = FTS5_CORRUPT;
256267 }
256268 sqlite3Fts5ClearLocale(pConfig);
256269 }
256270 }
256271 }
256272 if( rc==SQLITE_OK && p->nTotalRow<1 ){
256273 rc = FTS5_CORRUPT;
@@ -255446,11 +256308,13 @@
256308 i64 iOrigin = 0;
256309 sqlite3_stmt *pLookup = 0;
256310 int rc = SQLITE_OK;
256311
256312 assert( p->pConfig->bContentlessDelete );
256313 assert( p->pConfig->eContent==FTS5_CONTENT_NONE
256314 || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
256315 );
256316
256317 /* Look up the origin of the document in the %_docsize table. Store
256318 ** this in stack variable iOrigin. */
256319 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
256320 if( rc==SQLITE_OK ){
@@ -255570,10 +256434,16 @@
256434 }
256435
256436 if( rc==SQLITE_OK ){
256437 if( p->pConfig->bContentlessDelete ){
256438 rc = fts5StorageContentlessDelete(p, iDel);
256439 if( rc==SQLITE_OK
256440 && bSaveRow
256441 && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
256442 ){
256443 rc = sqlite3Fts5StorageFindDeleteRow(p, iDel);
256444 }
256445 }else{
256446 rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
256447 }
256448 }
256449
@@ -255586,11 +256456,13 @@
256456 rc = sqlite3_reset(pDel);
256457 }
256458 }
256459
256460 /* Delete the %_content record */
256461 if( pConfig->eContent==FTS5_CONTENT_NORMAL
256462 || pConfig->eContent==FTS5_CONTENT_UNINDEXED
256463 ){
256464 if( rc==SQLITE_OK ){
256465 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
256466 }
256467 if( rc==SQLITE_OK ){
256468 sqlite3_bind_int64(pDel, 1, iDel);
@@ -255618,12 +256490,17 @@
256490 pConfig->zDb, pConfig->zName,
256491 pConfig->zDb, pConfig->zName
256492 );
256493 if( rc==SQLITE_OK && pConfig->bColumnsize ){
256494 rc = fts5ExecPrintf(pConfig->db, 0,
256495 "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName
256496 );
256497 }
256498
256499 if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
256500 rc = fts5ExecPrintf(pConfig->db, 0,
256501 "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName
256502 );
256503 }
256504
256505 /* Reinitialize the %_data table. This call creates the initial structure
256506 ** and averages records. */
@@ -255660,24 +256537,39 @@
256537 sqlite3Fts5BufferZero(&buf);
256538 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
256539 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
256540 ctx.szCol = 0;
256541 if( pConfig->abUnindexed[ctx.iCol]==0 ){
 
256542 int nText = 0; /* Size of pText in bytes */
256543 const char *pText = 0; /* Pointer to buffer containing text value */
256544 int nLoc = 0; /* Size of pLoc in bytes */
256545 const char *pLoc = 0; /* Pointer to buffer containing text value */
256546
256547 sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
256548 if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
256549 && sqlite3Fts5IsLocaleValue(pConfig, pVal)
256550 ){
256551 rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256552 }else{
256553 pText = (const char*)sqlite3_value_text(pVal);
256554 nText = sqlite3_value_bytes(pVal);
256555 if( pConfig->bLocale ){
256556 int iCol = ctx.iCol + 1 + pConfig->nCol;
256557 pLoc = (const char*)sqlite3_column_text(pScan, iCol);
256558 nLoc = sqlite3_column_bytes(pScan, iCol);
256559 }
256560 }
256561
 
256562 if( rc==SQLITE_OK ){
256563 sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
256564 rc = sqlite3Fts5Tokenize(pConfig,
256565 FTS5_TOKENIZE_DOCUMENT,
256566 pText, nText,
256567 (void*)&ctx,
256568 fts5StorageInsertCallback
256569 );
256570 sqlite3Fts5ClearLocale(pConfig);
256571 }
256572 }
256573 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
256574 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
256575 }
@@ -255740,53 +256632,75 @@
256632 /*
256633 ** Insert a new row into the FTS content table.
256634 */
256635 static int sqlite3Fts5StorageContentInsert(
256636 Fts5Storage *p,
256637 int bReplace, /* True to use REPLACE instead of INSERT */
256638 sqlite3_value **apVal,
256639 i64 *piRowid
256640 ){
256641 Fts5Config *pConfig = p->pConfig;
256642 int rc = SQLITE_OK;
256643
256644 /* Insert the new row into the %_content table. */
256645 if( pConfig->eContent!=FTS5_CONTENT_NORMAL
256646 && pConfig->eContent!=FTS5_CONTENT_UNINDEXED
256647 ){
256648 if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
256649 *piRowid = sqlite3_value_int64(apVal[1]);
256650 }else{
256651 rc = fts5StorageNewRowid(p, piRowid);
256652 }
256653 }else{
256654 sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
256655 int i; /* Counter variable */
256656
256657 assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT );
256658 assert( bReplace==0 || bReplace==1 );
256659 rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0);
256660 if( pInsert ) sqlite3_clear_bindings(pInsert);
256661
256662 /* Bind the rowid value */
256663 sqlite3_bind_value(pInsert, 1, apVal[1]);
256664
256665 /* Loop through values for user-defined columns. i=2 is the leftmost
256666 ** user-defined column. As is column 1 of pSavedRow. */
256667 for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
256668 int bUnindexed = pConfig->abUnindexed[i-2];
256669 if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){
256670 sqlite3_value *pVal = apVal[i];
256671
256672 if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
256673 /* This is an UPDATE statement, and user-defined column (i-2) was not
256674 ** modified. Retrieve the value from Fts5Storage.pSavedRow. */
256675 pVal = sqlite3_column_value(p->pSavedRow, i-1);
256676 if( pConfig->bLocale && bUnindexed==0 ){
256677 sqlite3_bind_value(pInsert, pConfig->nCol + i,
256678 sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1)
256679 );
256680 }
256681 }else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
256682 const char *pText = 0;
256683 const char *pLoc = 0;
256684 int nText = 0;
256685 int nLoc = 0;
256686 assert( pConfig->bLocale );
256687
256688 rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256689 if( rc==SQLITE_OK ){
256690 sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
256691 if( bUnindexed==0 ){
256692 int iLoc = pConfig->nCol + i;
256693 sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT);
256694 }
256695 }
256696
256697 continue;
256698 }
256699
256700 rc = sqlite3_bind_value(pInsert, i, pVal);
256701 }
256702 }
256703 if( rc==SQLITE_OK ){
256704 sqlite3_step(pInsert);
256705 rc = sqlite3_reset(pInsert);
256706 }
@@ -255817,27 +256731,41 @@
256731 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
256732 }
256733 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
256734 ctx.szCol = 0;
256735 if( pConfig->abUnindexed[ctx.iCol]==0 ){
 
256736 int nText = 0; /* Size of pText in bytes */
256737 const char *pText = 0; /* Pointer to buffer containing text value */
256738 int nLoc = 0; /* Size of pText in bytes */
256739 const char *pLoc = 0; /* Pointer to buffer containing text value */
256740
256741 sqlite3_value *pVal = apVal[ctx.iCol+2];
 
256742 if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
256743 pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
256744 if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
256745 int iCol = ctx.iCol + 1 + pConfig->nCol;
256746 pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol);
256747 nLoc = sqlite3_column_bytes(p->pSavedRow, iCol);
256748 }
256749 }else{
256750 pVal = apVal[ctx.iCol+2];
256751 }
256752
256753 if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
256754 rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
256755 }else{
256756 pText = (const char*)sqlite3_value_text(pVal);
256757 nText = sqlite3_value_bytes(pVal);
256758 }
256759
256760 if( rc==SQLITE_OK ){
256761 sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
256762 rc = sqlite3Fts5Tokenize(pConfig,
256763 FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
256764 fts5StorageInsertCallback
256765 );
256766 sqlite3Fts5ClearLocale(pConfig);
256767 }
256768 }
256769 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
256770 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
256771 }
@@ -255998,41 +256926,65 @@
256926 }
256927 if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
256928 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256929 }
256930 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
256931 if( pConfig->abUnindexed[i]==0 ){
256932 const char *pText = 0;
256933 int nText = 0;
256934 const char *pLoc = 0;
256935 int nLoc = 0;
256936 sqlite3_value *pVal = sqlite3_column_value(pScan, i+1);
256937
256938 if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
256939 && sqlite3Fts5IsLocaleValue(pConfig, pVal)
256940 ){
256941 rc = sqlite3Fts5DecodeLocaleValue(
256942 pVal, &pText, &nText, &pLoc, &nLoc
256943 );
256944 }else{
256945 if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
256946 int iCol = i + 1 + pConfig->nCol;
256947 pLoc = (const char*)sqlite3_column_text(pScan, iCol);
256948 nLoc = sqlite3_column_bytes(pScan, iCol);
256949 }
256950 pText = (const char*)sqlite3_value_text(pVal);
256951 nText = sqlite3_value_bytes(pVal);
256952 }
256953
256954 ctx.iCol = i;
256955 ctx.szCol = 0;
256956
256957 if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256958 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256959 }
256960
256961 if( rc==SQLITE_OK ){
256962 sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
256963 rc = sqlite3Fts5Tokenize(pConfig,
256964 FTS5_TOKENIZE_DOCUMENT,
256965 pText, nText,
256966 (void*)&ctx,
256967 fts5StorageIntegrityCallback
256968 );
256969 sqlite3Fts5ClearLocale(pConfig);
256970 }
256971
256972 /* If this is not a columnsize=0 database, check that the number
256973 ** of tokens in the value matches the aColSize[] value read from
256974 ** the %_docsize table. */
256975 if( rc==SQLITE_OK
256976 && pConfig->bColumnsize
256977 && ctx.szCol!=aColSize[i]
256978 ){
256979 rc = FTS5_CORRUPT;
256980 }
256981 aTotalSize[i] += ctx.szCol;
256982 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256983 sqlite3Fts5TermsetFree(ctx.pTermset);
256984 ctx.pTermset = 0;
256985 }
256986 }
256987 }
256988 sqlite3Fts5TermsetFree(ctx.pTermset);
256989 ctx.pTermset = 0;
256990
@@ -256454,11 +257406,11 @@
257406
257407 #define READ_UTF8(zIn, zTerm, c) \
257408 c = *(zIn++); \
257409 if( c>=0xc0 ){ \
257410 c = sqlite3Utf8Trans1[c-0xc0]; \
257411 while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
257412 c = (c<<6) + (0x3f & *(zIn++)); \
257413 } \
257414 if( c<0x80 \
257415 || (c&0xFFFFF800)==0xD800 \
257416 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
@@ -257609,22 +258561,22 @@
258561 int rc = SQLITE_OK;
258562 char aBuf[32];
258563 char *zOut = aBuf;
258564 int ii;
258565 const unsigned char *zIn = (const unsigned char*)pText;
258566 const unsigned char *zEof = (zIn ? &zIn[nText] : 0);
258567 u32 iCode = 0;
258568 int aStart[3]; /* Input offset of each character in aBuf[] */
258569
258570 UNUSED_PARAM(unusedFlags);
258571
258572 /* Populate aBuf[] with the characters for the first trigram. */
258573 for(ii=0; ii<3; ii++){
258574 do {
258575 aStart[ii] = zIn - (const unsigned char*)pText;
258576 if( zIn>=zEof ) return SQLITE_OK;
258577 READ_UTF8(zIn, zEof, iCode);
 
258578 if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
258579 }while( iCode==0 );
258580 WRITE_UTF8(zOut, iCode);
258581 }
258582
@@ -257641,12 +258593,15 @@
258593 const char *z1;
258594
258595 /* Read characters from the input up until the first non-diacritic */
258596 do {
258597 iNext = zIn - (const unsigned char*)pText;
258598 if( zIn>=zEof ){
258599 iCode = 0;
258600 break;
258601 }
258602 READ_UTF8(zIn, zEof, iCode);
 
258603 if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
258604 }while( iCode==0 );
258605
258606 /* Pass the current trigram back to fts5 */
258607 rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
@@ -259679,11 +260634,11 @@
260634
260635 return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
260636 }
260637
260638
260639 /* Here ends the fts5.c composite file. */
260640 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
260641
260642 /************** End of fts5.c ************************************************/
260643 /************** Begin file stmt.c ********************************************/
260644 /*
@@ -260035,6 +260990,7 @@
260990 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
260991
260992 /************** End of stmt.c ************************************************/
260993 /* Return the source-id for this library */
260994 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
260995 #endif /* SQLITE_AMALGAMATION */
260996 /************************** End of sqlite3.c ******************************/
260997
+80 -13
--- extsrc/sqlite3.h
+++ extsrc/sqlite3.h
@@ -144,13 +144,13 @@
144144
**
145145
** See also: [sqlite3_libversion()],
146146
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147147
** [sqlite_version()] and [sqlite_source_id()].
148148
*/
149
-#define SQLITE_VERSION "3.47.0"
150
-#define SQLITE_VERSION_NUMBER 3047000
151
-#define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
149
+#define SQLITE_VERSION "3.48.0"
150
+#define SQLITE_VERSION_NUMBER 3048000
151
+#define SQLITE_SOURCE_ID "2024-12-09 20:46:36 e2bae4143afd07de1ae55a6d2606a3b541a5b94568aa41f6a96e5d1245471653"
152152
153153
/*
154154
** CAPI3REF: Run-Time Library Version Numbers
155155
** KEYWORDS: sqlite3_version sqlite3_sourceid
156156
**
@@ -650,10 +650,17 @@
650650
**
651651
** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
652652
** filesystem supports doing multiple write operations atomically when those
653653
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
654654
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
655
+**
656
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
657
+** from the database file in amounts that are not a multiple of the
658
+** page size and that do not begin at a page boundary. Without this
659
+** property, SQLite is careful to only do full-page reads and write
660
+** on aligned pages, with the one exception that it will do a sub-page
661
+** read of the first page to access the database header.
655662
*/
656663
#define SQLITE_IOCAP_ATOMIC 0x00000001
657664
#define SQLITE_IOCAP_ATOMIC512 0x00000002
658665
#define SQLITE_IOCAP_ATOMIC1K 0x00000004
659666
#define SQLITE_IOCAP_ATOMIC2K 0x00000008
@@ -666,10 +673,11 @@
666673
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
667674
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
668675
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
669676
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
670677
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
678
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
671679
672680
/*
673681
** CAPI3REF: File Locking Levels
674682
**
675683
** SQLite uses one of these integer values as the second
@@ -812,10 +820,11 @@
812820
** <li> [SQLITE_IOCAP_SEQUENTIAL]
813821
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
814822
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
815823
** <li> [SQLITE_IOCAP_IMMUTABLE]
816824
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
825
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
817826
** </ul>
818827
**
819828
** The SQLITE_IOCAP_ATOMIC property means that all writes of
820829
** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
821830
** mean that writes of blocks that are nnn bytes in size and
@@ -1089,10 +1098,15 @@
10891098
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
10901099
** opcode causes the xFileControl method to swap the file handle with the one
10911100
** pointed to by the pArg argument. This capability is used during testing
10921101
** and only needs to be supported when SQLITE_TEST is defined.
10931102
**
1103
+** <li>[[SQLITE_FCNTL_NULL_IO]]
1104
+** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
1105
+** or file handle for the [sqlite3_file] object such that it will no longer
1106
+** read or write to the database file.
1107
+**
10941108
** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
10951109
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
10961110
** be advantageous to block on the next WAL lock if the lock is not immediately
10971111
** available. The WAL subsystem issues this signal during rare
10981112
** circumstances in order to fix a problem with priority inversion.
@@ -1242,10 +1256,11 @@
12421256
#define SQLITE_FCNTL_RESERVE_BYTES 38
12431257
#define SQLITE_FCNTL_CKPT_START 39
12441258
#define SQLITE_FCNTL_EXTERNAL_READER 40
12451259
#define SQLITE_FCNTL_CKSM_FILE 41
12461260
#define SQLITE_FCNTL_RESET_CACHE 42
1261
+#define SQLITE_FCNTL_NULL_IO 43
12471262
12481263
/* deprecated names */
12491264
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
12501265
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
12511266
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2620,14 +2635,18 @@
26202635
**
26212636
** ^These functions return the number of rows modified, inserted or
26222637
** deleted by the most recently completed INSERT, UPDATE or DELETE
26232638
** statement on the database connection specified by the only parameter.
26242639
** The two functions are identical except for the type of the return value
2625
-** and that if the number of rows modified by the most recent INSERT, UPDATE
2640
+** and that if the number of rows modified by the most recent INSERT, UPDATE,
26262641
** or DELETE is greater than the maximum value supported by type "int", then
26272642
** the return value of sqlite3_changes() is undefined. ^Executing any other
26282643
** type of SQL statement does not modify the value returned by these functions.
2644
+** For the purposes of this interface, a CREATE TABLE AS SELECT statement
2645
+** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
2646
+** added to the new table by the CREATE TABLE AS SELECT statement are not
2647
+** counted.
26292648
**
26302649
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
26312650
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
26322651
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
26332652
**
@@ -4183,15 +4202,26 @@
41834202
**
41844203
** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
41854204
** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
41864205
** to return an error (error code SQLITE_ERROR) if the statement uses
41874206
** any virtual tables.
4207
+**
4208
+** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
4209
+** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
4210
+** errors from being sent to the error log defined by
4211
+** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
4212
+** compiles to see if some SQL syntax is well-formed, without generating
4213
+** messages on the global error log when it is not. If the test compile
4214
+** fails, the sqlite3_prepare_v3() call returns the same error indications
4215
+** with or without this flag; it just omits the call to [sqlite3_log()] that
4216
+** logs the error.
41884217
** </dl>
41894218
*/
41904219
#define SQLITE_PREPARE_PERSISTENT 0x01
41914220
#define SQLITE_PREPARE_NORMALIZE 0x02
41924221
#define SQLITE_PREPARE_NO_VTAB 0x04
4222
+#define SQLITE_PREPARE_DONT_LOG 0x10
41934223
41944224
/*
41954225
** CAPI3REF: Compiling An SQL Statement
41964226
** KEYWORDS: {SQL statement compiler}
41974227
** METHOD: sqlite3
@@ -4220,17 +4250,21 @@
42204250
** and sqlite3_prepare_v3()
42214251
** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
42224252
** and sqlite3_prepare16_v3() use UTF-16.
42234253
**
42244254
** ^If the nByte argument is negative, then zSql is read up to the
4225
-** first zero terminator. ^If nByte is positive, then it is the
4226
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
4255
+** first zero terminator. ^If nByte is positive, then it is the maximum
4256
+** number of bytes read from zSql. When nByte is positive, zSql is read
4257
+** up to the first zero terminator or until the nByte bytes have been read,
4258
+** whichever comes first. ^If nByte is zero, then no prepared
42274259
** statement is generated.
42284260
** If the caller knows that the supplied string is nul-terminated, then
42294261
** there is a small performance advantage to passing an nByte parameter that
42304262
** is the number of bytes in the input string <i>including</i>
42314263
** the nul-terminator.
4264
+** Note that nByte measure the length of the input in bytes, not
4265
+** characters, even for the UTF-16 interfaces.
42324266
**
42334267
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
42344268
** past the end of the first SQL statement in zSql. These routines only
42354269
** compile the first statement in zSql, so *pzTail is left pointing to
42364270
** what remains uncompiled.
@@ -5597,11 +5631,11 @@
55975631
** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
55985632
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
55995633
** This flag instructs SQLite to omit some corner-case optimizations that
56005634
** might disrupt the operation of the [sqlite3_value_subtype()] function,
56015635
** causing it to return zero rather than the correct subtype().
5602
-** SQL functions that invokes [sqlite3_value_subtype()] should have this
5636
+** All SQL functions that invoke [sqlite3_value_subtype()] should have this
56035637
** property. If the SQLITE_SUBTYPE property is omitted, then the return
56045638
** value from [sqlite3_value_subtype()] might sometimes be zero even though
56055639
** a non-zero subtype was specified by the function argument expression.
56065640
**
56075641
** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
@@ -8362,11 +8396,11 @@
83628396
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
83638397
#define SQLITE_TESTCTRL_SEEK_COUNT 30
83648398
#define SQLITE_TESTCTRL_TRACEFLAGS 31
83658399
#define SQLITE_TESTCTRL_TUNE 32
83668400
#define SQLITE_TESTCTRL_LOGEST 33
8367
-#define SQLITE_TESTCTRL_USELONGDOUBLE 34
8401
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
83688402
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
83698403
83708404
/*
83718405
** CAPI3REF: SQL Keyword Checking
83728406
**
@@ -9338,10 +9372,20 @@
93389372
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
93399373
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
93409374
** APIs are not strictly speaking threadsafe. If they are invoked at the
93419375
** same time as another thread is invoking sqlite3_backup_step() it is
93429376
** possible that they return invalid values.
9377
+**
9378
+** <b>Alternatives To Using The Backup API</b>
9379
+**
9380
+** Other techniques for safely creating a consistent backup of an SQLite
9381
+** database include:
9382
+**
9383
+** <ul>
9384
+** <li> The [VACUUM INTO] command.
9385
+** <li> The [sqlite3_rsync] utility program.
9386
+** </ul>
93439387
*/
93449388
SQLITE_API sqlite3_backup *sqlite3_backup_init(
93459389
sqlite3 *pDest, /* Destination database handle */
93469390
const char *zDestName, /* Destination database name */
93479391
sqlite3 *pSource, /* Source database handle */
@@ -10536,10 +10580,18 @@
1053610580
** schema S in database connection D. ^On success, the
1053710581
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
1053810582
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
1053910583
** If there is not already a read-transaction open on schema S when
1054010584
** this function is called, one is opened automatically.
10585
+**
10586
+** If a read-transaction is opened by this function, then it is guaranteed
10587
+** that the returned snapshot object may not be invalidated by a database
10588
+** writer or checkpointer until after the read-transaction is closed. This
10589
+** is not guaranteed if a read-transaction is already open when this
10590
+** function is called. In that case, any subsequent write or checkpoint
10591
+** operation on the database may invalidate the returned snapshot handle,
10592
+** even while the read-transaction remains open.
1054110593
**
1054210594
** The following must be true for this function to succeed. If any of
1054310595
** the following statements are false when sqlite3_snapshot_get() is
1054410596
** called, SQLITE_ERROR is returned. The final value of *P is undefined
1054510597
** in this case.
@@ -10856,11 +10908,11 @@
1085610908
#endif
1085710909
1085810910
#ifdef __cplusplus
1085910911
} /* End of the 'extern "C"' block */
1086010912
#endif
10861
-#endif /* SQLITE3_H */
10913
+/* #endif for SQLITE3_H will be added by mksqlite3.tcl */
1086210914
1086310915
/******** Begin file sqlite3rtree.h *********/
1086410916
/*
1086510917
** 2010 August 30
1086610918
**
@@ -13107,17 +13159,32 @@
1310713159
** This is used to access token iToken of phrase hit iIdx within the
1310813160
** current row. If iIdx is less than zero or greater than or equal to the
1310913161
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
1311013162
** output variable (*ppToken) is set to point to a buffer containing the
1311113163
** matching document token, and (*pnToken) to the size of that buffer in
13112
-** bytes. This API is not available if the specified token matches a
13113
-** prefix query term. In that case both output variables are always set
13114
-** to 0.
13164
+** bytes.
1311513165
**
1311613166
** The output text is not a copy of the document text that was tokenized.
1311713167
** It is the output of the tokenizer module. For tokendata=1 tables, this
1311813168
** includes any embedded 0x00 and trailing data.
13169
+**
13170
+** This API may be slow in some cases if the token identified by parameters
13171
+** iIdx and iToken matched a prefix token in the query. In most cases, the
13172
+** first call to this API for each prefix token in the query is forced
13173
+** to scan the portion of the full-text index that matches the prefix
13174
+** token to collect the extra data required by this API. If the prefix
13175
+** token matches a large number of token instances in the document set,
13176
+** this may be a performance problem.
13177
+**
13178
+** If the user knows in advance that a query may use this API for a
13179
+** prefix token, FTS5 may be configured to collect all required data as part
13180
+** of the initial querying of the full-text index, avoiding the second scan
13181
+** entirely. This also causes prefix queries that do not use this API to
13182
+** run more slowly and use more memory. FTS5 may be configured in this way
13183
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
13184
+** option, or on a per-query basis using the
13185
+** [fts5_insttoken | fts5_insttoken()] user function.
1311913186
**
1312013187
** This API can be quite slow if used with an FTS5 table created with the
1312113188
** "detail=none" or "detail=column" option.
1312213189
**
1312313190
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -13205,11 +13272,10 @@
1320513272
** CUSTOM TOKENIZERS
1320613273
**
1320713274
** Applications may also register custom tokenizer types. A tokenizer
1320813275
** is registered by providing fts5 with a populated instance of the
1320913276
** following structure. All structure methods must be defined, setting
13210
-**
1321113277
** any member of the fts5_tokenizer struct to NULL leads to undefined
1321213278
** behaviour. The structure methods are expected to function as follows:
1321313279
**
1321413280
** xCreate:
1321513281
** This function is used to allocate and initialize a tokenizer instance.
@@ -13549,5 +13615,6 @@
1354913615
#endif
1355013616
1355113617
#endif /* _FTS5_H */
1355213618
1355313619
/******** End of fts5.h *********/
13620
+#endif /* SQLITE3_H */
1355413621
--- extsrc/sqlite3.h
+++ extsrc/sqlite3.h
@@ -144,13 +144,13 @@
144 **
145 ** See also: [sqlite3_libversion()],
146 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147 ** [sqlite_version()] and [sqlite_source_id()].
148 */
149 #define SQLITE_VERSION "3.47.0"
150 #define SQLITE_VERSION_NUMBER 3047000
151 #define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
152
153 /*
154 ** CAPI3REF: Run-Time Library Version Numbers
155 ** KEYWORDS: sqlite3_version sqlite3_sourceid
156 **
@@ -650,10 +650,17 @@
650 **
651 ** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
652 ** filesystem supports doing multiple write operations atomically when those
653 ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
654 ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
 
 
 
 
 
 
 
655 */
656 #define SQLITE_IOCAP_ATOMIC 0x00000001
657 #define SQLITE_IOCAP_ATOMIC512 0x00000002
658 #define SQLITE_IOCAP_ATOMIC1K 0x00000004
659 #define SQLITE_IOCAP_ATOMIC2K 0x00000008
@@ -666,10 +673,11 @@
666 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400
667 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
668 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
669 #define SQLITE_IOCAP_IMMUTABLE 0x00002000
670 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
 
671
672 /*
673 ** CAPI3REF: File Locking Levels
674 **
675 ** SQLite uses one of these integer values as the second
@@ -812,10 +820,11 @@
812 ** <li> [SQLITE_IOCAP_SEQUENTIAL]
813 ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
814 ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
815 ** <li> [SQLITE_IOCAP_IMMUTABLE]
816 ** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
 
817 ** </ul>
818 **
819 ** The SQLITE_IOCAP_ATOMIC property means that all writes of
820 ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
821 ** mean that writes of blocks that are nnn bytes in size and
@@ -1089,10 +1098,15 @@
1089 ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
1090 ** opcode causes the xFileControl method to swap the file handle with the one
1091 ** pointed to by the pArg argument. This capability is used during testing
1092 ** and only needs to be supported when SQLITE_TEST is defined.
1093 **
 
 
 
 
 
1094 ** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
1095 ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
1096 ** be advantageous to block on the next WAL lock if the lock is not immediately
1097 ** available. The WAL subsystem issues this signal during rare
1098 ** circumstances in order to fix a problem with priority inversion.
@@ -1242,10 +1256,11 @@
1242 #define SQLITE_FCNTL_RESERVE_BYTES 38
1243 #define SQLITE_FCNTL_CKPT_START 39
1244 #define SQLITE_FCNTL_EXTERNAL_READER 40
1245 #define SQLITE_FCNTL_CKSM_FILE 41
1246 #define SQLITE_FCNTL_RESET_CACHE 42
 
1247
1248 /* deprecated names */
1249 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1250 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1251 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2620,14 +2635,18 @@
2620 **
2621 ** ^These functions return the number of rows modified, inserted or
2622 ** deleted by the most recently completed INSERT, UPDATE or DELETE
2623 ** statement on the database connection specified by the only parameter.
2624 ** The two functions are identical except for the type of the return value
2625 ** and that if the number of rows modified by the most recent INSERT, UPDATE
2626 ** or DELETE is greater than the maximum value supported by type "int", then
2627 ** the return value of sqlite3_changes() is undefined. ^Executing any other
2628 ** type of SQL statement does not modify the value returned by these functions.
 
 
 
 
2629 **
2630 ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
2631 ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
2632 ** [foreign key actions] or [REPLACE] constraint resolution are not counted.
2633 **
@@ -4183,15 +4202,26 @@
4183 **
4184 ** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
4185 ** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
4186 ** to return an error (error code SQLITE_ERROR) if the statement uses
4187 ** any virtual tables.
 
 
 
 
 
 
 
 
 
 
4188 ** </dl>
4189 */
4190 #define SQLITE_PREPARE_PERSISTENT 0x01
4191 #define SQLITE_PREPARE_NORMALIZE 0x02
4192 #define SQLITE_PREPARE_NO_VTAB 0x04
 
4193
4194 /*
4195 ** CAPI3REF: Compiling An SQL Statement
4196 ** KEYWORDS: {SQL statement compiler}
4197 ** METHOD: sqlite3
@@ -4220,17 +4250,21 @@
4220 ** and sqlite3_prepare_v3()
4221 ** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
4222 ** and sqlite3_prepare16_v3() use UTF-16.
4223 **
4224 ** ^If the nByte argument is negative, then zSql is read up to the
4225 ** first zero terminator. ^If nByte is positive, then it is the
4226 ** number of bytes read from zSql. ^If nByte is zero, then no prepared
 
 
4227 ** statement is generated.
4228 ** If the caller knows that the supplied string is nul-terminated, then
4229 ** there is a small performance advantage to passing an nByte parameter that
4230 ** is the number of bytes in the input string <i>including</i>
4231 ** the nul-terminator.
 
 
4232 **
4233 ** ^If pzTail is not NULL then *pzTail is made to point to the first byte
4234 ** past the end of the first SQL statement in zSql. These routines only
4235 ** compile the first statement in zSql, so *pzTail is left pointing to
4236 ** what remains uncompiled.
@@ -5597,11 +5631,11 @@
5597 ** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
5598 ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
5599 ** This flag instructs SQLite to omit some corner-case optimizations that
5600 ** might disrupt the operation of the [sqlite3_value_subtype()] function,
5601 ** causing it to return zero rather than the correct subtype().
5602 ** SQL functions that invokes [sqlite3_value_subtype()] should have this
5603 ** property. If the SQLITE_SUBTYPE property is omitted, then the return
5604 ** value from [sqlite3_value_subtype()] might sometimes be zero even though
5605 ** a non-zero subtype was specified by the function argument expression.
5606 **
5607 ** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
@@ -8362,11 +8396,11 @@
8362 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8363 #define SQLITE_TESTCTRL_SEEK_COUNT 30
8364 #define SQLITE_TESTCTRL_TRACEFLAGS 31
8365 #define SQLITE_TESTCTRL_TUNE 32
8366 #define SQLITE_TESTCTRL_LOGEST 33
8367 #define SQLITE_TESTCTRL_USELONGDOUBLE 34
8368 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
8369
8370 /*
8371 ** CAPI3REF: SQL Keyword Checking
8372 **
@@ -9338,10 +9372,20 @@
9338 ** threads may safely make multiple concurrent calls to sqlite3_backup_step().
9339 ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
9340 ** APIs are not strictly speaking threadsafe. If they are invoked at the
9341 ** same time as another thread is invoking sqlite3_backup_step() it is
9342 ** possible that they return invalid values.
 
 
 
 
 
 
 
 
 
 
9343 */
9344 SQLITE_API sqlite3_backup *sqlite3_backup_init(
9345 sqlite3 *pDest, /* Destination database handle */
9346 const char *zDestName, /* Destination database name */
9347 sqlite3 *pSource, /* Source database handle */
@@ -10536,10 +10580,18 @@
10536 ** schema S in database connection D. ^On success, the
10537 ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
10538 ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
10539 ** If there is not already a read-transaction open on schema S when
10540 ** this function is called, one is opened automatically.
 
 
 
 
 
 
 
 
10541 **
10542 ** The following must be true for this function to succeed. If any of
10543 ** the following statements are false when sqlite3_snapshot_get() is
10544 ** called, SQLITE_ERROR is returned. The final value of *P is undefined
10545 ** in this case.
@@ -10856,11 +10908,11 @@
10856 #endif
10857
10858 #ifdef __cplusplus
10859 } /* End of the 'extern "C"' block */
10860 #endif
10861 #endif /* SQLITE3_H */
10862
10863 /******** Begin file sqlite3rtree.h *********/
10864 /*
10865 ** 2010 August 30
10866 **
@@ -13107,17 +13159,32 @@
13107 ** This is used to access token iToken of phrase hit iIdx within the
13108 ** current row. If iIdx is less than zero or greater than or equal to the
13109 ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
13110 ** output variable (*ppToken) is set to point to a buffer containing the
13111 ** matching document token, and (*pnToken) to the size of that buffer in
13112 ** bytes. This API is not available if the specified token matches a
13113 ** prefix query term. In that case both output variables are always set
13114 ** to 0.
13115 **
13116 ** The output text is not a copy of the document text that was tokenized.
13117 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13118 ** includes any embedded 0x00 and trailing data.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13119 **
13120 ** This API can be quite slow if used with an FTS5 table created with the
13121 ** "detail=none" or "detail=column" option.
13122 **
13123 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -13205,11 +13272,10 @@
13205 ** CUSTOM TOKENIZERS
13206 **
13207 ** Applications may also register custom tokenizer types. A tokenizer
13208 ** is registered by providing fts5 with a populated instance of the
13209 ** following structure. All structure methods must be defined, setting
13210 **
13211 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13212 ** behaviour. The structure methods are expected to function as follows:
13213 **
13214 ** xCreate:
13215 ** This function is used to allocate and initialize a tokenizer instance.
@@ -13549,5 +13615,6 @@
13549 #endif
13550
13551 #endif /* _FTS5_H */
13552
13553 /******** End of fts5.h *********/
 
13554
--- extsrc/sqlite3.h
+++ extsrc/sqlite3.h
@@ -144,13 +144,13 @@
144 **
145 ** See also: [sqlite3_libversion()],
146 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147 ** [sqlite_version()] and [sqlite_source_id()].
148 */
149 #define SQLITE_VERSION "3.48.0"
150 #define SQLITE_VERSION_NUMBER 3048000
151 #define SQLITE_SOURCE_ID "2024-12-09 20:46:36 e2bae4143afd07de1ae55a6d2606a3b541a5b94568aa41f6a96e5d1245471653"
152
153 /*
154 ** CAPI3REF: Run-Time Library Version Numbers
155 ** KEYWORDS: sqlite3_version sqlite3_sourceid
156 **
@@ -650,10 +650,17 @@
650 **
651 ** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
652 ** filesystem supports doing multiple write operations atomically when those
653 ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
654 ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
655 **
656 ** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
657 ** from the database file in amounts that are not a multiple of the
658 ** page size and that do not begin at a page boundary. Without this
659 ** property, SQLite is careful to only do full-page reads and write
660 ** on aligned pages, with the one exception that it will do a sub-page
661 ** read of the first page to access the database header.
662 */
663 #define SQLITE_IOCAP_ATOMIC 0x00000001
664 #define SQLITE_IOCAP_ATOMIC512 0x00000002
665 #define SQLITE_IOCAP_ATOMIC1K 0x00000004
666 #define SQLITE_IOCAP_ATOMIC2K 0x00000008
@@ -666,10 +673,11 @@
673 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400
674 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
675 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
676 #define SQLITE_IOCAP_IMMUTABLE 0x00002000
677 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
678 #define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
679
680 /*
681 ** CAPI3REF: File Locking Levels
682 **
683 ** SQLite uses one of these integer values as the second
@@ -812,10 +820,11 @@
820 ** <li> [SQLITE_IOCAP_SEQUENTIAL]
821 ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
822 ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
823 ** <li> [SQLITE_IOCAP_IMMUTABLE]
824 ** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
825 ** <li> [SQLITE_IOCAP_SUBPAGE_READ]
826 ** </ul>
827 **
828 ** The SQLITE_IOCAP_ATOMIC property means that all writes of
829 ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
830 ** mean that writes of blocks that are nnn bytes in size and
@@ -1089,10 +1098,15 @@
1098 ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
1099 ** opcode causes the xFileControl method to swap the file handle with the one
1100 ** pointed to by the pArg argument. This capability is used during testing
1101 ** and only needs to be supported when SQLITE_TEST is defined.
1102 **
1103 ** <li>[[SQLITE_FCNTL_NULL_IO]]
1104 ** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
1105 ** or file handle for the [sqlite3_file] object such that it will no longer
1106 ** read or write to the database file.
1107 **
1108 ** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
1109 ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
1110 ** be advantageous to block on the next WAL lock if the lock is not immediately
1111 ** available. The WAL subsystem issues this signal during rare
1112 ** circumstances in order to fix a problem with priority inversion.
@@ -1242,10 +1256,11 @@
1256 #define SQLITE_FCNTL_RESERVE_BYTES 38
1257 #define SQLITE_FCNTL_CKPT_START 39
1258 #define SQLITE_FCNTL_EXTERNAL_READER 40
1259 #define SQLITE_FCNTL_CKSM_FILE 41
1260 #define SQLITE_FCNTL_RESET_CACHE 42
1261 #define SQLITE_FCNTL_NULL_IO 43
1262
1263 /* deprecated names */
1264 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1265 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1266 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2620,14 +2635,18 @@
2635 **
2636 ** ^These functions return the number of rows modified, inserted or
2637 ** deleted by the most recently completed INSERT, UPDATE or DELETE
2638 ** statement on the database connection specified by the only parameter.
2639 ** The two functions are identical except for the type of the return value
2640 ** and that if the number of rows modified by the most recent INSERT, UPDATE,
2641 ** or DELETE is greater than the maximum value supported by type "int", then
2642 ** the return value of sqlite3_changes() is undefined. ^Executing any other
2643 ** type of SQL statement does not modify the value returned by these functions.
2644 ** For the purposes of this interface, a CREATE TABLE AS SELECT statement
2645 ** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
2646 ** added to the new table by the CREATE TABLE AS SELECT statement are not
2647 ** counted.
2648 **
2649 ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
2650 ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
2651 ** [foreign key actions] or [REPLACE] constraint resolution are not counted.
2652 **
@@ -4183,15 +4202,26 @@
4202 **
4203 ** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
4204 ** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
4205 ** to return an error (error code SQLITE_ERROR) if the statement uses
4206 ** any virtual tables.
4207 **
4208 ** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
4209 ** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
4210 ** errors from being sent to the error log defined by
4211 ** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
4212 ** compiles to see if some SQL syntax is well-formed, without generating
4213 ** messages on the global error log when it is not. If the test compile
4214 ** fails, the sqlite3_prepare_v3() call returns the same error indications
4215 ** with or without this flag; it just omits the call to [sqlite3_log()] that
4216 ** logs the error.
4217 ** </dl>
4218 */
4219 #define SQLITE_PREPARE_PERSISTENT 0x01
4220 #define SQLITE_PREPARE_NORMALIZE 0x02
4221 #define SQLITE_PREPARE_NO_VTAB 0x04
4222 #define SQLITE_PREPARE_DONT_LOG 0x10
4223
4224 /*
4225 ** CAPI3REF: Compiling An SQL Statement
4226 ** KEYWORDS: {SQL statement compiler}
4227 ** METHOD: sqlite3
@@ -4220,17 +4250,21 @@
4250 ** and sqlite3_prepare_v3()
4251 ** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
4252 ** and sqlite3_prepare16_v3() use UTF-16.
4253 **
4254 ** ^If the nByte argument is negative, then zSql is read up to the
4255 ** first zero terminator. ^If nByte is positive, then it is the maximum
4256 ** number of bytes read from zSql. When nByte is positive, zSql is read
4257 ** up to the first zero terminator or until the nByte bytes have been read,
4258 ** whichever comes first. ^If nByte is zero, then no prepared
4259 ** statement is generated.
4260 ** If the caller knows that the supplied string is nul-terminated, then
4261 ** there is a small performance advantage to passing an nByte parameter that
4262 ** is the number of bytes in the input string <i>including</i>
4263 ** the nul-terminator.
4264 ** Note that nByte measure the length of the input in bytes, not
4265 ** characters, even for the UTF-16 interfaces.
4266 **
4267 ** ^If pzTail is not NULL then *pzTail is made to point to the first byte
4268 ** past the end of the first SQL statement in zSql. These routines only
4269 ** compile the first statement in zSql, so *pzTail is left pointing to
4270 ** what remains uncompiled.
@@ -5597,11 +5631,11 @@
5631 ** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
5632 ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
5633 ** This flag instructs SQLite to omit some corner-case optimizations that
5634 ** might disrupt the operation of the [sqlite3_value_subtype()] function,
5635 ** causing it to return zero rather than the correct subtype().
5636 ** All SQL functions that invoke [sqlite3_value_subtype()] should have this
5637 ** property. If the SQLITE_SUBTYPE property is omitted, then the return
5638 ** value from [sqlite3_value_subtype()] might sometimes be zero even though
5639 ** a non-zero subtype was specified by the function argument expression.
5640 **
5641 ** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
@@ -8362,11 +8396,11 @@
8396 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8397 #define SQLITE_TESTCTRL_SEEK_COUNT 30
8398 #define SQLITE_TESTCTRL_TRACEFLAGS 31
8399 #define SQLITE_TESTCTRL_TUNE 32
8400 #define SQLITE_TESTCTRL_LOGEST 33
8401 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
8402 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
8403
8404 /*
8405 ** CAPI3REF: SQL Keyword Checking
8406 **
@@ -9338,10 +9372,20 @@
9372 ** threads may safely make multiple concurrent calls to sqlite3_backup_step().
9373 ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
9374 ** APIs are not strictly speaking threadsafe. If they are invoked at the
9375 ** same time as another thread is invoking sqlite3_backup_step() it is
9376 ** possible that they return invalid values.
9377 **
9378 ** <b>Alternatives To Using The Backup API</b>
9379 **
9380 ** Other techniques for safely creating a consistent backup of an SQLite
9381 ** database include:
9382 **
9383 ** <ul>
9384 ** <li> The [VACUUM INTO] command.
9385 ** <li> The [sqlite3_rsync] utility program.
9386 ** </ul>
9387 */
9388 SQLITE_API sqlite3_backup *sqlite3_backup_init(
9389 sqlite3 *pDest, /* Destination database handle */
9390 const char *zDestName, /* Destination database name */
9391 sqlite3 *pSource, /* Source database handle */
@@ -10536,10 +10580,18 @@
10580 ** schema S in database connection D. ^On success, the
10581 ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
10582 ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
10583 ** If there is not already a read-transaction open on schema S when
10584 ** this function is called, one is opened automatically.
10585 **
10586 ** If a read-transaction is opened by this function, then it is guaranteed
10587 ** that the returned snapshot object may not be invalidated by a database
10588 ** writer or checkpointer until after the read-transaction is closed. This
10589 ** is not guaranteed if a read-transaction is already open when this
10590 ** function is called. In that case, any subsequent write or checkpoint
10591 ** operation on the database may invalidate the returned snapshot handle,
10592 ** even while the read-transaction remains open.
10593 **
10594 ** The following must be true for this function to succeed. If any of
10595 ** the following statements are false when sqlite3_snapshot_get() is
10596 ** called, SQLITE_ERROR is returned. The final value of *P is undefined
10597 ** in this case.
@@ -10856,11 +10908,11 @@
10908 #endif
10909
10910 #ifdef __cplusplus
10911 } /* End of the 'extern "C"' block */
10912 #endif
10913 /* #endif for SQLITE3_H will be added by mksqlite3.tcl */
10914
10915 /******** Begin file sqlite3rtree.h *********/
10916 /*
10917 ** 2010 August 30
10918 **
@@ -13107,17 +13159,32 @@
13159 ** This is used to access token iToken of phrase hit iIdx within the
13160 ** current row. If iIdx is less than zero or greater than or equal to the
13161 ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
13162 ** output variable (*ppToken) is set to point to a buffer containing the
13163 ** matching document token, and (*pnToken) to the size of that buffer in
13164 ** bytes.
 
 
13165 **
13166 ** The output text is not a copy of the document text that was tokenized.
13167 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13168 ** includes any embedded 0x00 and trailing data.
13169 **
13170 ** This API may be slow in some cases if the token identified by parameters
13171 ** iIdx and iToken matched a prefix token in the query. In most cases, the
13172 ** first call to this API for each prefix token in the query is forced
13173 ** to scan the portion of the full-text index that matches the prefix
13174 ** token to collect the extra data required by this API. If the prefix
13175 ** token matches a large number of token instances in the document set,
13176 ** this may be a performance problem.
13177 **
13178 ** If the user knows in advance that a query may use this API for a
13179 ** prefix token, FTS5 may be configured to collect all required data as part
13180 ** of the initial querying of the full-text index, avoiding the second scan
13181 ** entirely. This also causes prefix queries that do not use this API to
13182 ** run more slowly and use more memory. FTS5 may be configured in this way
13183 ** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
13184 ** option, or on a per-query basis using the
13185 ** [fts5_insttoken | fts5_insttoken()] user function.
13186 **
13187 ** This API can be quite slow if used with an FTS5 table created with the
13188 ** "detail=none" or "detail=column" option.
13189 **
13190 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
@@ -13205,11 +13272,10 @@
13272 ** CUSTOM TOKENIZERS
13273 **
13274 ** Applications may also register custom tokenizer types. A tokenizer
13275 ** is registered by providing fts5 with a populated instance of the
13276 ** following structure. All structure methods must be defined, setting
 
13277 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13278 ** behaviour. The structure methods are expected to function as follows:
13279 **
13280 ** xCreate:
13281 ** This function is used to allocate and initialize a tokenizer instance.
@@ -13549,5 +13615,6 @@
13615 #endif
13616
13617 #endif /* _FTS5_H */
13618
13619 /******** End of fts5.h *********/
13620 #endif /* SQLITE3_H */
13621
+22 -17
--- fossil.1
+++ fossil.1
@@ -1,6 +1,6 @@
1
-.TH FOSSIL "1" "July 2021" "https://fossil-scm.org" "User Commands"
1
+.TH FOSSIL "1" "Oct 2024" "https://fossil-scm.org" "User Commands"
22
.SH NAME
33
fossil \- Distributed Version Control System
44
.SH SYNOPSIS
55
.B fossil
66
\fIhelp\fR
@@ -14,26 +14,31 @@
1414
Fossil is a distributed version control system (DVCS) with built-in
1515
forum, wiki, ticket tracker, CGI/HTTP interface, and HTTP server.
1616
1717
.SH Common COMMANDs:
1818
19
-add cat diff ls revert timeline
20
-.br
21
-addremove changes extras merge rm ui
22
-.br
23
-all chat finfo mv settings undo
24
-.br
25
-amend clean gdiff open sql unversioned
26
-.br
27
-annotate clone grep pull stash update
28
-.br
29
-bisect commit help push status version
30
-.br
31
-blame dbstat info rebuild sync
32
-.br
33
-branch delete init remote tag
34
-.br
19
+add cherrypick grep push sync
20
+.br
21
+addremove clean help rebuild tag
22
+.br
23
+all clone info remote timeline
24
+.br
25
+amend commit init repack tree
26
+.br
27
+annotate dbstat ls revert ui
28
+.br
29
+bisect delete merge rm undo
30
+.br
31
+blame describe merge-base settings unversioned
32
+.br
33
+branch diff mv sql update
34
+.br
35
+cat extras open ssl-config version
36
+.br
37
+changes finfo patch stash xdiff
38
+.br
39
+chat gdiff pull status
3540
3641
.SH FEATURES
3742
3843
Features as described on the fossil home page.
3944
4045
--- fossil.1
+++ fossil.1
@@ -1,6 +1,6 @@
1 .TH FOSSIL "1" "July 2021" "https://fossil-scm.org" "User Commands"
2 .SH NAME
3 fossil \- Distributed Version Control System
4 .SH SYNOPSIS
5 .B fossil
6 \fIhelp\fR
@@ -14,26 +14,31 @@
14 Fossil is a distributed version control system (DVCS) with built-in
15 forum, wiki, ticket tracker, CGI/HTTP interface, and HTTP server.
16
17 .SH Common COMMANDs:
18
19 add cat diff ls revert timeline
20 .br
21 addremove changes extras merge rm ui
22 .br
23 all chat finfo mv settings undo
24 .br
25 amend clean gdiff open sql unversioned
26 .br
27 annotate clone grep pull stash update
28 .br
29 bisect commit help push status version
30 .br
31 blame dbstat info rebuild sync
32 .br
33 branch delete init remote tag
34 .br
 
 
 
 
 
35
36 .SH FEATURES
37
38 Features as described on the fossil home page.
39
40
--- fossil.1
+++ fossil.1
@@ -1,6 +1,6 @@
1 .TH FOSSIL "1" "Oct 2024" "https://fossil-scm.org" "User Commands"
2 .SH NAME
3 fossil \- Distributed Version Control System
4 .SH SYNOPSIS
5 .B fossil
6 \fIhelp\fR
@@ -14,26 +14,31 @@
14 Fossil is a distributed version control system (DVCS) with built-in
15 forum, wiki, ticket tracker, CGI/HTTP interface, and HTTP server.
16
17 .SH Common COMMANDs:
18
19 add cherrypick grep push sync
20 .br
21 addremove clean help rebuild tag
22 .br
23 all clone info remote timeline
24 .br
25 amend commit init repack tree
26 .br
27 annotate dbstat ls revert ui
28 .br
29 bisect delete merge rm undo
30 .br
31 blame describe merge-base settings unversioned
32 .br
33 branch diff mv sql update
34 .br
35 cat extras open ssl-config version
36 .br
37 changes finfo patch stash xdiff
38 .br
39 chat gdiff pull status
40
41 .SH FEATURES
42
43 Features as described on the fossil home page.
44
45
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -98,14 +98,17 @@
9898
}
9999
.fileage tr:hover,
100100
div.filetreeline:hover {
101101
background-color: #333;
102102
}
103
+div.file-change-line button {
104
+ background-color: #484848
105
+}
103106
.button,
104107
button {
105108
color: #aaa;
106
- background-color: #444;
109
+ background-color: #484848;
107110
border-radius: 5px;
108111
border: 0
109112
}
110113
.button:hover,
111114
button:hover {
112115
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -98,14 +98,17 @@
98 }
99 .fileage tr:hover,
100 div.filetreeline:hover {
101 background-color: #333;
102 }
 
 
 
103 .button,
104 button {
105 color: #aaa;
106 background-color: #444;
107 border-radius: 5px;
108 border: 0
109 }
110 .button:hover,
111 button:hover {
112
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -98,14 +98,17 @@
98 }
99 .fileage tr:hover,
100 div.filetreeline:hover {
101 background-color: #333;
102 }
103 div.file-change-line button {
104 background-color: #484848
105 }
106 .button,
107 button {
108 color: #aaa;
109 background-color: #484848;
110 border-radius: 5px;
111 border: 0
112 }
113 .button:hover,
114 button:hover {
115
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -42,10 +42,11 @@
4242
.artifact h1.page-title,
4343
.dir h1.page-title,
4444
.doc h1.page-title,
4545
.wiki h1.page-title {
4646
display: block; /* …for potentially long doc titles… */
47
+ color: #444;
4748
}
4849
.artifact .title > .page-title,
4950
.dir .title > .page-title,
5051
.doc .title > .page-title,
5152
.wiki .title > .page-title {
@@ -725,16 +726,16 @@
725726
margin-left: 20pt; /* special case for MD in forum; need less indent */
726727
}
727728
728729
/* Fossil UI uses these, but in sufficiently constrained ways that we
729730
* don't have to be nearly as careful to avoid an overreach. */
730
- .doc > .content h1, .artifact h1, .dir h1, .fileedit h1, .wiki h1 { margin-left: 10pt; }
731
- .doc > .content h2, .artifact h2, .dir h2, .fileedit h2, .wiki h2 { margin-left: 20pt; }
732
- .doc > .content h3, .artifact h3, .dir h3, .fileedit h3, .wiki h3 { margin-left: 30pt; }
733
- .doc > .content h4, .artifact h4, .dir h4, .fileedit h4, .wiki h4 { margin-left: 40pt; }
734
- .doc > .content h5, .artifact h5, .dir h5, .fileedit h5, .wiki h5 { margin-left: 50pt; }
735
- .doc > .content hr, .artifact hr, .dir hr, .fileedit hr, .wiki hr { margin-left: 10pt; }
731
+ .doc > .content h1, .artifact .content h1, .dir .content h1, .fileedit .content h1, .wiki .content h1 { margin-left: 10pt; }
732
+ .doc > .content h2, .artifact .content h2, .dir .content h2, .fileedit .content h2, .wiki .content h2 { margin-left: 20pt; }
733
+ .doc > .content h3, .artifact .content h3, .dir .content h3, .fileedit .content h3, .wiki .content h3 { margin-left: 30pt; }
734
+ .doc > .content h4, .artifact .content h4, .dir .content h4, .fileedit .content h4, .wiki .content h4 { margin-left: 40pt; }
735
+ .doc > .content h5, .artifact .content h5, .dir .content h5, .fileedit .content h5, .wiki .content h5 { margin-left: 50pt; }
736
+ .doc > .content hr, .artifact .content hr, .dir .content hr, .fileedit .content hr, .wiki .content hr { margin-left: 10pt; }
736737
737738
/* Don't need to be nearly as careful with tags Fossil UI doesn't use. */
738739
.doc dd, .artifact dd, .dir dd, .fileedit dd, .wikiedit dd { margin-left: 30pt; margin-bottom: 1em; }
739740
.doc dl, .artifact dl, .dir dl, .fileedit dl, .wikiedit dl { margin-left: 60pt; }
740741
.doc dt, .artifact dt, .dir dt, .fileedit dt, .wikiedit dt { margin-left: 10pt; }
741742
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -42,10 +42,11 @@
42 .artifact h1.page-title,
43 .dir h1.page-title,
44 .doc h1.page-title,
45 .wiki h1.page-title {
46 display: block; /* …for potentially long doc titles… */
 
47 }
48 .artifact .title > .page-title,
49 .dir .title > .page-title,
50 .doc .title > .page-title,
51 .wiki .title > .page-title {
@@ -725,16 +726,16 @@
725 margin-left: 20pt; /* special case for MD in forum; need less indent */
726 }
727
728 /* Fossil UI uses these, but in sufficiently constrained ways that we
729 * don't have to be nearly as careful to avoid an overreach. */
730 .doc > .content h1, .artifact h1, .dir h1, .fileedit h1, .wiki h1 { margin-left: 10pt; }
731 .doc > .content h2, .artifact h2, .dir h2, .fileedit h2, .wiki h2 { margin-left: 20pt; }
732 .doc > .content h3, .artifact h3, .dir h3, .fileedit h3, .wiki h3 { margin-left: 30pt; }
733 .doc > .content h4, .artifact h4, .dir h4, .fileedit h4, .wiki h4 { margin-left: 40pt; }
734 .doc > .content h5, .artifact h5, .dir h5, .fileedit h5, .wiki h5 { margin-left: 50pt; }
735 .doc > .content hr, .artifact hr, .dir hr, .fileedit hr, .wiki hr { margin-left: 10pt; }
736
737 /* Don't need to be nearly as careful with tags Fossil UI doesn't use. */
738 .doc dd, .artifact dd, .dir dd, .fileedit dd, .wikiedit dd { margin-left: 30pt; margin-bottom: 1em; }
739 .doc dl, .artifact dl, .dir dl, .fileedit dl, .wikiedit dl { margin-left: 60pt; }
740 .doc dt, .artifact dt, .dir dt, .fileedit dt, .wikiedit dt { margin-left: 10pt; }
741
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -42,10 +42,11 @@
42 .artifact h1.page-title,
43 .dir h1.page-title,
44 .doc h1.page-title,
45 .wiki h1.page-title {
46 display: block; /* …for potentially long doc titles… */
47 color: #444;
48 }
49 .artifact .title > .page-title,
50 .dir .title > .page-title,
51 .doc .title > .page-title,
52 .wiki .title > .page-title {
@@ -725,16 +726,16 @@
726 margin-left: 20pt; /* special case for MD in forum; need less indent */
727 }
728
729 /* Fossil UI uses these, but in sufficiently constrained ways that we
730 * don't have to be nearly as careful to avoid an overreach. */
731 .doc > .content h1, .artifact .content h1, .dir .content h1, .fileedit .content h1, .wiki .content h1 { margin-left: 10pt; }
732 .doc > .content h2, .artifact .content h2, .dir .content h2, .fileedit .content h2, .wiki .content h2 { margin-left: 20pt; }
733 .doc > .content h3, .artifact .content h3, .dir .content h3, .fileedit .content h3, .wiki .content h3 { margin-left: 30pt; }
734 .doc > .content h4, .artifact .content h4, .dir .content h4, .fileedit .content h4, .wiki .content h4 { margin-left: 40pt; }
735 .doc > .content h5, .artifact .content h5, .dir .content h5, .fileedit .content h5, .wiki .content h5 { margin-left: 50pt; }
736 .doc > .content hr, .artifact .content hr, .dir .content hr, .fileedit .content hr, .wiki .content hr { margin-left: 10pt; }
737
738 /* Don't need to be nearly as careful with tags Fossil UI doesn't use. */
739 .doc dd, .artifact dd, .dir dd, .fileedit dd, .wikiedit dd { margin-left: 30pt; margin-bottom: 1em; }
740 .doc dl, .artifact dl, .dir dl, .fileedit dl, .wikiedit dl { margin-left: 60pt; }
741 .doc dt, .artifact dt, .dir dt, .fileedit dt, .wikiedit dt { margin-left: 10pt; }
742
+1 -1
--- src/add.c
+++ src/add.c
@@ -353,11 +353,11 @@
353353
** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore
354354
** option does not appear on the command line then the "ignore-glob" setting
355355
** is used. If the --clean option does not appear on the command line then
356356
** the "clean-glob" setting is used.
357357
**
358
-** If files are attempted to be added explicitly on the command line which
358
+** When attempting to explicitly add files on the commandline, and if those
359359
** match "ignore-glob", a confirmation is asked first. This can be prevented
360360
** using the -f|--force option.
361361
**
362362
** The --case-sensitive option determines whether or not filenames should
363363
** be treated case sensitive or not. If the option is not given, the default
364364
--- src/add.c
+++ src/add.c
@@ -353,11 +353,11 @@
353 ** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore
354 ** option does not appear on the command line then the "ignore-glob" setting
355 ** is used. If the --clean option does not appear on the command line then
356 ** the "clean-glob" setting is used.
357 **
358 ** If files are attempted to be added explicitly on the command line which
359 ** match "ignore-glob", a confirmation is asked first. This can be prevented
360 ** using the -f|--force option.
361 **
362 ** The --case-sensitive option determines whether or not filenames should
363 ** be treated case sensitive or not. If the option is not given, the default
364
--- src/add.c
+++ src/add.c
@@ -353,11 +353,11 @@
353 ** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore
354 ** option does not appear on the command line then the "ignore-glob" setting
355 ** is used. If the --clean option does not appear on the command line then
356 ** the "clean-glob" setting is used.
357 **
358 ** When attempting to explicitly add files on the commandline, and if those
359 ** match "ignore-glob", a confirmation is asked first. This can be prevented
360 ** using the -f|--force option.
361 **
362 ** The --case-sensitive option determines whether or not filenames should
363 ** be treated case sensitive or not. If the option is not given, the default
364
+23 -6
--- src/allrepo.c
+++ src/allrepo.c
@@ -50,11 +50,10 @@
5050
for(i=iStart; i<g.argc; i++){
5151
blob_appendf(pExtra, " %s", g.argv[i]);
5252
}
5353
}
5454
55
-
5655
/*
5756
** COMMAND: all
5857
**
5958
** Usage: %fossil all SUBCOMMAND ...
6059
**
@@ -429,44 +428,62 @@
429428
"add cache changes clean dbstat extras fts-config git ignore "
430429
"info list ls pull push rebuild remote "
431430
"server settings sync ui unset whatis");
432431
}
433432
verify_all_options();
434
- db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
433
+ db_multi_exec(
434
+ "CREATE TEMP TABLE repolist(\n"
435
+ " name TEXT, -- Filename\n"
436
+ " tag TEXT, -- Key for the GLOBAL_CONFIG table entry\n"
437
+ " inode TEXT -- Unique identifier for this file\n"
438
+ ");\n"
439
+
440
+ /* The seenFile() table holds inode names for entries that have
441
+ ** already been processed. */
442
+ "CREATE TEMP TABLE seenFile(x TEXT COLLATE nocase);\n"
443
+
444
+ /* The toDel() table holds the "tag" for entries that need to be
445
+ ** deleted because they are redundant or no longer exist */
446
+ "CREATE TEMP TABLE toDel(x TEXT);\n"
447
+ );
448
+ sqlite3_create_function(g.db, "inode", 1, SQLITE_UTF8, 0,
449
+ file_inode_sql_func, 0, 0);
435450
if( useCheckouts ){
436451
db_multi_exec(
437452
"INSERT INTO repolist "
438
- "SELECT DISTINCT substr(name, 7), name COLLATE nocase"
453
+ "SELECT substr(name, 7), name, inode(substr(name,7))"
439454
" FROM global_config"
440455
" WHERE substr(name, 1, 6)=='ckout:'"
441456
" ORDER BY 1"
442457
);
443458
}else{
444459
db_multi_exec(
445460
"INSERT INTO repolist "
446
- "SELECT DISTINCT substr(name, 6), name COLLATE nocase"
461
+ "SELECT substr(name, 6), name, inode(substr(name,6))"
447462
" FROM global_config"
448463
" WHERE substr(name, 1, 5)=='repo:'"
449464
" ORDER BY 1"
450465
);
451466
}
452
- db_multi_exec("CREATE TEMP TABLE toDel(x TEXT)");
453
- db_prepare(&q, "SELECT name, tag FROM repolist ORDER BY 1");
467
+ db_prepare(&q,"SELECT name, tag, inode FROM repolist ORDER BY 1");
454468
while( db_step(&q)==SQLITE_ROW ){
455469
int rc;
456470
const char *zFilename = db_column_text(&q, 0);
471
+ const char *zInode = db_column_text(&q,2);
457472
#if !USE_SEE
458473
if( sqlite3_strglob("*.efossil", zFilename)==0 ) continue;
459474
#endif
460475
if( file_access(zFilename, F_OK)
461476
|| !file_is_canonical(zFilename)
462477
|| (useCheckouts && file_isdir(zFilename, ExtFILE)!=1)
478
+ || db_exists("SELECT 1 FROM temp.seenFile where x=%Q", zInode)
463479
){
464480
db_multi_exec("INSERT INTO toDel VALUES(%Q)", db_column_text(&q, 1));
465481
nToDel++;
466482
continue;
467483
}
484
+ db_multi_exec("INSERT INTO seenFile(x) VALUES(%Q)", zInode);
468485
if( zCmd[0]=='l' ){
469486
fossil_print("%s\n", zFilename);
470487
continue;
471488
}else if( showFile ){
472489
fossil_print("%s: %s\n", useCheckouts ? "check-out" : "repository",
473490
--- src/allrepo.c
+++ src/allrepo.c
@@ -50,11 +50,10 @@
50 for(i=iStart; i<g.argc; i++){
51 blob_appendf(pExtra, " %s", g.argv[i]);
52 }
53 }
54
55
56 /*
57 ** COMMAND: all
58 **
59 ** Usage: %fossil all SUBCOMMAND ...
60 **
@@ -429,44 +428,62 @@
429 "add cache changes clean dbstat extras fts-config git ignore "
430 "info list ls pull push rebuild remote "
431 "server settings sync ui unset whatis");
432 }
433 verify_all_options();
434 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435 if( useCheckouts ){
436 db_multi_exec(
437 "INSERT INTO repolist "
438 "SELECT DISTINCT substr(name, 7), name COLLATE nocase"
439 " FROM global_config"
440 " WHERE substr(name, 1, 6)=='ckout:'"
441 " ORDER BY 1"
442 );
443 }else{
444 db_multi_exec(
445 "INSERT INTO repolist "
446 "SELECT DISTINCT substr(name, 6), name COLLATE nocase"
447 " FROM global_config"
448 " WHERE substr(name, 1, 5)=='repo:'"
449 " ORDER BY 1"
450 );
451 }
452 db_multi_exec("CREATE TEMP TABLE toDel(x TEXT)");
453 db_prepare(&q, "SELECT name, tag FROM repolist ORDER BY 1");
454 while( db_step(&q)==SQLITE_ROW ){
455 int rc;
456 const char *zFilename = db_column_text(&q, 0);
 
457 #if !USE_SEE
458 if( sqlite3_strglob("*.efossil", zFilename)==0 ) continue;
459 #endif
460 if( file_access(zFilename, F_OK)
461 || !file_is_canonical(zFilename)
462 || (useCheckouts && file_isdir(zFilename, ExtFILE)!=1)
 
463 ){
464 db_multi_exec("INSERT INTO toDel VALUES(%Q)", db_column_text(&q, 1));
465 nToDel++;
466 continue;
467 }
 
468 if( zCmd[0]=='l' ){
469 fossil_print("%s\n", zFilename);
470 continue;
471 }else if( showFile ){
472 fossil_print("%s: %s\n", useCheckouts ? "check-out" : "repository",
473
--- src/allrepo.c
+++ src/allrepo.c
@@ -50,11 +50,10 @@
50 for(i=iStart; i<g.argc; i++){
51 blob_appendf(pExtra, " %s", g.argv[i]);
52 }
53 }
54
 
55 /*
56 ** COMMAND: all
57 **
58 ** Usage: %fossil all SUBCOMMAND ...
59 **
@@ -429,44 +428,62 @@
428 "add cache changes clean dbstat extras fts-config git ignore "
429 "info list ls pull push rebuild remote "
430 "server settings sync ui unset whatis");
431 }
432 verify_all_options();
433 db_multi_exec(
434 "CREATE TEMP TABLE repolist(\n"
435 " name TEXT, -- Filename\n"
436 " tag TEXT, -- Key for the GLOBAL_CONFIG table entry\n"
437 " inode TEXT -- Unique identifier for this file\n"
438 ");\n"
439
440 /* The seenFile() table holds inode names for entries that have
441 ** already been processed. */
442 "CREATE TEMP TABLE seenFile(x TEXT COLLATE nocase);\n"
443
444 /* The toDel() table holds the "tag" for entries that need to be
445 ** deleted because they are redundant or no longer exist */
446 "CREATE TEMP TABLE toDel(x TEXT);\n"
447 );
448 sqlite3_create_function(g.db, "inode", 1, SQLITE_UTF8, 0,
449 file_inode_sql_func, 0, 0);
450 if( useCheckouts ){
451 db_multi_exec(
452 "INSERT INTO repolist "
453 "SELECT substr(name, 7), name, inode(substr(name,7))"
454 " FROM global_config"
455 " WHERE substr(name, 1, 6)=='ckout:'"
456 " ORDER BY 1"
457 );
458 }else{
459 db_multi_exec(
460 "INSERT INTO repolist "
461 "SELECT substr(name, 6), name, inode(substr(name,6))"
462 " FROM global_config"
463 " WHERE substr(name, 1, 5)=='repo:'"
464 " ORDER BY 1"
465 );
466 }
467 db_prepare(&q,"SELECT name, tag, inode FROM repolist ORDER BY 1");
 
468 while( db_step(&q)==SQLITE_ROW ){
469 int rc;
470 const char *zFilename = db_column_text(&q, 0);
471 const char *zInode = db_column_text(&q,2);
472 #if !USE_SEE
473 if( sqlite3_strglob("*.efossil", zFilename)==0 ) continue;
474 #endif
475 if( file_access(zFilename, F_OK)
476 || !file_is_canonical(zFilename)
477 || (useCheckouts && file_isdir(zFilename, ExtFILE)!=1)
478 || db_exists("SELECT 1 FROM temp.seenFile where x=%Q", zInode)
479 ){
480 db_multi_exec("INSERT INTO toDel VALUES(%Q)", db_column_text(&q, 1));
481 nToDel++;
482 continue;
483 }
484 db_multi_exec("INSERT INTO seenFile(x) VALUES(%Q)", zInode);
485 if( zCmd[0]=='l' ){
486 fossil_print("%s\n", zFilename);
487 continue;
488 }else if( showFile ){
489 fossil_print("%s: %s\n", useCheckouts ? "check-out" : "repository",
490
+8 -1
--- src/attach.c
+++ src/attach.c
@@ -634,11 +634,12 @@
634634
/*
635635
** Output HTML to show a list of attachments.
636636
*/
637637
void attachment_list(
638638
const char *zTarget, /* Object that things are attached to */
639
- const char *zHeader /* Header to display with attachments */
639
+ const char *zHeader, /* Header to display with attachments */
640
+ int fHorizontalRule /* Insert <hr> separator above header */
640641
){
641642
int cnt = 0;
642643
Stmt q;
643644
db_prepare(&q,
644645
"SELECT datetime(mtime,toLocal()), filename, user,"
@@ -654,11 +655,16 @@
654655
const char *zUser = db_column_text(&q, 2);
655656
const char *zUuid = db_column_text(&q, 3);
656657
const char *zSrc = db_column_text(&q, 4);
657658
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
658659
if( cnt==0 ){
660
+ @ <section class='attachlist'>
661
+ if( fHorizontalRule ){
662
+ @ <hr>
663
+ }
659664
@ %s(zHeader)
665
+ @ <ul>
660666
}
661667
cnt++;
662668
@ <li>
663669
@ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a>
664670
@ [<a href="%R/attachdownload/%t(zFile)?page=%t(zTarget)&file=%t(zFile)">download</a>]
@@ -667,10 +673,11 @@
667673
@ [%z(href("%R/ainfo/%!S",zUuid))details</a>]
668674
@ </li>
669675
}
670676
if( cnt ){
671677
@ </ul>
678
+ @ </section>
672679
}
673680
db_finalize(&q);
674681
675682
}
676683
677684
--- src/attach.c
+++ src/attach.c
@@ -634,11 +634,12 @@
634 /*
635 ** Output HTML to show a list of attachments.
636 */
637 void attachment_list(
638 const char *zTarget, /* Object that things are attached to */
639 const char *zHeader /* Header to display with attachments */
 
640 ){
641 int cnt = 0;
642 Stmt q;
643 db_prepare(&q,
644 "SELECT datetime(mtime,toLocal()), filename, user,"
@@ -654,11 +655,16 @@
654 const char *zUser = db_column_text(&q, 2);
655 const char *zUuid = db_column_text(&q, 3);
656 const char *zSrc = db_column_text(&q, 4);
657 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
658 if( cnt==0 ){
 
 
 
 
659 @ %s(zHeader)
 
660 }
661 cnt++;
662 @ <li>
663 @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a>
664 @ [<a href="%R/attachdownload/%t(zFile)?page=%t(zTarget)&file=%t(zFile)">download</a>]
@@ -667,10 +673,11 @@
667 @ [%z(href("%R/ainfo/%!S",zUuid))details</a>]
668 @ </li>
669 }
670 if( cnt ){
671 @ </ul>
 
672 }
673 db_finalize(&q);
674
675 }
676
677
--- src/attach.c
+++ src/attach.c
@@ -634,11 +634,12 @@
634 /*
635 ** Output HTML to show a list of attachments.
636 */
637 void attachment_list(
638 const char *zTarget, /* Object that things are attached to */
639 const char *zHeader, /* Header to display with attachments */
640 int fHorizontalRule /* Insert <hr> separator above header */
641 ){
642 int cnt = 0;
643 Stmt q;
644 db_prepare(&q,
645 "SELECT datetime(mtime,toLocal()), filename, user,"
@@ -654,11 +655,16 @@
655 const char *zUser = db_column_text(&q, 2);
656 const char *zUuid = db_column_text(&q, 3);
657 const char *zSrc = db_column_text(&q, 4);
658 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
659 if( cnt==0 ){
660 @ <section class='attachlist'>
661 if( fHorizontalRule ){
662 @ <hr>
663 }
664 @ %s(zHeader)
665 @ <ul>
666 }
667 cnt++;
668 @ <li>
669 @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a>
670 @ [<a href="%R/attachdownload/%t(zFile)?page=%t(zTarget)&file=%t(zFile)">download</a>]
@@ -667,10 +673,11 @@
673 @ [%z(href("%R/ainfo/%!S",zUuid))details</a>]
674 @ </li>
675 }
676 if( cnt ){
677 @ </ul>
678 @ </section>
679 }
680 db_finalize(&q);
681
682 }
683
684
+12 -4
--- src/bisect.c
+++ src/bisect.c
@@ -543,14 +543,16 @@
543543
**
544544
** > fossil bisect vlist|ls|status ?-a|--all?
545545
**
546546
** List the versions in between the inner-most "bad" and "good".
547547
**
548
-** > fossil bisect ui
548
+** > fossil bisect ui ?HOST@USER:PATH?
549549
**
550550
** Like "fossil ui" except start on a timeline that shows only the
551
-** check-ins that are part of the current bisect.
551
+** check-ins that are part of the current bisect. If the optional
552
+** fourth term is added, then information is shown for the bisect that
553
+** occurred in the PATH directory by USER on remote machine HOST.
552554
**
553555
** > fossil bisect undo
554556
**
555557
** Undo the most recent "good", "bad", or "skip" command.
556558
*/
@@ -719,17 +721,23 @@
719721
}
720722
}else if( strncmp(zCmd, "reset", n)==0 ){
721723
bisect_reset();
722724
}else if( strcmp(zCmd, "ui")==0 ){
723725
char *newArgv[8];
726
+ verify_all_options();
724727
newArgv[0] = g.argv[0];
725728
newArgv[1] = "ui";
726729
newArgv[2] = "--page";
727730
newArgv[3] = "timeline?bisect";
728
- newArgv[4] = 0;
731
+ if( g.argc==4 ){
732
+ newArgv[4] = g.argv[3];
733
+ g.argc = 5;
734
+ }else{
735
+ g.argc = 4;
736
+ }
737
+ newArgv[g.argc] = 0;
729738
g.argv = newArgv;
730
- g.argc = 4;
731739
cmd_webserver();
732740
}else if( strncmp(zCmd, "vlist", n)==0
733741
|| strncmp(zCmd, "ls", n)==0
734742
|| strncmp(zCmd, "status", n)==0
735743
){
736744
--- src/bisect.c
+++ src/bisect.c
@@ -543,14 +543,16 @@
543 **
544 ** > fossil bisect vlist|ls|status ?-a|--all?
545 **
546 ** List the versions in between the inner-most "bad" and "good".
547 **
548 ** > fossil bisect ui
549 **
550 ** Like "fossil ui" except start on a timeline that shows only the
551 ** check-ins that are part of the current bisect.
 
 
552 **
553 ** > fossil bisect undo
554 **
555 ** Undo the most recent "good", "bad", or "skip" command.
556 */
@@ -719,17 +721,23 @@
719 }
720 }else if( strncmp(zCmd, "reset", n)==0 ){
721 bisect_reset();
722 }else if( strcmp(zCmd, "ui")==0 ){
723 char *newArgv[8];
 
724 newArgv[0] = g.argv[0];
725 newArgv[1] = "ui";
726 newArgv[2] = "--page";
727 newArgv[3] = "timeline?bisect";
728 newArgv[4] = 0;
 
 
 
 
 
 
729 g.argv = newArgv;
730 g.argc = 4;
731 cmd_webserver();
732 }else if( strncmp(zCmd, "vlist", n)==0
733 || strncmp(zCmd, "ls", n)==0
734 || strncmp(zCmd, "status", n)==0
735 ){
736
--- src/bisect.c
+++ src/bisect.c
@@ -543,14 +543,16 @@
543 **
544 ** > fossil bisect vlist|ls|status ?-a|--all?
545 **
546 ** List the versions in between the inner-most "bad" and "good".
547 **
548 ** > fossil bisect ui ?HOST@USER:PATH?
549 **
550 ** Like "fossil ui" except start on a timeline that shows only the
551 ** check-ins that are part of the current bisect. If the optional
552 ** fourth term is added, then information is shown for the bisect that
553 ** occurred in the PATH directory by USER on remote machine HOST.
554 **
555 ** > fossil bisect undo
556 **
557 ** Undo the most recent "good", "bad", or "skip" command.
558 */
@@ -719,17 +721,23 @@
721 }
722 }else if( strncmp(zCmd, "reset", n)==0 ){
723 bisect_reset();
724 }else if( strcmp(zCmd, "ui")==0 ){
725 char *newArgv[8];
726 verify_all_options();
727 newArgv[0] = g.argv[0];
728 newArgv[1] = "ui";
729 newArgv[2] = "--page";
730 newArgv[3] = "timeline?bisect";
731 if( g.argc==4 ){
732 newArgv[4] = g.argv[3];
733 g.argc = 5;
734 }else{
735 g.argc = 4;
736 }
737 newArgv[g.argc] = 0;
738 g.argv = newArgv;
 
739 cmd_webserver();
740 }else if( strncmp(zCmd, "vlist", n)==0
741 || strncmp(zCmd, "ls", n)==0
742 || strncmp(zCmd, "status", n)==0
743 ){
744
+49 -1
--- src/blob.c
+++ src/blob.c
@@ -665,11 +665,12 @@
665665
pBlob->nUsed = dehttpize(pBlob->aData);
666666
}
667667
668668
/*
669669
** Extract N bytes from blob pFrom and use it to initialize blob pTo.
670
-** Return the actual number of bytes extracted.
670
+** Return the actual number of bytes extracted. The cursor position
671
+** is advanced by the number of bytes extracted.
671672
**
672673
** After this call completes, pTo will be an ephemeral blob.
673674
*/
674675
int blob_extract(Blob *pFrom, int N, Blob *pTo){
675676
blob_is_init(pFrom);
@@ -687,10 +688,57 @@
687688
pTo->iCursor = 0;
688689
pTo->xRealloc = blobReallocStatic;
689690
pFrom->iCursor += N;
690691
return N;
691692
}
693
+
694
+/*
695
+** Extract N **lines** of text from blob pFrom beginning at the current
696
+** cursor position and use that text to initialize blob pTo. Unlike the
697
+** blob_extract() routine, the cursor position is unchanged.
698
+**
699
+** pTo is assumed to be uninitialized.
700
+**
701
+** After this call completes, pTo will be an ephemeral blob.
702
+*/
703
+int blob_extract_lines(Blob *pFrom, int N, Blob *pTo){
704
+ int i;
705
+ int mx;
706
+ int iStart;
707
+ int n;
708
+ const char *z;
709
+
710
+ blob_zero(pTo);
711
+ z = pFrom->aData;
712
+ i = pFrom->iCursor;
713
+ mx = pFrom->nUsed;
714
+ while( N>0 ){
715
+ while( i<mx && z[i]!='\n' ){ i++; }
716
+ if( i>=mx ) break;
717
+ i++;
718
+ N--;
719
+ }
720
+ iStart = pFrom->iCursor;
721
+ n = blob_extract(pFrom, i-pFrom->iCursor, pTo);
722
+ pFrom->iCursor = iStart;
723
+ return n;
724
+}
725
+
726
+/*
727
+** Return the number of lines of text in the blob. If the last
728
+** line is incomplete (if it does not have a \n at the end) then
729
+** it still counts.
730
+*/
731
+int blob_linecount(Blob *p){
732
+ int n = 0;
733
+ int i;
734
+ for(i=0; i<p->nUsed; i++){
735
+ if( p->aData[i]=='\n' ) n++;
736
+ }
737
+ if( p->nUsed>0 && p->aData[p->nUsed-1]!='\n' ) n++;
738
+ return n;
739
+}
692740
693741
/*
694742
** Rewind the cursor on a blob back to the beginning.
695743
*/
696744
void blob_rewind(Blob *p){
697745
--- src/blob.c
+++ src/blob.c
@@ -665,11 +665,12 @@
665 pBlob->nUsed = dehttpize(pBlob->aData);
666 }
667
668 /*
669 ** Extract N bytes from blob pFrom and use it to initialize blob pTo.
670 ** Return the actual number of bytes extracted.
 
671 **
672 ** After this call completes, pTo will be an ephemeral blob.
673 */
674 int blob_extract(Blob *pFrom, int N, Blob *pTo){
675 blob_is_init(pFrom);
@@ -687,10 +688,57 @@
687 pTo->iCursor = 0;
688 pTo->xRealloc = blobReallocStatic;
689 pFrom->iCursor += N;
690 return N;
691 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
693 /*
694 ** Rewind the cursor on a blob back to the beginning.
695 */
696 void blob_rewind(Blob *p){
697
--- src/blob.c
+++ src/blob.c
@@ -665,11 +665,12 @@
665 pBlob->nUsed = dehttpize(pBlob->aData);
666 }
667
668 /*
669 ** Extract N bytes from blob pFrom and use it to initialize blob pTo.
670 ** Return the actual number of bytes extracted. The cursor position
671 ** is advanced by the number of bytes extracted.
672 **
673 ** After this call completes, pTo will be an ephemeral blob.
674 */
675 int blob_extract(Blob *pFrom, int N, Blob *pTo){
676 blob_is_init(pFrom);
@@ -687,10 +688,57 @@
688 pTo->iCursor = 0;
689 pTo->xRealloc = blobReallocStatic;
690 pFrom->iCursor += N;
691 return N;
692 }
693
694 /*
695 ** Extract N **lines** of text from blob pFrom beginning at the current
696 ** cursor position and use that text to initialize blob pTo. Unlike the
697 ** blob_extract() routine, the cursor position is unchanged.
698 **
699 ** pTo is assumed to be uninitialized.
700 **
701 ** After this call completes, pTo will be an ephemeral blob.
702 */
703 int blob_extract_lines(Blob *pFrom, int N, Blob *pTo){
704 int i;
705 int mx;
706 int iStart;
707 int n;
708 const char *z;
709
710 blob_zero(pTo);
711 z = pFrom->aData;
712 i = pFrom->iCursor;
713 mx = pFrom->nUsed;
714 while( N>0 ){
715 while( i<mx && z[i]!='\n' ){ i++; }
716 if( i>=mx ) break;
717 i++;
718 N--;
719 }
720 iStart = pFrom->iCursor;
721 n = blob_extract(pFrom, i-pFrom->iCursor, pTo);
722 pFrom->iCursor = iStart;
723 return n;
724 }
725
726 /*
727 ** Return the number of lines of text in the blob. If the last
728 ** line is incomplete (if it does not have a \n at the end) then
729 ** it still counts.
730 */
731 int blob_linecount(Blob *p){
732 int n = 0;
733 int i;
734 for(i=0; i<p->nUsed; i++){
735 if( p->aData[i]=='\n' ) n++;
736 }
737 if( p->nUsed>0 && p->aData[p->nUsed-1]!='\n' ) n++;
738 return n;
739 }
740
741 /*
742 ** Rewind the cursor on a blob back to the beginning.
743 */
744 void blob_rewind(Blob *p){
745
+4 -3
--- src/branch.c
+++ src/branch.c
@@ -640,12 +640,12 @@
640640
** -M|--unmerged List branches not merged into the current branch
641641
** -p List only private branches
642642
** -r Reverse the sort order
643643
** -t Show recently changed branches first
644644
** --self List only branches where you participate
645
-** --username USER List only branches where USER participate
646
-** --users N List up to N users partipiating
645
+** --username USER List only branches where USER participates
646
+** --users N List up to N users participating
647647
**
648648
** The current branch is marked with an asterisk. Private branches are
649649
** marked with a hash sign.
650650
**
651651
** If GLOB is given, show only branches matching the pattern.
@@ -660,11 +660,12 @@
660660
** Create a new branch BRANCH-NAME off of check-in BASIS.
661661
**
662662
** Options:
663663
** --private Branch is private (i.e., remains local)
664664
** --bgcolor COLOR Use COLOR instead of automatic background
665
-** --nosign Do not sign contents on this branch
665
+** --nosign Do not sign the manifest for the check-in
666
+** that creates this branch
666667
** --nosync Do not auto-sync prior to creating the branch
667668
** --date-override DATE DATE to use instead of 'now'
668669
** --user-override USER USER to use instead of the current default
669670
**
670671
** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
671672
--- src/branch.c
+++ src/branch.c
@@ -640,12 +640,12 @@
640 ** -M|--unmerged List branches not merged into the current branch
641 ** -p List only private branches
642 ** -r Reverse the sort order
643 ** -t Show recently changed branches first
644 ** --self List only branches where you participate
645 ** --username USER List only branches where USER participate
646 ** --users N List up to N users partipiating
647 **
648 ** The current branch is marked with an asterisk. Private branches are
649 ** marked with a hash sign.
650 **
651 ** If GLOB is given, show only branches matching the pattern.
@@ -660,11 +660,12 @@
660 ** Create a new branch BRANCH-NAME off of check-in BASIS.
661 **
662 ** Options:
663 ** --private Branch is private (i.e., remains local)
664 ** --bgcolor COLOR Use COLOR instead of automatic background
665 ** --nosign Do not sign contents on this branch
 
666 ** --nosync Do not auto-sync prior to creating the branch
667 ** --date-override DATE DATE to use instead of 'now'
668 ** --user-override USER USER to use instead of the current default
669 **
670 ** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
671
--- src/branch.c
+++ src/branch.c
@@ -640,12 +640,12 @@
640 ** -M|--unmerged List branches not merged into the current branch
641 ** -p List only private branches
642 ** -r Reverse the sort order
643 ** -t Show recently changed branches first
644 ** --self List only branches where you participate
645 ** --username USER List only branches where USER participates
646 ** --users N List up to N users participating
647 **
648 ** The current branch is marked with an asterisk. Private branches are
649 ** marked with a hash sign.
650 **
651 ** If GLOB is given, show only branches matching the pattern.
@@ -660,11 +660,12 @@
660 ** Create a new branch BRANCH-NAME off of check-in BASIS.
661 **
662 ** Options:
663 ** --private Branch is private (i.e., remains local)
664 ** --bgcolor COLOR Use COLOR instead of automatic background
665 ** --nosign Do not sign the manifest for the check-in
666 ** that creates this branch
667 ** --nosync Do not auto-sync prior to creating the branch
668 ** --date-override DATE DATE to use instead of 'now'
669 ** --user-override USER USER to use instead of the current default
670 **
671 ** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
672
-17
--- src/browse.c
+++ src/browse.c
@@ -1258,22 +1258,5 @@
12581258
@ </table></div>
12591259
db_finalize(&q1);
12601260
db_finalize(&q2);
12611261
style_finish_page();
12621262
}
1263
-
1264
-/*
1265
-** WEBPAGE: files
1266
-**
1267
-** Show files as a flat table. If the ci=LABEL query parameter is provided,
1268
-** then show all the files in the specified check-in. Without the ci= query
1269
-** parameter show all files across all check-ins.
1270
-**
1271
-** Query parameters:
1272
-**
1273
-** name=PATH Directory to display. Optional
1274
-** ci=LABEL Show only files in this check-in. Optional.
1275
-** re=REGEXP Show only files matching REGEXP. Optional.
1276
-*/
1277
-void files_page(void){
1278
- return;
1279
-}
12801263
--- src/browse.c
+++ src/browse.c
@@ -1258,22 +1258,5 @@
1258 @ </table></div>
1259 db_finalize(&q1);
1260 db_finalize(&q2);
1261 style_finish_page();
1262 }
1263
1264 /*
1265 ** WEBPAGE: files
1266 **
1267 ** Show files as a flat table. If the ci=LABEL query parameter is provided,
1268 ** then show all the files in the specified check-in. Without the ci= query
1269 ** parameter show all files across all check-ins.
1270 **
1271 ** Query parameters:
1272 **
1273 ** name=PATH Directory to display. Optional
1274 ** ci=LABEL Show only files in this check-in. Optional.
1275 ** re=REGEXP Show only files matching REGEXP. Optional.
1276 */
1277 void files_page(void){
1278 return;
1279 }
1280
--- src/browse.c
+++ src/browse.c
@@ -1258,22 +1258,5 @@
1258 @ </table></div>
1259 db_finalize(&q1);
1260 db_finalize(&q2);
1261 style_finish_page();
1262 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1263
+3 -1
--- src/builtin.c
+++ src/builtin.c
@@ -718,11 +718,13 @@
718718
** the final one! */
719719
} fjs[] = {
720720
/* This list ordering isn't strictly important. */
721721
{"confirmer", 0, 0},
722722
{"copybutton", 0, "dom\0"},
723
- {"diff", 0, "dom\0fetch\0"},
723
+ {"diff", 0, "dom\0fetch\0storage\0"
724
+ /* maintenance note: "diff" needs "storage" for storing the the
725
+ ** sbs-sync-scroll toggle. */},
724726
{"dom", 0, 0},
725727
{"fetch", 0, 0},
726728
{"numbered-lines", 0, "popupwidget\0copybutton\0"},
727729
{"pikchr", 0, "dom\0"},
728730
{"popupwidget", 0, "dom\0"},
729731
--- src/builtin.c
+++ src/builtin.c
@@ -718,11 +718,13 @@
718 ** the final one! */
719 } fjs[] = {
720 /* This list ordering isn't strictly important. */
721 {"confirmer", 0, 0},
722 {"copybutton", 0, "dom\0"},
723 {"diff", 0, "dom\0fetch\0"},
 
 
724 {"dom", 0, 0},
725 {"fetch", 0, 0},
726 {"numbered-lines", 0, "popupwidget\0copybutton\0"},
727 {"pikchr", 0, "dom\0"},
728 {"popupwidget", 0, "dom\0"},
729
--- src/builtin.c
+++ src/builtin.c
@@ -718,11 +718,13 @@
718 ** the final one! */
719 } fjs[] = {
720 /* This list ordering isn't strictly important. */
721 {"confirmer", 0, 0},
722 {"copybutton", 0, "dom\0"},
723 {"diff", 0, "dom\0fetch\0storage\0"
724 /* maintenance note: "diff" needs "storage" for storing the the
725 ** sbs-sync-scroll toggle. */},
726 {"dom", 0, 0},
727 {"fetch", 0, 0},
728 {"numbered-lines", 0, "popupwidget\0copybutton\0"},
729 {"pikchr", 0, "dom\0"},
730 {"popupwidget", 0, "dom\0"},
731
+9 -3
--- src/chat.c
+++ src/chat.c
@@ -1137,12 +1137,11 @@
11371137
);
11381138
fossil_free(zBranch);
11391139
fossil_free(zUuid);
11401140
}else if( zType[0]=='w' ){
11411141
/* Wiki page changes */
1142
- char *zUuid;
1143
- zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
1142
+ char *zUuid = rid_to_uuid(rid);
11441143
wiki_hyperlink_override(zUuid);
11451144
if( zMsg[0]=='-' ){
11461145
zRes = mprintf("Delete wiki page <a href='%R/whistory?name=%t'>%h</a>",
11471146
zMsg+1, zMsg+1);
11481147
}else if( zMsg[0]=='+' ){
@@ -1155,10 +1154,17 @@
11551154
}else{
11561155
zRes = mprintf("%W", zMsg);
11571156
}
11581157
wiki_hyperlink_override(0);
11591158
fossil_free(zUuid);
1159
+ }else if( zType[0]=='f' ){
1160
+ /* Forum changes */
1161
+ char *zUuid = rid_to_uuid(rid);
1162
+ zRes = mprintf( "%W (artifact: <a href='%R/info/%S'>%S</a>, "
1163
+ "user: <a href='%R/timeline?u=%t&c=%S'>%h</a>)",
1164
+ zMsg, zUuid, zUuid, zUser, zUuid, zUser);
1165
+ fossil_free(zUuid);
11601166
}else{
11611167
/* Anything else */
11621168
zRes = mprintf("%W", zMsg);
11631169
}
11641170
if( zRes ){
@@ -1196,11 +1202,11 @@
11961202
**
11971203
** --all Download all chat content. Normally only
11981204
** previously undownloaded content is retrieved.
11991205
** --debug Additional debugging output
12001206
** --out DATABASE Store CHAT table in separate database file
1201
-** DATABASE rather that adding to local clone
1207
+** DATABASE rather than adding to local clone
12021208
** --unsafe Allow the use of unencrypted http://
12031209
**
12041210
** > fossil chat send [ARGUMENTS]
12051211
**
12061212
** This command sends a new message to the chatroom. The message
12071213
--- src/chat.c
+++ src/chat.c
@@ -1137,12 +1137,11 @@
1137 );
1138 fossil_free(zBranch);
1139 fossil_free(zUuid);
1140 }else if( zType[0]=='w' ){
1141 /* Wiki page changes */
1142 char *zUuid;
1143 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
1144 wiki_hyperlink_override(zUuid);
1145 if( zMsg[0]=='-' ){
1146 zRes = mprintf("Delete wiki page <a href='%R/whistory?name=%t'>%h</a>",
1147 zMsg+1, zMsg+1);
1148 }else if( zMsg[0]=='+' ){
@@ -1155,10 +1154,17 @@
1155 }else{
1156 zRes = mprintf("%W", zMsg);
1157 }
1158 wiki_hyperlink_override(0);
1159 fossil_free(zUuid);
 
 
 
 
 
 
 
1160 }else{
1161 /* Anything else */
1162 zRes = mprintf("%W", zMsg);
1163 }
1164 if( zRes ){
@@ -1196,11 +1202,11 @@
1196 **
1197 ** --all Download all chat content. Normally only
1198 ** previously undownloaded content is retrieved.
1199 ** --debug Additional debugging output
1200 ** --out DATABASE Store CHAT table in separate database file
1201 ** DATABASE rather that adding to local clone
1202 ** --unsafe Allow the use of unencrypted http://
1203 **
1204 ** > fossil chat send [ARGUMENTS]
1205 **
1206 ** This command sends a new message to the chatroom. The message
1207
--- src/chat.c
+++ src/chat.c
@@ -1137,12 +1137,11 @@
1137 );
1138 fossil_free(zBranch);
1139 fossil_free(zUuid);
1140 }else if( zType[0]=='w' ){
1141 /* Wiki page changes */
1142 char *zUuid = rid_to_uuid(rid);
 
1143 wiki_hyperlink_override(zUuid);
1144 if( zMsg[0]=='-' ){
1145 zRes = mprintf("Delete wiki page <a href='%R/whistory?name=%t'>%h</a>",
1146 zMsg+1, zMsg+1);
1147 }else if( zMsg[0]=='+' ){
@@ -1155,10 +1154,17 @@
1154 }else{
1155 zRes = mprintf("%W", zMsg);
1156 }
1157 wiki_hyperlink_override(0);
1158 fossil_free(zUuid);
1159 }else if( zType[0]=='f' ){
1160 /* Forum changes */
1161 char *zUuid = rid_to_uuid(rid);
1162 zRes = mprintf( "%W (artifact: <a href='%R/info/%S'>%S</a>, "
1163 "user: <a href='%R/timeline?u=%t&c=%S'>%h</a>)",
1164 zMsg, zUuid, zUuid, zUser, zUuid, zUser);
1165 fossil_free(zUuid);
1166 }else{
1167 /* Anything else */
1168 zRes = mprintf("%W", zMsg);
1169 }
1170 if( zRes ){
@@ -1196,11 +1202,11 @@
1202 **
1203 ** --all Download all chat content. Normally only
1204 ** previously undownloaded content is retrieved.
1205 ** --debug Additional debugging output
1206 ** --out DATABASE Store CHAT table in separate database file
1207 ** DATABASE rather than adding to local clone
1208 ** --unsafe Allow the use of unencrypted http://
1209 **
1210 ** > fossil chat send [ARGUMENTS]
1211 **
1212 ** This command sends a new message to the chatroom. The message
1213
+114 -14
--- src/checkin.c
+++ src/checkin.c
@@ -430,10 +430,11 @@
430430
**
431431
** The "fossil changes --extra" command is equivalent to "fossil extras".
432432
**
433433
** General options:
434434
** --abs-paths Display absolute pathnames
435
+** -b|--brief Show a single keyword for the status
435436
** --rel-paths Display pathnames relative to the current working
436437
** directory
437438
** --hash Verify file status using hashing rather than
438439
** relying on file mtimes
439440
** --case-sensitive BOOL Override case-sensitive setting
@@ -493,10 +494,48 @@
493494
unsigned scanFlags = 0;
494495
unsigned flags = 0;
495496
int vid, i;
496497
497498
fossil_pledge("stdio rpath wpath cpath fattr id flock tty chown");
499
+
500
+ if( find_option("brief","b",0) ){
501
+ /* The --brief or -b option is special. It cannot be used with any
502
+ ** other options. It outputs a single keyword which indicates the
503
+ ** fossil status, for use by shell scripts. The output might be
504
+ ** one of:
505
+ **
506
+ ** clean The current working directory is within an
507
+ ** unmodified fossil check-out.
508
+ **
509
+ ** dirty The pwd is within a fossil check-out that has
510
+ ** uncommitted changes
511
+ **
512
+ ** none The pwd is not within a fossil check-out.
513
+ */
514
+ int chnged;
515
+ if( g.argc>2 ){
516
+ fossil_fatal("No other arguments or options may occur with --brief");
517
+ }
518
+ if( db_open_local(0)==0 ){
519
+ fossil_print("none\n");
520
+ return;
521
+ }
522
+ vid = db_lget_int("checkout", 0);
523
+ vfile_check_signature(vid, 0);
524
+ chnged = db_int(0,
525
+ "SELECT 1 FROM vfile"
526
+ " WHERE vid=%d"
527
+ " AND (chnged>0 OR deleted OR rid==0)",
528
+ vid
529
+ );
530
+ if( chnged ){
531
+ fossil_print("dirty\n");
532
+ }else{
533
+ fossil_print("clean\n");
534
+ }
535
+ return;
536
+ }
498537
499538
/* Load affirmative flag options. */
500539
for( i=0; i<count(flagDefs); ++i ){
501540
if( (command==CHANGES || !(flagDefs[i].mask & C_CLASSIFY))
502541
&& find_option(flagDefs[i].option, 0, 0) ){
@@ -528,11 +567,11 @@
528567
}
529568
530569
/* Confirm current working directory is within check-out. */
531570
db_must_be_within_tree();
532571
533
- /* Get check-out version. l*/
572
+ /* Get check-out version. */
534573
vid = db_lget_int("checkout", 0);
535574
536575
/* Relative path flag determination is done by a shared function. */
537576
if( determine_cwd_relative_option() ){
538577
flags |= C_RELPATH;
@@ -928,12 +967,12 @@
928967
/*
929968
** COMMAND: tree
930969
**
931970
** Usage: %fossil tree ?OPTIONS? ?PATHS ...?
932971
**
933
-** List all files in the current check-out in after the fashion of the
934
-** "tree" command. If PATHS is included, only the named files
972
+** List all files in the current check-out much like the "tree"
973
+** command does. If PATHS is included, only the named files
935974
** (or their children if directories) are shown.
936975
**
937976
** Options:
938977
** -r VERSION The specific check-in to list
939978
** -R|--repository REPO Extract info from repository REPO
@@ -2279,11 +2318,11 @@
22792318
**
22802319
** A check-in is not permitted to fork unless the --allow-fork option
22812320
** appears. An empty check-in (i.e. with nothing changed) is not
22822321
** allowed unless the --allow-empty option appears. A check-in may not
22832322
** be older than its ancestor unless the --allow-older option appears.
2284
-** If any of files in the check-in appear to contain unresolved merge
2323
+** If any files in the check-in appear to contain unresolved merge
22852324
** conflicts, the check-in will not be allowed unless the
22862325
** --allow-conflict option is present. In addition, the entire
22872326
** check-in process may be aborted if a file contains content that
22882327
** appears to be binary, Unicode text, or text with CR/LF line endings
22892328
** unless the interactive user chooses to proceed. If there is no
@@ -2319,11 +2358,11 @@
23192358
** than relying on file mtimes
23202359
** --ignore-clock-skew If a clock skew is detected, ignore it and
23212360
** behave as if the user had entered 'yes' to
23222361
** the question of whether to proceed despite
23232362
** the skew.
2324
-** --ignore-oversize Do not warning the user about oversized files
2363
+** --ignore-oversize Do not warn the user about oversized files
23252364
** --integrate Close all merged-in branches
23262365
** -m|--comment COMMENT-TEXT Use COMMENT-TEXT as commit comment
23272366
** -M|--message-file FILE Read the commit comment from given file
23282367
** --mimetype MIMETYPE Mimetype of check-in comment
23292368
** -n|--dry-run If given, display instead of run actions
@@ -2395,10 +2434,12 @@
23952434
Blob ans; /* Answer to continuation prompts */
23962435
char cReply; /* First character of ans */
23972436
int bRecheck = 0; /* Repeat fork and closed-branch checks*/
23982437
int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
23992438
int mxSize;
2439
+ char *zCurBranch = 0; /* The current branch name of checkout */
2440
+ char *zNewBranch = 0; /* The branch name after update */
24002441
24012442
memset(&sCiInfo, 0, sizeof(sCiInfo));
24022443
url_proxy_options();
24032444
/* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
24042445
useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2469,10 +2510,55 @@
24692510
}
24702511
}else{
24712512
privateParent = content_is_private(vid);
24722513
}
24732514
2515
+ user_select();
2516
+ /*
2517
+ ** Check that the user exists.
2518
+ */
2519
+ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2520
+ fossil_fatal("no such user: %s", g.zLogin);
2521
+ }
2522
+
2523
+ /*
2524
+ ** Detect if the branch name has changed from the parent check-in
2525
+ ** and prompt if necessary
2526
+ **/
2527
+ zCurBranch = db_text(0,
2528
+ " SELECT value FROM tagxref AS tx"
2529
+ " WHERE rid=(SELECT pid"
2530
+ " FROM tagxref LEFT JOIN event ON srcid=objid"
2531
+ " LEFT JOIN plink ON rid=cid"
2532
+ " WHERE rid=%d AND tagxref.tagid=%d"
2533
+ " AND srcid!=origid"
2534
+ " AND tagtype=2 AND coalesce(euser,user)!=%Q)"
2535
+ " AND tx.tagid=%d",
2536
+ vid, TAG_BRANCH, g.zLogin, TAG_BRANCH
2537
+ );
2538
+ if( zCurBranch!=0 && zCurBranch[0]!=0
2539
+ && forceFlag==0
2540
+ && noPrompt==0
2541
+ ){
2542
+ zNewBranch = branch_of_rid(vid);
2543
+ fossil_warning(
2544
+ "WARNING: The parent check-in [%.10s] has been moved from branch\n"
2545
+ " '%s' over to branch '%s'.",
2546
+ rid_to_uuid(vid), zCurBranch, zNewBranch
2547
+ );
2548
+ prompt_user("Commit anyway? (y/N) ", &ans);
2549
+ cReply = blob_str(&ans)[0];
2550
+ blob_reset(&ans);
2551
+ if( cReply!='y' && cReply!='Y' ){
2552
+ fossil_fatal("Abandoning commit because branch has changed");
2553
+ }
2554
+ fossil_free(zNewBranch);
2555
+ fossil_free(zCurBranch);
2556
+ zCurBranch = branch_of_rid(vid);
2557
+ }
2558
+ if( zCurBranch==0 ) zCurBranch = branch_of_rid(vid);
2559
+
24742560
/* Track the "private" status */
24752561
g.markPrivate = privateFlag || privateParent;
24762562
if( privateFlag && !privateParent ){
24772563
/* Apply default branch name ("private") and color ("orange") if not
24782564
** specified otherwise on the command-line, and if the parent is not
@@ -2521,11 +2607,11 @@
25212607
**
25222608
** If the remote repository sent an avoid-delta-manifests pragma on
25232609
** the autosync above, then also try to avoid deltas, unless the
25242610
** --delta option is specified. The remote repo will send the
25252611
** avoid-delta-manifests pragma if it has its "forbid-delta-manifests"
2526
- ** setting is enabled.
2612
+ ** setting enabled.
25272613
*/
25282614
if( !db_get_boolean("seen-delta-manifest",0)
25292615
|| db_get_boolean("forbid-delta-manifests",0)
25302616
|| g.bAvoidDeltaManifests
25312617
){
@@ -2600,18 +2686,10 @@
26002686
"'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
26012687
}
26022688
db_finalize(&q);
26032689
}
26042690
2605
- user_select();
2606
- /*
2607
- ** Check that the user exists.
2608
- */
2609
- if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2610
- fossil_fatal("no such user: %s", g.zLogin);
2611
- }
2612
-
26132691
hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
26142692
db_begin_transaction();
26152693
db_record_repository_filename(0);
26162694
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
26172695
fossil_fatal("nothing has changed; use --allow-empty to override");
@@ -2674,10 +2752,32 @@
26742752
" WHERE tagid=%d AND rid=%d AND tagtype>0"
26752753
" AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch))
26762754
){
26772755
fossil_fatal("cannot commit against a closed leaf");
26782756
}
2757
+
2758
+ /* Require confirmation to continue with the check-in if the branch
2759
+ ** has changed and the committer did not provide the same branch
2760
+ */
2761
+ zNewBranch = branch_of_rid(vid);
2762
+ if( fossil_strcmp(zCurBranch, zNewBranch)!=0
2763
+ && fossil_strcmp(sCiInfo.zBranch, zNewBranch)!=0
2764
+ && forceFlag==0
2765
+ && noPrompt==0
2766
+ ){
2767
+ fossil_warning("parent check-in [%.10s] branch changed from '%s' to '%s'",
2768
+ rid_to_uuid(vid), zCurBranch, zNewBranch);
2769
+ prompt_user("continue (y/N)? ", &ans);
2770
+ cReply = blob_str(&ans)[0];
2771
+ blob_reset(&ans);
2772
+ if( cReply!='y' && cReply!='Y' ){
2773
+ fossil_fatal("Abandoning commit because branch has changed");
2774
+ }
2775
+ fossil_free(zCurBranch);
2776
+ zCurBranch = branch_of_rid(vid);
2777
+ }
2778
+ fossil_free(zNewBranch);
26792779
26802780
/* Always exit the loop on the second pass */
26812781
if( bRecheck ) break;
26822782
26832783
26842784
--- src/checkin.c
+++ src/checkin.c
@@ -430,10 +430,11 @@
430 **
431 ** The "fossil changes --extra" command is equivalent to "fossil extras".
432 **
433 ** General options:
434 ** --abs-paths Display absolute pathnames
 
435 ** --rel-paths Display pathnames relative to the current working
436 ** directory
437 ** --hash Verify file status using hashing rather than
438 ** relying on file mtimes
439 ** --case-sensitive BOOL Override case-sensitive setting
@@ -493,10 +494,48 @@
493 unsigned scanFlags = 0;
494 unsigned flags = 0;
495 int vid, i;
496
497 fossil_pledge("stdio rpath wpath cpath fattr id flock tty chown");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
499 /* Load affirmative flag options. */
500 for( i=0; i<count(flagDefs); ++i ){
501 if( (command==CHANGES || !(flagDefs[i].mask & C_CLASSIFY))
502 && find_option(flagDefs[i].option, 0, 0) ){
@@ -528,11 +567,11 @@
528 }
529
530 /* Confirm current working directory is within check-out. */
531 db_must_be_within_tree();
532
533 /* Get check-out version. l*/
534 vid = db_lget_int("checkout", 0);
535
536 /* Relative path flag determination is done by a shared function. */
537 if( determine_cwd_relative_option() ){
538 flags |= C_RELPATH;
@@ -928,12 +967,12 @@
928 /*
929 ** COMMAND: tree
930 **
931 ** Usage: %fossil tree ?OPTIONS? ?PATHS ...?
932 **
933 ** List all files in the current check-out in after the fashion of the
934 ** "tree" command. If PATHS is included, only the named files
935 ** (or their children if directories) are shown.
936 **
937 ** Options:
938 ** -r VERSION The specific check-in to list
939 ** -R|--repository REPO Extract info from repository REPO
@@ -2279,11 +2318,11 @@
2279 **
2280 ** A check-in is not permitted to fork unless the --allow-fork option
2281 ** appears. An empty check-in (i.e. with nothing changed) is not
2282 ** allowed unless the --allow-empty option appears. A check-in may not
2283 ** be older than its ancestor unless the --allow-older option appears.
2284 ** If any of files in the check-in appear to contain unresolved merge
2285 ** conflicts, the check-in will not be allowed unless the
2286 ** --allow-conflict option is present. In addition, the entire
2287 ** check-in process may be aborted if a file contains content that
2288 ** appears to be binary, Unicode text, or text with CR/LF line endings
2289 ** unless the interactive user chooses to proceed. If there is no
@@ -2319,11 +2358,11 @@
2319 ** than relying on file mtimes
2320 ** --ignore-clock-skew If a clock skew is detected, ignore it and
2321 ** behave as if the user had entered 'yes' to
2322 ** the question of whether to proceed despite
2323 ** the skew.
2324 ** --ignore-oversize Do not warning the user about oversized files
2325 ** --integrate Close all merged-in branches
2326 ** -m|--comment COMMENT-TEXT Use COMMENT-TEXT as commit comment
2327 ** -M|--message-file FILE Read the commit comment from given file
2328 ** --mimetype MIMETYPE Mimetype of check-in comment
2329 ** -n|--dry-run If given, display instead of run actions
@@ -2395,10 +2434,12 @@
2395 Blob ans; /* Answer to continuation prompts */
2396 char cReply; /* First character of ans */
2397 int bRecheck = 0; /* Repeat fork and closed-branch checks*/
2398 int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
2399 int mxSize;
 
 
2400
2401 memset(&sCiInfo, 0, sizeof(sCiInfo));
2402 url_proxy_options();
2403 /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
2404 useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2469,10 +2510,55 @@
2469 }
2470 }else{
2471 privateParent = content_is_private(vid);
2472 }
2473
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2474 /* Track the "private" status */
2475 g.markPrivate = privateFlag || privateParent;
2476 if( privateFlag && !privateParent ){
2477 /* Apply default branch name ("private") and color ("orange") if not
2478 ** specified otherwise on the command-line, and if the parent is not
@@ -2521,11 +2607,11 @@
2521 **
2522 ** If the remote repository sent an avoid-delta-manifests pragma on
2523 ** the autosync above, then also try to avoid deltas, unless the
2524 ** --delta option is specified. The remote repo will send the
2525 ** avoid-delta-manifests pragma if it has its "forbid-delta-manifests"
2526 ** setting is enabled.
2527 */
2528 if( !db_get_boolean("seen-delta-manifest",0)
2529 || db_get_boolean("forbid-delta-manifests",0)
2530 || g.bAvoidDeltaManifests
2531 ){
@@ -2600,18 +2686,10 @@
2600 "'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
2601 }
2602 db_finalize(&q);
2603 }
2604
2605 user_select();
2606 /*
2607 ** Check that the user exists.
2608 */
2609 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2610 fossil_fatal("no such user: %s", g.zLogin);
2611 }
2612
2613 hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
2614 db_begin_transaction();
2615 db_record_repository_filename(0);
2616 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
2617 fossil_fatal("nothing has changed; use --allow-empty to override");
@@ -2674,10 +2752,32 @@
2674 " WHERE tagid=%d AND rid=%d AND tagtype>0"
2675 " AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch))
2676 ){
2677 fossil_fatal("cannot commit against a closed leaf");
2678 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2679
2680 /* Always exit the loop on the second pass */
2681 if( bRecheck ) break;
2682
2683
2684
--- src/checkin.c
+++ src/checkin.c
@@ -430,10 +430,11 @@
430 **
431 ** The "fossil changes --extra" command is equivalent to "fossil extras".
432 **
433 ** General options:
434 ** --abs-paths Display absolute pathnames
435 ** -b|--brief Show a single keyword for the status
436 ** --rel-paths Display pathnames relative to the current working
437 ** directory
438 ** --hash Verify file status using hashing rather than
439 ** relying on file mtimes
440 ** --case-sensitive BOOL Override case-sensitive setting
@@ -493,10 +494,48 @@
494 unsigned scanFlags = 0;
495 unsigned flags = 0;
496 int vid, i;
497
498 fossil_pledge("stdio rpath wpath cpath fattr id flock tty chown");
499
500 if( find_option("brief","b",0) ){
501 /* The --brief or -b option is special. It cannot be used with any
502 ** other options. It outputs a single keyword which indicates the
503 ** fossil status, for use by shell scripts. The output might be
504 ** one of:
505 **
506 ** clean The current working directory is within an
507 ** unmodified fossil check-out.
508 **
509 ** dirty The pwd is within a fossil check-out that has
510 ** uncommitted changes
511 **
512 ** none The pwd is not within a fossil check-out.
513 */
514 int chnged;
515 if( g.argc>2 ){
516 fossil_fatal("No other arguments or options may occur with --brief");
517 }
518 if( db_open_local(0)==0 ){
519 fossil_print("none\n");
520 return;
521 }
522 vid = db_lget_int("checkout", 0);
523 vfile_check_signature(vid, 0);
524 chnged = db_int(0,
525 "SELECT 1 FROM vfile"
526 " WHERE vid=%d"
527 " AND (chnged>0 OR deleted OR rid==0)",
528 vid
529 );
530 if( chnged ){
531 fossil_print("dirty\n");
532 }else{
533 fossil_print("clean\n");
534 }
535 return;
536 }
537
538 /* Load affirmative flag options. */
539 for( i=0; i<count(flagDefs); ++i ){
540 if( (command==CHANGES || !(flagDefs[i].mask & C_CLASSIFY))
541 && find_option(flagDefs[i].option, 0, 0) ){
@@ -528,11 +567,11 @@
567 }
568
569 /* Confirm current working directory is within check-out. */
570 db_must_be_within_tree();
571
572 /* Get check-out version. */
573 vid = db_lget_int("checkout", 0);
574
575 /* Relative path flag determination is done by a shared function. */
576 if( determine_cwd_relative_option() ){
577 flags |= C_RELPATH;
@@ -928,12 +967,12 @@
967 /*
968 ** COMMAND: tree
969 **
970 ** Usage: %fossil tree ?OPTIONS? ?PATHS ...?
971 **
972 ** List all files in the current check-out much like the "tree"
973 ** command does. If PATHS is included, only the named files
974 ** (or their children if directories) are shown.
975 **
976 ** Options:
977 ** -r VERSION The specific check-in to list
978 ** -R|--repository REPO Extract info from repository REPO
@@ -2279,11 +2318,11 @@
2318 **
2319 ** A check-in is not permitted to fork unless the --allow-fork option
2320 ** appears. An empty check-in (i.e. with nothing changed) is not
2321 ** allowed unless the --allow-empty option appears. A check-in may not
2322 ** be older than its ancestor unless the --allow-older option appears.
2323 ** If any files in the check-in appear to contain unresolved merge
2324 ** conflicts, the check-in will not be allowed unless the
2325 ** --allow-conflict option is present. In addition, the entire
2326 ** check-in process may be aborted if a file contains content that
2327 ** appears to be binary, Unicode text, or text with CR/LF line endings
2328 ** unless the interactive user chooses to proceed. If there is no
@@ -2319,11 +2358,11 @@
2358 ** than relying on file mtimes
2359 ** --ignore-clock-skew If a clock skew is detected, ignore it and
2360 ** behave as if the user had entered 'yes' to
2361 ** the question of whether to proceed despite
2362 ** the skew.
2363 ** --ignore-oversize Do not warn the user about oversized files
2364 ** --integrate Close all merged-in branches
2365 ** -m|--comment COMMENT-TEXT Use COMMENT-TEXT as commit comment
2366 ** -M|--message-file FILE Read the commit comment from given file
2367 ** --mimetype MIMETYPE Mimetype of check-in comment
2368 ** -n|--dry-run If given, display instead of run actions
@@ -2395,10 +2434,12 @@
2434 Blob ans; /* Answer to continuation prompts */
2435 char cReply; /* First character of ans */
2436 int bRecheck = 0; /* Repeat fork and closed-branch checks*/
2437 int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
2438 int mxSize;
2439 char *zCurBranch = 0; /* The current branch name of checkout */
2440 char *zNewBranch = 0; /* The branch name after update */
2441
2442 memset(&sCiInfo, 0, sizeof(sCiInfo));
2443 url_proxy_options();
2444 /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
2445 useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2469,10 +2510,55 @@
2510 }
2511 }else{
2512 privateParent = content_is_private(vid);
2513 }
2514
2515 user_select();
2516 /*
2517 ** Check that the user exists.
2518 */
2519 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2520 fossil_fatal("no such user: %s", g.zLogin);
2521 }
2522
2523 /*
2524 ** Detect if the branch name has changed from the parent check-in
2525 ** and prompt if necessary
2526 **/
2527 zCurBranch = db_text(0,
2528 " SELECT value FROM tagxref AS tx"
2529 " WHERE rid=(SELECT pid"
2530 " FROM tagxref LEFT JOIN event ON srcid=objid"
2531 " LEFT JOIN plink ON rid=cid"
2532 " WHERE rid=%d AND tagxref.tagid=%d"
2533 " AND srcid!=origid"
2534 " AND tagtype=2 AND coalesce(euser,user)!=%Q)"
2535 " AND tx.tagid=%d",
2536 vid, TAG_BRANCH, g.zLogin, TAG_BRANCH
2537 );
2538 if( zCurBranch!=0 && zCurBranch[0]!=0
2539 && forceFlag==0
2540 && noPrompt==0
2541 ){
2542 zNewBranch = branch_of_rid(vid);
2543 fossil_warning(
2544 "WARNING: The parent check-in [%.10s] has been moved from branch\n"
2545 " '%s' over to branch '%s'.",
2546 rid_to_uuid(vid), zCurBranch, zNewBranch
2547 );
2548 prompt_user("Commit anyway? (y/N) ", &ans);
2549 cReply = blob_str(&ans)[0];
2550 blob_reset(&ans);
2551 if( cReply!='y' && cReply!='Y' ){
2552 fossil_fatal("Abandoning commit because branch has changed");
2553 }
2554 fossil_free(zNewBranch);
2555 fossil_free(zCurBranch);
2556 zCurBranch = branch_of_rid(vid);
2557 }
2558 if( zCurBranch==0 ) zCurBranch = branch_of_rid(vid);
2559
2560 /* Track the "private" status */
2561 g.markPrivate = privateFlag || privateParent;
2562 if( privateFlag && !privateParent ){
2563 /* Apply default branch name ("private") and color ("orange") if not
2564 ** specified otherwise on the command-line, and if the parent is not
@@ -2521,11 +2607,11 @@
2607 **
2608 ** If the remote repository sent an avoid-delta-manifests pragma on
2609 ** the autosync above, then also try to avoid deltas, unless the
2610 ** --delta option is specified. The remote repo will send the
2611 ** avoid-delta-manifests pragma if it has its "forbid-delta-manifests"
2612 ** setting enabled.
2613 */
2614 if( !db_get_boolean("seen-delta-manifest",0)
2615 || db_get_boolean("forbid-delta-manifests",0)
2616 || g.bAvoidDeltaManifests
2617 ){
@@ -2600,18 +2686,10 @@
2686 "'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
2687 }
2688 db_finalize(&q);
2689 }
2690
 
 
 
 
 
 
 
 
2691 hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
2692 db_begin_transaction();
2693 db_record_repository_filename(0);
2694 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
2695 fossil_fatal("nothing has changed; use --allow-empty to override");
@@ -2674,10 +2752,32 @@
2752 " WHERE tagid=%d AND rid=%d AND tagtype>0"
2753 " AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch))
2754 ){
2755 fossil_fatal("cannot commit against a closed leaf");
2756 }
2757
2758 /* Require confirmation to continue with the check-in if the branch
2759 ** has changed and the committer did not provide the same branch
2760 */
2761 zNewBranch = branch_of_rid(vid);
2762 if( fossil_strcmp(zCurBranch, zNewBranch)!=0
2763 && fossil_strcmp(sCiInfo.zBranch, zNewBranch)!=0
2764 && forceFlag==0
2765 && noPrompt==0
2766 ){
2767 fossil_warning("parent check-in [%.10s] branch changed from '%s' to '%s'",
2768 rid_to_uuid(vid), zCurBranch, zNewBranch);
2769 prompt_user("continue (y/N)? ", &ans);
2770 cReply = blob_str(&ans)[0];
2771 blob_reset(&ans);
2772 if( cReply!='y' && cReply!='Y' ){
2773 fossil_fatal("Abandoning commit because branch has changed");
2774 }
2775 fossil_free(zCurBranch);
2776 zCurBranch = branch_of_rid(vid);
2777 }
2778 fossil_free(zNewBranch);
2779
2780 /* Always exit the loop on the second pass */
2781 if( bRecheck ) break;
2782
2783
2784
+221 -71
--- src/comformat.c
+++ src/comformat.c
@@ -31,10 +31,117 @@
3131
#define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
3232
#define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */
3333
#define COMMENT_PRINT_UNSET (-1) /* Not initialized. */
3434
#endif
3535
36
+/********* Code copied from SQLite src/shell.c.in on 2024-09-30 **********/
37
+/* Lookup table to estimate the number of columns consumed by a Unicode
38
+** character.
39
+*/
40
+static const struct {
41
+ unsigned char w; /* Width of the character in columns */
42
+ int iFirst; /* First character in a span having this width */
43
+} aUWidth[] = {
44
+ /* {1, 0x00000}, */
45
+ {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488},
46
+ {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0},
47
+ {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7},
48
+ {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616},
49
+ {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6},
50
+ {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee},
51
+ {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730},
52
+ {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4},
53
+ {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941},
54
+ {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955},
55
+ {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc},
56
+ {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce},
57
+ {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c},
58
+ {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49},
59
+ {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81},
60
+ {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6},
61
+ {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2},
62
+ {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d},
63
+ {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d},
64
+ {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83},
65
+ {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e},
66
+ {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e},
67
+ {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf},
68
+ {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce},
69
+ {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d},
70
+ {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5},
71
+ {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34},
72
+ {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2},
73
+ {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8},
74
+ {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36},
75
+ {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71},
76
+ {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
77
+ {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
78
+ {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
79
+ {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
80
+ {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
81
+ {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
82
+ {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
83
+ {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7},
84
+ {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b},
85
+ {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923},
86
+ {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939},
87
+ {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04},
88
+ {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c},
89
+ {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74},
90
+ {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b},
91
+ {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064},
92
+ {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329},
93
+ {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f},
94
+ {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806},
95
+ {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827},
96
+ {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e},
97
+ {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20},
98
+ {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00},
99
+ {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc},
100
+ {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c},
101
+ {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40},
102
+ {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185},
103
+ {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245},
104
+ {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001},
105
+ {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0}
106
+};
107
+
108
+/*
109
+** Return an estimate of the width, in columns, for the single Unicode
110
+** character c. For normal characters, the answer is always 1. But the
111
+** estimate might be 0 or 2 for zero-width and double-width characters.
112
+**
113
+** Different display devices display unicode using different widths. So
114
+** it is impossible to know that true display width with 100% accuracy.
115
+** Inaccuracies in the width estimates might cause columns to be misaligned.
116
+** Unfortunately, there is nothing we can do about that.
117
+*/
118
+static int cli_wcwidth(int c){
119
+ int iFirst, iLast;
120
+
121
+ /* Fast path for common characters */
122
+ if( c<=0x300 ) return 1;
123
+
124
+ /* The general case */
125
+ iFirst = 0;
126
+ iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1;
127
+ while( iFirst<iLast-1 ){
128
+ int iMid = (iFirst+iLast)/2;
129
+ int cMid = aUWidth[iMid].iFirst;
130
+ if( cMid < c ){
131
+ iFirst = iMid;
132
+ }else if( cMid > c ){
133
+ iLast = iMid - 1;
134
+ }else{
135
+ return aUWidth[iMid].w;
136
+ }
137
+ }
138
+ if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w;
139
+ return aUWidth[iLast].w;
140
+}
141
+/******* End of code copied from SQLite *************************************/
142
+
36143
/*
37144
** This is the previous value used by most external callers when they
38145
** needed to specify a default maximum line length to be used with the
39146
** comment_print() function.
40147
*/
@@ -108,62 +215,99 @@
108215
** algorithm, the NUL character is treated the same as a spacing character.
109216
*/
110217
static int comment_next_space(
111218
const char *zLine, /* [in] The comment line being printed. */
112219
int index, /* [in] The current character index being handled. */
113
- int *distUTF8 /* [out] Distance to next space in UTF-8 sequences. */
220
+ int maxChars, /* [in] Optimization hint to abort before space found. */
221
+ int *sumWidth /* [out] Summated width of all characters to next space. */
114222
){
115
- int nextIndex = index + 1;
116
- int fNonASCII=0;
223
+ int cchUTF8, utf32, wcwidth = 0;
224
+ int nextIndex = index;
117225
for(;;){
118
- char c = zLine[nextIndex];
119
- if( (c&0x80)==0x80 ) fNonASCII=1;
120
- if( c==0 || fossil_isspace(c) ){
121
- if( distUTF8 ){
122
- if( fNonASCII!=0 ){
123
- *distUTF8 = strlen_utf8(&zLine[index], nextIndex-index);
124
- }else{
125
- *distUTF8 = nextIndex-index;
126
- }
127
- }
226
+ char_info_utf8(&zLine[nextIndex],&cchUTF8,&utf32);
227
+ nextIndex += cchUTF8;
228
+ wcwidth += cli_wcwidth(utf32);
229
+ if( zLine[nextIndex]==0 || fossil_isspace(zLine[nextIndex]) ||
230
+ wcwidth>maxChars ){
231
+ *sumWidth = wcwidth;
128232
return nextIndex;
129233
}
130
- nextIndex++;
131234
}
132235
return 0; /* NOT REACHED */
133236
}
134237
135238
/*
136
-** Count the number of UTF-8 sequences in a string. Incomplete, ill-formed and
137
-** overlong sequences are counted as one sequence. The invalid lead bytes 0xC0
138
-** to 0xC1 and 0xF5 to 0xF7 are allowed to initiate (ill-formed) 2- and 4-byte
139
-** sequences, respectively, the other invalid lead bytes 0xF8 to 0xFF are
140
-** treated as invalid 1-byte sequences (as lone trail bytes).
141
-** Combining characters and East Asian Wide and Fullwidth characters are counted
142
-** as one, so this function does not calculate the effective "display width".
239
+** Return information about the next (single- or multi-byte) character in the
240
+** specified UTF-8 string: The number of UTF-8 code units (in this case: bytes)
241
+** and the decoded UTF-32 code point. Incomplete, ill-formed and overlong
242
+** sequences are consumed together as one invalid code point. The invalid lead
243
+** bytes 0xC0 to 0xC1 and 0xF5 to 0xF7 are allowed to initiate (ill-formed) 2-
244
+** and 4-byte sequences, respectively, the other invalid lead bytes 0xF8 to 0xFF
245
+** are treated as invalid 1-byte sequences (as lone trail bytes), all resulting
246
+** in one invalid code point. Invalid UTF-8 sequences encoding a non-scalar code
247
+** point (UTF-16 surrogates U+D800 to U+DFFF) are allowed.
143248
*/
144
-int strlen_utf8(const char *zString, int lengthBytes){
145
- int i; /* Counted bytes. */
146
- int lengthUTF8; /* Counted UTF-8 sequences. */
147
-#if 0
148
- assert( lengthBytes>=0 );
249
+void char_info_utf8(
250
+ const char *z,
251
+ int *pCchUTF8,
252
+ int *pUtf32
253
+){
254
+ int i = 0; /* Counted bytes. */
255
+ int cchUTF8 = 1; /* Code units consumed. */
256
+ int maxUTF8 = 1; /* Expected sequence length. */
257
+ char c = z[i++];
258
+ if( (c&0x80)==0x00 ){ /* 7-bit ASCII character. */
259
+ *pCchUTF8 = 1;
260
+ *pUtf32 = (int)z[0];
261
+ return;
262
+ }
263
+ else if( (c&0xe0)==0xc0 ) maxUTF8 = 2; /* UTF-8 lead byte 110vvvvv */
264
+ else if( (c&0xf0)==0xe0 ) maxUTF8 = 3; /* UTF-8 lead byte 1110vvvv */
265
+ else if( (c&0xf8)==0xf0 ) maxUTF8 = 4; /* UTF-8 lead byte 11110vvv */
266
+ while( cchUTF8<maxUTF8 &&
267
+ (z[i]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
268
+ cchUTF8++;
269
+ i++;
270
+ }
271
+ *pCchUTF8 = cchUTF8;
272
+ if( cchUTF8!=maxUTF8 || /* Incomplete UTF-8 sequence. */
273
+ ( cchUTF8==1 && (c&0x80)==0x80 )){ /* Lone UTF-8 trail byte. */
274
+ *pUtf32 = 0xfffd; /* U+FFFD Replacement Character */
275
+#ifdef FOSSIL_DEBUG
276
+ assert( *pUtf32!=0xfffd ); /* Invalid UTF-8 sequence. */
149277
#endif
150
- for(i=0, lengthUTF8=0; i<lengthBytes; i++, lengthUTF8++){
151
- char c = zString[i];
152
- int cchUTF8=1; /* Code units consumed. */
153
- int maxUTF8=1; /* Expected sequence length. */
154
- if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */
155
- else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */
156
- else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */
157
- while( cchUTF8<maxUTF8 &&
158
- i<lengthBytes-1 &&
159
- (zString[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
160
- cchUTF8++;
161
- i++;
162
- }
163
- }
164
- return lengthUTF8;
278
+ return;
279
+ }
280
+ switch( cchUTF8 ){
281
+ case 4:
282
+ *pUtf32 =
283
+ ( (z[0] & 0x0f)<<18 ) |
284
+ ( (z[1] & 0x3f)<<12 ) |
285
+ ( (z[2] & 0x3f)<< 6 ) |
286
+ ( (z[4] & 0x3f)<< 0 ) ;
287
+ break;
288
+ case 3:
289
+ *pUtf32 =
290
+ ( (z[0] & 0x0f)<<12 ) |
291
+ ( (z[1] & 0x3f)<< 6 ) |
292
+ ( (z[2] & 0x3f)<< 0 ) ;
293
+ break;
294
+ case 2:
295
+ *pUtf32 =
296
+ ( (z[0] & 0x1f)<< 6 ) |
297
+ ( (z[1] & 0x3f)<< 0 ) ;
298
+ break;
299
+ default:
300
+ *pUtf32 = 0xfffd; /* U+FFFD Replacement Character */
301
+ break;
302
+ }
303
+#ifdef FOSSIL_DEBUG
304
+ assert(
305
+ *pUtf32>=0 && *pUtf32<=0x10ffff && /* Valid range U+0000 to U+10FFFF. */
306
+ *pUtf32<0xd800 && *pUtf32>0xdfff /* Non-scalar (UTF-16 surrogates). */
307
+ );
308
+#endif
165309
}
166310
167311
/*
168312
** This function is called when printing a logical comment line to calculate
169313
** the necessary indenting. The caller needs to emit the indenting spaces.
@@ -206,11 +350,10 @@
206350
int *pLineCnt, /* [in/out] Pointer to the total line count. */
207351
const char **pzLine /* [out] Pointer to the end of the logical line. */
208352
){
209353
int index = 0, charCnt = 0, lineCnt = 0, maxChars, i;
210354
char zBuf[400]; int iBuf=0; /* Output buffer and counter. */
211
- int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */
212355
if( !zLine ) return;
213356
if( lineChars<=0 ) return;
214357
#if 0
215358
assert( indent<sizeof(zBuf)-5 ); /* See following comments to explain */
216359
assert( origIndent<sizeof(zBuf)-5 ); /* these limits. */
@@ -229,10 +372,11 @@
229372
/* Limit line indent to fit output buffer. */
230373
origIndent = sizeof(zBuf)-6;
231374
}
232375
maxChars = lineChars;
233376
for(;;){
377
+ int cchUTF8, utf32;
234378
int useChars = 1;
235379
char c = zLine[index];
236380
/* Flush the output buffer if there's no space left for at least one more
237381
** (potentially 4-byte) UTF-8 sequence, one level of indentation spaces,
238382
** a new line, and a terminating NULL. */
@@ -260,43 +404,47 @@
260404
if( c=='\n' ){
261405
lineCnt++;
262406
charCnt = 0;
263407
useChars = 0;
264408
}else if( c=='\t' ){
265
- int distUTF8;
266
- int nextIndex = comment_next_space(zLine, index, &distUTF8);
267
- if( nextIndex<=0 || distUTF8>maxChars ){
409
+ int sumWidth;
410
+ int nextIndex = comment_next_space(zLine, index, maxChars, &sumWidth);
411
+ if( nextIndex<=0 || sumWidth>maxChars ){
268412
break;
269413
}
270414
charCnt++;
271415
useChars = COMMENT_TAB_WIDTH;
272416
if( maxChars<useChars ){
273417
zBuf[iBuf++] = ' ';
274418
break;
275419
}
276420
}else if( wordBreak && fossil_isspace(c) ){
277
- int distUTF8;
278
- int nextIndex = comment_next_space(zLine, index, &distUTF8);
279
- if( nextIndex<=0 || distUTF8>=maxChars ){
421
+ int sumWidth;
422
+ int nextIndex = comment_next_space(zLine, index, maxChars, &sumWidth);
423
+ if( nextIndex<=0 || sumWidth>=maxChars ){
280424
break;
281425
}
282426
charCnt++;
283427
}else{
284428
charCnt++;
285429
}
286430
assert( c!='\n' || charCnt==0 );
287431
zBuf[iBuf++] = c;
288
- /* Skip over UTF-8 sequences, see comment on strlen_utf8() for details. */
289
- cchUTF8=1; /* Code units consumed. */
290
- maxUTF8=1; /* Expected sequence length. */
291
- if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */
292
- else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */
293
- else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */
294
- while( cchUTF8<maxUTF8 &&
295
- (zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
296
- cchUTF8++;
297
- zBuf[iBuf++] = zLine[index++];
432
+ char_info_utf8(&zLine[index-1],&cchUTF8,&utf32);
433
+ if( cchUTF8>1 ){
434
+ int wcwidth;
435
+ wcwidth = cli_wcwidth(utf32);
436
+ if( wcwidth>maxChars && lineChars>=wcwidth ){ /* rollback */
437
+ index--;
438
+ iBuf--;
439
+ zBuf[iBuf] = 0;
440
+ break;
441
+ }
442
+ for( ; cchUTF8>1; cchUTF8-- ){
443
+ zBuf[iBuf++] = zLine[index++];
444
+ }
445
+ useChars += wcwidth - 1;
298446
}
299447
maxChars -= useChars;
300448
if( maxChars<=0 ) break;
301449
if( c=='\n' ) break;
302450
}
@@ -338,11 +486,10 @@
338486
int si, sk, i, k, kc;
339487
int doIndent = 0;
340488
char *zBuf;
341489
char zBuffer[400];
342490
int lineCnt = 0;
343
- int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */
344491
345492
if( width<0 ){
346493
comment_set_maxchars(indent, &maxChars);
347494
}
348495
if( zText==0 ) zText = "(NULL)";
@@ -364,25 +511,25 @@
364511
}
365512
if( zBuf!=zBuffer) fossil_free(zBuf);
366513
return lineCnt;
367514
}
368515
for(sk=si=i=k=kc=0; zText[i] && kc<maxChars; i++){
516
+ int cchUTF8, utf32;
369517
char c = zText[i];
370518
kc++; /* Count complete UTF-8 sequences. */
371
- /* Skip over UTF-8 sequences, see comment on strlen_utf8() for details. */
372
- cchUTF8=1; /* Code units consumed. */
373
- maxUTF8=1; /* Expected sequence length. */
374
- if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */
375
- else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */
376
- else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */
377
- if( maxUTF8>1 ){
378
- zBuf[k++] = c;
379
- while( cchUTF8<maxUTF8 &&
380
- (zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
381
- cchUTF8++;
519
+ char_info_utf8(&zText[i],&cchUTF8,&utf32);
520
+ if( cchUTF8>1 ){
521
+ int wcwidth;
522
+ wcwidth = cli_wcwidth(utf32);
523
+ if( kc+wcwidth-1>maxChars && maxChars>=wcwidth ){ /* rollback */
524
+ kc--;
525
+ break;
526
+ }
527
+ for( i--; cchUTF8>0; cchUTF8-- ){
382528
zBuf[k++] = zText[++i];
383529
}
530
+ kc += wcwidth - 1;
384531
}
385532
else if( fossil_isspace(c) ){
386533
si = i;
387534
sk = k;
388535
if( k==0 || zBuf[k-1]!=' ' ){
@@ -497,11 +644,13 @@
497644
zLine = zText;
498645
for(;;){
499646
comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0,
500647
maxChars, trimCrLf, trimSpace, wordBreak, origBreak,
501648
&lineCnt, &zLine);
502
- if( !zLine || !zLine[0] ) break;
649
+ if( zLine==0 ) break;
650
+ while( fossil_isspace(zLine[0]) ) zLine++;
651
+ if( zLine[0]==0 ) break;
503652
}
504653
return lineCnt;
505654
}
506655
507656
/*
@@ -597,10 +746,11 @@
597746
if( zIndent ){
598747
indent = atoi(zIndent);
599748
}else{
600749
indent = -1; /* automatic */
601750
}
751
+ verify_all_options();
602752
if( g.argc!=4 && g.argc!=5 ){
603753
usage("?OPTIONS? PREFIX TEXT ?ORIGTEXT?");
604754
}
605755
zPrefix = g.argv[2];
606756
zText = g.argv[3];
607757
--- src/comformat.c
+++ src/comformat.c
@@ -31,10 +31,117 @@
31 #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
32 #define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */
33 #define COMMENT_PRINT_UNSET (-1) /* Not initialized. */
34 #endif
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36 /*
37 ** This is the previous value used by most external callers when they
38 ** needed to specify a default maximum line length to be used with the
39 ** comment_print() function.
40 */
@@ -108,62 +215,99 @@
108 ** algorithm, the NUL character is treated the same as a spacing character.
109 */
110 static int comment_next_space(
111 const char *zLine, /* [in] The comment line being printed. */
112 int index, /* [in] The current character index being handled. */
113 int *distUTF8 /* [out] Distance to next space in UTF-8 sequences. */
 
114 ){
115 int nextIndex = index + 1;
116 int fNonASCII=0;
117 for(;;){
118 char c = zLine[nextIndex];
119 if( (c&0x80)==0x80 ) fNonASCII=1;
120 if( c==0 || fossil_isspace(c) ){
121 if( distUTF8 ){
122 if( fNonASCII!=0 ){
123 *distUTF8 = strlen_utf8(&zLine[index], nextIndex-index);
124 }else{
125 *distUTF8 = nextIndex-index;
126 }
127 }
128 return nextIndex;
129 }
130 nextIndex++;
131 }
132 return 0; /* NOT REACHED */
133 }
134
135 /*
136 ** Count the number of UTF-8 sequences in a string. Incomplete, ill-formed and
137 ** overlong sequences are counted as one sequence. The invalid lead bytes 0xC0
138 ** to 0xC1 and 0xF5 to 0xF7 are allowed to initiate (ill-formed) 2- and 4-byte
139 ** sequences, respectively, the other invalid lead bytes 0xF8 to 0xFF are
140 ** treated as invalid 1-byte sequences (as lone trail bytes).
141 ** Combining characters and East Asian Wide and Fullwidth characters are counted
142 ** as one, so this function does not calculate the effective "display width".
 
 
143 */
144 int strlen_utf8(const char *zString, int lengthBytes){
145 int i; /* Counted bytes. */
146 int lengthUTF8; /* Counted UTF-8 sequences. */
147 #if 0
148 assert( lengthBytes>=0 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149 #endif
150 for(i=0, lengthUTF8=0; i<lengthBytes; i++, lengthUTF8++){
151 char c = zString[i];
152 int cchUTF8=1; /* Code units consumed. */
153 int maxUTF8=1; /* Expected sequence length. */
154 if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */
155 else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */
156 else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */
157 while( cchUTF8<maxUTF8 &&
158 i<lengthBytes-1 &&
159 (zString[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
160 cchUTF8++;
161 i++;
162 }
163 }
164 return lengthUTF8;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165 }
166
167 /*
168 ** This function is called when printing a logical comment line to calculate
169 ** the necessary indenting. The caller needs to emit the indenting spaces.
@@ -206,11 +350,10 @@
206 int *pLineCnt, /* [in/out] Pointer to the total line count. */
207 const char **pzLine /* [out] Pointer to the end of the logical line. */
208 ){
209 int index = 0, charCnt = 0, lineCnt = 0, maxChars, i;
210 char zBuf[400]; int iBuf=0; /* Output buffer and counter. */
211 int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */
212 if( !zLine ) return;
213 if( lineChars<=0 ) return;
214 #if 0
215 assert( indent<sizeof(zBuf)-5 ); /* See following comments to explain */
216 assert( origIndent<sizeof(zBuf)-5 ); /* these limits. */
@@ -229,10 +372,11 @@
229 /* Limit line indent to fit output buffer. */
230 origIndent = sizeof(zBuf)-6;
231 }
232 maxChars = lineChars;
233 for(;;){
 
234 int useChars = 1;
235 char c = zLine[index];
236 /* Flush the output buffer if there's no space left for at least one more
237 ** (potentially 4-byte) UTF-8 sequence, one level of indentation spaces,
238 ** a new line, and a terminating NULL. */
@@ -260,43 +404,47 @@
260 if( c=='\n' ){
261 lineCnt++;
262 charCnt = 0;
263 useChars = 0;
264 }else if( c=='\t' ){
265 int distUTF8;
266 int nextIndex = comment_next_space(zLine, index, &distUTF8);
267 if( nextIndex<=0 || distUTF8>maxChars ){
268 break;
269 }
270 charCnt++;
271 useChars = COMMENT_TAB_WIDTH;
272 if( maxChars<useChars ){
273 zBuf[iBuf++] = ' ';
274 break;
275 }
276 }else if( wordBreak && fossil_isspace(c) ){
277 int distUTF8;
278 int nextIndex = comment_next_space(zLine, index, &distUTF8);
279 if( nextIndex<=0 || distUTF8>=maxChars ){
280 break;
281 }
282 charCnt++;
283 }else{
284 charCnt++;
285 }
286 assert( c!='\n' || charCnt==0 );
287 zBuf[iBuf++] = c;
288 /* Skip over UTF-8 sequences, see comment on strlen_utf8() for details. */
289 cchUTF8=1; /* Code units consumed. */
290 maxUTF8=1; /* Expected sequence length. */
291 if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */
292 else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */
293 else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */
294 while( cchUTF8<maxUTF8 &&
295 (zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
296 cchUTF8++;
297 zBuf[iBuf++] = zLine[index++];
 
 
 
 
298 }
299 maxChars -= useChars;
300 if( maxChars<=0 ) break;
301 if( c=='\n' ) break;
302 }
@@ -338,11 +486,10 @@
338 int si, sk, i, k, kc;
339 int doIndent = 0;
340 char *zBuf;
341 char zBuffer[400];
342 int lineCnt = 0;
343 int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */
344
345 if( width<0 ){
346 comment_set_maxchars(indent, &maxChars);
347 }
348 if( zText==0 ) zText = "(NULL)";
@@ -364,25 +511,25 @@
364 }
365 if( zBuf!=zBuffer) fossil_free(zBuf);
366 return lineCnt;
367 }
368 for(sk=si=i=k=kc=0; zText[i] && kc<maxChars; i++){
 
369 char c = zText[i];
370 kc++; /* Count complete UTF-8 sequences. */
371 /* Skip over UTF-8 sequences, see comment on strlen_utf8() for details. */
372 cchUTF8=1; /* Code units consumed. */
373 maxUTF8=1; /* Expected sequence length. */
374 if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */
375 else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */
376 else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */
377 if( maxUTF8>1 ){
378 zBuf[k++] = c;
379 while( cchUTF8<maxUTF8 &&
380 (zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
381 cchUTF8++;
382 zBuf[k++] = zText[++i];
383 }
 
384 }
385 else if( fossil_isspace(c) ){
386 si = i;
387 sk = k;
388 if( k==0 || zBuf[k-1]!=' ' ){
@@ -497,11 +644,13 @@
497 zLine = zText;
498 for(;;){
499 comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0,
500 maxChars, trimCrLf, trimSpace, wordBreak, origBreak,
501 &lineCnt, &zLine);
502 if( !zLine || !zLine[0] ) break;
 
 
503 }
504 return lineCnt;
505 }
506
507 /*
@@ -597,10 +746,11 @@
597 if( zIndent ){
598 indent = atoi(zIndent);
599 }else{
600 indent = -1; /* automatic */
601 }
 
602 if( g.argc!=4 && g.argc!=5 ){
603 usage("?OPTIONS? PREFIX TEXT ?ORIGTEXT?");
604 }
605 zPrefix = g.argv[2];
606 zText = g.argv[3];
607
--- src/comformat.c
+++ src/comformat.c
@@ -31,10 +31,117 @@
31 #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
32 #define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */
33 #define COMMENT_PRINT_UNSET (-1) /* Not initialized. */
34 #endif
35
36 /********* Code copied from SQLite src/shell.c.in on 2024-09-30 **********/
37 /* Lookup table to estimate the number of columns consumed by a Unicode
38 ** character.
39 */
40 static const struct {
41 unsigned char w; /* Width of the character in columns */
42 int iFirst; /* First character in a span having this width */
43 } aUWidth[] = {
44 /* {1, 0x00000}, */
45 {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488},
46 {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0},
47 {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7},
48 {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616},
49 {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6},
50 {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee},
51 {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730},
52 {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4},
53 {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941},
54 {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955},
55 {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc},
56 {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce},
57 {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c},
58 {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49},
59 {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81},
60 {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6},
61 {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2},
62 {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d},
63 {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d},
64 {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83},
65 {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e},
66 {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e},
67 {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf},
68 {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce},
69 {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d},
70 {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5},
71 {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34},
72 {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2},
73 {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8},
74 {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36},
75 {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71},
76 {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
77 {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
78 {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
79 {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
80 {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
81 {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
82 {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
83 {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7},
84 {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b},
85 {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923},
86 {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939},
87 {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04},
88 {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c},
89 {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74},
90 {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b},
91 {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064},
92 {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329},
93 {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f},
94 {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806},
95 {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827},
96 {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e},
97 {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20},
98 {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00},
99 {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc},
100 {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c},
101 {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40},
102 {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185},
103 {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245},
104 {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001},
105 {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0}
106 };
107
108 /*
109 ** Return an estimate of the width, in columns, for the single Unicode
110 ** character c. For normal characters, the answer is always 1. But the
111 ** estimate might be 0 or 2 for zero-width and double-width characters.
112 **
113 ** Different display devices display unicode using different widths. So
114 ** it is impossible to know that true display width with 100% accuracy.
115 ** Inaccuracies in the width estimates might cause columns to be misaligned.
116 ** Unfortunately, there is nothing we can do about that.
117 */
118 static int cli_wcwidth(int c){
119 int iFirst, iLast;
120
121 /* Fast path for common characters */
122 if( c<=0x300 ) return 1;
123
124 /* The general case */
125 iFirst = 0;
126 iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1;
127 while( iFirst<iLast-1 ){
128 int iMid = (iFirst+iLast)/2;
129 int cMid = aUWidth[iMid].iFirst;
130 if( cMid < c ){
131 iFirst = iMid;
132 }else if( cMid > c ){
133 iLast = iMid - 1;
134 }else{
135 return aUWidth[iMid].w;
136 }
137 }
138 if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w;
139 return aUWidth[iLast].w;
140 }
141 /******* End of code copied from SQLite *************************************/
142
143 /*
144 ** This is the previous value used by most external callers when they
145 ** needed to specify a default maximum line length to be used with the
146 ** comment_print() function.
147 */
@@ -108,62 +215,99 @@
215 ** algorithm, the NUL character is treated the same as a spacing character.
216 */
217 static int comment_next_space(
218 const char *zLine, /* [in] The comment line being printed. */
219 int index, /* [in] The current character index being handled. */
220 int maxChars, /* [in] Optimization hint to abort before space found. */
221 int *sumWidth /* [out] Summated width of all characters to next space. */
222 ){
223 int cchUTF8, utf32, wcwidth = 0;
224 int nextIndex = index;
225 for(;;){
226 char_info_utf8(&zLine[nextIndex],&cchUTF8,&utf32);
227 nextIndex += cchUTF8;
228 wcwidth += cli_wcwidth(utf32);
229 if( zLine[nextIndex]==0 || fossil_isspace(zLine[nextIndex]) ||
230 wcwidth>maxChars ){
231 *sumWidth = wcwidth;
 
 
 
 
232 return nextIndex;
233 }
 
234 }
235 return 0; /* NOT REACHED */
236 }
237
238 /*
239 ** Return information about the next (single- or multi-byte) character in the
240 ** specified UTF-8 string: The number of UTF-8 code units (in this case: bytes)
241 ** and the decoded UTF-32 code point. Incomplete, ill-formed and overlong
242 ** sequences are consumed together as one invalid code point. The invalid lead
243 ** bytes 0xC0 to 0xC1 and 0xF5 to 0xF7 are allowed to initiate (ill-formed) 2-
244 ** and 4-byte sequences, respectively, the other invalid lead bytes 0xF8 to 0xFF
245 ** are treated as invalid 1-byte sequences (as lone trail bytes), all resulting
246 ** in one invalid code point. Invalid UTF-8 sequences encoding a non-scalar code
247 ** point (UTF-16 surrogates U+D800 to U+DFFF) are allowed.
248 */
249 void char_info_utf8(
250 const char *z,
251 int *pCchUTF8,
252 int *pUtf32
253 ){
254 int i = 0; /* Counted bytes. */
255 int cchUTF8 = 1; /* Code units consumed. */
256 int maxUTF8 = 1; /* Expected sequence length. */
257 char c = z[i++];
258 if( (c&0x80)==0x00 ){ /* 7-bit ASCII character. */
259 *pCchUTF8 = 1;
260 *pUtf32 = (int)z[0];
261 return;
262 }
263 else if( (c&0xe0)==0xc0 ) maxUTF8 = 2; /* UTF-8 lead byte 110vvvvv */
264 else if( (c&0xf0)==0xe0 ) maxUTF8 = 3; /* UTF-8 lead byte 1110vvvv */
265 else if( (c&0xf8)==0xf0 ) maxUTF8 = 4; /* UTF-8 lead byte 11110vvv */
266 while( cchUTF8<maxUTF8 &&
267 (z[i]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
268 cchUTF8++;
269 i++;
270 }
271 *pCchUTF8 = cchUTF8;
272 if( cchUTF8!=maxUTF8 || /* Incomplete UTF-8 sequence. */
273 ( cchUTF8==1 && (c&0x80)==0x80 )){ /* Lone UTF-8 trail byte. */
274 *pUtf32 = 0xfffd; /* U+FFFD Replacement Character */
275 #ifdef FOSSIL_DEBUG
276 assert( *pUtf32!=0xfffd ); /* Invalid UTF-8 sequence. */
277 #endif
278 return;
279 }
280 switch( cchUTF8 ){
281 case 4:
282 *pUtf32 =
283 ( (z[0] & 0x0f)<<18 ) |
284 ( (z[1] & 0x3f)<<12 ) |
285 ( (z[2] & 0x3f)<< 6 ) |
286 ( (z[4] & 0x3f)<< 0 ) ;
287 break;
288 case 3:
289 *pUtf32 =
290 ( (z[0] & 0x0f)<<12 ) |
291 ( (z[1] & 0x3f)<< 6 ) |
292 ( (z[2] & 0x3f)<< 0 ) ;
293 break;
294 case 2:
295 *pUtf32 =
296 ( (z[0] & 0x1f)<< 6 ) |
297 ( (z[1] & 0x3f)<< 0 ) ;
298 break;
299 default:
300 *pUtf32 = 0xfffd; /* U+FFFD Replacement Character */
301 break;
302 }
303 #ifdef FOSSIL_DEBUG
304 assert(
305 *pUtf32>=0 && *pUtf32<=0x10ffff && /* Valid range U+0000 to U+10FFFF. */
306 *pUtf32<0xd800 && *pUtf32>0xdfff /* Non-scalar (UTF-16 surrogates). */
307 );
308 #endif
309 }
310
311 /*
312 ** This function is called when printing a logical comment line to calculate
313 ** the necessary indenting. The caller needs to emit the indenting spaces.
@@ -206,11 +350,10 @@
350 int *pLineCnt, /* [in/out] Pointer to the total line count. */
351 const char **pzLine /* [out] Pointer to the end of the logical line. */
352 ){
353 int index = 0, charCnt = 0, lineCnt = 0, maxChars, i;
354 char zBuf[400]; int iBuf=0; /* Output buffer and counter. */
 
355 if( !zLine ) return;
356 if( lineChars<=0 ) return;
357 #if 0
358 assert( indent<sizeof(zBuf)-5 ); /* See following comments to explain */
359 assert( origIndent<sizeof(zBuf)-5 ); /* these limits. */
@@ -229,10 +372,11 @@
372 /* Limit line indent to fit output buffer. */
373 origIndent = sizeof(zBuf)-6;
374 }
375 maxChars = lineChars;
376 for(;;){
377 int cchUTF8, utf32;
378 int useChars = 1;
379 char c = zLine[index];
380 /* Flush the output buffer if there's no space left for at least one more
381 ** (potentially 4-byte) UTF-8 sequence, one level of indentation spaces,
382 ** a new line, and a terminating NULL. */
@@ -260,43 +404,47 @@
404 if( c=='\n' ){
405 lineCnt++;
406 charCnt = 0;
407 useChars = 0;
408 }else if( c=='\t' ){
409 int sumWidth;
410 int nextIndex = comment_next_space(zLine, index, maxChars, &sumWidth);
411 if( nextIndex<=0 || sumWidth>maxChars ){
412 break;
413 }
414 charCnt++;
415 useChars = COMMENT_TAB_WIDTH;
416 if( maxChars<useChars ){
417 zBuf[iBuf++] = ' ';
418 break;
419 }
420 }else if( wordBreak && fossil_isspace(c) ){
421 int sumWidth;
422 int nextIndex = comment_next_space(zLine, index, maxChars, &sumWidth);
423 if( nextIndex<=0 || sumWidth>=maxChars ){
424 break;
425 }
426 charCnt++;
427 }else{
428 charCnt++;
429 }
430 assert( c!='\n' || charCnt==0 );
431 zBuf[iBuf++] = c;
432 char_info_utf8(&zLine[index-1],&cchUTF8,&utf32);
433 if( cchUTF8>1 ){
434 int wcwidth;
435 wcwidth = cli_wcwidth(utf32);
436 if( wcwidth>maxChars && lineChars>=wcwidth ){ /* rollback */
437 index--;
438 iBuf--;
439 zBuf[iBuf] = 0;
440 break;
441 }
442 for( ; cchUTF8>1; cchUTF8-- ){
443 zBuf[iBuf++] = zLine[index++];
444 }
445 useChars += wcwidth - 1;
446 }
447 maxChars -= useChars;
448 if( maxChars<=0 ) break;
449 if( c=='\n' ) break;
450 }
@@ -338,11 +486,10 @@
486 int si, sk, i, k, kc;
487 int doIndent = 0;
488 char *zBuf;
489 char zBuffer[400];
490 int lineCnt = 0;
 
491
492 if( width<0 ){
493 comment_set_maxchars(indent, &maxChars);
494 }
495 if( zText==0 ) zText = "(NULL)";
@@ -364,25 +511,25 @@
511 }
512 if( zBuf!=zBuffer) fossil_free(zBuf);
513 return lineCnt;
514 }
515 for(sk=si=i=k=kc=0; zText[i] && kc<maxChars; i++){
516 int cchUTF8, utf32;
517 char c = zText[i];
518 kc++; /* Count complete UTF-8 sequences. */
519 char_info_utf8(&zText[i],&cchUTF8,&utf32);
520 if( cchUTF8>1 ){
521 int wcwidth;
522 wcwidth = cli_wcwidth(utf32);
523 if( kc+wcwidth-1>maxChars && maxChars>=wcwidth ){ /* rollback */
524 kc--;
525 break;
526 }
527 for( i--; cchUTF8>0; cchUTF8-- ){
 
 
528 zBuf[k++] = zText[++i];
529 }
530 kc += wcwidth - 1;
531 }
532 else if( fossil_isspace(c) ){
533 si = i;
534 sk = k;
535 if( k==0 || zBuf[k-1]!=' ' ){
@@ -497,11 +644,13 @@
644 zLine = zText;
645 for(;;){
646 comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0,
647 maxChars, trimCrLf, trimSpace, wordBreak, origBreak,
648 &lineCnt, &zLine);
649 if( zLine==0 ) break;
650 while( fossil_isspace(zLine[0]) ) zLine++;
651 if( zLine[0]==0 ) break;
652 }
653 return lineCnt;
654 }
655
656 /*
@@ -597,10 +746,11 @@
746 if( zIndent ){
747 indent = atoi(zIndent);
748 }else{
749 indent = -1; /* automatic */
750 }
751 verify_all_options();
752 if( g.argc!=4 && g.argc!=5 ){
753 usage("?OPTIONS? PREFIX TEXT ?ORIGTEXT?");
754 }
755 zPrefix = g.argv[2];
756 zText = g.argv[3];
757
+28 -9
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118118
{ "adunit-omit-if-user", CONFIGSET_SKIN },
119119
{ "default-csp", CONFIGSET_SKIN },
120120
{ "sitemap-extra", CONFIGSET_SKIN },
121121
{ "safe-html", CONFIGSET_SKIN },
122122
123
-#ifdef FOSSIL_ENABLE_TH1_DOCS
124
- { "th1-docs", CONFIGSET_TH1 },
125
-#endif
126123
#ifdef FOSSIL_ENABLE_TH1_HOOKS
127124
{ "th1-hooks", CONFIGSET_TH1 },
128125
#endif
129
- { "th1-setup", CONFIGSET_TH1 },
130126
{ "th1-uri-regexp", CONFIGSET_TH1 },
131127
132
-#ifdef FOSSIL_ENABLE_TCL
133
- { "tcl", CONFIGSET_TH1 },
134
- { "tcl-setup", CONFIGSET_TH1 },
135
-#endif
136
-
137128
{ "project-name", CONFIGSET_PROJ },
138129
{ "short-project-name", CONFIGSET_PROJ },
139130
{ "project-description", CONFIGSET_PROJ },
140131
{ "index-page", CONFIGSET_PROJ },
141132
{ "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
239230
**
240231
** "Safe" in the previous paragraph means the permission is granted to
241232
** export the property. In other words, the requesting side has presented
242233
** login credentials and has sufficient capabilities to access the requested
243234
** information.
235
+**
236
+** Settings which are specifically flagged as sensitive will (as of
237
+** 2024-10-15) cause this function to return 0, regardless of user
238
+** permissions. As an example, if the th1-setup setting were not
239
+** sensitive then a malicious repo admin could set that to include
240
+** arbitrary TCL code and affect users who configure fossil with the
241
+** --with-tcl flag.
244242
*/
245243
int configure_is_exportable(const char *zName){
246244
int i;
247245
int n = strlen(zName);
246
+ Setting *pSet;
248247
if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
248
+ char * zCpy;
249249
zName++;
250250
n -= 2;
251
+ zCpy = fossil_strndup(zName, (ssize_t)n);
252
+ pSet = db_find_setting(zCpy, 0);
253
+ fossil_free(zCpy);
254
+ }else{
255
+ pSet = db_find_setting(zName, 0);
256
+ }
257
+ if( pSet && pSet->sensitive ){
258
+ /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
259
+ return 0;
251260
}
252261
for(i=0; i<count(aConfig); i++){
253262
if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
254263
int m = aConfig[i].groupMask;
255264
if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
414423
if( nToken>=count(azToken)-1 ) break;
415424
}
416425
if( nToken<2 ) return;
417426
if( aType[ii].zName[0]=='/' ){
418427
thisMask = configure_is_exportable(azToken[1]);
428
+ if( 0==thisMask ){
429
+ fossil_warning("Skipping non-exportable setting: %s = %s",
430
+ azToken[1], nToken>3 ? azToken[3] : "?");
431
+ /* Will be skipped below */
432
+ }
419433
}else{
420434
thisMask = configure_is_exportable(aType[ii].zName);
421435
}
422436
if( (thisMask & groupMask)==0 ) return;
423437
if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
681695
}
682696
db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
683697
" WHERE name=:name AND mtime>=%lld", iStart);
684698
for(ii=0; ii<count(aConfig); ii++){
685699
if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
700
+ const Setting * pSet = db_find_setting(aConfig[ii].zName, 0);
701
+ if( pSet && pSet->sensitive ){
702
+ /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
703
+ continue;
704
+ }
686705
db_bind_text(&q, ":name", aConfig[ii].zName);
687706
while( db_step(&q)==SQLITE_ROW ){
688707
blob_appendf(&rec,"%s %s value %s",
689708
db_column_text(&q, 0),
690709
db_column_text(&q, 1),
691710
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118 { "adunit-omit-if-user", CONFIGSET_SKIN },
119 { "default-csp", CONFIGSET_SKIN },
120 { "sitemap-extra", CONFIGSET_SKIN },
121 { "safe-html", CONFIGSET_SKIN },
122
123 #ifdef FOSSIL_ENABLE_TH1_DOCS
124 { "th1-docs", CONFIGSET_TH1 },
125 #endif
126 #ifdef FOSSIL_ENABLE_TH1_HOOKS
127 { "th1-hooks", CONFIGSET_TH1 },
128 #endif
129 { "th1-setup", CONFIGSET_TH1 },
130 { "th1-uri-regexp", CONFIGSET_TH1 },
131
132 #ifdef FOSSIL_ENABLE_TCL
133 { "tcl", CONFIGSET_TH1 },
134 { "tcl-setup", CONFIGSET_TH1 },
135 #endif
136
137 { "project-name", CONFIGSET_PROJ },
138 { "short-project-name", CONFIGSET_PROJ },
139 { "project-description", CONFIGSET_PROJ },
140 { "index-page", CONFIGSET_PROJ },
141 { "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
239 **
240 ** "Safe" in the previous paragraph means the permission is granted to
241 ** export the property. In other words, the requesting side has presented
242 ** login credentials and has sufficient capabilities to access the requested
243 ** information.
 
 
 
 
 
 
 
244 */
245 int configure_is_exportable(const char *zName){
246 int i;
247 int n = strlen(zName);
 
248 if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
 
249 zName++;
250 n -= 2;
 
 
 
 
 
 
 
 
 
251 }
252 for(i=0; i<count(aConfig); i++){
253 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
254 int m = aConfig[i].groupMask;
255 if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
414 if( nToken>=count(azToken)-1 ) break;
415 }
416 if( nToken<2 ) return;
417 if( aType[ii].zName[0]=='/' ){
418 thisMask = configure_is_exportable(azToken[1]);
 
 
 
 
 
419 }else{
420 thisMask = configure_is_exportable(aType[ii].zName);
421 }
422 if( (thisMask & groupMask)==0 ) return;
423 if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
681 }
682 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
683 " WHERE name=:name AND mtime>=%lld", iStart);
684 for(ii=0; ii<count(aConfig); ii++){
685 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
 
 
 
 
 
686 db_bind_text(&q, ":name", aConfig[ii].zName);
687 while( db_step(&q)==SQLITE_ROW ){
688 blob_appendf(&rec,"%s %s value %s",
689 db_column_text(&q, 0),
690 db_column_text(&q, 1),
691
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118 { "adunit-omit-if-user", CONFIGSET_SKIN },
119 { "default-csp", CONFIGSET_SKIN },
120 { "sitemap-extra", CONFIGSET_SKIN },
121 { "safe-html", CONFIGSET_SKIN },
122
 
 
 
123 #ifdef FOSSIL_ENABLE_TH1_HOOKS
124 { "th1-hooks", CONFIGSET_TH1 },
125 #endif
 
126 { "th1-uri-regexp", CONFIGSET_TH1 },
127
 
 
 
 
 
128 { "project-name", CONFIGSET_PROJ },
129 { "short-project-name", CONFIGSET_PROJ },
130 { "project-description", CONFIGSET_PROJ },
131 { "index-page", CONFIGSET_PROJ },
132 { "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
230 **
231 ** "Safe" in the previous paragraph means the permission is granted to
232 ** export the property. In other words, the requesting side has presented
233 ** login credentials and has sufficient capabilities to access the requested
234 ** information.
235 **
236 ** Settings which are specifically flagged as sensitive will (as of
237 ** 2024-10-15) cause this function to return 0, regardless of user
238 ** permissions. As an example, if the th1-setup setting were not
239 ** sensitive then a malicious repo admin could set that to include
240 ** arbitrary TCL code and affect users who configure fossil with the
241 ** --with-tcl flag.
242 */
243 int configure_is_exportable(const char *zName){
244 int i;
245 int n = strlen(zName);
246 Setting *pSet;
247 if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
248 char * zCpy;
249 zName++;
250 n -= 2;
251 zCpy = fossil_strndup(zName, (ssize_t)n);
252 pSet = db_find_setting(zCpy, 0);
253 fossil_free(zCpy);
254 }else{
255 pSet = db_find_setting(zName, 0);
256 }
257 if( pSet && pSet->sensitive ){
258 /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
259 return 0;
260 }
261 for(i=0; i<count(aConfig); i++){
262 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
263 int m = aConfig[i].groupMask;
264 if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
423 if( nToken>=count(azToken)-1 ) break;
424 }
425 if( nToken<2 ) return;
426 if( aType[ii].zName[0]=='/' ){
427 thisMask = configure_is_exportable(azToken[1]);
428 if( 0==thisMask ){
429 fossil_warning("Skipping non-exportable setting: %s = %s",
430 azToken[1], nToken>3 ? azToken[3] : "?");
431 /* Will be skipped below */
432 }
433 }else{
434 thisMask = configure_is_exportable(aType[ii].zName);
435 }
436 if( (thisMask & groupMask)==0 ) return;
437 if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
695 }
696 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
697 " WHERE name=:name AND mtime>=%lld", iStart);
698 for(ii=0; ii<count(aConfig); ii++){
699 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
700 const Setting * pSet = db_find_setting(aConfig[ii].zName, 0);
701 if( pSet && pSet->sensitive ){
702 /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
703 continue;
704 }
705 db_bind_text(&q, ":name", aConfig[ii].zName);
706 while( db_step(&q)==SQLITE_ROW ){
707 blob_appendf(&rec,"%s %s value %s",
708 db_column_text(&q, 0),
709 db_column_text(&q, 1),
710
+13 -14
--- src/db.c
+++ src/db.c
@@ -1557,10 +1557,12 @@
15571557
sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
15581558
url_nouser_func,0,0);
15591559
sqlite3_create_function(db, "chat_msg_from_event", 4,
15601560
SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
15611561
chat_msg_from_event, 0, 0);
1562
+ sqlite3_create_function(db, "inode", 1, SQLITE_UTF8, 0,
1563
+ file_inode_sql_func,0,0);
15621564
15631565
}
15641566
15651567
#if USE_SEE
15661568
/*
@@ -4080,11 +4082,11 @@
40804082
** specified then that version is checked out. Otherwise the most recent
40814083
** check-in on the main branch (usually "trunk") is used.
40824084
**
40834085
** REPOSITORY can be the filename for a repository that already exists on the
40844086
** local machine or it can be a URI for a remote repository. If REPOSITORY
4085
-** is a URI in one of the formats recognized by the [[clone]] command, then
4087
+** is a URI in one of the formats recognized by the [[clone]] command, the
40864088
** remote repo is first cloned, then the clone is opened. The clone will be
40874089
** stored in the current directory, or in DIR if the "--repodir DIR" option
40884090
** is used. The name of the clone will be taken from the last term of the URI.
40894091
** For "http:" and "https:" URIs, you can append an extra term to the end of
40904092
** the URI to get any repository name you like. For example:
@@ -4681,17 +4683,10 @@
46814683
** to obtain a check-in lock during auto-sync, the server will
46824684
** send the "pragma avoid-delta-manifests" statement in its reply,
46834685
** which will cause the client to avoid generating a delta
46844686
** manifest.
46854687
*/
4686
-/*
4687
-** SETTING: forum-close-policy boolean default=off
4688
-** If true, forum moderators may close/re-open forum posts, and reply
4689
-** to closed posts. If false, only administrators may do so. Note that
4690
-** this only affects the forum web UI, not post-closing tags which
4691
-** arrive via the command-line or from synchronization with a remote.
4692
-*/
46934688
/*
46944689
** SETTING: gdiff-command width=40 default=gdiff sensitive
46954690
** The value is an external command to run when performing a graphical
46964691
** diff. If undefined, text diff will be used.
46974692
*/
@@ -4841,15 +4836,19 @@
48414836
** URL of the HTTP proxy. If undefined or "system", the "http_proxy"
48424837
** environment variable is consulted. If "off", a direct HTTP connection is
48434838
** used.
48444839
*/
48454840
/*
4846
-** SETTING: redirect-to-https default=0 width=-1
4847
-** Specifies whether or not to redirect http:// requests to
4848
-** https:// URIs. A value of 0 (the default) means not to
4841
+** SETTING: redirect-to-https default=0 width=2
4842
+** Specifies whether or not to redirect unencrypted "http://" requests to
4843
+** encrypted "https://" URIs. A value of 0 (the default) means do not
48494844
** redirect, 1 means to redirect only the /login page, and 2
48504845
** means to always redirect.
4846
+**
4847
+** For security, a value of 2 is recommended. The default value is 0
4848
+** because not all sites are TLS-capable. But you should definitely enable
4849
+** TLS and change this setting to 2 for all public-facing repositories.
48514850
*/
48524851
/*
48534852
** SETTING: relative-paths boolean default=on
48544853
** When showing changes and extras, report paths relative
48554854
** to the current working directory.
@@ -4967,11 +4966,11 @@
49674966
** If enabled, special TH1 commands will be called before and
49684967
** after any Fossil command or web page.
49694968
*/
49704969
#endif
49714970
/*
4972
-** SETTING: th1-setup width=40 block-text
4971
+** SETTING: th1-setup width=40 block-text sensitive
49734972
** This is the setup script to be evaluated after creating
49744973
** and initializing the TH1 interpreter. By default, this
49754974
** is empty and no extra setup is performed.
49764975
*/
49774976
/*
@@ -5358,11 +5357,11 @@
53585357
}
53595358
53605359
/*
53615360
** Compute a "fingerprint" on the repository. A fingerprint is used
53625361
** to verify that that the repository has not been replaced by a clone
5363
-** of the same repository. More precisely, a fingerprint are used to
5362
+** of the same repository. More precisely, a fingerprint is used to
53645363
** verify that the mapping between SHA3 hashes and RID values is unchanged.
53655364
**
53665365
** The check-out database ("localdb") stores RID values. When associating
53675366
** a check-out database against a repository database, it is useful to verify
53685367
** the fingerprint so that we know tha the RID values in the check-out
@@ -5423,11 +5422,11 @@
54235422
** COMMAND: test-fingerprint
54245423
**
54255424
** Usage: %fossil test-fingerprint ?RCVID?
54265425
**
54275426
** Display the repository fingerprint using the supplied RCVID or
5428
-** using the latest RCVID if not is given on the command line.
5427
+** using the latest RCVID if none is given on the command line.
54295428
** Show both the legacy and the newer version of the fingerprint,
54305429
** and the currently stored fingerprint if there is one.
54315430
*/
54325431
void test_fingerprint(void){
54335432
int rcvid = 0;
54345433
--- src/db.c
+++ src/db.c
@@ -1557,10 +1557,12 @@
1557 sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
1558 url_nouser_func,0,0);
1559 sqlite3_create_function(db, "chat_msg_from_event", 4,
1560 SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
1561 chat_msg_from_event, 0, 0);
 
 
1562
1563 }
1564
1565 #if USE_SEE
1566 /*
@@ -4080,11 +4082,11 @@
4080 ** specified then that version is checked out. Otherwise the most recent
4081 ** check-in on the main branch (usually "trunk") is used.
4082 **
4083 ** REPOSITORY can be the filename for a repository that already exists on the
4084 ** local machine or it can be a URI for a remote repository. If REPOSITORY
4085 ** is a URI in one of the formats recognized by the [[clone]] command, then
4086 ** remote repo is first cloned, then the clone is opened. The clone will be
4087 ** stored in the current directory, or in DIR if the "--repodir DIR" option
4088 ** is used. The name of the clone will be taken from the last term of the URI.
4089 ** For "http:" and "https:" URIs, you can append an extra term to the end of
4090 ** the URI to get any repository name you like. For example:
@@ -4681,17 +4683,10 @@
4681 ** to obtain a check-in lock during auto-sync, the server will
4682 ** send the "pragma avoid-delta-manifests" statement in its reply,
4683 ** which will cause the client to avoid generating a delta
4684 ** manifest.
4685 */
4686 /*
4687 ** SETTING: forum-close-policy boolean default=off
4688 ** If true, forum moderators may close/re-open forum posts, and reply
4689 ** to closed posts. If false, only administrators may do so. Note that
4690 ** this only affects the forum web UI, not post-closing tags which
4691 ** arrive via the command-line or from synchronization with a remote.
4692 */
4693 /*
4694 ** SETTING: gdiff-command width=40 default=gdiff sensitive
4695 ** The value is an external command to run when performing a graphical
4696 ** diff. If undefined, text diff will be used.
4697 */
@@ -4841,15 +4836,19 @@
4841 ** URL of the HTTP proxy. If undefined or "system", the "http_proxy"
4842 ** environment variable is consulted. If "off", a direct HTTP connection is
4843 ** used.
4844 */
4845 /*
4846 ** SETTING: redirect-to-https default=0 width=-1
4847 ** Specifies whether or not to redirect http:// requests to
4848 ** https:// URIs. A value of 0 (the default) means not to
4849 ** redirect, 1 means to redirect only the /login page, and 2
4850 ** means to always redirect.
 
 
 
 
4851 */
4852 /*
4853 ** SETTING: relative-paths boolean default=on
4854 ** When showing changes and extras, report paths relative
4855 ** to the current working directory.
@@ -4967,11 +4966,11 @@
4967 ** If enabled, special TH1 commands will be called before and
4968 ** after any Fossil command or web page.
4969 */
4970 #endif
4971 /*
4972 ** SETTING: th1-setup width=40 block-text
4973 ** This is the setup script to be evaluated after creating
4974 ** and initializing the TH1 interpreter. By default, this
4975 ** is empty and no extra setup is performed.
4976 */
4977 /*
@@ -5358,11 +5357,11 @@
5358 }
5359
5360 /*
5361 ** Compute a "fingerprint" on the repository. A fingerprint is used
5362 ** to verify that that the repository has not been replaced by a clone
5363 ** of the same repository. More precisely, a fingerprint are used to
5364 ** verify that the mapping between SHA3 hashes and RID values is unchanged.
5365 **
5366 ** The check-out database ("localdb") stores RID values. When associating
5367 ** a check-out database against a repository database, it is useful to verify
5368 ** the fingerprint so that we know tha the RID values in the check-out
@@ -5423,11 +5422,11 @@
5423 ** COMMAND: test-fingerprint
5424 **
5425 ** Usage: %fossil test-fingerprint ?RCVID?
5426 **
5427 ** Display the repository fingerprint using the supplied RCVID or
5428 ** using the latest RCVID if not is given on the command line.
5429 ** Show both the legacy and the newer version of the fingerprint,
5430 ** and the currently stored fingerprint if there is one.
5431 */
5432 void test_fingerprint(void){
5433 int rcvid = 0;
5434
--- src/db.c
+++ src/db.c
@@ -1557,10 +1557,12 @@
1557 sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
1558 url_nouser_func,0,0);
1559 sqlite3_create_function(db, "chat_msg_from_event", 4,
1560 SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
1561 chat_msg_from_event, 0, 0);
1562 sqlite3_create_function(db, "inode", 1, SQLITE_UTF8, 0,
1563 file_inode_sql_func,0,0);
1564
1565 }
1566
1567 #if USE_SEE
1568 /*
@@ -4080,11 +4082,11 @@
4082 ** specified then that version is checked out. Otherwise the most recent
4083 ** check-in on the main branch (usually "trunk") is used.
4084 **
4085 ** REPOSITORY can be the filename for a repository that already exists on the
4086 ** local machine or it can be a URI for a remote repository. If REPOSITORY
4087 ** is a URI in one of the formats recognized by the [[clone]] command, the
4088 ** remote repo is first cloned, then the clone is opened. The clone will be
4089 ** stored in the current directory, or in DIR if the "--repodir DIR" option
4090 ** is used. The name of the clone will be taken from the last term of the URI.
4091 ** For "http:" and "https:" URIs, you can append an extra term to the end of
4092 ** the URI to get any repository name you like. For example:
@@ -4681,17 +4683,10 @@
4683 ** to obtain a check-in lock during auto-sync, the server will
4684 ** send the "pragma avoid-delta-manifests" statement in its reply,
4685 ** which will cause the client to avoid generating a delta
4686 ** manifest.
4687 */
 
 
 
 
 
 
 
4688 /*
4689 ** SETTING: gdiff-command width=40 default=gdiff sensitive
4690 ** The value is an external command to run when performing a graphical
4691 ** diff. If undefined, text diff will be used.
4692 */
@@ -4841,15 +4836,19 @@
4836 ** URL of the HTTP proxy. If undefined or "system", the "http_proxy"
4837 ** environment variable is consulted. If "off", a direct HTTP connection is
4838 ** used.
4839 */
4840 /*
4841 ** SETTING: redirect-to-https default=0 width=2
4842 ** Specifies whether or not to redirect unencrypted "http://" requests to
4843 ** encrypted "https://" URIs. A value of 0 (the default) means do not
4844 ** redirect, 1 means to redirect only the /login page, and 2
4845 ** means to always redirect.
4846 **
4847 ** For security, a value of 2 is recommended. The default value is 0
4848 ** because not all sites are TLS-capable. But you should definitely enable
4849 ** TLS and change this setting to 2 for all public-facing repositories.
4850 */
4851 /*
4852 ** SETTING: relative-paths boolean default=on
4853 ** When showing changes and extras, report paths relative
4854 ** to the current working directory.
@@ -4967,11 +4966,11 @@
4966 ** If enabled, special TH1 commands will be called before and
4967 ** after any Fossil command or web page.
4968 */
4969 #endif
4970 /*
4971 ** SETTING: th1-setup width=40 block-text sensitive
4972 ** This is the setup script to be evaluated after creating
4973 ** and initializing the TH1 interpreter. By default, this
4974 ** is empty and no extra setup is performed.
4975 */
4976 /*
@@ -5358,11 +5357,11 @@
5357 }
5358
5359 /*
5360 ** Compute a "fingerprint" on the repository. A fingerprint is used
5361 ** to verify that that the repository has not been replaced by a clone
5362 ** of the same repository. More precisely, a fingerprint is used to
5363 ** verify that the mapping between SHA3 hashes and RID values is unchanged.
5364 **
5365 ** The check-out database ("localdb") stores RID values. When associating
5366 ** a check-out database against a repository database, it is useful to verify
5367 ** the fingerprint so that we know tha the RID values in the check-out
@@ -5423,11 +5422,11 @@
5422 ** COMMAND: test-fingerprint
5423 **
5424 ** Usage: %fossil test-fingerprint ?RCVID?
5425 **
5426 ** Display the repository fingerprint using the supplied RCVID or
5427 ** using the latest RCVID if none is given on the command line.
5428 ** Show both the legacy and the newer version of the fingerprint,
5429 ** and the currently stored fingerprint if there is one.
5430 */
5431 void test_fingerprint(void){
5432 int rcvid = 0;
5433
+52 -10
--- src/default.css
+++ src/default.css
@@ -762,10 +762,19 @@
762762
border-bottom: 3px solid gold;
763763
}
764764
body.tkt div.content ol.tkt-changes > li:target > ol {
765765
border-left: 1px solid gold;
766766
}
767
+body.cpage-info .file-change-line,
768
+body.cpage-vdiff .file-change-line {
769
+ margin-top: 16px;
770
+ margin-bottom: 16px;
771
+ margin-right: 1em /* keep it from nudging right up against the scrollbar-reveal zone */;
772
+ display: flex;
773
+ flex-direction: row;
774
+ justify-content: space-between;
775
+}
767776
768777
span.modpending {
769778
color: #b03800;
770779
font-style: italic;
771780
}
@@ -919,10 +928,17 @@
919928
padding: 1px;
920929
}
921930
div.forum_body p {
922931
margin-top: 0;
923932
}
933
+div.forum-editor-widget{
934
+ display: flex;
935
+ flex-direction: column;
936
+}
937
+div.forum-editor-widget > textarea {
938
+ max-width: initial;
939
+}
924940
td.form_label {
925941
vertical-align: top;
926942
text-align: right;
927943
}
928944
.debug {
@@ -982,10 +998,17 @@
982998
** in the thread view. */
983999
}
9841000
.forum div > form {
9851001
margin: 0.5em 0;
9861002
display: inline-block;
1003
+}
1004
+body.cpage-forumedit div > form,
1005
+body.cpage-forume2 div > form{
1006
+ width: 100%;
1007
+}
1008
+.forum div > form > * {
1009
+ margin-bottom: 0.35em;
9871010
}
9881011
.forum-post-collapser {
9891012
/* Common style for the bottom-of-post and right-of-post
9901013
expand/collapse widgets. */
9911014
font-size: 0.8em;
@@ -1681,22 +1704,45 @@
16811704
DOM structure:
16821705
<DIV.pikchr-wrapper>
16831706
<DIV.pikchr-svg>
16841707
<SVG.pikchr>...</SVG>
16851708
</DIV.pikchr-svg>
1686
- <PRE.pikchr-src>...</PRE>
1709
+ <DIV.pikchr-src>
1710
+ <PRE>pikchr source code</PRE>
1711
+ <SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
1712
+ <!-- ^^^ is unhidden and activated by JS code -->
1713
+ </DIV.pikchr-src>
16871714
</DIV.pikchr-wrapper>
16881715
16891716
************************************************************/
16901717
div.pikchr-wrapper {/*outer wrapper elem for a pikchr construct*/}
16911718
div.pikchr-svg {/*wrapper for SVG.pikchr element*/}
16921719
svg.pikchr {/*pikchr SVG*/
16931720
width: 100%/*necessary for SOME SVGs for Chrome!*/;
16941721
}
1695
-pre.pikchr-src {/*source code view for a pikchr (see fossil.pikchr.js)*/
1722
+
1723
+div.pikchr-src {
1724
+ /*Wrapper for source code view of a pikchr (see fossil.pikchr.js)*/
1725
+ display: flex;
1726
+ flex-direction: column;
1727
+}
1728
+div.pikchr-src > pre {
1729
+ /*Source code for a pikchr*/
16961730
box-sizing: border-box;
16971731
text-align: left;
1732
+}
1733
+div.pikchr-src > span {
1734
+ /*Wrapper for a link to open a pikchr in /pikchrshow*/
1735
+ margin-top: 0.5em;
1736
+ margin-bottom: 0.5em;
1737
+ font-size: 85%;
1738
+}
1739
+div.pikchr-src > span::before {
1740
+ content: "[";
1741
+}
1742
+div.pikchr-src > span::after {
1743
+ content: "]";
16981744
}
16991745
/* The .source-inline class tells the .source class that the
17001746
source view, when enabled, should be "inline" (same position
17011747
as the graphic), else the sources are shifted to the left as
17021748
if they were "plain text". */
@@ -1712,14 +1758,14 @@
17121758
still-seemingly-legitimate browsers don't support grid mode. */
17131759
}
17141760
div.pikchr-wrapper.center > div.pikchr-svg {
17151761
width: 100%/*necessary for Chrome!*/;
17161762
}
1717
-div.pikchr-wrapper.center:not(.source) > pre.pikchr-src,
1763
+div.pikchr-wrapper.center:not(.source) > div.pikchr-src,
17181764
div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
17191765
/* ^^^ Centered non-source-view elements */
1720
-div.pikchr-wrapper.center.source.source-inline > pre.pikchr-src,
1766
+div.pikchr-wrapper.center.source.source-inline div.pikchr-src,
17211767
div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
17221768
/* ^^^ Centered inline-source-view elements */{
17231769
display:inline-block/*allows parent text-align to do the alignment*/;
17241770
/* ^^^^ Browser incompatibility: inline-block causes the centered
17251771
pikchr to shrink to the point of illegiblity in Chrome. The
@@ -1743,14 +1789,14 @@
17431789
padding: 4em;
17441790
}
17451791
17461792
/* For pikchr-wrapper.source mode, toggle pre.pikchr-src and
17471793
svg.pikchr visibility... */
1748
-div.pikchr-wrapper.source > pre.pikchr-src {
1794
+div.pikchr-wrapper.source > div.pikchr-src {
17491795
/* Source code ^^^^^^^ is visible, else it is hidden */
17501796
}
1751
-div.pikchr-wrapper:not(.source) > pre.pikchr-src {
1797
+div.pikchr-wrapper:not(.source) > div.pikchr-src {
17521798
/* Hide sources when image is being shown. */
17531799
position: absolute !important;
17541800
opacity: 0 !important;
17551801
pointer-events: none !important;
17561802
display: none !important;
@@ -1795,14 +1841,10 @@
17951841
}
17961842
body.fossil-dark-style .settings-icon {
17971843
filter: invert(100%);
17981844
}
17991845
1800
-input[type="checkbox"].diff-toggle {
1801
- float: right;
1802
-}
1803
-
18041846
body.branch .brlist > table > tbody > tr:hover:not(.selected),
18051847
body.branch .brlist > table > tbody > tr.selected {
18061848
background-color: #ffc;
18071849
}
18081850
body.branch .brlist > table > tbody td:first-child > input {
18091851
--- src/default.css
+++ src/default.css
@@ -762,10 +762,19 @@
762 border-bottom: 3px solid gold;
763 }
764 body.tkt div.content ol.tkt-changes > li:target > ol {
765 border-left: 1px solid gold;
766 }
 
 
 
 
 
 
 
 
 
767
768 span.modpending {
769 color: #b03800;
770 font-style: italic;
771 }
@@ -919,10 +928,17 @@
919 padding: 1px;
920 }
921 div.forum_body p {
922 margin-top: 0;
923 }
 
 
 
 
 
 
 
924 td.form_label {
925 vertical-align: top;
926 text-align: right;
927 }
928 .debug {
@@ -982,10 +998,17 @@
982 ** in the thread view. */
983 }
984 .forum div > form {
985 margin: 0.5em 0;
986 display: inline-block;
 
 
 
 
 
 
 
987 }
988 .forum-post-collapser {
989 /* Common style for the bottom-of-post and right-of-post
990 expand/collapse widgets. */
991 font-size: 0.8em;
@@ -1681,22 +1704,45 @@
1681 DOM structure:
1682 <DIV.pikchr-wrapper>
1683 <DIV.pikchr-svg>
1684 <SVG.pikchr>...</SVG>
1685 </DIV.pikchr-svg>
1686 <PRE.pikchr-src>...</PRE>
 
 
 
 
1687 </DIV.pikchr-wrapper>
1688
1689 ************************************************************/
1690 div.pikchr-wrapper {/*outer wrapper elem for a pikchr construct*/}
1691 div.pikchr-svg {/*wrapper for SVG.pikchr element*/}
1692 svg.pikchr {/*pikchr SVG*/
1693 width: 100%/*necessary for SOME SVGs for Chrome!*/;
1694 }
1695 pre.pikchr-src {/*source code view for a pikchr (see fossil.pikchr.js)*/
 
 
 
 
 
 
 
1696 box-sizing: border-box;
1697 text-align: left;
 
 
 
 
 
 
 
 
 
 
 
 
1698 }
1699 /* The .source-inline class tells the .source class that the
1700 source view, when enabled, should be "inline" (same position
1701 as the graphic), else the sources are shifted to the left as
1702 if they were "plain text". */
@@ -1712,14 +1758,14 @@
1712 still-seemingly-legitimate browsers don't support grid mode. */
1713 }
1714 div.pikchr-wrapper.center > div.pikchr-svg {
1715 width: 100%/*necessary for Chrome!*/;
1716 }
1717 div.pikchr-wrapper.center:not(.source) > pre.pikchr-src,
1718 div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
1719 /* ^^^ Centered non-source-view elements */
1720 div.pikchr-wrapper.center.source.source-inline > pre.pikchr-src,
1721 div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
1722 /* ^^^ Centered inline-source-view elements */{
1723 display:inline-block/*allows parent text-align to do the alignment*/;
1724 /* ^^^^ Browser incompatibility: inline-block causes the centered
1725 pikchr to shrink to the point of illegiblity in Chrome. The
@@ -1743,14 +1789,14 @@
1743 padding: 4em;
1744 }
1745
1746 /* For pikchr-wrapper.source mode, toggle pre.pikchr-src and
1747 svg.pikchr visibility... */
1748 div.pikchr-wrapper.source > pre.pikchr-src {
1749 /* Source code ^^^^^^^ is visible, else it is hidden */
1750 }
1751 div.pikchr-wrapper:not(.source) > pre.pikchr-src {
1752 /* Hide sources when image is being shown. */
1753 position: absolute !important;
1754 opacity: 0 !important;
1755 pointer-events: none !important;
1756 display: none !important;
@@ -1795,14 +1841,10 @@
1795 }
1796 body.fossil-dark-style .settings-icon {
1797 filter: invert(100%);
1798 }
1799
1800 input[type="checkbox"].diff-toggle {
1801 float: right;
1802 }
1803
1804 body.branch .brlist > table > tbody > tr:hover:not(.selected),
1805 body.branch .brlist > table > tbody > tr.selected {
1806 background-color: #ffc;
1807 }
1808 body.branch .brlist > table > tbody td:first-child > input {
1809
--- src/default.css
+++ src/default.css
@@ -762,10 +762,19 @@
762 border-bottom: 3px solid gold;
763 }
764 body.tkt div.content ol.tkt-changes > li:target > ol {
765 border-left: 1px solid gold;
766 }
767 body.cpage-info .file-change-line,
768 body.cpage-vdiff .file-change-line {
769 margin-top: 16px;
770 margin-bottom: 16px;
771 margin-right: 1em /* keep it from nudging right up against the scrollbar-reveal zone */;
772 display: flex;
773 flex-direction: row;
774 justify-content: space-between;
775 }
776
777 span.modpending {
778 color: #b03800;
779 font-style: italic;
780 }
@@ -919,10 +928,17 @@
928 padding: 1px;
929 }
930 div.forum_body p {
931 margin-top: 0;
932 }
933 div.forum-editor-widget{
934 display: flex;
935 flex-direction: column;
936 }
937 div.forum-editor-widget > textarea {
938 max-width: initial;
939 }
940 td.form_label {
941 vertical-align: top;
942 text-align: right;
943 }
944 .debug {
@@ -982,10 +998,17 @@
998 ** in the thread view. */
999 }
1000 .forum div > form {
1001 margin: 0.5em 0;
1002 display: inline-block;
1003 }
1004 body.cpage-forumedit div > form,
1005 body.cpage-forume2 div > form{
1006 width: 100%;
1007 }
1008 .forum div > form > * {
1009 margin-bottom: 0.35em;
1010 }
1011 .forum-post-collapser {
1012 /* Common style for the bottom-of-post and right-of-post
1013 expand/collapse widgets. */
1014 font-size: 0.8em;
@@ -1681,22 +1704,45 @@
1704 DOM structure:
1705 <DIV.pikchr-wrapper>
1706 <DIV.pikchr-svg>
1707 <SVG.pikchr>...</SVG>
1708 </DIV.pikchr-svg>
1709 <DIV.pikchr-src>
1710 <PRE>pikchr source code</PRE>
1711 <SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
1712 <!-- ^^^ is unhidden and activated by JS code -->
1713 </DIV.pikchr-src>
1714 </DIV.pikchr-wrapper>
1715
1716 ************************************************************/
1717 div.pikchr-wrapper {/*outer wrapper elem for a pikchr construct*/}
1718 div.pikchr-svg {/*wrapper for SVG.pikchr element*/}
1719 svg.pikchr {/*pikchr SVG*/
1720 width: 100%/*necessary for SOME SVGs for Chrome!*/;
1721 }
1722
1723 div.pikchr-src {
1724 /*Wrapper for source code view of a pikchr (see fossil.pikchr.js)*/
1725 display: flex;
1726 flex-direction: column;
1727 }
1728 div.pikchr-src > pre {
1729 /*Source code for a pikchr*/
1730 box-sizing: border-box;
1731 text-align: left;
1732 }
1733 div.pikchr-src > span {
1734 /*Wrapper for a link to open a pikchr in /pikchrshow*/
1735 margin-top: 0.5em;
1736 margin-bottom: 0.5em;
1737 font-size: 85%;
1738 }
1739 div.pikchr-src > span::before {
1740 content: "[";
1741 }
1742 div.pikchr-src > span::after {
1743 content: "]";
1744 }
1745 /* The .source-inline class tells the .source class that the
1746 source view, when enabled, should be "inline" (same position
1747 as the graphic), else the sources are shifted to the left as
1748 if they were "plain text". */
@@ -1712,14 +1758,14 @@
1758 still-seemingly-legitimate browsers don't support grid mode. */
1759 }
1760 div.pikchr-wrapper.center > div.pikchr-svg {
1761 width: 100%/*necessary for Chrome!*/;
1762 }
1763 div.pikchr-wrapper.center:not(.source) > div.pikchr-src,
1764 div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
1765 /* ^^^ Centered non-source-view elements */
1766 div.pikchr-wrapper.center.source.source-inline div.pikchr-src,
1767 div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
1768 /* ^^^ Centered inline-source-view elements */{
1769 display:inline-block/*allows parent text-align to do the alignment*/;
1770 /* ^^^^ Browser incompatibility: inline-block causes the centered
1771 pikchr to shrink to the point of illegiblity in Chrome. The
@@ -1743,14 +1789,14 @@
1789 padding: 4em;
1790 }
1791
1792 /* For pikchr-wrapper.source mode, toggle pre.pikchr-src and
1793 svg.pikchr visibility... */
1794 div.pikchr-wrapper.source > div.pikchr-src {
1795 /* Source code ^^^^^^^ is visible, else it is hidden */
1796 }
1797 div.pikchr-wrapper:not(.source) > div.pikchr-src {
1798 /* Hide sources when image is being shown. */
1799 position: absolute !important;
1800 opacity: 0 !important;
1801 pointer-events: none !important;
1802 display: none !important;
@@ -1795,14 +1841,10 @@
1841 }
1842 body.fossil-dark-style .settings-icon {
1843 filter: invert(100%);
1844 }
1845
 
 
 
 
1846 body.branch .brlist > table > tbody > tr:hover:not(.selected),
1847 body.branch .brlist > table > tbody > tr.selected {
1848 background-color: #ffc;
1849 }
1850 body.branch .brlist > table > tbody td:first-child > input {
1851
+52 -10
--- src/default.css
+++ src/default.css
@@ -762,10 +762,19 @@
762762
border-bottom: 3px solid gold;
763763
}
764764
body.tkt div.content ol.tkt-changes > li:target > ol {
765765
border-left: 1px solid gold;
766766
}
767
+body.cpage-info .file-change-line,
768
+body.cpage-vdiff .file-change-line {
769
+ margin-top: 16px;
770
+ margin-bottom: 16px;
771
+ margin-right: 1em /* keep it from nudging right up against the scrollbar-reveal zone */;
772
+ display: flex;
773
+ flex-direction: row;
774
+ justify-content: space-between;
775
+}
767776
768777
span.modpending {
769778
color: #b03800;
770779
font-style: italic;
771780
}
@@ -919,10 +928,17 @@
919928
padding: 1px;
920929
}
921930
div.forum_body p {
922931
margin-top: 0;
923932
}
933
+div.forum-editor-widget{
934
+ display: flex;
935
+ flex-direction: column;
936
+}
937
+div.forum-editor-widget > textarea {
938
+ max-width: initial;
939
+}
924940
td.form_label {
925941
vertical-align: top;
926942
text-align: right;
927943
}
928944
.debug {
@@ -982,10 +998,17 @@
982998
** in the thread view. */
983999
}
9841000
.forum div > form {
9851001
margin: 0.5em 0;
9861002
display: inline-block;
1003
+}
1004
+body.cpage-forumedit div > form,
1005
+body.cpage-forume2 div > form{
1006
+ width: 100%;
1007
+}
1008
+.forum div > form > * {
1009
+ margin-bottom: 0.35em;
9871010
}
9881011
.forum-post-collapser {
9891012
/* Common style for the bottom-of-post and right-of-post
9901013
expand/collapse widgets. */
9911014
font-size: 0.8em;
@@ -1681,22 +1704,45 @@
16811704
DOM structure:
16821705
<DIV.pikchr-wrapper>
16831706
<DIV.pikchr-svg>
16841707
<SVG.pikchr>...</SVG>
16851708
</DIV.pikchr-svg>
1686
- <PRE.pikchr-src>...</PRE>
1709
+ <DIV.pikchr-src>
1710
+ <PRE>pikchr source code</PRE>
1711
+ <SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
1712
+ <!-- ^^^ is unhidden and activated by JS code -->
1713
+ </DIV.pikchr-src>
16871714
</DIV.pikchr-wrapper>
16881715
16891716
************************************************************/
16901717
div.pikchr-wrapper {/*outer wrapper elem for a pikchr construct*/}
16911718
div.pikchr-svg {/*wrapper for SVG.pikchr element*/}
16921719
svg.pikchr {/*pikchr SVG*/
16931720
width: 100%/*necessary for SOME SVGs for Chrome!*/;
16941721
}
1695
-pre.pikchr-src {/*source code view for a pikchr (see fossil.pikchr.js)*/
1722
+
1723
+div.pikchr-src {
1724
+ /*Wrapper for source code view of a pikchr (see fossil.pikchr.js)*/
1725
+ display: flex;
1726
+ flex-direction: column;
1727
+}
1728
+div.pikchr-src > pre {
1729
+ /*Source code for a pikchr*/
16961730
box-sizing: border-box;
16971731
text-align: left;
1732
+}
1733
+div.pikchr-src > span {
1734
+ /*Wrapper for a link to open a pikchr in /pikchrshow*/
1735
+ margin-top: 0.5em;
1736
+ margin-bottom: 0.5em;
1737
+ font-size: 85%;
1738
+}
1739
+div.pikchr-src > span::before {
1740
+ content: "[";
1741
+}
1742
+div.pikchr-src > span::after {
1743
+ content: "]";
16981744
}
16991745
/* The .source-inline class tells the .source class that the
17001746
source view, when enabled, should be "inline" (same position
17011747
as the graphic), else the sources are shifted to the left as
17021748
if they were "plain text". */
@@ -1712,14 +1758,14 @@
17121758
still-seemingly-legitimate browsers don't support grid mode. */
17131759
}
17141760
div.pikchr-wrapper.center > div.pikchr-svg {
17151761
width: 100%/*necessary for Chrome!*/;
17161762
}
1717
-div.pikchr-wrapper.center:not(.source) > pre.pikchr-src,
1763
+div.pikchr-wrapper.center:not(.source) > div.pikchr-src,
17181764
div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
17191765
/* ^^^ Centered non-source-view elements */
1720
-div.pikchr-wrapper.center.source.source-inline > pre.pikchr-src,
1766
+div.pikchr-wrapper.center.source.source-inline div.pikchr-src,
17211767
div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
17221768
/* ^^^ Centered inline-source-view elements */{
17231769
display:inline-block/*allows parent text-align to do the alignment*/;
17241770
/* ^^^^ Browser incompatibility: inline-block causes the centered
17251771
pikchr to shrink to the point of illegiblity in Chrome. The
@@ -1743,14 +1789,14 @@
17431789
padding: 4em;
17441790
}
17451791
17461792
/* For pikchr-wrapper.source mode, toggle pre.pikchr-src and
17471793
svg.pikchr visibility... */
1748
-div.pikchr-wrapper.source > pre.pikchr-src {
1794
+div.pikchr-wrapper.source > div.pikchr-src {
17491795
/* Source code ^^^^^^^ is visible, else it is hidden */
17501796
}
1751
-div.pikchr-wrapper:not(.source) > pre.pikchr-src {
1797
+div.pikchr-wrapper:not(.source) > div.pikchr-src {
17521798
/* Hide sources when image is being shown. */
17531799
position: absolute !important;
17541800
opacity: 0 !important;
17551801
pointer-events: none !important;
17561802
display: none !important;
@@ -1795,14 +1841,10 @@
17951841
}
17961842
body.fossil-dark-style .settings-icon {
17971843
filter: invert(100%);
17981844
}
17991845
1800
-input[type="checkbox"].diff-toggle {
1801
- float: right;
1802
-}
1803
-
18041846
body.branch .brlist > table > tbody > tr:hover:not(.selected),
18051847
body.branch .brlist > table > tbody > tr.selected {
18061848
background-color: #ffc;
18071849
}
18081850
body.branch .brlist > table > tbody td:first-child > input {
18091851
--- src/default.css
+++ src/default.css
@@ -762,10 +762,19 @@
762 border-bottom: 3px solid gold;
763 }
764 body.tkt div.content ol.tkt-changes > li:target > ol {
765 border-left: 1px solid gold;
766 }
 
 
 
 
 
 
 
 
 
767
768 span.modpending {
769 color: #b03800;
770 font-style: italic;
771 }
@@ -919,10 +928,17 @@
919 padding: 1px;
920 }
921 div.forum_body p {
922 margin-top: 0;
923 }
 
 
 
 
 
 
 
924 td.form_label {
925 vertical-align: top;
926 text-align: right;
927 }
928 .debug {
@@ -982,10 +998,17 @@
982 ** in the thread view. */
983 }
984 .forum div > form {
985 margin: 0.5em 0;
986 display: inline-block;
 
 
 
 
 
 
 
987 }
988 .forum-post-collapser {
989 /* Common style for the bottom-of-post and right-of-post
990 expand/collapse widgets. */
991 font-size: 0.8em;
@@ -1681,22 +1704,45 @@
1681 DOM structure:
1682 <DIV.pikchr-wrapper>
1683 <DIV.pikchr-svg>
1684 <SVG.pikchr>...</SVG>
1685 </DIV.pikchr-svg>
1686 <PRE.pikchr-src>...</PRE>
 
 
 
 
1687 </DIV.pikchr-wrapper>
1688
1689 ************************************************************/
1690 div.pikchr-wrapper {/*outer wrapper elem for a pikchr construct*/}
1691 div.pikchr-svg {/*wrapper for SVG.pikchr element*/}
1692 svg.pikchr {/*pikchr SVG*/
1693 width: 100%/*necessary for SOME SVGs for Chrome!*/;
1694 }
1695 pre.pikchr-src {/*source code view for a pikchr (see fossil.pikchr.js)*/
 
 
 
 
 
 
 
1696 box-sizing: border-box;
1697 text-align: left;
 
 
 
 
 
 
 
 
 
 
 
 
1698 }
1699 /* The .source-inline class tells the .source class that the
1700 source view, when enabled, should be "inline" (same position
1701 as the graphic), else the sources are shifted to the left as
1702 if they were "plain text". */
@@ -1712,14 +1758,14 @@
1712 still-seemingly-legitimate browsers don't support grid mode. */
1713 }
1714 div.pikchr-wrapper.center > div.pikchr-svg {
1715 width: 100%/*necessary for Chrome!*/;
1716 }
1717 div.pikchr-wrapper.center:not(.source) > pre.pikchr-src,
1718 div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
1719 /* ^^^ Centered non-source-view elements */
1720 div.pikchr-wrapper.center.source.source-inline > pre.pikchr-src,
1721 div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
1722 /* ^^^ Centered inline-source-view elements */{
1723 display:inline-block/*allows parent text-align to do the alignment*/;
1724 /* ^^^^ Browser incompatibility: inline-block causes the centered
1725 pikchr to shrink to the point of illegiblity in Chrome. The
@@ -1743,14 +1789,14 @@
1743 padding: 4em;
1744 }
1745
1746 /* For pikchr-wrapper.source mode, toggle pre.pikchr-src and
1747 svg.pikchr visibility... */
1748 div.pikchr-wrapper.source > pre.pikchr-src {
1749 /* Source code ^^^^^^^ is visible, else it is hidden */
1750 }
1751 div.pikchr-wrapper:not(.source) > pre.pikchr-src {
1752 /* Hide sources when image is being shown. */
1753 position: absolute !important;
1754 opacity: 0 !important;
1755 pointer-events: none !important;
1756 display: none !important;
@@ -1795,14 +1841,10 @@
1795 }
1796 body.fossil-dark-style .settings-icon {
1797 filter: invert(100%);
1798 }
1799
1800 input[type="checkbox"].diff-toggle {
1801 float: right;
1802 }
1803
1804 body.branch .brlist > table > tbody > tr:hover:not(.selected),
1805 body.branch .brlist > table > tbody > tr.selected {
1806 background-color: #ffc;
1807 }
1808 body.branch .brlist > table > tbody td:first-child > input {
1809
--- src/default.css
+++ src/default.css
@@ -762,10 +762,19 @@
762 border-bottom: 3px solid gold;
763 }
764 body.tkt div.content ol.tkt-changes > li:target > ol {
765 border-left: 1px solid gold;
766 }
767 body.cpage-info .file-change-line,
768 body.cpage-vdiff .file-change-line {
769 margin-top: 16px;
770 margin-bottom: 16px;
771 margin-right: 1em /* keep it from nudging right up against the scrollbar-reveal zone */;
772 display: flex;
773 flex-direction: row;
774 justify-content: space-between;
775 }
776
777 span.modpending {
778 color: #b03800;
779 font-style: italic;
780 }
@@ -919,10 +928,17 @@
928 padding: 1px;
929 }
930 div.forum_body p {
931 margin-top: 0;
932 }
933 div.forum-editor-widget{
934 display: flex;
935 flex-direction: column;
936 }
937 div.forum-editor-widget > textarea {
938 max-width: initial;
939 }
940 td.form_label {
941 vertical-align: top;
942 text-align: right;
943 }
944 .debug {
@@ -982,10 +998,17 @@
998 ** in the thread view. */
999 }
1000 .forum div > form {
1001 margin: 0.5em 0;
1002 display: inline-block;
1003 }
1004 body.cpage-forumedit div > form,
1005 body.cpage-forume2 div > form{
1006 width: 100%;
1007 }
1008 .forum div > form > * {
1009 margin-bottom: 0.35em;
1010 }
1011 .forum-post-collapser {
1012 /* Common style for the bottom-of-post and right-of-post
1013 expand/collapse widgets. */
1014 font-size: 0.8em;
@@ -1681,22 +1704,45 @@
1704 DOM structure:
1705 <DIV.pikchr-wrapper>
1706 <DIV.pikchr-svg>
1707 <SVG.pikchr>...</SVG>
1708 </DIV.pikchr-svg>
1709 <DIV.pikchr-src>
1710 <PRE>pikchr source code</PRE>
1711 <SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
1712 <!-- ^^^ is unhidden and activated by JS code -->
1713 </DIV.pikchr-src>
1714 </DIV.pikchr-wrapper>
1715
1716 ************************************************************/
1717 div.pikchr-wrapper {/*outer wrapper elem for a pikchr construct*/}
1718 div.pikchr-svg {/*wrapper for SVG.pikchr element*/}
1719 svg.pikchr {/*pikchr SVG*/
1720 width: 100%/*necessary for SOME SVGs for Chrome!*/;
1721 }
1722
1723 div.pikchr-src {
1724 /*Wrapper for source code view of a pikchr (see fossil.pikchr.js)*/
1725 display: flex;
1726 flex-direction: column;
1727 }
1728 div.pikchr-src > pre {
1729 /*Source code for a pikchr*/
1730 box-sizing: border-box;
1731 text-align: left;
1732 }
1733 div.pikchr-src > span {
1734 /*Wrapper for a link to open a pikchr in /pikchrshow*/
1735 margin-top: 0.5em;
1736 margin-bottom: 0.5em;
1737 font-size: 85%;
1738 }
1739 div.pikchr-src > span::before {
1740 content: "[";
1741 }
1742 div.pikchr-src > span::after {
1743 content: "]";
1744 }
1745 /* The .source-inline class tells the .source class that the
1746 source view, when enabled, should be "inline" (same position
1747 as the graphic), else the sources are shifted to the left as
1748 if they were "plain text". */
@@ -1712,14 +1758,14 @@
1758 still-seemingly-legitimate browsers don't support grid mode. */
1759 }
1760 div.pikchr-wrapper.center > div.pikchr-svg {
1761 width: 100%/*necessary for Chrome!*/;
1762 }
1763 div.pikchr-wrapper.center:not(.source) > div.pikchr-src,
1764 div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
1765 /* ^^^ Centered non-source-view elements */
1766 div.pikchr-wrapper.center.source.source-inline div.pikchr-src,
1767 div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
1768 /* ^^^ Centered inline-source-view elements */{
1769 display:inline-block/*allows parent text-align to do the alignment*/;
1770 /* ^^^^ Browser incompatibility: inline-block causes the centered
1771 pikchr to shrink to the point of illegiblity in Chrome. The
@@ -1743,14 +1789,14 @@
1789 padding: 4em;
1790 }
1791
1792 /* For pikchr-wrapper.source mode, toggle pre.pikchr-src and
1793 svg.pikchr visibility... */
1794 div.pikchr-wrapper.source > div.pikchr-src {
1795 /* Source code ^^^^^^^ is visible, else it is hidden */
1796 }
1797 div.pikchr-wrapper:not(.source) > div.pikchr-src {
1798 /* Hide sources when image is being shown. */
1799 position: absolute !important;
1800 opacity: 0 !important;
1801 pointer-events: none !important;
1802 display: none !important;
@@ -1795,14 +1841,10 @@
1841 }
1842 body.fossil-dark-style .settings-icon {
1843 filter: invert(100%);
1844 }
1845
 
 
 
 
1846 body.branch .brlist > table > tbody > tr:hover:not(.selected),
1847 body.branch .brlist > table > tbody > tr.selected {
1848 background-color: #ffc;
1849 }
1850 body.branch .brlist > table > tbody td:first-child > input {
1851
+50 -48
--- src/delta.c
+++ src/delta.c
@@ -225,59 +225,61 @@
225225
** of four bytes.
226226
*/
227227
static unsigned int checksum(const char *zIn, size_t N){
228228
static const int byteOrderTest = 1;
229229
const unsigned char *z = (const unsigned char *)zIn;
230
- const unsigned char *zEnd = (const unsigned char*)&zIn[N&~3];
231230
unsigned sum = 0;
232
- assert( (z - (const unsigned char*)0)%4==0 ); /* Four-byte alignment */
233
- if( 0==*(char*)&byteOrderTest ){
234
- /* This is a big-endian machine */
235
- while( z<zEnd ){
236
- sum += *(unsigned*)z;
237
- z += 4;
238
- }
239
- }else{
240
- /* A little-endian machine */
241
-#if GCC_VERSION>=4003000
242
- while( z<zEnd ){
243
- sum += __builtin_bswap32(*(unsigned*)z);
244
- z += 4;
245
- }
246
-#elif defined(_MSC_VER) && _MSC_VER>=1300
247
- while( z<zEnd ){
248
- sum += _byteswap_ulong(*(unsigned*)z);
249
- z += 4;
250
- }
251
-#else
252
- unsigned sum0 = 0;
253
- unsigned sum1 = 0;
254
- unsigned sum2 = 0;
255
- while(N >= 16){
256
- sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
257
- sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
258
- sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
259
- sum += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
260
- z += 16;
261
- N -= 16;
262
- }
263
- while(N >= 4){
264
- sum0 += z[0];
265
- sum1 += z[1];
266
- sum2 += z[2];
267
- sum += z[3];
268
- z += 4;
269
- N -= 4;
270
- }
271
- sum += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
272
-#endif
273
- }
274
- switch(N&3){
275
- case 3: sum += (z[2] << 8);
276
- case 2: sum += (z[1] << 16);
277
- case 1: sum += (z[0] << 24);
278
- default: ;
231
+ if( N>0 ){
232
+ const unsigned char *zEnd = (const unsigned char*)&zIn[N&~3];
233
+ assert( (z - (const unsigned char*)0)%4==0 ); /* Four-byte alignment */
234
+ if( 0==*(char*)&byteOrderTest ){
235
+ /* This is a big-endian machine */
236
+ while( z<zEnd ){
237
+ sum += *(unsigned*)z;
238
+ z += 4;
239
+ }
240
+ }else{
241
+ /* A little-endian machine */
242
+ #if GCC_VERSION>=4003000
243
+ while( z<zEnd ){
244
+ sum += __builtin_bswap32(*(unsigned*)z);
245
+ z += 4;
246
+ }
247
+ #elif defined(_MSC_VER) && _MSC_VER>=1300
248
+ while( z<zEnd ){
249
+ sum += _byteswap_ulong(*(unsigned*)z);
250
+ z += 4;
251
+ }
252
+ #else
253
+ unsigned sum0 = 0;
254
+ unsigned sum1 = 0;
255
+ unsigned sum2 = 0;
256
+ while(N >= 16){
257
+ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
258
+ sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
259
+ sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
260
+ sum += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
261
+ z += 16;
262
+ N -= 16;
263
+ }
264
+ while(N >= 4){
265
+ sum0 += z[0];
266
+ sum1 += z[1];
267
+ sum2 += z[2];
268
+ sum += z[3];
269
+ z += 4;
270
+ N -= 4;
271
+ }
272
+ sum += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
273
+ #endif
274
+ }
275
+ switch(N&3){
276
+ case 3: sum += (z[2] << 8);
277
+ case 2: sum += (z[1] << 16);
278
+ case 1: sum += (z[0] << 24);
279
+ default: ;
280
+ }
279281
}
280282
return sum;
281283
}
282284
283285
/*
284286
--- src/delta.c
+++ src/delta.c
@@ -225,59 +225,61 @@
225 ** of four bytes.
226 */
227 static unsigned int checksum(const char *zIn, size_t N){
228 static const int byteOrderTest = 1;
229 const unsigned char *z = (const unsigned char *)zIn;
230 const unsigned char *zEnd = (const unsigned char*)&zIn[N&~3];
231 unsigned sum = 0;
232 assert( (z - (const unsigned char*)0)%4==0 ); /* Four-byte alignment */
233 if( 0==*(char*)&byteOrderTest ){
234 /* This is a big-endian machine */
235 while( z<zEnd ){
236 sum += *(unsigned*)z;
237 z += 4;
238 }
239 }else{
240 /* A little-endian machine */
241 #if GCC_VERSION>=4003000
242 while( z<zEnd ){
243 sum += __builtin_bswap32(*(unsigned*)z);
244 z += 4;
245 }
246 #elif defined(_MSC_VER) && _MSC_VER>=1300
247 while( z<zEnd ){
248 sum += _byteswap_ulong(*(unsigned*)z);
249 z += 4;
250 }
251 #else
252 unsigned sum0 = 0;
253 unsigned sum1 = 0;
254 unsigned sum2 = 0;
255 while(N >= 16){
256 sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
257 sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
258 sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
259 sum += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
260 z += 16;
261 N -= 16;
262 }
263 while(N >= 4){
264 sum0 += z[0];
265 sum1 += z[1];
266 sum2 += z[2];
267 sum += z[3];
268 z += 4;
269 N -= 4;
270 }
271 sum += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
272 #endif
273 }
274 switch(N&3){
275 case 3: sum += (z[2] << 8);
276 case 2: sum += (z[1] << 16);
277 case 1: sum += (z[0] << 24);
278 default: ;
 
 
 
279 }
280 return sum;
281 }
282
283 /*
284
--- src/delta.c
+++ src/delta.c
@@ -225,59 +225,61 @@
225 ** of four bytes.
226 */
227 static unsigned int checksum(const char *zIn, size_t N){
228 static const int byteOrderTest = 1;
229 const unsigned char *z = (const unsigned char *)zIn;
 
230 unsigned sum = 0;
231 if( N>0 ){
232 const unsigned char *zEnd = (const unsigned char*)&zIn[N&~3];
233 assert( (z - (const unsigned char*)0)%4==0 ); /* Four-byte alignment */
234 if( 0==*(char*)&byteOrderTest ){
235 /* This is a big-endian machine */
236 while( z<zEnd ){
237 sum += *(unsigned*)z;
238 z += 4;
239 }
240 }else{
241 /* A little-endian machine */
242 #if GCC_VERSION>=4003000
243 while( z<zEnd ){
244 sum += __builtin_bswap32(*(unsigned*)z);
245 z += 4;
246 }
247 #elif defined(_MSC_VER) && _MSC_VER>=1300
248 while( z<zEnd ){
249 sum += _byteswap_ulong(*(unsigned*)z);
250 z += 4;
251 }
252 #else
253 unsigned sum0 = 0;
254 unsigned sum1 = 0;
255 unsigned sum2 = 0;
256 while(N >= 16){
257 sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
258 sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
259 sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
260 sum += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
261 z += 16;
262 N -= 16;
263 }
264 while(N >= 4){
265 sum0 += z[0];
266 sum1 += z[1];
267 sum2 += z[2];
268 sum += z[3];
269 z += 4;
270 N -= 4;
271 }
272 sum += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
273 #endif
274 }
275 switch(N&3){
276 case 3: sum += (z[2] << 8);
277 case 2: sum += (z[1] << 16);
278 case 1: sum += (z[0] << 24);
279 default: ;
280 }
281 }
282 return sum;
283 }
284
285 /*
286
+146 -7
--- src/diff.c
+++ src/diff.c
@@ -50,10 +50,11 @@
5050
#define DIFF_RAW 0x00040000 /* Raw triples - for debugging */
5151
#define DIFF_TCL 0x00080000 /* For the --tk option */
5252
#define DIFF_INCBINARY 0x00100000 /* The --diff-binary option */
5353
#define DIFF_SHOW_VERS 0x00200000 /* Show compared versions */
5454
#define DIFF_DARKMODE 0x00400000 /* Use dark mode for HTML */
55
+#define DIFF_BY_TOKEN 0x01000000 /* Split on tokens, not lines */
5556
5657
/*
5758
** Per file information that may influence output.
5859
*/
5960
#define DIFF_FILE_ADDED 0x40000000 /* Added or rename destination */
@@ -319,10 +320,113 @@
319320
320321
/* Return results */
321322
*pnLine = nLine;
322323
return a;
323324
}
325
+
326
+/*
327
+** Character classes for the purpose of tokenization.
328
+**
329
+** 1 - alphanumeric
330
+** 2 - whitespace
331
+** 3 - punctuation
332
+*/
333
+static char aTCharClass[256] = {
334
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
335
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
336
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
337
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
338
+
339
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
340
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
341
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
342
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
343
+
344
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
345
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
346
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
347
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
348
+
349
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
350
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
351
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
352
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
353
+};
354
+
355
+/*
356
+** Count the number of tokens in the given string.
357
+*/
358
+static int count_tokens(const unsigned char *p, int n){
359
+ int nToken = 0;
360
+ int iPrev = 0;
361
+ int i;
362
+ for(i=0; i<n; i++){
363
+ char x = aTCharClass[p[i]];
364
+ if( x!=iPrev ){
365
+ iPrev = x;
366
+ nToken++;
367
+ }
368
+ }
369
+ return nToken;
370
+}
371
+
372
+/*
373
+** Return an array of DLine objects containing a pointer to the
374
+** start of each token and a hash of that token. The lower
375
+** bits of the hash store the length of each token.
376
+**
377
+** This is like break_into_lines() except that it works with tokens
378
+** instead of lines. A token is:
379
+**
380
+** * A contiguous sequence of alphanumeric characters.
381
+** * A contiguous sequence of whitespace
382
+** * A contiguous sequence of punctuation characters.
383
+**
384
+** Return 0 if the file is binary or contains a line that is
385
+** too long.
386
+*/
387
+static DLine *break_into_tokens(
388
+ const char *z,
389
+ int n,
390
+ int *pnToken,
391
+ u64 diffFlags
392
+){
393
+ int nToken, i, k;
394
+ u64 h, h2;
395
+ DLine *a;
396
+ unsigned char *p = (unsigned char*)z;
397
+
398
+ nToken = count_tokens(p, n);
399
+ a = fossil_malloc( sizeof(a[0])*(nToken+1) );
400
+ memset(a, 0, sizeof(a[0])*(nToken+1));
401
+ if( n==0 ){
402
+ *pnToken = 0;
403
+ return a;
404
+ }
405
+ i = 0;
406
+ while( n>0 ){
407
+ char x = aTCharClass[*p];
408
+ h = 0xcbf29ce484222325LL;
409
+ for(k=1; k<n && aTCharClass[p[k]]==x; k++){
410
+ h ^= p[k];
411
+ h *= 0x100000001b3LL;
412
+ }
413
+ a[i].z = (char*)p;
414
+ a[i].n = k;
415
+ a[i].h = h = ((h%281474976710597LL)<<LENGTH_MASK_SZ) | k;
416
+ h2 = h % nToken;
417
+ a[i].iNext = a[h2].iHash;
418
+ a[h2].iHash = i+1;
419
+ p += k; n -= k;
420
+ i++;
421
+ };
422
+ assert( i==nToken );
423
+
424
+ /* Return results */
425
+ *pnToken = nToken;
426
+ return a;
427
+}
324428
325429
/*
326430
** Return zero if two DLine elements are identical.
327431
*/
328432
static int compare_dline(const DLine *pA, const DLine *pB){
@@ -2462,11 +2566,11 @@
24622566
int span; /* combined width of the input sequences */
24632567
int cutoff = 4; /* Max hash chain entries to follow */
24642568
int nextCutoff = -1; /* Value of cutoff for next iteration */
24652569
24662570
span = (iE1 - iS1) + (iE2 - iS2);
2467
- bestScore = -10000;
2571
+ bestScore = -9223300000*(sqlite3_int64)1000000000;
24682572
score = 0;
24692573
iSXb = iSXp = iS1;
24702574
iEXb = iEXp = iS1;
24712575
iSYb = iSYp = iS2;
24722576
iEYb = iEYp = iS2;
@@ -2997,14 +3101,21 @@
29973101
if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
29983102
c.xDiffer = compare_dline_ignore_allws;
29993103
}else{
30003104
c.xDiffer = compare_dline;
30013105
}
3002
- c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
3003
- &c.nFrom, pCfg->diffFlags);
3004
- c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
3005
- &c.nTo, pCfg->diffFlags);
3106
+ if( pCfg->diffFlags & DIFF_BY_TOKEN ){
3107
+ c.aFrom = break_into_tokens(blob_str(pA_Blob), blob_size(pA_Blob),
3108
+ &c.nFrom, pCfg->diffFlags);
3109
+ c.aTo = break_into_tokens(blob_str(pB_Blob), blob_size(pB_Blob),
3110
+ &c.nTo, pCfg->diffFlags);
3111
+ }else{
3112
+ c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
3113
+ &c.nFrom, pCfg->diffFlags);
3114
+ c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
3115
+ &c.nTo, pCfg->diffFlags);
3116
+ }
30063117
if( c.aFrom==0 || c.aTo==0 ){
30073118
fossil_free(c.aFrom);
30083119
fossil_free(c.aTo);
30093120
if( pOut ){
30103121
diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags);
@@ -3035,10 +3146,26 @@
30353146
}
30363147
}
30373148
if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){
30383149
diff_optimize(&c);
30393150
}
3151
+ if( (pCfg->diffFlags & DIFF_BY_TOKEN)!=0 ){
3152
+ /* Convert token counts into byte counts. */
3153
+ int i;
3154
+ int iA = 0;
3155
+ int iB = 0;
3156
+ for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
3157
+ int k, sum;
3158
+ for(k=0, sum=0; k<c.aEdit[i]; k++) sum += c.aFrom[iA++].n;
3159
+ iB += c.aEdit[i];
3160
+ c.aEdit[i] = sum;
3161
+ for(k=0, sum=0; k<c.aEdit[i+1]; k++) sum += c.aFrom[iA++].n;
3162
+ c.aEdit[i+1] = sum;
3163
+ for(k=0, sum=0; k<c.aEdit[i+2]; k++) sum += c.aTo[iB++].n;
3164
+ c.aEdit[i+2] = sum;
3165
+ }
3166
+ }
30403167
30413168
if( pOut ){
30423169
if( pCfg->diffFlags & DIFF_NUMSTAT ){
30433170
int nDel = 0, nIns = 0, i;
30443171
for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
@@ -3049,11 +3176,11 @@
30493176
g.diffCnt[2] += nDel;
30503177
if( nIns+nDel ){
30513178
g.diffCnt[0]++;
30523179
blob_appendf(pOut, "%10d %10d", nIns, nDel);
30533180
}
3054
- }else if( pCfg->diffFlags & DIFF_RAW ){
3181
+ }else if( pCfg->diffFlags & (DIFF_RAW|DIFF_BY_TOKEN) ){
30553182
const int *R = c.aEdit;
30563183
unsigned int r;
30573184
for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
30583185
blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
30593186
R[r], R[r+1], R[r+2]);
@@ -3100,20 +3227,29 @@
31003227
** Initialize the DiffConfig object using command-line options.
31013228
**
31023229
** Process diff-related command-line options and return an appropriate
31033230
** "diffFlags" integer.
31043231
**
3232
+** -b|--browser Show the diff output in a web-browser
31053233
** --brief Show filenames only DIFF_BRIEF
3234
+** --by Shorthand for "--browser -y"
31063235
** -c|--context N N lines of context. nContext
3236
+** --dark Use dark mode for Tcl/Tk and HTML output
31073237
** --html Format for HTML DIFF_HTML
3238
+** -i|--internal Use built-in diff, not an external tool
31083239
** --invert Invert the diff DIFF_INVERT
3240
+** --json Output formatted as JSON
31093241
** -n|--linenum Show line numbers DIFF_LINENO
3242
+** -N|--new-file Alias for --verbose
31103243
** --noopt Disable optimization DIFF_NOOPT
31113244
** --numstat Show change counts DIFF_NUMSTAT
31123245
** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
3246
+** --tcl Tcl-formatted output used internally by --tk
31133247
** --unified Unified diff. ~DIFF_SIDEBYSIDE
3248
+** -v|--verbose Show complete text of added or deleted files
31143249
** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
3250
+** --webpage Format output as a stand-alone HTML webpage
31153251
** -W|--width N N character lines. wColumn
31163252
** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
31173253
** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
31183254
*/
31193255
void diff_options(DiffConfig *pCfg, int isGDiff, int bUnifiedTextOnly){
@@ -3157,10 +3293,13 @@
31573293
31583294
/* Undocumented and unsupported flags used for development
31593295
** debugging and analysis: */
31603296
if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
31613297
if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
3298
+ if( find_option("bytoken",0,0)!=0 ){
3299
+ diffFlags = DIFF_RAW|DIFF_BY_TOKEN;
3300
+ }
31623301
}
31633302
if( (z = find_option("context","c",1))!=0 ){
31643303
char *zEnd;
31653304
f = (int)strtol(z, &zEnd, 10);
31663305
if( zEnd[0]==0 && errno!=ERANGE ){
@@ -3771,11 +3910,11 @@
37713910
int szHash; /* Display size of a version hash */
37723911
Blob treename; /* Name of file to be annotated */
37733912
char *zFilename; /* Name of file to be annotated */
37743913
37753914
bBlame = g.argv[1][0]!='a';
3776
- zRevision = find_option("r","revision",1);
3915
+ zRevision = find_option("revision","r",1);
37773916
zLimit = find_option("limit","n",1);
37783917
zOrig = find_option("origin","o",1);
37793918
showLog = find_option("log","l",0)!=0;
37803919
if( find_option("ignore-trailing-space","Z",0)!=0 ){
37813920
annFlags = DIFF_IGNORE_EOLWS;
37823921
--- src/diff.c
+++ src/diff.c
@@ -50,10 +50,11 @@
50 #define DIFF_RAW 0x00040000 /* Raw triples - for debugging */
51 #define DIFF_TCL 0x00080000 /* For the --tk option */
52 #define DIFF_INCBINARY 0x00100000 /* The --diff-binary option */
53 #define DIFF_SHOW_VERS 0x00200000 /* Show compared versions */
54 #define DIFF_DARKMODE 0x00400000 /* Use dark mode for HTML */
 
55
56 /*
57 ** Per file information that may influence output.
58 */
59 #define DIFF_FILE_ADDED 0x40000000 /* Added or rename destination */
@@ -319,10 +320,113 @@
319
320 /* Return results */
321 *pnLine = nLine;
322 return a;
323 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
325 /*
326 ** Return zero if two DLine elements are identical.
327 */
328 static int compare_dline(const DLine *pA, const DLine *pB){
@@ -2462,11 +2566,11 @@
2462 int span; /* combined width of the input sequences */
2463 int cutoff = 4; /* Max hash chain entries to follow */
2464 int nextCutoff = -1; /* Value of cutoff for next iteration */
2465
2466 span = (iE1 - iS1) + (iE2 - iS2);
2467 bestScore = -10000;
2468 score = 0;
2469 iSXb = iSXp = iS1;
2470 iEXb = iEXp = iS1;
2471 iSYb = iSYp = iS2;
2472 iEYb = iEYp = iS2;
@@ -2997,14 +3101,21 @@
2997 if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2998 c.xDiffer = compare_dline_ignore_allws;
2999 }else{
3000 c.xDiffer = compare_dline;
3001 }
3002 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
3003 &c.nFrom, pCfg->diffFlags);
3004 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
3005 &c.nTo, pCfg->diffFlags);
 
 
 
 
 
 
 
3006 if( c.aFrom==0 || c.aTo==0 ){
3007 fossil_free(c.aFrom);
3008 fossil_free(c.aTo);
3009 if( pOut ){
3010 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags);
@@ -3035,10 +3146,26 @@
3035 }
3036 }
3037 if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){
3038 diff_optimize(&c);
3039 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3040
3041 if( pOut ){
3042 if( pCfg->diffFlags & DIFF_NUMSTAT ){
3043 int nDel = 0, nIns = 0, i;
3044 for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
@@ -3049,11 +3176,11 @@
3049 g.diffCnt[2] += nDel;
3050 if( nIns+nDel ){
3051 g.diffCnt[0]++;
3052 blob_appendf(pOut, "%10d %10d", nIns, nDel);
3053 }
3054 }else if( pCfg->diffFlags & DIFF_RAW ){
3055 const int *R = c.aEdit;
3056 unsigned int r;
3057 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
3058 blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
3059 R[r], R[r+1], R[r+2]);
@@ -3100,20 +3227,29 @@
3100 ** Initialize the DiffConfig object using command-line options.
3101 **
3102 ** Process diff-related command-line options and return an appropriate
3103 ** "diffFlags" integer.
3104 **
 
3105 ** --brief Show filenames only DIFF_BRIEF
 
3106 ** -c|--context N N lines of context. nContext
 
3107 ** --html Format for HTML DIFF_HTML
 
3108 ** --invert Invert the diff DIFF_INVERT
 
3109 ** -n|--linenum Show line numbers DIFF_LINENO
 
3110 ** --noopt Disable optimization DIFF_NOOPT
3111 ** --numstat Show change counts DIFF_NUMSTAT
3112 ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
 
3113 ** --unified Unified diff. ~DIFF_SIDEBYSIDE
 
3114 ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
 
3115 ** -W|--width N N character lines. wColumn
3116 ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
3117 ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
3118 */
3119 void diff_options(DiffConfig *pCfg, int isGDiff, int bUnifiedTextOnly){
@@ -3157,10 +3293,13 @@
3157
3158 /* Undocumented and unsupported flags used for development
3159 ** debugging and analysis: */
3160 if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
3161 if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
 
 
 
3162 }
3163 if( (z = find_option("context","c",1))!=0 ){
3164 char *zEnd;
3165 f = (int)strtol(z, &zEnd, 10);
3166 if( zEnd[0]==0 && errno!=ERANGE ){
@@ -3771,11 +3910,11 @@
3771 int szHash; /* Display size of a version hash */
3772 Blob treename; /* Name of file to be annotated */
3773 char *zFilename; /* Name of file to be annotated */
3774
3775 bBlame = g.argv[1][0]!='a';
3776 zRevision = find_option("r","revision",1);
3777 zLimit = find_option("limit","n",1);
3778 zOrig = find_option("origin","o",1);
3779 showLog = find_option("log","l",0)!=0;
3780 if( find_option("ignore-trailing-space","Z",0)!=0 ){
3781 annFlags = DIFF_IGNORE_EOLWS;
3782
--- src/diff.c
+++ src/diff.c
@@ -50,10 +50,11 @@
50 #define DIFF_RAW 0x00040000 /* Raw triples - for debugging */
51 #define DIFF_TCL 0x00080000 /* For the --tk option */
52 #define DIFF_INCBINARY 0x00100000 /* The --diff-binary option */
53 #define DIFF_SHOW_VERS 0x00200000 /* Show compared versions */
54 #define DIFF_DARKMODE 0x00400000 /* Use dark mode for HTML */
55 #define DIFF_BY_TOKEN 0x01000000 /* Split on tokens, not lines */
56
57 /*
58 ** Per file information that may influence output.
59 */
60 #define DIFF_FILE_ADDED 0x40000000 /* Added or rename destination */
@@ -319,10 +320,113 @@
320
321 /* Return results */
322 *pnLine = nLine;
323 return a;
324 }
325
326 /*
327 ** Character classes for the purpose of tokenization.
328 **
329 ** 1 - alphanumeric
330 ** 2 - whitespace
331 ** 3 - punctuation
332 */
333 static char aTCharClass[256] = {
334 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
335 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
336 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
337 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
338
339 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
340 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
341 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
342 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
343
344 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
345 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
346 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
347 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
348
349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
353 };
354
355 /*
356 ** Count the number of tokens in the given string.
357 */
358 static int count_tokens(const unsigned char *p, int n){
359 int nToken = 0;
360 int iPrev = 0;
361 int i;
362 for(i=0; i<n; i++){
363 char x = aTCharClass[p[i]];
364 if( x!=iPrev ){
365 iPrev = x;
366 nToken++;
367 }
368 }
369 return nToken;
370 }
371
372 /*
373 ** Return an array of DLine objects containing a pointer to the
374 ** start of each token and a hash of that token. The lower
375 ** bits of the hash store the length of each token.
376 **
377 ** This is like break_into_lines() except that it works with tokens
378 ** instead of lines. A token is:
379 **
380 ** * A contiguous sequence of alphanumeric characters.
381 ** * A contiguous sequence of whitespace
382 ** * A contiguous sequence of punctuation characters.
383 **
384 ** Return 0 if the file is binary or contains a line that is
385 ** too long.
386 */
387 static DLine *break_into_tokens(
388 const char *z,
389 int n,
390 int *pnToken,
391 u64 diffFlags
392 ){
393 int nToken, i, k;
394 u64 h, h2;
395 DLine *a;
396 unsigned char *p = (unsigned char*)z;
397
398 nToken = count_tokens(p, n);
399 a = fossil_malloc( sizeof(a[0])*(nToken+1) );
400 memset(a, 0, sizeof(a[0])*(nToken+1));
401 if( n==0 ){
402 *pnToken = 0;
403 return a;
404 }
405 i = 0;
406 while( n>0 ){
407 char x = aTCharClass[*p];
408 h = 0xcbf29ce484222325LL;
409 for(k=1; k<n && aTCharClass[p[k]]==x; k++){
410 h ^= p[k];
411 h *= 0x100000001b3LL;
412 }
413 a[i].z = (char*)p;
414 a[i].n = k;
415 a[i].h = h = ((h%281474976710597LL)<<LENGTH_MASK_SZ) | k;
416 h2 = h % nToken;
417 a[i].iNext = a[h2].iHash;
418 a[h2].iHash = i+1;
419 p += k; n -= k;
420 i++;
421 };
422 assert( i==nToken );
423
424 /* Return results */
425 *pnToken = nToken;
426 return a;
427 }
428
429 /*
430 ** Return zero if two DLine elements are identical.
431 */
432 static int compare_dline(const DLine *pA, const DLine *pB){
@@ -2462,11 +2566,11 @@
2566 int span; /* combined width of the input sequences */
2567 int cutoff = 4; /* Max hash chain entries to follow */
2568 int nextCutoff = -1; /* Value of cutoff for next iteration */
2569
2570 span = (iE1 - iS1) + (iE2 - iS2);
2571 bestScore = -9223300000*(sqlite3_int64)1000000000;
2572 score = 0;
2573 iSXb = iSXp = iS1;
2574 iEXb = iEXp = iS1;
2575 iSYb = iSYp = iS2;
2576 iEYb = iEYp = iS2;
@@ -2997,14 +3101,21 @@
3101 if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
3102 c.xDiffer = compare_dline_ignore_allws;
3103 }else{
3104 c.xDiffer = compare_dline;
3105 }
3106 if( pCfg->diffFlags & DIFF_BY_TOKEN ){
3107 c.aFrom = break_into_tokens(blob_str(pA_Blob), blob_size(pA_Blob),
3108 &c.nFrom, pCfg->diffFlags);
3109 c.aTo = break_into_tokens(blob_str(pB_Blob), blob_size(pB_Blob),
3110 &c.nTo, pCfg->diffFlags);
3111 }else{
3112 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
3113 &c.nFrom, pCfg->diffFlags);
3114 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
3115 &c.nTo, pCfg->diffFlags);
3116 }
3117 if( c.aFrom==0 || c.aTo==0 ){
3118 fossil_free(c.aFrom);
3119 fossil_free(c.aTo);
3120 if( pOut ){
3121 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags);
@@ -3035,10 +3146,26 @@
3146 }
3147 }
3148 if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){
3149 diff_optimize(&c);
3150 }
3151 if( (pCfg->diffFlags & DIFF_BY_TOKEN)!=0 ){
3152 /* Convert token counts into byte counts. */
3153 int i;
3154 int iA = 0;
3155 int iB = 0;
3156 for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
3157 int k, sum;
3158 for(k=0, sum=0; k<c.aEdit[i]; k++) sum += c.aFrom[iA++].n;
3159 iB += c.aEdit[i];
3160 c.aEdit[i] = sum;
3161 for(k=0, sum=0; k<c.aEdit[i+1]; k++) sum += c.aFrom[iA++].n;
3162 c.aEdit[i+1] = sum;
3163 for(k=0, sum=0; k<c.aEdit[i+2]; k++) sum += c.aTo[iB++].n;
3164 c.aEdit[i+2] = sum;
3165 }
3166 }
3167
3168 if( pOut ){
3169 if( pCfg->diffFlags & DIFF_NUMSTAT ){
3170 int nDel = 0, nIns = 0, i;
3171 for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
@@ -3049,11 +3176,11 @@
3176 g.diffCnt[2] += nDel;
3177 if( nIns+nDel ){
3178 g.diffCnt[0]++;
3179 blob_appendf(pOut, "%10d %10d", nIns, nDel);
3180 }
3181 }else if( pCfg->diffFlags & (DIFF_RAW|DIFF_BY_TOKEN) ){
3182 const int *R = c.aEdit;
3183 unsigned int r;
3184 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
3185 blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
3186 R[r], R[r+1], R[r+2]);
@@ -3100,20 +3227,29 @@
3227 ** Initialize the DiffConfig object using command-line options.
3228 **
3229 ** Process diff-related command-line options and return an appropriate
3230 ** "diffFlags" integer.
3231 **
3232 ** -b|--browser Show the diff output in a web-browser
3233 ** --brief Show filenames only DIFF_BRIEF
3234 ** --by Shorthand for "--browser -y"
3235 ** -c|--context N N lines of context. nContext
3236 ** --dark Use dark mode for Tcl/Tk and HTML output
3237 ** --html Format for HTML DIFF_HTML
3238 ** -i|--internal Use built-in diff, not an external tool
3239 ** --invert Invert the diff DIFF_INVERT
3240 ** --json Output formatted as JSON
3241 ** -n|--linenum Show line numbers DIFF_LINENO
3242 ** -N|--new-file Alias for --verbose
3243 ** --noopt Disable optimization DIFF_NOOPT
3244 ** --numstat Show change counts DIFF_NUMSTAT
3245 ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
3246 ** --tcl Tcl-formatted output used internally by --tk
3247 ** --unified Unified diff. ~DIFF_SIDEBYSIDE
3248 ** -v|--verbose Show complete text of added or deleted files
3249 ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
3250 ** --webpage Format output as a stand-alone HTML webpage
3251 ** -W|--width N N character lines. wColumn
3252 ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
3253 ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
3254 */
3255 void diff_options(DiffConfig *pCfg, int isGDiff, int bUnifiedTextOnly){
@@ -3157,10 +3293,13 @@
3293
3294 /* Undocumented and unsupported flags used for development
3295 ** debugging and analysis: */
3296 if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
3297 if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
3298 if( find_option("bytoken",0,0)!=0 ){
3299 diffFlags = DIFF_RAW|DIFF_BY_TOKEN;
3300 }
3301 }
3302 if( (z = find_option("context","c",1))!=0 ){
3303 char *zEnd;
3304 f = (int)strtol(z, &zEnd, 10);
3305 if( zEnd[0]==0 && errno!=ERANGE ){
@@ -3771,11 +3910,11 @@
3910 int szHash; /* Display size of a version hash */
3911 Blob treename; /* Name of file to be annotated */
3912 char *zFilename; /* Name of file to be annotated */
3913
3914 bBlame = g.argv[1][0]!='a';
3915 zRevision = find_option("revision","r",1);
3916 zLimit = find_option("limit","n",1);
3917 zOrig = find_option("origin","o",1);
3918 showLog = find_option("log","l",0)!=0;
3919 if( find_option("ignore-trailing-space","Z",0)!=0 ){
3920 annFlags = DIFF_IGNORE_EOLWS;
3921
+1 -1
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,11 +1,11 @@
11
# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
22
# to this file, then runs this file using "tclsh" in order to display the
33
# graphical diff in a separate window. A typical "set fossilcmd" line
44
# looks like this:
55
#
6
-# set fossilcmd {| "./fossil" diff --html -y -i -v}
6
+# set fossilcmd {| "./fossil" diff --tcl -i -v}
77
#
88
# This header comment is stripped off by the "mkbuiltin.c" program.
99
#
1010
set prog {
1111
package require Tk
1212
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,11 +1,11 @@
1 # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
2 # to this file, then runs this file using "tclsh" in order to display the
3 # graphical diff in a separate window. A typical "set fossilcmd" line
4 # looks like this:
5 #
6 # set fossilcmd {| "./fossil" diff --html -y -i -v}
7 #
8 # This header comment is stripped off by the "mkbuiltin.c" program.
9 #
10 set prog {
11 package require Tk
12
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,11 +1,11 @@
1 # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
2 # to this file, then runs this file using "tclsh" in order to display the
3 # graphical diff in a separate window. A typical "set fossilcmd" line
4 # looks like this:
5 #
6 # set fossilcmd {| "./fossil" diff --tcl -i -v}
7 #
8 # This header comment is stripped off by the "mkbuiltin.c" program.
9 #
10 set prog {
11 package require Tk
12
+8 -8
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -249,19 +249,19 @@
249249
@ margin: 0 0 0 0;
250250
@ line-height: inherit;
251251
@ font-size: inherit;
252252
@ }
253253
@ td.diffln {
254
-@ width: 1px;
254
+@ width: fit-content;
255255
@ text-align: right;
256256
@ padding: 0 1em 0 0;
257257
@ }
258258
@ td.difflne {
259259
@ padding-bottom: 0.4em;
260260
@ }
261261
@ td.diffsep {
262
-@ width: 1px;
262
+@ width: fit-content;
263263
@ padding: 0 0.3em 0 1em;
264264
@ line-height: inherit;
265265
@ font-size: inherit;
266266
@ }
267267
@ td.diffsep pre {
@@ -379,19 +379,19 @@
379379
@ margin: 0 0 0 0;
380380
@ line-height: inherit;
381381
@ font-size: inherit;
382382
@ }
383383
@ td.diffln {
384
-@ width: 1px;
384
+@ width: fit-content;
385385
@ text-align: right;
386386
@ padding: 0 1em 0 0;
387387
@ }
388388
@ td.difflne {
389389
@ padding-bottom: 0.4em;
390390
@ }
391391
@ td.diffsep {
392
-@ width: 1px;
392
+@ width: fit-content;
393393
@ padding: 0 0.3em 0 1em;
394394
@ line-height: inherit;
395395
@ font-size: inherit;
396396
@ }
397397
@ td.diffsep pre {
@@ -1266,11 +1266,11 @@
12661266
** -n|--linenum Show line numbers
12671267
** -N|--new-file Alias for --verbose
12681268
** --numstat Show only the number of added and deleted lines
12691269
** -y|--side-by-side Side-by-side diff
12701270
** --strip-trailing-cr Strip trailing CR
1271
-** --tcl Tcl-formated output used internally by --tk
1271
+** --tcl Tcl-formatted output used internally by --tk
12721272
** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh")
12731273
** --tk Launch a Tcl/Tk GUI for display
12741274
** --to VERSION Select VERSION as target for the diff
12751275
** --undo Diff against the "undo" buffer
12761276
** --unified Unified diff
@@ -1312,11 +1312,12 @@
13121312
zFrom = mprintf("root:%s", zBranch);
13131313
}
13141314
if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){
13151315
fossil_fatal("cannot use --checkin together with --from or --to");
13161316
}
1317
- g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0;
1317
+ diff_options(&DCfg, isGDiff, 0);
1318
+ determine_exec_relative_option(1);
13181319
if( 0==zCheckin ){
13191320
if( zTo==0 || againstUndo ){
13201321
db_must_be_within_tree();
13211322
}else if( zFrom==0 ){
13221323
fossil_fatal("must use --from if --to is present");
@@ -1324,13 +1325,12 @@
13241325
db_find_and_open_repository(0, 0);
13251326
}
13261327
}else{
13271328
db_find_and_open_repository(0, 0);
13281329
}
1329
- diff_options(&DCfg, isGDiff, 0);
1330
- determine_exec_relative_option(1);
13311330
verify_all_options();
1331
+ g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0;
13321332
if( g.argc>=3 ){
13331333
int i;
13341334
Blob fname;
13351335
pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) );
13361336
memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1));
13371337
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -249,19 +249,19 @@
249 @ margin: 0 0 0 0;
250 @ line-height: inherit;
251 @ font-size: inherit;
252 @ }
253 @ td.diffln {
254 @ width: 1px;
255 @ text-align: right;
256 @ padding: 0 1em 0 0;
257 @ }
258 @ td.difflne {
259 @ padding-bottom: 0.4em;
260 @ }
261 @ td.diffsep {
262 @ width: 1px;
263 @ padding: 0 0.3em 0 1em;
264 @ line-height: inherit;
265 @ font-size: inherit;
266 @ }
267 @ td.diffsep pre {
@@ -379,19 +379,19 @@
379 @ margin: 0 0 0 0;
380 @ line-height: inherit;
381 @ font-size: inherit;
382 @ }
383 @ td.diffln {
384 @ width: 1px;
385 @ text-align: right;
386 @ padding: 0 1em 0 0;
387 @ }
388 @ td.difflne {
389 @ padding-bottom: 0.4em;
390 @ }
391 @ td.diffsep {
392 @ width: 1px;
393 @ padding: 0 0.3em 0 1em;
394 @ line-height: inherit;
395 @ font-size: inherit;
396 @ }
397 @ td.diffsep pre {
@@ -1266,11 +1266,11 @@
1266 ** -n|--linenum Show line numbers
1267 ** -N|--new-file Alias for --verbose
1268 ** --numstat Show only the number of added and deleted lines
1269 ** -y|--side-by-side Side-by-side diff
1270 ** --strip-trailing-cr Strip trailing CR
1271 ** --tcl Tcl-formated output used internally by --tk
1272 ** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh")
1273 ** --tk Launch a Tcl/Tk GUI for display
1274 ** --to VERSION Select VERSION as target for the diff
1275 ** --undo Diff against the "undo" buffer
1276 ** --unified Unified diff
@@ -1312,11 +1312,12 @@
1312 zFrom = mprintf("root:%s", zBranch);
1313 }
1314 if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){
1315 fossil_fatal("cannot use --checkin together with --from or --to");
1316 }
1317 g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0;
 
1318 if( 0==zCheckin ){
1319 if( zTo==0 || againstUndo ){
1320 db_must_be_within_tree();
1321 }else if( zFrom==0 ){
1322 fossil_fatal("must use --from if --to is present");
@@ -1324,13 +1325,12 @@
1324 db_find_and_open_repository(0, 0);
1325 }
1326 }else{
1327 db_find_and_open_repository(0, 0);
1328 }
1329 diff_options(&DCfg, isGDiff, 0);
1330 determine_exec_relative_option(1);
1331 verify_all_options();
 
1332 if( g.argc>=3 ){
1333 int i;
1334 Blob fname;
1335 pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) );
1336 memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1));
1337
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -249,19 +249,19 @@
249 @ margin: 0 0 0 0;
250 @ line-height: inherit;
251 @ font-size: inherit;
252 @ }
253 @ td.diffln {
254 @ width: fit-content;
255 @ text-align: right;
256 @ padding: 0 1em 0 0;
257 @ }
258 @ td.difflne {
259 @ padding-bottom: 0.4em;
260 @ }
261 @ td.diffsep {
262 @ width: fit-content;
263 @ padding: 0 0.3em 0 1em;
264 @ line-height: inherit;
265 @ font-size: inherit;
266 @ }
267 @ td.diffsep pre {
@@ -379,19 +379,19 @@
379 @ margin: 0 0 0 0;
380 @ line-height: inherit;
381 @ font-size: inherit;
382 @ }
383 @ td.diffln {
384 @ width: fit-content;
385 @ text-align: right;
386 @ padding: 0 1em 0 0;
387 @ }
388 @ td.difflne {
389 @ padding-bottom: 0.4em;
390 @ }
391 @ td.diffsep {
392 @ width: fit-content;
393 @ padding: 0 0.3em 0 1em;
394 @ line-height: inherit;
395 @ font-size: inherit;
396 @ }
397 @ td.diffsep pre {
@@ -1266,11 +1266,11 @@
1266 ** -n|--linenum Show line numbers
1267 ** -N|--new-file Alias for --verbose
1268 ** --numstat Show only the number of added and deleted lines
1269 ** -y|--side-by-side Side-by-side diff
1270 ** --strip-trailing-cr Strip trailing CR
1271 ** --tcl Tcl-formatted output used internally by --tk
1272 ** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh")
1273 ** --tk Launch a Tcl/Tk GUI for display
1274 ** --to VERSION Select VERSION as target for the diff
1275 ** --undo Diff against the "undo" buffer
1276 ** --unified Unified diff
@@ -1312,11 +1312,12 @@
1312 zFrom = mprintf("root:%s", zBranch);
1313 }
1314 if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){
1315 fossil_fatal("cannot use --checkin together with --from or --to");
1316 }
1317 diff_options(&DCfg, isGDiff, 0);
1318 determine_exec_relative_option(1);
1319 if( 0==zCheckin ){
1320 if( zTo==0 || againstUndo ){
1321 db_must_be_within_tree();
1322 }else if( zFrom==0 ){
1323 fossil_fatal("must use --from if --to is present");
@@ -1324,13 +1325,12 @@
1325 db_find_and_open_repository(0, 0);
1326 }
1327 }else{
1328 db_find_and_open_repository(0, 0);
1329 }
 
 
1330 verify_all_options();
1331 g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0;
1332 if( g.argc>=3 ){
1333 int i;
1334 Blob fname;
1335 pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) );
1336 memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1));
1337
+26 -1
--- src/dispatch.c
+++ src/dispatch.c
@@ -1307,17 +1307,42 @@
13071307
}
13081308
13091309
/*
13101310
** Return a pointer to the setting information array.
13111311
**
1312
-** This routine provides access to the aSetting2[] array which is created
1312
+** This routine provides access to the aSetting[] array which is created
13131313
** by the mkindex utility program and included with <page_index.h>.
13141314
*/
13151315
const Setting *setting_info(int *pnCount){
13161316
if( pnCount ) *pnCount = (int)(sizeof(aSetting)/sizeof(aSetting[0])) - 1;
13171317
return aSetting;
13181318
}
1319
+
1320
+/*
1321
+** Return a pointer to a specific Setting entry for the setting named
1322
+** in the argument. Or return NULL if no such setting exists.
1323
+**
1324
+** The pointer returned points into the middle of the global aSetting[]
1325
+** array that is generated by mkindex. Use setting_info() to fetch the
1326
+** whole array. Use this routine to fetch a specific entry.
1327
+*/
1328
+const Setting *setting_find(const char *zName){
1329
+ int iFirst = 0;
1330
+ int iLast = ArraySize(aSetting)-1;
1331
+ while( iFirst<=iLast ){
1332
+ int iCur = (iFirst+iLast)/2;
1333
+ int c = strcmp(aSetting[iCur].name, zName);
1334
+ if( c<0 ){
1335
+ iFirst = iCur+1;
1336
+ }else if( c>0 ){
1337
+ iLast = iCur-1;
1338
+ }else{
1339
+ return &aSetting[iCur];
1340
+ }
1341
+ }
1342
+ return 0;
1343
+}
13191344
13201345
/*****************************************************************************
13211346
** A virtual table for accessing the information in aCommand[], and
13221347
** especially the help-text
13231348
*/
13241349
--- src/dispatch.c
+++ src/dispatch.c
@@ -1307,17 +1307,42 @@
1307 }
1308
1309 /*
1310 ** Return a pointer to the setting information array.
1311 **
1312 ** This routine provides access to the aSetting2[] array which is created
1313 ** by the mkindex utility program and included with <page_index.h>.
1314 */
1315 const Setting *setting_info(int *pnCount){
1316 if( pnCount ) *pnCount = (int)(sizeof(aSetting)/sizeof(aSetting[0])) - 1;
1317 return aSetting;
1318 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1319
1320 /*****************************************************************************
1321 ** A virtual table for accessing the information in aCommand[], and
1322 ** especially the help-text
1323 */
1324
--- src/dispatch.c
+++ src/dispatch.c
@@ -1307,17 +1307,42 @@
1307 }
1308
1309 /*
1310 ** Return a pointer to the setting information array.
1311 **
1312 ** This routine provides access to the aSetting[] array which is created
1313 ** by the mkindex utility program and included with <page_index.h>.
1314 */
1315 const Setting *setting_info(int *pnCount){
1316 if( pnCount ) *pnCount = (int)(sizeof(aSetting)/sizeof(aSetting[0])) - 1;
1317 return aSetting;
1318 }
1319
1320 /*
1321 ** Return a pointer to a specific Setting entry for the setting named
1322 ** in the argument. Or return NULL if no such setting exists.
1323 **
1324 ** The pointer returned points into the middle of the global aSetting[]
1325 ** array that is generated by mkindex. Use setting_info() to fetch the
1326 ** whole array. Use this routine to fetch a specific entry.
1327 */
1328 const Setting *setting_find(const char *zName){
1329 int iFirst = 0;
1330 int iLast = ArraySize(aSetting)-1;
1331 while( iFirst<=iLast ){
1332 int iCur = (iFirst+iLast)/2;
1333 int c = strcmp(aSetting[iCur].name, zName);
1334 if( c<0 ){
1335 iFirst = iCur+1;
1336 }else if( c>0 ){
1337 iLast = iCur-1;
1338 }else{
1339 return &aSetting[iCur];
1340 }
1341 }
1342 return 0;
1343 }
1344
1345 /*****************************************************************************
1346 ** A virtual table for accessing the information in aCommand[], and
1347 ** especially the help-text
1348 */
1349
+2
--- src/doc.c
+++ src/doc.c
@@ -305,10 +305,12 @@
305305
{ "xlsx", 4, "application/vnd.openxmlformats-"
306306
"officedocument.spreadsheetml.sheet"},
307307
{ "xlw", 3, "application/vnd.ms-excel" },
308308
{ "xml", 3, "text/xml" },
309309
{ "xpm", 3, "image/x-xpixmap" },
310
+ { "xsl", 3, "text/xml" },
311
+ { "xslt", 4, "text/xml" },
310312
{ "xwd", 3, "image/x-xwindowdump" },
311313
{ "xyz", 3, "chemical/x-pdb" },
312314
{ "zip", 3, "application/zip" },
313315
};
314316
315317
--- src/doc.c
+++ src/doc.c
@@ -305,10 +305,12 @@
305 { "xlsx", 4, "application/vnd.openxmlformats-"
306 "officedocument.spreadsheetml.sheet"},
307 { "xlw", 3, "application/vnd.ms-excel" },
308 { "xml", 3, "text/xml" },
309 { "xpm", 3, "image/x-xpixmap" },
 
 
310 { "xwd", 3, "image/x-xwindowdump" },
311 { "xyz", 3, "chemical/x-pdb" },
312 { "zip", 3, "application/zip" },
313 };
314
315
--- src/doc.c
+++ src/doc.c
@@ -305,10 +305,12 @@
305 { "xlsx", 4, "application/vnd.openxmlformats-"
306 "officedocument.spreadsheetml.sheet"},
307 { "xlw", 3, "application/vnd.ms-excel" },
308 { "xml", 3, "text/xml" },
309 { "xpm", 3, "image/x-xpixmap" },
310 { "xsl", 3, "text/xml" },
311 { "xslt", 4, "text/xml" },
312 { "xwd", 3, "image/x-xwindowdump" },
313 { "xyz", 3, "chemical/x-pdb" },
314 { "zip", 3, "application/zip" },
315 };
316
317
+1 -1
--- src/event.c
+++ src/event.c
@@ -229,11 +229,11 @@
229229
}
230230
zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
231231
" FROM tag"
232232
" WHERE tagname GLOB 'event-%q*'",
233233
zId);
234
- attachment_list(zFullId, "<hr><h2>Attachments:</h2><ul>");
234
+ attachment_list(zFullId, "<h2>Attachments:</h2>", 1);
235235
document_emit_js();
236236
style_finish_page();
237237
manifest_destroy(pTNote);
238238
}
239239
240240
--- src/event.c
+++ src/event.c
@@ -229,11 +229,11 @@
229 }
230 zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
231 " FROM tag"
232 " WHERE tagname GLOB 'event-%q*'",
233 zId);
234 attachment_list(zFullId, "<hr><h2>Attachments:</h2><ul>");
235 document_emit_js();
236 style_finish_page();
237 manifest_destroy(pTNote);
238 }
239
240
--- src/event.c
+++ src/event.c
@@ -229,11 +229,11 @@
229 }
230 zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
231 " FROM tag"
232 " WHERE tagname GLOB 'event-%q*'",
233 zId);
234 attachment_list(zFullId, "<h2>Attachments:</h2>", 1);
235 document_emit_js();
236 style_finish_page();
237 manifest_destroy(pTNote);
238 }
239
240
+99 -9
--- src/file.c
+++ src/file.c
@@ -1302,25 +1302,37 @@
13021302
}
13031303
}
13041304
13051305
/*
13061306
** Compute a canonical pathname for a file or directory.
1307
-** Make the name absolute if it is relative.
1308
-** Remove redundant / characters
1309
-** Remove all /./ path elements.
1310
-** Convert /A/../ to just /
1307
+**
1308
+** * Make the name absolute if it is relative.
1309
+** * Remove redundant / characters
1310
+** * Remove all /./ path elements.
1311
+** * Convert /A/../ to just /
1312
+** * On windows, add the drive letter prefix.
1313
+**
13111314
** If the slash parameter is non-zero, the trailing slash, if any,
13121315
** is retained.
13131316
**
13141317
** See also: file_canonical_name_dup()
13151318
*/
13161319
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
1320
+ char zPwd[2000];
13171321
blob_zero(pOut);
13181322
if( file_is_absolute_path(zOrigName) ){
1319
- blob_appendf(pOut, "%/", zOrigName);
1323
+#if defined(_WIN32)
1324
+ if( fossil_isdirsep(zOrigName[0]) ){
1325
+ /* Add the drive letter to the full pathname */
1326
+ file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
1327
+ blob_appendf(pOut, "%.2s%/", zPwd, zOrigName);
1328
+ }else
1329
+#endif
1330
+ {
1331
+ blob_appendf(pOut, "%/", zOrigName);
1332
+ }
13201333
}else{
1321
- char zPwd[2000];
13221334
file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
13231335
if( zPwd[0]=='/' && strlen(zPwd)==1 ){
13241336
/* when on '/', don't add an extra '/' */
13251337
if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){
13261338
/* '.' when on '/' mean '/' */
@@ -1372,10 +1384,11 @@
13721384
** just fossil_strdup(). But for case-insenstiive but "case preserving"
13731385
** filesystems, such as on MacOS or Windows, we want the filename to be
13741386
** in the preserved casing. That's what this routine does.
13751387
*/
13761388
char *file_case_preferred_name(const char *zDir, const char *zPath){
1389
+#ifndef _WIN32 /* Call win32_file_case_preferred_name() on Windows. */
13771390
DIR *d;
13781391
int i;
13791392
char *zResult = 0;
13801393
void *zNative = 0;
13811394
@@ -1407,10 +1420,13 @@
14071420
closedir(d);
14081421
}
14091422
fossil_path_free(zNative);
14101423
if( zResult==0 ) zResult = fossil_strdup(zPath);
14111424
return zResult;
1425
+#else /* !_WIN32 */
1426
+ return win32_file_case_preferred_name(zDir,zPath);
1427
+#endif /* !_WIN32 */
14121428
}
14131429
14141430
/*
14151431
** COMMAND: test-case-filename
14161432
**
@@ -1637,13 +1653,16 @@
16371653
fossil_print("filenames_are_case_sensitive() = %d\n",
16381654
filenames_are_case_sensitive());
16391655
if( zAllow ){
16401656
g.allowSymlinks = !is_false(zAllow);
16411657
}
1642
- if( zRoot==0 ) zRoot = g.zLocalRoot;
1658
+ if( zRoot==0 ) zRoot = g.zLocalRoot==0 ? "" : g.zLocalRoot;
16431659
fossil_print("db_allow_symlinks() = %d\n", db_allow_symlinks());
16441660
fossil_print("local-root = [%s]\n", zRoot);
1661
+ if( g.db==0 ) sqlite3_open(":memory:", &g.db);
1662
+ sqlite3_create_function(g.db, "inode", 1, SQLITE_UTF8, 0,
1663
+ file_inode_sql_func, 0, 0);
16451664
for(i=2; i<g.argc; i++){
16461665
char *z;
16471666
emitFileStat(g.argv[i], slashFlag, resetFlag);
16481667
z = file_canonical_name_dup(g.argv[i]);
16491668
fossil_print(" file_canonical_name = %s\n", z);
@@ -1653,10 +1672,13 @@
16531672
}else{
16541673
int n = file_nondir_objects_on_path(zRoot, z);
16551674
fossil_print("%.*s\n", n, z);
16561675
}
16571676
fossil_free(z);
1677
+ z = db_text(0, "SELECT inode(%Q)", g.argv[i]);
1678
+ fossil_print(" file_inode_sql_func = \"%s\"\n", z);
1679
+ fossil_free(z);
16581680
}
16591681
}
16601682
16611683
/*
16621684
** COMMAND: test-canonical-name
@@ -1695,13 +1717,15 @@
16951717
** Canonical names are full pathnames using "/" not "\" and which
16961718
** contain no "/./" or "/../" terms.
16971719
*/
16981720
int file_is_canonical(const char *z){
16991721
int i;
1700
- if( z[0]!='/'
1722
+ if(
17011723
#if defined(_WIN32) || defined(__CYGWIN__)
1702
- && (!fossil_isupper(z[0]) || z[1]!=':' || z[2]!='/')
1724
+ !fossil_isupper(z[0]) || z[1]!=':' || !fossil_isdirsep(z[2])
1725
+#else
1726
+ z[0]!='/'
17031727
#endif
17041728
) return 0;
17051729
17061730
for(i=0; z[i]; i++){
17071731
if( z[i]=='\\' ) return 0;
@@ -2949,18 +2973,84 @@
29492973
** Returns 1 if the given directory contains a file named .fslckout, 2
29502974
** if it contains a file named _FOSSIL_, else returns 0.
29512975
*/
29522976
int dir_has_ckout_db(const char *zDir){
29532977
int rc = 0;
2978
+ i64 sz;
29542979
char * zCkoutDb = mprintf("%//.fslckout", zDir);
29552980
if(file_isfile(zCkoutDb, ExtFILE)){
29562981
rc = 1;
29572982
}else{
29582983
fossil_free(zCkoutDb);
29592984
zCkoutDb = mprintf("%//_FOSSIL_", zDir);
29602985
if(file_isfile(zCkoutDb, ExtFILE)){
29612986
rc = 2;
29622987
}
2988
+ }
2989
+ if( rc && ((sz = file_size(zCkoutDb, ExtFILE))<1024 || (sz%512)!=0) ){
2990
+ rc = 0;
29632991
}
29642992
fossil_free(zCkoutDb);
29652993
return rc;
29662994
}
2995
+
2996
+/*
2997
+** This is the implementation of inode(FILENAME) SQL function.
2998
+**
2999
+** dev_inode(FILENAME) returns a string. If FILENAME exists and is
3000
+** a regular file, then the return string is of the form:
3001
+**
3002
+** DEV/INODE
3003
+**
3004
+** Where DEV and INODE are the device number and inode number for
3005
+** the file. On Windows, the volume serial number (DEV) and file
3006
+** identifier (INODE) are used to compute the value, see comments
3007
+** on the win32_file_id() function.
3008
+**
3009
+** If FILENAME does not exist, then the return is an empty string.
3010
+**
3011
+** The value of inode() can be used to eliminate files from a list
3012
+** that have duplicates because they have differing names due to links.
3013
+**
3014
+** Code that wants to use this SQL function needs to first register
3015
+** it using a call such as the following:
3016
+**
3017
+** sqlite3_create_function(g.db, "inode", 1, SQLITE_UTF8, 0,
3018
+** file_inode_sql_func, 0, 0);
3019
+*/
3020
+void file_inode_sql_func(
3021
+ sqlite3_context *context,
3022
+ int argc,
3023
+ sqlite3_value **argv
3024
+){
3025
+ const char *zFilename;
3026
+ assert( argc==1 );
3027
+ zFilename = (const char*)sqlite3_value_text(argv[0]);
3028
+ if( zFilename==0 || zFilename[0]==0 || file_access(zFilename,F_OK) ){
3029
+ sqlite3_result_text(context, "", 0, SQLITE_STATIC);
3030
+ return;
3031
+ }
3032
+#if defined(_WIN32)
3033
+ {
3034
+ char *zFileId = win32_file_id(zFilename);
3035
+ if( zFileId ){
3036
+ sqlite3_result_text(context, zFileId, -1, fossil_free);
3037
+ }else{
3038
+ sqlite3_result_text(context, "", 0, SQLITE_STATIC);
3039
+ }
3040
+ }
3041
+#else
3042
+ {
3043
+ struct stat buf;
3044
+ int rc;
3045
+ memset(&buf, 0, sizeof(buf));
3046
+ rc = stat(zFilename, &buf);
3047
+ if( rc ){
3048
+ sqlite3_result_text(context, "", 0, SQLITE_STATIC);
3049
+ }else{
3050
+ sqlite3_result_text(context,
3051
+ mprintf("%lld/%lld", (i64)buf.st_dev, (i64)buf.st_ino), -1,
3052
+ fossil_free);
3053
+ }
3054
+ }
3055
+#endif
3056
+}
29673057
--- src/file.c
+++ src/file.c
@@ -1302,25 +1302,37 @@
1302 }
1303 }
1304
1305 /*
1306 ** Compute a canonical pathname for a file or directory.
1307 ** Make the name absolute if it is relative.
1308 ** Remove redundant / characters
1309 ** Remove all /./ path elements.
1310 ** Convert /A/../ to just /
 
 
 
1311 ** If the slash parameter is non-zero, the trailing slash, if any,
1312 ** is retained.
1313 **
1314 ** See also: file_canonical_name_dup()
1315 */
1316 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
 
1317 blob_zero(pOut);
1318 if( file_is_absolute_path(zOrigName) ){
1319 blob_appendf(pOut, "%/", zOrigName);
 
 
 
 
 
 
 
 
 
1320 }else{
1321 char zPwd[2000];
1322 file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
1323 if( zPwd[0]=='/' && strlen(zPwd)==1 ){
1324 /* when on '/', don't add an extra '/' */
1325 if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){
1326 /* '.' when on '/' mean '/' */
@@ -1372,10 +1384,11 @@
1372 ** just fossil_strdup(). But for case-insenstiive but "case preserving"
1373 ** filesystems, such as on MacOS or Windows, we want the filename to be
1374 ** in the preserved casing. That's what this routine does.
1375 */
1376 char *file_case_preferred_name(const char *zDir, const char *zPath){
 
1377 DIR *d;
1378 int i;
1379 char *zResult = 0;
1380 void *zNative = 0;
1381
@@ -1407,10 +1420,13 @@
1407 closedir(d);
1408 }
1409 fossil_path_free(zNative);
1410 if( zResult==0 ) zResult = fossil_strdup(zPath);
1411 return zResult;
 
 
 
1412 }
1413
1414 /*
1415 ** COMMAND: test-case-filename
1416 **
@@ -1637,13 +1653,16 @@
1637 fossil_print("filenames_are_case_sensitive() = %d\n",
1638 filenames_are_case_sensitive());
1639 if( zAllow ){
1640 g.allowSymlinks = !is_false(zAllow);
1641 }
1642 if( zRoot==0 ) zRoot = g.zLocalRoot;
1643 fossil_print("db_allow_symlinks() = %d\n", db_allow_symlinks());
1644 fossil_print("local-root = [%s]\n", zRoot);
 
 
 
1645 for(i=2; i<g.argc; i++){
1646 char *z;
1647 emitFileStat(g.argv[i], slashFlag, resetFlag);
1648 z = file_canonical_name_dup(g.argv[i]);
1649 fossil_print(" file_canonical_name = %s\n", z);
@@ -1653,10 +1672,13 @@
1653 }else{
1654 int n = file_nondir_objects_on_path(zRoot, z);
1655 fossil_print("%.*s\n", n, z);
1656 }
1657 fossil_free(z);
 
 
 
1658 }
1659 }
1660
1661 /*
1662 ** COMMAND: test-canonical-name
@@ -1695,13 +1717,15 @@
1695 ** Canonical names are full pathnames using "/" not "\" and which
1696 ** contain no "/./" or "/../" terms.
1697 */
1698 int file_is_canonical(const char *z){
1699 int i;
1700 if( z[0]!='/'
1701 #if defined(_WIN32) || defined(__CYGWIN__)
1702 && (!fossil_isupper(z[0]) || z[1]!=':' || z[2]!='/')
 
 
1703 #endif
1704 ) return 0;
1705
1706 for(i=0; z[i]; i++){
1707 if( z[i]=='\\' ) return 0;
@@ -2949,18 +2973,84 @@
2949 ** Returns 1 if the given directory contains a file named .fslckout, 2
2950 ** if it contains a file named _FOSSIL_, else returns 0.
2951 */
2952 int dir_has_ckout_db(const char *zDir){
2953 int rc = 0;
 
2954 char * zCkoutDb = mprintf("%//.fslckout", zDir);
2955 if(file_isfile(zCkoutDb, ExtFILE)){
2956 rc = 1;
2957 }else{
2958 fossil_free(zCkoutDb);
2959 zCkoutDb = mprintf("%//_FOSSIL_", zDir);
2960 if(file_isfile(zCkoutDb, ExtFILE)){
2961 rc = 2;
2962 }
 
 
 
2963 }
2964 fossil_free(zCkoutDb);
2965 return rc;
2966 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2967
--- src/file.c
+++ src/file.c
@@ -1302,25 +1302,37 @@
1302 }
1303 }
1304
1305 /*
1306 ** Compute a canonical pathname for a file or directory.
1307 **
1308 ** * Make the name absolute if it is relative.
1309 ** * Remove redundant / characters
1310 ** * Remove all /./ path elements.
1311 ** * Convert /A/../ to just /
1312 ** * On windows, add the drive letter prefix.
1313 **
1314 ** If the slash parameter is non-zero, the trailing slash, if any,
1315 ** is retained.
1316 **
1317 ** See also: file_canonical_name_dup()
1318 */
1319 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
1320 char zPwd[2000];
1321 blob_zero(pOut);
1322 if( file_is_absolute_path(zOrigName) ){
1323 #if defined(_WIN32)
1324 if( fossil_isdirsep(zOrigName[0]) ){
1325 /* Add the drive letter to the full pathname */
1326 file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
1327 blob_appendf(pOut, "%.2s%/", zPwd, zOrigName);
1328 }else
1329 #endif
1330 {
1331 blob_appendf(pOut, "%/", zOrigName);
1332 }
1333 }else{
 
1334 file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
1335 if( zPwd[0]=='/' && strlen(zPwd)==1 ){
1336 /* when on '/', don't add an extra '/' */
1337 if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){
1338 /* '.' when on '/' mean '/' */
@@ -1372,10 +1384,11 @@
1384 ** just fossil_strdup(). But for case-insenstiive but "case preserving"
1385 ** filesystems, such as on MacOS or Windows, we want the filename to be
1386 ** in the preserved casing. That's what this routine does.
1387 */
1388 char *file_case_preferred_name(const char *zDir, const char *zPath){
1389 #ifndef _WIN32 /* Call win32_file_case_preferred_name() on Windows. */
1390 DIR *d;
1391 int i;
1392 char *zResult = 0;
1393 void *zNative = 0;
1394
@@ -1407,10 +1420,13 @@
1420 closedir(d);
1421 }
1422 fossil_path_free(zNative);
1423 if( zResult==0 ) zResult = fossil_strdup(zPath);
1424 return zResult;
1425 #else /* !_WIN32 */
1426 return win32_file_case_preferred_name(zDir,zPath);
1427 #endif /* !_WIN32 */
1428 }
1429
1430 /*
1431 ** COMMAND: test-case-filename
1432 **
@@ -1637,13 +1653,16 @@
1653 fossil_print("filenames_are_case_sensitive() = %d\n",
1654 filenames_are_case_sensitive());
1655 if( zAllow ){
1656 g.allowSymlinks = !is_false(zAllow);
1657 }
1658 if( zRoot==0 ) zRoot = g.zLocalRoot==0 ? "" : g.zLocalRoot;
1659 fossil_print("db_allow_symlinks() = %d\n", db_allow_symlinks());
1660 fossil_print("local-root = [%s]\n", zRoot);
1661 if( g.db==0 ) sqlite3_open(":memory:", &g.db);
1662 sqlite3_create_function(g.db, "inode", 1, SQLITE_UTF8, 0,
1663 file_inode_sql_func, 0, 0);
1664 for(i=2; i<g.argc; i++){
1665 char *z;
1666 emitFileStat(g.argv[i], slashFlag, resetFlag);
1667 z = file_canonical_name_dup(g.argv[i]);
1668 fossil_print(" file_canonical_name = %s\n", z);
@@ -1653,10 +1672,13 @@
1672 }else{
1673 int n = file_nondir_objects_on_path(zRoot, z);
1674 fossil_print("%.*s\n", n, z);
1675 }
1676 fossil_free(z);
1677 z = db_text(0, "SELECT inode(%Q)", g.argv[i]);
1678 fossil_print(" file_inode_sql_func = \"%s\"\n", z);
1679 fossil_free(z);
1680 }
1681 }
1682
1683 /*
1684 ** COMMAND: test-canonical-name
@@ -1695,13 +1717,15 @@
1717 ** Canonical names are full pathnames using "/" not "\" and which
1718 ** contain no "/./" or "/../" terms.
1719 */
1720 int file_is_canonical(const char *z){
1721 int i;
1722 if(
1723 #if defined(_WIN32) || defined(__CYGWIN__)
1724 !fossil_isupper(z[0]) || z[1]!=':' || !fossil_isdirsep(z[2])
1725 #else
1726 z[0]!='/'
1727 #endif
1728 ) return 0;
1729
1730 for(i=0; z[i]; i++){
1731 if( z[i]=='\\' ) return 0;
@@ -2949,18 +2973,84 @@
2973 ** Returns 1 if the given directory contains a file named .fslckout, 2
2974 ** if it contains a file named _FOSSIL_, else returns 0.
2975 */
2976 int dir_has_ckout_db(const char *zDir){
2977 int rc = 0;
2978 i64 sz;
2979 char * zCkoutDb = mprintf("%//.fslckout", zDir);
2980 if(file_isfile(zCkoutDb, ExtFILE)){
2981 rc = 1;
2982 }else{
2983 fossil_free(zCkoutDb);
2984 zCkoutDb = mprintf("%//_FOSSIL_", zDir);
2985 if(file_isfile(zCkoutDb, ExtFILE)){
2986 rc = 2;
2987 }
2988 }
2989 if( rc && ((sz = file_size(zCkoutDb, ExtFILE))<1024 || (sz%512)!=0) ){
2990 rc = 0;
2991 }
2992 fossil_free(zCkoutDb);
2993 return rc;
2994 }
2995
2996 /*
2997 ** This is the implementation of inode(FILENAME) SQL function.
2998 **
2999 ** dev_inode(FILENAME) returns a string. If FILENAME exists and is
3000 ** a regular file, then the return string is of the form:
3001 **
3002 ** DEV/INODE
3003 **
3004 ** Where DEV and INODE are the device number and inode number for
3005 ** the file. On Windows, the volume serial number (DEV) and file
3006 ** identifier (INODE) are used to compute the value, see comments
3007 ** on the win32_file_id() function.
3008 **
3009 ** If FILENAME does not exist, then the return is an empty string.
3010 **
3011 ** The value of inode() can be used to eliminate files from a list
3012 ** that have duplicates because they have differing names due to links.
3013 **
3014 ** Code that wants to use this SQL function needs to first register
3015 ** it using a call such as the following:
3016 **
3017 ** sqlite3_create_function(g.db, "inode", 1, SQLITE_UTF8, 0,
3018 ** file_inode_sql_func, 0, 0);
3019 */
3020 void file_inode_sql_func(
3021 sqlite3_context *context,
3022 int argc,
3023 sqlite3_value **argv
3024 ){
3025 const char *zFilename;
3026 assert( argc==1 );
3027 zFilename = (const char*)sqlite3_value_text(argv[0]);
3028 if( zFilename==0 || zFilename[0]==0 || file_access(zFilename,F_OK) ){
3029 sqlite3_result_text(context, "", 0, SQLITE_STATIC);
3030 return;
3031 }
3032 #if defined(_WIN32)
3033 {
3034 char *zFileId = win32_file_id(zFilename);
3035 if( zFileId ){
3036 sqlite3_result_text(context, zFileId, -1, fossil_free);
3037 }else{
3038 sqlite3_result_text(context, "", 0, SQLITE_STATIC);
3039 }
3040 }
3041 #else
3042 {
3043 struct stat buf;
3044 int rc;
3045 memset(&buf, 0, sizeof(buf));
3046 rc = stat(zFilename, &buf);
3047 if( rc ){
3048 sqlite3_result_text(context, "", 0, SQLITE_STATIC);
3049 }else{
3050 sqlite3_result_text(context,
3051 mprintf("%lld/%lld", (i64)buf.st_dev, (i64)buf.st_ino), -1,
3052 fossil_free);
3053 }
3054 }
3055 #endif
3056 }
3057
+13 -5
--- src/finfo.c
+++ src/finfo.c
@@ -185,11 +185,11 @@
185185
zLimit = find_option("limit","n",1);
186186
zWidth = find_option("width","W",1);
187187
iLimit = zLimit ? atoi(zLimit) : -1;
188188
zOffset = find_option("offset",0,1);
189189
iOffset = zOffset ? atoi(zOffset) : 0;
190
- iBrief = (find_option("brief","b",0) == 0);
190
+ iBrief = find_option("brief","b",0) != 0;
191191
if( iLimit==0 ){
192192
iLimit = -1;
193193
}
194194
if( zWidth ){
195195
iWidth = atoi(zWidth);
@@ -228,11 +228,11 @@
228228
" ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
229229
TAG_BRANCH, zFilename, filename_collation(),
230230
iLimit, iOffset
231231
);
232232
blob_zero(&line);
233
- if( iBrief ){
233
+ if( iBrief == 0 ){
234234
fossil_print("History for %s\n", blob_str(&fname));
235235
}
236236
while( db_step(&q)==SQLITE_ROW ){
237237
const char *zFileUuid = db_column_text(&q, 0);
238238
const char *zCiUuid = db_column_text(&q,1);
@@ -240,11 +240,11 @@
240240
const char *zCom = db_column_text(&q, 3);
241241
const char *zUser = db_column_text(&q, 4);
242242
const char *zBr = db_column_text(&q, 5);
243243
char *zOut;
244244
if( zBr==0 ) zBr = "trunk";
245
- if( iBrief ){
245
+ if( iBrief == 0 ){
246246
fossil_print("%s ", zDate);
247247
zOut = mprintf(
248248
"[%S] %s (user: %s, artifact: [%S], branch: %s)",
249249
zCiUuid, zCom, zUser, zFileUuid, zBr);
250250
comment_print(zOut, zCom, 11, iWidth, get_comment_format());
@@ -620,10 +620,11 @@
620620
int fnid = db_column_int(&q, 13);
621621
const char *zFName = db_column_text(&q,14);
622622
int gidx;
623623
char zTime[10];
624624
int nParent = 0;
625
+ int bIsModified = 0;
625626
GraphRowId aParent[GR_MAX_RAIL];
626627
627628
db_bind_int(&qparent, ":fid", frid);
628629
db_bind_int(&qparent, ":mid", fmid);
629630
db_bind_int(&qparent, ":fnid", fnid);
@@ -661,19 +662,26 @@
661662
@ </td>
662663
if( zBgClr && zBgClr[0] ){
663664
@ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
664665
}else{
665666
@ <td class="timeline%s(zStyle)Cell">
667
+ }
668
+ if( zPUuid && zUuid && fossil_strcmp(zPUuid, zUuid)!=0 ){
669
+ bIsModified = 1;
666670
}
667671
if( tmFlags & TIMELINE_COMPACT ){
668672
@ <span class='timelineCompactComment' data-id='%d(frid)'>
669673
}else{
670674
@ <span class='timeline%s(zStyle)Comment'>
671675
if( pfnid ){
672676
char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
673677
pfnid);
674
- @ <b>Renamed</b> %h(zPrevName) &rarr; %h(zFName).
678
+ if( bIsModified ){
679
+ @ <b>Renamed and modified</b> %h(zPrevName) &rarr; %h(zFName).
680
+ }else{
681
+ @ <b>Renamed</b> %h(zPrevName) &rarr; %h(zFName).
682
+ }
675683
fossil_free(zPrevName);
676684
}
677685
if( zUuid && ridTo==0 && nParent==0 ){
678686
@ <b>Added:</b>
679687
}
@@ -756,11 +764,11 @@
756764
@ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
757765
@ [annotate]</a>
758766
@ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
759767
@ [blame]</a>
760768
@ %z(href("%R/timeline?uf=%!S",zUuid))[check-ins&nbsp;using]</a>
761
- if( fpid>0 ){
769
+ if( fpid>0 && bIsModified!=0 ){
762770
@ %z(href("%R/fdiff?v1=%!S&v2=%!S",zPUuid,zUuid))[diff]</a>
763771
}
764772
if( fileedit_is_editable(zFName) ){
765773
@ %z(href("%R/fileedit?filename=%T&checkin=%!S",zFName,zCkin))\
766774
@ [edit]</a>
767775
--- src/finfo.c
+++ src/finfo.c
@@ -185,11 +185,11 @@
185 zLimit = find_option("limit","n",1);
186 zWidth = find_option("width","W",1);
187 iLimit = zLimit ? atoi(zLimit) : -1;
188 zOffset = find_option("offset",0,1);
189 iOffset = zOffset ? atoi(zOffset) : 0;
190 iBrief = (find_option("brief","b",0) == 0);
191 if( iLimit==0 ){
192 iLimit = -1;
193 }
194 if( zWidth ){
195 iWidth = atoi(zWidth);
@@ -228,11 +228,11 @@
228 " ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
229 TAG_BRANCH, zFilename, filename_collation(),
230 iLimit, iOffset
231 );
232 blob_zero(&line);
233 if( iBrief ){
234 fossil_print("History for %s\n", blob_str(&fname));
235 }
236 while( db_step(&q)==SQLITE_ROW ){
237 const char *zFileUuid = db_column_text(&q, 0);
238 const char *zCiUuid = db_column_text(&q,1);
@@ -240,11 +240,11 @@
240 const char *zCom = db_column_text(&q, 3);
241 const char *zUser = db_column_text(&q, 4);
242 const char *zBr = db_column_text(&q, 5);
243 char *zOut;
244 if( zBr==0 ) zBr = "trunk";
245 if( iBrief ){
246 fossil_print("%s ", zDate);
247 zOut = mprintf(
248 "[%S] %s (user: %s, artifact: [%S], branch: %s)",
249 zCiUuid, zCom, zUser, zFileUuid, zBr);
250 comment_print(zOut, zCom, 11, iWidth, get_comment_format());
@@ -620,10 +620,11 @@
620 int fnid = db_column_int(&q, 13);
621 const char *zFName = db_column_text(&q,14);
622 int gidx;
623 char zTime[10];
624 int nParent = 0;
 
625 GraphRowId aParent[GR_MAX_RAIL];
626
627 db_bind_int(&qparent, ":fid", frid);
628 db_bind_int(&qparent, ":mid", fmid);
629 db_bind_int(&qparent, ":fnid", fnid);
@@ -661,19 +662,26 @@
661 @ </td>
662 if( zBgClr && zBgClr[0] ){
663 @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
664 }else{
665 @ <td class="timeline%s(zStyle)Cell">
 
 
 
666 }
667 if( tmFlags & TIMELINE_COMPACT ){
668 @ <span class='timelineCompactComment' data-id='%d(frid)'>
669 }else{
670 @ <span class='timeline%s(zStyle)Comment'>
671 if( pfnid ){
672 char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
673 pfnid);
674 @ <b>Renamed</b> %h(zPrevName) &rarr; %h(zFName).
 
 
 
 
675 fossil_free(zPrevName);
676 }
677 if( zUuid && ridTo==0 && nParent==0 ){
678 @ <b>Added:</b>
679 }
@@ -756,11 +764,11 @@
756 @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
757 @ [annotate]</a>
758 @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
759 @ [blame]</a>
760 @ %z(href("%R/timeline?uf=%!S",zUuid))[check-ins&nbsp;using]</a>
761 if( fpid>0 ){
762 @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zPUuid,zUuid))[diff]</a>
763 }
764 if( fileedit_is_editable(zFName) ){
765 @ %z(href("%R/fileedit?filename=%T&checkin=%!S",zFName,zCkin))\
766 @ [edit]</a>
767
--- src/finfo.c
+++ src/finfo.c
@@ -185,11 +185,11 @@
185 zLimit = find_option("limit","n",1);
186 zWidth = find_option("width","W",1);
187 iLimit = zLimit ? atoi(zLimit) : -1;
188 zOffset = find_option("offset",0,1);
189 iOffset = zOffset ? atoi(zOffset) : 0;
190 iBrief = find_option("brief","b",0) != 0;
191 if( iLimit==0 ){
192 iLimit = -1;
193 }
194 if( zWidth ){
195 iWidth = atoi(zWidth);
@@ -228,11 +228,11 @@
228 " ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
229 TAG_BRANCH, zFilename, filename_collation(),
230 iLimit, iOffset
231 );
232 blob_zero(&line);
233 if( iBrief == 0 ){
234 fossil_print("History for %s\n", blob_str(&fname));
235 }
236 while( db_step(&q)==SQLITE_ROW ){
237 const char *zFileUuid = db_column_text(&q, 0);
238 const char *zCiUuid = db_column_text(&q,1);
@@ -240,11 +240,11 @@
240 const char *zCom = db_column_text(&q, 3);
241 const char *zUser = db_column_text(&q, 4);
242 const char *zBr = db_column_text(&q, 5);
243 char *zOut;
244 if( zBr==0 ) zBr = "trunk";
245 if( iBrief == 0 ){
246 fossil_print("%s ", zDate);
247 zOut = mprintf(
248 "[%S] %s (user: %s, artifact: [%S], branch: %s)",
249 zCiUuid, zCom, zUser, zFileUuid, zBr);
250 comment_print(zOut, zCom, 11, iWidth, get_comment_format());
@@ -620,10 +620,11 @@
620 int fnid = db_column_int(&q, 13);
621 const char *zFName = db_column_text(&q,14);
622 int gidx;
623 char zTime[10];
624 int nParent = 0;
625 int bIsModified = 0;
626 GraphRowId aParent[GR_MAX_RAIL];
627
628 db_bind_int(&qparent, ":fid", frid);
629 db_bind_int(&qparent, ":mid", fmid);
630 db_bind_int(&qparent, ":fnid", fnid);
@@ -661,19 +662,26 @@
662 @ </td>
663 if( zBgClr && zBgClr[0] ){
664 @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
665 }else{
666 @ <td class="timeline%s(zStyle)Cell">
667 }
668 if( zPUuid && zUuid && fossil_strcmp(zPUuid, zUuid)!=0 ){
669 bIsModified = 1;
670 }
671 if( tmFlags & TIMELINE_COMPACT ){
672 @ <span class='timelineCompactComment' data-id='%d(frid)'>
673 }else{
674 @ <span class='timeline%s(zStyle)Comment'>
675 if( pfnid ){
676 char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
677 pfnid);
678 if( bIsModified ){
679 @ <b>Renamed and modified</b> %h(zPrevName) &rarr; %h(zFName).
680 }else{
681 @ <b>Renamed</b> %h(zPrevName) &rarr; %h(zFName).
682 }
683 fossil_free(zPrevName);
684 }
685 if( zUuid && ridTo==0 && nParent==0 ){
686 @ <b>Added:</b>
687 }
@@ -756,11 +764,11 @@
764 @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
765 @ [annotate]</a>
766 @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
767 @ [blame]</a>
768 @ %z(href("%R/timeline?uf=%!S",zUuid))[check-ins&nbsp;using]</a>
769 if( fpid>0 && bIsModified!=0 ){
770 @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zPUuid,zUuid))[diff]</a>
771 }
772 if( fileedit_is_editable(zFName) ){
773 @ %z(href("%R/fileedit?filename=%T&checkin=%!S",zFName,zCkin))\
774 @ [edit]</a>
775
+63 -35
--- src/forum.c
+++ src/forum.c
@@ -1397,12 +1397,13 @@
13971397
@ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
13981398
@ maxlength="125"><br>
13991399
}
14001400
@ %z(href("%R/markup_help"))Markup style</a>:
14011401
mimetype_option_menu(zMimetype, "mimetype");
1402
- @ <br><textarea aria-label="Content:" name="content" class="wikiedit" \
1403
- @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea><br>
1402
+ @ <div class="forum-editor-widget">
1403
+ @ <textarea aria-label="Content:" name="content" class="wikiedit" \
1404
+ @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea></div>
14041405
}
14051406
14061407
/*
14071408
** WEBPAGE: forumpost_close hidden
14081409
** WEBPAGE: forumpost_reopen hidden
@@ -1760,20 +1761,35 @@
17601761
@ </form>
17611762
forum_emit_js();
17621763
style_finish_page();
17631764
}
17641765
1766
+/*
1767
+** SETTING: forum-close-policy boolean default=off
1768
+** If true, forum moderators may close/re-open forum posts, and reply
1769
+** to closed posts. If false, only administrators may do so. Note that
1770
+** this only affects the forum web UI, not post-closing tags which
1771
+** arrive via the command-line or from synchronization with a remote.
1772
+*/
1773
+/*
1774
+** SETTING: forum-title width=20 default=Forum
1775
+** This is the name or "title" of the Forum for this repository. The
1776
+** default is just "Forum". But in some setups, admins might want to
1777
+** change it to "Developer Forum" or "User Forum" or whatever other name
1778
+** seems more appropriate for the particular usage.
1779
+*/
1780
+
17651781
/*
17661782
** WEBPAGE: setup_forum
17671783
**
17681784
** Forum configuration and metrics.
17691785
*/
17701786
void forum_setup(void){
17711787
/* boolean config settings specific to the forum. */
1772
- const char * zSettingsBool[] = {
1773
- "forum-close-policy",
1774
- NULL /* sentinel entry */
1788
+ static const char *azForumSettings[] = {
1789
+ "forum-close-policy",
1790
+ "forum-title",
17751791
};
17761792
17771793
login_check_credentials();
17781794
if( !g.perm.Setup ){
17791795
login_needed(g.anon.Setup);
@@ -1788,45 +1804,40 @@
17881804
@ <p><a href='%R/forum'>Forum posts</a>:
17891805
@ <a href='%R/timeline?y=f'>%d(nPosts)</a></p>
17901806
}
17911807
17921808
@ <h2>Supervisors</h2>
1793
- @ <p>Users with capabilities 's', 'a', or '6'.</p>
17941809
{
17951810
Stmt q = empty_Stmt;
1796
- int nRows = 0;
17971811
db_prepare(&q, "SELECT uid, login, cap FROM user "
17981812
"WHERE cap GLOB '*[as6]*' ORDER BY login");
17991813
@ <table class='bordered'>
18001814
@ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
18011815
@ <tbody>
18021816
while( SQLITE_ROW==db_step(&q) ){
18031817
const int iUid = db_column_int(&q, 0);
18041818
const char *zUser = db_column_text(&q, 1);
18051819
const char *zCap = db_column_text(&q, 2);
1806
- ++nRows;
18071820
@ <tr>
18081821
@ <td><a href='%R/setup_uedit?id=%d(iUid)'>%h(zUser)</a></td>
18091822
@ <td>(%h(zCap))</td>
18101823
@ </tr>
18111824
}
18121825
db_finalize(&q);
18131826
@</tbody></table>
1814
- if( 0==nRows ){
1815
- @ No supervisors
1816
- }else{
1817
- @ %d(nRows) supervisor(s)
1818
- }
18191827
}
18201828
18211829
@ <h2>Moderators</h2>
1822
- @ <p>Users with capability '5'.</p>
1823
- {
1830
+ if( db_int(0, "SELECT count(*) FROM user "
1831
+ " WHERE cap GLOB '*5*' AND cap NOT GLOB '*[as6]*'")==0 ){
1832
+ @ <p>No non-supervisor moderators
1833
+ }else{
18241834
Stmt q = empty_Stmt;
18251835
int nRows = 0;
18261836
db_prepare(&q, "SELECT uid, login, cap FROM user "
1827
- "WHERE cap GLOB '*5*' ORDER BY login");
1837
+ "WHERE cap GLOB '*5*' AND cap NOT GLOB '*[as6]*'"
1838
+ " ORDER BY login");
18281839
@ <table class='bordered'>
18291840
@ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
18301841
@ <tbody>
18311842
while( SQLITE_ROW==db_step(&q) ){
18321843
const int iUid = db_column_int(&q, 0);
@@ -1838,43 +1849,59 @@
18381849
@ <td>(%h(zCap))</td>
18391850
@ </tr>
18401851
}
18411852
db_finalize(&q);
18421853
@ </tbody></table>
1843
- if( 0==nRows ){
1844
- @ No non-supervisor moderators
1845
- }else{
1846
- @ %d(nRows) moderator(s)
1847
- }
18481854
}
18491855
18501856
@ <h2>Settings</h2>
1851
- @ <p>Configuration settings specific to the forum.</p>
18521857
if( P("submit") && cgi_csrf_safe(2) ){
18531858
int i = 0;
1854
- const char *zSetting;
18551859
db_begin_transaction();
1856
- while( (zSetting = zSettingsBool[i++]) ){
1857
- const char *z = P(zSetting);
1858
- if( !z || !z[0] ) z = "off";
1859
- db_set(zSetting/*works-like:"x"*/, z, 0);
1860
+ for(i=0; i<ArraySize(azForumSettings); i++){
1861
+ char zQP[4];
1862
+ const char *z;
1863
+ const Setting *pSetting = setting_find(azForumSettings[i]);
1864
+ if( pSetting==0 ) continue;
1865
+ zQP[0] = 'a'+i;
1866
+ zQP[1] = zQP[0];
1867
+ zQP[2] = 0;
1868
+ z = P(zQP);
1869
+ if( z==0 || z[0]==0 ) continue;
1870
+ db_set(pSetting->name/*works-like:"x"*/, z, 0);
18601871
}
18611872
db_end_transaction(0);
18621873
@ <p><em>Settings saved.</em></p>
18631874
}
18641875
{
18651876
int i = 0;
1866
- const char *zSetting;
18671877
@ <form action="%R/setup_forum" method="post">
18681878
login_insert_csrf_secret();
18691879
@ <table class='forum-settings-list'><tbody>
1870
- while( (zSetting = zSettingsBool[i++]) ){
1871
- @ <tr><td>
1872
- onoff_attribute("", zSetting, zSetting/*works-like:"x"*/, 0, 0);
1873
- @ </td><td>
1874
- @ <a href='%R/help?cmd=%h(zSetting)'>%h(zSetting)</a>
1875
- @ </td></tr>
1880
+ for(i=0; i<ArraySize(azForumSettings); i++){
1881
+ char zQP[4];
1882
+ const Setting *pSetting = setting_find(azForumSettings[i]);
1883
+ if( pSetting==0 ) continue;
1884
+ zQP[0] = 'a'+i;
1885
+ zQP[1] = zQP[0];
1886
+ zQP[2] = 0;
1887
+ if( pSetting->width==0 ){
1888
+ /* Boolean setting */
1889
+ @ <tr><td align="right">
1890
+ @ <a href='%R/help?cmd=%h(pSetting->name)'>%h(pSetting->name)</a>:
1891
+ @ </td><td>
1892
+ onoff_attribute("", zQP, pSetting->name/*works-like:"x"*/, 0, 0);
1893
+ @ </td></tr>
1894
+ }else{
1895
+ /* Text value setting */
1896
+ @ <tr><td align="right">
1897
+ @ <a href='%R/help?cmd=%h(pSetting->name)'>%h(pSetting->name)</a>:
1898
+ @ </td><td>
1899
+ entry_attribute("", 25, pSetting->name, zQP/*works-like:""*/,
1900
+ pSetting->def, 0);
1901
+ @ </td></tr>
1902
+ }
18761903
}
18771904
@ </tbody></table>
18781905
@ <input type='submit' name='submit' value='Apply changes'>
18791906
@ </form>
18801907
}
@@ -1909,11 +1936,12 @@
19091936
login_needed(g.anon.RdForum);
19101937
return;
19111938
}
19121939
cgi_check_for_malice();
19131940
style_set_current_feature("forum");
1914
- style_header( "%s", isSearch ? "Forum Search Results" : "Forum" );
1941
+ style_header("%s%s", db_get("forum-title","Forum"),
1942
+ isSearch ? " Search Results" : "");
19151943
style_submenu_element("Timeline", "%R/timeline?ss=v&y=f&vfx");
19161944
if( g.perm.WrForum ){
19171945
style_submenu_element("New Thread","%R/forumnew");
19181946
}else{
19191947
/* Can't combine this with previous case using the ternary operator
19201948
--- src/forum.c
+++ src/forum.c
@@ -1397,12 +1397,13 @@
1397 @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
1398 @ maxlength="125"><br>
1399 }
1400 @ %z(href("%R/markup_help"))Markup style</a>:
1401 mimetype_option_menu(zMimetype, "mimetype");
1402 @ <br><textarea aria-label="Content:" name="content" class="wikiedit" \
1403 @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea><br>
 
1404 }
1405
1406 /*
1407 ** WEBPAGE: forumpost_close hidden
1408 ** WEBPAGE: forumpost_reopen hidden
@@ -1760,20 +1761,35 @@
1760 @ </form>
1761 forum_emit_js();
1762 style_finish_page();
1763 }
1764
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1765 /*
1766 ** WEBPAGE: setup_forum
1767 **
1768 ** Forum configuration and metrics.
1769 */
1770 void forum_setup(void){
1771 /* boolean config settings specific to the forum. */
1772 const char * zSettingsBool[] = {
1773 "forum-close-policy",
1774 NULL /* sentinel entry */
1775 };
1776
1777 login_check_credentials();
1778 if( !g.perm.Setup ){
1779 login_needed(g.anon.Setup);
@@ -1788,45 +1804,40 @@
1788 @ <p><a href='%R/forum'>Forum posts</a>:
1789 @ <a href='%R/timeline?y=f'>%d(nPosts)</a></p>
1790 }
1791
1792 @ <h2>Supervisors</h2>
1793 @ <p>Users with capabilities 's', 'a', or '6'.</p>
1794 {
1795 Stmt q = empty_Stmt;
1796 int nRows = 0;
1797 db_prepare(&q, "SELECT uid, login, cap FROM user "
1798 "WHERE cap GLOB '*[as6]*' ORDER BY login");
1799 @ <table class='bordered'>
1800 @ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
1801 @ <tbody>
1802 while( SQLITE_ROW==db_step(&q) ){
1803 const int iUid = db_column_int(&q, 0);
1804 const char *zUser = db_column_text(&q, 1);
1805 const char *zCap = db_column_text(&q, 2);
1806 ++nRows;
1807 @ <tr>
1808 @ <td><a href='%R/setup_uedit?id=%d(iUid)'>%h(zUser)</a></td>
1809 @ <td>(%h(zCap))</td>
1810 @ </tr>
1811 }
1812 db_finalize(&q);
1813 @</tbody></table>
1814 if( 0==nRows ){
1815 @ No supervisors
1816 }else{
1817 @ %d(nRows) supervisor(s)
1818 }
1819 }
1820
1821 @ <h2>Moderators</h2>
1822 @ <p>Users with capability '5'.</p>
1823 {
 
 
1824 Stmt q = empty_Stmt;
1825 int nRows = 0;
1826 db_prepare(&q, "SELECT uid, login, cap FROM user "
1827 "WHERE cap GLOB '*5*' ORDER BY login");
 
1828 @ <table class='bordered'>
1829 @ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
1830 @ <tbody>
1831 while( SQLITE_ROW==db_step(&q) ){
1832 const int iUid = db_column_int(&q, 0);
@@ -1838,43 +1849,59 @@
1838 @ <td>(%h(zCap))</td>
1839 @ </tr>
1840 }
1841 db_finalize(&q);
1842 @ </tbody></table>
1843 if( 0==nRows ){
1844 @ No non-supervisor moderators
1845 }else{
1846 @ %d(nRows) moderator(s)
1847 }
1848 }
1849
1850 @ <h2>Settings</h2>
1851 @ <p>Configuration settings specific to the forum.</p>
1852 if( P("submit") && cgi_csrf_safe(2) ){
1853 int i = 0;
1854 const char *zSetting;
1855 db_begin_transaction();
1856 while( (zSetting = zSettingsBool[i++]) ){
1857 const char *z = P(zSetting);
1858 if( !z || !z[0] ) z = "off";
1859 db_set(zSetting/*works-like:"x"*/, z, 0);
 
 
 
 
 
 
 
1860 }
1861 db_end_transaction(0);
1862 @ <p><em>Settings saved.</em></p>
1863 }
1864 {
1865 int i = 0;
1866 const char *zSetting;
1867 @ <form action="%R/setup_forum" method="post">
1868 login_insert_csrf_secret();
1869 @ <table class='forum-settings-list'><tbody>
1870 while( (zSetting = zSettingsBool[i++]) ){
1871 @ <tr><td>
1872 onoff_attribute("", zSetting, zSetting/*works-like:"x"*/, 0, 0);
1873 @ </td><td>
1874 @ <a href='%R/help?cmd=%h(zSetting)'>%h(zSetting)</a>
1875 @ </td></tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1876 }
1877 @ </tbody></table>
1878 @ <input type='submit' name='submit' value='Apply changes'>
1879 @ </form>
1880 }
@@ -1909,11 +1936,12 @@
1909 login_needed(g.anon.RdForum);
1910 return;
1911 }
1912 cgi_check_for_malice();
1913 style_set_current_feature("forum");
1914 style_header( "%s", isSearch ? "Forum Search Results" : "Forum" );
 
1915 style_submenu_element("Timeline", "%R/timeline?ss=v&y=f&vfx");
1916 if( g.perm.WrForum ){
1917 style_submenu_element("New Thread","%R/forumnew");
1918 }else{
1919 /* Can't combine this with previous case using the ternary operator
1920
--- src/forum.c
+++ src/forum.c
@@ -1397,12 +1397,13 @@
1397 @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
1398 @ maxlength="125"><br>
1399 }
1400 @ %z(href("%R/markup_help"))Markup style</a>:
1401 mimetype_option_menu(zMimetype, "mimetype");
1402 @ <div class="forum-editor-widget">
1403 @ <textarea aria-label="Content:" name="content" class="wikiedit" \
1404 @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea></div>
1405 }
1406
1407 /*
1408 ** WEBPAGE: forumpost_close hidden
1409 ** WEBPAGE: forumpost_reopen hidden
@@ -1760,20 +1761,35 @@
1761 @ </form>
1762 forum_emit_js();
1763 style_finish_page();
1764 }
1765
1766 /*
1767 ** SETTING: forum-close-policy boolean default=off
1768 ** If true, forum moderators may close/re-open forum posts, and reply
1769 ** to closed posts. If false, only administrators may do so. Note that
1770 ** this only affects the forum web UI, not post-closing tags which
1771 ** arrive via the command-line or from synchronization with a remote.
1772 */
1773 /*
1774 ** SETTING: forum-title width=20 default=Forum
1775 ** This is the name or "title" of the Forum for this repository. The
1776 ** default is just "Forum". But in some setups, admins might want to
1777 ** change it to "Developer Forum" or "User Forum" or whatever other name
1778 ** seems more appropriate for the particular usage.
1779 */
1780
1781 /*
1782 ** WEBPAGE: setup_forum
1783 **
1784 ** Forum configuration and metrics.
1785 */
1786 void forum_setup(void){
1787 /* boolean config settings specific to the forum. */
1788 static const char *azForumSettings[] = {
1789 "forum-close-policy",
1790 "forum-title",
1791 };
1792
1793 login_check_credentials();
1794 if( !g.perm.Setup ){
1795 login_needed(g.anon.Setup);
@@ -1788,45 +1804,40 @@
1804 @ <p><a href='%R/forum'>Forum posts</a>:
1805 @ <a href='%R/timeline?y=f'>%d(nPosts)</a></p>
1806 }
1807
1808 @ <h2>Supervisors</h2>
 
1809 {
1810 Stmt q = empty_Stmt;
 
1811 db_prepare(&q, "SELECT uid, login, cap FROM user "
1812 "WHERE cap GLOB '*[as6]*' ORDER BY login");
1813 @ <table class='bordered'>
1814 @ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
1815 @ <tbody>
1816 while( SQLITE_ROW==db_step(&q) ){
1817 const int iUid = db_column_int(&q, 0);
1818 const char *zUser = db_column_text(&q, 1);
1819 const char *zCap = db_column_text(&q, 2);
 
1820 @ <tr>
1821 @ <td><a href='%R/setup_uedit?id=%d(iUid)'>%h(zUser)</a></td>
1822 @ <td>(%h(zCap))</td>
1823 @ </tr>
1824 }
1825 db_finalize(&q);
1826 @</tbody></table>
 
 
 
 
 
1827 }
1828
1829 @ <h2>Moderators</h2>
1830 if( db_int(0, "SELECT count(*) FROM user "
1831 " WHERE cap GLOB '*5*' AND cap NOT GLOB '*[as6]*'")==0 ){
1832 @ <p>No non-supervisor moderators
1833 }else{
1834 Stmt q = empty_Stmt;
1835 int nRows = 0;
1836 db_prepare(&q, "SELECT uid, login, cap FROM user "
1837 "WHERE cap GLOB '*5*' AND cap NOT GLOB '*[as6]*'"
1838 " ORDER BY login");
1839 @ <table class='bordered'>
1840 @ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
1841 @ <tbody>
1842 while( SQLITE_ROW==db_step(&q) ){
1843 const int iUid = db_column_int(&q, 0);
@@ -1838,43 +1849,59 @@
1849 @ <td>(%h(zCap))</td>
1850 @ </tr>
1851 }
1852 db_finalize(&q);
1853 @ </tbody></table>
 
 
 
 
 
1854 }
1855
1856 @ <h2>Settings</h2>
 
1857 if( P("submit") && cgi_csrf_safe(2) ){
1858 int i = 0;
 
1859 db_begin_transaction();
1860 for(i=0; i<ArraySize(azForumSettings); i++){
1861 char zQP[4];
1862 const char *z;
1863 const Setting *pSetting = setting_find(azForumSettings[i]);
1864 if( pSetting==0 ) continue;
1865 zQP[0] = 'a'+i;
1866 zQP[1] = zQP[0];
1867 zQP[2] = 0;
1868 z = P(zQP);
1869 if( z==0 || z[0]==0 ) continue;
1870 db_set(pSetting->name/*works-like:"x"*/, z, 0);
1871 }
1872 db_end_transaction(0);
1873 @ <p><em>Settings saved.</em></p>
1874 }
1875 {
1876 int i = 0;
 
1877 @ <form action="%R/setup_forum" method="post">
1878 login_insert_csrf_secret();
1879 @ <table class='forum-settings-list'><tbody>
1880 for(i=0; i<ArraySize(azForumSettings); i++){
1881 char zQP[4];
1882 const Setting *pSetting = setting_find(azForumSettings[i]);
1883 if( pSetting==0 ) continue;
1884 zQP[0] = 'a'+i;
1885 zQP[1] = zQP[0];
1886 zQP[2] = 0;
1887 if( pSetting->width==0 ){
1888 /* Boolean setting */
1889 @ <tr><td align="right">
1890 @ <a href='%R/help?cmd=%h(pSetting->name)'>%h(pSetting->name)</a>:
1891 @ </td><td>
1892 onoff_attribute("", zQP, pSetting->name/*works-like:"x"*/, 0, 0);
1893 @ </td></tr>
1894 }else{
1895 /* Text value setting */
1896 @ <tr><td align="right">
1897 @ <a href='%R/help?cmd=%h(pSetting->name)'>%h(pSetting->name)</a>:
1898 @ </td><td>
1899 entry_attribute("", 25, pSetting->name, zQP/*works-like:""*/,
1900 pSetting->def, 0);
1901 @ </td></tr>
1902 }
1903 }
1904 @ </tbody></table>
1905 @ <input type='submit' name='submit' value='Apply changes'>
1906 @ </form>
1907 }
@@ -1909,11 +1936,12 @@
1936 login_needed(g.anon.RdForum);
1937 return;
1938 }
1939 cgi_check_for_malice();
1940 style_set_current_feature("forum");
1941 style_header("%s%s", db_get("forum-title","Forum"),
1942 isSearch ? " Search Results" : "");
1943 style_submenu_element("Timeline", "%R/timeline?ss=v&y=f&vfx");
1944 if( g.perm.WrForum ){
1945 style_submenu_element("New Thread","%R/forumnew");
1946 }else{
1947 /* Can't combine this with previous case using the ternary operator
1948
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -6,20 +6,39 @@
66
/**
77
Adds toggle checkboxes to each file entry in the diff views for
88
/info and similar pages.
99
*/
1010
const D = window.fossil.dom;
11
+ const allToggles = [/*collection of all diff-toggle checkboxes */];
1112
const addToggle = function(diffElem){
1213
const sib = diffElem.previousElementSibling,
13
- btn = sib ? D.addClass(D.checkbox(true), 'diff-toggle') : 0;
14
+ btnOne = sib ? D.addClass(D.checkbox(true), 'diff-toggle') : 0;
1415
if(!sib) return;
15
- D.append(sib,btn);
16
- btn.addEventListener('click', function(){
17
- diffElem.classList.toggle('hidden');
16
+ const lblToggle = D.append(D.label(null, " Toggle "), btnOne);
17
+ const wrapper = D.append(D.span(), lblToggle);
18
+ const btnAll = D.button("all");
19
+ btnAll.$cb = btnOne;
20
+ allToggles.push(btnOne);
21
+ D.append(sib, D.append(wrapper, lblToggle, D.text(" "), btnAll));
22
+ btnOne.addEventListener('change', function(){
23
+ diffElem.classList[this.checked ? 'remove' : 'add']('hidden');
24
+ }, false);
25
+ btnAll.addEventListener('click', function(){
26
+ /* Toggle all entries to match this line's new state. Note that
27
+ we use click() instead of cb.checked=... so that the
28
+ on-change event handler fires. */
29
+ const checked = !this.$cb.checked;
30
+ allToggles.forEach( (cb)=>{
31
+ if(cb.checked!==checked) cb.click();
32
+ });
1833
}, false);
1934
};
20
- document.querySelectorAll('table.diff').forEach(addToggle);
35
+ if( !document.querySelector('body.fdiff') ){
36
+ /* Don't show the diff toggle button for /fdiff because it only
37
+ has a single file to show (and also a different DOM layout). */
38
+ document.querySelectorAll('table.diff').forEach(addToggle);
39
+ }
2140
});
2241
2342
window.fossil.onPageLoad(function(){
2443
const F = window.fossil, D = F.dom;
2544
const Diff = F.diff = {
@@ -638,10 +657,11 @@
638657
const potentialParents = [ /* possible parents for the checkbox */
639658
/* Put the most likely pages at the end, as array.pop() is more
640659
efficient than array.shift() (see loop below). */
641660
/* /filedit */ 'body.cpage-fileedit #fileedit-tab-diff-buttons',
642661
/* /wikiedit */ 'body.cpage-wikiedit #wikiedit-tab-diff-buttons',
662
+ /* /fdiff */ 'body.fdiff form div.submenu',
643663
/* /vdiff */ 'body.vdiff form div.submenu',
644664
/* /info, /vinfo */ 'body.vinfo div.sectionmenu.info-changes-menu'
645665
];
646666
while( potentialParents.length ){
647667
if( (eToggleParent = document.querySelector(potentialParents.pop())) ){
648668
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -6,20 +6,39 @@
6 /**
7 Adds toggle checkboxes to each file entry in the diff views for
8 /info and similar pages.
9 */
10 const D = window.fossil.dom;
 
11 const addToggle = function(diffElem){
12 const sib = diffElem.previousElementSibling,
13 btn = sib ? D.addClass(D.checkbox(true), 'diff-toggle') : 0;
14 if(!sib) return;
15 D.append(sib,btn);
16 btn.addEventListener('click', function(){
17 diffElem.classList.toggle('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18 }, false);
19 };
20 document.querySelectorAll('table.diff').forEach(addToggle);
 
 
 
 
21 });
22
23 window.fossil.onPageLoad(function(){
24 const F = window.fossil, D = F.dom;
25 const Diff = F.diff = {
@@ -638,10 +657,11 @@
638 const potentialParents = [ /* possible parents for the checkbox */
639 /* Put the most likely pages at the end, as array.pop() is more
640 efficient than array.shift() (see loop below). */
641 /* /filedit */ 'body.cpage-fileedit #fileedit-tab-diff-buttons',
642 /* /wikiedit */ 'body.cpage-wikiedit #wikiedit-tab-diff-buttons',
 
643 /* /vdiff */ 'body.vdiff form div.submenu',
644 /* /info, /vinfo */ 'body.vinfo div.sectionmenu.info-changes-menu'
645 ];
646 while( potentialParents.length ){
647 if( (eToggleParent = document.querySelector(potentialParents.pop())) ){
648
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -6,20 +6,39 @@
6 /**
7 Adds toggle checkboxes to each file entry in the diff views for
8 /info and similar pages.
9 */
10 const D = window.fossil.dom;
11 const allToggles = [/*collection of all diff-toggle checkboxes */];
12 const addToggle = function(diffElem){
13 const sib = diffElem.previousElementSibling,
14 btnOne = sib ? D.addClass(D.checkbox(true), 'diff-toggle') : 0;
15 if(!sib) return;
16 const lblToggle = D.append(D.label(null, " Toggle "), btnOne);
17 const wrapper = D.append(D.span(), lblToggle);
18 const btnAll = D.button("all");
19 btnAll.$cb = btnOne;
20 allToggles.push(btnOne);
21 D.append(sib, D.append(wrapper, lblToggle, D.text(" "), btnAll));
22 btnOne.addEventListener('change', function(){
23 diffElem.classList[this.checked ? 'remove' : 'add']('hidden');
24 }, false);
25 btnAll.addEventListener('click', function(){
26 /* Toggle all entries to match this line's new state. Note that
27 we use click() instead of cb.checked=... so that the
28 on-change event handler fires. */
29 const checked = !this.$cb.checked;
30 allToggles.forEach( (cb)=>{
31 if(cb.checked!==checked) cb.click();
32 });
33 }, false);
34 };
35 if( !document.querySelector('body.fdiff') ){
36 /* Don't show the diff toggle button for /fdiff because it only
37 has a single file to show (and also a different DOM layout). */
38 document.querySelectorAll('table.diff').forEach(addToggle);
39 }
40 });
41
42 window.fossil.onPageLoad(function(){
43 const F = window.fossil, D = F.dom;
44 const Diff = F.diff = {
@@ -638,10 +657,11 @@
657 const potentialParents = [ /* possible parents for the checkbox */
658 /* Put the most likely pages at the end, as array.pop() is more
659 efficient than array.shift() (see loop below). */
660 /* /filedit */ 'body.cpage-fileedit #fileedit-tab-diff-buttons',
661 /* /wikiedit */ 'body.cpage-wikiedit #wikiedit-tab-diff-buttons',
662 /* /fdiff */ 'body.fdiff form div.submenu',
663 /* /vdiff */ 'body.vdiff form div.submenu',
664 /* /info, /vinfo */ 'body.vinfo div.sectionmenu.info-changes-menu'
665 ];
666 while( potentialParents.length ){
667 if( (eToggleParent = document.querySelector(potentialParents.pop())) ){
668
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -87,11 +87,13 @@
8787
const rc = document.createElement('label');
8888
if(forElem){
8989
if(forElem instanceof HTMLElement){
9090
forElem = this.attr(forElem, 'id');
9191
}
92
- dom.attr(rc, 'for', forElem);
92
+ if(forElem){
93
+ dom.attr(rc, 'for', forElem);
94
+ }
9395
}
9496
if(text) this.append(rc, text);
9597
return rc;
9698
};
9799
/**
98100
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -87,11 +87,13 @@
87 const rc = document.createElement('label');
88 if(forElem){
89 if(forElem instanceof HTMLElement){
90 forElem = this.attr(forElem, 'id');
91 }
92 dom.attr(rc, 'for', forElem);
 
 
93 }
94 if(text) this.append(rc, text);
95 return rc;
96 };
97 /**
98
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -87,11 +87,13 @@
87 const rc = document.createElement('label');
88 if(forElem){
89 if(forElem instanceof HTMLElement){
90 forElem = this.attr(forElem, 'id');
91 }
92 if(forElem){
93 dom.attr(rc, 'for', forElem);
94 }
95 }
96 if(text) this.append(rc, text);
97 return rc;
98 };
99 /**
100
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -2132,11 +2132,11 @@
21322132
s.value ? 'add' : 'remove'
21332133
]('compact');
21342134
Chat.e.inputFields[Chat.e.inputFields.$currentIndex].focus();
21352135
});
21362136
Chat.settings.addListener('edit-ctrl-send',function(s){
2137
- const label = (s.value ? "Ctrl-" : "")+"Enter submits message";
2137
+ const label = (s.value ? "Ctrl-" : "")+"Enter submits message.";
21382138
Chat.e.inputFields.forEach((e)=>{
21392139
const v = e.dataset.placeholder0 + " " +label;
21402140
if(e.isContentEditable) e.dataset.placeholder = v;
21412141
else D.attr(e,'placeholder',v);
21422142
});
21432143
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -2132,11 +2132,11 @@
2132 s.value ? 'add' : 'remove'
2133 ]('compact');
2134 Chat.e.inputFields[Chat.e.inputFields.$currentIndex].focus();
2135 });
2136 Chat.settings.addListener('edit-ctrl-send',function(s){
2137 const label = (s.value ? "Ctrl-" : "")+"Enter submits message";
2138 Chat.e.inputFields.forEach((e)=>{
2139 const v = e.dataset.placeholder0 + " " +label;
2140 if(e.isContentEditable) e.dataset.placeholder = v;
2141 else D.attr(e,'placeholder',v);
2142 });
2143
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -2132,11 +2132,11 @@
2132 s.value ? 'add' : 'remove'
2133 ]('compact');
2134 Chat.e.inputFields[Chat.e.inputFields.$currentIndex].focus();
2135 });
2136 Chat.settings.addListener('edit-ctrl-send',function(s){
2137 const label = (s.value ? "Ctrl-" : "")+"Enter submits message.";
2138 Chat.e.inputFields.forEach((e)=>{
2139 const v = e.dataset.placeholder0 + " " +label;
2140 if(e.isContentEditable) e.dataset.placeholder = v;
2141 else D.attr(e,'placeholder',v);
2142 });
2143
--- src/fossil.page.pikchrshowasm.js
+++ src/fossil.page.pikchrshowasm.js
@@ -206,11 +206,11 @@
206206
const text = getCurrentText();
207207
if(text) PS.render(text);
208208
};
209209
const setCurrentText = function(txt){
210210
taInput.value = txt;
211
- renderCurrentText();
211
+ renderCurrentText();
212212
};
213213
PS.e.btnRender.addEventListener('click',function(ev){
214214
ev.preventDefault();
215215
renderCurrentText();
216216
},false);
@@ -427,13 +427,25 @@
427427
btnToggle.addEventListener('click', function(){
428428
fs.classList.toggle('collapsed');
429429
content.forEach((d)=>d.classList.toggle('hidden'));
430430
}, false);
431431
});
432
+
433
+ if(window.sessionStorage){
434
+ /* If sessionStorage['pikchr-xfer'] exists and the "fromSession"
435
+ URL argument was passed to this page, load the pikchr source
436
+ from the session. This is used by the "open in pikchrshow"
437
+ link in the forum. */
438
+ const src = window.sessionStorage.getItem('pikchr-xfer');
439
+ if( src && (new URL(self.location.href).searchParams).has('fromSession') ){
440
+ taInput.value = src;
441
+ window.sessionStorage.removeItem('pikchr-xfer');
442
+ }
443
+ }
432444
433445
PS.e.btnRender.click();
434
-
446
+
435447
/** Debounce handler for auto-rendering while typing. */
436448
const debounceAutoRender = F.debounce(function f(){
437449
if(!PS._isDirty) return;
438450
const text = getCurrentText();
439451
if(f._ === text){
@@ -618,11 +630,11 @@
618630
"Darlene" above aligned
619631
620632
# fill in content for the Alice lane
621633
right
622634
A1: circle rad 0.1in at end of first line + (0.2,-0.2) \
623
- fill white thickness 1.5px "1"
635
+ fill white thickness 1.5px "1"
624636
arrow right 50%
625637
circle same "2"
626638
arrow right until even with first box.e - (0.65,0.0)
627639
ellipse "future" fit fill white height 0.2 width 0.5 thickness 1.5px
628640
A3: circle same at A1+(0.8,-0.3) "3" fill 0xc0c0c0
629641
--- src/fossil.page.pikchrshowasm.js
+++ src/fossil.page.pikchrshowasm.js
@@ -206,11 +206,11 @@
206 const text = getCurrentText();
207 if(text) PS.render(text);
208 };
209 const setCurrentText = function(txt){
210 taInput.value = txt;
211 renderCurrentText();
212 };
213 PS.e.btnRender.addEventListener('click',function(ev){
214 ev.preventDefault();
215 renderCurrentText();
216 },false);
@@ -427,13 +427,25 @@
427 btnToggle.addEventListener('click', function(){
428 fs.classList.toggle('collapsed');
429 content.forEach((d)=>d.classList.toggle('hidden'));
430 }, false);
431 });
 
 
 
 
 
 
 
 
 
 
 
 
432
433 PS.e.btnRender.click();
434
435 /** Debounce handler for auto-rendering while typing. */
436 const debounceAutoRender = F.debounce(function f(){
437 if(!PS._isDirty) return;
438 const text = getCurrentText();
439 if(f._ === text){
@@ -618,11 +630,11 @@
618 "Darlene" above aligned
619
620 # fill in content for the Alice lane
621 right
622 A1: circle rad 0.1in at end of first line + (0.2,-0.2) \
623 fill white thickness 1.5px "1"
624 arrow right 50%
625 circle same "2"
626 arrow right until even with first box.e - (0.65,0.0)
627 ellipse "future" fit fill white height 0.2 width 0.5 thickness 1.5px
628 A3: circle same at A1+(0.8,-0.3) "3" fill 0xc0c0c0
629
--- src/fossil.page.pikchrshowasm.js
+++ src/fossil.page.pikchrshowasm.js
@@ -206,11 +206,11 @@
206 const text = getCurrentText();
207 if(text) PS.render(text);
208 };
209 const setCurrentText = function(txt){
210 taInput.value = txt;
211 renderCurrentText();
212 };
213 PS.e.btnRender.addEventListener('click',function(ev){
214 ev.preventDefault();
215 renderCurrentText();
216 },false);
@@ -427,13 +427,25 @@
427 btnToggle.addEventListener('click', function(){
428 fs.classList.toggle('collapsed');
429 content.forEach((d)=>d.classList.toggle('hidden'));
430 }, false);
431 });
432
433 if(window.sessionStorage){
434 /* If sessionStorage['pikchr-xfer'] exists and the "fromSession"
435 URL argument was passed to this page, load the pikchr source
436 from the session. This is used by the "open in pikchrshow"
437 link in the forum. */
438 const src = window.sessionStorage.getItem('pikchr-xfer');
439 if( src && (new URL(self.location.href).searchParams).has('fromSession') ){
440 taInput.value = src;
441 window.sessionStorage.removeItem('pikchr-xfer');
442 }
443 }
444
445 PS.e.btnRender.click();
446
447 /** Debounce handler for auto-rendering while typing. */
448 const debounceAutoRender = F.debounce(function f(){
449 if(!PS._isDirty) return;
450 const text = getCurrentText();
451 if(f._ === text){
@@ -618,11 +630,11 @@
630 "Darlene" above aligned
631
632 # fill in content for the Alice lane
633 right
634 A1: circle rad 0.1in at end of first line + (0.2,-0.2) \
635 fill white thickness 1.5px "1"
636 arrow right 50%
637 circle same "2"
638 arrow right until even with first box.e - (0.65,0.0)
639 ellipse "future" fit fill white height 0.2 width 0.5 thickness 1.5px
640 A3: circle same at A1+(0.8,-0.3) "3" fill 0xc0c0c0
641
--- src/fossil.pikchr.js
+++ src/fossil.pikchr.js
@@ -38,11 +38,14 @@
3838
This code expects the following structure around the SVGs, and
3939
will not process any which don't match this:
4040
4141
<DIV.pikchr-wrapper>
4242
<DIV.pikchr-svg><SVG.pikchr></SVG></DIV>
43
- <PRE.pikchr-src></PRE>
43
+ <DIV.pikchr-src>
44
+ <PRE>pikchr source code</PRE>
45
+ <SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
46
+ </DIV>
4447
</DIV>
4548
*/
4649
P.addSrcView = function f(svg){
4750
if(!f.hasOwnProperty('parentClick')){
4851
f.parentClick = function(ev){
@@ -58,10 +61,46 @@
5861
this.classList.toggle('source');
5962
ev.stopPropagation();
6063
ev.preventDefault();
6164
}
6265
};
66
+ /**
67
+ Event handler for the "open in pikchrshow" links: store the
68
+ source code for the link's pikchr in
69
+ window.sessionStorage['pikchr-xfer'] then open
70
+ /pikchrshow?fromSession to trigger loading of that pikchr.
71
+ */
72
+ f.clickPikchrShow = function(ev){
73
+ const pId = this.dataset['pikchrid'] /* ID of the associated pikchr source code element */;
74
+ if(!pId) return;
75
+ const ePikchr = this.parentNode.parentNode.querySelector('#'+pId);
76
+ if(!ePikchr) return;
77
+ ev.stopPropagation() /* keep pikchr source view from toggling */;
78
+ window.sessionStorage.setItem('pikchr-xfer', ePikchr.innerText);
79
+ /*
80
+ After returning from this function the link element will
81
+ open [/pikchrshow?fromSession], and pikchrshow will extract
82
+ the pikchr source code from sessionStorage['pikchr-xfer'].
83
+
84
+ Quirks of this ^^^ design:
85
+
86
+ We use only a single slot in sessionStorage. We could
87
+ alternately use a key like pikchr-$pId and pass that key on
88
+ to /pikchrshow via fromSession=pikchr-$pId, but that would
89
+ eventually lead to stale session entries if loading of
90
+ pikchrshow were interrupted at an untimely point. The
91
+ down-side of _not_ doing that is that some user (or
92
+ automation) options multiple "open in pikchrshow" links
93
+ rapidly enough, the will open the same pikchr (the one which
94
+ was stored in the session's slot most recently). The
95
+ current approach should be fine for normal human interaction
96
+ speeds, but if it proves to be a problem we can instead use
97
+ the above-described approach of storing each pikchr in its
98
+ own session slot and simply accept that there may be stale
99
+ entries at some point.
100
+ */
101
+ };
63102
};
64103
if(!svg) svg = 'svg.pikchr';
65104
if('string' === typeof svg){
66105
document.querySelectorAll(svg).forEach((e)=>f.call(this, e));
67106
return this;
@@ -71,15 +110,24 @@
71110
}
72111
if(svg.dataset.pikchrProcessed){
73112
return this;
74113
}
75114
svg.dataset.pikchrProcessed = 1;
76
- const parent = svg.parentNode.parentNode /* outermost div.pikchr-wrapper */;
77
- const srcView = parent ? svg.parentNode.nextElementSibling : undefined;
78
- if(!srcView || !srcView.classList.contains('pikchr-src')){
115
+ const parent = svg.parentNode.parentNode /* outermost DIV.pikchr-wrapper */;
116
+ const srcView = parent ? svg.parentNode.nextElementSibling /* DIV.pikchr-src */ : undefined;
117
+ if(srcView && srcView.classList.contains('pikchr-src')){
79118
/* Without this element, there's nothing for us to do here. */
80
- return this;
119
+ parent.addEventListener('click', f.parentClick, false);
120
+ const eSpan = window.sessionStorage
121
+ ? srcView.querySelector('span') /* "open in..." link wrapper */
122
+ : undefined;
123
+ if(eSpan){
124
+ const openLink = eSpan.querySelector('a');
125
+ if(openLink){
126
+ openLink.addEventListener('click', f.clickPikchrShow, false);
127
+ eSpan.classList.remove('hidden');
128
+ }
129
+ }
81130
}
82
- parent.addEventListener('click', f.parentClick, false);
83131
return this;
84132
};
85133
})(window.fossil);
86134
--- src/fossil.pikchr.js
+++ src/fossil.pikchr.js
@@ -38,11 +38,14 @@
38 This code expects the following structure around the SVGs, and
39 will not process any which don't match this:
40
41 <DIV.pikchr-wrapper>
42 <DIV.pikchr-svg><SVG.pikchr></SVG></DIV>
43 <PRE.pikchr-src></PRE>
 
 
 
44 </DIV>
45 */
46 P.addSrcView = function f(svg){
47 if(!f.hasOwnProperty('parentClick')){
48 f.parentClick = function(ev){
@@ -58,10 +61,46 @@
58 this.classList.toggle('source');
59 ev.stopPropagation();
60 ev.preventDefault();
61 }
62 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63 };
64 if(!svg) svg = 'svg.pikchr';
65 if('string' === typeof svg){
66 document.querySelectorAll(svg).forEach((e)=>f.call(this, e));
67 return this;
@@ -71,15 +110,24 @@
71 }
72 if(svg.dataset.pikchrProcessed){
73 return this;
74 }
75 svg.dataset.pikchrProcessed = 1;
76 const parent = svg.parentNode.parentNode /* outermost div.pikchr-wrapper */;
77 const srcView = parent ? svg.parentNode.nextElementSibling : undefined;
78 if(!srcView || !srcView.classList.contains('pikchr-src')){
79 /* Without this element, there's nothing for us to do here. */
80 return this;
 
 
 
 
 
 
 
 
 
 
81 }
82 parent.addEventListener('click', f.parentClick, false);
83 return this;
84 };
85 })(window.fossil);
86
--- src/fossil.pikchr.js
+++ src/fossil.pikchr.js
@@ -38,11 +38,14 @@
38 This code expects the following structure around the SVGs, and
39 will not process any which don't match this:
40
41 <DIV.pikchr-wrapper>
42 <DIV.pikchr-svg><SVG.pikchr></SVG></DIV>
43 <DIV.pikchr-src>
44 <PRE>pikchr source code</PRE>
45 <SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
46 </DIV>
47 </DIV>
48 */
49 P.addSrcView = function f(svg){
50 if(!f.hasOwnProperty('parentClick')){
51 f.parentClick = function(ev){
@@ -58,10 +61,46 @@
61 this.classList.toggle('source');
62 ev.stopPropagation();
63 ev.preventDefault();
64 }
65 };
66 /**
67 Event handler for the "open in pikchrshow" links: store the
68 source code for the link's pikchr in
69 window.sessionStorage['pikchr-xfer'] then open
70 /pikchrshow?fromSession to trigger loading of that pikchr.
71 */
72 f.clickPikchrShow = function(ev){
73 const pId = this.dataset['pikchrid'] /* ID of the associated pikchr source code element */;
74 if(!pId) return;
75 const ePikchr = this.parentNode.parentNode.querySelector('#'+pId);
76 if(!ePikchr) return;
77 ev.stopPropagation() /* keep pikchr source view from toggling */;
78 window.sessionStorage.setItem('pikchr-xfer', ePikchr.innerText);
79 /*
80 After returning from this function the link element will
81 open [/pikchrshow?fromSession], and pikchrshow will extract
82 the pikchr source code from sessionStorage['pikchr-xfer'].
83
84 Quirks of this ^^^ design:
85
86 We use only a single slot in sessionStorage. We could
87 alternately use a key like pikchr-$pId and pass that key on
88 to /pikchrshow via fromSession=pikchr-$pId, but that would
89 eventually lead to stale session entries if loading of
90 pikchrshow were interrupted at an untimely point. The
91 down-side of _not_ doing that is that some user (or
92 automation) options multiple "open in pikchrshow" links
93 rapidly enough, the will open the same pikchr (the one which
94 was stored in the session's slot most recently). The
95 current approach should be fine for normal human interaction
96 speeds, but if it proves to be a problem we can instead use
97 the above-described approach of storing each pikchr in its
98 own session slot and simply accept that there may be stale
99 entries at some point.
100 */
101 };
102 };
103 if(!svg) svg = 'svg.pikchr';
104 if('string' === typeof svg){
105 document.querySelectorAll(svg).forEach((e)=>f.call(this, e));
106 return this;
@@ -71,15 +110,24 @@
110 }
111 if(svg.dataset.pikchrProcessed){
112 return this;
113 }
114 svg.dataset.pikchrProcessed = 1;
115 const parent = svg.parentNode.parentNode /* outermost DIV.pikchr-wrapper */;
116 const srcView = parent ? svg.parentNode.nextElementSibling /* DIV.pikchr-src */ : undefined;
117 if(srcView && srcView.classList.contains('pikchr-src')){
118 /* Without this element, there's nothing for us to do here. */
119 parent.addEventListener('click', f.parentClick, false);
120 const eSpan = window.sessionStorage
121 ? srcView.querySelector('span') /* "open in..." link wrapper */
122 : undefined;
123 if(eSpan){
124 const openLink = eSpan.querySelector('a');
125 if(openLink){
126 openLink.addEventListener('click', f.clickPikchrShow, false);
127 eSpan.classList.remove('hidden');
128 }
129 }
130 }
 
131 return this;
132 };
133 })(window.fossil);
134
+2 -2
--- src/glob.c
+++ src/glob.c
@@ -34,12 +34,12 @@
3434
** Commas and whitespace are considered to be element delimters. Each
3535
** element of the GLOB list may optionally be enclosed in either '...' or
3636
** "...". This allows commas and/or whitespace to be used in the elements
3737
** themselves.
3838
**
39
-** This routine makes no effort to free the memory space it uses, which
40
-** currently consists of a blob object and its contents.
39
+** The returned string is owned by the caller, who must fossil_free()
40
+** it.
4141
*/
4242
char *glob_expr(const char *zVal, const char *zGlobList){
4343
Blob expr;
4444
const char *zSep = "(";
4545
int nTerm = 0;
4646
--- src/glob.c
+++ src/glob.c
@@ -34,12 +34,12 @@
34 ** Commas and whitespace are considered to be element delimters. Each
35 ** element of the GLOB list may optionally be enclosed in either '...' or
36 ** "...". This allows commas and/or whitespace to be used in the elements
37 ** themselves.
38 **
39 ** This routine makes no effort to free the memory space it uses, which
40 ** currently consists of a blob object and its contents.
41 */
42 char *glob_expr(const char *zVal, const char *zGlobList){
43 Blob expr;
44 const char *zSep = "(";
45 int nTerm = 0;
46
--- src/glob.c
+++ src/glob.c
@@ -34,12 +34,12 @@
34 ** Commas and whitespace are considered to be element delimters. Each
35 ** element of the GLOB list may optionally be enclosed in either '...' or
36 ** "...". This allows commas and/or whitespace to be used in the elements
37 ** themselves.
38 **
39 ** The returned string is owned by the caller, who must fossil_free()
40 ** it.
41 */
42 char *glob_expr(const char *zVal, const char *zGlobList){
43 Blob expr;
44 const char *zSep = "(";
45 int nTerm = 0;
46
+6
--- src/http.c
+++ src/http.c
@@ -768,10 +768,11 @@
768768
** a GET request where there is no PAYLOAD.
769769
**
770770
** Options:
771771
** --compress Use ZLIB compression on the payload
772772
** --mimetype TYPE Mimetype of the payload
773
+** --no-cert-verify Disable TLS cert verification
773774
** --out FILE Store the reply in FILE
774775
** -v Verbose output
775776
** --xfer PAYLOAD in a Fossil xfer protocol message
776777
*/
777778
void test_httpmsg_command(void){
@@ -783,10 +784,15 @@
783784
784785
zMimetype = find_option("mimetype",0,1);
785786
zOutFile = find_option("out","o",1);
786787
if( find_option("verbose","v",0)!=0 ) mHttpFlags |= HTTP_VERBOSE;
787788
if( find_option("compress",0,0)!=0 ) mHttpFlags &= ~HTTP_NOCOMPRESS;
789
+ if( find_option("no-cert-verify",0,0)!=0 ){
790
+ #ifdef FOSSIL_ENABLE_SSL
791
+ ssl_disable_cert_verification();
792
+ #endif
793
+ }
788794
if( find_option("xfer",0,0)!=0 ){
789795
mHttpFlags |= HTTP_USE_LOGIN;
790796
mHttpFlags &= ~HTTP_GENERIC;
791797
}
792798
verify_all_options();
793799
--- src/http.c
+++ src/http.c
@@ -768,10 +768,11 @@
768 ** a GET request where there is no PAYLOAD.
769 **
770 ** Options:
771 ** --compress Use ZLIB compression on the payload
772 ** --mimetype TYPE Mimetype of the payload
 
773 ** --out FILE Store the reply in FILE
774 ** -v Verbose output
775 ** --xfer PAYLOAD in a Fossil xfer protocol message
776 */
777 void test_httpmsg_command(void){
@@ -783,10 +784,15 @@
783
784 zMimetype = find_option("mimetype",0,1);
785 zOutFile = find_option("out","o",1);
786 if( find_option("verbose","v",0)!=0 ) mHttpFlags |= HTTP_VERBOSE;
787 if( find_option("compress",0,0)!=0 ) mHttpFlags &= ~HTTP_NOCOMPRESS;
 
 
 
 
 
788 if( find_option("xfer",0,0)!=0 ){
789 mHttpFlags |= HTTP_USE_LOGIN;
790 mHttpFlags &= ~HTTP_GENERIC;
791 }
792 verify_all_options();
793
--- src/http.c
+++ src/http.c
@@ -768,10 +768,11 @@
768 ** a GET request where there is no PAYLOAD.
769 **
770 ** Options:
771 ** --compress Use ZLIB compression on the payload
772 ** --mimetype TYPE Mimetype of the payload
773 ** --no-cert-verify Disable TLS cert verification
774 ** --out FILE Store the reply in FILE
775 ** -v Verbose output
776 ** --xfer PAYLOAD in a Fossil xfer protocol message
777 */
778 void test_httpmsg_command(void){
@@ -783,10 +784,15 @@
784
785 zMimetype = find_option("mimetype",0,1);
786 zOutFile = find_option("out","o",1);
787 if( find_option("verbose","v",0)!=0 ) mHttpFlags |= HTTP_VERBOSE;
788 if( find_option("compress",0,0)!=0 ) mHttpFlags &= ~HTTP_NOCOMPRESS;
789 if( find_option("no-cert-verify",0,0)!=0 ){
790 #ifdef FOSSIL_ENABLE_SSL
791 ssl_disable_cert_verification();
792 #endif
793 }
794 if( find_option("xfer",0,0)!=0 ){
795 mHttpFlags |= HTTP_USE_LOGIN;
796 mHttpFlags &= ~HTTP_GENERIC;
797 }
798 verify_all_options();
799
+4 -6
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -403,16 +403,14 @@
403403
blob_append(&reply, buf, len);
404404
405405
bbuf = blob_buffer(&reply);
406406
len = blob_size(&reply);
407407
while(end < len) {
408
- if(bbuf[end] == '\r') {
409
- if(len - end < 4) {
410
- /* need more data */
411
- break;
412
- }
413
- if(memcmp(&bbuf[end], "\r\n\r\n", 4) == 0) {
408
+ if( bbuf[end]=='\n' ) {
409
+ if( (end+1<len && bbuf[end+1]=='\n')
410
+ || (end+2<len && bbuf[end+1]=='\r' && bbuf[end+2]=='\n')
411
+ ){
414412
done = 1;
415413
break;
416414
}
417415
}
418416
end++;
419417
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -403,16 +403,14 @@
403 blob_append(&reply, buf, len);
404
405 bbuf = blob_buffer(&reply);
406 len = blob_size(&reply);
407 while(end < len) {
408 if(bbuf[end] == '\r') {
409 if(len - end < 4) {
410 /* need more data */
411 break;
412 }
413 if(memcmp(&bbuf[end], "\r\n\r\n", 4) == 0) {
414 done = 1;
415 break;
416 }
417 }
418 end++;
419
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -403,16 +403,14 @@
403 blob_append(&reply, buf, len);
404
405 bbuf = blob_buffer(&reply);
406 len = blob_size(&reply);
407 while(end < len) {
408 if( bbuf[end]=='\n' ) {
409 if( (end+1<len && bbuf[end+1]=='\n')
410 || (end+2<len && bbuf[end+1]=='\r' && bbuf[end+2]=='\n')
411 ){
 
 
412 done = 1;
413 break;
414 }
415 }
416 end++;
417
--- src/http_transport.c
+++ src/http_transport.c
@@ -103,11 +103,14 @@
103103
/*
104104
** Initialize a Blob to the name of the configured SSH command.
105105
*/
106106
void transport_ssh_command(Blob *p){
107107
char *zSsh; /* The base SSH command */
108
- zSsh = db_get("ssh-command", zDefaultSshCmd);
108
+ zSsh = g.zSshCmd;
109
+ if( zSsh==0 || zSsh[0]==0 ){
110
+ zSsh = db_get("ssh-command", zDefaultSshCmd);
111
+ }
109112
blob_init(p, zSsh, -1);
110113
}
111114
112115
/*
113116
** SSH initialization of the transport layer
114117
--- src/http_transport.c
+++ src/http_transport.c
@@ -103,11 +103,14 @@
103 /*
104 ** Initialize a Blob to the name of the configured SSH command.
105 */
106 void transport_ssh_command(Blob *p){
107 char *zSsh; /* The base SSH command */
108 zSsh = db_get("ssh-command", zDefaultSshCmd);
 
 
 
109 blob_init(p, zSsh, -1);
110 }
111
112 /*
113 ** SSH initialization of the transport layer
114
--- src/http_transport.c
+++ src/http_transport.c
@@ -103,11 +103,14 @@
103 /*
104 ** Initialize a Blob to the name of the configured SSH command.
105 */
106 void transport_ssh_command(Blob *p){
107 char *zSsh; /* The base SSH command */
108 zSsh = g.zSshCmd;
109 if( zSsh==0 || zSsh[0]==0 ){
110 zSsh = db_get("ssh-command", zDefaultSshCmd);
111 }
112 blob_init(p, zSsh, -1);
113 }
114
115 /*
116 ** SSH initialization of the transport layer
117
+152 -17
--- src/info.c
+++ src/info.c
@@ -372,11 +372,13 @@
372372
const char *zNew, /* blob.uuid after change. NULL for deletes */
373373
const char *zOldName, /* Prior name. NULL if no name change. */
374374
DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
375375
int mperm /* executable or symlink permission for zNew */
376376
){
377
- @ <p>
377
+ @ <div class='file-change-line'><span>
378
+ /* Maintenance reminder: the extra level of SPAN is for
379
+ ** arranging new elements via JS. */
378380
if( !g.perm.Hyperlink ){
379381
if( zNew==0 ){
380382
@ Deleted %h(zName).
381383
}else if( zOld==0 ){
382384
@ Added %h(zName).
@@ -391,10 +393,11 @@
391393
@ %h(zName) became a regular file.
392394
}
393395
}else{
394396
@ Changes to %h(zName).
395397
}
398
+ @ </span></div>
396399
if( pCfg ){
397400
append_diff(zOld, zNew, pCfg);
398401
}
399402
}else{
400403
if( zOld && zNew ){
@@ -436,18 +439,22 @@
436439
@ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
437440
}else{
438441
@ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
439442
@ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
440443
}
441
- if( pCfg ){
442
- append_diff(zOld, zNew, pCfg);
443
- }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
444
- @ &nbsp;&nbsp;
445
- @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
444
+ if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
445
+ if( pCfg ){
446
+ @ </span></div>
447
+ append_diff(zOld, zNew, pCfg);
448
+ }else{
449
+ @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
450
+ @ </span></div>
451
+ }
452
+ }else{
453
+ @ </span></div>
446454
}
447455
}
448
- @ </p>
449456
}
450457
451458
/*
452459
** Generate javascript to enhance HTML diffs.
453460
*/
@@ -600,10 +607,130 @@
600607
www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
601608
0, 0, 0, rid, 0, 0);
602609
db_finalize(&q);
603610
style_finish_page();
604611
}
612
+
613
+/*
614
+** WEBPAGE: ckout
615
+**
616
+** Show information about the current checkout. This page only functions
617
+** if the web server is run on a loopback interface (in other words, was
618
+** started using "fossil ui" or similar) from with on open check-out.
619
+*/
620
+void ckout_page(void){
621
+ int vid;
622
+ char *zHostname;
623
+ char *zCwd;
624
+ int diffType; /* 0: no diff, 1: unified, 2: side-by-side */
625
+ DiffConfig DCfg,*pCfg; /* Diff details */
626
+ const char *zHome; /* Home directory */
627
+ Stmt q;
628
+
629
+ if( !db_open_local(0) || !cgi_is_loopback(g.zIpAddr) ){
630
+ cgi_redirect("%R/home");
631
+ return;
632
+ }
633
+ diffType = preferred_diff_type();
634
+ pCfg = construct_diff_flags(diffType, &DCfg);
635
+ vid = db_lget_int("checkout", 0);
636
+ db_unprotect(PROTECT_ALL);
637
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
638
+ db_protect_pop();
639
+ style_set_current_feature("vinfo");
640
+ zHostname = fossil_hostname();
641
+ zCwd = file_getcwd(0,0);
642
+ zHome = fossil_getenv("HOME");
643
+ if( zHome ){
644
+ int nHome = (int)strlen(zHome);
645
+ if( strncmp(zCwd, zHome, nHome)==0 && zCwd[nHome]=='/' ){
646
+ zCwd = mprintf("~%s", zCwd+nHome);
647
+ }
648
+ }
649
+ if( zHostname ){
650
+ style_header("Checkout Status: %h on %h", zCwd, zHostname);
651
+ }else{
652
+ style_header("Checkout Status: %h", zCwd);
653
+ }
654
+ render_checkin_context(vid, 0, 0, 0);
655
+ if( pCfg==0 ){
656
+ style_finish_page();
657
+ return;
658
+ }
659
+ db_prepare(&q,
660
+ /* 0 1 2 3 4 5 6 */
661
+ "SELECT pathname, deleted, chnged , rid==0, rid, islink, uuid"
662
+ " FROM vfile LEFT JOIN blob USING(rid)"
663
+ " WHERE vid=%d"
664
+ " AND (deleted OR chnged OR rid==0)"
665
+ " ORDER BY pathname /*scan*/",
666
+ vid
667
+ );
668
+ if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
669
+ pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
670
+ }else{
671
+ pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
672
+ }
673
+ while( db_step(&q)==SQLITE_ROW ){
674
+ const char *zTreename = db_column_text(&q,0);
675
+ int isDeleted = db_column_int(&q, 1);
676
+ int isChnged = db_column_int(&q,2);
677
+ int isNew = db_column_int(&q,3);
678
+ int srcid = db_column_int(&q, 4);
679
+ int isLink = db_column_int(&q, 5);
680
+ const char *zUuid = db_column_text(&q, 6);
681
+ int showDiff = 1;
682
+
683
+ pCfg->diffFlags &= (~DIFF_FILE_MASK);
684
+ if( isDeleted ){
685
+ @ <p>DELETED %h(zTreename)</p>
686
+ pCfg->diffFlags |= DIFF_FILE_DELETED;
687
+ showDiff = 0;
688
+ }else if( file_access(zTreename, F_OK) ){
689
+ @ <p>MISSING %h(zTreename)</p>
690
+ showDiff = 0;
691
+ }else if( isNew ){
692
+ @ <p>ADDED %h(zTreename)</p>
693
+ pCfg->diffFlags |= DIFF_FILE_ADDED;
694
+ srcid = 0;
695
+ showDiff = 0;
696
+ }else if( isChnged==3 ){
697
+ @ <p>ADDED_BY_MERGE %h(zTreename)</p>
698
+ pCfg->diffFlags |= DIFF_FILE_ADDED;
699
+ srcid = 0;
700
+ showDiff = 0;
701
+ }else if( isChnged==5 ){
702
+ @ <p>ADDED_BY_INTEGRATE %h(zTreename)</p>
703
+ pCfg->diffFlags |= DIFF_FILE_ADDED;
704
+ srcid = 0;
705
+ showDiff = 0;
706
+ }else{
707
+ @ <p>CHANGED %h(zTreename)</p>
708
+ }
709
+ if( showDiff ){
710
+ Blob old, new;
711
+ if( !isLink != !file_islink(zTreename) ){
712
+ @ %s(DIFF_CANNOT_COMPUTE_SYMLINK)
713
+ continue;
714
+ }
715
+ if( srcid>0 ){
716
+ content_get(srcid, &old);
717
+ pCfg->zLeftHash = zUuid;
718
+ }else{
719
+ blob_zero(&old);
720
+ pCfg->zLeftHash = 0;
721
+ }
722
+ blob_read_from_file(&new, zTreename, ExtFILE);
723
+ text_diff(&old, &new, cgi_output_blob(), pCfg);
724
+ blob_reset(&old);
725
+ blob_reset(&new);
726
+ }
727
+ }
728
+ db_finalize(&q);
729
+ append_diff_javascript(diffType);
730
+ style_finish_page();
731
+}
605732
606733
/*
607734
** WEBPAGE: vinfo
608735
** WEBPAGE: ci
609736
** URL: /ci/ARTIFACTID
@@ -1191,22 +1318,25 @@
11911318
const char *zBranch;
11921319
const char *zFrom;
11931320
const char *zTo;
11941321
const char *zRe;
11951322
const char *zGlob;
1323
+ Glob * pGlob = 0;
11961324
char *zMergeOrigin = 0;
11971325
ReCompiled *pRe = 0;
11981326
DiffConfig DCfg, *pCfg = 0;
11991327
int graphFlags = 0;
1200
- Blob qp;
1328
+ Blob qp; /* non-glob= query parameters for generated links */
1329
+ Blob qpGlob; /* glob= query parameter for generated links */
12011330
int bInvert = PB("inv");
12021331
12031332
login_check_credentials();
12041333
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
12051334
login_anonymous_available();
12061335
fossil_nice_default();
12071336
blob_init(&qp, 0, 0);
1337
+ blob_init(&qpGlob, 0, 0);
12081338
diffType = preferred_diff_type();
12091339
zRe = P("regex");
12101340
if( zRe ) re_compile(&pRe, zRe, 0);
12111341
zBranch = P("branch");
12121342
if( zBranch && zBranch[0]==0 ) zBranch = 0;
@@ -1246,11 +1376,12 @@
12461376
}
12471377
if( zGlob ){
12481378
if( !*zGlob ){
12491379
zGlob = NULL;
12501380
}else{
1251
- blob_appendf(&qp, "&glob=%T", zGlob);
1381
+ blob_appendf(&qpGlob, "&glob=%T", zGlob);
1382
+ pGlob = glob_create(zGlob);
12521383
}
12531384
}
12541385
if( PB("nc") ){
12551386
graphFlags |= TIMELINE_NOCOLOR;
12561387
blob_appendf(&qp, "&nc");
@@ -1263,20 +1394,22 @@
12631394
style_set_current_feature("vdiff");
12641395
if( zBranch==0 ){
12651396
style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
12661397
}
12671398
if( diffType!=0 ){
1268
- style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b", &qp);
1399
+ style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b%b", &qp, &qpGlob);
12691400
}
12701401
if( diffType!=2 ){
1271
- style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b", &qp);
1402
+ style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b%b", &qp,
1403
+ &qpGlob);
12721404
}
12731405
if( diffType!=1 ) {
1274
- style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b", &qp);
1406
+ style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b%b", &qp, &qpGlob);
12751407
}
12761408
if( zBranch==0 ){
1277
- style_submenu_element("Invert","%R/vdiff?diff=%d&inv&%b", diffType, &qp);
1409
+ style_submenu_element("Invert","%R/vdiff?diff=%d&inv&%b%b", diffType,
1410
+ &qp, &qpGlob);
12781411
}
12791412
if( zGlob ){
12801413
style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
12811414
}else{
12821415
style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
@@ -1321,10 +1454,11 @@
13211454
@ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p>
13221455
}
13231456
@<hr><p>
13241457
}
13251458
blob_reset(&qp);
1459
+ blob_reset(&qpGlob);
13261460
13271461
manifest_file_rewind(pFrom);
13281462
pFileFrom = manifest_file_next(pFrom, 0);
13291463
manifest_file_rewind(pTo);
13301464
pFileTo = manifest_file_next(pTo, 0);
@@ -1337,37 +1471,38 @@
13371471
cmp = -1;
13381472
}else{
13391473
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
13401474
}
13411475
if( cmp<0 ){
1342
- if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
1476
+ if( !pGlob || glob_match(pGlob, pFileFrom->zName) ){
13431477
append_file_change_line(zFrom, pFileFrom->zName,
13441478
pFileFrom->zUuid, 0, 0, pCfg, 0);
13451479
}
13461480
pFileFrom = manifest_file_next(pFrom, 0);
13471481
}else if( cmp>0 ){
1348
- if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
1482
+ if( !pGlob || glob_match(pGlob, pFileTo->zName) ){
13491483
append_file_change_line(zTo, pFileTo->zName,
13501484
0, pFileTo->zUuid, 0, pCfg,
13511485
manifest_file_mperm(pFileTo));
13521486
}
13531487
pFileTo = manifest_file_next(pTo, 0);
13541488
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
13551489
pFileFrom = manifest_file_next(pFrom, 0);
13561490
pFileTo = manifest_file_next(pTo, 0);
13571491
}else{
1358
- if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
1359
- || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
1492
+ if(!pGlob || (glob_match(pGlob, pFileFrom->zName)
1493
+ || glob_match(pGlob, pFileTo->zName)) ){
13601494
append_file_change_line(zFrom, pFileFrom->zName,
13611495
pFileFrom->zUuid,
13621496
pFileTo->zUuid, 0, pCfg,
13631497
manifest_file_mperm(pFileTo));
13641498
}
13651499
pFileFrom = manifest_file_next(pFrom, 0);
13661500
pFileTo = manifest_file_next(pTo, 0);
13671501
}
13681502
}
1503
+ glob_free(pGlob);
13691504
manifest_destroy(pFrom);
13701505
manifest_destroy(pTo);
13711506
append_diff_javascript(diffType);
13721507
style_finish_page();
13731508
}
13741509
--- src/info.c
+++ src/info.c
@@ -372,11 +372,13 @@
372 const char *zNew, /* blob.uuid after change. NULL for deletes */
373 const char *zOldName, /* Prior name. NULL if no name change. */
374 DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
375 int mperm /* executable or symlink permission for zNew */
376 ){
377 @ <p>
 
 
378 if( !g.perm.Hyperlink ){
379 if( zNew==0 ){
380 @ Deleted %h(zName).
381 }else if( zOld==0 ){
382 @ Added %h(zName).
@@ -391,10 +393,11 @@
391 @ %h(zName) became a regular file.
392 }
393 }else{
394 @ Changes to %h(zName).
395 }
 
396 if( pCfg ){
397 append_diff(zOld, zNew, pCfg);
398 }
399 }else{
400 if( zOld && zNew ){
@@ -436,18 +439,22 @@
436 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
437 }else{
438 @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
439 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
440 }
441 if( pCfg ){
442 append_diff(zOld, zNew, pCfg);
443 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
444 @ &nbsp;&nbsp;
445 @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
 
 
 
 
 
446 }
447 }
448 @ </p>
449 }
450
451 /*
452 ** Generate javascript to enhance HTML diffs.
453 */
@@ -600,10 +607,130 @@
600 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
601 0, 0, 0, rid, 0, 0);
602 db_finalize(&q);
603 style_finish_page();
604 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
606 /*
607 ** WEBPAGE: vinfo
608 ** WEBPAGE: ci
609 ** URL: /ci/ARTIFACTID
@@ -1191,22 +1318,25 @@
1191 const char *zBranch;
1192 const char *zFrom;
1193 const char *zTo;
1194 const char *zRe;
1195 const char *zGlob;
 
1196 char *zMergeOrigin = 0;
1197 ReCompiled *pRe = 0;
1198 DiffConfig DCfg, *pCfg = 0;
1199 int graphFlags = 0;
1200 Blob qp;
 
1201 int bInvert = PB("inv");
1202
1203 login_check_credentials();
1204 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1205 login_anonymous_available();
1206 fossil_nice_default();
1207 blob_init(&qp, 0, 0);
 
1208 diffType = preferred_diff_type();
1209 zRe = P("regex");
1210 if( zRe ) re_compile(&pRe, zRe, 0);
1211 zBranch = P("branch");
1212 if( zBranch && zBranch[0]==0 ) zBranch = 0;
@@ -1246,11 +1376,12 @@
1246 }
1247 if( zGlob ){
1248 if( !*zGlob ){
1249 zGlob = NULL;
1250 }else{
1251 blob_appendf(&qp, "&glob=%T", zGlob);
 
1252 }
1253 }
1254 if( PB("nc") ){
1255 graphFlags |= TIMELINE_NOCOLOR;
1256 blob_appendf(&qp, "&nc");
@@ -1263,20 +1394,22 @@
1263 style_set_current_feature("vdiff");
1264 if( zBranch==0 ){
1265 style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
1266 }
1267 if( diffType!=0 ){
1268 style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b", &qp);
1269 }
1270 if( diffType!=2 ){
1271 style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b", &qp);
 
1272 }
1273 if( diffType!=1 ) {
1274 style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b", &qp);
1275 }
1276 if( zBranch==0 ){
1277 style_submenu_element("Invert","%R/vdiff?diff=%d&inv&%b", diffType, &qp);
 
1278 }
1279 if( zGlob ){
1280 style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
1281 }else{
1282 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
@@ -1321,10 +1454,11 @@
1321 @ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p>
1322 }
1323 @<hr><p>
1324 }
1325 blob_reset(&qp);
 
1326
1327 manifest_file_rewind(pFrom);
1328 pFileFrom = manifest_file_next(pFrom, 0);
1329 manifest_file_rewind(pTo);
1330 pFileTo = manifest_file_next(pTo, 0);
@@ -1337,37 +1471,38 @@
1337 cmp = -1;
1338 }else{
1339 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
1340 }
1341 if( cmp<0 ){
1342 if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
1343 append_file_change_line(zFrom, pFileFrom->zName,
1344 pFileFrom->zUuid, 0, 0, pCfg, 0);
1345 }
1346 pFileFrom = manifest_file_next(pFrom, 0);
1347 }else if( cmp>0 ){
1348 if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
1349 append_file_change_line(zTo, pFileTo->zName,
1350 0, pFileTo->zUuid, 0, pCfg,
1351 manifest_file_mperm(pFileTo));
1352 }
1353 pFileTo = manifest_file_next(pTo, 0);
1354 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
1355 pFileFrom = manifest_file_next(pFrom, 0);
1356 pFileTo = manifest_file_next(pTo, 0);
1357 }else{
1358 if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
1359 || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
1360 append_file_change_line(zFrom, pFileFrom->zName,
1361 pFileFrom->zUuid,
1362 pFileTo->zUuid, 0, pCfg,
1363 manifest_file_mperm(pFileTo));
1364 }
1365 pFileFrom = manifest_file_next(pFrom, 0);
1366 pFileTo = manifest_file_next(pTo, 0);
1367 }
1368 }
 
1369 manifest_destroy(pFrom);
1370 manifest_destroy(pTo);
1371 append_diff_javascript(diffType);
1372 style_finish_page();
1373 }
1374
--- src/info.c
+++ src/info.c
@@ -372,11 +372,13 @@
372 const char *zNew, /* blob.uuid after change. NULL for deletes */
373 const char *zOldName, /* Prior name. NULL if no name change. */
374 DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
375 int mperm /* executable or symlink permission for zNew */
376 ){
377 @ <div class='file-change-line'><span>
378 /* Maintenance reminder: the extra level of SPAN is for
379 ** arranging new elements via JS. */
380 if( !g.perm.Hyperlink ){
381 if( zNew==0 ){
382 @ Deleted %h(zName).
383 }else if( zOld==0 ){
384 @ Added %h(zName).
@@ -391,10 +393,11 @@
393 @ %h(zName) became a regular file.
394 }
395 }else{
396 @ Changes to %h(zName).
397 }
398 @ </span></div>
399 if( pCfg ){
400 append_diff(zOld, zNew, pCfg);
401 }
402 }else{
403 if( zOld && zNew ){
@@ -436,18 +439,22 @@
439 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
440 }else{
441 @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
442 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
443 }
444 if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
445 if( pCfg ){
446 @ </span></div>
447 append_diff(zOld, zNew, pCfg);
448 }else{
449 @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
450 @ </span></div>
451 }
452 }else{
453 @ </span></div>
454 }
455 }
 
456 }
457
458 /*
459 ** Generate javascript to enhance HTML diffs.
460 */
@@ -600,10 +607,130 @@
607 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
608 0, 0, 0, rid, 0, 0);
609 db_finalize(&q);
610 style_finish_page();
611 }
612
613 /*
614 ** WEBPAGE: ckout
615 **
616 ** Show information about the current checkout. This page only functions
617 ** if the web server is run on a loopback interface (in other words, was
618 ** started using "fossil ui" or similar) from with on open check-out.
619 */
620 void ckout_page(void){
621 int vid;
622 char *zHostname;
623 char *zCwd;
624 int diffType; /* 0: no diff, 1: unified, 2: side-by-side */
625 DiffConfig DCfg,*pCfg; /* Diff details */
626 const char *zHome; /* Home directory */
627 Stmt q;
628
629 if( !db_open_local(0) || !cgi_is_loopback(g.zIpAddr) ){
630 cgi_redirect("%R/home");
631 return;
632 }
633 diffType = preferred_diff_type();
634 pCfg = construct_diff_flags(diffType, &DCfg);
635 vid = db_lget_int("checkout", 0);
636 db_unprotect(PROTECT_ALL);
637 vfile_check_signature(vid, CKSIG_ENOTFILE);
638 db_protect_pop();
639 style_set_current_feature("vinfo");
640 zHostname = fossil_hostname();
641 zCwd = file_getcwd(0,0);
642 zHome = fossil_getenv("HOME");
643 if( zHome ){
644 int nHome = (int)strlen(zHome);
645 if( strncmp(zCwd, zHome, nHome)==0 && zCwd[nHome]=='/' ){
646 zCwd = mprintf("~%s", zCwd+nHome);
647 }
648 }
649 if( zHostname ){
650 style_header("Checkout Status: %h on %h", zCwd, zHostname);
651 }else{
652 style_header("Checkout Status: %h", zCwd);
653 }
654 render_checkin_context(vid, 0, 0, 0);
655 if( pCfg==0 ){
656 style_finish_page();
657 return;
658 }
659 db_prepare(&q,
660 /* 0 1 2 3 4 5 6 */
661 "SELECT pathname, deleted, chnged , rid==0, rid, islink, uuid"
662 " FROM vfile LEFT JOIN blob USING(rid)"
663 " WHERE vid=%d"
664 " AND (deleted OR chnged OR rid==0)"
665 " ORDER BY pathname /*scan*/",
666 vid
667 );
668 if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
669 pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
670 }else{
671 pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
672 }
673 while( db_step(&q)==SQLITE_ROW ){
674 const char *zTreename = db_column_text(&q,0);
675 int isDeleted = db_column_int(&q, 1);
676 int isChnged = db_column_int(&q,2);
677 int isNew = db_column_int(&q,3);
678 int srcid = db_column_int(&q, 4);
679 int isLink = db_column_int(&q, 5);
680 const char *zUuid = db_column_text(&q, 6);
681 int showDiff = 1;
682
683 pCfg->diffFlags &= (~DIFF_FILE_MASK);
684 if( isDeleted ){
685 @ <p>DELETED %h(zTreename)</p>
686 pCfg->diffFlags |= DIFF_FILE_DELETED;
687 showDiff = 0;
688 }else if( file_access(zTreename, F_OK) ){
689 @ <p>MISSING %h(zTreename)</p>
690 showDiff = 0;
691 }else if( isNew ){
692 @ <p>ADDED %h(zTreename)</p>
693 pCfg->diffFlags |= DIFF_FILE_ADDED;
694 srcid = 0;
695 showDiff = 0;
696 }else if( isChnged==3 ){
697 @ <p>ADDED_BY_MERGE %h(zTreename)</p>
698 pCfg->diffFlags |= DIFF_FILE_ADDED;
699 srcid = 0;
700 showDiff = 0;
701 }else if( isChnged==5 ){
702 @ <p>ADDED_BY_INTEGRATE %h(zTreename)</p>
703 pCfg->diffFlags |= DIFF_FILE_ADDED;
704 srcid = 0;
705 showDiff = 0;
706 }else{
707 @ <p>CHANGED %h(zTreename)</p>
708 }
709 if( showDiff ){
710 Blob old, new;
711 if( !isLink != !file_islink(zTreename) ){
712 @ %s(DIFF_CANNOT_COMPUTE_SYMLINK)
713 continue;
714 }
715 if( srcid>0 ){
716 content_get(srcid, &old);
717 pCfg->zLeftHash = zUuid;
718 }else{
719 blob_zero(&old);
720 pCfg->zLeftHash = 0;
721 }
722 blob_read_from_file(&new, zTreename, ExtFILE);
723 text_diff(&old, &new, cgi_output_blob(), pCfg);
724 blob_reset(&old);
725 blob_reset(&new);
726 }
727 }
728 db_finalize(&q);
729 append_diff_javascript(diffType);
730 style_finish_page();
731 }
732
733 /*
734 ** WEBPAGE: vinfo
735 ** WEBPAGE: ci
736 ** URL: /ci/ARTIFACTID
@@ -1191,22 +1318,25 @@
1318 const char *zBranch;
1319 const char *zFrom;
1320 const char *zTo;
1321 const char *zRe;
1322 const char *zGlob;
1323 Glob * pGlob = 0;
1324 char *zMergeOrigin = 0;
1325 ReCompiled *pRe = 0;
1326 DiffConfig DCfg, *pCfg = 0;
1327 int graphFlags = 0;
1328 Blob qp; /* non-glob= query parameters for generated links */
1329 Blob qpGlob; /* glob= query parameter for generated links */
1330 int bInvert = PB("inv");
1331
1332 login_check_credentials();
1333 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1334 login_anonymous_available();
1335 fossil_nice_default();
1336 blob_init(&qp, 0, 0);
1337 blob_init(&qpGlob, 0, 0);
1338 diffType = preferred_diff_type();
1339 zRe = P("regex");
1340 if( zRe ) re_compile(&pRe, zRe, 0);
1341 zBranch = P("branch");
1342 if( zBranch && zBranch[0]==0 ) zBranch = 0;
@@ -1246,11 +1376,12 @@
1376 }
1377 if( zGlob ){
1378 if( !*zGlob ){
1379 zGlob = NULL;
1380 }else{
1381 blob_appendf(&qpGlob, "&glob=%T", zGlob);
1382 pGlob = glob_create(zGlob);
1383 }
1384 }
1385 if( PB("nc") ){
1386 graphFlags |= TIMELINE_NOCOLOR;
1387 blob_appendf(&qp, "&nc");
@@ -1263,20 +1394,22 @@
1394 style_set_current_feature("vdiff");
1395 if( zBranch==0 ){
1396 style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
1397 }
1398 if( diffType!=0 ){
1399 style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b%b", &qp, &qpGlob);
1400 }
1401 if( diffType!=2 ){
1402 style_submenu_element("Side-by-Side Diff", "%R/vdiff?diff=2&%b%b", &qp,
1403 &qpGlob);
1404 }
1405 if( diffType!=1 ) {
1406 style_submenu_element("Unified Diff", "%R/vdiff?diff=1&%b%b", &qp, &qpGlob);
1407 }
1408 if( zBranch==0 ){
1409 style_submenu_element("Invert","%R/vdiff?diff=%d&inv&%b%b", diffType,
1410 &qp, &qpGlob);
1411 }
1412 if( zGlob ){
1413 style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
1414 }else{
1415 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
@@ -1321,10 +1454,11 @@
1454 @ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p>
1455 }
1456 @<hr><p>
1457 }
1458 blob_reset(&qp);
1459 blob_reset(&qpGlob);
1460
1461 manifest_file_rewind(pFrom);
1462 pFileFrom = manifest_file_next(pFrom, 0);
1463 manifest_file_rewind(pTo);
1464 pFileTo = manifest_file_next(pTo, 0);
@@ -1337,37 +1471,38 @@
1471 cmp = -1;
1472 }else{
1473 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
1474 }
1475 if( cmp<0 ){
1476 if( !pGlob || glob_match(pGlob, pFileFrom->zName) ){
1477 append_file_change_line(zFrom, pFileFrom->zName,
1478 pFileFrom->zUuid, 0, 0, pCfg, 0);
1479 }
1480 pFileFrom = manifest_file_next(pFrom, 0);
1481 }else if( cmp>0 ){
1482 if( !pGlob || glob_match(pGlob, pFileTo->zName) ){
1483 append_file_change_line(zTo, pFileTo->zName,
1484 0, pFileTo->zUuid, 0, pCfg,
1485 manifest_file_mperm(pFileTo));
1486 }
1487 pFileTo = manifest_file_next(pTo, 0);
1488 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
1489 pFileFrom = manifest_file_next(pFrom, 0);
1490 pFileTo = manifest_file_next(pTo, 0);
1491 }else{
1492 if(!pGlob || (glob_match(pGlob, pFileFrom->zName)
1493 || glob_match(pGlob, pFileTo->zName)) ){
1494 append_file_change_line(zFrom, pFileFrom->zName,
1495 pFileFrom->zUuid,
1496 pFileTo->zUuid, 0, pCfg,
1497 manifest_file_mperm(pFileTo));
1498 }
1499 pFileFrom = manifest_file_next(pFrom, 0);
1500 pFileTo = manifest_file_next(pTo, 0);
1501 }
1502 }
1503 glob_free(pGlob);
1504 manifest_destroy(pFrom);
1505 manifest_destroy(pTo);
1506 append_diff_javascript(diffType);
1507 style_finish_page();
1508 }
1509
+2 -1
--- src/interwiki.c
+++ src/interwiki.c
@@ -275,13 +275,14 @@
275275
db_prepare(&q,
276276
"SELECT substr(name,11), value->>'base'"
277277
" FROM config WHERE name glob 'interwiki:*' AND json_valid(value)"
278278
" ORDER BY name;"
279279
);
280
+ blob_append(out, "<blockquote>", -1);
280281
while( db_step(&q)==SQLITE_ROW ){
281282
if( n==0 ){
282
- blob_appendf(out, "<blockquote><table>\n");
283
+ blob_appendf(out, "<table>\n");
283284
}
284285
blob_appendf(out,"<tr><td>%h</td><td>&nbsp;&rarr;&nbsp;</td>",
285286
db_column_text(&q,0));
286287
blob_appendf(out,"<td>%h</td></tr>\n",
287288
db_column_text(&q,1));
288289
--- src/interwiki.c
+++ src/interwiki.c
@@ -275,13 +275,14 @@
275 db_prepare(&q,
276 "SELECT substr(name,11), value->>'base'"
277 " FROM config WHERE name glob 'interwiki:*' AND json_valid(value)"
278 " ORDER BY name;"
279 );
 
280 while( db_step(&q)==SQLITE_ROW ){
281 if( n==0 ){
282 blob_appendf(out, "<blockquote><table>\n");
283 }
284 blob_appendf(out,"<tr><td>%h</td><td>&nbsp;&rarr;&nbsp;</td>",
285 db_column_text(&q,0));
286 blob_appendf(out,"<td>%h</td></tr>\n",
287 db_column_text(&q,1));
288
--- src/interwiki.c
+++ src/interwiki.c
@@ -275,13 +275,14 @@
275 db_prepare(&q,
276 "SELECT substr(name,11), value->>'base'"
277 " FROM config WHERE name glob 'interwiki:*' AND json_valid(value)"
278 " ORDER BY name;"
279 );
280 blob_append(out, "<blockquote>", -1);
281 while( db_step(&q)==SQLITE_ROW ){
282 if( n==0 ){
283 blob_appendf(out, "<table>\n");
284 }
285 blob_appendf(out,"<tr><td>%h</td><td>&nbsp;&rarr;&nbsp;</td>",
286 db_column_text(&q,0));
287 blob_appendf(out,"<td>%h</td></tr>\n",
288 db_column_text(&q,1));
289
+16 -4
--- src/login.c
+++ src/login.c
@@ -751,11 +751,11 @@
751751
if( anonFlag ){
752752
@ <input type="hidden" name="anon" value="1">
753753
}
754754
if( g.zLogin ){
755755
@ <p>Currently logged in as <b>%h(g.zLogin)</b>.
756
- @ <input type="submit" name="out" value="Logout"></p>
756
+ @ <input type="submit" name="out" value="Logout" autofocus></p>
757757
@ </form>
758758
}else{
759759
unsigned int uSeed = captcha_seed();
760760
if( g.zLogin==0 && (anonFlag || zGoto==0) ){
761761
zAnonPw = db_text(0, "SELECT pw FROM user"
@@ -777,11 +777,11 @@
777777
@ </span></td></tr>
778778
}
779779
@ <tr>
780780
@ <td class="form_label" id="userlabel1">User ID:</td>
781781
@ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
782
- @ size="30" value="%s(anonFlag?"anonymous":"")"></td>
782
+ @ size="30" value="%s(anonFlag?"anonymous":"")" autofocus></td>
783783
@ </tr>
784784
@ <tr>
785785
@ <td class="form_label" id="pswdlabel">Password:</td>
786786
@ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
787787
@ name="p" value="" size="30">\
@@ -1302,20 +1302,32 @@
13021302
*/
13031303
void login_restrict_robot_access(void){
13041304
const char *zReferer;
13051305
const char *zGlob;
13061306
int isMatch = 1;
1307
+ int nQP; /* Number of query parameters other than name= */
13071308
if( g.zLogin!=0 ) return;
13081309
zGlob = db_get("robot-restrict",0);
13091310
if( zGlob==0 || zGlob[0]==0 ) return;
13101311
if( g.isHuman ){
13111312
zReferer = P("HTTP_REFERER");
13121313
if( zReferer && zReferer[0]!=0 ) return;
13131314
}
1314
- if( cgi_qp_count()<1 ) return;
1315
+ nQP = cgi_qp_count();
1316
+ if( nQP<1 ) return;
13151317
isMatch = glob_multi_match(zGlob, g.zPath);
13161318
if( !isMatch ) return;
1319
+
1320
+ /* Check for exceptions to the restriction on the number of query
1321
+ ** parameters. */
1322
+ zGlob = db_get("robot-restrict-qp",0);
1323
+ if( zGlob && zGlob[0] ){
1324
+ char *zPath = mprintf("%s/%d", g.zPath, nQP);
1325
+ isMatch = glob_multi_match(zGlob, zPath);
1326
+ fossil_free(zPath);
1327
+ if( isMatch ) return;
1328
+ }
13171329
13181330
/* If we reach this point, it means we have a situation where we
13191331
** want to restrict the activity of a robot.
13201332
*/
13211333
g.isHuman = 0;
@@ -2243,11 +2255,11 @@
22432255
@ <p><input type="hidden" name="captchaseed" value="%u(uSeed)">
22442256
@ <table class="login_out">
22452257
@ <tr>
22462258
@ <td class="form_label" align="right" id="uid">User ID:</td>
22472259
@ <td><input aria-labelledby="uid" type="text" name="u" \
2248
- @ value="%h(zUserID)" size="30"></td>
2260
+ @ value="%h(zUserID)" size="30" autofocus></td>
22492261
@
22502262
if( iErrLine==1 ){
22512263
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
22522264
}
22532265
@ <tr>
22542266
--- src/login.c
+++ src/login.c
@@ -751,11 +751,11 @@
751 if( anonFlag ){
752 @ <input type="hidden" name="anon" value="1">
753 }
754 if( g.zLogin ){
755 @ <p>Currently logged in as <b>%h(g.zLogin)</b>.
756 @ <input type="submit" name="out" value="Logout"></p>
757 @ </form>
758 }else{
759 unsigned int uSeed = captcha_seed();
760 if( g.zLogin==0 && (anonFlag || zGoto==0) ){
761 zAnonPw = db_text(0, "SELECT pw FROM user"
@@ -777,11 +777,11 @@
777 @ </span></td></tr>
778 }
779 @ <tr>
780 @ <td class="form_label" id="userlabel1">User ID:</td>
781 @ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
782 @ size="30" value="%s(anonFlag?"anonymous":"")"></td>
783 @ </tr>
784 @ <tr>
785 @ <td class="form_label" id="pswdlabel">Password:</td>
786 @ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
787 @ name="p" value="" size="30">\
@@ -1302,20 +1302,32 @@
1302 */
1303 void login_restrict_robot_access(void){
1304 const char *zReferer;
1305 const char *zGlob;
1306 int isMatch = 1;
 
1307 if( g.zLogin!=0 ) return;
1308 zGlob = db_get("robot-restrict",0);
1309 if( zGlob==0 || zGlob[0]==0 ) return;
1310 if( g.isHuman ){
1311 zReferer = P("HTTP_REFERER");
1312 if( zReferer && zReferer[0]!=0 ) return;
1313 }
1314 if( cgi_qp_count()<1 ) return;
 
1315 isMatch = glob_multi_match(zGlob, g.zPath);
1316 if( !isMatch ) return;
 
 
 
 
 
 
 
 
 
 
1317
1318 /* If we reach this point, it means we have a situation where we
1319 ** want to restrict the activity of a robot.
1320 */
1321 g.isHuman = 0;
@@ -2243,11 +2255,11 @@
2243 @ <p><input type="hidden" name="captchaseed" value="%u(uSeed)">
2244 @ <table class="login_out">
2245 @ <tr>
2246 @ <td class="form_label" align="right" id="uid">User ID:</td>
2247 @ <td><input aria-labelledby="uid" type="text" name="u" \
2248 @ value="%h(zUserID)" size="30"></td>
2249 @
2250 if( iErrLine==1 ){
2251 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
2252 }
2253 @ <tr>
2254
--- src/login.c
+++ src/login.c
@@ -751,11 +751,11 @@
751 if( anonFlag ){
752 @ <input type="hidden" name="anon" value="1">
753 }
754 if( g.zLogin ){
755 @ <p>Currently logged in as <b>%h(g.zLogin)</b>.
756 @ <input type="submit" name="out" value="Logout" autofocus></p>
757 @ </form>
758 }else{
759 unsigned int uSeed = captcha_seed();
760 if( g.zLogin==0 && (anonFlag || zGoto==0) ){
761 zAnonPw = db_text(0, "SELECT pw FROM user"
@@ -777,11 +777,11 @@
777 @ </span></td></tr>
778 }
779 @ <tr>
780 @ <td class="form_label" id="userlabel1">User ID:</td>
781 @ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
782 @ size="30" value="%s(anonFlag?"anonymous":"")" autofocus></td>
783 @ </tr>
784 @ <tr>
785 @ <td class="form_label" id="pswdlabel">Password:</td>
786 @ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
787 @ name="p" value="" size="30">\
@@ -1302,20 +1302,32 @@
1302 */
1303 void login_restrict_robot_access(void){
1304 const char *zReferer;
1305 const char *zGlob;
1306 int isMatch = 1;
1307 int nQP; /* Number of query parameters other than name= */
1308 if( g.zLogin!=0 ) return;
1309 zGlob = db_get("robot-restrict",0);
1310 if( zGlob==0 || zGlob[0]==0 ) return;
1311 if( g.isHuman ){
1312 zReferer = P("HTTP_REFERER");
1313 if( zReferer && zReferer[0]!=0 ) return;
1314 }
1315 nQP = cgi_qp_count();
1316 if( nQP<1 ) return;
1317 isMatch = glob_multi_match(zGlob, g.zPath);
1318 if( !isMatch ) return;
1319
1320 /* Check for exceptions to the restriction on the number of query
1321 ** parameters. */
1322 zGlob = db_get("robot-restrict-qp",0);
1323 if( zGlob && zGlob[0] ){
1324 char *zPath = mprintf("%s/%d", g.zPath, nQP);
1325 isMatch = glob_multi_match(zGlob, zPath);
1326 fossil_free(zPath);
1327 if( isMatch ) return;
1328 }
1329
1330 /* If we reach this point, it means we have a situation where we
1331 ** want to restrict the activity of a robot.
1332 */
1333 g.isHuman = 0;
@@ -2243,11 +2255,11 @@
2255 @ <p><input type="hidden" name="captchaseed" value="%u(uSeed)">
2256 @ <table class="login_out">
2257 @ <tr>
2258 @ <td class="form_label" align="right" id="uid">User ID:</td>
2259 @ <td><input aria-labelledby="uid" type="text" name="u" \
2260 @ value="%h(zUserID)" size="30" autofocus></td>
2261 @
2262 if( iErrLine==1 ){
2263 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
2264 }
2265 @ <tr>
2266
+13 -10
--- src/main.c
+++ src/main.c
@@ -2040,20 +2040,27 @@
20402040
*/
20412041
set_base_url(0);
20422042
if( fossil_redirect_to_https_if_needed(2) ) return;
20432043
if( zPathInfo==0 || zPathInfo[0]==0
20442044
|| (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
2045
- /* Second special case: If the PATH_INFO is blank, issue a redirect to
2046
- ** the home page identified by the "index-page" setting in the repository
2047
- ** CONFIG table, to "/index" if there no "index-page" setting. */
2045
+ /* Second special case: If the PATH_INFO is blank, issue a redirect:
2046
+ ** (1) to "/ckout" if g.useLocalauth and g.localOpen are both set.
2047
+ ** (2) to the home page identified by the "index-page" setting
2048
+ ** in the repository CONFIG table
2049
+ ** (3) to "/index" if there no "index-page" setting in CONFIG
2050
+ */
20482051
#ifdef FOSSIL_ENABLE_JSON
20492052
if(g.json.isJsonMode){
20502053
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
20512054
fossil_exit(0);
20522055
}
20532056
#endif
2054
- fossil_redirect_home() /*does not return*/;
2057
+ if( g.useLocalauth && g.localOpen ){
2058
+ cgi_redirectf("%R/ckout");
2059
+ }else{
2060
+ fossil_redirect_home() /*does not return*/;
2061
+ }
20552062
}else{
20562063
zPath = mprintf("%s", zPathInfo);
20572064
}
20582065
20592066
/* Make g.zPath point to the first element of the path. Make
@@ -3356,11 +3363,11 @@
33563363
const char * zDir = g.argv[2];
33573364
if(dir_has_ckout_db(zDir)){
33583365
if(0!=file_chdir(zDir, 0)){
33593366
fossil_fatal("Cannot chdir to %s", zDir);
33603367
}
3361
- findServerArg = 99;
3368
+ findServerArg = g.argc;
33623369
fCreate = 0;
33633370
g.argv[2] = 0;
33643371
--g.argc;
33653372
}
33663373
}
@@ -3384,15 +3391,11 @@
33843391
}
33853392
if( !zRemote ){
33863393
find_server_repository(findServerArg, fCreate);
33873394
}
33883395
if( zInitPage==0 ){
3389
- if( isUiCmd && g.localOpen ){
3390
- zInitPage = "timeline?c=current";
3391
- }else{
3392
- zInitPage = "";
3393
- }
3396
+ zInitPage = "";
33943397
}
33953398
if( zPort ){
33963399
if( strchr(zPort,':') ){
33973400
int i;
33983401
for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){}
33993402
--- src/main.c
+++ src/main.c
@@ -2040,20 +2040,27 @@
2040 */
2041 set_base_url(0);
2042 if( fossil_redirect_to_https_if_needed(2) ) return;
2043 if( zPathInfo==0 || zPathInfo[0]==0
2044 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
2045 /* Second special case: If the PATH_INFO is blank, issue a redirect to
2046 ** the home page identified by the "index-page" setting in the repository
2047 ** CONFIG table, to "/index" if there no "index-page" setting. */
 
 
 
2048 #ifdef FOSSIL_ENABLE_JSON
2049 if(g.json.isJsonMode){
2050 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
2051 fossil_exit(0);
2052 }
2053 #endif
2054 fossil_redirect_home() /*does not return*/;
 
 
 
 
2055 }else{
2056 zPath = mprintf("%s", zPathInfo);
2057 }
2058
2059 /* Make g.zPath point to the first element of the path. Make
@@ -3356,11 +3363,11 @@
3356 const char * zDir = g.argv[2];
3357 if(dir_has_ckout_db(zDir)){
3358 if(0!=file_chdir(zDir, 0)){
3359 fossil_fatal("Cannot chdir to %s", zDir);
3360 }
3361 findServerArg = 99;
3362 fCreate = 0;
3363 g.argv[2] = 0;
3364 --g.argc;
3365 }
3366 }
@@ -3384,15 +3391,11 @@
3384 }
3385 if( !zRemote ){
3386 find_server_repository(findServerArg, fCreate);
3387 }
3388 if( zInitPage==0 ){
3389 if( isUiCmd && g.localOpen ){
3390 zInitPage = "timeline?c=current";
3391 }else{
3392 zInitPage = "";
3393 }
3394 }
3395 if( zPort ){
3396 if( strchr(zPort,':') ){
3397 int i;
3398 for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){}
3399
--- src/main.c
+++ src/main.c
@@ -2040,20 +2040,27 @@
2040 */
2041 set_base_url(0);
2042 if( fossil_redirect_to_https_if_needed(2) ) return;
2043 if( zPathInfo==0 || zPathInfo[0]==0
2044 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
2045 /* Second special case: If the PATH_INFO is blank, issue a redirect:
2046 ** (1) to "/ckout" if g.useLocalauth and g.localOpen are both set.
2047 ** (2) to the home page identified by the "index-page" setting
2048 ** in the repository CONFIG table
2049 ** (3) to "/index" if there no "index-page" setting in CONFIG
2050 */
2051 #ifdef FOSSIL_ENABLE_JSON
2052 if(g.json.isJsonMode){
2053 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
2054 fossil_exit(0);
2055 }
2056 #endif
2057 if( g.useLocalauth && g.localOpen ){
2058 cgi_redirectf("%R/ckout");
2059 }else{
2060 fossil_redirect_home() /*does not return*/;
2061 }
2062 }else{
2063 zPath = mprintf("%s", zPathInfo);
2064 }
2065
2066 /* Make g.zPath point to the first element of the path. Make
@@ -3356,11 +3363,11 @@
3363 const char * zDir = g.argv[2];
3364 if(dir_has_ckout_db(zDir)){
3365 if(0!=file_chdir(zDir, 0)){
3366 fossil_fatal("Cannot chdir to %s", zDir);
3367 }
3368 findServerArg = g.argc;
3369 fCreate = 0;
3370 g.argv[2] = 0;
3371 --g.argc;
3372 }
3373 }
@@ -3384,15 +3391,11 @@
3391 }
3392 if( !zRemote ){
3393 find_server_repository(findServerArg, fCreate);
3394 }
3395 if( zInitPage==0 ){
3396 zInitPage = "";
 
 
 
 
3397 }
3398 if( zPort ){
3399 if( strchr(zPort,':') ){
3400 int i;
3401 for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){}
3402
+2 -1
--- src/main.mk
+++ src/main.mk
@@ -248,10 +248,11 @@
248248
$(SRCDIR)/hbmenu.js \
249249
$(SRCDIR)/href.js \
250250
$(SRCDIR)/login.js \
251251
$(SRCDIR)/markdown.md \
252252
$(SRCDIR)/menu.js \
253
+ $(SRCDIR)/merge.tcl \
253254
$(SRCDIR)/scroll.js \
254255
$(SRCDIR)/skin.js \
255256
$(SRCDIR)/sorttable.js \
256257
$(SRCDIR)/sounds/0.wav \
257258
$(SRCDIR)/sounds/1.wav \
@@ -704,11 +705,11 @@
704705
705706
# The USE_LINENOISE variable may be undefined, set to 0, or set
706707
# to 1. If it is set to 0, then there is no need to build or link
707708
# the linenoise.o object.
708709
LINENOISE_DEF.0 =
709
-LINENOISE_DEF.1 = -DHAVE_LINENOISE
710
+LINENOISE_DEF.1 = -DHAVE_LINENOISE=2
710711
LINENOISE_DEF. = $(LINENOISE_DEF.0)
711712
LINENOISE_OBJ.0 =
712713
LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
713714
LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
714715
715716
--- src/main.mk
+++ src/main.mk
@@ -248,10 +248,11 @@
248 $(SRCDIR)/hbmenu.js \
249 $(SRCDIR)/href.js \
250 $(SRCDIR)/login.js \
251 $(SRCDIR)/markdown.md \
252 $(SRCDIR)/menu.js \
 
253 $(SRCDIR)/scroll.js \
254 $(SRCDIR)/skin.js \
255 $(SRCDIR)/sorttable.js \
256 $(SRCDIR)/sounds/0.wav \
257 $(SRCDIR)/sounds/1.wav \
@@ -704,11 +705,11 @@
704
705 # The USE_LINENOISE variable may be undefined, set to 0, or set
706 # to 1. If it is set to 0, then there is no need to build or link
707 # the linenoise.o object.
708 LINENOISE_DEF.0 =
709 LINENOISE_DEF.1 = -DHAVE_LINENOISE
710 LINENOISE_DEF. = $(LINENOISE_DEF.0)
711 LINENOISE_OBJ.0 =
712 LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
713 LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
714
715
--- src/main.mk
+++ src/main.mk
@@ -248,10 +248,11 @@
248 $(SRCDIR)/hbmenu.js \
249 $(SRCDIR)/href.js \
250 $(SRCDIR)/login.js \
251 $(SRCDIR)/markdown.md \
252 $(SRCDIR)/menu.js \
253 $(SRCDIR)/merge.tcl \
254 $(SRCDIR)/scroll.js \
255 $(SRCDIR)/skin.js \
256 $(SRCDIR)/sorttable.js \
257 $(SRCDIR)/sounds/0.wav \
258 $(SRCDIR)/sounds/1.wav \
@@ -704,11 +705,11 @@
705
706 # The USE_LINENOISE variable may be undefined, set to 0, or set
707 # to 1. If it is set to 0, then there is no need to build or link
708 # the linenoise.o object.
709 LINENOISE_DEF.0 =
710 LINENOISE_DEF.1 = -DHAVE_LINENOISE=2
711 LINENOISE_DEF. = $(LINENOISE_DEF.0)
712 LINENOISE_OBJ.0 =
713 LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
714 LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
715
716
+7 -3
--- src/manifest.c
+++ src/manifest.c
@@ -2334,11 +2334,11 @@
23342334
int i, rc = TH_OK;
23352335
Manifest *p;
23362336
int parentid = 0;
23372337
int permitHooks = (flags & MC_PERMIT_HOOKS);
23382338
const char *zScript = 0;
2339
- const char *zUuid = 0;
2339
+ char *zUuid = 0;
23402340
23412341
if( g.fSqlTrace ){
23422342
fossil_trace("-- manifest_crosslink(%d)\n", rid);
23432343
}
23442344
manifest_create_event_triggers();
@@ -2370,11 +2370,11 @@
23702370
}
23712371
db_begin_transaction();
23722372
if( p->type==CFTYPE_MANIFEST ){
23732373
if( permitHooks ){
23742374
zScript = xfer_commit_code();
2375
- zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
2375
+ zUuid = rid_to_uuid(rid);
23762376
}
23772377
if( p->nCherrypick && db_table_exists("repository","cherrypick") ){
23782378
int i;
23792379
for(i=0; i<p->nCherrypick; i++){
23802380
db_multi_exec(
@@ -2722,11 +2722,12 @@
27222722
branchMove = 0;
27232723
if( permitHooks && db_exists("SELECT 1 FROM event, blob"
27242724
" WHERE event.type='ci' AND event.objid=blob.rid"
27252725
" AND blob.uuid=%Q", zTagUuid) ){
27262726
zScript = xfer_commit_code();
2727
- zUuid = zTagUuid;
2727
+ fossil_free(zUuid);
2728
+ zUuid = fossil_strdup(zTagUuid);
27282729
}
27292730
}
27302731
zName = p->aTag[i].zName;
27312732
zValue = p->aTag[i].zValue;
27322733
if( strcmp(zName, "*branch")==0 ){
@@ -2805,10 +2806,12 @@
28052806
}
28062807
if( p->type==CFTYPE_FORUM ){
28072808
int froot, fprev, firt;
28082809
char *zFType;
28092810
char *zTitle;
2811
+
2812
+ assert( 0==zUuid );
28102813
schema_forum();
28112814
search_doc_touch('f', rid, 0);
28122815
froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
28132816
fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
28142817
firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
@@ -2877,10 +2880,11 @@
28772880
rc = xfer_run_common_script();
28782881
if( rc==TH_OK ){
28792882
rc = xfer_run_script(zScript, zUuid, 0);
28802883
}
28812884
}
2885
+ fossil_free(zUuid);
28822886
if( p->type==CFTYPE_MANIFEST ){
28832887
manifest_cache_insert(p);
28842888
}else{
28852889
manifest_destroy(p);
28862890
}
28872891
--- src/manifest.c
+++ src/manifest.c
@@ -2334,11 +2334,11 @@
2334 int i, rc = TH_OK;
2335 Manifest *p;
2336 int parentid = 0;
2337 int permitHooks = (flags & MC_PERMIT_HOOKS);
2338 const char *zScript = 0;
2339 const char *zUuid = 0;
2340
2341 if( g.fSqlTrace ){
2342 fossil_trace("-- manifest_crosslink(%d)\n", rid);
2343 }
2344 manifest_create_event_triggers();
@@ -2370,11 +2370,11 @@
2370 }
2371 db_begin_transaction();
2372 if( p->type==CFTYPE_MANIFEST ){
2373 if( permitHooks ){
2374 zScript = xfer_commit_code();
2375 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
2376 }
2377 if( p->nCherrypick && db_table_exists("repository","cherrypick") ){
2378 int i;
2379 for(i=0; i<p->nCherrypick; i++){
2380 db_multi_exec(
@@ -2722,11 +2722,12 @@
2722 branchMove = 0;
2723 if( permitHooks && db_exists("SELECT 1 FROM event, blob"
2724 " WHERE event.type='ci' AND event.objid=blob.rid"
2725 " AND blob.uuid=%Q", zTagUuid) ){
2726 zScript = xfer_commit_code();
2727 zUuid = zTagUuid;
 
2728 }
2729 }
2730 zName = p->aTag[i].zName;
2731 zValue = p->aTag[i].zValue;
2732 if( strcmp(zName, "*branch")==0 ){
@@ -2805,10 +2806,12 @@
2805 }
2806 if( p->type==CFTYPE_FORUM ){
2807 int froot, fprev, firt;
2808 char *zFType;
2809 char *zTitle;
 
 
2810 schema_forum();
2811 search_doc_touch('f', rid, 0);
2812 froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
2813 fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
2814 firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
@@ -2877,10 +2880,11 @@
2877 rc = xfer_run_common_script();
2878 if( rc==TH_OK ){
2879 rc = xfer_run_script(zScript, zUuid, 0);
2880 }
2881 }
 
2882 if( p->type==CFTYPE_MANIFEST ){
2883 manifest_cache_insert(p);
2884 }else{
2885 manifest_destroy(p);
2886 }
2887
--- src/manifest.c
+++ src/manifest.c
@@ -2334,11 +2334,11 @@
2334 int i, rc = TH_OK;
2335 Manifest *p;
2336 int parentid = 0;
2337 int permitHooks = (flags & MC_PERMIT_HOOKS);
2338 const char *zScript = 0;
2339 char *zUuid = 0;
2340
2341 if( g.fSqlTrace ){
2342 fossil_trace("-- manifest_crosslink(%d)\n", rid);
2343 }
2344 manifest_create_event_triggers();
@@ -2370,11 +2370,11 @@
2370 }
2371 db_begin_transaction();
2372 if( p->type==CFTYPE_MANIFEST ){
2373 if( permitHooks ){
2374 zScript = xfer_commit_code();
2375 zUuid = rid_to_uuid(rid);
2376 }
2377 if( p->nCherrypick && db_table_exists("repository","cherrypick") ){
2378 int i;
2379 for(i=0; i<p->nCherrypick; i++){
2380 db_multi_exec(
@@ -2722,11 +2722,12 @@
2722 branchMove = 0;
2723 if( permitHooks && db_exists("SELECT 1 FROM event, blob"
2724 " WHERE event.type='ci' AND event.objid=blob.rid"
2725 " AND blob.uuid=%Q", zTagUuid) ){
2726 zScript = xfer_commit_code();
2727 fossil_free(zUuid);
2728 zUuid = fossil_strdup(zTagUuid);
2729 }
2730 }
2731 zName = p->aTag[i].zName;
2732 zValue = p->aTag[i].zValue;
2733 if( strcmp(zName, "*branch")==0 ){
@@ -2805,10 +2806,12 @@
2806 }
2807 if( p->type==CFTYPE_FORUM ){
2808 int froot, fprev, firt;
2809 char *zFType;
2810 char *zTitle;
2811
2812 assert( 0==zUuid );
2813 schema_forum();
2814 search_doc_touch('f', rid, 0);
2815 froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
2816 fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
2817 firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
@@ -2877,10 +2880,11 @@
2880 rc = xfer_run_common_script();
2881 if( rc==TH_OK ){
2882 rc = xfer_run_script(zScript, zUuid, 0);
2883 }
2884 }
2885 fossil_free(zUuid);
2886 if( p->type==CFTYPE_MANIFEST ){
2887 manifest_cache_insert(p);
2888 }else{
2889 manifest_destroy(p);
2890 }
2891
+465 -6
--- src/merge.c
+++ src/merge.c
@@ -20,10 +20,372 @@
2020
*/
2121
#include "config.h"
2222
#include "merge.h"
2323
#include <assert.h>
2424
25
+
26
+/*
27
+** Bring up a Tcl/Tk GUI to show details of the most recent merge.
28
+*/
29
+static void merge_info_tk(int bDark, int bAll, int nContext){
30
+ int i;
31
+ Blob script;
32
+ const char *zTempFile = 0;
33
+ char *zCmd;
34
+ const char *zTclsh;
35
+ zTclsh = find_option("tclsh",0,1);
36
+ if( zTclsh==0 ){
37
+ zTclsh = db_get("tclsh",0);
38
+ }
39
+ /* The undocumented --script FILENAME option causes the Tk script to
40
+ ** be written into the FILENAME instead of being run. This is used
41
+ ** for testing and debugging. */
42
+ zTempFile = find_option("script",0,1);
43
+ verify_all_options();
44
+
45
+ blob_zero(&script);
46
+ blob_appendf(&script, "set ncontext %d\n", nContext);
47
+ blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info}\n",
48
+ g.nameOfExe);
49
+ blob_appendf(&script, "set filelist [list");
50
+ if( g.argc==2 ){
51
+ /* No files named on the command-line. Use every file mentioned
52
+ ** in the MERGESTAT table to generate the file list. */
53
+ Stmt q;
54
+ int cnt = 0;
55
+ db_prepare(&q,
56
+ "WITH priority(op,pri) AS (VALUES('CONFLICT',0),('ERROR',0),"
57
+ "('MERGE',1),('ADDED',2),('UPDATE',2))"
58
+ "SELECT coalesce(fnr,fn), op FROM mergestat JOIN priority USING(op)"
59
+ " %s ORDER BY pri, 1",
60
+ bAll ? "" : "WHERE op IN ('MERGE','CONFLICT')" /*safe-for-%s*/
61
+ );
62
+ while( db_step(&q)==SQLITE_ROW ){
63
+ blob_appendf(&script," %s ", db_column_text(&q,1));
64
+ blob_append_tcl_literal(&script, db_column_text(&q,0),
65
+ db_column_bytes(&q,0));
66
+ cnt++;
67
+ }
68
+ db_finalize(&q);
69
+ if( cnt==0 ){
70
+ fossil_print(
71
+ "No interesting changes in this merge. Use --all to see everything\n"
72
+ );
73
+ return;
74
+ }
75
+ }else{
76
+ /* Use only files named on the command-line in the file list.
77
+ ** But verify each file named is actually found in the MERGESTAT
78
+ ** table first. */
79
+ for(i=2; i<g.argc; i++){
80
+ char *zFile; /* Input filename */
81
+ char *zTreename; /* Name of the file in the tree */
82
+ Blob fname; /* Filename relative to root */
83
+ char *zOp; /* Operation on this file */
84
+ zFile = mprintf("%/", g.argv[i]);
85
+ file_tree_name(zFile, &fname, 0, 1);
86
+ fossil_free(zFile);
87
+ zTreename = blob_str(&fname);
88
+ zOp = db_text(0, "SELECT op FROM mergestat WHERE fn=%Q or fnr=%Q",
89
+ zTreename, zTreename);
90
+ blob_appendf(&script, " %s ", zOp);
91
+ fossil_free(zOp);
92
+ blob_append_tcl_literal(&script, zTreename, (int)strlen(zTreename));
93
+ blob_reset(&fname);
94
+ }
95
+ }
96
+ blob_appendf(&script, "]\n");
97
+ blob_appendf(&script, "set darkmode %d\n", bDark!=0);
98
+ blob_appendf(&script, "%s", builtin_file("merge.tcl", 0));
99
+ if( zTempFile ){
100
+ blob_write_to_file(&script, zTempFile);
101
+ fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile);
102
+ }else{
103
+#if defined(FOSSIL_ENABLE_TCL)
104
+ Th_FossilInit(TH_INIT_DEFAULT);
105
+ if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
106
+ blob_size(&script), 1, 1, 0)==TCL_OK ){
107
+ blob_reset(&script);
108
+ return;
109
+ }
110
+ /*
111
+ * If evaluation of the Tcl script fails, the reason may be that Tk
112
+ * could not be found by the loaded Tcl, or that Tcl cannot be loaded
113
+ * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
114
+ * to using the external "tclsh", if available.
115
+ */
116
+#endif
117
+ zTempFile = write_blob_to_temp_file(&script);
118
+ zCmd = mprintf("%$ %$", zTclsh, zTempFile);
119
+ fossil_system(zCmd);
120
+ file_delete(zTempFile);
121
+ fossil_free(zCmd);
122
+ }
123
+ blob_reset(&script);
124
+}
125
+
126
+/*
127
+** Generate a TCL list on standard output that can be fed into the
128
+** merge.tcl script to show the details of the most recent merge
129
+** command associated with file "zFName". zFName must be the filename
130
+** relative to the root of the check-in - in other words a "tree name".
131
+**
132
+** When this routine is called, we know that the mergestat table
133
+** exists, but we do not know if zFName is mentioned in that table.
134
+*/
135
+static void merge_info_tcl(const char *zFName, int nContext){
136
+ const char *zTreename;/* Name of the file in the tree */
137
+ Stmt q; /* To query the MERGESTAT table */
138
+ MergeBuilder mb; /* The merge builder object */
139
+ Blob pivot,v1,v2,out; /* Blobs for holding content */
140
+ const char *zFN; /* A filename */
141
+ int rid; /* RID value */
142
+ int sz; /* File size value */
143
+
144
+ zTreename = zFName;
145
+ db_prepare(&q,
146
+ /* 0 1 2 3 4 5 6 7 */
147
+ "SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr"
148
+ " FROM mergestat"
149
+ " WHERE fnp=%Q OR fnr=%Q",
150
+ zTreename, zTreename
151
+ );
152
+ if( db_step(&q)!=SQLITE_ROW ){
153
+ db_finalize(&q);
154
+ fossil_print("ERROR {don't know anything about file: %s}\n", zTreename);
155
+ return;
156
+ }
157
+ mergebuilder_init_tcl(&mb);
158
+ mb.nContext = nContext;
159
+
160
+ /* Set up the pivot */
161
+ zFN = db_column_text(&q, 0);
162
+ if( zFN==0 ){
163
+ /* No pivot because the file was added */
164
+ mb.zPivot = "(no baseline)";
165
+ blob_zero(&pivot);
166
+ }else{
167
+ mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
168
+ rid = db_column_int(&q, 1);
169
+ content_get(rid, &pivot);
170
+ }
171
+ mb.pPivot = &pivot;
172
+
173
+ /* Set up the merge-in as V2 */
174
+ zFN = db_column_text(&q, 5);
175
+ if( zFN==0 ){
176
+ /* File deleted in the merged-in branch */
177
+ mb.zV2 = "(deleted file)";
178
+ blob_zero(&v2);
179
+ }else{
180
+ mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
181
+ rid = db_column_int(&q, 6);
182
+ content_get(rid, &v2);
183
+ }
184
+ mb.pV2 = &v2;
185
+
186
+ /* Set up the local content as V1 */
187
+ zFN = db_column_text(&q, 2);
188
+ if( zFN==0 ){
189
+ /* File added by merge */
190
+ mb.zV1 = "(no original)";
191
+ blob_zero(&v1);
192
+ }else{
193
+ mb.zV1 = mprintf("%s (local)", file_tail(zFN));
194
+ rid = db_column_int(&q, 3);
195
+ sz = db_column_int(&q, 4);
196
+ if( rid==0 && sz>0 ){
197
+ /* The origin file had been edited so we'll have to pull its
198
+ ** original content out of the undo buffer */
199
+ Stmt q2;
200
+ db_prepare(&q2,
201
+ "SELECT content FROM undo"
202
+ " WHERE pathname=%Q AND octet_length(content)=%d",
203
+ zFN, sz
204
+ );
205
+ blob_zero(&v1);
206
+ if( db_step(&q2)==SQLITE_ROW ){
207
+ db_column_blob(&q2, 0, &v1);
208
+ }else{
209
+ mb.zV1 = "(local content missing)";
210
+ }
211
+ db_finalize(&q2);
212
+ }else{
213
+ /* The origin file was unchanged when the merge first occurred */
214
+ content_get(rid, &v1);
215
+ }
216
+ }
217
+ mb.pV1 = &v1;
218
+
219
+ /* Set up the output */
220
+ zFN = db_column_text(&q, 7);
221
+ if( zFN==0 ){
222
+ mb.zOut = "(Merge Result)";
223
+ }else{
224
+ mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
225
+ }
226
+ blob_zero(&out);
227
+ mb.pOut = &out;
228
+
229
+ merge_three_blobs(&mb);
230
+ blob_write_to_file(&out, "-");
231
+
232
+ mb.xDestroy(&mb);
233
+ blob_reset(&pivot);
234
+ blob_reset(&v1);
235
+ blob_reset(&v2);
236
+ blob_reset(&out);
237
+ db_finalize(&q);
238
+}
239
+
240
+/*
241
+** COMMAND: merge-info
242
+**
243
+** Usage: %fossil merge-info [OPTIONS]
244
+**
245
+** Display information about the most recent merge operation.
246
+**
247
+** Options:
248
+** -a|--all Show all file changes that happened because of
249
+** the merge. Normally only MERGE, CONFLICT, and ERROR
250
+** lines are shown
251
+** -c|--context N Show N lines of context around each change,
252
+** with negative N meaning show all content. Only
253
+** meaningful in combination with --tcl or --tk.
254
+** --dark Use dark mode for the Tcl/Tk-based GUI
255
+** --tcl FILE Generate (to stdout) a TCL list containing
256
+** information needed to display the changes to
257
+** FILE caused by the most recent merge. FILE must
258
+** be a pathname relative to the root of the check-out.
259
+** --tk Bring up a Tcl/Tk GUI that shows the changes
260
+** associated with the most recent merge.
261
+**
262
+*/
263
+void merge_info_cmd(void){
264
+ const char *zCnt;
265
+ const char *zTcl;
266
+ int bTk;
267
+ int bDark;
268
+ int bAll;
269
+ int nContext;
270
+ Stmt q;
271
+ const char *zWhere;
272
+ int cnt = 0;
273
+
274
+ db_must_be_within_tree();
275
+ zTcl = find_option("tcl", 0, 1);
276
+ bTk = find_option("tk", 0, 0)!=0;
277
+ zCnt = find_option("context", "c", 1);
278
+ bDark = find_option("dark", 0, 0)!=0;
279
+ bAll = find_option("all", "a", 0)!=0;
280
+ if( bTk==0 ){
281
+ verify_all_options();
282
+ if( g.argc>2 ){
283
+ usage("[OPTIONS]");
284
+ }
285
+ }
286
+ if( zCnt ){
287
+ nContext = atoi(zCnt);
288
+ if( nContext<0 ) nContext = 0xfffffff;
289
+ }else{
290
+ nContext = 6;
291
+ }
292
+ if( !db_table_exists("localdb","mergestat") ){
293
+ if( zTcl ){
294
+ fossil_print("ERROR {no merge data available}\n");
295
+ }else{
296
+ fossil_print("No merge data is available\n");
297
+ }
298
+ return;
299
+ }
300
+ if( bTk ){
301
+ merge_info_tk(bDark, bAll, nContext);
302
+ return;
303
+ }
304
+ if( zTcl ){
305
+ merge_info_tcl(zTcl, nContext);
306
+ return;
307
+ }
308
+ if( bAll ){
309
+ zWhere = "";
310
+ }else{
311
+ zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
312
+ }
313
+ db_prepare(&q,
314
+ "WITH priority(op,pri) AS (VALUES('CONFLICT',0),('ERROR',0),"
315
+ "('MERGE',1),('ADDED',2),('UPDATE',2))"
316
+
317
+ /* 0 1 2 */
318
+ "SELECT op, coalesce(fnr,fn), msg"
319
+ " FROM mergestat JOIN priority USING(op)"
320
+ " %s"
321
+ " ORDER BY pri, coalesce(fnr,fn)",
322
+ zWhere /*safe-for-%s*/
323
+ );
324
+ while( db_step(&q)==SQLITE_ROW ){
325
+ const char *zOp = db_column_text(&q, 0);
326
+ const char *zName = db_column_text(&q, 1);
327
+ const char *zErr = db_column_text(&q, 2);
328
+ if( zErr && fossil_strcmp(zOp,"CONFLICT")!=0 ){
329
+ fossil_print("%-9s %s (%s)\n", zOp, zName, zErr);
330
+ }else{
331
+ fossil_print("%-9s %s\n", zOp, zName);
332
+ }
333
+ cnt++;
334
+ }
335
+ db_finalize(&q);
336
+ if( !bAll && cnt==0 ){
337
+ fossil_print(
338
+ "No interesting changes in this merge. Use --all to see everything.\n"
339
+ );
340
+ }
341
+}
342
+
343
+/*
344
+** Erase all information about prior merges. Do this, for example, after
345
+** a commit.
346
+*/
347
+void merge_info_forget(void){
348
+ db_multi_exec(
349
+ "DROP TABLE IF EXISTS localdb.mergestat;"
350
+ "DELETE FROM localdb.vvar WHERE name glob 'mergestat-*';"
351
+ );
352
+}
353
+
354
+
355
+/*
356
+** Initialize the MERGESTAT table.
357
+**
358
+** Notes about mergestat:
359
+**
360
+** * ridv is a positive integer and sz is NULL if the V file contained
361
+** no local edits prior to the merge. If the V file was modified prior
362
+** to the merge then ridv is NULL and sz is the size of the file prior
363
+** to merge.
364
+**
365
+** * fnp, ridp, fn, ridv, and sz are all NULL for a file that was
366
+** added by merge.
367
+*/
368
+void merge_info_init(void){
369
+ merge_info_forget();
370
+ db_multi_exec(
371
+ "CREATE TABLE localdb.mergestat(\n"
372
+ " op TEXT, -- 'UPDATE', 'ADDED', 'MERGE', etc...\n"
373
+ " fnp TEXT, -- Name of the pivot file (P)\n"
374
+ " ridp INT, -- RID for the pivot file\n"
375
+ " fn TEXT, -- Name of origin file (V)\n"
376
+ " ridv INT, -- RID for origin file, or NULL if previously edited\n"
377
+ " sz INT, -- Size of origin file in bytes, NULL if unedited\n"
378
+ " fnm TEXT, -- Name of the file being merged in (M)\n"
379
+ " ridm INT, -- RID for the merge-in file\n"
380
+ " fnr TEXT, -- Name of the final output file, after all renaming\n"
381
+ " nc INT DEFAULT 0, -- Number of conflicts\n"
382
+ " msg TEXT -- Error message\n"
383
+ ");"
384
+ );
385
+}
386
+
25387
/*
26388
** Print information about a particular check-in.
27389
*/
28390
void print_checkin_description(int rid, int indent, const char *zLabel){
29391
Stmt q;
@@ -295,10 +657,13 @@
295657
** Files which are renamed in the merged-in branch will be renamed in
296658
** the current check-out.
297659
**
298660
** If the VERSION argument is omitted, then Fossil attempts to find
299661
** a recent fork on the current branch to merge.
662
+**
663
+** Note that this command does not commit the merge, as that is a
664
+** separate step.
300665
**
301666
** If there are multiple VERSION arguments, then each VERSION is merged
302667
** (or cherrypicked) in the order that they appear on the command-line.
303668
**
304669
** Options:
@@ -320,11 +685,11 @@
320685
** --force-missing Force the merge even if there is missing content
321686
** --integrate Merged branch will be closed when committing
322687
** -K|--keep-merge-files On merge conflict, retain the temporary files
323688
** used for merging, named *-baseline, *-original,
324689
** and *-merge.
325
-** -n|--dry-run If given, display instead of run actions
690
+** -n|--dry-run Do not actually change files on disk
326691
** --nosync Do not auto-sync prior to merging
327692
** -v|--verbose Show additional details of the merge
328693
*/
329694
void merge_cmd(void){
330695
int vid; /* Current version "V" */
@@ -797,15 +1162,21 @@
7971162
7981163
/************************************************************************
7991164
** All of the information needed to do the merge is now contained in the
8001165
** FV table. Starting here, we begin to actually carry out the merge.
8011166
**
802
- ** First, find files that have changed from P->M but not P->V.
1167
+ ** Begin by constructing the localdb.mergestat table.
1168
+ */
1169
+ merge_info_init();
1170
+
1171
+ /*
1172
+ ** Find files that have changed from P->M but not P->V.
8031173
** Copy the M content over into V.
8041174
*/
8051175
db_prepare(&q,
806
- "SELECT idv, ridm, fn, islinkm FROM fv"
1176
+ /* 0 1 2 3 4 5 6 7 */
1177
+ "SELECT idv, ridm, fn, islinkm, fnp, ridp, ridv, fnm FROM fv"
8071178
" WHERE idp>0 AND idv>0 AND idm>0"
8081179
" AND ridm!=ridp AND ridv=ridp AND NOT chnged"
8091180
);
8101181
while( db_step(&q)==SQLITE_ROW ){
8111182
int idv = db_column_int(&q, 0);
@@ -822,10 +1193,21 @@
8221193
" THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END"
8231194
" WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv
8241195
);
8251196
vfile_to_disk(0, idv, 0, 0);
8261197
}
1198
+ db_multi_exec(
1199
+ "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,fnm,ridm,fnr)"
1200
+ "VALUES('UPDATE',%Q,%d,%Q,%d,%Q,%d,%Q)",
1201
+ /* fnp */ db_column_text(&q, 4),
1202
+ /* ridp */ db_column_int(&q,5),
1203
+ /* fn */ zName,
1204
+ /* ridv */ db_column_int(&q,6),
1205
+ /* fnm */ db_column_text(&q, 7),
1206
+ /* ridm */ ridm,
1207
+ /* fnr */ zName
1208
+ );
8271209
}
8281210
db_finalize(&q);
8291211
8301212
/*
8311213
** Do a three-way merge on files that have changes on both P->M and P->V.
@@ -833,11 +1215,15 @@
8331215
** Proceed even if the file doesn't exist on P, just like the common ancestor
8341216
** of M and V is an empty file. In this case, merge conflict marks will be
8351217
** added to the file and user will be forced to take a decision.
8361218
*/
8371219
db_prepare(&q,
838
- "SELECT ridm, idv, ridp, ridv, %s, fn, isexe, islinkv, islinkm FROM fv"
1220
+ /* 0 1 2 3 4 5 6 7 8 */
1221
+ "SELECT ridm, idv, ridp, ridv, %z, fn, isexe, islinkv, islinkm,"
1222
+ /* 9 10 11 */
1223
+ " fnp, fnm, chnged"
1224
+ " FROM fv"
8391225
" WHERE idv>0 AND idm>0"
8401226
" AND ridm!=ridp AND (ridv!=ridp OR chnged)",
8411227
glob_expr("fv.fn", zBinGlob)
8421228
);
8431229
while( db_step(&q)==SQLITE_ROW ){
@@ -848,12 +1234,14 @@
8481234
int isBinary = db_column_int(&q, 4);
8491235
const char *zName = db_column_text(&q, 5);
8501236
int isExe = db_column_int(&q, 6);
8511237
int islinkv = db_column_int(&q, 7);
8521238
int islinkm = db_column_int(&q, 8);
1239
+ int chnged = db_column_int(&q, 11);
8531240
int rc;
8541241
char *zFullPath;
1242
+ const char *zType = "MERGE";
8551243
Blob m, p, r;
8561244
/* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
8571245
if( verboseFlag ){
8581246
fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
8591247
zName, ridp, ridm, ridv);
@@ -861,13 +1249,29 @@
8611249
fossil_print("MERGE %s\n", zName);
8621250
}
8631251
if( islinkv || islinkm ){
8641252
fossil_print("***** Cannot merge symlink %s\n", zName);
8651253
nConflict++;
1254
+ db_multi_exec(
1255
+ "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,fnm,ridm,fnr,nc,msg)"
1256
+ "VALUES('ERROR',%Q,%d,%Q,%d,%Q,%d,%Q,1,'cannot merge symlink')",
1257
+ /* fnp */ db_column_text(&q, 9),
1258
+ /* ridp */ ridp,
1259
+ /* fn */ zName,
1260
+ /* ridv */ ridv,
1261
+ /* fnm */ db_column_text(&q, 10),
1262
+ /* ridm */ ridm,
1263
+ /* fnr */ zName
1264
+ );
8661265
}else{
1266
+ i64 sz;
1267
+ const char *zErrMsg = 0;
1268
+ int nc = 0;
1269
+
8671270
if( !dryRunFlag ) undo_save(zName);
8681271
zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
1272
+ sz = file_size(zFullPath, ExtFILE);
8691273
content_get(ridp, &p);
8701274
content_get(ridm, &m);
8711275
if( isBinary ){
8721276
rc = -1;
8731277
blob_zero(&r);
@@ -884,15 +1288,38 @@
8841288
db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv);
8851289
if( rc>0 ){
8861290
fossil_print("***** %d merge conflict%s in %s\n",
8871291
rc, rc>1 ? "s" : "", zName);
8881292
nConflict++;
1293
+ nc = rc;
1294
+ zErrMsg = "merge conflicts";
1295
+ zType = "CONFLICT";
8891296
}
8901297
}else{
8911298
fossil_print("***** Cannot merge binary file %s\n", zName);
8921299
nConflict++;
1300
+ nc = 1;
1301
+ zErrMsg = "cannot merge binary file";
1302
+ zType = "ERROR";
8931303
}
1304
+ db_multi_exec(
1305
+ "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,fnr,nc,msg)"
1306
+ "VALUES(%Q,%Q,%d,%Q,iif(%d,%d,NULL),iif(%d,%lld,NULL),%Q,%d,"
1307
+ "%Q,%d,%Q)",
1308
+ /* op */ zType,
1309
+ /* fnp */ db_column_text(&q, 9),
1310
+ /* ridp */ ridp,
1311
+ /* fn */ zName,
1312
+ /* ridv */ chnged==0, ridv,
1313
+ /* sz */ chnged!=0, sz,
1314
+ /* fnm */ db_column_text(&q, 10),
1315
+ /* ridm */ ridm,
1316
+ /* fnr */ zName,
1317
+ /* nc */ nc,
1318
+ /* msg */ zErrMsg
1319
+ );
1320
+ fossil_free(zFullPath);
8941321
blob_reset(&p);
8951322
blob_reset(&m);
8961323
blob_reset(&r);
8971324
}
8981325
vmerge_insert(idv, ridm);
@@ -901,22 +1328,33 @@
9011328
9021329
/*
9031330
** Drop files that are in P and V but not in M
9041331
*/
9051332
db_prepare(&q,
906
- "SELECT idv, fn, chnged FROM fv"
1333
+ "SELECT idv, fn, chnged, ridv FROM fv"
9071334
" WHERE idp>0 AND idv>0 AND idm=0"
9081335
);
9091336
while( db_step(&q)==SQLITE_ROW ){
9101337
int idv = db_column_int(&q, 0);
9111338
const char *zName = db_column_text(&q, 1);
9121339
int chnged = db_column_int(&q, 2);
1340
+ int ridv = db_column_int(&q, 3);
1341
+ int sz = -1;
1342
+ const char *zErrMsg = 0;
1343
+ int nc = 0;
9131344
/* Delete the file idv */
9141345
fossil_print("DELETE %s\n", zName);
9151346
if( chnged ){
1347
+ char *zFullPath;
9161348
fossil_warning("WARNING: local edits lost for %s", zName);
9171349
nConflict++;
1350
+ ridv = 0;
1351
+ nc = 1;
1352
+ zErrMsg = "local edits lost";
1353
+ zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
1354
+ sz = file_size(zFullPath, ExtFILE);
1355
+ fossil_free(zFullPath);
9181356
}
9191357
if( !dryRunFlag ) undo_save(zName);
9201358
db_multi_exec(
9211359
"UPDATE vfile SET deleted=1 WHERE id=%d", idv
9221360
);
@@ -923,10 +1361,20 @@
9231361
if( !dryRunFlag ){
9241362
char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
9251363
file_delete(zFullPath);
9261364
free(zFullPath);
9271365
}
1366
+ db_multi_exec(
1367
+ "INSERT INTO localdb.mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,nc,msg)"
1368
+ "VALUES('DELETE',NULL,NULL,%Q,iif(%d,%d,NULL),iif(%d,%d,NULL),"
1369
+ "NULL,NULL,%d,%Q)",
1370
+ /* fn */ zName,
1371
+ /* ridv */ chnged==0, ridv,
1372
+ /* sz */ chnged!=0, sz,
1373
+ /* nc */ nc,
1374
+ /* msg */ zErrMsg
1375
+ );
9281376
}
9291377
db_finalize(&q);
9301378
9311379
/* For certain sets of renames (e.g. A -> B and B -> A), a file that is
9321380
** being renamed must first be moved to a temporary location to avoid
@@ -953,10 +1401,14 @@
9531401
const char *zNewName = db_column_text(&q, 2);
9541402
int isExe = db_column_int(&q, 3);
9551403
fossil_print("RENAME %s -> %s\n", zOldName, zNewName);
9561404
if( !dryRunFlag ) undo_save(zOldName);
9571405
if( !dryRunFlag ) undo_save(zNewName);
1406
+ db_multi_exec(
1407
+ "UPDATE mergestat SET fnr=fnm WHERE fnp=%Q",
1408
+ zOldName
1409
+ );
9581410
db_multi_exec(
9591411
"UPDATE vfile SET pathname=NULL, origname=pathname"
9601412
" WHERE vid=%d AND pathname=%Q;"
9611413
"UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
9621414
" WHERE id=%d;",
@@ -1006,11 +1458,11 @@
10061458
10071459
/*
10081460
** Insert into V any files that are not in V or P but are in M.
10091461
*/
10101462
db_prepare(&q,
1011
- "SELECT idm, fnm FROM fv"
1463
+ "SELECT idm, fnm, ridm FROM fv"
10121464
" WHERE idp=0 AND idv=0 AND idm>0"
10131465
);
10141466
while( db_step(&q)==SQLITE_ROW ){
10151467
int idm = db_column_int(&q, 0);
10161468
const char *zName;
@@ -1039,10 +1491,17 @@
10391491
nOverwrite++;
10401492
}else{
10411493
fossil_print("ADDED %s\n", zName);
10421494
}
10431495
fossil_free(zFullName);
1496
+ db_multi_exec(
1497
+ "INSERT INTO mergestat(op,fnm,ridm,fnr)"
1498
+ "VALUES('ADDED',%Q,%d,%Q)",
1499
+ /* fnm */ zName,
1500
+ /* ridm */ db_column_int(&q,2),
1501
+ /* fnr */ zName
1502
+ );
10441503
if( !dryRunFlag ){
10451504
undo_save(zName);
10461505
vfile_to_disk(0, idm, 0, 0);
10471506
}
10481507
}
10491508
10501509
ADDED src/merge.tcl
--- src/merge.c
+++ src/merge.c
@@ -20,10 +20,372 @@
20 */
21 #include "config.h"
22 #include "merge.h"
23 #include <assert.h>
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25 /*
26 ** Print information about a particular check-in.
27 */
28 void print_checkin_description(int rid, int indent, const char *zLabel){
29 Stmt q;
@@ -295,10 +657,13 @@
295 ** Files which are renamed in the merged-in branch will be renamed in
296 ** the current check-out.
297 **
298 ** If the VERSION argument is omitted, then Fossil attempts to find
299 ** a recent fork on the current branch to merge.
 
 
 
300 **
301 ** If there are multiple VERSION arguments, then each VERSION is merged
302 ** (or cherrypicked) in the order that they appear on the command-line.
303 **
304 ** Options:
@@ -320,11 +685,11 @@
320 ** --force-missing Force the merge even if there is missing content
321 ** --integrate Merged branch will be closed when committing
322 ** -K|--keep-merge-files On merge conflict, retain the temporary files
323 ** used for merging, named *-baseline, *-original,
324 ** and *-merge.
325 ** -n|--dry-run If given, display instead of run actions
326 ** --nosync Do not auto-sync prior to merging
327 ** -v|--verbose Show additional details of the merge
328 */
329 void merge_cmd(void){
330 int vid; /* Current version "V" */
@@ -797,15 +1162,21 @@
797
798 /************************************************************************
799 ** All of the information needed to do the merge is now contained in the
800 ** FV table. Starting here, we begin to actually carry out the merge.
801 **
802 ** First, find files that have changed from P->M but not P->V.
 
 
 
 
 
803 ** Copy the M content over into V.
804 */
805 db_prepare(&q,
806 "SELECT idv, ridm, fn, islinkm FROM fv"
 
807 " WHERE idp>0 AND idv>0 AND idm>0"
808 " AND ridm!=ridp AND ridv=ridp AND NOT chnged"
809 );
810 while( db_step(&q)==SQLITE_ROW ){
811 int idv = db_column_int(&q, 0);
@@ -822,10 +1193,21 @@
822 " THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END"
823 " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv
824 );
825 vfile_to_disk(0, idv, 0, 0);
826 }
 
 
 
 
 
 
 
 
 
 
 
827 }
828 db_finalize(&q);
829
830 /*
831 ** Do a three-way merge on files that have changes on both P->M and P->V.
@@ -833,11 +1215,15 @@
833 ** Proceed even if the file doesn't exist on P, just like the common ancestor
834 ** of M and V is an empty file. In this case, merge conflict marks will be
835 ** added to the file and user will be forced to take a decision.
836 */
837 db_prepare(&q,
838 "SELECT ridm, idv, ridp, ridv, %s, fn, isexe, islinkv, islinkm FROM fv"
 
 
 
 
839 " WHERE idv>0 AND idm>0"
840 " AND ridm!=ridp AND (ridv!=ridp OR chnged)",
841 glob_expr("fv.fn", zBinGlob)
842 );
843 while( db_step(&q)==SQLITE_ROW ){
@@ -848,12 +1234,14 @@
848 int isBinary = db_column_int(&q, 4);
849 const char *zName = db_column_text(&q, 5);
850 int isExe = db_column_int(&q, 6);
851 int islinkv = db_column_int(&q, 7);
852 int islinkm = db_column_int(&q, 8);
 
853 int rc;
854 char *zFullPath;
 
855 Blob m, p, r;
856 /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
857 if( verboseFlag ){
858 fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
859 zName, ridp, ridm, ridv);
@@ -861,13 +1249,29 @@
861 fossil_print("MERGE %s\n", zName);
862 }
863 if( islinkv || islinkm ){
864 fossil_print("***** Cannot merge symlink %s\n", zName);
865 nConflict++;
 
 
 
 
 
 
 
 
 
 
 
866 }else{
 
 
 
 
867 if( !dryRunFlag ) undo_save(zName);
868 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
 
869 content_get(ridp, &p);
870 content_get(ridm, &m);
871 if( isBinary ){
872 rc = -1;
873 blob_zero(&r);
@@ -884,15 +1288,38 @@
884 db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv);
885 if( rc>0 ){
886 fossil_print("***** %d merge conflict%s in %s\n",
887 rc, rc>1 ? "s" : "", zName);
888 nConflict++;
 
 
 
889 }
890 }else{
891 fossil_print("***** Cannot merge binary file %s\n", zName);
892 nConflict++;
 
 
 
893 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894 blob_reset(&p);
895 blob_reset(&m);
896 blob_reset(&r);
897 }
898 vmerge_insert(idv, ridm);
@@ -901,22 +1328,33 @@
901
902 /*
903 ** Drop files that are in P and V but not in M
904 */
905 db_prepare(&q,
906 "SELECT idv, fn, chnged FROM fv"
907 " WHERE idp>0 AND idv>0 AND idm=0"
908 );
909 while( db_step(&q)==SQLITE_ROW ){
910 int idv = db_column_int(&q, 0);
911 const char *zName = db_column_text(&q, 1);
912 int chnged = db_column_int(&q, 2);
 
 
 
 
913 /* Delete the file idv */
914 fossil_print("DELETE %s\n", zName);
915 if( chnged ){
 
916 fossil_warning("WARNING: local edits lost for %s", zName);
917 nConflict++;
 
 
 
 
 
 
918 }
919 if( !dryRunFlag ) undo_save(zName);
920 db_multi_exec(
921 "UPDATE vfile SET deleted=1 WHERE id=%d", idv
922 );
@@ -923,10 +1361,20 @@
923 if( !dryRunFlag ){
924 char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
925 file_delete(zFullPath);
926 free(zFullPath);
927 }
 
 
 
 
 
 
 
 
 
 
928 }
929 db_finalize(&q);
930
931 /* For certain sets of renames (e.g. A -> B and B -> A), a file that is
932 ** being renamed must first be moved to a temporary location to avoid
@@ -953,10 +1401,14 @@
953 const char *zNewName = db_column_text(&q, 2);
954 int isExe = db_column_int(&q, 3);
955 fossil_print("RENAME %s -> %s\n", zOldName, zNewName);
956 if( !dryRunFlag ) undo_save(zOldName);
957 if( !dryRunFlag ) undo_save(zNewName);
 
 
 
 
958 db_multi_exec(
959 "UPDATE vfile SET pathname=NULL, origname=pathname"
960 " WHERE vid=%d AND pathname=%Q;"
961 "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
962 " WHERE id=%d;",
@@ -1006,11 +1458,11 @@
1006
1007 /*
1008 ** Insert into V any files that are not in V or P but are in M.
1009 */
1010 db_prepare(&q,
1011 "SELECT idm, fnm FROM fv"
1012 " WHERE idp=0 AND idv=0 AND idm>0"
1013 );
1014 while( db_step(&q)==SQLITE_ROW ){
1015 int idm = db_column_int(&q, 0);
1016 const char *zName;
@@ -1039,10 +1491,17 @@
1039 nOverwrite++;
1040 }else{
1041 fossil_print("ADDED %s\n", zName);
1042 }
1043 fossil_free(zFullName);
 
 
 
 
 
 
 
1044 if( !dryRunFlag ){
1045 undo_save(zName);
1046 vfile_to_disk(0, idm, 0, 0);
1047 }
1048 }
1049
1050 DDED src/merge.tcl
--- src/merge.c
+++ src/merge.c
@@ -20,10 +20,372 @@
20 */
21 #include "config.h"
22 #include "merge.h"
23 #include <assert.h>
24
25
26 /*
27 ** Bring up a Tcl/Tk GUI to show details of the most recent merge.
28 */
29 static void merge_info_tk(int bDark, int bAll, int nContext){
30 int i;
31 Blob script;
32 const char *zTempFile = 0;
33 char *zCmd;
34 const char *zTclsh;
35 zTclsh = find_option("tclsh",0,1);
36 if( zTclsh==0 ){
37 zTclsh = db_get("tclsh",0);
38 }
39 /* The undocumented --script FILENAME option causes the Tk script to
40 ** be written into the FILENAME instead of being run. This is used
41 ** for testing and debugging. */
42 zTempFile = find_option("script",0,1);
43 verify_all_options();
44
45 blob_zero(&script);
46 blob_appendf(&script, "set ncontext %d\n", nContext);
47 blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info}\n",
48 g.nameOfExe);
49 blob_appendf(&script, "set filelist [list");
50 if( g.argc==2 ){
51 /* No files named on the command-line. Use every file mentioned
52 ** in the MERGESTAT table to generate the file list. */
53 Stmt q;
54 int cnt = 0;
55 db_prepare(&q,
56 "WITH priority(op,pri) AS (VALUES('CONFLICT',0),('ERROR',0),"
57 "('MERGE',1),('ADDED',2),('UPDATE',2))"
58 "SELECT coalesce(fnr,fn), op FROM mergestat JOIN priority USING(op)"
59 " %s ORDER BY pri, 1",
60 bAll ? "" : "WHERE op IN ('MERGE','CONFLICT')" /*safe-for-%s*/
61 );
62 while( db_step(&q)==SQLITE_ROW ){
63 blob_appendf(&script," %s ", db_column_text(&q,1));
64 blob_append_tcl_literal(&script, db_column_text(&q,0),
65 db_column_bytes(&q,0));
66 cnt++;
67 }
68 db_finalize(&q);
69 if( cnt==0 ){
70 fossil_print(
71 "No interesting changes in this merge. Use --all to see everything\n"
72 );
73 return;
74 }
75 }else{
76 /* Use only files named on the command-line in the file list.
77 ** But verify each file named is actually found in the MERGESTAT
78 ** table first. */
79 for(i=2; i<g.argc; i++){
80 char *zFile; /* Input filename */
81 char *zTreename; /* Name of the file in the tree */
82 Blob fname; /* Filename relative to root */
83 char *zOp; /* Operation on this file */
84 zFile = mprintf("%/", g.argv[i]);
85 file_tree_name(zFile, &fname, 0, 1);
86 fossil_free(zFile);
87 zTreename = blob_str(&fname);
88 zOp = db_text(0, "SELECT op FROM mergestat WHERE fn=%Q or fnr=%Q",
89 zTreename, zTreename);
90 blob_appendf(&script, " %s ", zOp);
91 fossil_free(zOp);
92 blob_append_tcl_literal(&script, zTreename, (int)strlen(zTreename));
93 blob_reset(&fname);
94 }
95 }
96 blob_appendf(&script, "]\n");
97 blob_appendf(&script, "set darkmode %d\n", bDark!=0);
98 blob_appendf(&script, "%s", builtin_file("merge.tcl", 0));
99 if( zTempFile ){
100 blob_write_to_file(&script, zTempFile);
101 fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile);
102 }else{
103 #if defined(FOSSIL_ENABLE_TCL)
104 Th_FossilInit(TH_INIT_DEFAULT);
105 if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
106 blob_size(&script), 1, 1, 0)==TCL_OK ){
107 blob_reset(&script);
108 return;
109 }
110 /*
111 * If evaluation of the Tcl script fails, the reason may be that Tk
112 * could not be found by the loaded Tcl, or that Tcl cannot be loaded
113 * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
114 * to using the external "tclsh", if available.
115 */
116 #endif
117 zTempFile = write_blob_to_temp_file(&script);
118 zCmd = mprintf("%$ %$", zTclsh, zTempFile);
119 fossil_system(zCmd);
120 file_delete(zTempFile);
121 fossil_free(zCmd);
122 }
123 blob_reset(&script);
124 }
125
126 /*
127 ** Generate a TCL list on standard output that can be fed into the
128 ** merge.tcl script to show the details of the most recent merge
129 ** command associated with file "zFName". zFName must be the filename
130 ** relative to the root of the check-in - in other words a "tree name".
131 **
132 ** When this routine is called, we know that the mergestat table
133 ** exists, but we do not know if zFName is mentioned in that table.
134 */
135 static void merge_info_tcl(const char *zFName, int nContext){
136 const char *zTreename;/* Name of the file in the tree */
137 Stmt q; /* To query the MERGESTAT table */
138 MergeBuilder mb; /* The merge builder object */
139 Blob pivot,v1,v2,out; /* Blobs for holding content */
140 const char *zFN; /* A filename */
141 int rid; /* RID value */
142 int sz; /* File size value */
143
144 zTreename = zFName;
145 db_prepare(&q,
146 /* 0 1 2 3 4 5 6 7 */
147 "SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr"
148 " FROM mergestat"
149 " WHERE fnp=%Q OR fnr=%Q",
150 zTreename, zTreename
151 );
152 if( db_step(&q)!=SQLITE_ROW ){
153 db_finalize(&q);
154 fossil_print("ERROR {don't know anything about file: %s}\n", zTreename);
155 return;
156 }
157 mergebuilder_init_tcl(&mb);
158 mb.nContext = nContext;
159
160 /* Set up the pivot */
161 zFN = db_column_text(&q, 0);
162 if( zFN==0 ){
163 /* No pivot because the file was added */
164 mb.zPivot = "(no baseline)";
165 blob_zero(&pivot);
166 }else{
167 mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
168 rid = db_column_int(&q, 1);
169 content_get(rid, &pivot);
170 }
171 mb.pPivot = &pivot;
172
173 /* Set up the merge-in as V2 */
174 zFN = db_column_text(&q, 5);
175 if( zFN==0 ){
176 /* File deleted in the merged-in branch */
177 mb.zV2 = "(deleted file)";
178 blob_zero(&v2);
179 }else{
180 mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
181 rid = db_column_int(&q, 6);
182 content_get(rid, &v2);
183 }
184 mb.pV2 = &v2;
185
186 /* Set up the local content as V1 */
187 zFN = db_column_text(&q, 2);
188 if( zFN==0 ){
189 /* File added by merge */
190 mb.zV1 = "(no original)";
191 blob_zero(&v1);
192 }else{
193 mb.zV1 = mprintf("%s (local)", file_tail(zFN));
194 rid = db_column_int(&q, 3);
195 sz = db_column_int(&q, 4);
196 if( rid==0 && sz>0 ){
197 /* The origin file had been edited so we'll have to pull its
198 ** original content out of the undo buffer */
199 Stmt q2;
200 db_prepare(&q2,
201 "SELECT content FROM undo"
202 " WHERE pathname=%Q AND octet_length(content)=%d",
203 zFN, sz
204 );
205 blob_zero(&v1);
206 if( db_step(&q2)==SQLITE_ROW ){
207 db_column_blob(&q2, 0, &v1);
208 }else{
209 mb.zV1 = "(local content missing)";
210 }
211 db_finalize(&q2);
212 }else{
213 /* The origin file was unchanged when the merge first occurred */
214 content_get(rid, &v1);
215 }
216 }
217 mb.pV1 = &v1;
218
219 /* Set up the output */
220 zFN = db_column_text(&q, 7);
221 if( zFN==0 ){
222 mb.zOut = "(Merge Result)";
223 }else{
224 mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
225 }
226 blob_zero(&out);
227 mb.pOut = &out;
228
229 merge_three_blobs(&mb);
230 blob_write_to_file(&out, "-");
231
232 mb.xDestroy(&mb);
233 blob_reset(&pivot);
234 blob_reset(&v1);
235 blob_reset(&v2);
236 blob_reset(&out);
237 db_finalize(&q);
238 }
239
240 /*
241 ** COMMAND: merge-info
242 **
243 ** Usage: %fossil merge-info [OPTIONS]
244 **
245 ** Display information about the most recent merge operation.
246 **
247 ** Options:
248 ** -a|--all Show all file changes that happened because of
249 ** the merge. Normally only MERGE, CONFLICT, and ERROR
250 ** lines are shown
251 ** -c|--context N Show N lines of context around each change,
252 ** with negative N meaning show all content. Only
253 ** meaningful in combination with --tcl or --tk.
254 ** --dark Use dark mode for the Tcl/Tk-based GUI
255 ** --tcl FILE Generate (to stdout) a TCL list containing
256 ** information needed to display the changes to
257 ** FILE caused by the most recent merge. FILE must
258 ** be a pathname relative to the root of the check-out.
259 ** --tk Bring up a Tcl/Tk GUI that shows the changes
260 ** associated with the most recent merge.
261 **
262 */
263 void merge_info_cmd(void){
264 const char *zCnt;
265 const char *zTcl;
266 int bTk;
267 int bDark;
268 int bAll;
269 int nContext;
270 Stmt q;
271 const char *zWhere;
272 int cnt = 0;
273
274 db_must_be_within_tree();
275 zTcl = find_option("tcl", 0, 1);
276 bTk = find_option("tk", 0, 0)!=0;
277 zCnt = find_option("context", "c", 1);
278 bDark = find_option("dark", 0, 0)!=0;
279 bAll = find_option("all", "a", 0)!=0;
280 if( bTk==0 ){
281 verify_all_options();
282 if( g.argc>2 ){
283 usage("[OPTIONS]");
284 }
285 }
286 if( zCnt ){
287 nContext = atoi(zCnt);
288 if( nContext<0 ) nContext = 0xfffffff;
289 }else{
290 nContext = 6;
291 }
292 if( !db_table_exists("localdb","mergestat") ){
293 if( zTcl ){
294 fossil_print("ERROR {no merge data available}\n");
295 }else{
296 fossil_print("No merge data is available\n");
297 }
298 return;
299 }
300 if( bTk ){
301 merge_info_tk(bDark, bAll, nContext);
302 return;
303 }
304 if( zTcl ){
305 merge_info_tcl(zTcl, nContext);
306 return;
307 }
308 if( bAll ){
309 zWhere = "";
310 }else{
311 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
312 }
313 db_prepare(&q,
314 "WITH priority(op,pri) AS (VALUES('CONFLICT',0),('ERROR',0),"
315 "('MERGE',1),('ADDED',2),('UPDATE',2))"
316
317 /* 0 1 2 */
318 "SELECT op, coalesce(fnr,fn), msg"
319 " FROM mergestat JOIN priority USING(op)"
320 " %s"
321 " ORDER BY pri, coalesce(fnr,fn)",
322 zWhere /*safe-for-%s*/
323 );
324 while( db_step(&q)==SQLITE_ROW ){
325 const char *zOp = db_column_text(&q, 0);
326 const char *zName = db_column_text(&q, 1);
327 const char *zErr = db_column_text(&q, 2);
328 if( zErr && fossil_strcmp(zOp,"CONFLICT")!=0 ){
329 fossil_print("%-9s %s (%s)\n", zOp, zName, zErr);
330 }else{
331 fossil_print("%-9s %s\n", zOp, zName);
332 }
333 cnt++;
334 }
335 db_finalize(&q);
336 if( !bAll && cnt==0 ){
337 fossil_print(
338 "No interesting changes in this merge. Use --all to see everything.\n"
339 );
340 }
341 }
342
343 /*
344 ** Erase all information about prior merges. Do this, for example, after
345 ** a commit.
346 */
347 void merge_info_forget(void){
348 db_multi_exec(
349 "DROP TABLE IF EXISTS localdb.mergestat;"
350 "DELETE FROM localdb.vvar WHERE name glob 'mergestat-*';"
351 );
352 }
353
354
355 /*
356 ** Initialize the MERGESTAT table.
357 **
358 ** Notes about mergestat:
359 **
360 ** * ridv is a positive integer and sz is NULL if the V file contained
361 ** no local edits prior to the merge. If the V file was modified prior
362 ** to the merge then ridv is NULL and sz is the size of the file prior
363 ** to merge.
364 **
365 ** * fnp, ridp, fn, ridv, and sz are all NULL for a file that was
366 ** added by merge.
367 */
368 void merge_info_init(void){
369 merge_info_forget();
370 db_multi_exec(
371 "CREATE TABLE localdb.mergestat(\n"
372 " op TEXT, -- 'UPDATE', 'ADDED', 'MERGE', etc...\n"
373 " fnp TEXT, -- Name of the pivot file (P)\n"
374 " ridp INT, -- RID for the pivot file\n"
375 " fn TEXT, -- Name of origin file (V)\n"
376 " ridv INT, -- RID for origin file, or NULL if previously edited\n"
377 " sz INT, -- Size of origin file in bytes, NULL if unedited\n"
378 " fnm TEXT, -- Name of the file being merged in (M)\n"
379 " ridm INT, -- RID for the merge-in file\n"
380 " fnr TEXT, -- Name of the final output file, after all renaming\n"
381 " nc INT DEFAULT 0, -- Number of conflicts\n"
382 " msg TEXT -- Error message\n"
383 ");"
384 );
385 }
386
387 /*
388 ** Print information about a particular check-in.
389 */
390 void print_checkin_description(int rid, int indent, const char *zLabel){
391 Stmt q;
@@ -295,10 +657,13 @@
657 ** Files which are renamed in the merged-in branch will be renamed in
658 ** the current check-out.
659 **
660 ** If the VERSION argument is omitted, then Fossil attempts to find
661 ** a recent fork on the current branch to merge.
662 **
663 ** Note that this command does not commit the merge, as that is a
664 ** separate step.
665 **
666 ** If there are multiple VERSION arguments, then each VERSION is merged
667 ** (or cherrypicked) in the order that they appear on the command-line.
668 **
669 ** Options:
@@ -320,11 +685,11 @@
685 ** --force-missing Force the merge even if there is missing content
686 ** --integrate Merged branch will be closed when committing
687 ** -K|--keep-merge-files On merge conflict, retain the temporary files
688 ** used for merging, named *-baseline, *-original,
689 ** and *-merge.
690 ** -n|--dry-run Do not actually change files on disk
691 ** --nosync Do not auto-sync prior to merging
692 ** -v|--verbose Show additional details of the merge
693 */
694 void merge_cmd(void){
695 int vid; /* Current version "V" */
@@ -797,15 +1162,21 @@
1162
1163 /************************************************************************
1164 ** All of the information needed to do the merge is now contained in the
1165 ** FV table. Starting here, we begin to actually carry out the merge.
1166 **
1167 ** Begin by constructing the localdb.mergestat table.
1168 */
1169 merge_info_init();
1170
1171 /*
1172 ** Find files that have changed from P->M but not P->V.
1173 ** Copy the M content over into V.
1174 */
1175 db_prepare(&q,
1176 /* 0 1 2 3 4 5 6 7 */
1177 "SELECT idv, ridm, fn, islinkm, fnp, ridp, ridv, fnm FROM fv"
1178 " WHERE idp>0 AND idv>0 AND idm>0"
1179 " AND ridm!=ridp AND ridv=ridp AND NOT chnged"
1180 );
1181 while( db_step(&q)==SQLITE_ROW ){
1182 int idv = db_column_int(&q, 0);
@@ -822,10 +1193,21 @@
1193 " THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END"
1194 " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv
1195 );
1196 vfile_to_disk(0, idv, 0, 0);
1197 }
1198 db_multi_exec(
1199 "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,fnm,ridm,fnr)"
1200 "VALUES('UPDATE',%Q,%d,%Q,%d,%Q,%d,%Q)",
1201 /* fnp */ db_column_text(&q, 4),
1202 /* ridp */ db_column_int(&q,5),
1203 /* fn */ zName,
1204 /* ridv */ db_column_int(&q,6),
1205 /* fnm */ db_column_text(&q, 7),
1206 /* ridm */ ridm,
1207 /* fnr */ zName
1208 );
1209 }
1210 db_finalize(&q);
1211
1212 /*
1213 ** Do a three-way merge on files that have changes on both P->M and P->V.
@@ -833,11 +1215,15 @@
1215 ** Proceed even if the file doesn't exist on P, just like the common ancestor
1216 ** of M and V is an empty file. In this case, merge conflict marks will be
1217 ** added to the file and user will be forced to take a decision.
1218 */
1219 db_prepare(&q,
1220 /* 0 1 2 3 4 5 6 7 8 */
1221 "SELECT ridm, idv, ridp, ridv, %z, fn, isexe, islinkv, islinkm,"
1222 /* 9 10 11 */
1223 " fnp, fnm, chnged"
1224 " FROM fv"
1225 " WHERE idv>0 AND idm>0"
1226 " AND ridm!=ridp AND (ridv!=ridp OR chnged)",
1227 glob_expr("fv.fn", zBinGlob)
1228 );
1229 while( db_step(&q)==SQLITE_ROW ){
@@ -848,12 +1234,14 @@
1234 int isBinary = db_column_int(&q, 4);
1235 const char *zName = db_column_text(&q, 5);
1236 int isExe = db_column_int(&q, 6);
1237 int islinkv = db_column_int(&q, 7);
1238 int islinkm = db_column_int(&q, 8);
1239 int chnged = db_column_int(&q, 11);
1240 int rc;
1241 char *zFullPath;
1242 const char *zType = "MERGE";
1243 Blob m, p, r;
1244 /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
1245 if( verboseFlag ){
1246 fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
1247 zName, ridp, ridm, ridv);
@@ -861,13 +1249,29 @@
1249 fossil_print("MERGE %s\n", zName);
1250 }
1251 if( islinkv || islinkm ){
1252 fossil_print("***** Cannot merge symlink %s\n", zName);
1253 nConflict++;
1254 db_multi_exec(
1255 "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,fnm,ridm,fnr,nc,msg)"
1256 "VALUES('ERROR',%Q,%d,%Q,%d,%Q,%d,%Q,1,'cannot merge symlink')",
1257 /* fnp */ db_column_text(&q, 9),
1258 /* ridp */ ridp,
1259 /* fn */ zName,
1260 /* ridv */ ridv,
1261 /* fnm */ db_column_text(&q, 10),
1262 /* ridm */ ridm,
1263 /* fnr */ zName
1264 );
1265 }else{
1266 i64 sz;
1267 const char *zErrMsg = 0;
1268 int nc = 0;
1269
1270 if( !dryRunFlag ) undo_save(zName);
1271 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
1272 sz = file_size(zFullPath, ExtFILE);
1273 content_get(ridp, &p);
1274 content_get(ridm, &m);
1275 if( isBinary ){
1276 rc = -1;
1277 blob_zero(&r);
@@ -884,15 +1288,38 @@
1288 db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv);
1289 if( rc>0 ){
1290 fossil_print("***** %d merge conflict%s in %s\n",
1291 rc, rc>1 ? "s" : "", zName);
1292 nConflict++;
1293 nc = rc;
1294 zErrMsg = "merge conflicts";
1295 zType = "CONFLICT";
1296 }
1297 }else{
1298 fossil_print("***** Cannot merge binary file %s\n", zName);
1299 nConflict++;
1300 nc = 1;
1301 zErrMsg = "cannot merge binary file";
1302 zType = "ERROR";
1303 }
1304 db_multi_exec(
1305 "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,fnr,nc,msg)"
1306 "VALUES(%Q,%Q,%d,%Q,iif(%d,%d,NULL),iif(%d,%lld,NULL),%Q,%d,"
1307 "%Q,%d,%Q)",
1308 /* op */ zType,
1309 /* fnp */ db_column_text(&q, 9),
1310 /* ridp */ ridp,
1311 /* fn */ zName,
1312 /* ridv */ chnged==0, ridv,
1313 /* sz */ chnged!=0, sz,
1314 /* fnm */ db_column_text(&q, 10),
1315 /* ridm */ ridm,
1316 /* fnr */ zName,
1317 /* nc */ nc,
1318 /* msg */ zErrMsg
1319 );
1320 fossil_free(zFullPath);
1321 blob_reset(&p);
1322 blob_reset(&m);
1323 blob_reset(&r);
1324 }
1325 vmerge_insert(idv, ridm);
@@ -901,22 +1328,33 @@
1328
1329 /*
1330 ** Drop files that are in P and V but not in M
1331 */
1332 db_prepare(&q,
1333 "SELECT idv, fn, chnged, ridv FROM fv"
1334 " WHERE idp>0 AND idv>0 AND idm=0"
1335 );
1336 while( db_step(&q)==SQLITE_ROW ){
1337 int idv = db_column_int(&q, 0);
1338 const char *zName = db_column_text(&q, 1);
1339 int chnged = db_column_int(&q, 2);
1340 int ridv = db_column_int(&q, 3);
1341 int sz = -1;
1342 const char *zErrMsg = 0;
1343 int nc = 0;
1344 /* Delete the file idv */
1345 fossil_print("DELETE %s\n", zName);
1346 if( chnged ){
1347 char *zFullPath;
1348 fossil_warning("WARNING: local edits lost for %s", zName);
1349 nConflict++;
1350 ridv = 0;
1351 nc = 1;
1352 zErrMsg = "local edits lost";
1353 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
1354 sz = file_size(zFullPath, ExtFILE);
1355 fossil_free(zFullPath);
1356 }
1357 if( !dryRunFlag ) undo_save(zName);
1358 db_multi_exec(
1359 "UPDATE vfile SET deleted=1 WHERE id=%d", idv
1360 );
@@ -923,10 +1361,20 @@
1361 if( !dryRunFlag ){
1362 char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
1363 file_delete(zFullPath);
1364 free(zFullPath);
1365 }
1366 db_multi_exec(
1367 "INSERT INTO localdb.mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,nc,msg)"
1368 "VALUES('DELETE',NULL,NULL,%Q,iif(%d,%d,NULL),iif(%d,%d,NULL),"
1369 "NULL,NULL,%d,%Q)",
1370 /* fn */ zName,
1371 /* ridv */ chnged==0, ridv,
1372 /* sz */ chnged!=0, sz,
1373 /* nc */ nc,
1374 /* msg */ zErrMsg
1375 );
1376 }
1377 db_finalize(&q);
1378
1379 /* For certain sets of renames (e.g. A -> B and B -> A), a file that is
1380 ** being renamed must first be moved to a temporary location to avoid
@@ -953,10 +1401,14 @@
1401 const char *zNewName = db_column_text(&q, 2);
1402 int isExe = db_column_int(&q, 3);
1403 fossil_print("RENAME %s -> %s\n", zOldName, zNewName);
1404 if( !dryRunFlag ) undo_save(zOldName);
1405 if( !dryRunFlag ) undo_save(zNewName);
1406 db_multi_exec(
1407 "UPDATE mergestat SET fnr=fnm WHERE fnp=%Q",
1408 zOldName
1409 );
1410 db_multi_exec(
1411 "UPDATE vfile SET pathname=NULL, origname=pathname"
1412 " WHERE vid=%d AND pathname=%Q;"
1413 "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
1414 " WHERE id=%d;",
@@ -1006,11 +1458,11 @@
1458
1459 /*
1460 ** Insert into V any files that are not in V or P but are in M.
1461 */
1462 db_prepare(&q,
1463 "SELECT idm, fnm, ridm FROM fv"
1464 " WHERE idp=0 AND idv=0 AND idm>0"
1465 );
1466 while( db_step(&q)==SQLITE_ROW ){
1467 int idm = db_column_int(&q, 0);
1468 const char *zName;
@@ -1039,10 +1491,17 @@
1491 nOverwrite++;
1492 }else{
1493 fossil_print("ADDED %s\n", zName);
1494 }
1495 fossil_free(zFullName);
1496 db_multi_exec(
1497 "INSERT INTO mergestat(op,fnm,ridm,fnr)"
1498 "VALUES('ADDED',%Q,%d,%Q)",
1499 /* fnm */ zName,
1500 /* ridm */ db_column_int(&q,2),
1501 /* fnr */ zName
1502 );
1503 if( !dryRunFlag ){
1504 undo_save(zName);
1505 vfile_to_disk(0, idm, 0, 0);
1506 }
1507 }
1508
1509 DDED src/merge.tcl
+581
--- a/src/merge.tcl
+++ b/src/merge.tcl
@@ -0,0 +1,581 @@
1
+# Show details of a 3-way merge operation. The left-most column is the
2
+# common ancestor. The next two columns are edits of that common ancestor.
3
+# The right-most column is the result of the merge.
4
+#
5
+# There is always a "fossilcmd" variable which tells the script how to
6
+# invoke Fossil to get the information it needs. This script will
7
+# automatically append "-c N" to tell Fossil how much context it wants. True for debugging output
8
+#
9
+# If the "filelist" global variable is defined, then it is a list of
10
+# alternating "merge-type names" (ex: UPDATE, MERGE, CONFLICT, ERROR) and
11
+# filenames. In that case, the initial display shows the changes for
12
+# the first pair on the list and there is a optionmenu that allows the
13
+# useelect otheere should also be a global variable named "ncontext" which is the
14
+# number of lines of context to display. The value of this variable
15
+# controls the "-c N" argument that is appended to fossilcmdht {
16
+ TITLE {Fossil Merge}
17
+ LN_COL_BG #dddddd
18
+ LN_COL_FG #444444
19
+ TXT_COL_BG #ffffff
20
+ TXT_COL_FG #000000
21
+ MKR_COL_BG #444444
22
+ MKR_COL_FG #dddddd
23
+ CHNG_BG #d0d070
24
+ ADD_BG #c0ffc0
25
+ RM_BG #ffc0c0
26
+ HR_FG #444444
27
+ HR_PAD_TOP 4
28
+ HR_PAD_BTM 8
29
+ FN_BG #444444
30
+ FN_FG #ffffff
31
+ FN_PAD 5
32
+ ERR_FG #ee0000
33
+ PADX 5
34
+ WIDTH 80
35
+ HEIGHT 45
36
+ LB_HEIGHT 25
37
+}
38
+
39
+array set CFG_dark {
40
+ TITLE {Fossil Merge}
41
+ LN_COL_BG #dddddd
42
+ LN_COL_FG #444444
43
+ TXT_COL_BG #3f3f3f
44
+ TXT_COL_FG #dcdccc
45
+ MKR_COL_BG #444444
46
+ MKR_COL_FG #dddddd
47
+ CHNG_BG #6a6a00
48
+ ADD_BG #57934c
49
+ RM_BG #ef6767
50
+ HR_FG #444444
51
+ HR_PAD_TOP 4
52
+ HR_PAD_BTM 8
53
+ FN_BG #5e5e5e
54
+ FN_FG #ffffff
55
+ FN_PAD 5
56
+ ERR_FG #ee0000
57
+ PADX 5
58
+ WIDTH 80
59
+ HEIGHT 45
60
+ LB_HEIGHT 25
61
+}
62
+
63
+array set CFG_arr {
64
+ 0 CFG_light
65
+ 1 CFG_dark
66
+}
67
+
68
+array set CFG [array get $CFG_arr($darkmode)]
69
+
70
+if {![namespace exists ttk]} {
71
+ interp alias {} ::ttk::scrollbar {} ::scrollbar
72
+ interp alias {} ::ttk::menubutton {} ::menubutton
73
+}
74
+
75
+proc dehtml {x} {
76
+ set x [regsub -all {<[^>]*>} $x {}]
77
+ return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
78
+}
79
+
80
+proc cols {} {
81
+ return [list .lnA .txtA .lnB .txtB .lnC .txtC .lnD .txtD]
82
+}
83
+
84
+proc colType {c} {
85
+ regexp {[a-z]+} $c type
86
+ return $type
87
+}
88
+
89
+proc readMercmdes currentails of a 3-way merge operation# Show det for
90
+# the first pair on the list and there is a optionmenu that allows the
91
+# user to select other fiels on the list.
92
+#
93
+# This header comment is stripped off by the "mkbuiltin.c" program.
94
+#
95
+package require Tk
96
+
97
+array set CFG_light {
98
+ TITLE {Fossil Merge}
99
+ LN_COL_BG #dddddd
100
+ LN_COL_FG #444444
101
+ TXT_COL_BG #ffffff
102
+ TXT_COL_FG #000000
103
+ MKR_COL_BG #444444
104
+ MKR_COL_FG #dddddd
105
+ CHNG_BG #d0d070
106
+ ADD_BG #c0ffc0
107
+ RM_BG #ffc0c0
108
+ HR_FG #444444
109
+ HR_PAD_TOP 4
110
+ HR_PAD_BTM 8
111
+ FN_BG #444444
112
+ FN_FG #ffffff
113
+ FN_PAD 5
114
+ ERR_FG #ee0000
115
+ PADX 5
116
+ WIDTH 80
117
+ HEIGHT 45
118
+ LB_HEIGHT 25
119
+}
120
+
121
+array set CFG_dark {
122
+ TITLE {Fossil Merge}
123
+ LN_COL_BG #dddddd
124
+ LN_COL_FG #444444
125
+ TXT_COL_BG #3f3f3f
126
+ TXT_COL_FG #dcdccc
127
+ MKR_COL_BG #444444
128
+ MKR_COL_FG #dddddd
129
+ CHNG_BG #6a6a00
130
+ ADD_BG #57934c
131
+ RM_BG #ef6767
132
+ HR_FG #444444
133
+ HR_PAD_TOP 4
134
+ HR_PAD_BTM 8
135
+ FN_BG #5e5e5e
136
+ FN_FG #ffffff
137
+ FN_PAD 5
138
+ ERR_FG #ee0000
139
+ PADX 5
140
+ WIDTH 80
141
+ HEIGHT 45
142
+ LB_HEIGHT 25
143
+}
144
+
145
+array set CFG_arr {
146
+ 0 CFG_light
147
+ 1 CFG_dark
148
+}
149
+
150
+array set CFG [array get $CFG_arr($darkmode)]
151
+
152
+if {![namespace exists ttk]} {
153
+ interp alias {} ::ttk::scrollbar {} ::scrollbar
154
+ interp alias {} ::ttk::menubutton {} ::menubutton
155
+}
156
+
157
+proc dehtml {x} {
158
+ set x [regsub -all {<[^>]*>} $x {}]
159
+ return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
160
+}
161
+
162
+proc cols {} {
163
+ return [list .lnA .txtA .lnB .txtB .lnC .txtC .lnD .txtD]
164
+}
165
+
166
+proc colType {c} {
167
+ regexp {[a-z]+} $c type
168
+ return $type
169
+}
170
+
171
+proc readMerge {args} {
172
+ global fossilexe ncontext current_file debug
173
+ if {$ncontext=="All"} {
174
+ set cmd "| $fossilexe merge-info -c -1"
175
+ } else {
176
+ set cmd "| $fossilexe merge-info -c $ncontext"
177
+ }
178
+ if {[info exists current_file]} {
179
+ regsub {^[A-Z]+ } $current_file {} fn
180
+ lappend cmd -tcl $fn
181
+ }
182
+ if {$debug} {
183
+ regsub {^\| +} $cmd {} cmd2
184
+ puts $cmd2
185
+ flush stdout
186
+ }
187
+ if {[catch {
188
+ set in [open $cmd r]
189
+ fconfigure $in -encoding utf-8
190
+ set mergetxt [read $in]
191
+ close $in
192
+ } msg]} {
193
+ tk_messageBox -message "Unable to run command: \"$cmd\""
194
+ set mergetxt {}
195
+ }
196
+ foreach c [cols] {
197
+ $c config -state normal
198
+ $c delete 1.0 end
199
+ }
200
+ set lnA 1
201
+ set lnB 1
202
+ set lnC 1
203
+ set lnD 1
204
+ foreach {A B C D} $mergetxt {
205
+ set key1 [string index $A 0]
206
+ if {$key1=="S"} {
207
+ scan [string range $A 1 end] "%d %d %d %d" nA nB nC nD
208
+ foreach x {A B C D} {
209
+ set N [set n$x]
210
+ incr ln$x $N
211
+ if {$N>0} {
212
+ .ln$x insert end ...\n hrln
213
+ .txt$x insert end [string repeat . 30]\n hrtxt
214
+ } else {
215
+ .ln$x insert end \n hrln
216
+ .txt$x insert end \n hrtxt
217
+ }
218
+ }
219
+ continue
220
+ }
221
+ set key2 [string index $B 0]
222
+ set key3 [string index $C 0]
223
+ set key4 [string index $D 0]
224
+ if {$key1=="."} {
225
+ .lnA insert end \n -
226
+ .txtA insert end \n -
227
+ } elseif {$key1=="N"} {
228
+ .nameA config -text [string range $A 1 end]
229
+ } else {
230
+ .lnA insert end $lnA\n -
231
+ incr lnA
232
+ if {$key1=="X"} {
233
+ .txtA insert end [string range $A 1 end]\n rm
234
+ } else {
235
+ .txtA insert end [string range $A 1 end]\n -
236
+ }
237
+ }
238
+ if {$key2=="."} {
239
+ .lnB insert end \n -
240
+ .txtB insert end \n -
241
+ } elseif {$key2=="N"} {
242
+ .nameB config -text [string range $B 1 end]
243
+ } else {
244
+ .lnB insert end $lnB\n -
245
+ incr lnB
246
+ if {$key4=="2"} {set tag chng} {set tag -}
247
+ if {$key2=="1"} {
248
+ .txtB insert end [string range $A 1 end]\n $tag
249
+ } elseif {$key2=="X"} {
250
+ .txtB insert end [string range $B 1 end]\n rm
251
+ } else {
252
+ .txtB insert end [string range $B 1 end]\n $tag
253
+ }
254
+ }
255
+ if {$key3=="."} {
256
+ .lnC insert end \n -
257
+ .txtC insert end \n -
258
+ } elseif {$key3=="N"} {
259
+ .nameC config -text [string range $C 1 end]
260
+ } else {
261
+ .lnC insert end $lnC\n -
262
+ incr lnC
263
+ if {$key4=="3"} {set tag add} {set tag -}
264
+ if {$key3=="1"} {
265
+ .txtC insert end [string range $A 1 end]\n $tag
266
+ } elseif {$key3=="2"} {
267
+ .txtC insert end [string range $B 1 end]\n chng
268
+ } elseif {$key3=="X"} {
269
+ .txtC insert end [string range $C 1 end]\n rm
270
+ } else {
271
+ .txtC insert end [string range $C 1 end]\n $tag
272
+ }
273
+ }
274
+ if {$key4=="."} {
275
+ .lnD insert end \n -
276
+ .txtD insert end \n -
277
+ } elseif {$key4=="N"} {
278
+ .nameD config -text [string range $D 1 end]
279
+ } else {
280
+ .lnD insert end $lnD\n -
281
+ incr lnD
282
+ if {$key4=="1"} {
283
+ .txtD insert end [string range $A 1 end]\n -
284
+ } elseif {$key4=="2"} {
285
+ .txtD insert end [string range $B 1 end]\n chng
286
+ } elseif {$key4=="3"} {
287
+ .txtD insert end [string range $C 1 end]\n add
288
+ } elseif {$key4=="X"} {
289
+ .txtD insert end [string range $D 1 end]\n rm
290
+ } else {
291
+ .txtD insert end [string range $D 1 end]\n -
292
+ }
293
+ }
294
+ }
295
+ foreach c [cols] {
296
+ set type [colType $c]
297
+ if {$type ne "txt"} {
298
+ $c config -width 6; # $widths($type)
299
+ }
300
+ $c config -state disabled
301
+ }
302
+ set mx $lnA
303
+ if {$lnB>$mx} {set mx $lnB}
304
+ if {$lnC>$mx} {set mx $lnC}
305
+ if {$lnD>$mx} {set mx $lnD}
306
+ global lnWidth
307
+ set lnWidth [string length [format +%d $mx]]
308
+ .lnA config -width $lnWidth
309
+ .lnB config -width $lnWidth
310
+ .lnC config -width $lnWidth
311
+ .lnD config -width $lnWidth
312
+ grid columnconfig . {0 2 4 6} -minsize $lnWidth
313
+}
314
+
315
+proc viewDiff {idx} {
316
+ .txtA yview $idx
317
+ .txtA xview moveto 0
318
+}
319
+
320
+proc cycleDiffs {{reverse 0}} {
321
+ if {$reverse} {
322
+ set range [.txtA tag prevrange fn @0,0 1.0]
323
+ if {$range eq ""} {
324
+ viewDiff {fn.last -1c}
325
+ } else {
326
+ viewDiff [lindex $range 0]
327
+ }
328
+ } else {
329
+ set range [.txtA tag nextrange fn {@0,0 +1c} end]
330
+ if {$range eq "" || [lindex [.txtA yview] 1] == 1} {
331
+ viewDiff fn.first
332
+ } else {
333
+ viewDiff [lindex $range 0]
334
+ }
335
+ }
336
+}
337
+
338
+proc xvis {col} {
339
+ set view [$col xview]
340
+ return [expr {[lindex $view 1]-[lindex $view 0]}]
341
+}
342
+
343
+proc scroll-x {args} {
344
+ set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}]
345
+ eval $c xview $args
346
+}
347
+
348
+interp alias {} scroll-y {} .txtA yview
349
+
350
+proc noop {args} {}
351
+
352
+proc enableSync {axis} {
353
+ update idletasks
354
+ interp alias {} sync-$axis {}
355
+ rename _sync-$axis sync-$axis
356
+}
357
+
358
+proc disableSync {axis} {
359
+ rename sync-$axis _sync-$axis
360
+ interp alias {} sync-$axis {} noop
361
+}
362
+
363
+proc sync-y {first last} {
364
+ disableSync y
365
+ foreach c [cols] {
366
+ $c yview moveto $first
367
+ }
368
+ if {$first > 0 || $last < 1} {
369
+ grid .sby
370
+ .sby set $first $last
371
+ } else {
372
+ grid remove .sby
373
+ }
374
+ enableSync y
375
+}
376
+
377
+wm withdraw .
378
+wm title . $CFG(TITLE)
379
+wm iconname . $CFG(TITLE)
380
+# Keystroke bindings for on the top-level window for navigation and
381
+# control also fire when those same keystrokes are pressed in the
382
+# Search entry box. Disable them, to prevent the diff screen from
383
+# disappearing abruptly and unexpectedly when searching for "q".
384
+#
385
+bind . <Control-q> exit
386
+bind . <Control-p> {catch searchPrev; break}
387
+bind . <Control-n> {catch searchNext; break}
388
+bind . <Escape><Escape> exit
389
+bind . <Destroy> {after 0 exit}
390
+bind . <Tab> {cycleDiffs; break}
391
+bind . <<PrevWindow>> {cycleDiffs 1; break}
392
+bind . <Control-f> {searchOnOff; break}
393
+bind . <Control-g> {catch searchNext; break}
394
+bind . <Return> {
395
+ event generate .bb.files <1>
396
+ event generate .bb.files <ButtonRelease-1>
397
+ break
398
+}
399
+foreach {key axis args} {
400
+ Up y {scroll -5 units}
401
+ k y {scroll -5 units}
402
+ Down y {scroll 5 units}
403
+ j y {scroll 5 units}
404
+ Left x {scroll -5 units}
405
+ h x {scroll -5 units}
406
+ Right x {scroll 5 units}
407
+ l x {scroll 5 units}
408
+ Prior y {scroll -1 page}
409
+ b y {scroll -1 page}
410
+ Next y {scroll 1 page}
411
+ space y {scroll 1 page}
412
+ Home y {moveto 0}
413
+ g y {moveto 0}
414
+ End y {moveto 1}
415
+} {
416
+ bind . <$key> "scroll-$axis $args; break"
417
+ bind . <Shift-$key> continue
418
+}
419
+
420
+frame .bb
421
+::ttk::menubutton .bb.diff2 -text {2-way diffs
422
+.bb.diff2.m add command -label {baseline vs. local} -command {two-way 12}
423
+.bb.diff2.m add command -label {baseline vs. merge-in} -command {two-way 13}
424
+.bb.diff2.m add command -label {local vs. merge-in} -command {two-way 23}
425
+
426
+# Bring up a separate two-way diff between a pair of columns
427
+# the argument is one of:
428
+# 12 Baseline versus Local
429
+# 13 Baseline versus Merge-in
430
+# 23 Local versus Merge-in
431
+#
432
+proc two-way {mode} {
433
+ global current_file fossilexe debug darkmode ncontext
434
+ regsub {^[A-Z]+ } $current_file {} fn
435
+ set cmd $fossilexe
436
+ lappend cmd merge-info --diff$mode $fn -c $ncontext
437
+ if {$darkmode} {
438
+ lappend cmd --dark
439
+ }
440
+ if {$debug} {
441
+ lappend cc {*}$cmd &
442
+}
443
+
444
+set useOptionMenu 1
445
+if {[info exists filelist]} {
446
+ set current_file "[lindex $filelist 0] [lindex $filelist 1]"
447
+ if {[llength $filelist]>2} {
448
+ trace add variable current_file write readMerge
449
+
450
+ if {$tcl_platform(os)=="Darwin" || [llength $filelist]<30} {
451
+ set fnlist {}
452
+ foreach {op fn} $filelist {lappend fnlist "$op $fn"}
453
+ tk_optionMenu .bb.files current_file {*}$fnlist
454
+ } else {
455
+ set useOptionMenu 0
456
+ ::ttk::menubutton .bb.files -text $current_file
457
+ if {[tk windowingsystem] eq "win32"} {
458
+ ::ttk::style theme use winnative
459
+ .bb.files configure -padding {20 1 10 2}
460
+ }
461
+ toplevel .wfiles
462
+ wm withdraw .wfiles
463
+ update idletasks
464
+ wm transient .wfiles .
465
+ wm overrideredirect .wfiles 1
466
+ set ht [expr {[llength $filelist]/2}]
467
+ if {$ht>$CFG(LB_HEIGHT)} {set ht $CFG(LB_HEIGHT)}
468
+ listbox .wfiles.lb -width 0 -height $ht -activestyle none \
469
+ -yscroll {.wfiles.sb set}
470
+ set mx 1
471
+ foreach {op fn} $filelist {
472
+ set n [string length $fn]
473
+ if {$n>$mx} {set mx $n}
474
+ .wfiles.lb insert end "$op $fn"
475
+ }
476
+ .bb.files config -width $mx
477
+ ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
478
+ grid .wfiles.lb .wfiles.sb -sticky ns
479
+ bind .bb.files <1> {
480
+ set x [winfo rootx %W]
481
+ set y [expr {[winfo rooty %W]+[winfo height %W]}]
482
+ wm geometry .wfiles +$x+$y
483
+ wm deiconify .wfiles
484
+ focus .wfiles.lb
485
+ }
486
+ bind .wfiles <FocusOut> {wm withdraw .wfiles}
487
+ bind .wfiles <Escape> {focus .}
488
+ foreach evt {1 Return} {
489
+ bind .wfiles.lb <$evt> {
490
+ set ii [%W curselection]
491
+ set ::current_file [%W get $ii]
492
+ .bb.files config -text $::current_file
493
+ focus .
494
+ break
495
+ }
496
+ }
497
+ bind .wfiles.lb <Motion> {
498
+ %W selection clear 0 end
499
+ %W selection set @%x,%y
500
+ }
501
+ }
502
+ }
503
+}
504
+
505
+label .bb.ctxtag -text "Context:"
506
+set context_choices {3 6 12 25 50 100 All}
507
+if {$ncontext<0} {set ncontext All}
508
+trace add variable ncontext write readMerge
509
+if {$tcl_platform(os)=="Darwin" || $useOptionMenu} {
510
+ tk_optionMenu .bb.ctx ncontext {*}$context_choices
511
+} else {
512
+ ::ttk::menubutton .bb.ctx -text $ncontext
513
+ if {[tk windowingsystem] eq "win32"} {
514
+ ::ttk::style theme use winnative
515
+ .bb.ctx configure -padding {20 1 10 2}
516
+ }
517
+ toplevel .wctx
518
+ wm withdraw .wctx
519
+ update idletasks
520
+ wm transient .wctx .
521
+ wm overrideredirect .wctx 1
522
+ listbox .wctx.lb -width 0 -height 7 -activestyle none
523
+ .wctx.lb insert end {*}$context_choices
524
+ pack .wctx.lb
525
+ bind .bb.ctx <1> {
526
+ set x [winfo rootx %W]
527
+ set y [expr {[winfo rooty %W]+[winfo height %W]}]
528
+ wm geometry .wctx +$x+$y
529
+ wm deiconify .wctx
530
+ focus .wctx.lb
531
+ }
532
+ bind .wctx <FocusOut> {wm withdraw .wctx}
533
+ bind .wctx <Escape> {focus .}
534
+ foreach evt {1 Return} {
535
+ bind .wctx.lb <$evt> {
536
+ set ::ncontext [lindex $::context_choices [%W curselection]]
537
+ .bb.ctx config -text $::ncontext
538
+ focus .
539
+ break
540
+ }
541
+ }
542
+ bind .wctx.lb <Motion> {
543
+ %W selection clear 0 end
544
+ %W selection set @%x,%y
545
+ }
546
+}
547
+
548
+foreach {side syncCol} {A .txtA B .txtB C .txtC D .txtD} {
549
+ set ln .ln$side
550
+ text $ln -width 6
551
+ $ln tag config - -justify right
552
+
553
+ set txt .txt$side
554
+ text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \
555
+ -xscroll ".sbx$side set"
556
+ catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5
557
+ foreach tag {add rm chng} {
558
+ $txt tag config $tag -background $CFG([string toupper $tag]_BG)
559
+ $txt tag lower $tag
560
+ }
561
+ $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \
562
+ -justify center
563
+ $txt tag config err -foreground $CFG(ERR_FG)
564
+}
565
+text .mkr
566
+
567
+set mxwidth [lindex [wm maxsize .] 0]
568
+while {$CFG(WIDTH)>=40} {
569
+ set wanted [expr {([winfo reqwidth .lnA]+[winfo reqwidth .txtA])*4+30}]
570
+ if {$wanted<=$mxwidth} break
571
+ incr CFG(WIDTH) -10
572
+ .txtA config -width $CFG(WIDTH)
573
+ .txtB config -width $CFG(WIDTH)
574
+ .txtC config -width $CFG(WIDTH)
575
+ .txtD config -width $CFG(WIDTH)
576
+}
577
+
578
+foreach c [cols] {
579
+ set keyPrefix [string toupper [colType $c]]_COL_
580
+ if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}}
581
+ $c co
--- a/src/merge.tcl
+++ b/src/merge.tcl
@@ -0,0 +1,581 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/merge.tcl
+++ b/src/merge.tcl
@@ -0,0 +1,581 @@
1 # Show details of a 3-way merge operation. The left-most column is the
2 # common ancestor. The next two columns are edits of that common ancestor.
3 # The right-most column is the result of the merge.
4 #
5 # There is always a "fossilcmd" variable which tells the script how to
6 # invoke Fossil to get the information it needs. This script will
7 # automatically append "-c N" to tell Fossil how much context it wants. True for debugging output
8 #
9 # If the "filelist" global variable is defined, then it is a list of
10 # alternating "merge-type names" (ex: UPDATE, MERGE, CONFLICT, ERROR) and
11 # filenames. In that case, the initial display shows the changes for
12 # the first pair on the list and there is a optionmenu that allows the
13 # useelect otheere should also be a global variable named "ncontext" which is the
14 # number of lines of context to display. The value of this variable
15 # controls the "-c N" argument that is appended to fossilcmdht {
16 TITLE {Fossil Merge}
17 LN_COL_BG #dddddd
18 LN_COL_FG #444444
19 TXT_COL_BG #ffffff
20 TXT_COL_FG #000000
21 MKR_COL_BG #444444
22 MKR_COL_FG #dddddd
23 CHNG_BG #d0d070
24 ADD_BG #c0ffc0
25 RM_BG #ffc0c0
26 HR_FG #444444
27 HR_PAD_TOP 4
28 HR_PAD_BTM 8
29 FN_BG #444444
30 FN_FG #ffffff
31 FN_PAD 5
32 ERR_FG #ee0000
33 PADX 5
34 WIDTH 80
35 HEIGHT 45
36 LB_HEIGHT 25
37 }
38
39 array set CFG_dark {
40 TITLE {Fossil Merge}
41 LN_COL_BG #dddddd
42 LN_COL_FG #444444
43 TXT_COL_BG #3f3f3f
44 TXT_COL_FG #dcdccc
45 MKR_COL_BG #444444
46 MKR_COL_FG #dddddd
47 CHNG_BG #6a6a00
48 ADD_BG #57934c
49 RM_BG #ef6767
50 HR_FG #444444
51 HR_PAD_TOP 4
52 HR_PAD_BTM 8
53 FN_BG #5e5e5e
54 FN_FG #ffffff
55 FN_PAD 5
56 ERR_FG #ee0000
57 PADX 5
58 WIDTH 80
59 HEIGHT 45
60 LB_HEIGHT 25
61 }
62
63 array set CFG_arr {
64 0 CFG_light
65 1 CFG_dark
66 }
67
68 array set CFG [array get $CFG_arr($darkmode)]
69
70 if {![namespace exists ttk]} {
71 interp alias {} ::ttk::scrollbar {} ::scrollbar
72 interp alias {} ::ttk::menubutton {} ::menubutton
73 }
74
75 proc dehtml {x} {
76 set x [regsub -all {<[^>]*>} $x {}]
77 return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
78 }
79
80 proc cols {} {
81 return [list .lnA .txtA .lnB .txtB .lnC .txtC .lnD .txtD]
82 }
83
84 proc colType {c} {
85 regexp {[a-z]+} $c type
86 return $type
87 }
88
89 proc readMercmdes currentails of a 3-way merge operation# Show det for
90 # the first pair on the list and there is a optionmenu that allows the
91 # user to select other fiels on the list.
92 #
93 # This header comment is stripped off by the "mkbuiltin.c" program.
94 #
95 package require Tk
96
97 array set CFG_light {
98 TITLE {Fossil Merge}
99 LN_COL_BG #dddddd
100 LN_COL_FG #444444
101 TXT_COL_BG #ffffff
102 TXT_COL_FG #000000
103 MKR_COL_BG #444444
104 MKR_COL_FG #dddddd
105 CHNG_BG #d0d070
106 ADD_BG #c0ffc0
107 RM_BG #ffc0c0
108 HR_FG #444444
109 HR_PAD_TOP 4
110 HR_PAD_BTM 8
111 FN_BG #444444
112 FN_FG #ffffff
113 FN_PAD 5
114 ERR_FG #ee0000
115 PADX 5
116 WIDTH 80
117 HEIGHT 45
118 LB_HEIGHT 25
119 }
120
121 array set CFG_dark {
122 TITLE {Fossil Merge}
123 LN_COL_BG #dddddd
124 LN_COL_FG #444444
125 TXT_COL_BG #3f3f3f
126 TXT_COL_FG #dcdccc
127 MKR_COL_BG #444444
128 MKR_COL_FG #dddddd
129 CHNG_BG #6a6a00
130 ADD_BG #57934c
131 RM_BG #ef6767
132 HR_FG #444444
133 HR_PAD_TOP 4
134 HR_PAD_BTM 8
135 FN_BG #5e5e5e
136 FN_FG #ffffff
137 FN_PAD 5
138 ERR_FG #ee0000
139 PADX 5
140 WIDTH 80
141 HEIGHT 45
142 LB_HEIGHT 25
143 }
144
145 array set CFG_arr {
146 0 CFG_light
147 1 CFG_dark
148 }
149
150 array set CFG [array get $CFG_arr($darkmode)]
151
152 if {![namespace exists ttk]} {
153 interp alias {} ::ttk::scrollbar {} ::scrollbar
154 interp alias {} ::ttk::menubutton {} ::menubutton
155 }
156
157 proc dehtml {x} {
158 set x [regsub -all {<[^>]*>} $x {}]
159 return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
160 }
161
162 proc cols {} {
163 return [list .lnA .txtA .lnB .txtB .lnC .txtC .lnD .txtD]
164 }
165
166 proc colType {c} {
167 regexp {[a-z]+} $c type
168 return $type
169 }
170
171 proc readMerge {args} {
172 global fossilexe ncontext current_file debug
173 if {$ncontext=="All"} {
174 set cmd "| $fossilexe merge-info -c -1"
175 } else {
176 set cmd "| $fossilexe merge-info -c $ncontext"
177 }
178 if {[info exists current_file]} {
179 regsub {^[A-Z]+ } $current_file {} fn
180 lappend cmd -tcl $fn
181 }
182 if {$debug} {
183 regsub {^\| +} $cmd {} cmd2
184 puts $cmd2
185 flush stdout
186 }
187 if {[catch {
188 set in [open $cmd r]
189 fconfigure $in -encoding utf-8
190 set mergetxt [read $in]
191 close $in
192 } msg]} {
193 tk_messageBox -message "Unable to run command: \"$cmd\""
194 set mergetxt {}
195 }
196 foreach c [cols] {
197 $c config -state normal
198 $c delete 1.0 end
199 }
200 set lnA 1
201 set lnB 1
202 set lnC 1
203 set lnD 1
204 foreach {A B C D} $mergetxt {
205 set key1 [string index $A 0]
206 if {$key1=="S"} {
207 scan [string range $A 1 end] "%d %d %d %d" nA nB nC nD
208 foreach x {A B C D} {
209 set N [set n$x]
210 incr ln$x $N
211 if {$N>0} {
212 .ln$x insert end ...\n hrln
213 .txt$x insert end [string repeat . 30]\n hrtxt
214 } else {
215 .ln$x insert end \n hrln
216 .txt$x insert end \n hrtxt
217 }
218 }
219 continue
220 }
221 set key2 [string index $B 0]
222 set key3 [string index $C 0]
223 set key4 [string index $D 0]
224 if {$key1=="."} {
225 .lnA insert end \n -
226 .txtA insert end \n -
227 } elseif {$key1=="N"} {
228 .nameA config -text [string range $A 1 end]
229 } else {
230 .lnA insert end $lnA\n -
231 incr lnA
232 if {$key1=="X"} {
233 .txtA insert end [string range $A 1 end]\n rm
234 } else {
235 .txtA insert end [string range $A 1 end]\n -
236 }
237 }
238 if {$key2=="."} {
239 .lnB insert end \n -
240 .txtB insert end \n -
241 } elseif {$key2=="N"} {
242 .nameB config -text [string range $B 1 end]
243 } else {
244 .lnB insert end $lnB\n -
245 incr lnB
246 if {$key4=="2"} {set tag chng} {set tag -}
247 if {$key2=="1"} {
248 .txtB insert end [string range $A 1 end]\n $tag
249 } elseif {$key2=="X"} {
250 .txtB insert end [string range $B 1 end]\n rm
251 } else {
252 .txtB insert end [string range $B 1 end]\n $tag
253 }
254 }
255 if {$key3=="."} {
256 .lnC insert end \n -
257 .txtC insert end \n -
258 } elseif {$key3=="N"} {
259 .nameC config -text [string range $C 1 end]
260 } else {
261 .lnC insert end $lnC\n -
262 incr lnC
263 if {$key4=="3"} {set tag add} {set tag -}
264 if {$key3=="1"} {
265 .txtC insert end [string range $A 1 end]\n $tag
266 } elseif {$key3=="2"} {
267 .txtC insert end [string range $B 1 end]\n chng
268 } elseif {$key3=="X"} {
269 .txtC insert end [string range $C 1 end]\n rm
270 } else {
271 .txtC insert end [string range $C 1 end]\n $tag
272 }
273 }
274 if {$key4=="."} {
275 .lnD insert end \n -
276 .txtD insert end \n -
277 } elseif {$key4=="N"} {
278 .nameD config -text [string range $D 1 end]
279 } else {
280 .lnD insert end $lnD\n -
281 incr lnD
282 if {$key4=="1"} {
283 .txtD insert end [string range $A 1 end]\n -
284 } elseif {$key4=="2"} {
285 .txtD insert end [string range $B 1 end]\n chng
286 } elseif {$key4=="3"} {
287 .txtD insert end [string range $C 1 end]\n add
288 } elseif {$key4=="X"} {
289 .txtD insert end [string range $D 1 end]\n rm
290 } else {
291 .txtD insert end [string range $D 1 end]\n -
292 }
293 }
294 }
295 foreach c [cols] {
296 set type [colType $c]
297 if {$type ne "txt"} {
298 $c config -width 6; # $widths($type)
299 }
300 $c config -state disabled
301 }
302 set mx $lnA
303 if {$lnB>$mx} {set mx $lnB}
304 if {$lnC>$mx} {set mx $lnC}
305 if {$lnD>$mx} {set mx $lnD}
306 global lnWidth
307 set lnWidth [string length [format +%d $mx]]
308 .lnA config -width $lnWidth
309 .lnB config -width $lnWidth
310 .lnC config -width $lnWidth
311 .lnD config -width $lnWidth
312 grid columnconfig . {0 2 4 6} -minsize $lnWidth
313 }
314
315 proc viewDiff {idx} {
316 .txtA yview $idx
317 .txtA xview moveto 0
318 }
319
320 proc cycleDiffs {{reverse 0}} {
321 if {$reverse} {
322 set range [.txtA tag prevrange fn @0,0 1.0]
323 if {$range eq ""} {
324 viewDiff {fn.last -1c}
325 } else {
326 viewDiff [lindex $range 0]
327 }
328 } else {
329 set range [.txtA tag nextrange fn {@0,0 +1c} end]
330 if {$range eq "" || [lindex [.txtA yview] 1] == 1} {
331 viewDiff fn.first
332 } else {
333 viewDiff [lindex $range 0]
334 }
335 }
336 }
337
338 proc xvis {col} {
339 set view [$col xview]
340 return [expr {[lindex $view 1]-[lindex $view 0]}]
341 }
342
343 proc scroll-x {args} {
344 set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}]
345 eval $c xview $args
346 }
347
348 interp alias {} scroll-y {} .txtA yview
349
350 proc noop {args} {}
351
352 proc enableSync {axis} {
353 update idletasks
354 interp alias {} sync-$axis {}
355 rename _sync-$axis sync-$axis
356 }
357
358 proc disableSync {axis} {
359 rename sync-$axis _sync-$axis
360 interp alias {} sync-$axis {} noop
361 }
362
363 proc sync-y {first last} {
364 disableSync y
365 foreach c [cols] {
366 $c yview moveto $first
367 }
368 if {$first > 0 || $last < 1} {
369 grid .sby
370 .sby set $first $last
371 } else {
372 grid remove .sby
373 }
374 enableSync y
375 }
376
377 wm withdraw .
378 wm title . $CFG(TITLE)
379 wm iconname . $CFG(TITLE)
380 # Keystroke bindings for on the top-level window for navigation and
381 # control also fire when those same keystrokes are pressed in the
382 # Search entry box. Disable them, to prevent the diff screen from
383 # disappearing abruptly and unexpectedly when searching for "q".
384 #
385 bind . <Control-q> exit
386 bind . <Control-p> {catch searchPrev; break}
387 bind . <Control-n> {catch searchNext; break}
388 bind . <Escape><Escape> exit
389 bind . <Destroy> {after 0 exit}
390 bind . <Tab> {cycleDiffs; break}
391 bind . <<PrevWindow>> {cycleDiffs 1; break}
392 bind . <Control-f> {searchOnOff; break}
393 bind . <Control-g> {catch searchNext; break}
394 bind . <Return> {
395 event generate .bb.files <1>
396 event generate .bb.files <ButtonRelease-1>
397 break
398 }
399 foreach {key axis args} {
400 Up y {scroll -5 units}
401 k y {scroll -5 units}
402 Down y {scroll 5 units}
403 j y {scroll 5 units}
404 Left x {scroll -5 units}
405 h x {scroll -5 units}
406 Right x {scroll 5 units}
407 l x {scroll 5 units}
408 Prior y {scroll -1 page}
409 b y {scroll -1 page}
410 Next y {scroll 1 page}
411 space y {scroll 1 page}
412 Home y {moveto 0}
413 g y {moveto 0}
414 End y {moveto 1}
415 } {
416 bind . <$key> "scroll-$axis $args; break"
417 bind . <Shift-$key> continue
418 }
419
420 frame .bb
421 ::ttk::menubutton .bb.diff2 -text {2-way diffs
422 .bb.diff2.m add command -label {baseline vs. local} -command {two-way 12}
423 .bb.diff2.m add command -label {baseline vs. merge-in} -command {two-way 13}
424 .bb.diff2.m add command -label {local vs. merge-in} -command {two-way 23}
425
426 # Bring up a separate two-way diff between a pair of columns
427 # the argument is one of:
428 # 12 Baseline versus Local
429 # 13 Baseline versus Merge-in
430 # 23 Local versus Merge-in
431 #
432 proc two-way {mode} {
433 global current_file fossilexe debug darkmode ncontext
434 regsub {^[A-Z]+ } $current_file {} fn
435 set cmd $fossilexe
436 lappend cmd merge-info --diff$mode $fn -c $ncontext
437 if {$darkmode} {
438 lappend cmd --dark
439 }
440 if {$debug} {
441 lappend cc {*}$cmd &
442 }
443
444 set useOptionMenu 1
445 if {[info exists filelist]} {
446 set current_file "[lindex $filelist 0] [lindex $filelist 1]"
447 if {[llength $filelist]>2} {
448 trace add variable current_file write readMerge
449
450 if {$tcl_platform(os)=="Darwin" || [llength $filelist]<30} {
451 set fnlist {}
452 foreach {op fn} $filelist {lappend fnlist "$op $fn"}
453 tk_optionMenu .bb.files current_file {*}$fnlist
454 } else {
455 set useOptionMenu 0
456 ::ttk::menubutton .bb.files -text $current_file
457 if {[tk windowingsystem] eq "win32"} {
458 ::ttk::style theme use winnative
459 .bb.files configure -padding {20 1 10 2}
460 }
461 toplevel .wfiles
462 wm withdraw .wfiles
463 update idletasks
464 wm transient .wfiles .
465 wm overrideredirect .wfiles 1
466 set ht [expr {[llength $filelist]/2}]
467 if {$ht>$CFG(LB_HEIGHT)} {set ht $CFG(LB_HEIGHT)}
468 listbox .wfiles.lb -width 0 -height $ht -activestyle none \
469 -yscroll {.wfiles.sb set}
470 set mx 1
471 foreach {op fn} $filelist {
472 set n [string length $fn]
473 if {$n>$mx} {set mx $n}
474 .wfiles.lb insert end "$op $fn"
475 }
476 .bb.files config -width $mx
477 ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
478 grid .wfiles.lb .wfiles.sb -sticky ns
479 bind .bb.files <1> {
480 set x [winfo rootx %W]
481 set y [expr {[winfo rooty %W]+[winfo height %W]}]
482 wm geometry .wfiles +$x+$y
483 wm deiconify .wfiles
484 focus .wfiles.lb
485 }
486 bind .wfiles <FocusOut> {wm withdraw .wfiles}
487 bind .wfiles <Escape> {focus .}
488 foreach evt {1 Return} {
489 bind .wfiles.lb <$evt> {
490 set ii [%W curselection]
491 set ::current_file [%W get $ii]
492 .bb.files config -text $::current_file
493 focus .
494 break
495 }
496 }
497 bind .wfiles.lb <Motion> {
498 %W selection clear 0 end
499 %W selection set @%x,%y
500 }
501 }
502 }
503 }
504
505 label .bb.ctxtag -text "Context:"
506 set context_choices {3 6 12 25 50 100 All}
507 if {$ncontext<0} {set ncontext All}
508 trace add variable ncontext write readMerge
509 if {$tcl_platform(os)=="Darwin" || $useOptionMenu} {
510 tk_optionMenu .bb.ctx ncontext {*}$context_choices
511 } else {
512 ::ttk::menubutton .bb.ctx -text $ncontext
513 if {[tk windowingsystem] eq "win32"} {
514 ::ttk::style theme use winnative
515 .bb.ctx configure -padding {20 1 10 2}
516 }
517 toplevel .wctx
518 wm withdraw .wctx
519 update idletasks
520 wm transient .wctx .
521 wm overrideredirect .wctx 1
522 listbox .wctx.lb -width 0 -height 7 -activestyle none
523 .wctx.lb insert end {*}$context_choices
524 pack .wctx.lb
525 bind .bb.ctx <1> {
526 set x [winfo rootx %W]
527 set y [expr {[winfo rooty %W]+[winfo height %W]}]
528 wm geometry .wctx +$x+$y
529 wm deiconify .wctx
530 focus .wctx.lb
531 }
532 bind .wctx <FocusOut> {wm withdraw .wctx}
533 bind .wctx <Escape> {focus .}
534 foreach evt {1 Return} {
535 bind .wctx.lb <$evt> {
536 set ::ncontext [lindex $::context_choices [%W curselection]]
537 .bb.ctx config -text $::ncontext
538 focus .
539 break
540 }
541 }
542 bind .wctx.lb <Motion> {
543 %W selection clear 0 end
544 %W selection set @%x,%y
545 }
546 }
547
548 foreach {side syncCol} {A .txtA B .txtB C .txtC D .txtD} {
549 set ln .ln$side
550 text $ln -width 6
551 $ln tag config - -justify right
552
553 set txt .txt$side
554 text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \
555 -xscroll ".sbx$side set"
556 catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5
557 foreach tag {add rm chng} {
558 $txt tag config $tag -background $CFG([string toupper $tag]_BG)
559 $txt tag lower $tag
560 }
561 $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \
562 -justify center
563 $txt tag config err -foreground $CFG(ERR_FG)
564 }
565 text .mkr
566
567 set mxwidth [lindex [wm maxsize .] 0]
568 while {$CFG(WIDTH)>=40} {
569 set wanted [expr {([winfo reqwidth .lnA]+[winfo reqwidth .txtA])*4+30}]
570 if {$wanted<=$mxwidth} break
571 incr CFG(WIDTH) -10
572 .txtA config -width $CFG(WIDTH)
573 .txtB config -width $CFG(WIDTH)
574 .txtC config -width $CFG(WIDTH)
575 .txtD config -width $CFG(WIDTH)
576 }
577
578 foreach c [cols] {
579 set keyPrefix [string toupper [colType $c]]_COL_
580 if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}}
581 $c co
+804 -168
--- src/merge3.c
+++ src/merge3.c
@@ -75,75 +75,17 @@
7575
if( aC1[2]!=aC2[2] ) return 0;
7676
if( sameLines(pV1, pV2, aC1[2]) ) return 1;
7777
return 0;
7878
}
7979
80
-/*
81
-** The aC[] array contains triples of integers. Within each triple, the
82
-** elements are:
83
-**
84
-** (0) The number of lines to copy
85
-** (1) The number of lines to delete
86
-** (2) The number of liens to insert
87
-**
88
-** Suppose we want to advance over sz lines of the original file. This routine
89
-** returns true if that advance would land us on a copy operation. It
90
-** returns false if the advance would end on a delete.
91
-*/
92
-static int ends_at_CPY(int *aC, int sz){
93
- while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
94
- if( aC[0]>=sz ) return 1;
95
- sz -= aC[0];
96
- if( aC[1]>sz ) return 0;
97
- sz -= aC[1];
98
- aC += 3;
99
- }
100
- return 1;
101
-}
102
-
103
-/*
104
-** pSrc contains an edited file where aC[] describes the edit. Part of
105
-** pSrc has already been output. This routine outputs additional lines
106
-** of pSrc - lines that correspond to the next sz lines of the original
107
-** unedited file.
108
-**
109
-** Note that sz counts the number of lines of text in the original file.
110
-** But text is output from the edited file. So the number of lines transfer
111
-** to pOut might be different from sz. Fewer lines appear in pOut if there
112
-** are deletes. More lines appear if there are inserts.
113
-**
114
-** The aC[] array is updated and the new index into aC[] is returned.
115
-*/
116
-static int output_one_side(
117
- Blob *pOut, /* Write to this blob */
118
- Blob *pSrc, /* The edited file that is to be copied to pOut */
119
- int *aC, /* Array of integer triples describing the edit */
120
- int i, /* Index in aC[] of current location in pSrc */
121
- int sz, /* Number of lines in unedited source to output */
122
- int *pLn /* Line number counter */
123
-){
124
- while( sz>0 ){
125
- if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
126
- if( aC[i]>=sz ){
127
- blob_copy_lines(pOut, pSrc, sz); *pLn += sz;
128
- aC[i] -= sz;
129
- break;
130
- }
131
- blob_copy_lines(pOut, pSrc, aC[i]); *pLn += aC[i];
132
- blob_copy_lines(pOut, pSrc, aC[i+2]); *pLn += aC[i+2];
133
- sz -= aC[i] + aC[i+1];
134
- i += 3;
135
- }
136
- return i;
137
-}
138
-
13980
/*
14081
** Text of boundary markers for merge conflicts.
14182
*/
14283
static const char *const mergeMarker[] = {
14384
/*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
14485
"<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<",
86
+ "####### SUGGESTED CONFLICT RESOLUTION follows ###################",
14587
"||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||",
14688
"======= MERGED IN content follows ===============================",
14789
">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
14890
};
14991
@@ -186,10 +128,615 @@
186128
ensure_line_end(pOut, useCrLf);
187129
blob_append(pOut, mergeMarker[iMark], -1);
188130
if( ln>0 ) blob_appendf(pOut, " (line %d)", ln);
189131
ensure_line_end(pOut, useCrLf);
190132
}
133
+
134
+#if INTERFACE
135
+/*
136
+** This is an abstract class for constructing a merge.
137
+** Subclasses of this object format the merge output in different ways.
138
+**
139
+** To subclass, create an instance of the MergeBuilder object and fill
140
+** in appropriate method implementations.
141
+*/
142
+struct MergeBuilder {
143
+ void (*xStart)(MergeBuilder*);
144
+ void (*xSame)(MergeBuilder*, unsigned int);
145
+ void (*xChngV1)(MergeBuilder*, unsigned int, unsigned int);
146
+ void (*xChngV2)(MergeBuilder*, unsigned int, unsigned int);
147
+ void (*xChngBoth)(MergeBuilder*, unsigned int, unsigned int);
148
+ void (*xConflict)(MergeBuilder*, unsigned int, unsigned int, unsigned int);
149
+ void (*xEnd)(MergeBuilder*);
150
+ void (*xDestroy)(MergeBuilder*);
151
+ const char *zPivot; /* Label or name for the pivot */
152
+ const char *zV1; /* Label or name for the V1 file */
153
+ const char *zV2; /* Label or name for the V2 file */
154
+ const char *zOut; /* Label or name for the output */
155
+ Blob *pPivot; /* The common ancestor */
156
+ Blob *pV1; /* First variant (local copy) */
157
+ Blob *pV2; /* Second variant (merged in) */
158
+ Blob *pOut; /* Write merge results here */
159
+ int useCrLf; /* Use CRLF line endings */
160
+ int nContext; /* Size of unchanged line boundaries */
161
+ unsigned int mxPivot; /* Number of lines in the pivot */
162
+ unsigned int mxV1; /* Number of lines in V1 */
163
+ unsigned int mxV2; /* Number of lines in V2 */
164
+ unsigned int lnPivot; /* Lines read from pivot */
165
+ unsigned int lnV1; /* Lines read from v1 */
166
+ unsigned int lnV2; /* Lines read from v2 */
167
+ unsigned int lnOut; /* Lines written to out */
168
+ unsigned int nConflict; /* Number of conflicts seen */
169
+ u64 diffFlags; /* Flags for difference engine */
170
+};
171
+#endif /* INTERFACE */
172
+
173
+
174
+/************************* Generic MergeBuilder ******************************/
175
+/* These are generic methods for MergeBuilder. They just output debugging
176
+** information. But some of them are useful as base methods for other useful
177
+** implementations of MergeBuilder.
178
+*/
179
+
180
+/* xStart() and xEnd() are called to generate header and fotter information
181
+** in the output. This is a no-op in the generic implementation.
182
+*/
183
+static void dbgStartEnd(MergeBuilder *p){ (void)p; }
184
+
185
+/* The next N lines of PIVOT are unchanged in both V1 and V2
186
+*/
187
+static void dbgSame(MergeBuilder *p, unsigned int N){
188
+ blob_appendf(p->pOut,
189
+ "COPY %u from BASELINE(%u..%u) or V1(%u..%u) or V2(%u..%u)\n",
190
+ N, p->lnPivot+1, p->lnPivot+N, p->lnV1+1, p->lnV1+N,
191
+ p->lnV2+1, p->lnV2+N);
192
+ p->lnPivot += N;
193
+ p->lnV1 += N;
194
+ p->lnV2 += N;
195
+}
196
+
197
+/* The next nPivot lines of the PIVOT are changed into nV1 lines by V1
198
+*/
199
+static void dbgChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
200
+ blob_appendf(p->pOut, "COPY %u from V1(%u..%u)\n",
201
+ nV1, p->lnV1+1, p->lnV1+nV1);
202
+ p->lnPivot += nPivot;
203
+ p->lnV2 += nPivot;
204
+ p->lnV1 += nV1;
205
+}
206
+
207
+/* The next nPivot lines of the PIVOT are changed into nV2 lines by V2
208
+*/
209
+static void dbgChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
210
+ blob_appendf(p->pOut, "COPY %u lines FROM V2(%u..%u)\n",
211
+ nV2, p->lnV2+1, p->lnV2+nV2);
212
+ p->lnPivot += nPivot;
213
+ p->lnV1 += nPivot;
214
+ p->lnV2 += nV2;
215
+}
216
+
217
+/* The next nPivot lines of the PIVOT are changed into nV lines from V1 and
218
+** V2, which should be the same. In other words, the same change is found
219
+** in both V1 and V2.
220
+*/
221
+static void dbgChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
222
+ blob_appendf(p->pOut, "COPY %u lines from V1(%u..%u) or V2(%u..%u)\n",
223
+ nV, p->lnV1+1, p->lnV1+nV, p->lnV2+1, p->lnV2+nV);
224
+ p->lnPivot += nPivot;
225
+ p->lnV1 += nV;
226
+ p->lnV2 += nV;
227
+}
228
+
229
+/* V1 and V2 have different and overlapping changes. The next nPivot lines
230
+** of the PIVOT are converted into nV1 lines of V1 and nV2 lines of V2.
231
+*/
232
+static void dbgConflict(
233
+ MergeBuilder *p,
234
+ unsigned int nPivot,
235
+ unsigned int nV1,
236
+ unsigned int nV2
237
+){
238
+ blob_appendf(p->pOut,
239
+ "CONFLICT %u,%u,%u BASELINE(%u..%u) versus V1(%u..%u) versus V2(%u..%u)\n",
240
+ nPivot, nV1, nV2,
241
+ p->lnPivot+1, p->lnPivot+nPivot,
242
+ p->lnV1+1, p->lnV1+nV1,
243
+ p->lnV2+1, p->lnV2+nV2);
244
+ p->lnV1 += nV1;
245
+ p->lnPivot += nPivot;
246
+ p->lnV2 += nV2;
247
+}
248
+
249
+/* Generic destructor for the MergeBuilder object
250
+*/
251
+static void dbgDestroy(MergeBuilder *p){
252
+ memset(p, 0, sizeof(*p));
253
+}
254
+
255
+/* Generic initializer for a MergeBuilder object
256
+*/
257
+static void mergebuilder_init(MergeBuilder *p){
258
+ memset(p, 0, sizeof(*p));
259
+ p->xStart = dbgStartEnd;
260
+ p->xSame = dbgSame;
261
+ p->xChngV1 = dbgChngV1;
262
+ p->xChngV2 = dbgChngV2;
263
+ p->xChngBoth = dbgChngBoth;
264
+ p->xConflict = dbgConflict;
265
+ p->xEnd = dbgStartEnd;
266
+ p->xDestroy = dbgDestroy;
267
+}
268
+
269
+/************************* MergeBuilderToken ********************************/
270
+/* This version of MergeBuilder actually performs a merge on file that
271
+** are broken up into tokens instead of lines, and puts the result in pOut.
272
+*/
273
+static void tokenSame(MergeBuilder *p, unsigned int N){
274
+ blob_append(p->pOut, p->pPivot->aData+p->pPivot->iCursor, N);
275
+ p->pPivot->iCursor += N;
276
+ p->pV1->iCursor += N;
277
+ p->pV2->iCursor += N;
278
+}
279
+static void tokenChngV1(MergeBuilder *p, unsigned int nPivot, unsigned nV1){
280
+ blob_append(p->pOut, p->pV1->aData+p->pV1->iCursor, nV1);
281
+ p->pPivot->iCursor += nPivot;
282
+ p->pV1->iCursor += nV1;
283
+ p->pV2->iCursor += nPivot;
284
+}
285
+static void tokenChngV2(MergeBuilder *p, unsigned int nPivot, unsigned nV2){
286
+ blob_append(p->pOut, p->pV2->aData+p->pV2->iCursor, nV2);
287
+ p->pPivot->iCursor += nPivot;
288
+ p->pV1->iCursor += nPivot;
289
+ p->pV2->iCursor += nV2;
290
+}
291
+static void tokenChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned nV){
292
+ blob_append(p->pOut, p->pV2->aData+p->pV2->iCursor, nV);
293
+ p->pPivot->iCursor += nPivot;
294
+ p->pV1->iCursor += nV;
295
+ p->pV2->iCursor += nV;
296
+}
297
+static void tokenConflict(
298
+ MergeBuilder *p,
299
+ unsigned int nPivot,
300
+ unsigned int nV1,
301
+ unsigned int nV2
302
+){
303
+ /* For a token-merge conflict, use the text from the merge-in */
304
+ blob_append(p->pOut, p->pV2->aData+p->pV2->iCursor, nV2);
305
+ p->pPivot->iCursor += nPivot;
306
+ p->pV1->iCursor += nV1;
307
+ p->pV2->iCursor += nV2;
308
+}
309
+static void mergebuilder_init_token(MergeBuilder *p){
310
+ mergebuilder_init(p);
311
+ p->xSame = tokenSame;
312
+ p->xChngV1 = tokenChngV1;
313
+ p->xChngV2 = tokenChngV2;
314
+ p->xChngBoth = tokenChngBoth;
315
+ p->xConflict = tokenConflict;
316
+ p->diffFlags = DIFF_BY_TOKEN;
317
+}
318
+
319
+/*
320
+** Attempt to do a low-level merge on a conflict. The conflict is
321
+** described by the first four parameters, which are the same as the
322
+** arguments to the xConflict method of the MergeBuilder object.
323
+** This routine attempts to resolve the conflict by looking at
324
+** elements of the conflict region that are finer grain than complete
325
+** lines of text.
326
+**
327
+** The result is written into Blob pOut. pOut is initialized by this
328
+** routine.
329
+*/
330
+int merge_try_to_resolve_conflict(
331
+ MergeBuilder *pMB, /* MergeBuilder that encounter conflict */
332
+ unsigned int nPivot, /* Lines of conflict in the pivot */
333
+ unsigned int nV1, /* Lines of conflict in V1 */
334
+ unsigned int nV2, /* Lines of conflict in V2 */
335
+ Blob *pOut /* Write resolution text here */
336
+){
337
+ int nConflict;
338
+ MergeBuilder mb;
339
+ Blob pv, v1, v2;
340
+ mergebuilder_init_token(&mb);
341
+ blob_extract_lines(pMB->pPivot, nPivot, &pv);
342
+ blob_extract_lines(pMB->pV1, nV1, &v1);
343
+ blob_extract_lines(pMB->pV2, nV2, &v2);
344
+ blob_zero(pOut);
345
+ blob_materialize(&pv);
346
+ blob_materialize(&v1);
347
+ blob_materialize(&v2);
348
+ mb.pPivot = &pv;
349
+ mb.pV1 = &v1;
350
+ mb.pV2 = &v2;
351
+ mb.pOut = pOut;
352
+ nConflict = merge_three_blobs(&mb);
353
+ blob_reset(&pv);
354
+ blob_reset(&v1);
355
+ blob_reset(&v2);
356
+ /* mb has not allocated any resources, so we do not need to invoke
357
+ ** the xDestroy method. */
358
+ blob_add_final_newline(pOut);
359
+ return nConflict;
360
+}
361
+
362
+
363
+/************************* MergeBuilderText **********************************/
364
+/* This version of MergeBuilder actually performs a merge on file and puts
365
+** the result in pOut
366
+*/
367
+static void txtStart(MergeBuilder *p){
368
+ /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
369
+ ** keep it in the output. This should be secure enough not to cause
370
+ ** unintended changes to the merged file and consistent with what
371
+ ** users are using in their source files.
372
+ */
373
+ if( starts_with_utf8_bom(p->pV1, 0) && starts_with_utf8_bom(p->pV2, 0) ){
374
+ blob_append(p->pOut, (char*)get_utf8_bom(0), -1);
375
+ }
376
+ if( contains_crlf(p->pV1) && contains_crlf(p->pV2) ){
377
+ p->useCrLf = 1;
378
+ }
379
+}
380
+static void txtSame(MergeBuilder *p, unsigned int N){
381
+ blob_copy_lines(p->pOut, p->pPivot, N); p->lnPivot += N;
382
+ blob_copy_lines(0, p->pV1, N); p->lnV1 += N;
383
+ blob_copy_lines(0, p->pV2, N); p->lnV2 += N;
384
+}
385
+static void txtChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
386
+ blob_copy_lines(0, p->pPivot, nPivot); p->lnPivot += nPivot;
387
+ blob_copy_lines(0, p->pV2, nPivot); p->lnV2 += nPivot;
388
+ blob_copy_lines(p->pOut, p->pV1, nV1); p->lnV1 += nV1;
389
+}
390
+static void txtChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
391
+ blob_copy_lines(0, p->pPivot, nPivot); p->lnPivot += nPivot;
392
+ blob_copy_lines(0, p->pV1, nPivot); p->lnV1 += nPivot;
393
+ blob_copy_lines(p->pOut, p->pV2, nV2); p->lnV2 += nV2;
394
+}
395
+static void txtChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
396
+ blob_copy_lines(0, p->pPivot, nPivot); p->lnPivot += nPivot;
397
+ blob_copy_lines(0, p->pV1, nV); p->lnV1 += nV;
398
+ blob_copy_lines(p->pOut, p->pV2, nV); p->lnV2 += nV;
399
+}
400
+static void txtConflict(
401
+ MergeBuilder *p,
402
+ unsigned int nPivot,
403
+ unsigned int nV1,
404
+ unsigned int nV2
405
+){
406
+ int nRes; /* Lines in the computed conflict resolution */
407
+ Blob res; /* Text of the conflict resolution */
408
+
409
+ merge_try_to_resolve_conflict(p, nPivot, nV1, nV2, &res);
410
+ nRes = blob_linecount(&res);
411
+
412
+ append_merge_mark(p->pOut, 0, p->lnV1+1, p->useCrLf);
413
+ blob_copy_lines(p->pOut, p->pV1, nV1); p->lnV1 += nV1;
414
+
415
+ if( nRes>0 ){
416
+ append_merge_mark(p->pOut, 1, 0, p->useCrLf);
417
+ blob_copy_lines(p->pOut, &res, nRes);
418
+ }
419
+ blob_reset(&res);
420
+
421
+ append_merge_mark(p->pOut, 2, p->lnPivot+1, p->useCrLf);
422
+ blob_copy_lines(p->pOut, p->pPivot, nPivot); p->lnPivot += nPivot;
423
+
424
+ append_merge_mark(p->pOut, 3, p->lnV2+1, p->useCrLf);
425
+ blob_copy_lines(p->pOut, p->pV2, nV2); p->lnV2 += nV2;
426
+
427
+ append_merge_mark(p->pOut, 4, -1, p->useCrLf);
428
+}
429
+static void mergebuilder_init_text(MergeBuilder *p){
430
+ mergebuilder_init(p);
431
+ p->xStart = txtStart;
432
+ p->xSame = txtSame;
433
+ p->xChngV1 = txtChngV1;
434
+ p->xChngV2 = txtChngV2;
435
+ p->xChngBoth = txtChngBoth;
436
+ p->xConflict = txtConflict;
437
+}
438
+
439
+/************************* MergeBuilderTcl **********************************/
440
+/* Generate merge output formatted for reading by a TCL script.
441
+**
442
+** The output consists of lines of text, each with 4 tokens. The tokens
443
+** represent the content for one line from baseline, v1, v2, and output
444
+** respectively. The first character of each token provides auxiliary
445
+** information:
446
+**
447
+** . This line is omitted.
448
+** N Name of the file.
449
+** T Literal text follows that should have a \n terminator.
450
+** R Literal text follows that needs a \r\n terminator.
451
+** X Merge conflict.
452
+** Z Literal text without a line terminator.
453
+** S Skipped lines. Followed by number of lines to skip.
454
+** 1 Text is a copy of token 1
455
+** 2 Use data from data-token 2
456
+** 3 Use data from data-token 3
457
+*/
458
+
459
+/* Write text that goes into the interior of a double-quoted string in TCL */
460
+static void tclWriteQuotedText(Blob *pOut, const char *zIn, int nIn){
461
+ int j;
462
+ for(j=0; j<nIn; j++){
463
+ char c = zIn[j];
464
+ if( c=='\\' ){
465
+ blob_append(pOut, "\\\\", 2);
466
+ }else if( c=='"' ){
467
+ blob_append(pOut, "\\\"", 2);
468
+ }else if( c<' ' || c>0x7e ){
469
+ char z[5];
470
+ z[0] = '\\';
471
+ z[1] = "01234567"[(c>>6)&0x3];
472
+ z[2] = "01234567"[(c>>3)&0x7];
473
+ z[3] = "01234567"[c&0x7];
474
+ z[4] = 0;
475
+ blob_append(pOut, z, 4);
476
+ }else{
477
+ blob_append_char(pOut, c);
478
+ }
479
+ }
480
+}
481
+
482
+/* Copy one line of text from pIn and append to pOut, encoded as TCL */
483
+static void tclLineOfText(Blob *pOut, Blob *pIn, char cType){
484
+ int i, k;
485
+ for(i=pIn->iCursor; i<pIn->nUsed && pIn->aData[i]!='\n'; i++){}
486
+ if( i==pIn->nUsed ){
487
+ k = i;
488
+ }else if( i>pIn->iCursor && pIn->aData[i-1]=='\r' ){
489
+ k = i-1;
490
+ i++;
491
+ }else{
492
+ k = i;
493
+ i++;
494
+ }
495
+ blob_append_char(pOut, '"');
496
+ blob_append_char(pOut, cType);
497
+ tclWriteQuotedText(pOut, pIn->aData+pIn->iCursor, k-pIn->iCursor);
498
+ pIn->iCursor = i;
499
+ blob_append_char(pOut, '"');
500
+}
501
+static void tclStart(MergeBuilder *p){
502
+ Blob *pOut = p->pOut;
503
+ blob_append(pOut, "\"N", 2);
504
+ tclWriteQuotedText(pOut, p->zPivot, (int)strlen(p->zPivot));
505
+ blob_append(pOut, "\" \"N", 4);
506
+ tclWriteQuotedText(pOut, p->zV1, (int)strlen(p->zV1));
507
+ blob_append(pOut, "\" \"N", 4);
508
+ tclWriteQuotedText(pOut, p->zV2, (int)strlen(p->zV2));
509
+ blob_append(pOut, "\" \"N", 4);
510
+ if( p->zOut ){
511
+ tclWriteQuotedText(pOut, p->zOut, (int)strlen(p->zOut));
512
+ }else{
513
+ blob_append(pOut, "(Merge Result)", -1);
514
+ }
515
+ blob_append(pOut, "\"\n", 2);
516
+}
517
+static void tclSame(MergeBuilder *p, unsigned int N){
518
+ int i = 0;
519
+ int nSkip;
520
+
521
+ if( p->lnPivot>=2 || p->lnV1>2 || p->lnV2>2 ){
522
+ while( i<N && i<p->nContext ){
523
+ tclLineOfText(p->pOut, p->pPivot, 'T');
524
+ blob_append(p->pOut, " 1 1 1\n", 7);
525
+ i++;
526
+ }
527
+ nSkip = N - p->nContext*2;
528
+ }else{
529
+ nSkip = N - p->nContext;
530
+ }
531
+ if( nSkip>0 ){
532
+ blob_appendf(p->pOut, "\"S%d %d %d %d\" . . .\n",
533
+ nSkip, nSkip, nSkip, nSkip);
534
+ blob_copy_lines(0, p->pPivot, nSkip);
535
+ i += nSkip;
536
+ }
537
+
538
+ p->lnPivot += N;
539
+ p->lnV1 += N;
540
+ p->lnV2 += N;
541
+
542
+ if( p->lnPivot<p->mxPivot || p->lnV1<p->mxV1 || p->lnV2<p->mxV2 ){
543
+ while( i<N ){
544
+ tclLineOfText(p->pOut, p->pPivot, 'T');
545
+ blob_append(p->pOut, " 1 1 1\n", 7);
546
+ i++;
547
+ }
548
+ }
549
+
550
+ blob_copy_lines(0, p->pV1, N);
551
+ blob_copy_lines(0, p->pV2, N);
552
+}
553
+static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
554
+ int i;
555
+ for(i=0; i<nPivot && i<nV1; i++){
556
+ tclLineOfText(p->pOut, p->pPivot, 'T');
557
+ blob_append_char(p->pOut, ' ');
558
+ tclLineOfText(p->pOut, p->pV1, 'T');
559
+ blob_append(p->pOut, " 1 2\n", 5);
560
+ }
561
+ while( i<nPivot ){
562
+ tclLineOfText(p->pOut, p->pPivot, 'T');
563
+ blob_append(p->pOut, " . 1 .\n", 7);
564
+ i++;
565
+ }
566
+ while( i<nV1 ){
567
+ blob_append(p->pOut, ". ", 2);
568
+ tclLineOfText(p->pOut, p->pV1, 'T');
569
+ blob_append(p->pOut, " . 2\n", 5);
570
+ i++;
571
+ }
572
+ p->lnPivot += nPivot;
573
+ p->lnV1 += nV1;
574
+ p->lnV2 += nPivot;
575
+ blob_copy_lines(0, p->pV2, nPivot);
576
+}
577
+static void tclChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
578
+ int i;
579
+ for(i=0; i<nPivot && i<nV2; i++){
580
+ tclLineOfText(p->pOut, p->pPivot, 'T');
581
+ blob_append(p->pOut, " 1 ", 3);
582
+ tclLineOfText(p->pOut, p->pV2, 'T');
583
+ blob_append(p->pOut, " 3\n", 3);
584
+ }
585
+ while( i<nPivot ){
586
+ tclLineOfText(p->pOut, p->pPivot, 'T');
587
+ blob_append(p->pOut, " 1 . .\n", 7);
588
+ i++;
589
+ }
590
+ while( i<nV2 ){
591
+ blob_append(p->pOut, ". . ", 4);
592
+ tclLineOfText(p->pOut, p->pV2, 'T');
593
+ blob_append(p->pOut, " 3\n", 3);
594
+ i++;
595
+ }
596
+ p->lnPivot += nPivot;
597
+ p->lnV1 += nPivot;
598
+ p->lnV2 += nV2;
599
+ blob_copy_lines(0, p->pV1, nPivot);
600
+}
601
+static void tclChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
602
+ int i;
603
+ for(i=0; i<nPivot && i<nV; i++){
604
+ tclLineOfText(p->pOut, p->pPivot, 'T');
605
+ blob_append_char(p->pOut, ' ');
606
+ tclLineOfText(p->pOut, p->pV1, 'T');
607
+ blob_append(p->pOut, " 2 2\n", 5);
608
+ }
609
+ while( i<nPivot ){
610
+ tclLineOfText(p->pOut, p->pPivot, 'T');
611
+ blob_append(p->pOut, " . . .\n", 7);
612
+ i++;
613
+ }
614
+ while( i<nV ){
615
+ blob_append(p->pOut, ". ", 2);
616
+ tclLineOfText(p->pOut, p->pV1, 'T');
617
+ blob_append(p->pOut, " 2 2\n", 5);
618
+ i++;
619
+ }
620
+ p->lnPivot += nPivot;
621
+ p->lnV1 += nV;
622
+ p->lnV2 += nV;
623
+ blob_copy_lines(0, p->pV2, nV);
624
+}
625
+static void tclConflict(
626
+ MergeBuilder *p,
627
+ unsigned int nPivot,
628
+ unsigned int nV1,
629
+ unsigned int nV2
630
+){
631
+ int mx = nPivot;
632
+ int i;
633
+ int nRes;
634
+ Blob res;
635
+
636
+ merge_try_to_resolve_conflict(p, nPivot, nV1, nV2, &res);
637
+ nRes = blob_linecount(&res);
638
+ if( nV1>mx ) mx = nV1;
639
+ if( nV2>mx ) mx = nV2;
640
+ if( nRes>mx ) mx = nRes;
641
+ if( nRes>0 ){
642
+ blob_appendf(p->pOut, "\"S0 0 0 %d\" . . .\n", nV2+2);
643
+ }
644
+ for(i=0; i<mx; i++){
645
+ if( i<nPivot ){
646
+ tclLineOfText(p->pOut, p->pPivot, 'X');
647
+ }else{
648
+ blob_append_char(p->pOut, '.');
649
+ }
650
+ blob_append_char(p->pOut, ' ');
651
+ if( i<nV1 ){
652
+ tclLineOfText(p->pOut, p->pV1, 'X');
653
+ }else{
654
+ blob_append_char(p->pOut, '.');
655
+ }
656
+ blob_append_char(p->pOut, ' ');
657
+ if( i<nV2 ){
658
+ tclLineOfText(p->pOut, p->pV2, 'X');
659
+ }else{
660
+ blob_append_char(p->pOut, '.');
661
+ }
662
+ if( i<nRes ){
663
+ blob_append_char(p->pOut, ' ');
664
+ tclLineOfText(p->pOut, &res, 'X');
665
+ blob_append_char(p->pOut, '\n');
666
+ }else{
667
+ blob_append(p->pOut, " .\n", 3);
668
+ }
669
+ if( i==mx-1 ){
670
+ blob_appendf(p->pOut, "\"S0 0 0 %d\" . . .\n", nPivot+nV1+3);
671
+ }
672
+ }
673
+ blob_reset(&res);
674
+ p->lnPivot += nPivot;
675
+ p->lnV1 += nV1;
676
+ p->lnV2 += nV2;
677
+}
678
+void mergebuilder_init_tcl(MergeBuilder *p){
679
+ mergebuilder_init(p);
680
+ p->xStart = tclStart;
681
+ p->xSame = tclSame;
682
+ p->xChngV1 = tclChngV1;
683
+ p->xChngV2 = tclChngV2;
684
+ p->xChngBoth = tclChngBoth;
685
+ p->xConflict = tclConflict;
686
+}
687
+/*****************************************************************************/
688
+
689
+/*
690
+** The aC[] array contains triples of integers. Within each triple, the
691
+** elements are:
692
+**
693
+** (0) The number of lines to copy
694
+** (1) The number of lines to delete
695
+** (2) The number of liens to insert
696
+**
697
+** Suppose we want to advance over sz lines of the original file. This routine
698
+** returns true if that advance would land us on a copy operation. It
699
+** returns false if the advance would end on a delete.
700
+*/
701
+static int ends_with_copy(int *aC, int sz){
702
+ while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
703
+ if( aC[0]>=sz ) return 1;
704
+ sz -= aC[0];
705
+ if( aC[1]>sz ) return 0;
706
+ sz -= aC[1];
707
+ aC += 3;
708
+ }
709
+ return 1;
710
+}
711
+
712
+/*
713
+** aC[] is an "edit triple" for changes from A to B. Advance through
714
+** this triple to determine the number of lines to bypass on B in order
715
+** to match an advance of sz lines on A.
716
+*/
717
+static int skip_conflict(
718
+ int *aC, /* Array of integer triples describing the edit */
719
+ int i, /* Index in aC[] of current location */
720
+ int sz, /* Lines of A that have been skipped */
721
+ unsigned int *pLn /* OUT: Lines of B to skip to keep aligment with A */
722
+){
723
+ *pLn = 0;
724
+ while( sz>0 ){
725
+ if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
726
+ if( aC[i]>=sz ){
727
+ aC[i] -= sz;
728
+ *pLn += sz;
729
+ break;
730
+ }
731
+ *pLn += aC[i];
732
+ *pLn += aC[i+2];
733
+ sz -= aC[i] + aC[i+1];
734
+ i += 3;
735
+ }
736
+ return i;
737
+}
191738
192739
/*
193740
** Do a three-way merge. Initialize pOut to contain the result.
194741
**
195742
** The merge is an edit against pV2. Both pV1 and pV2 have a
@@ -199,156 +746,113 @@
199746
** The return is 0 upon complete success. If any input file is binary,
200747
** -1 is returned and pOut is unmodified. If there are merge
201748
** conflicts, the merge proceeds as best as it can and the number
202749
** of conflicts is returns
203750
*/
204
-static int blob_merge(Blob *pPivot, Blob *pV1, Blob *pV2, Blob *pOut){
751
+int merge_three_blobs(MergeBuilder *p){
205752
int *aC1; /* Changes from pPivot to pV1 */
206753
int *aC2; /* Changes from pPivot to pV2 */
207754
int i1, i2; /* Index into aC1[] and aC2[] */
208755
int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
209756
int limit1, limit2; /* Sizes of aC1[] and aC2[] */
210757
int nConflict = 0; /* Number of merge conflicts seen so far */
211
- int useCrLf = 0;
212
- int ln1, ln2, lnPivot; /* Line numbers for all files */
213758
DiffConfig DCfg;
214759
215
- blob_zero(pOut); /* Merge results stored in pOut */
216
-
217
- /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
218
- ** keep it in the output. This should be secure enough not to cause
219
- ** unintended changes to the merged file and consistent with what
220
- ** users are using in their source files.
221
- */
222
- if( starts_with_utf8_bom(pV1, 0) && starts_with_utf8_bom(pV2, 0) ){
223
- blob_append(pOut, (char*)get_utf8_bom(0), -1);
224
- }
225
-
226
- /* Check once to see if both pV1 and pV2 contains CR/LF endings.
227
- ** If true, CR/LF pair will be used later to append the
228
- ** boundary markers for merge conflicts.
229
- */
230
- if( contains_crlf(pV1) && contains_crlf(pV2) ){
231
- useCrLf = 1;
232
- }
233
-
234760
/* Compute the edits that occur from pPivot => pV1 (into aC1)
235761
** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is
236762
** an array of integer triples. Within each triple, the first integer
237763
** is the number of lines of text to copy directly from the pivot,
238764
** the second integer is the number of lines of text to omit from the
239765
** pivot, and the third integer is the number of lines of text that are
240766
** inserted. The edit array ends with a triple of 0,0,0.
241767
*/
242768
diff_config_init(&DCfg, 0);
243
- aC1 = text_diff(pPivot, pV1, 0, &DCfg);
244
- aC2 = text_diff(pPivot, pV2, 0, &DCfg);
769
+ DCfg.diffFlags = p->diffFlags;
770
+ aC1 = text_diff(p->pPivot, p->pV1, 0, &DCfg);
771
+ aC2 = text_diff(p->pPivot, p->pV2, 0, &DCfg);
245772
if( aC1==0 || aC2==0 ){
246773
free(aC1);
247774
free(aC2);
248775
return -1;
249776
}
250777
251
- blob_rewind(pV1); /* Rewind inputs: Needed to reconstruct output */
252
- blob_rewind(pV2);
253
- blob_rewind(pPivot);
778
+ blob_rewind(p->pV1); /* Rewind inputs: Needed to reconstruct output */
779
+ blob_rewind(p->pV2);
780
+ blob_rewind(p->pPivot);
254781
255782
/* Determine the length of the aC1[] and aC2[] change vectors */
256
- for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){}
783
+ p->mxPivot = 0;
784
+ p->mxV1 = 0;
785
+ for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){
786
+ p->mxPivot += aC1[i1] + aC1[i1+1];
787
+ p->mxV1 += aC1[i1] + aC1[i1+2];
788
+ }
257789
limit1 = i1;
258
- for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){}
790
+ p->mxV2 = 0;
791
+ for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){
792
+ p->mxV2 += aC2[i2] + aC2[i2+2];
793
+ }
259794
limit2 = i2;
260795
261
- DEBUG(
262
- for(i1=0; i1<limit1; i1+=3){
263
- printf("c1: %4d %4d %4d\n", aC1[i1], aC1[i1+1], aC1[i1+2]);
264
- }
265
- for(i2=0; i2<limit2; i2+=3){
266
- printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]);
267
- }
268
- )
796
+ /* Output header text and do any other required initialization */
797
+ p->xStart(p);
269798
270799
/* Loop over the two edit vectors and use them to compute merged text
271800
** which is written into pOut. i1 and i2 are multiples of 3 which are
272801
** indices into aC1[] and aC2[] to the edit triple currently being
273802
** processed
274803
*/
275804
i1 = i2 = 0;
276
- ln1 = ln2 = lnPivot = 1;
277805
while( i1<limit1 && i2<limit2 ){
278
- DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n",
279
- i1/3, aC1[i1], aC1[i1+1], aC1[i1+2],
280
- i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); )
281
-
282806
if( aC1[i1]>0 && aC2[i2]>0 ){
283807
/* Output text that is unchanged in both V1 and V2 */
284808
nCpy = min(aC1[i1], aC2[i2]);
285
- DEBUG( printf("COPY %d\n", nCpy); )
286
- blob_copy_lines(pOut, pPivot, nCpy); lnPivot += nCpy;
287
- blob_copy_lines(0, pV1, nCpy); ln1 += nCpy;
288
- blob_copy_lines(0, pV2, nCpy); ln2 += nCpy;
809
+ p->xSame(p, nCpy);
289810
aC1[i1] -= nCpy;
290811
aC2[i2] -= nCpy;
291812
}else
292813
if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){
293814
/* Output edits to V2 that occurs within unchanged regions of V1 */
294815
nDel = aC2[i2+1];
295816
nIns = aC2[i2+2];
296
- DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); )
297
- blob_copy_lines(0, pPivot, nDel); lnPivot += nDel;
298
- blob_copy_lines(0, pV1, nDel); ln1 += nDel;
299
- blob_copy_lines(pOut, pV2, nIns); ln2 += nIns;
817
+ p->xChngV2(p, nDel, nIns);
300818
aC1[i1] -= nDel;
301819
i2 += 3;
302820
}else
303821
if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){
304822
/* Output edits to V1 that occur within unchanged regions of V2 */
305823
nDel = aC1[i1+1];
306824
nIns = aC1[i1+2];
307
- DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); )
308
- blob_copy_lines(0, pPivot, nDel); lnPivot += nDel;
309
- blob_copy_lines(0, pV2, nDel); ln2 += nDel;
310
- blob_copy_lines(pOut, pV1, nIns); ln1 += nIns;
825
+ p->xChngV1(p, nDel, nIns);
311826
aC2[i2] -= nDel;
312827
i1 += 3;
313828
}else
314
- if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){
829
+ if( sameEdit(&aC1[i1], &aC2[i2], p->pV1, p->pV2) ){
315830
/* Output edits that are identical in both V1 and V2. */
316831
assert( aC1[i1]==0 );
317832
nDel = aC1[i1+1];
318833
nIns = aC1[i1+2];
319
- DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); )
320
- blob_copy_lines(0, pPivot, nDel); lnPivot += nDel;
321
- blob_copy_lines(pOut, pV1, nIns); ln1 += nIns;
322
- blob_copy_lines(0, pV2, nIns); ln2 += nIns;
834
+ p->xChngBoth(p, nDel, nIns);
323835
i1 += 3;
324836
i2 += 3;
325837
}else
326838
{
327839
/* We have found a region where different edits to V1 and V2 overlap.
328840
** This is a merge conflict. Find the size of the conflict, then
329841
** output both possible edits separated by distinctive marks.
330842
*/
331
- int sz = 1; /* Size of the conflict in lines */
843
+ unsigned int sz = 1; /* Size of the conflict in the pivot, in lines */
844
+ unsigned int nV1, nV2; /* Size of conflict in V1 and V2, in lines */
332845
nConflict++;
333
- while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
846
+ while( !ends_with_copy(&aC1[i1], sz) || !ends_with_copy(&aC2[i2], sz) ){
334847
sz++;
335848
}
336
- DEBUG( printf("CONFLICT %d\n", sz); )
337
-
338
- append_merge_mark(pOut, 0, ln1, useCrLf);
339
- i1 = output_one_side(pOut, pV1, aC1, i1, sz, &ln1);
340
-
341
- append_merge_mark(pOut, 1, lnPivot, useCrLf);
342
- blob_copy_lines(pOut, pPivot, sz); lnPivot += sz;
343
-
344
- append_merge_mark(pOut, 2, ln2, useCrLf);
345
- i2 = output_one_side(pOut, pV2, aC2, i2, sz, &ln2);
346
-
347
- append_merge_mark(pOut, 3, -1, useCrLf);
348
- }
349
-
849
+ i1 = skip_conflict(aC1, i1, sz, &nV1);
850
+ i2 = skip_conflict(aC2, i2, sz, &nV2);
851
+ p->xConflict(p, sz, nV1, nV2);
852
+ }
853
+
350854
/* If we are finished with an edit triple, advance to the next
351855
** triple.
352856
*/
353857
if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3;
354858
if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3;
@@ -356,20 +860,18 @@
356860
357861
/* When one of the two edit vectors reaches its end, there might still
358862
** be an insert in the other edit vector. Output this remaining
359863
** insert.
360864
*/
361
- DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n",
362
- i1/3, aC1[i1], aC1[i1+1], aC1[i1+2],
363
- i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); )
364865
if( i1<limit1 && aC1[i1+2]>0 ){
365
- DEBUG( printf("INSERT +%d left\n", aC1[i1+2]); )
366
- blob_copy_lines(pOut, pV1, aC1[i1+2]);
866
+ p->xChngV1(p, 0, aC1[i1+2]);
367867
}else if( i2<limit2 && aC2[i2+2]>0 ){
368
- DEBUG( printf("INSERT +%d right\n", aC2[i2+2]); )
369
- blob_copy_lines(pOut, pV2, aC2[i2+2]);
868
+ p->xChngV2(p, 0, aC2[i2+2]);
370869
}
870
+
871
+ /* Output footer text */
872
+ p->xEnd(p);
371873
372874
free(aC1);
373875
free(aC2);
374876
return nConflict;
375877
}
@@ -384,11 +886,12 @@
384886
const char *z = blob_buffer(p);
385887
int n = blob_size(p) - len + 1;
386888
assert( len==(int)strlen(mergeMarker[1]) );
387889
assert( len==(int)strlen(mergeMarker[2]) );
388890
assert( len==(int)strlen(mergeMarker[3]) );
389
- assert( count(mergeMarker)==4 );
891
+ assert( len==(int)strlen(mergeMarker[4]) );
892
+ assert( count(mergeMarker)==5 );
390893
for(i=0; i<n; ){
391894
for(j=0; j<4; j++){
392895
if( (memcmp(&z[i], mergeMarker[j], len)==0) ){
393896
return 1;
394897
}
@@ -408,18 +911,106 @@
408911
blob_read_from_file(&file, zFullpath, ExtFILE);
409912
rc = contains_merge_marker(&file);
410913
blob_reset(&file);
411914
return rc;
412915
}
916
+
917
+/*
918
+** Show merge output in a Tcl/Tk window, in response to the --tk option
919
+** to the "merge" or "3-way-merge" command.
920
+**
921
+** If fossil has direct access to a Tcl interpreter (either loaded
922
+** dynamically through stubs or linked in statically), we can use it
923
+** directly. Otherwise:
924
+** (1) Write the Tcl/Tk script used for rendering into a temp file.
925
+** (2) Invoke "tclsh" on the temp file using fossil_system().
926
+** (3) Delete the temp file.
927
+*/
928
+void merge_tk(const char *zSubCmd, int firstArg){
929
+ int i;
930
+ Blob script;
931
+ const char *zTempFile = 0;
932
+ char *zCmd;
933
+ const char *zTclsh;
934
+ const char *zCnt;
935
+ int bDarkMode = find_option("dark",0,0)!=0;
936
+ int nContext;
937
+ zCnt = find_option("context", "c", 1);
938
+ if( zCnt==0 ){
939
+ nContext = 6;
940
+ }else{
941
+ nContext = atoi(zCnt);
942
+ if( nContext<0 ) nContext = 0xfffffff;
943
+ }
944
+ blob_zero(&script);
945
+ blob_appendf(&script, "set ncontext %d\n", nContext);
946
+ blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl",
947
+ g.nameOfExe, zSubCmd);
948
+ find_option("tcl",0,0);
949
+ find_option("debug",0,0);
950
+ zTclsh = find_option("tclsh",0,1);
951
+ if( zTclsh==0 ){
952
+ zTclsh = db_get("tclsh",0);
953
+ }
954
+ /* The undocumented --script FILENAME option causes the Tk script to
955
+ ** be written into the FILENAME instead of being run. This is used
956
+ ** for testing and debugging. */
957
+ zTempFile = find_option("script",0,1);
958
+ verify_all_options();
959
+
960
+ if( (g.argc - firstArg)!=3 ){
961
+ fossil_fatal("Requires 3 filename arguments");
962
+ }
963
+
964
+ for(i=firstArg; i<g.argc; i++){
965
+ const char *z = g.argv[i];
966
+ if( sqlite3_strglob("*}*",z) ){
967
+ blob_appendf(&script, " {%/}", z);
968
+ }else{
969
+ int j;
970
+ blob_append(&script, " ", 1);
971
+ for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
972
+ }
973
+ }
974
+ blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
975
+ blob_appendf(&script, "%s", builtin_file("merge.tcl", 0));
976
+ if( zTempFile ){
977
+ blob_write_to_file(&script, zTempFile);
978
+ fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile);
979
+ }else{
980
+#if defined(FOSSIL_ENABLE_TCL)
981
+ Th_FossilInit(TH_INIT_DEFAULT);
982
+ if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
983
+ blob_size(&script), 1, 1, 0)==TCL_OK ){
984
+ blob_reset(&script);
985
+ return;
986
+ }
987
+ /*
988
+ * If evaluation of the Tcl script fails, the reason may be that Tk
989
+ * could not be found by the loaded Tcl, or that Tcl cannot be loaded
990
+ * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
991
+ * to using the external "tclsh", if available.
992
+ */
993
+#endif
994
+ zTempFile = write_blob_to_temp_file(&script);
995
+ zCmd = mprintf("%$ %$", zTclsh, zTempFile);
996
+ fossil_system(zCmd);
997
+ file_delete(zTempFile);
998
+ fossil_free(zCmd);
999
+ }
1000
+ blob_reset(&script);
1001
+}
1002
+
4131003
4141004
/*
4151005
** COMMAND: 3-way-merge*
4161006
**
417
-** Usage: %fossil 3-way-merge BASELINE V1 V2 MERGED
1007
+** Usage: %fossil 3-way-merge BASELINE V1 V2 [MERGED]
4181008
**
4191009
** Inputs are files BASELINE, V1, and V2. The file MERGED is generated
420
-** as output.
1010
+** as output. If no MERGED file is specified, output is sent to
1011
+** stdout.
4211012
**
4221013
** BASELINE is a common ancestor of two files V1 and V2 that have diverging
4231014
** edits. The generated output file MERGED is the combination of all
4241015
** changes in both V1 and V2.
4251016
**
@@ -436,38 +1027,75 @@
4361027
** cp Xup.c Xbase.c
4371028
** # Verify that everything still works
4381029
** fossil commit
4391030
**
4401031
*/
441
-void delta_3waymerge_cmd(void){
442
- Blob pivot, v1, v2, merged;
1032
+void merge_3way_cmd(void){
1033
+ MergeBuilder s;
4431034
int nConflict;
1035
+ Blob pivot, v1, v2, out;
1036
+ int noWarn = 0;
1037
+ const char *zCnt;
1038
+
1039
+ if( find_option("tk", 0, 0)!=0 ){
1040
+ merge_tk("3-way-merge", 2);
1041
+ return;
1042
+ }
1043
+ mergebuilder_init_text(&s);
1044
+ if( find_option("debug", 0, 0) ){
1045
+ mergebuilder_init(&s);
1046
+ }
1047
+ if( find_option("tcl", 0, 0) ){
1048
+ mergebuilder_init_tcl(&s);
1049
+ noWarn = 1;
1050
+ }
1051
+ zCnt = find_option("context", "c", 1);
1052
+ if( zCnt ){
1053
+ s.nContext = atoi(zCnt);
1054
+ if( s.nContext<0 ) s.nContext = 0xfffffff;
1055
+ }else{
1056
+ s.nContext = 6;
1057
+ }
1058
+ blob_zero(&pivot); s.pPivot = &pivot;
1059
+ blob_zero(&v1); s.pV1 = &v1;
1060
+ blob_zero(&v2); s.pV2 = &v2;
1061
+ blob_zero(&out); s.pOut = &out;
4441062
4451063
/* We should be done with options.. */
4461064
verify_all_options();
4471065
448
- if( g.argc!=6 ){
449
- usage("PIVOT V1 V2 MERGED");
1066
+ if( g.argc!=6 && g.argc!=5 ){
1067
+ usage("[OPTIONS] PIVOT V1 V2 [MERGED]");
4501068
}
451
- if( blob_read_from_file(&pivot, g.argv[2], ExtFILE)<0 ){
1069
+ s.zPivot = file_tail(g.argv[2]);
1070
+ s.zV1 = file_tail(g.argv[3]);
1071
+ s.zV2 = file_tail(g.argv[4]);
1072
+ if( blob_read_from_file(s.pPivot, g.argv[2], ExtFILE)<0 ){
4521073
fossil_fatal("cannot read %s", g.argv[2]);
4531074
}
454
- if( blob_read_from_file(&v1, g.argv[3], ExtFILE)<0 ){
1075
+ if( blob_read_from_file(s.pV1, g.argv[3], ExtFILE)<0 ){
4551076
fossil_fatal("cannot read %s", g.argv[3]);
4561077
}
457
- if( blob_read_from_file(&v2, g.argv[4], ExtFILE)<0 ){
1078
+ if( blob_read_from_file(s.pV2, g.argv[4], ExtFILE)<0 ){
4581079
fossil_fatal("cannot read %s", g.argv[4]);
4591080
}
460
- nConflict = blob_merge(&pivot, &v1, &v2, &merged);
461
- if( blob_write_to_file(&merged, g.argv[5])<(int)blob_size(&merged) ){
462
- fossil_fatal("cannot write %s", g.argv[4]);
1081
+ nConflict = merge_three_blobs(&s);
1082
+ if( g.argc==6 ){
1083
+ s.zOut = file_tail(g.argv[5]);
1084
+ blob_write_to_file(s.pOut, g.argv[5]);
1085
+ }else{
1086
+ s.zOut = "(Merge Result)";
1087
+ blob_write_to_file(s.pOut, "-");
4631088
}
1089
+ s.xDestroy(&s);
4641090
blob_reset(&pivot);
4651091
blob_reset(&v1);
4661092
blob_reset(&v2);
467
- blob_reset(&merged);
468
- if( nConflict>0 ) fossil_warning("WARNING: %d merge conflicts", nConflict);
1093
+ blob_reset(&out);
1094
+ if( nConflict>0 && !noWarn ){
1095
+ fossil_warning("WARNING: %d merge conflicts", nConflict);
1096
+ }
4691097
}
4701098
4711099
/*
4721100
** aSubst is an array of string pairs. The first element of each pair is
4731101
** a string that begins with %. The second element is a replacement for that
@@ -505,32 +1133,32 @@
5051133
5061134
#if INTERFACE
5071135
/*
5081136
** Flags to the 3-way merger
5091137
*/
510
-#define MERGE_DRYRUN 0x0001
1138
+#define MERGE_DRYRUN 0x0001
5111139
/*
5121140
** The MERGE_KEEP_FILES flag specifies that merge_3way() should retain
5131141
** its temporary files on error. By default they are removed after the
5141142
** merge, regardless of success or failure.
5151143
*/
516
-#define MERGE_KEEP_FILES 0x0002
1144
+#define MERGE_KEEP_FILES 0x0002
5171145
#endif
5181146
5191147
5201148
/*
521
-** This routine is a wrapper around blob_merge() with the following
1149
+** This routine is a wrapper around merge_three_blobs() with the following
5221150
** enhancements:
5231151
**
5241152
** (1) If the merge-command is defined, then use the external merging
5251153
** program specified instead of the built-in blob-merge to do the
5261154
** merging. Panic if the external merger fails.
5271155
** ** Not currently implemented **
5281156
**
5291157
** (2) If gmerge-command is defined and there are merge conflicts in
530
-** blob_merge() then invoke the external graphical merger to resolve
531
-** the conflicts.
1158
+** merge_three_blobs() then invoke the external graphical merger
1159
+** to resolve the conflicts.
5321160
**
5331161
** (3) If a merge conflict occurs and gmerge-command is not defined,
5341162
** then write the pivot, original, and merge-in files to the
5351163
** filesystem.
5361164
*/
@@ -539,30 +1167,37 @@
5391167
const char *zV1, /* Name of file for version merging into (mine) */
5401168
Blob *pV2, /* Version merging from (yours) */
5411169
Blob *pOut, /* Output written here */
5421170
unsigned mergeFlags /* Flags that control operation */
5431171
){
544
- Blob v1; /* Content of zV1 */
545
- int rc; /* Return code of subroutines and this routine */
1172
+ Blob v1; /* Content of zV1 */
1173
+ int rc; /* Return code of subroutines and this routine */
5461174
const char *zGMerge; /* Name of the gmerge command */
1175
+ MergeBuilder s; /* The merge state */
5471176
548
- blob_read_from_file(&v1, zV1, ExtFILE);
549
- rc = blob_merge(pPivot, &v1, pV2, pOut);
1177
+ mergebuilder_init_text(&s);
1178
+ s.pPivot = pPivot;
1179
+ s.pV1 = &v1;
1180
+ s.pV2 = pV2;
1181
+ blob_zero(pOut);
1182
+ s.pOut = pOut;
1183
+ blob_read_from_file(s.pV1, zV1, ExtFILE);
1184
+ rc = merge_three_blobs(&s);
5501185
zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
5511186
if( (mergeFlags & MERGE_DRYRUN)==0
5521187
&& ((zGMerge!=0 && zGMerge[0]!=0)
5531188
|| (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
5541189
char *zPivot; /* Name of the pivot file */
5551190
char *zOrig; /* Name of the original content file */
5561191
char *zOther; /* Name of the merge file */
5571192
5581193
zPivot = file_newname(zV1, "baseline", 1);
559
- blob_write_to_file(pPivot, zPivot);
1194
+ blob_write_to_file(s.pPivot, zPivot);
5601195
zOrig = file_newname(zV1, "original", 1);
561
- blob_write_to_file(&v1, zOrig);
1196
+ blob_write_to_file(s.pV1, zOrig);
5621197
zOther = file_newname(zV1, "merge", 1);
563
- blob_write_to_file(pV2, zOther);
1198
+ blob_write_to_file(s.pV2, zOther);
5641199
if( rc>0 ){
5651200
if( zGMerge && zGMerge[0] ){
5661201
char *zOut; /* Temporary output file */
5671202
char *zCmd; /* Command to invoke */
5681203
const char *azSubst[8]; /* Strings to be substituted */
@@ -590,7 +1225,8 @@
5901225
fossil_free(zPivot);
5911226
fossil_free(zOrig);
5921227
fossil_free(zOther);
5931228
}
5941229
blob_reset(&v1);
1230
+ s.xDestroy(&s);
5951231
return rc;
5961232
}
5971233
--- src/merge3.c
+++ src/merge3.c
@@ -75,75 +75,17 @@
75 if( aC1[2]!=aC2[2] ) return 0;
76 if( sameLines(pV1, pV2, aC1[2]) ) return 1;
77 return 0;
78 }
79
80 /*
81 ** The aC[] array contains triples of integers. Within each triple, the
82 ** elements are:
83 **
84 ** (0) The number of lines to copy
85 ** (1) The number of lines to delete
86 ** (2) The number of liens to insert
87 **
88 ** Suppose we want to advance over sz lines of the original file. This routine
89 ** returns true if that advance would land us on a copy operation. It
90 ** returns false if the advance would end on a delete.
91 */
92 static int ends_at_CPY(int *aC, int sz){
93 while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
94 if( aC[0]>=sz ) return 1;
95 sz -= aC[0];
96 if( aC[1]>sz ) return 0;
97 sz -= aC[1];
98 aC += 3;
99 }
100 return 1;
101 }
102
103 /*
104 ** pSrc contains an edited file where aC[] describes the edit. Part of
105 ** pSrc has already been output. This routine outputs additional lines
106 ** of pSrc - lines that correspond to the next sz lines of the original
107 ** unedited file.
108 **
109 ** Note that sz counts the number of lines of text in the original file.
110 ** But text is output from the edited file. So the number of lines transfer
111 ** to pOut might be different from sz. Fewer lines appear in pOut if there
112 ** are deletes. More lines appear if there are inserts.
113 **
114 ** The aC[] array is updated and the new index into aC[] is returned.
115 */
116 static int output_one_side(
117 Blob *pOut, /* Write to this blob */
118 Blob *pSrc, /* The edited file that is to be copied to pOut */
119 int *aC, /* Array of integer triples describing the edit */
120 int i, /* Index in aC[] of current location in pSrc */
121 int sz, /* Number of lines in unedited source to output */
122 int *pLn /* Line number counter */
123 ){
124 while( sz>0 ){
125 if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
126 if( aC[i]>=sz ){
127 blob_copy_lines(pOut, pSrc, sz); *pLn += sz;
128 aC[i] -= sz;
129 break;
130 }
131 blob_copy_lines(pOut, pSrc, aC[i]); *pLn += aC[i];
132 blob_copy_lines(pOut, pSrc, aC[i+2]); *pLn += aC[i+2];
133 sz -= aC[i] + aC[i+1];
134 i += 3;
135 }
136 return i;
137 }
138
139 /*
140 ** Text of boundary markers for merge conflicts.
141 */
142 static const char *const mergeMarker[] = {
143 /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
144 "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<",
 
145 "||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||",
146 "======= MERGED IN content follows ===============================",
147 ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
148 };
149
@@ -186,10 +128,615 @@
186 ensure_line_end(pOut, useCrLf);
187 blob_append(pOut, mergeMarker[iMark], -1);
188 if( ln>0 ) blob_appendf(pOut, " (line %d)", ln);
189 ensure_line_end(pOut, useCrLf);
190 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
192 /*
193 ** Do a three-way merge. Initialize pOut to contain the result.
194 **
195 ** The merge is an edit against pV2. Both pV1 and pV2 have a
@@ -199,156 +746,113 @@
199 ** The return is 0 upon complete success. If any input file is binary,
200 ** -1 is returned and pOut is unmodified. If there are merge
201 ** conflicts, the merge proceeds as best as it can and the number
202 ** of conflicts is returns
203 */
204 static int blob_merge(Blob *pPivot, Blob *pV1, Blob *pV2, Blob *pOut){
205 int *aC1; /* Changes from pPivot to pV1 */
206 int *aC2; /* Changes from pPivot to pV2 */
207 int i1, i2; /* Index into aC1[] and aC2[] */
208 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
209 int limit1, limit2; /* Sizes of aC1[] and aC2[] */
210 int nConflict = 0; /* Number of merge conflicts seen so far */
211 int useCrLf = 0;
212 int ln1, ln2, lnPivot; /* Line numbers for all files */
213 DiffConfig DCfg;
214
215 blob_zero(pOut); /* Merge results stored in pOut */
216
217 /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
218 ** keep it in the output. This should be secure enough not to cause
219 ** unintended changes to the merged file and consistent with what
220 ** users are using in their source files.
221 */
222 if( starts_with_utf8_bom(pV1, 0) && starts_with_utf8_bom(pV2, 0) ){
223 blob_append(pOut, (char*)get_utf8_bom(0), -1);
224 }
225
226 /* Check once to see if both pV1 and pV2 contains CR/LF endings.
227 ** If true, CR/LF pair will be used later to append the
228 ** boundary markers for merge conflicts.
229 */
230 if( contains_crlf(pV1) && contains_crlf(pV2) ){
231 useCrLf = 1;
232 }
233
234 /* Compute the edits that occur from pPivot => pV1 (into aC1)
235 ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is
236 ** an array of integer triples. Within each triple, the first integer
237 ** is the number of lines of text to copy directly from the pivot,
238 ** the second integer is the number of lines of text to omit from the
239 ** pivot, and the third integer is the number of lines of text that are
240 ** inserted. The edit array ends with a triple of 0,0,0.
241 */
242 diff_config_init(&DCfg, 0);
243 aC1 = text_diff(pPivot, pV1, 0, &DCfg);
244 aC2 = text_diff(pPivot, pV2, 0, &DCfg);
 
245 if( aC1==0 || aC2==0 ){
246 free(aC1);
247 free(aC2);
248 return -1;
249 }
250
251 blob_rewind(pV1); /* Rewind inputs: Needed to reconstruct output */
252 blob_rewind(pV2);
253 blob_rewind(pPivot);
254
255 /* Determine the length of the aC1[] and aC2[] change vectors */
256 for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){}
 
 
 
 
 
257 limit1 = i1;
258 for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){}
 
 
 
259 limit2 = i2;
260
261 DEBUG(
262 for(i1=0; i1<limit1; i1+=3){
263 printf("c1: %4d %4d %4d\n", aC1[i1], aC1[i1+1], aC1[i1+2]);
264 }
265 for(i2=0; i2<limit2; i2+=3){
266 printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]);
267 }
268 )
269
270 /* Loop over the two edit vectors and use them to compute merged text
271 ** which is written into pOut. i1 and i2 are multiples of 3 which are
272 ** indices into aC1[] and aC2[] to the edit triple currently being
273 ** processed
274 */
275 i1 = i2 = 0;
276 ln1 = ln2 = lnPivot = 1;
277 while( i1<limit1 && i2<limit2 ){
278 DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n",
279 i1/3, aC1[i1], aC1[i1+1], aC1[i1+2],
280 i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); )
281
282 if( aC1[i1]>0 && aC2[i2]>0 ){
283 /* Output text that is unchanged in both V1 and V2 */
284 nCpy = min(aC1[i1], aC2[i2]);
285 DEBUG( printf("COPY %d\n", nCpy); )
286 blob_copy_lines(pOut, pPivot, nCpy); lnPivot += nCpy;
287 blob_copy_lines(0, pV1, nCpy); ln1 += nCpy;
288 blob_copy_lines(0, pV2, nCpy); ln2 += nCpy;
289 aC1[i1] -= nCpy;
290 aC2[i2] -= nCpy;
291 }else
292 if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){
293 /* Output edits to V2 that occurs within unchanged regions of V1 */
294 nDel = aC2[i2+1];
295 nIns = aC2[i2+2];
296 DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); )
297 blob_copy_lines(0, pPivot, nDel); lnPivot += nDel;
298 blob_copy_lines(0, pV1, nDel); ln1 += nDel;
299 blob_copy_lines(pOut, pV2, nIns); ln2 += nIns;
300 aC1[i1] -= nDel;
301 i2 += 3;
302 }else
303 if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){
304 /* Output edits to V1 that occur within unchanged regions of V2 */
305 nDel = aC1[i1+1];
306 nIns = aC1[i1+2];
307 DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); )
308 blob_copy_lines(0, pPivot, nDel); lnPivot += nDel;
309 blob_copy_lines(0, pV2, nDel); ln2 += nDel;
310 blob_copy_lines(pOut, pV1, nIns); ln1 += nIns;
311 aC2[i2] -= nDel;
312 i1 += 3;
313 }else
314 if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){
315 /* Output edits that are identical in both V1 and V2. */
316 assert( aC1[i1]==0 );
317 nDel = aC1[i1+1];
318 nIns = aC1[i1+2];
319 DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); )
320 blob_copy_lines(0, pPivot, nDel); lnPivot += nDel;
321 blob_copy_lines(pOut, pV1, nIns); ln1 += nIns;
322 blob_copy_lines(0, pV2, nIns); ln2 += nIns;
323 i1 += 3;
324 i2 += 3;
325 }else
326 {
327 /* We have found a region where different edits to V1 and V2 overlap.
328 ** This is a merge conflict. Find the size of the conflict, then
329 ** output both possible edits separated by distinctive marks.
330 */
331 int sz = 1; /* Size of the conflict in lines */
 
332 nConflict++;
333 while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
334 sz++;
335 }
336 DEBUG( printf("CONFLICT %d\n", sz); )
337
338 append_merge_mark(pOut, 0, ln1, useCrLf);
339 i1 = output_one_side(pOut, pV1, aC1, i1, sz, &ln1);
340
341 append_merge_mark(pOut, 1, lnPivot, useCrLf);
342 blob_copy_lines(pOut, pPivot, sz); lnPivot += sz;
343
344 append_merge_mark(pOut, 2, ln2, useCrLf);
345 i2 = output_one_side(pOut, pV2, aC2, i2, sz, &ln2);
346
347 append_merge_mark(pOut, 3, -1, useCrLf);
348 }
349
350 /* If we are finished with an edit triple, advance to the next
351 ** triple.
352 */
353 if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3;
354 if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3;
@@ -356,20 +860,18 @@
356
357 /* When one of the two edit vectors reaches its end, there might still
358 ** be an insert in the other edit vector. Output this remaining
359 ** insert.
360 */
361 DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n",
362 i1/3, aC1[i1], aC1[i1+1], aC1[i1+2],
363 i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); )
364 if( i1<limit1 && aC1[i1+2]>0 ){
365 DEBUG( printf("INSERT +%d left\n", aC1[i1+2]); )
366 blob_copy_lines(pOut, pV1, aC1[i1+2]);
367 }else if( i2<limit2 && aC2[i2+2]>0 ){
368 DEBUG( printf("INSERT +%d right\n", aC2[i2+2]); )
369 blob_copy_lines(pOut, pV2, aC2[i2+2]);
370 }
 
 
 
371
372 free(aC1);
373 free(aC2);
374 return nConflict;
375 }
@@ -384,11 +886,12 @@
384 const char *z = blob_buffer(p);
385 int n = blob_size(p) - len + 1;
386 assert( len==(int)strlen(mergeMarker[1]) );
387 assert( len==(int)strlen(mergeMarker[2]) );
388 assert( len==(int)strlen(mergeMarker[3]) );
389 assert( count(mergeMarker)==4 );
 
390 for(i=0; i<n; ){
391 for(j=0; j<4; j++){
392 if( (memcmp(&z[i], mergeMarker[j], len)==0) ){
393 return 1;
394 }
@@ -408,18 +911,106 @@
408 blob_read_from_file(&file, zFullpath, ExtFILE);
409 rc = contains_merge_marker(&file);
410 blob_reset(&file);
411 return rc;
412 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
414 /*
415 ** COMMAND: 3-way-merge*
416 **
417 ** Usage: %fossil 3-way-merge BASELINE V1 V2 MERGED
418 **
419 ** Inputs are files BASELINE, V1, and V2. The file MERGED is generated
420 ** as output.
 
421 **
422 ** BASELINE is a common ancestor of two files V1 and V2 that have diverging
423 ** edits. The generated output file MERGED is the combination of all
424 ** changes in both V1 and V2.
425 **
@@ -436,38 +1027,75 @@
436 ** cp Xup.c Xbase.c
437 ** # Verify that everything still works
438 ** fossil commit
439 **
440 */
441 void delta_3waymerge_cmd(void){
442 Blob pivot, v1, v2, merged;
443 int nConflict;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
445 /* We should be done with options.. */
446 verify_all_options();
447
448 if( g.argc!=6 ){
449 usage("PIVOT V1 V2 MERGED");
450 }
451 if( blob_read_from_file(&pivot, g.argv[2], ExtFILE)<0 ){
 
 
 
452 fossil_fatal("cannot read %s", g.argv[2]);
453 }
454 if( blob_read_from_file(&v1, g.argv[3], ExtFILE)<0 ){
455 fossil_fatal("cannot read %s", g.argv[3]);
456 }
457 if( blob_read_from_file(&v2, g.argv[4], ExtFILE)<0 ){
458 fossil_fatal("cannot read %s", g.argv[4]);
459 }
460 nConflict = blob_merge(&pivot, &v1, &v2, &merged);
461 if( blob_write_to_file(&merged, g.argv[5])<(int)blob_size(&merged) ){
462 fossil_fatal("cannot write %s", g.argv[4]);
 
 
 
 
463 }
 
464 blob_reset(&pivot);
465 blob_reset(&v1);
466 blob_reset(&v2);
467 blob_reset(&merged);
468 if( nConflict>0 ) fossil_warning("WARNING: %d merge conflicts", nConflict);
 
 
469 }
470
471 /*
472 ** aSubst is an array of string pairs. The first element of each pair is
473 ** a string that begins with %. The second element is a replacement for that
@@ -505,32 +1133,32 @@
505
506 #if INTERFACE
507 /*
508 ** Flags to the 3-way merger
509 */
510 #define MERGE_DRYRUN 0x0001
511 /*
512 ** The MERGE_KEEP_FILES flag specifies that merge_3way() should retain
513 ** its temporary files on error. By default they are removed after the
514 ** merge, regardless of success or failure.
515 */
516 #define MERGE_KEEP_FILES 0x0002
517 #endif
518
519
520 /*
521 ** This routine is a wrapper around blob_merge() with the following
522 ** enhancements:
523 **
524 ** (1) If the merge-command is defined, then use the external merging
525 ** program specified instead of the built-in blob-merge to do the
526 ** merging. Panic if the external merger fails.
527 ** ** Not currently implemented **
528 **
529 ** (2) If gmerge-command is defined and there are merge conflicts in
530 ** blob_merge() then invoke the external graphical merger to resolve
531 ** the conflicts.
532 **
533 ** (3) If a merge conflict occurs and gmerge-command is not defined,
534 ** then write the pivot, original, and merge-in files to the
535 ** filesystem.
536 */
@@ -539,30 +1167,37 @@
539 const char *zV1, /* Name of file for version merging into (mine) */
540 Blob *pV2, /* Version merging from (yours) */
541 Blob *pOut, /* Output written here */
542 unsigned mergeFlags /* Flags that control operation */
543 ){
544 Blob v1; /* Content of zV1 */
545 int rc; /* Return code of subroutines and this routine */
546 const char *zGMerge; /* Name of the gmerge command */
 
547
548 blob_read_from_file(&v1, zV1, ExtFILE);
549 rc = blob_merge(pPivot, &v1, pV2, pOut);
 
 
 
 
 
 
550 zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
551 if( (mergeFlags & MERGE_DRYRUN)==0
552 && ((zGMerge!=0 && zGMerge[0]!=0)
553 || (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
554 char *zPivot; /* Name of the pivot file */
555 char *zOrig; /* Name of the original content file */
556 char *zOther; /* Name of the merge file */
557
558 zPivot = file_newname(zV1, "baseline", 1);
559 blob_write_to_file(pPivot, zPivot);
560 zOrig = file_newname(zV1, "original", 1);
561 blob_write_to_file(&v1, zOrig);
562 zOther = file_newname(zV1, "merge", 1);
563 blob_write_to_file(pV2, zOther);
564 if( rc>0 ){
565 if( zGMerge && zGMerge[0] ){
566 char *zOut; /* Temporary output file */
567 char *zCmd; /* Command to invoke */
568 const char *azSubst[8]; /* Strings to be substituted */
@@ -590,7 +1225,8 @@
590 fossil_free(zPivot);
591 fossil_free(zOrig);
592 fossil_free(zOther);
593 }
594 blob_reset(&v1);
 
595 return rc;
596 }
597
--- src/merge3.c
+++ src/merge3.c
@@ -75,75 +75,17 @@
75 if( aC1[2]!=aC2[2] ) return 0;
76 if( sameLines(pV1, pV2, aC1[2]) ) return 1;
77 return 0;
78 }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80 /*
81 ** Text of boundary markers for merge conflicts.
82 */
83 static const char *const mergeMarker[] = {
84 /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
85 "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<",
86 "####### SUGGESTED CONFLICT RESOLUTION follows ###################",
87 "||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||",
88 "======= MERGED IN content follows ===============================",
89 ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
90 };
91
@@ -186,10 +128,615 @@
128 ensure_line_end(pOut, useCrLf);
129 blob_append(pOut, mergeMarker[iMark], -1);
130 if( ln>0 ) blob_appendf(pOut, " (line %d)", ln);
131 ensure_line_end(pOut, useCrLf);
132 }
133
134 #if INTERFACE
135 /*
136 ** This is an abstract class for constructing a merge.
137 ** Subclasses of this object format the merge output in different ways.
138 **
139 ** To subclass, create an instance of the MergeBuilder object and fill
140 ** in appropriate method implementations.
141 */
142 struct MergeBuilder {
143 void (*xStart)(MergeBuilder*);
144 void (*xSame)(MergeBuilder*, unsigned int);
145 void (*xChngV1)(MergeBuilder*, unsigned int, unsigned int);
146 void (*xChngV2)(MergeBuilder*, unsigned int, unsigned int);
147 void (*xChngBoth)(MergeBuilder*, unsigned int, unsigned int);
148 void (*xConflict)(MergeBuilder*, unsigned int, unsigned int, unsigned int);
149 void (*xEnd)(MergeBuilder*);
150 void (*xDestroy)(MergeBuilder*);
151 const char *zPivot; /* Label or name for the pivot */
152 const char *zV1; /* Label or name for the V1 file */
153 const char *zV2; /* Label or name for the V2 file */
154 const char *zOut; /* Label or name for the output */
155 Blob *pPivot; /* The common ancestor */
156 Blob *pV1; /* First variant (local copy) */
157 Blob *pV2; /* Second variant (merged in) */
158 Blob *pOut; /* Write merge results here */
159 int useCrLf; /* Use CRLF line endings */
160 int nContext; /* Size of unchanged line boundaries */
161 unsigned int mxPivot; /* Number of lines in the pivot */
162 unsigned int mxV1; /* Number of lines in V1 */
163 unsigned int mxV2; /* Number of lines in V2 */
164 unsigned int lnPivot; /* Lines read from pivot */
165 unsigned int lnV1; /* Lines read from v1 */
166 unsigned int lnV2; /* Lines read from v2 */
167 unsigned int lnOut; /* Lines written to out */
168 unsigned int nConflict; /* Number of conflicts seen */
169 u64 diffFlags; /* Flags for difference engine */
170 };
171 #endif /* INTERFACE */
172
173
174 /************************* Generic MergeBuilder ******************************/
175 /* These are generic methods for MergeBuilder. They just output debugging
176 ** information. But some of them are useful as base methods for other useful
177 ** implementations of MergeBuilder.
178 */
179
180 /* xStart() and xEnd() are called to generate header and fotter information
181 ** in the output. This is a no-op in the generic implementation.
182 */
183 static void dbgStartEnd(MergeBuilder *p){ (void)p; }
184
185 /* The next N lines of PIVOT are unchanged in both V1 and V2
186 */
187 static void dbgSame(MergeBuilder *p, unsigned int N){
188 blob_appendf(p->pOut,
189 "COPY %u from BASELINE(%u..%u) or V1(%u..%u) or V2(%u..%u)\n",
190 N, p->lnPivot+1, p->lnPivot+N, p->lnV1+1, p->lnV1+N,
191 p->lnV2+1, p->lnV2+N);
192 p->lnPivot += N;
193 p->lnV1 += N;
194 p->lnV2 += N;
195 }
196
197 /* The next nPivot lines of the PIVOT are changed into nV1 lines by V1
198 */
199 static void dbgChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
200 blob_appendf(p->pOut, "COPY %u from V1(%u..%u)\n",
201 nV1, p->lnV1+1, p->lnV1+nV1);
202 p->lnPivot += nPivot;
203 p->lnV2 += nPivot;
204 p->lnV1 += nV1;
205 }
206
207 /* The next nPivot lines of the PIVOT are changed into nV2 lines by V2
208 */
209 static void dbgChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
210 blob_appendf(p->pOut, "COPY %u lines FROM V2(%u..%u)\n",
211 nV2, p->lnV2+1, p->lnV2+nV2);
212 p->lnPivot += nPivot;
213 p->lnV1 += nPivot;
214 p->lnV2 += nV2;
215 }
216
217 /* The next nPivot lines of the PIVOT are changed into nV lines from V1 and
218 ** V2, which should be the same. In other words, the same change is found
219 ** in both V1 and V2.
220 */
221 static void dbgChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
222 blob_appendf(p->pOut, "COPY %u lines from V1(%u..%u) or V2(%u..%u)\n",
223 nV, p->lnV1+1, p->lnV1+nV, p->lnV2+1, p->lnV2+nV);
224 p->lnPivot += nPivot;
225 p->lnV1 += nV;
226 p->lnV2 += nV;
227 }
228
229 /* V1 and V2 have different and overlapping changes. The next nPivot lines
230 ** of the PIVOT are converted into nV1 lines of V1 and nV2 lines of V2.
231 */
232 static void dbgConflict(
233 MergeBuilder *p,
234 unsigned int nPivot,
235 unsigned int nV1,
236 unsigned int nV2
237 ){
238 blob_appendf(p->pOut,
239 "CONFLICT %u,%u,%u BASELINE(%u..%u) versus V1(%u..%u) versus V2(%u..%u)\n",
240 nPivot, nV1, nV2,
241 p->lnPivot+1, p->lnPivot+nPivot,
242 p->lnV1+1, p->lnV1+nV1,
243 p->lnV2+1, p->lnV2+nV2);
244 p->lnV1 += nV1;
245 p->lnPivot += nPivot;
246 p->lnV2 += nV2;
247 }
248
249 /* Generic destructor for the MergeBuilder object
250 */
251 static void dbgDestroy(MergeBuilder *p){
252 memset(p, 0, sizeof(*p));
253 }
254
255 /* Generic initializer for a MergeBuilder object
256 */
257 static void mergebuilder_init(MergeBuilder *p){
258 memset(p, 0, sizeof(*p));
259 p->xStart = dbgStartEnd;
260 p->xSame = dbgSame;
261 p->xChngV1 = dbgChngV1;
262 p->xChngV2 = dbgChngV2;
263 p->xChngBoth = dbgChngBoth;
264 p->xConflict = dbgConflict;
265 p->xEnd = dbgStartEnd;
266 p->xDestroy = dbgDestroy;
267 }
268
269 /************************* MergeBuilderToken ********************************/
270 /* This version of MergeBuilder actually performs a merge on file that
271 ** are broken up into tokens instead of lines, and puts the result in pOut.
272 */
273 static void tokenSame(MergeBuilder *p, unsigned int N){
274 blob_append(p->pOut, p->pPivot->aData+p->pPivot->iCursor, N);
275 p->pPivot->iCursor += N;
276 p->pV1->iCursor += N;
277 p->pV2->iCursor += N;
278 }
279 static void tokenChngV1(MergeBuilder *p, unsigned int nPivot, unsigned nV1){
280 blob_append(p->pOut, p->pV1->aData+p->pV1->iCursor, nV1);
281 p->pPivot->iCursor += nPivot;
282 p->pV1->iCursor += nV1;
283 p->pV2->iCursor += nPivot;
284 }
285 static void tokenChngV2(MergeBuilder *p, unsigned int nPivot, unsigned nV2){
286 blob_append(p->pOut, p->pV2->aData+p->pV2->iCursor, nV2);
287 p->pPivot->iCursor += nPivot;
288 p->pV1->iCursor += nPivot;
289 p->pV2->iCursor += nV2;
290 }
291 static void tokenChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned nV){
292 blob_append(p->pOut, p->pV2->aData+p->pV2->iCursor, nV);
293 p->pPivot->iCursor += nPivot;
294 p->pV1->iCursor += nV;
295 p->pV2->iCursor += nV;
296 }
297 static void tokenConflict(
298 MergeBuilder *p,
299 unsigned int nPivot,
300 unsigned int nV1,
301 unsigned int nV2
302 ){
303 /* For a token-merge conflict, use the text from the merge-in */
304 blob_append(p->pOut, p->pV2->aData+p->pV2->iCursor, nV2);
305 p->pPivot->iCursor += nPivot;
306 p->pV1->iCursor += nV1;
307 p->pV2->iCursor += nV2;
308 }
309 static void mergebuilder_init_token(MergeBuilder *p){
310 mergebuilder_init(p);
311 p->xSame = tokenSame;
312 p->xChngV1 = tokenChngV1;
313 p->xChngV2 = tokenChngV2;
314 p->xChngBoth = tokenChngBoth;
315 p->xConflict = tokenConflict;
316 p->diffFlags = DIFF_BY_TOKEN;
317 }
318
319 /*
320 ** Attempt to do a low-level merge on a conflict. The conflict is
321 ** described by the first four parameters, which are the same as the
322 ** arguments to the xConflict method of the MergeBuilder object.
323 ** This routine attempts to resolve the conflict by looking at
324 ** elements of the conflict region that are finer grain than complete
325 ** lines of text.
326 **
327 ** The result is written into Blob pOut. pOut is initialized by this
328 ** routine.
329 */
330 int merge_try_to_resolve_conflict(
331 MergeBuilder *pMB, /* MergeBuilder that encounter conflict */
332 unsigned int nPivot, /* Lines of conflict in the pivot */
333 unsigned int nV1, /* Lines of conflict in V1 */
334 unsigned int nV2, /* Lines of conflict in V2 */
335 Blob *pOut /* Write resolution text here */
336 ){
337 int nConflict;
338 MergeBuilder mb;
339 Blob pv, v1, v2;
340 mergebuilder_init_token(&mb);
341 blob_extract_lines(pMB->pPivot, nPivot, &pv);
342 blob_extract_lines(pMB->pV1, nV1, &v1);
343 blob_extract_lines(pMB->pV2, nV2, &v2);
344 blob_zero(pOut);
345 blob_materialize(&pv);
346 blob_materialize(&v1);
347 blob_materialize(&v2);
348 mb.pPivot = &pv;
349 mb.pV1 = &v1;
350 mb.pV2 = &v2;
351 mb.pOut = pOut;
352 nConflict = merge_three_blobs(&mb);
353 blob_reset(&pv);
354 blob_reset(&v1);
355 blob_reset(&v2);
356 /* mb has not allocated any resources, so we do not need to invoke
357 ** the xDestroy method. */
358 blob_add_final_newline(pOut);
359 return nConflict;
360 }
361
362
363 /************************* MergeBuilderText **********************************/
364 /* This version of MergeBuilder actually performs a merge on file and puts
365 ** the result in pOut
366 */
367 static void txtStart(MergeBuilder *p){
368 /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
369 ** keep it in the output. This should be secure enough not to cause
370 ** unintended changes to the merged file and consistent with what
371 ** users are using in their source files.
372 */
373 if( starts_with_utf8_bom(p->pV1, 0) && starts_with_utf8_bom(p->pV2, 0) ){
374 blob_append(p->pOut, (char*)get_utf8_bom(0), -1);
375 }
376 if( contains_crlf(p->pV1) && contains_crlf(p->pV2) ){
377 p->useCrLf = 1;
378 }
379 }
380 static void txtSame(MergeBuilder *p, unsigned int N){
381 blob_copy_lines(p->pOut, p->pPivot, N); p->lnPivot += N;
382 blob_copy_lines(0, p->pV1, N); p->lnV1 += N;
383 blob_copy_lines(0, p->pV2, N); p->lnV2 += N;
384 }
385 static void txtChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
386 blob_copy_lines(0, p->pPivot, nPivot); p->lnPivot += nPivot;
387 blob_copy_lines(0, p->pV2, nPivot); p->lnV2 += nPivot;
388 blob_copy_lines(p->pOut, p->pV1, nV1); p->lnV1 += nV1;
389 }
390 static void txtChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
391 blob_copy_lines(0, p->pPivot, nPivot); p->lnPivot += nPivot;
392 blob_copy_lines(0, p->pV1, nPivot); p->lnV1 += nPivot;
393 blob_copy_lines(p->pOut, p->pV2, nV2); p->lnV2 += nV2;
394 }
395 static void txtChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
396 blob_copy_lines(0, p->pPivot, nPivot); p->lnPivot += nPivot;
397 blob_copy_lines(0, p->pV1, nV); p->lnV1 += nV;
398 blob_copy_lines(p->pOut, p->pV2, nV); p->lnV2 += nV;
399 }
400 static void txtConflict(
401 MergeBuilder *p,
402 unsigned int nPivot,
403 unsigned int nV1,
404 unsigned int nV2
405 ){
406 int nRes; /* Lines in the computed conflict resolution */
407 Blob res; /* Text of the conflict resolution */
408
409 merge_try_to_resolve_conflict(p, nPivot, nV1, nV2, &res);
410 nRes = blob_linecount(&res);
411
412 append_merge_mark(p->pOut, 0, p->lnV1+1, p->useCrLf);
413 blob_copy_lines(p->pOut, p->pV1, nV1); p->lnV1 += nV1;
414
415 if( nRes>0 ){
416 append_merge_mark(p->pOut, 1, 0, p->useCrLf);
417 blob_copy_lines(p->pOut, &res, nRes);
418 }
419 blob_reset(&res);
420
421 append_merge_mark(p->pOut, 2, p->lnPivot+1, p->useCrLf);
422 blob_copy_lines(p->pOut, p->pPivot, nPivot); p->lnPivot += nPivot;
423
424 append_merge_mark(p->pOut, 3, p->lnV2+1, p->useCrLf);
425 blob_copy_lines(p->pOut, p->pV2, nV2); p->lnV2 += nV2;
426
427 append_merge_mark(p->pOut, 4, -1, p->useCrLf);
428 }
429 static void mergebuilder_init_text(MergeBuilder *p){
430 mergebuilder_init(p);
431 p->xStart = txtStart;
432 p->xSame = txtSame;
433 p->xChngV1 = txtChngV1;
434 p->xChngV2 = txtChngV2;
435 p->xChngBoth = txtChngBoth;
436 p->xConflict = txtConflict;
437 }
438
439 /************************* MergeBuilderTcl **********************************/
440 /* Generate merge output formatted for reading by a TCL script.
441 **
442 ** The output consists of lines of text, each with 4 tokens. The tokens
443 ** represent the content for one line from baseline, v1, v2, and output
444 ** respectively. The first character of each token provides auxiliary
445 ** information:
446 **
447 ** . This line is omitted.
448 ** N Name of the file.
449 ** T Literal text follows that should have a \n terminator.
450 ** R Literal text follows that needs a \r\n terminator.
451 ** X Merge conflict.
452 ** Z Literal text without a line terminator.
453 ** S Skipped lines. Followed by number of lines to skip.
454 ** 1 Text is a copy of token 1
455 ** 2 Use data from data-token 2
456 ** 3 Use data from data-token 3
457 */
458
459 /* Write text that goes into the interior of a double-quoted string in TCL */
460 static void tclWriteQuotedText(Blob *pOut, const char *zIn, int nIn){
461 int j;
462 for(j=0; j<nIn; j++){
463 char c = zIn[j];
464 if( c=='\\' ){
465 blob_append(pOut, "\\\\", 2);
466 }else if( c=='"' ){
467 blob_append(pOut, "\\\"", 2);
468 }else if( c<' ' || c>0x7e ){
469 char z[5];
470 z[0] = '\\';
471 z[1] = "01234567"[(c>>6)&0x3];
472 z[2] = "01234567"[(c>>3)&0x7];
473 z[3] = "01234567"[c&0x7];
474 z[4] = 0;
475 blob_append(pOut, z, 4);
476 }else{
477 blob_append_char(pOut, c);
478 }
479 }
480 }
481
482 /* Copy one line of text from pIn and append to pOut, encoded as TCL */
483 static void tclLineOfText(Blob *pOut, Blob *pIn, char cType){
484 int i, k;
485 for(i=pIn->iCursor; i<pIn->nUsed && pIn->aData[i]!='\n'; i++){}
486 if( i==pIn->nUsed ){
487 k = i;
488 }else if( i>pIn->iCursor && pIn->aData[i-1]=='\r' ){
489 k = i-1;
490 i++;
491 }else{
492 k = i;
493 i++;
494 }
495 blob_append_char(pOut, '"');
496 blob_append_char(pOut, cType);
497 tclWriteQuotedText(pOut, pIn->aData+pIn->iCursor, k-pIn->iCursor);
498 pIn->iCursor = i;
499 blob_append_char(pOut, '"');
500 }
501 static void tclStart(MergeBuilder *p){
502 Blob *pOut = p->pOut;
503 blob_append(pOut, "\"N", 2);
504 tclWriteQuotedText(pOut, p->zPivot, (int)strlen(p->zPivot));
505 blob_append(pOut, "\" \"N", 4);
506 tclWriteQuotedText(pOut, p->zV1, (int)strlen(p->zV1));
507 blob_append(pOut, "\" \"N", 4);
508 tclWriteQuotedText(pOut, p->zV2, (int)strlen(p->zV2));
509 blob_append(pOut, "\" \"N", 4);
510 if( p->zOut ){
511 tclWriteQuotedText(pOut, p->zOut, (int)strlen(p->zOut));
512 }else{
513 blob_append(pOut, "(Merge Result)", -1);
514 }
515 blob_append(pOut, "\"\n", 2);
516 }
517 static void tclSame(MergeBuilder *p, unsigned int N){
518 int i = 0;
519 int nSkip;
520
521 if( p->lnPivot>=2 || p->lnV1>2 || p->lnV2>2 ){
522 while( i<N && i<p->nContext ){
523 tclLineOfText(p->pOut, p->pPivot, 'T');
524 blob_append(p->pOut, " 1 1 1\n", 7);
525 i++;
526 }
527 nSkip = N - p->nContext*2;
528 }else{
529 nSkip = N - p->nContext;
530 }
531 if( nSkip>0 ){
532 blob_appendf(p->pOut, "\"S%d %d %d %d\" . . .\n",
533 nSkip, nSkip, nSkip, nSkip);
534 blob_copy_lines(0, p->pPivot, nSkip);
535 i += nSkip;
536 }
537
538 p->lnPivot += N;
539 p->lnV1 += N;
540 p->lnV2 += N;
541
542 if( p->lnPivot<p->mxPivot || p->lnV1<p->mxV1 || p->lnV2<p->mxV2 ){
543 while( i<N ){
544 tclLineOfText(p->pOut, p->pPivot, 'T');
545 blob_append(p->pOut, " 1 1 1\n", 7);
546 i++;
547 }
548 }
549
550 blob_copy_lines(0, p->pV1, N);
551 blob_copy_lines(0, p->pV2, N);
552 }
553 static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
554 int i;
555 for(i=0; i<nPivot && i<nV1; i++){
556 tclLineOfText(p->pOut, p->pPivot, 'T');
557 blob_append_char(p->pOut, ' ');
558 tclLineOfText(p->pOut, p->pV1, 'T');
559 blob_append(p->pOut, " 1 2\n", 5);
560 }
561 while( i<nPivot ){
562 tclLineOfText(p->pOut, p->pPivot, 'T');
563 blob_append(p->pOut, " . 1 .\n", 7);
564 i++;
565 }
566 while( i<nV1 ){
567 blob_append(p->pOut, ". ", 2);
568 tclLineOfText(p->pOut, p->pV1, 'T');
569 blob_append(p->pOut, " . 2\n", 5);
570 i++;
571 }
572 p->lnPivot += nPivot;
573 p->lnV1 += nV1;
574 p->lnV2 += nPivot;
575 blob_copy_lines(0, p->pV2, nPivot);
576 }
577 static void tclChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
578 int i;
579 for(i=0; i<nPivot && i<nV2; i++){
580 tclLineOfText(p->pOut, p->pPivot, 'T');
581 blob_append(p->pOut, " 1 ", 3);
582 tclLineOfText(p->pOut, p->pV2, 'T');
583 blob_append(p->pOut, " 3\n", 3);
584 }
585 while( i<nPivot ){
586 tclLineOfText(p->pOut, p->pPivot, 'T');
587 blob_append(p->pOut, " 1 . .\n", 7);
588 i++;
589 }
590 while( i<nV2 ){
591 blob_append(p->pOut, ". . ", 4);
592 tclLineOfText(p->pOut, p->pV2, 'T');
593 blob_append(p->pOut, " 3\n", 3);
594 i++;
595 }
596 p->lnPivot += nPivot;
597 p->lnV1 += nPivot;
598 p->lnV2 += nV2;
599 blob_copy_lines(0, p->pV1, nPivot);
600 }
601 static void tclChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
602 int i;
603 for(i=0; i<nPivot && i<nV; i++){
604 tclLineOfText(p->pOut, p->pPivot, 'T');
605 blob_append_char(p->pOut, ' ');
606 tclLineOfText(p->pOut, p->pV1, 'T');
607 blob_append(p->pOut, " 2 2\n", 5);
608 }
609 while( i<nPivot ){
610 tclLineOfText(p->pOut, p->pPivot, 'T');
611 blob_append(p->pOut, " . . .\n", 7);
612 i++;
613 }
614 while( i<nV ){
615 blob_append(p->pOut, ". ", 2);
616 tclLineOfText(p->pOut, p->pV1, 'T');
617 blob_append(p->pOut, " 2 2\n", 5);
618 i++;
619 }
620 p->lnPivot += nPivot;
621 p->lnV1 += nV;
622 p->lnV2 += nV;
623 blob_copy_lines(0, p->pV2, nV);
624 }
625 static void tclConflict(
626 MergeBuilder *p,
627 unsigned int nPivot,
628 unsigned int nV1,
629 unsigned int nV2
630 ){
631 int mx = nPivot;
632 int i;
633 int nRes;
634 Blob res;
635
636 merge_try_to_resolve_conflict(p, nPivot, nV1, nV2, &res);
637 nRes = blob_linecount(&res);
638 if( nV1>mx ) mx = nV1;
639 if( nV2>mx ) mx = nV2;
640 if( nRes>mx ) mx = nRes;
641 if( nRes>0 ){
642 blob_appendf(p->pOut, "\"S0 0 0 %d\" . . .\n", nV2+2);
643 }
644 for(i=0; i<mx; i++){
645 if( i<nPivot ){
646 tclLineOfText(p->pOut, p->pPivot, 'X');
647 }else{
648 blob_append_char(p->pOut, '.');
649 }
650 blob_append_char(p->pOut, ' ');
651 if( i<nV1 ){
652 tclLineOfText(p->pOut, p->pV1, 'X');
653 }else{
654 blob_append_char(p->pOut, '.');
655 }
656 blob_append_char(p->pOut, ' ');
657 if( i<nV2 ){
658 tclLineOfText(p->pOut, p->pV2, 'X');
659 }else{
660 blob_append_char(p->pOut, '.');
661 }
662 if( i<nRes ){
663 blob_append_char(p->pOut, ' ');
664 tclLineOfText(p->pOut, &res, 'X');
665 blob_append_char(p->pOut, '\n');
666 }else{
667 blob_append(p->pOut, " .\n", 3);
668 }
669 if( i==mx-1 ){
670 blob_appendf(p->pOut, "\"S0 0 0 %d\" . . .\n", nPivot+nV1+3);
671 }
672 }
673 blob_reset(&res);
674 p->lnPivot += nPivot;
675 p->lnV1 += nV1;
676 p->lnV2 += nV2;
677 }
678 void mergebuilder_init_tcl(MergeBuilder *p){
679 mergebuilder_init(p);
680 p->xStart = tclStart;
681 p->xSame = tclSame;
682 p->xChngV1 = tclChngV1;
683 p->xChngV2 = tclChngV2;
684 p->xChngBoth = tclChngBoth;
685 p->xConflict = tclConflict;
686 }
687 /*****************************************************************************/
688
689 /*
690 ** The aC[] array contains triples of integers. Within each triple, the
691 ** elements are:
692 **
693 ** (0) The number of lines to copy
694 ** (1) The number of lines to delete
695 ** (2) The number of liens to insert
696 **
697 ** Suppose we want to advance over sz lines of the original file. This routine
698 ** returns true if that advance would land us on a copy operation. It
699 ** returns false if the advance would end on a delete.
700 */
701 static int ends_with_copy(int *aC, int sz){
702 while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
703 if( aC[0]>=sz ) return 1;
704 sz -= aC[0];
705 if( aC[1]>sz ) return 0;
706 sz -= aC[1];
707 aC += 3;
708 }
709 return 1;
710 }
711
712 /*
713 ** aC[] is an "edit triple" for changes from A to B. Advance through
714 ** this triple to determine the number of lines to bypass on B in order
715 ** to match an advance of sz lines on A.
716 */
717 static int skip_conflict(
718 int *aC, /* Array of integer triples describing the edit */
719 int i, /* Index in aC[] of current location */
720 int sz, /* Lines of A that have been skipped */
721 unsigned int *pLn /* OUT: Lines of B to skip to keep aligment with A */
722 ){
723 *pLn = 0;
724 while( sz>0 ){
725 if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
726 if( aC[i]>=sz ){
727 aC[i] -= sz;
728 *pLn += sz;
729 break;
730 }
731 *pLn += aC[i];
732 *pLn += aC[i+2];
733 sz -= aC[i] + aC[i+1];
734 i += 3;
735 }
736 return i;
737 }
738
739 /*
740 ** Do a three-way merge. Initialize pOut to contain the result.
741 **
742 ** The merge is an edit against pV2. Both pV1 and pV2 have a
@@ -199,156 +746,113 @@
746 ** The return is 0 upon complete success. If any input file is binary,
747 ** -1 is returned and pOut is unmodified. If there are merge
748 ** conflicts, the merge proceeds as best as it can and the number
749 ** of conflicts is returns
750 */
751 int merge_three_blobs(MergeBuilder *p){
752 int *aC1; /* Changes from pPivot to pV1 */
753 int *aC2; /* Changes from pPivot to pV2 */
754 int i1, i2; /* Index into aC1[] and aC2[] */
755 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
756 int limit1, limit2; /* Sizes of aC1[] and aC2[] */
757 int nConflict = 0; /* Number of merge conflicts seen so far */
 
 
758 DiffConfig DCfg;
759
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
760 /* Compute the edits that occur from pPivot => pV1 (into aC1)
761 ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is
762 ** an array of integer triples. Within each triple, the first integer
763 ** is the number of lines of text to copy directly from the pivot,
764 ** the second integer is the number of lines of text to omit from the
765 ** pivot, and the third integer is the number of lines of text that are
766 ** inserted. The edit array ends with a triple of 0,0,0.
767 */
768 diff_config_init(&DCfg, 0);
769 DCfg.diffFlags = p->diffFlags;
770 aC1 = text_diff(p->pPivot, p->pV1, 0, &DCfg);
771 aC2 = text_diff(p->pPivot, p->pV2, 0, &DCfg);
772 if( aC1==0 || aC2==0 ){
773 free(aC1);
774 free(aC2);
775 return -1;
776 }
777
778 blob_rewind(p->pV1); /* Rewind inputs: Needed to reconstruct output */
779 blob_rewind(p->pV2);
780 blob_rewind(p->pPivot);
781
782 /* Determine the length of the aC1[] and aC2[] change vectors */
783 p->mxPivot = 0;
784 p->mxV1 = 0;
785 for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){
786 p->mxPivot += aC1[i1] + aC1[i1+1];
787 p->mxV1 += aC1[i1] + aC1[i1+2];
788 }
789 limit1 = i1;
790 p->mxV2 = 0;
791 for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){
792 p->mxV2 += aC2[i2] + aC2[i2+2];
793 }
794 limit2 = i2;
795
796 /* Output header text and do any other required initialization */
797 p->xStart(p);
 
 
 
 
 
 
798
799 /* Loop over the two edit vectors and use them to compute merged text
800 ** which is written into pOut. i1 and i2 are multiples of 3 which are
801 ** indices into aC1[] and aC2[] to the edit triple currently being
802 ** processed
803 */
804 i1 = i2 = 0;
 
805 while( i1<limit1 && i2<limit2 ){
 
 
 
 
806 if( aC1[i1]>0 && aC2[i2]>0 ){
807 /* Output text that is unchanged in both V1 and V2 */
808 nCpy = min(aC1[i1], aC2[i2]);
809 p->xSame(p, nCpy);
 
 
 
810 aC1[i1] -= nCpy;
811 aC2[i2] -= nCpy;
812 }else
813 if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){
814 /* Output edits to V2 that occurs within unchanged regions of V1 */
815 nDel = aC2[i2+1];
816 nIns = aC2[i2+2];
817 p->xChngV2(p, nDel, nIns);
 
 
 
818 aC1[i1] -= nDel;
819 i2 += 3;
820 }else
821 if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){
822 /* Output edits to V1 that occur within unchanged regions of V2 */
823 nDel = aC1[i1+1];
824 nIns = aC1[i1+2];
825 p->xChngV1(p, nDel, nIns);
 
 
 
826 aC2[i2] -= nDel;
827 i1 += 3;
828 }else
829 if( sameEdit(&aC1[i1], &aC2[i2], p->pV1, p->pV2) ){
830 /* Output edits that are identical in both V1 and V2. */
831 assert( aC1[i1]==0 );
832 nDel = aC1[i1+1];
833 nIns = aC1[i1+2];
834 p->xChngBoth(p, nDel, nIns);
 
 
 
835 i1 += 3;
836 i2 += 3;
837 }else
838 {
839 /* We have found a region where different edits to V1 and V2 overlap.
840 ** This is a merge conflict. Find the size of the conflict, then
841 ** output both possible edits separated by distinctive marks.
842 */
843 unsigned int sz = 1; /* Size of the conflict in the pivot, in lines */
844 unsigned int nV1, nV2; /* Size of conflict in V1 and V2, in lines */
845 nConflict++;
846 while( !ends_with_copy(&aC1[i1], sz) || !ends_with_copy(&aC2[i2], sz) ){
847 sz++;
848 }
849 i1 = skip_conflict(aC1, i1, sz, &nV1);
850 i2 = skip_conflict(aC2, i2, sz, &nV2);
851 p->xConflict(p, sz, nV1, nV2);
852 }
853
 
 
 
 
 
 
 
 
 
854 /* If we are finished with an edit triple, advance to the next
855 ** triple.
856 */
857 if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3;
858 if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3;
@@ -356,20 +860,18 @@
860
861 /* When one of the two edit vectors reaches its end, there might still
862 ** be an insert in the other edit vector. Output this remaining
863 ** insert.
864 */
 
 
 
865 if( i1<limit1 && aC1[i1+2]>0 ){
866 p->xChngV1(p, 0, aC1[i1+2]);
 
867 }else if( i2<limit2 && aC2[i2+2]>0 ){
868 p->xChngV2(p, 0, aC2[i2+2]);
 
869 }
870
871 /* Output footer text */
872 p->xEnd(p);
873
874 free(aC1);
875 free(aC2);
876 return nConflict;
877 }
@@ -384,11 +886,12 @@
886 const char *z = blob_buffer(p);
887 int n = blob_size(p) - len + 1;
888 assert( len==(int)strlen(mergeMarker[1]) );
889 assert( len==(int)strlen(mergeMarker[2]) );
890 assert( len==(int)strlen(mergeMarker[3]) );
891 assert( len==(int)strlen(mergeMarker[4]) );
892 assert( count(mergeMarker)==5 );
893 for(i=0; i<n; ){
894 for(j=0; j<4; j++){
895 if( (memcmp(&z[i], mergeMarker[j], len)==0) ){
896 return 1;
897 }
@@ -408,18 +911,106 @@
911 blob_read_from_file(&file, zFullpath, ExtFILE);
912 rc = contains_merge_marker(&file);
913 blob_reset(&file);
914 return rc;
915 }
916
917 /*
918 ** Show merge output in a Tcl/Tk window, in response to the --tk option
919 ** to the "merge" or "3-way-merge" command.
920 **
921 ** If fossil has direct access to a Tcl interpreter (either loaded
922 ** dynamically through stubs or linked in statically), we can use it
923 ** directly. Otherwise:
924 ** (1) Write the Tcl/Tk script used for rendering into a temp file.
925 ** (2) Invoke "tclsh" on the temp file using fossil_system().
926 ** (3) Delete the temp file.
927 */
928 void merge_tk(const char *zSubCmd, int firstArg){
929 int i;
930 Blob script;
931 const char *zTempFile = 0;
932 char *zCmd;
933 const char *zTclsh;
934 const char *zCnt;
935 int bDarkMode = find_option("dark",0,0)!=0;
936 int nContext;
937 zCnt = find_option("context", "c", 1);
938 if( zCnt==0 ){
939 nContext = 6;
940 }else{
941 nContext = atoi(zCnt);
942 if( nContext<0 ) nContext = 0xfffffff;
943 }
944 blob_zero(&script);
945 blob_appendf(&script, "set ncontext %d\n", nContext);
946 blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl",
947 g.nameOfExe, zSubCmd);
948 find_option("tcl",0,0);
949 find_option("debug",0,0);
950 zTclsh = find_option("tclsh",0,1);
951 if( zTclsh==0 ){
952 zTclsh = db_get("tclsh",0);
953 }
954 /* The undocumented --script FILENAME option causes the Tk script to
955 ** be written into the FILENAME instead of being run. This is used
956 ** for testing and debugging. */
957 zTempFile = find_option("script",0,1);
958 verify_all_options();
959
960 if( (g.argc - firstArg)!=3 ){
961 fossil_fatal("Requires 3 filename arguments");
962 }
963
964 for(i=firstArg; i<g.argc; i++){
965 const char *z = g.argv[i];
966 if( sqlite3_strglob("*}*",z) ){
967 blob_appendf(&script, " {%/}", z);
968 }else{
969 int j;
970 blob_append(&script, " ", 1);
971 for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
972 }
973 }
974 blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
975 blob_appendf(&script, "%s", builtin_file("merge.tcl", 0));
976 if( zTempFile ){
977 blob_write_to_file(&script, zTempFile);
978 fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile);
979 }else{
980 #if defined(FOSSIL_ENABLE_TCL)
981 Th_FossilInit(TH_INIT_DEFAULT);
982 if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
983 blob_size(&script), 1, 1, 0)==TCL_OK ){
984 blob_reset(&script);
985 return;
986 }
987 /*
988 * If evaluation of the Tcl script fails, the reason may be that Tk
989 * could not be found by the loaded Tcl, or that Tcl cannot be loaded
990 * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
991 * to using the external "tclsh", if available.
992 */
993 #endif
994 zTempFile = write_blob_to_temp_file(&script);
995 zCmd = mprintf("%$ %$", zTclsh, zTempFile);
996 fossil_system(zCmd);
997 file_delete(zTempFile);
998 fossil_free(zCmd);
999 }
1000 blob_reset(&script);
1001 }
1002
1003
1004 /*
1005 ** COMMAND: 3-way-merge*
1006 **
1007 ** Usage: %fossil 3-way-merge BASELINE V1 V2 [MERGED]
1008 **
1009 ** Inputs are files BASELINE, V1, and V2. The file MERGED is generated
1010 ** as output. If no MERGED file is specified, output is sent to
1011 ** stdout.
1012 **
1013 ** BASELINE is a common ancestor of two files V1 and V2 that have diverging
1014 ** edits. The generated output file MERGED is the combination of all
1015 ** changes in both V1 and V2.
1016 **
@@ -436,38 +1027,75 @@
1027 ** cp Xup.c Xbase.c
1028 ** # Verify that everything still works
1029 ** fossil commit
1030 **
1031 */
1032 void merge_3way_cmd(void){
1033 MergeBuilder s;
1034 int nConflict;
1035 Blob pivot, v1, v2, out;
1036 int noWarn = 0;
1037 const char *zCnt;
1038
1039 if( find_option("tk", 0, 0)!=0 ){
1040 merge_tk("3-way-merge", 2);
1041 return;
1042 }
1043 mergebuilder_init_text(&s);
1044 if( find_option("debug", 0, 0) ){
1045 mergebuilder_init(&s);
1046 }
1047 if( find_option("tcl", 0, 0) ){
1048 mergebuilder_init_tcl(&s);
1049 noWarn = 1;
1050 }
1051 zCnt = find_option("context", "c", 1);
1052 if( zCnt ){
1053 s.nContext = atoi(zCnt);
1054 if( s.nContext<0 ) s.nContext = 0xfffffff;
1055 }else{
1056 s.nContext = 6;
1057 }
1058 blob_zero(&pivot); s.pPivot = &pivot;
1059 blob_zero(&v1); s.pV1 = &v1;
1060 blob_zero(&v2); s.pV2 = &v2;
1061 blob_zero(&out); s.pOut = &out;
1062
1063 /* We should be done with options.. */
1064 verify_all_options();
1065
1066 if( g.argc!=6 && g.argc!=5 ){
1067 usage("[OPTIONS] PIVOT V1 V2 [MERGED]");
1068 }
1069 s.zPivot = file_tail(g.argv[2]);
1070 s.zV1 = file_tail(g.argv[3]);
1071 s.zV2 = file_tail(g.argv[4]);
1072 if( blob_read_from_file(s.pPivot, g.argv[2], ExtFILE)<0 ){
1073 fossil_fatal("cannot read %s", g.argv[2]);
1074 }
1075 if( blob_read_from_file(s.pV1, g.argv[3], ExtFILE)<0 ){
1076 fossil_fatal("cannot read %s", g.argv[3]);
1077 }
1078 if( blob_read_from_file(s.pV2, g.argv[4], ExtFILE)<0 ){
1079 fossil_fatal("cannot read %s", g.argv[4]);
1080 }
1081 nConflict = merge_three_blobs(&s);
1082 if( g.argc==6 ){
1083 s.zOut = file_tail(g.argv[5]);
1084 blob_write_to_file(s.pOut, g.argv[5]);
1085 }else{
1086 s.zOut = "(Merge Result)";
1087 blob_write_to_file(s.pOut, "-");
1088 }
1089 s.xDestroy(&s);
1090 blob_reset(&pivot);
1091 blob_reset(&v1);
1092 blob_reset(&v2);
1093 blob_reset(&out);
1094 if( nConflict>0 && !noWarn ){
1095 fossil_warning("WARNING: %d merge conflicts", nConflict);
1096 }
1097 }
1098
1099 /*
1100 ** aSubst is an array of string pairs. The first element of each pair is
1101 ** a string that begins with %. The second element is a replacement for that
@@ -505,32 +1133,32 @@
1133
1134 #if INTERFACE
1135 /*
1136 ** Flags to the 3-way merger
1137 */
1138 #define MERGE_DRYRUN 0x0001
1139 /*
1140 ** The MERGE_KEEP_FILES flag specifies that merge_3way() should retain
1141 ** its temporary files on error. By default they are removed after the
1142 ** merge, regardless of success or failure.
1143 */
1144 #define MERGE_KEEP_FILES 0x0002
1145 #endif
1146
1147
1148 /*
1149 ** This routine is a wrapper around merge_three_blobs() with the following
1150 ** enhancements:
1151 **
1152 ** (1) If the merge-command is defined, then use the external merging
1153 ** program specified instead of the built-in blob-merge to do the
1154 ** merging. Panic if the external merger fails.
1155 ** ** Not currently implemented **
1156 **
1157 ** (2) If gmerge-command is defined and there are merge conflicts in
1158 ** merge_three_blobs() then invoke the external graphical merger
1159 ** to resolve the conflicts.
1160 **
1161 ** (3) If a merge conflict occurs and gmerge-command is not defined,
1162 ** then write the pivot, original, and merge-in files to the
1163 ** filesystem.
1164 */
@@ -539,30 +1167,37 @@
1167 const char *zV1, /* Name of file for version merging into (mine) */
1168 Blob *pV2, /* Version merging from (yours) */
1169 Blob *pOut, /* Output written here */
1170 unsigned mergeFlags /* Flags that control operation */
1171 ){
1172 Blob v1; /* Content of zV1 */
1173 int rc; /* Return code of subroutines and this routine */
1174 const char *zGMerge; /* Name of the gmerge command */
1175 MergeBuilder s; /* The merge state */
1176
1177 mergebuilder_init_text(&s);
1178 s.pPivot = pPivot;
1179 s.pV1 = &v1;
1180 s.pV2 = pV2;
1181 blob_zero(pOut);
1182 s.pOut = pOut;
1183 blob_read_from_file(s.pV1, zV1, ExtFILE);
1184 rc = merge_three_blobs(&s);
1185 zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
1186 if( (mergeFlags & MERGE_DRYRUN)==0
1187 && ((zGMerge!=0 && zGMerge[0]!=0)
1188 || (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
1189 char *zPivot; /* Name of the pivot file */
1190 char *zOrig; /* Name of the original content file */
1191 char *zOther; /* Name of the merge file */
1192
1193 zPivot = file_newname(zV1, "baseline", 1);
1194 blob_write_to_file(s.pPivot, zPivot);
1195 zOrig = file_newname(zV1, "original", 1);
1196 blob_write_to_file(s.pV1, zOrig);
1197 zOther = file_newname(zV1, "merge", 1);
1198 blob_write_to_file(s.pV2, zOther);
1199 if( rc>0 ){
1200 if( zGMerge && zGMerge[0] ){
1201 char *zOut; /* Temporary output file */
1202 char *zCmd; /* Command to invoke */
1203 const char *azSubst[8]; /* Strings to be substituted */
@@ -590,7 +1225,8 @@
1225 fossil_free(zPivot);
1226 fossil_free(zOrig);
1227 fossil_free(zOther);
1228 }
1229 blob_reset(&v1);
1230 s.xDestroy(&s);
1231 return rc;
1232 }
1233
+6 -2
--- src/patch.c
+++ src/patch.c
@@ -464,18 +464,22 @@
464464
465465
/* Deletions */
466466
db_prepare(&q, "SELECT pathname FROM patch.chng"
467467
" WHERE origname IS NULL AND delta IS NULL");
468468
while( db_step(&q)==SQLITE_ROW ){
469
- blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
470
- blob_appendf(&cmd, " rm --hard %$\n", db_column_text(&q,0));
469
+ if( blob_size(&cmd)==0 ){
470
+ blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
471
+ blob_appendf(&cmd, " rm --hard");
472
+ }
473
+ blob_appendf(&cmd, " %$", db_column_text(&q,0));
471474
if( mFlags & PATCH_VERBOSE ){
472475
fossil_print("%-10s %s\n", "DELETE", db_column_text(&q,0));
473476
}
474477
}
475478
db_finalize(&q);
476479
if( blob_size(&cmd)>0 ){
480
+ blob_appendf(&cmd, "\n");
477481
if( mFlags & PATCH_DRYRUN ){
478482
fossil_print("%s", blob_str(&cmd));
479483
}else{
480484
int rc = fossil_unsafe_system(blob_str(&cmd));
481485
if( rc ){
482486
--- src/patch.c
+++ src/patch.c
@@ -464,18 +464,22 @@
464
465 /* Deletions */
466 db_prepare(&q, "SELECT pathname FROM patch.chng"
467 " WHERE origname IS NULL AND delta IS NULL");
468 while( db_step(&q)==SQLITE_ROW ){
469 blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
470 blob_appendf(&cmd, " rm --hard %$\n", db_column_text(&q,0));
 
 
 
471 if( mFlags & PATCH_VERBOSE ){
472 fossil_print("%-10s %s\n", "DELETE", db_column_text(&q,0));
473 }
474 }
475 db_finalize(&q);
476 if( blob_size(&cmd)>0 ){
 
477 if( mFlags & PATCH_DRYRUN ){
478 fossil_print("%s", blob_str(&cmd));
479 }else{
480 int rc = fossil_unsafe_system(blob_str(&cmd));
481 if( rc ){
482
--- src/patch.c
+++ src/patch.c
@@ -464,18 +464,22 @@
464
465 /* Deletions */
466 db_prepare(&q, "SELECT pathname FROM patch.chng"
467 " WHERE origname IS NULL AND delta IS NULL");
468 while( db_step(&q)==SQLITE_ROW ){
469 if( blob_size(&cmd)==0 ){
470 blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
471 blob_appendf(&cmd, " rm --hard");
472 }
473 blob_appendf(&cmd, " %$", db_column_text(&q,0));
474 if( mFlags & PATCH_VERBOSE ){
475 fossil_print("%-10s %s\n", "DELETE", db_column_text(&q,0));
476 }
477 }
478 db_finalize(&q);
479 if( blob_size(&cmd)>0 ){
480 blob_appendf(&cmd, "\n");
481 if( mFlags & PATCH_DRYRUN ){
482 fossil_print("%s", blob_str(&cmd));
483 }else{
484 int rc = fossil_unsafe_system(blob_str(&cmd));
485 if( rc ){
486
+1
--- src/path.c
+++ src/path.c
@@ -542,10 +542,11 @@
542542
pChng = pAll;
543543
pAll = pAll->pNext;
544544
fossil_free(pChng);
545545
}
546546
}
547
+ path_reset();
547548
}
548549
549550
/*
550551
** COMMAND: test-name-changes
551552
**
552553
--- src/path.c
+++ src/path.c
@@ -542,10 +542,11 @@
542 pChng = pAll;
543 pAll = pAll->pNext;
544 fossil_free(pChng);
545 }
546 }
 
547 }
548
549 /*
550 ** COMMAND: test-name-changes
551 **
552
--- src/path.c
+++ src/path.c
@@ -542,10 +542,11 @@
542 pChng = pAll;
543 pAll = pAll->pNext;
544 fossil_free(pChng);
545 }
546 }
547 path_reset();
548 }
549
550 /*
551 ** COMMAND: test-name-changes
552 **
553
+12 -2
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -207,12 +207,22 @@
207207
blob_append(pOut, zOut, -1);
208208
if(PIKCHR_PROCESS_DIV & pikFlags){
209209
blob_append(pOut, "</div>\n", 7);
210210
}
211211
if(PIKCHR_PROCESS_SRC & pikFlags){
212
- blob_appendf(pOut, "<pre class='pikchr-src'>%h</pre>\n",
213
- blob_str(&bIn));
212
+ static int counter = 0;
213
+ ++counter;
214
+ blob_appendf(pOut, "<div class='pikchr-src'>"
215
+ "<pre id='pikchr-src-%d'>%h</pre>"
216
+ "<span class='hidden'>"
217
+ "<a href='%R/pikchrshow?fromSession' "
218
+ "class='pikchr-src-pikchrshow' target='_new-%d' "
219
+ "data-pikchrid='pikchr-src-%d' "
220
+ "title='Open this pikchr in /pikchrshow'"
221
+ ">&rarr; /pikchrshow</a></span>"
222
+ "</div>\n",
223
+ counter, blob_str(&bIn), counter, counter);
214224
}
215225
if(PIKCHR_PROCESS_DIV & pikFlags){
216226
blob_append(pOut, "</div>\n", 7);
217227
}
218228
}else{
219229
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -207,12 +207,22 @@
207 blob_append(pOut, zOut, -1);
208 if(PIKCHR_PROCESS_DIV & pikFlags){
209 blob_append(pOut, "</div>\n", 7);
210 }
211 if(PIKCHR_PROCESS_SRC & pikFlags){
212 blob_appendf(pOut, "<pre class='pikchr-src'>%h</pre>\n",
213 blob_str(&bIn));
 
 
 
 
 
 
 
 
 
 
214 }
215 if(PIKCHR_PROCESS_DIV & pikFlags){
216 blob_append(pOut, "</div>\n", 7);
217 }
218 }else{
219
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -207,12 +207,22 @@
207 blob_append(pOut, zOut, -1);
208 if(PIKCHR_PROCESS_DIV & pikFlags){
209 blob_append(pOut, "</div>\n", 7);
210 }
211 if(PIKCHR_PROCESS_SRC & pikFlags){
212 static int counter = 0;
213 ++counter;
214 blob_appendf(pOut, "<div class='pikchr-src'>"
215 "<pre id='pikchr-src-%d'>%h</pre>"
216 "<span class='hidden'>"
217 "<a href='%R/pikchrshow?fromSession' "
218 "class='pikchr-src-pikchrshow' target='_new-%d' "
219 "data-pikchrid='pikchr-src-%d' "
220 "title='Open this pikchr in /pikchrshow'"
221 ">&rarr; /pikchrshow</a></span>"
222 "</div>\n",
223 counter, blob_str(&bIn), counter, counter);
224 }
225 if(PIKCHR_PROCESS_DIV & pikFlags){
226 blob_append(pOut, "</div>\n", 7);
227 }
228 }else{
229
+9 -3
--- src/rebuild.c
+++ src/rebuild.c
@@ -390,25 +390,31 @@
390390
}
391391
manifest_disable_event_triggers();
392392
rebuild_update_schema();
393393
blob_init(&sql, 0, 0);
394394
db_unprotect(PROTECT_ALL);
395
+#ifndef SQLITE_PREPARE_DONT_LOG
396
+ g.dbIgnoreErrors++;
397
+#endif
395398
db_prepare(&q,
396
- "SELECT name FROM sqlite_schema /*scan*/"
397
- " WHERE type='table'"
399
+ "SELECT name FROM pragma_table_list /*scan*/"
400
+ " WHERE schema='repository' AND type IN ('table','virtual')"
398401
" AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
399402
"'config','shun','private','reportfmt',"
400403
"'concealed','accesslog','modreq',"
401404
"'purgeevent','purgeitem','unversioned',"
402405
"'subscriber','pending_alert','chat')"
403406
" AND name NOT GLOB 'sqlite_*'"
404
- " AND name NOT GLOB 'fx_*'"
407
+ " AND name NOT GLOB 'fx_*';"
405408
);
406409
while( db_step(&q)==SQLITE_ROW ){
407410
blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0));
408411
}
409412
db_finalize(&q);
413
+#ifndef SQLITE_PREPARE_DONT_LOG
414
+ g.dbIgnoreErrors--;
415
+#endif
410416
db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
411417
blob_reset(&sql);
412418
db_multi_exec("%s", zRepositorySchema2/*safe-for-%s*/);
413419
ticket_create_table(0);
414420
shun_artifacts();
415421
--- src/rebuild.c
+++ src/rebuild.c
@@ -390,25 +390,31 @@
390 }
391 manifest_disable_event_triggers();
392 rebuild_update_schema();
393 blob_init(&sql, 0, 0);
394 db_unprotect(PROTECT_ALL);
 
 
 
395 db_prepare(&q,
396 "SELECT name FROM sqlite_schema /*scan*/"
397 " WHERE type='table'"
398 " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
399 "'config','shun','private','reportfmt',"
400 "'concealed','accesslog','modreq',"
401 "'purgeevent','purgeitem','unversioned',"
402 "'subscriber','pending_alert','chat')"
403 " AND name NOT GLOB 'sqlite_*'"
404 " AND name NOT GLOB 'fx_*'"
405 );
406 while( db_step(&q)==SQLITE_ROW ){
407 blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0));
408 }
409 db_finalize(&q);
 
 
 
410 db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
411 blob_reset(&sql);
412 db_multi_exec("%s", zRepositorySchema2/*safe-for-%s*/);
413 ticket_create_table(0);
414 shun_artifacts();
415
--- src/rebuild.c
+++ src/rebuild.c
@@ -390,25 +390,31 @@
390 }
391 manifest_disable_event_triggers();
392 rebuild_update_schema();
393 blob_init(&sql, 0, 0);
394 db_unprotect(PROTECT_ALL);
395 #ifndef SQLITE_PREPARE_DONT_LOG
396 g.dbIgnoreErrors++;
397 #endif
398 db_prepare(&q,
399 "SELECT name FROM pragma_table_list /*scan*/"
400 " WHERE schema='repository' AND type IN ('table','virtual')"
401 " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
402 "'config','shun','private','reportfmt',"
403 "'concealed','accesslog','modreq',"
404 "'purgeevent','purgeitem','unversioned',"
405 "'subscriber','pending_alert','chat')"
406 " AND name NOT GLOB 'sqlite_*'"
407 " AND name NOT GLOB 'fx_*';"
408 );
409 while( db_step(&q)==SQLITE_ROW ){
410 blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0));
411 }
412 db_finalize(&q);
413 #ifndef SQLITE_PREPARE_DONT_LOG
414 g.dbIgnoreErrors--;
415 #endif
416 db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
417 blob_reset(&sql);
418 db_multi_exec("%s", zRepositorySchema2/*safe-for-%s*/);
419 ticket_create_table(0);
420 shun_artifacts();
421
+4 -5
--- src/rss.c
+++ src/rss.c
@@ -39,11 +39,10 @@
3939
**
4040
** In addition, name=FILENAME filters for a specific file. This may be
4141
** combined with one of the other filters (useful for looking at a specific
4242
** branch).
4343
*/
44
-
4544
void page_timeline_rss(void){
4645
Stmt q;
4746
int nLine=0;
4847
char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
4948
Blob bSQL;
@@ -79,13 +78,13 @@
7978
blob_zero(&bSQL);
8079
blob_append_sql( &bSQL, "%s", zSQL1/*safe-for-%s*/ );
8180
8281
if( zType[0]!='a' ){
8382
if( zType[0]=='c' && !g.perm.Read ) zType = "x";
84
- if( zType[0]=='w' && !g.perm.RdWiki ) zType = "x";
85
- if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x";
86
- if( zType[0]=='f' && !g.perm.RdForum ) zType = "x";
83
+ else if( (zType[0]=='w' || zType[0]=='e') && !g.perm.RdWiki ) zType = "x";
84
+ else if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x";
85
+ else if( zType[0]=='f' && !g.perm.RdForum ) zType = "x";
8786
blob_append_sql(&bSQL, " AND event.type=%Q", zType);
8887
}else{
8988
blob_append_sql(&bSQL, " AND event.type in (");
9089
if( g.perm.Read ){
9190
blob_append_sql(&bSQL, "'ci',");
@@ -92,11 +91,11 @@
9291
}
9392
if( g.perm.RdTkt ){
9493
blob_append_sql(&bSQL, "'t',");
9594
}
9695
if( g.perm.RdWiki ){
97
- blob_append_sql(&bSQL, "'w',");
96
+ blob_append_sql(&bSQL, "'w','e',");
9897
}
9998
if( g.perm.RdForum ){
10099
blob_append_sql(&bSQL, "'f',");
101100
}
102101
blob_append_sql(&bSQL, "'x')");
103102
--- src/rss.c
+++ src/rss.c
@@ -39,11 +39,10 @@
39 **
40 ** In addition, name=FILENAME filters for a specific file. This may be
41 ** combined with one of the other filters (useful for looking at a specific
42 ** branch).
43 */
44
45 void page_timeline_rss(void){
46 Stmt q;
47 int nLine=0;
48 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
49 Blob bSQL;
@@ -79,13 +78,13 @@
79 blob_zero(&bSQL);
80 blob_append_sql( &bSQL, "%s", zSQL1/*safe-for-%s*/ );
81
82 if( zType[0]!='a' ){
83 if( zType[0]=='c' && !g.perm.Read ) zType = "x";
84 if( zType[0]=='w' && !g.perm.RdWiki ) zType = "x";
85 if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x";
86 if( zType[0]=='f' && !g.perm.RdForum ) zType = "x";
87 blob_append_sql(&bSQL, " AND event.type=%Q", zType);
88 }else{
89 blob_append_sql(&bSQL, " AND event.type in (");
90 if( g.perm.Read ){
91 blob_append_sql(&bSQL, "'ci',");
@@ -92,11 +91,11 @@
92 }
93 if( g.perm.RdTkt ){
94 blob_append_sql(&bSQL, "'t',");
95 }
96 if( g.perm.RdWiki ){
97 blob_append_sql(&bSQL, "'w',");
98 }
99 if( g.perm.RdForum ){
100 blob_append_sql(&bSQL, "'f',");
101 }
102 blob_append_sql(&bSQL, "'x')");
103
--- src/rss.c
+++ src/rss.c
@@ -39,11 +39,10 @@
39 **
40 ** In addition, name=FILENAME filters for a specific file. This may be
41 ** combined with one of the other filters (useful for looking at a specific
42 ** branch).
43 */
 
44 void page_timeline_rss(void){
45 Stmt q;
46 int nLine=0;
47 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
48 Blob bSQL;
@@ -79,13 +78,13 @@
78 blob_zero(&bSQL);
79 blob_append_sql( &bSQL, "%s", zSQL1/*safe-for-%s*/ );
80
81 if( zType[0]!='a' ){
82 if( zType[0]=='c' && !g.perm.Read ) zType = "x";
83 else if( (zType[0]=='w' || zType[0]=='e') && !g.perm.RdWiki ) zType = "x";
84 else if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x";
85 else if( zType[0]=='f' && !g.perm.RdForum ) zType = "x";
86 blob_append_sql(&bSQL, " AND event.type=%Q", zType);
87 }else{
88 blob_append_sql(&bSQL, " AND event.type in (");
89 if( g.perm.Read ){
90 blob_append_sql(&bSQL, "'ci',");
@@ -92,11 +91,11 @@
91 }
92 if( g.perm.RdTkt ){
93 blob_append_sql(&bSQL, "'t',");
94 }
95 if( g.perm.RdWiki ){
96 blob_append_sql(&bSQL, "'w','e',");
97 }
98 if( g.perm.RdForum ){
99 blob_append_sql(&bSQL, "'f',");
100 }
101 blob_append_sql(&bSQL, "'x')");
102
+7 -7
--- src/schema.c
+++ src/schema.c
@@ -28,11 +28,11 @@
2828
@ -- ~/.fossil file and that stores information about the users setup.
2929
@ --
3030
@ CREATE TABLE global_config(
3131
@ name TEXT PRIMARY KEY,
3232
@ value TEXT
33
-@ );
33
+@ ) WITHOUT ROWID;
3434
@
3535
@ -- Identifier for this file type.
3636
@ -- The integer is the same as 'FSLG'.
3737
@ PRAGMA application_id=252006675;
3838
;
@@ -138,11 +138,11 @@
138138
@ CREATE TABLE config(
139139
@ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
140140
@ value CLOB, -- Content of the named parameter
141141
@ mtime DATE, -- last modified. seconds since 1970
142142
@ CHECK( typeof(name)='text' AND length(name)>=1 )
143
-@ );
143
+@ ) WITHOUT ROWID;
144144
@
145145
@ -- Artifacts that should not be processed are identified in the
146146
@ -- "shun" table. Artifacts that are control-file forgeries or
147147
@ -- spam or artifacts whose contents violate administrative policy
148148
@ -- can be shunned in order to prevent them from contaminating
@@ -151,14 +151,14 @@
151151
@ -- Shunned artifacts do not exist in the blob table. Hence they
152152
@ -- have not artifact ID (rid) and we thus must store their full
153153
@ -- UUID.
154154
@ --
155155
@ CREATE TABLE shun(
156
-@ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form
156
+@ uuid TEXT PRIMARY KEY,-- UUID of artifact to be shunned. Canonical form
157157
@ mtime DATE, -- When added. seconds since 1970
158158
@ scom TEXT -- Optional text explaining why the shun occurred
159
-@ );
159
+@ ) WITHOUT ROWID;
160160
@
161161
@ -- Artifacts that should not be pushed are stored in the "private"
162162
@ -- table. Private artifacts are omitted from the "unclustered" and
163163
@ -- "unsent" tables.
164164
@ --
@@ -193,11 +193,11 @@
193193
@ --
194194
@ CREATE TABLE concealed(
195195
@ hash TEXT PRIMARY KEY, -- The SHA1 hash of content
196196
@ mtime DATE, -- Time created. Seconds since 1970
197197
@ content TEXT -- Content intended to be concealed
198
-@ );
198
+@ ) WITHOUT ROWID;
199199
@
200200
@ -- The application ID helps the unix "file" command to identify the
201201
@ -- database as a fossil repository.
202202
@ PRAGMA application_id=252006673;
203203
;
@@ -528,11 +528,11 @@
528528
** The schema for the local FOSSIL database file found at the root
529529
** of every check-out. This database contains the complete state of
530530
** the check-out. See also the addendum in zLocalSchemaVmerge[].
531531
*/
532532
const char zLocalSchema[] =
533
-@ -- The VVAR table holds miscellanous information about the local database
533
+@ -- The VVAR table holds miscellanous information about the local checkout
534534
@ -- in the form of name-value pairs. This is similar to the VAR table
535535
@ -- table in the repository except that this table holds information that
536536
@ -- is specific to the local check-out.
537537
@ --
538538
@ -- Important Variables:
@@ -542,11 +542,11 @@
542542
@ --
543543
@ CREATE TABLE vvar(
544544
@ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
545545
@ value CLOB, -- Content of the named parameter
546546
@ CHECK( typeof(name)='text' AND length(name)>=1 )
547
-@ );
547
+@ ) WITHOUT ROWID;
548548
@
549549
@ -- Each entry in the vfile table represents a single file in the
550550
@ -- current check-out.
551551
@ --
552552
@ -- The file.rid field is 0 for files or folders that have been
553553
--- src/schema.c
+++ src/schema.c
@@ -28,11 +28,11 @@
28 @ -- ~/.fossil file and that stores information about the users setup.
29 @ --
30 @ CREATE TABLE global_config(
31 @ name TEXT PRIMARY KEY,
32 @ value TEXT
33 @ );
34 @
35 @ -- Identifier for this file type.
36 @ -- The integer is the same as 'FSLG'.
37 @ PRAGMA application_id=252006675;
38 ;
@@ -138,11 +138,11 @@
138 @ CREATE TABLE config(
139 @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
140 @ value CLOB, -- Content of the named parameter
141 @ mtime DATE, -- last modified. seconds since 1970
142 @ CHECK( typeof(name)='text' AND length(name)>=1 )
143 @ );
144 @
145 @ -- Artifacts that should not be processed are identified in the
146 @ -- "shun" table. Artifacts that are control-file forgeries or
147 @ -- spam or artifacts whose contents violate administrative policy
148 @ -- can be shunned in order to prevent them from contaminating
@@ -151,14 +151,14 @@
151 @ -- Shunned artifacts do not exist in the blob table. Hence they
152 @ -- have not artifact ID (rid) and we thus must store their full
153 @ -- UUID.
154 @ --
155 @ CREATE TABLE shun(
156 @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form
157 @ mtime DATE, -- When added. seconds since 1970
158 @ scom TEXT -- Optional text explaining why the shun occurred
159 @ );
160 @
161 @ -- Artifacts that should not be pushed are stored in the "private"
162 @ -- table. Private artifacts are omitted from the "unclustered" and
163 @ -- "unsent" tables.
164 @ --
@@ -193,11 +193,11 @@
193 @ --
194 @ CREATE TABLE concealed(
195 @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content
196 @ mtime DATE, -- Time created. Seconds since 1970
197 @ content TEXT -- Content intended to be concealed
198 @ );
199 @
200 @ -- The application ID helps the unix "file" command to identify the
201 @ -- database as a fossil repository.
202 @ PRAGMA application_id=252006673;
203 ;
@@ -528,11 +528,11 @@
528 ** The schema for the local FOSSIL database file found at the root
529 ** of every check-out. This database contains the complete state of
530 ** the check-out. See also the addendum in zLocalSchemaVmerge[].
531 */
532 const char zLocalSchema[] =
533 @ -- The VVAR table holds miscellanous information about the local database
534 @ -- in the form of name-value pairs. This is similar to the VAR table
535 @ -- table in the repository except that this table holds information that
536 @ -- is specific to the local check-out.
537 @ --
538 @ -- Important Variables:
@@ -542,11 +542,11 @@
542 @ --
543 @ CREATE TABLE vvar(
544 @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
545 @ value CLOB, -- Content of the named parameter
546 @ CHECK( typeof(name)='text' AND length(name)>=1 )
547 @ );
548 @
549 @ -- Each entry in the vfile table represents a single file in the
550 @ -- current check-out.
551 @ --
552 @ -- The file.rid field is 0 for files or folders that have been
553
--- src/schema.c
+++ src/schema.c
@@ -28,11 +28,11 @@
28 @ -- ~/.fossil file and that stores information about the users setup.
29 @ --
30 @ CREATE TABLE global_config(
31 @ name TEXT PRIMARY KEY,
32 @ value TEXT
33 @ ) WITHOUT ROWID;
34 @
35 @ -- Identifier for this file type.
36 @ -- The integer is the same as 'FSLG'.
37 @ PRAGMA application_id=252006675;
38 ;
@@ -138,11 +138,11 @@
138 @ CREATE TABLE config(
139 @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
140 @ value CLOB, -- Content of the named parameter
141 @ mtime DATE, -- last modified. seconds since 1970
142 @ CHECK( typeof(name)='text' AND length(name)>=1 )
143 @ ) WITHOUT ROWID;
144 @
145 @ -- Artifacts that should not be processed are identified in the
146 @ -- "shun" table. Artifacts that are control-file forgeries or
147 @ -- spam or artifacts whose contents violate administrative policy
148 @ -- can be shunned in order to prevent them from contaminating
@@ -151,14 +151,14 @@
151 @ -- Shunned artifacts do not exist in the blob table. Hence they
152 @ -- have not artifact ID (rid) and we thus must store their full
153 @ -- UUID.
154 @ --
155 @ CREATE TABLE shun(
156 @ uuid TEXT PRIMARY KEY,-- UUID of artifact to be shunned. Canonical form
157 @ mtime DATE, -- When added. seconds since 1970
158 @ scom TEXT -- Optional text explaining why the shun occurred
159 @ ) WITHOUT ROWID;
160 @
161 @ -- Artifacts that should not be pushed are stored in the "private"
162 @ -- table. Private artifacts are omitted from the "unclustered" and
163 @ -- "unsent" tables.
164 @ --
@@ -193,11 +193,11 @@
193 @ --
194 @ CREATE TABLE concealed(
195 @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content
196 @ mtime DATE, -- Time created. Seconds since 1970
197 @ content TEXT -- Content intended to be concealed
198 @ ) WITHOUT ROWID;
199 @
200 @ -- The application ID helps the unix "file" command to identify the
201 @ -- database as a fossil repository.
202 @ PRAGMA application_id=252006673;
203 ;
@@ -528,11 +528,11 @@
528 ** The schema for the local FOSSIL database file found at the root
529 ** of every check-out. This database contains the complete state of
530 ** the check-out. See also the addendum in zLocalSchemaVmerge[].
531 */
532 const char zLocalSchema[] =
533 @ -- The VVAR table holds miscellanous information about the local checkout
534 @ -- in the form of name-value pairs. This is similar to the VAR table
535 @ -- table in the repository except that this table holds information that
536 @ -- is specific to the local check-out.
537 @ --
538 @ -- Important Variables:
@@ -542,11 +542,11 @@
542 @ --
543 @ CREATE TABLE vvar(
544 @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
545 @ value CLOB, -- Content of the named parameter
546 @ CHECK( typeof(name)='text' AND length(name)>=1 )
547 @ ) WITHOUT ROWID;
548 @
549 @ -- Each entry in the vfile table represents a single file in the
550 @ -- current check-out.
551 @ --
552 @ -- The file.rid field is 0 for files or folders that have been
553
+83 -64
--- src/search.c
+++ src/search.c
@@ -794,31 +794,41 @@
794794
SRCHFLG_STATIC|SRCHFLG_HTML);
795795
if( (srchFlags & SRCH_DOC)!=0 ){
796796
char *zDocGlob = db_get("doc-glob","");
797797
char *zDocBr = db_get("doc-branch","trunk");
798798
if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
799
+ Glob * pGlob = glob_create(zDocBr)
800
+ /* We're misusing a Glob as a list of comma-/space-delimited
801
+ ** tokens. We're not actually doing glob matches here. */;
802
+ int i;
799803
db_multi_exec(
800804
"CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
801805
);
802
- db_multi_exec(
803
- "INSERT INTO x(label,url,score,id,date,snip)"
804
- " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
805
- " printf('/doc/%T/%%s',foci.filename),"
806
- " search_score(),"
807
- " 'd'||blob.rid,"
808
- " (SELECT datetime(event.mtime) FROM event"
809
- " WHERE objid=symbolic_name_to_rid('trunk')),"
810
- " search_snippet()"
811
- " FROM foci CROSS JOIN blob"
812
- " WHERE checkinID=symbolic_name_to_rid('trunk')"
813
- " AND blob.uuid=foci.uuid"
814
- " AND search_match(title('d',blob.rid,foci.filename),"
815
- " body('d',blob.rid,foci.filename))"
816
- " AND %z",
817
- zDocBr, glob_expr("foci.filename", zDocGlob)
818
- );
819
- }
806
+ for( i = 0; i < pGlob->nPattern; ++i ){
807
+ const char * zBranch = pGlob->azPattern[i];
808
+ db_multi_exec(
809
+ "INSERT INTO x(label,url,score,id,date,snip)"
810
+ " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
811
+ " printf('/doc/%T/%%s',foci.filename),"
812
+ " search_score(),"
813
+ " 'd'||blob.rid,"
814
+ " (SELECT datetime(event.mtime) FROM event"
815
+ " WHERE objid=symbolic_name_to_rid(%Q)),"
816
+ " search_snippet()"
817
+ " FROM foci CROSS JOIN blob"
818
+ " WHERE checkinID=symbolic_name_to_rid(%Q)"
819
+ " AND blob.uuid=foci.uuid"
820
+ " AND search_match(title('d',blob.rid,foci.filename),"
821
+ " body('d',blob.rid,foci.filename))"
822
+ " AND %z",
823
+ zBranch, zBranch, zBranch, glob_expr("foci.filename", zDocGlob)
824
+ );
825
+ }
826
+ glob_free(pGlob);
827
+ }
828
+ fossil_free(zDocGlob);
829
+ fossil_free(zDocBr);
820830
}
821831
if( (srchFlags & SRCH_WIKI)!=0 ){
822832
db_multi_exec(
823833
"WITH wiki(name,rid,mtime) AS ("
824834
" SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
@@ -1878,59 +1888,68 @@
18781888
** and if the latest check-in on doc-br is in the unindexed set of
18791889
** check-ins, then update all 'd' entries in FTSDOCS that have
18801890
** changed.
18811891
*/
18821892
static void search_update_doc_index(void){
1883
- const char *zDocBr = db_get("doc-branch","trunk");
1884
- int ckid = zDocBr ? symbolic_name_to_rid(zDocBr,"ci") : 0;
1885
- double rTime;
1886
- if( ckid==0 ) return;
1887
- if( !db_exists("SELECT 1 FROM ftsdocs WHERE type='c' AND rid=%d"
1888
- " AND NOT idxed", ckid) ) return;
1889
-
1890
- /* If we get this far, it means that changes to 'd' entries are
1891
- ** required. */
1892
- rTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", ckid);
1893
+ const char *zDocBranches = db_get("doc-branch","trunk");
1894
+ int i;
1895
+ Glob * pGlob = glob_create(zDocBranches)
1896
+ /* We're misusing a Glob as a list of comma-/space-delimited
1897
+ ** tokens. We're not actually doing glob matches here. */;
1898
+ if( !pGlob ) return;
18931899
db_multi_exec(
18941900
"CREATE TEMP TABLE current_docs(rid INTEGER PRIMARY KEY, name);"
18951901
"CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
1896
- "INSERT OR IGNORE INTO current_docs(rid, name)"
1897
- " SELECT blob.rid, foci.filename FROM foci, blob"
1898
- " WHERE foci.checkinID=%d AND blob.uuid=foci.uuid"
1899
- " AND %z",
1900
- ckid, glob_expr("foci.filename", db_get("doc-glob",""))
1901
- );
1902
- db_multi_exec(
1903
- "DELETE FROM ftsidx WHERE rowid IN"
1904
- " (SELECT rowid FROM ftsdocs WHERE type='d'"
1905
- " AND rid NOT IN (SELECT rid FROM current_docs))"
1906
- );
1907
- db_multi_exec(
1908
- "DELETE FROM ftsdocs WHERE type='d'"
1909
- " AND rid NOT IN (SELECT rid FROM current_docs)"
1910
- );
1911
- db_multi_exec(
1912
- "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)"
1913
- " SELECT 'd', rid, name, 0,"
1914
- " title('d',rid,name),"
1915
- " body('d',rid,name),"
1916
- " printf('/doc/%T/%%s',urlencode(name)),"
1917
- " %.17g"
1918
- " FROM current_docs",
1919
- zDocBr, rTime
1920
- );
1921
- db_multi_exec(
1922
- "INSERT INTO ftsidx(rowid,title,body)"
1923
- " SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed"
1924
- );
1925
- db_multi_exec(
1926
- "UPDATE ftsdocs SET"
1927
- " idxed=1,"
1928
- " bx=NULL,"
1929
- " label='Document: '||label"
1930
- " WHERE type='d' AND NOT idxed"
1931
- );
1902
+ );
1903
+ for( i = 0; i < pGlob->nPattern; ++i ){
1904
+ const char *zDocBr = pGlob->azPattern[i];
1905
+ int ckid = symbolic_name_to_rid(zDocBr,"ci");
1906
+ double rTime;
1907
+ if( !db_exists("SELECT 1 FROM ftsdocs WHERE type='c' AND rid=%d"
1908
+ " AND NOT idxed", ckid) ) continue;
1909
+ /* If we get this far, it means that changes to 'd' entries are
1910
+ ** required. */
1911
+ rTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", ckid);
1912
+ db_multi_exec(
1913
+ "INSERT OR IGNORE INTO current_docs(rid, name)"
1914
+ " SELECT blob.rid, foci.filename FROM foci, blob"
1915
+ " WHERE foci.checkinID=%d AND blob.uuid=foci.uuid"
1916
+ " AND %z",
1917
+ ckid, glob_expr("foci.filename", db_get("doc-glob",""))
1918
+ );
1919
+ db_multi_exec(
1920
+ "DELETE FROM ftsidx WHERE rowid IN"
1921
+ " (SELECT rowid FROM ftsdocs WHERE type='d'"
1922
+ " AND rid NOT IN (SELECT rid FROM current_docs))"
1923
+ );
1924
+ db_multi_exec(
1925
+ "DELETE FROM ftsdocs WHERE type='d'"
1926
+ " AND rid NOT IN (SELECT rid FROM current_docs)"
1927
+ );
1928
+ db_multi_exec(
1929
+ "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)"
1930
+ " SELECT 'd', rid, name, 0,"
1931
+ " title('d',rid,name),"
1932
+ " body('d',rid,name),"
1933
+ " printf('/doc/%T/%%s',urlencode(name)),"
1934
+ " %.17g"
1935
+ " FROM current_docs",
1936
+ zDocBr, rTime
1937
+ );
1938
+ db_multi_exec(
1939
+ "INSERT INTO ftsidx(rowid,title,body)"
1940
+ " SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed"
1941
+ );
1942
+ db_multi_exec(
1943
+ "UPDATE ftsdocs SET"
1944
+ " idxed=1,"
1945
+ " bx=NULL,"
1946
+ " label='Document: '||label"
1947
+ " WHERE type='d' AND NOT idxed"
1948
+ );
1949
+ }
1950
+ glob_free(pGlob);
19321951
}
19331952
19341953
/*
19351954
** Deal with all of the unindexed 'c' terms in FTSDOCS
19361955
*/
19371956
--- src/search.c
+++ src/search.c
@@ -794,31 +794,41 @@
794 SRCHFLG_STATIC|SRCHFLG_HTML);
795 if( (srchFlags & SRCH_DOC)!=0 ){
796 char *zDocGlob = db_get("doc-glob","");
797 char *zDocBr = db_get("doc-branch","trunk");
798 if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
 
 
 
 
799 db_multi_exec(
800 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
801 );
802 db_multi_exec(
803 "INSERT INTO x(label,url,score,id,date,snip)"
804 " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
805 " printf('/doc/%T/%%s',foci.filename),"
806 " search_score(),"
807 " 'd'||blob.rid,"
808 " (SELECT datetime(event.mtime) FROM event"
809 " WHERE objid=symbolic_name_to_rid('trunk')),"
810 " search_snippet()"
811 " FROM foci CROSS JOIN blob"
812 " WHERE checkinID=symbolic_name_to_rid('trunk')"
813 " AND blob.uuid=foci.uuid"
814 " AND search_match(title('d',blob.rid,foci.filename),"
815 " body('d',blob.rid,foci.filename))"
816 " AND %z",
817 zDocBr, glob_expr("foci.filename", zDocGlob)
818 );
819 }
 
 
 
 
 
 
820 }
821 if( (srchFlags & SRCH_WIKI)!=0 ){
822 db_multi_exec(
823 "WITH wiki(name,rid,mtime) AS ("
824 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
@@ -1878,59 +1888,68 @@
1878 ** and if the latest check-in on doc-br is in the unindexed set of
1879 ** check-ins, then update all 'd' entries in FTSDOCS that have
1880 ** changed.
1881 */
1882 static void search_update_doc_index(void){
1883 const char *zDocBr = db_get("doc-branch","trunk");
1884 int ckid = zDocBr ? symbolic_name_to_rid(zDocBr,"ci") : 0;
1885 double rTime;
1886 if( ckid==0 ) return;
1887 if( !db_exists("SELECT 1 FROM ftsdocs WHERE type='c' AND rid=%d"
1888 " AND NOT idxed", ckid) ) return;
1889
1890 /* If we get this far, it means that changes to 'd' entries are
1891 ** required. */
1892 rTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", ckid);
1893 db_multi_exec(
1894 "CREATE TEMP TABLE current_docs(rid INTEGER PRIMARY KEY, name);"
1895 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
1896 "INSERT OR IGNORE INTO current_docs(rid, name)"
1897 " SELECT blob.rid, foci.filename FROM foci, blob"
1898 " WHERE foci.checkinID=%d AND blob.uuid=foci.uuid"
1899 " AND %z",
1900 ckid, glob_expr("foci.filename", db_get("doc-glob",""))
1901 );
1902 db_multi_exec(
1903 "DELETE FROM ftsidx WHERE rowid IN"
1904 " (SELECT rowid FROM ftsdocs WHERE type='d'"
1905 " AND rid NOT IN (SELECT rid FROM current_docs))"
1906 );
1907 db_multi_exec(
1908 "DELETE FROM ftsdocs WHERE type='d'"
1909 " AND rid NOT IN (SELECT rid FROM current_docs)"
1910 );
1911 db_multi_exec(
1912 "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)"
1913 " SELECT 'd', rid, name, 0,"
1914 " title('d',rid,name),"
1915 " body('d',rid,name),"
1916 " printf('/doc/%T/%%s',urlencode(name)),"
1917 " %.17g"
1918 " FROM current_docs",
1919 zDocBr, rTime
1920 );
1921 db_multi_exec(
1922 "INSERT INTO ftsidx(rowid,title,body)"
1923 " SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed"
1924 );
1925 db_multi_exec(
1926 "UPDATE ftsdocs SET"
1927 " idxed=1,"
1928 " bx=NULL,"
1929 " label='Document: '||label"
1930 " WHERE type='d' AND NOT idxed"
1931 );
 
 
 
 
 
 
 
 
 
 
 
 
 
1932 }
1933
1934 /*
1935 ** Deal with all of the unindexed 'c' terms in FTSDOCS
1936 */
1937
--- src/search.c
+++ src/search.c
@@ -794,31 +794,41 @@
794 SRCHFLG_STATIC|SRCHFLG_HTML);
795 if( (srchFlags & SRCH_DOC)!=0 ){
796 char *zDocGlob = db_get("doc-glob","");
797 char *zDocBr = db_get("doc-branch","trunk");
798 if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
799 Glob * pGlob = glob_create(zDocBr)
800 /* We're misusing a Glob as a list of comma-/space-delimited
801 ** tokens. We're not actually doing glob matches here. */;
802 int i;
803 db_multi_exec(
804 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
805 );
806 for( i = 0; i < pGlob->nPattern; ++i ){
807 const char * zBranch = pGlob->azPattern[i];
808 db_multi_exec(
809 "INSERT INTO x(label,url,score,id,date,snip)"
810 " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
811 " printf('/doc/%T/%%s',foci.filename),"
812 " search_score(),"
813 " 'd'||blob.rid,"
814 " (SELECT datetime(event.mtime) FROM event"
815 " WHERE objid=symbolic_name_to_rid(%Q)),"
816 " search_snippet()"
817 " FROM foci CROSS JOIN blob"
818 " WHERE checkinID=symbolic_name_to_rid(%Q)"
819 " AND blob.uuid=foci.uuid"
820 " AND search_match(title('d',blob.rid,foci.filename),"
821 " body('d',blob.rid,foci.filename))"
822 " AND %z",
823 zBranch, zBranch, zBranch, glob_expr("foci.filename", zDocGlob)
824 );
825 }
826 glob_free(pGlob);
827 }
828 fossil_free(zDocGlob);
829 fossil_free(zDocBr);
830 }
831 if( (srchFlags & SRCH_WIKI)!=0 ){
832 db_multi_exec(
833 "WITH wiki(name,rid,mtime) AS ("
834 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
@@ -1878,59 +1888,68 @@
1888 ** and if the latest check-in on doc-br is in the unindexed set of
1889 ** check-ins, then update all 'd' entries in FTSDOCS that have
1890 ** changed.
1891 */
1892 static void search_update_doc_index(void){
1893 const char *zDocBranches = db_get("doc-branch","trunk");
1894 int i;
1895 Glob * pGlob = glob_create(zDocBranches)
1896 /* We're misusing a Glob as a list of comma-/space-delimited
1897 ** tokens. We're not actually doing glob matches here. */;
1898 if( !pGlob ) return;
 
 
 
 
1899 db_multi_exec(
1900 "CREATE TEMP TABLE current_docs(rid INTEGER PRIMARY KEY, name);"
1901 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
1902 );
1903 for( i = 0; i < pGlob->nPattern; ++i ){
1904 const char *zDocBr = pGlob->azPattern[i];
1905 int ckid = symbolic_name_to_rid(zDocBr,"ci");
1906 double rTime;
1907 if( !db_exists("SELECT 1 FROM ftsdocs WHERE type='c' AND rid=%d"
1908 " AND NOT idxed", ckid) ) continue;
1909 /* If we get this far, it means that changes to 'd' entries are
1910 ** required. */
1911 rTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", ckid);
1912 db_multi_exec(
1913 "INSERT OR IGNORE INTO current_docs(rid, name)"
1914 " SELECT blob.rid, foci.filename FROM foci, blob"
1915 " WHERE foci.checkinID=%d AND blob.uuid=foci.uuid"
1916 " AND %z",
1917 ckid, glob_expr("foci.filename", db_get("doc-glob",""))
1918 );
1919 db_multi_exec(
1920 "DELETE FROM ftsidx WHERE rowid IN"
1921 " (SELECT rowid FROM ftsdocs WHERE type='d'"
1922 " AND rid NOT IN (SELECT rid FROM current_docs))"
1923 );
1924 db_multi_exec(
1925 "DELETE FROM ftsdocs WHERE type='d'"
1926 " AND rid NOT IN (SELECT rid FROM current_docs)"
1927 );
1928 db_multi_exec(
1929 "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)"
1930 " SELECT 'd', rid, name, 0,"
1931 " title('d',rid,name),"
1932 " body('d',rid,name),"
1933 " printf('/doc/%T/%%s',urlencode(name)),"
1934 " %.17g"
1935 " FROM current_docs",
1936 zDocBr, rTime
1937 );
1938 db_multi_exec(
1939 "INSERT INTO ftsidx(rowid,title,body)"
1940 " SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed"
1941 );
1942 db_multi_exec(
1943 "UPDATE ftsdocs SET"
1944 " idxed=1,"
1945 " bx=NULL,"
1946 " label='Document: '||label"
1947 " WHERE type='d' AND NOT idxed"
1948 );
1949 }
1950 glob_free(pGlob);
1951 }
1952
1953 /*
1954 ** Deal with all of the unindexed 'c' terms in FTSDOCS
1955 */
1956
+16 -4
--- src/setup.c
+++ src/setup.c
@@ -501,13 +501,24 @@
501501
@ behavior or to find an SQL injection opportunity or similar. This can
502502
@ waste hours of CPU time and gigabytes of bandwidth on the server. A
503503
@ suggested value for this setting is:
504504
@ "<tt>timeline,*diff,vpatch,annotate,blame,praise,dir,tree</tt>".
505505
@ (Property: robot-restrict)
506
- @ <p>
506
+ @ <br>
507507
textarea_attribute("", 2, 80,
508508
"robot-restrict", "rbrestrict", "", 0);
509
+ @ <br> The following comma-separated GLOB pattern allows for exceptions
510
+ @ in the maximum number of query parameters before a request is considered
511
+ @ complex. If this GLOB pattern exists and is non-empty and if it
512
+ @ matches against the pagename followed by "/" and the number of query
513
+ @ parameters, then the request is allowed through. For example, the
514
+ @ suggested pattern of "timeline/[012]" allows the /timeline page to
515
+ @ pass with up to 2 query parameters besides "name".
516
+ @ (Property: robot-restrict-qp)
517
+ @ <br>
518
+ textarea_attribute("", 2, 80,
519
+ "robot-restrict-qp", "rbrestrictqp", "", 0);
509520
510521
@ <hr>
511522
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
512523
@ </div></form>
513524
db_end_transaction(0);
@@ -2187,14 +2198,15 @@
21872198
@ <tr><td>*<td><td>Search all checked-in files</tr>
21882199
@ <tr><td><i>(blank)</i><td>
21892200
@ <td>Search nothing. (Disables document search).</tr>
21902201
@ </table>
21912202
@ <hr>
2192
- entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
2203
+ entry_attribute("Document Branches", 20, "doc-branch", "db", "trunk", 0);
21932204
@ <p>When searching documents, use the versions of the files found at the
2194
- @ type of the "Document Branch" branch. Recommended value: "trunk".
2195
- @ Document search is disabled if blank.
2205
+ @ type of the "Document Branches" branch. Recommended value: "trunk".
2206
+ @ Document search is disabled if blank. It may be a list of branch names
2207
+ @ separated by spaces and/or commas.
21962208
@ <hr>
21972209
onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
21982210
@ <br>
21992211
onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
22002212
@ <br>
22012213
--- src/setup.c
+++ src/setup.c
@@ -501,13 +501,24 @@
501 @ behavior or to find an SQL injection opportunity or similar. This can
502 @ waste hours of CPU time and gigabytes of bandwidth on the server. A
503 @ suggested value for this setting is:
504 @ "<tt>timeline,*diff,vpatch,annotate,blame,praise,dir,tree</tt>".
505 @ (Property: robot-restrict)
506 @ <p>
507 textarea_attribute("", 2, 80,
508 "robot-restrict", "rbrestrict", "", 0);
 
 
 
 
 
 
 
 
 
 
 
509
510 @ <hr>
511 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
512 @ </div></form>
513 db_end_transaction(0);
@@ -2187,14 +2198,15 @@
2187 @ <tr><td>*<td><td>Search all checked-in files</tr>
2188 @ <tr><td><i>(blank)</i><td>
2189 @ <td>Search nothing. (Disables document search).</tr>
2190 @ </table>
2191 @ <hr>
2192 entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
2193 @ <p>When searching documents, use the versions of the files found at the
2194 @ type of the "Document Branch" branch. Recommended value: "trunk".
2195 @ Document search is disabled if blank.
 
2196 @ <hr>
2197 onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
2198 @ <br>
2199 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2200 @ <br>
2201
--- src/setup.c
+++ src/setup.c
@@ -501,13 +501,24 @@
501 @ behavior or to find an SQL injection opportunity or similar. This can
502 @ waste hours of CPU time and gigabytes of bandwidth on the server. A
503 @ suggested value for this setting is:
504 @ "<tt>timeline,*diff,vpatch,annotate,blame,praise,dir,tree</tt>".
505 @ (Property: robot-restrict)
506 @ <br>
507 textarea_attribute("", 2, 80,
508 "robot-restrict", "rbrestrict", "", 0);
509 @ <br> The following comma-separated GLOB pattern allows for exceptions
510 @ in the maximum number of query parameters before a request is considered
511 @ complex. If this GLOB pattern exists and is non-empty and if it
512 @ matches against the pagename followed by "/" and the number of query
513 @ parameters, then the request is allowed through. For example, the
514 @ suggested pattern of "timeline/[012]" allows the /timeline page to
515 @ pass with up to 2 query parameters besides "name".
516 @ (Property: robot-restrict-qp)
517 @ <br>
518 textarea_attribute("", 2, 80,
519 "robot-restrict-qp", "rbrestrictqp", "", 0);
520
521 @ <hr>
522 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
523 @ </div></form>
524 db_end_transaction(0);
@@ -2187,14 +2198,15 @@
2198 @ <tr><td>*<td><td>Search all checked-in files</tr>
2199 @ <tr><td><i>(blank)</i><td>
2200 @ <td>Search nothing. (Disables document search).</tr>
2201 @ </table>
2202 @ <hr>
2203 entry_attribute("Document Branches", 20, "doc-branch", "db", "trunk", 0);
2204 @ <p>When searching documents, use the versions of the files found at the
2205 @ type of the "Document Branches" branch. Recommended value: "trunk".
2206 @ Document search is disabled if blank. It may be a list of branch names
2207 @ separated by spaces and/or commas.
2208 @ <hr>
2209 onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
2210 @ <br>
2211 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2212 @ <br>
2213
+7 -5
--- src/setupuser.c
+++ src/setupuser.c
@@ -115,11 +115,11 @@
115115
}
116116
if( !bUnusedOnly ){
117117
style_submenu_element("Unused", "setup_ulist?unused");
118118
}
119119
@ <table border=1 cellpadding=2 cellspacing=0 class='userTable sortable' \
120
- @ data-column-types='ktxTTKt' data-init-sort='2'>
120
+ @ data-column-types='ktxKTKt' data-init-sort='4'>
121121
@ <thead><tr>
122122
@ <th>Login Name<th>Caps<th>Info<th>Date<th>Expire<th>Last Login\
123123
@ <th>Alerts</tr></thead>
124124
@ <tbody>
125125
db_multi_exec(
@@ -161,15 +161,16 @@
161161
" lower(login) AS sortkey, "
162162
" CASE WHEN info LIKE '%%expires 20%%'"
163163
" THEN substr(info,instr(lower(info),'expires')+8,10)"
164164
" END AS exp,"
165165
"atime,"
166
- " subscriber.ssub, subscriber.subscriberId"
166
+ " subscriber.ssub, subscriber.subscriberId,"
167
+ " user.mtime AS sorttime"
167168
" FROM user LEFT JOIN lastAccess ON login=uname"
168169
" LEFT JOIN subscriber ON login=suname"
169170
" WHERE login NOT IN ('anonymous','nobody','developer','reader') %s"
170
- " ORDER BY sortkey", zWith/*safe-for-%s*/
171
+ " ORDER BY sorttime DESC", zWith/*safe-for-%s*/
171172
);
172173
rNow = db_double(0.0, "SELECT julianday('now');");
173174
while( db_step(&s)==SQLITE_ROW ){
174175
int uid = db_column_int(&s, 0);
175176
const char *zLogin = db_column_text(&s, 1);
@@ -180,10 +181,11 @@
180181
const char *zExp = db_column_text(&s,6);
181182
double rATime = db_column_double(&s,7);
182183
char *zAge = 0;
183184
const char *zSub;
184185
int sid = db_column_int(&s,9);
186
+ sqlite3_int64 sorttime = db_column_int64(&s, 10);
185187
if( rATime>0.0 ){
186188
zAge = human_readable_age(rNow - rATime);
187189
}
188190
if( bUbg ){
189191
@ <tr style='background-color: %h(user_color(zLogin));'>
@@ -192,11 +194,11 @@
192194
}
193195
@ <td data-sortkey='%h(zSortKey)'>\
194196
@ <a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a>
195197
@ <td>%h(zCap)
196198
@ <td>%h(zInfo)
197
- @ <td>%h(zDate?zDate:"")
199
+ @ <td data-sortkey='%09llx(sorttime)'>%h(zDate?zDate:"")
198200
@ <td>%h(zExp?zExp:"")
199201
@ <td data-sortkey='%f(rATime)' style='white-space:nowrap'>%s(zAge?zAge:"")
200202
if( db_column_type(&s,8)==SQLITE_NULL ){
201203
@ <td>
202204
}else if( (zSub = db_column_text(&s,8))==0 || zSub[0]==0 ){
@@ -1016,11 +1018,11 @@
10161018
style_header("User %h", db_column_text(&q,1));
10171019
@ <table class="label-value">
10181020
@ <tr><th>uid:</th><td>%d(db_column_int(&q,0))
10191021
@ (<a href="%R/setup_uedit?id=%d(db_column_int(&q,0))">edit</a>)</td></tr>
10201022
@ <tr><th>login:</th><td>%h(db_column_text(&q,1))</td></tr>
1021
- @ <tr><th>capabilities:</th><td>%h(db_column_text(&q,2))</th></tr>
1023
+ @ <tr><th>capabilities:</th><td>%h(db_column_text(&q,2))</td></tr>
10221024
@ <tr><th valign="top">info:</th>
10231025
@ <td valign="top"><span style='white-space:pre-line;'>\
10241026
@ %h(db_column_text(&q,5))</span></td></tr>
10251027
@ <tr><th>user.mtime:</th><td>%h(db_column_text(&q,6))</td></tr>
10261028
if( db_column_type(&q,7)!=SQLITE_NULL ){
10271029
--- src/setupuser.c
+++ src/setupuser.c
@@ -115,11 +115,11 @@
115 }
116 if( !bUnusedOnly ){
117 style_submenu_element("Unused", "setup_ulist?unused");
118 }
119 @ <table border=1 cellpadding=2 cellspacing=0 class='userTable sortable' \
120 @ data-column-types='ktxTTKt' data-init-sort='2'>
121 @ <thead><tr>
122 @ <th>Login Name<th>Caps<th>Info<th>Date<th>Expire<th>Last Login\
123 @ <th>Alerts</tr></thead>
124 @ <tbody>
125 db_multi_exec(
@@ -161,15 +161,16 @@
161 " lower(login) AS sortkey, "
162 " CASE WHEN info LIKE '%%expires 20%%'"
163 " THEN substr(info,instr(lower(info),'expires')+8,10)"
164 " END AS exp,"
165 "atime,"
166 " subscriber.ssub, subscriber.subscriberId"
 
167 " FROM user LEFT JOIN lastAccess ON login=uname"
168 " LEFT JOIN subscriber ON login=suname"
169 " WHERE login NOT IN ('anonymous','nobody','developer','reader') %s"
170 " ORDER BY sortkey", zWith/*safe-for-%s*/
171 );
172 rNow = db_double(0.0, "SELECT julianday('now');");
173 while( db_step(&s)==SQLITE_ROW ){
174 int uid = db_column_int(&s, 0);
175 const char *zLogin = db_column_text(&s, 1);
@@ -180,10 +181,11 @@
180 const char *zExp = db_column_text(&s,6);
181 double rATime = db_column_double(&s,7);
182 char *zAge = 0;
183 const char *zSub;
184 int sid = db_column_int(&s,9);
 
185 if( rATime>0.0 ){
186 zAge = human_readable_age(rNow - rATime);
187 }
188 if( bUbg ){
189 @ <tr style='background-color: %h(user_color(zLogin));'>
@@ -192,11 +194,11 @@
192 }
193 @ <td data-sortkey='%h(zSortKey)'>\
194 @ <a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a>
195 @ <td>%h(zCap)
196 @ <td>%h(zInfo)
197 @ <td>%h(zDate?zDate:"")
198 @ <td>%h(zExp?zExp:"")
199 @ <td data-sortkey='%f(rATime)' style='white-space:nowrap'>%s(zAge?zAge:"")
200 if( db_column_type(&s,8)==SQLITE_NULL ){
201 @ <td>
202 }else if( (zSub = db_column_text(&s,8))==0 || zSub[0]==0 ){
@@ -1016,11 +1018,11 @@
1016 style_header("User %h", db_column_text(&q,1));
1017 @ <table class="label-value">
1018 @ <tr><th>uid:</th><td>%d(db_column_int(&q,0))
1019 @ (<a href="%R/setup_uedit?id=%d(db_column_int(&q,0))">edit</a>)</td></tr>
1020 @ <tr><th>login:</th><td>%h(db_column_text(&q,1))</td></tr>
1021 @ <tr><th>capabilities:</th><td>%h(db_column_text(&q,2))</th></tr>
1022 @ <tr><th valign="top">info:</th>
1023 @ <td valign="top"><span style='white-space:pre-line;'>\
1024 @ %h(db_column_text(&q,5))</span></td></tr>
1025 @ <tr><th>user.mtime:</th><td>%h(db_column_text(&q,6))</td></tr>
1026 if( db_column_type(&q,7)!=SQLITE_NULL ){
1027
--- src/setupuser.c
+++ src/setupuser.c
@@ -115,11 +115,11 @@
115 }
116 if( !bUnusedOnly ){
117 style_submenu_element("Unused", "setup_ulist?unused");
118 }
119 @ <table border=1 cellpadding=2 cellspacing=0 class='userTable sortable' \
120 @ data-column-types='ktxKTKt' data-init-sort='4'>
121 @ <thead><tr>
122 @ <th>Login Name<th>Caps<th>Info<th>Date<th>Expire<th>Last Login\
123 @ <th>Alerts</tr></thead>
124 @ <tbody>
125 db_multi_exec(
@@ -161,15 +161,16 @@
161 " lower(login) AS sortkey, "
162 " CASE WHEN info LIKE '%%expires 20%%'"
163 " THEN substr(info,instr(lower(info),'expires')+8,10)"
164 " END AS exp,"
165 "atime,"
166 " subscriber.ssub, subscriber.subscriberId,"
167 " user.mtime AS sorttime"
168 " FROM user LEFT JOIN lastAccess ON login=uname"
169 " LEFT JOIN subscriber ON login=suname"
170 " WHERE login NOT IN ('anonymous','nobody','developer','reader') %s"
171 " ORDER BY sorttime DESC", zWith/*safe-for-%s*/
172 );
173 rNow = db_double(0.0, "SELECT julianday('now');");
174 while( db_step(&s)==SQLITE_ROW ){
175 int uid = db_column_int(&s, 0);
176 const char *zLogin = db_column_text(&s, 1);
@@ -180,10 +181,11 @@
181 const char *zExp = db_column_text(&s,6);
182 double rATime = db_column_double(&s,7);
183 char *zAge = 0;
184 const char *zSub;
185 int sid = db_column_int(&s,9);
186 sqlite3_int64 sorttime = db_column_int64(&s, 10);
187 if( rATime>0.0 ){
188 zAge = human_readable_age(rNow - rATime);
189 }
190 if( bUbg ){
191 @ <tr style='background-color: %h(user_color(zLogin));'>
@@ -192,11 +194,11 @@
194 }
195 @ <td data-sortkey='%h(zSortKey)'>\
196 @ <a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a>
197 @ <td>%h(zCap)
198 @ <td>%h(zInfo)
199 @ <td data-sortkey='%09llx(sorttime)'>%h(zDate?zDate:"")
200 @ <td>%h(zExp?zExp:"")
201 @ <td data-sortkey='%f(rATime)' style='white-space:nowrap'>%s(zAge?zAge:"")
202 if( db_column_type(&s,8)==SQLITE_NULL ){
203 @ <td>
204 }else if( (zSub = db_column_text(&s,8))==0 || zSub[0]==0 ){
@@ -1016,11 +1018,11 @@
1018 style_header("User %h", db_column_text(&q,1));
1019 @ <table class="label-value">
1020 @ <tr><th>uid:</th><td>%d(db_column_int(&q,0))
1021 @ (<a href="%R/setup_uedit?id=%d(db_column_int(&q,0))">edit</a>)</td></tr>
1022 @ <tr><th>login:</th><td>%h(db_column_text(&q,1))</td></tr>
1023 @ <tr><th>capabilities:</th><td>%h(db_column_text(&q,2))</td></tr>
1024 @ <tr><th valign="top">info:</th>
1025 @ <td valign="top"><span style='white-space:pre-line;'>\
1026 @ %h(db_column_text(&q,5))</span></td></tr>
1027 @ <tr><th>user.mtime:</th><td>%h(db_column_text(&q,6))</td></tr>
1028 if( db_column_type(&q,7)!=SQLITE_NULL ){
1029
+5 -40
--- src/sitemap.c
+++ src/sitemap.c
@@ -56,22 +56,10 @@
5656
int i;
5757
int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
5858
int e = atoi(PD("e","0"));
5959
const char *zExtra;
6060
61
-#if 0 /* Removed 2021-01-26 */
62
- const struct {
63
- const char *zTitle;
64
- const char *zProperty;
65
- } aExtra[] = {
66
- { "Documentation", "sitemap-docidx" },
67
- { "Download", "sitemap-download" },
68
- { "License", "sitemap-license" },
69
- { "Contact", "sitemap-contact" },
70
- };
71
-#endif
72
-
7361
login_check_credentials();
7462
if( P("popup")!=0 ){
7563
/* The "popup" query parameter
7664
** then disable anti-robot defenses */
7765
isPopup = 1;
@@ -87,26 +75,10 @@
8775
@ <ul id="sitemap" class="columns" style="column-width:20em">
8876
if( (e&1)==0 ){
8977
@ <li>%z(href("%R/home"))Home Page</a>
9078
}
9179
92
-#if 0 /* Removed 2021-01-26 */
93
- for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){
94
- char *z = db_get(aExtra[i].zProperty,0);
95
- if( z==0 || z[0]==0 ) continue;
96
- if( !inSublist ){
97
- @ <ul>
98
- inSublist = 1;
99
- }
100
- if( z[0]=='/' ){
101
- @ <li>%z(href("%R%s",z))%s(aExtra[i].zTitle)</a></li>
102
- }else{
103
- @ <li>%z(href("%s",z))%s(aExtra[i].zTitle)</a></li>
104
- }
105
- }
106
-#endif
107
-
10880
zExtra = db_get("sitemap-extra",0);
10981
if( zExtra && (e&2)==0 ){
11082
int rc;
11183
char **azExtra = 0;
11284
int *anExtra;
@@ -139,26 +111,18 @@
139111
}
140112
Th_Free(g.interp, azExtra);
141113
}
142114
if( (e&1)!=0 ) goto end_of_sitemap;
143115
144
-#if 0 /* Removed on 2021-02-11. Make a sitemap-extra entry if you */
145
- /* really want this */
146
- if( srchFlags & SRCH_DOC ){
147
- if( !inSublist ){
148
- @ <ul>
149
- inSublist = 1;
150
- }
151
- @ <li>%z(href("%R/docsrch"))Documentation Search</a></li>
152
- }
153
-#endif
154
-
155116
if( inSublist ){
156117
@ </ul>
157118
inSublist = 0;
158119
}
159120
@ </li>
121
+ if( db_open_local(0) && cgi_is_loopback(g.zIpAddr) ){
122
+ @ <li>%z(href("%R/ckout"))Checkout Status</a></li>
123
+ }
160124
if( g.perm.Read ){
161125
const char *zEditGlob = db_get("fileedit-glob","");
162126
@ <li>%z(href("%R/tree"))File Browser</a>
163127
@ <ul>
164128
@ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
@@ -192,11 +156,12 @@
192156
}
193157
if( g.perm.Chat ){
194158
@ <li>%z(href("%R/chat"))Chat</a></li>
195159
}
196160
if( g.perm.RdForum ){
197
- @ <li>%z(href("%R/forum"))Forum</a>
161
+ const char *zTitle = db_get("forum-title","Forum");
162
+ @ <li>%z(href("%R/forum"))%h(zTitle)</a>
198163
@ <ul>
199164
@ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li>
200165
@ </ul>
201166
@ </li>
202167
}
203168
--- src/sitemap.c
+++ src/sitemap.c
@@ -56,22 +56,10 @@
56 int i;
57 int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
58 int e = atoi(PD("e","0"));
59 const char *zExtra;
60
61 #if 0 /* Removed 2021-01-26 */
62 const struct {
63 const char *zTitle;
64 const char *zProperty;
65 } aExtra[] = {
66 { "Documentation", "sitemap-docidx" },
67 { "Download", "sitemap-download" },
68 { "License", "sitemap-license" },
69 { "Contact", "sitemap-contact" },
70 };
71 #endif
72
73 login_check_credentials();
74 if( P("popup")!=0 ){
75 /* The "popup" query parameter
76 ** then disable anti-robot defenses */
77 isPopup = 1;
@@ -87,26 +75,10 @@
87 @ <ul id="sitemap" class="columns" style="column-width:20em">
88 if( (e&1)==0 ){
89 @ <li>%z(href("%R/home"))Home Page</a>
90 }
91
92 #if 0 /* Removed 2021-01-26 */
93 for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){
94 char *z = db_get(aExtra[i].zProperty,0);
95 if( z==0 || z[0]==0 ) continue;
96 if( !inSublist ){
97 @ <ul>
98 inSublist = 1;
99 }
100 if( z[0]=='/' ){
101 @ <li>%z(href("%R%s",z))%s(aExtra[i].zTitle)</a></li>
102 }else{
103 @ <li>%z(href("%s",z))%s(aExtra[i].zTitle)</a></li>
104 }
105 }
106 #endif
107
108 zExtra = db_get("sitemap-extra",0);
109 if( zExtra && (e&2)==0 ){
110 int rc;
111 char **azExtra = 0;
112 int *anExtra;
@@ -139,26 +111,18 @@
139 }
140 Th_Free(g.interp, azExtra);
141 }
142 if( (e&1)!=0 ) goto end_of_sitemap;
143
144 #if 0 /* Removed on 2021-02-11. Make a sitemap-extra entry if you */
145 /* really want this */
146 if( srchFlags & SRCH_DOC ){
147 if( !inSublist ){
148 @ <ul>
149 inSublist = 1;
150 }
151 @ <li>%z(href("%R/docsrch"))Documentation Search</a></li>
152 }
153 #endif
154
155 if( inSublist ){
156 @ </ul>
157 inSublist = 0;
158 }
159 @ </li>
 
 
 
160 if( g.perm.Read ){
161 const char *zEditGlob = db_get("fileedit-glob","");
162 @ <li>%z(href("%R/tree"))File Browser</a>
163 @ <ul>
164 @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
@@ -192,11 +156,12 @@
192 }
193 if( g.perm.Chat ){
194 @ <li>%z(href("%R/chat"))Chat</a></li>
195 }
196 if( g.perm.RdForum ){
197 @ <li>%z(href("%R/forum"))Forum</a>
 
198 @ <ul>
199 @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li>
200 @ </ul>
201 @ </li>
202 }
203
--- src/sitemap.c
+++ src/sitemap.c
@@ -56,22 +56,10 @@
56 int i;
57 int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
58 int e = atoi(PD("e","0"));
59 const char *zExtra;
60
 
 
 
 
 
 
 
 
 
 
 
 
61 login_check_credentials();
62 if( P("popup")!=0 ){
63 /* The "popup" query parameter
64 ** then disable anti-robot defenses */
65 isPopup = 1;
@@ -87,26 +75,10 @@
75 @ <ul id="sitemap" class="columns" style="column-width:20em">
76 if( (e&1)==0 ){
77 @ <li>%z(href("%R/home"))Home Page</a>
78 }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80 zExtra = db_get("sitemap-extra",0);
81 if( zExtra && (e&2)==0 ){
82 int rc;
83 char **azExtra = 0;
84 int *anExtra;
@@ -139,26 +111,18 @@
111 }
112 Th_Free(g.interp, azExtra);
113 }
114 if( (e&1)!=0 ) goto end_of_sitemap;
115
 
 
 
 
 
 
 
 
 
 
 
116 if( inSublist ){
117 @ </ul>
118 inSublist = 0;
119 }
120 @ </li>
121 if( db_open_local(0) && cgi_is_loopback(g.zIpAddr) ){
122 @ <li>%z(href("%R/ckout"))Checkout Status</a></li>
123 }
124 if( g.perm.Read ){
125 const char *zEditGlob = db_get("fileedit-glob","");
126 @ <li>%z(href("%R/tree"))File Browser</a>
127 @ <ul>
128 @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
@@ -192,11 +156,12 @@
156 }
157 if( g.perm.Chat ){
158 @ <li>%z(href("%R/chat"))Chat</a></li>
159 }
160 if( g.perm.RdForum ){
161 const char *zTitle = db_get("forum-title","Forum");
162 @ <li>%z(href("%R/forum"))%h(zTitle)</a>
163 @ <ul>
164 @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li>
165 @ </ul>
166 @ </li>
167 }
168
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -731,10 +731,19 @@
731731
Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDIN));
732732
Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDOUT));
733733
Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDERR));
734734
}
735735
Tcl_Preserve((ClientData)tclInterp);
736
+#if ((TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>6) \
737
+ || (TCL_MAJOR_VERSION>8))
738
+ /* TCL 8.7+ removes Tcl_MakeSafe():
739
+ ** https://core.tcl-lang.org/tcl/tktview?name=655300
740
+ ** https://core.tcl-lang.org/tips/doc/trunk/tip/624.md
741
+ ** 8.7 has it in the headers but not in the libs.
742
+ */
743
+# define Tcl_MakeSafe(X) TCL_OK
744
+#endif
736745
if( Tcl_MakeSafe(tclInterp)!=TCL_OK ){
737746
int nResult;
738747
const char *zResult = getTclResult(tclInterp, &nResult);
739748
Th_ErrorMessage(interp,
740749
"could not make Tcl interpreter 'safe':", zResult, nResult);
741750
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -731,10 +731,19 @@
731 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDIN));
732 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDOUT));
733 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDERR));
734 }
735 Tcl_Preserve((ClientData)tclInterp);
 
 
 
 
 
 
 
 
 
736 if( Tcl_MakeSafe(tclInterp)!=TCL_OK ){
737 int nResult;
738 const char *zResult = getTclResult(tclInterp, &nResult);
739 Th_ErrorMessage(interp,
740 "could not make Tcl interpreter 'safe':", zResult, nResult);
741
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -731,10 +731,19 @@
731 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDIN));
732 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDOUT));
733 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDERR));
734 }
735 Tcl_Preserve((ClientData)tclInterp);
736 #if ((TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>6) \
737 || (TCL_MAJOR_VERSION>8))
738 /* TCL 8.7+ removes Tcl_MakeSafe():
739 ** https://core.tcl-lang.org/tcl/tktview?name=655300
740 ** https://core.tcl-lang.org/tips/doc/trunk/tip/624.md
741 ** 8.7 has it in the headers but not in the libs.
742 */
743 # define Tcl_MakeSafe(X) TCL_OK
744 #endif
745 if( Tcl_MakeSafe(tclInterp)!=TCL_OK ){
746 int nResult;
747 const char *zResult = getTclResult(tclInterp, &nResult);
748 Th_ErrorMessage(interp,
749 "could not make Tcl interpreter 'safe':", zResult, nResult);
750
+2 -1
--- src/timeline.c
+++ src/timeline.c
@@ -1885,10 +1885,11 @@
18851885
char *zPlural; /* Ending for plural forms */
18861886
int showCherrypicks = 1; /* True to show cherrypick merges */
18871887
int haveParameterN; /* True if n= query parameter present */
18881888
int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
18891889
1890
+ login_check_credentials();
18901891
url_initialize(&url, "timeline");
18911892
cgi_query_parameters_to_url(&url);
18921893
18931894
(void)P_NoBot("ss")
18941895
/* "ss" is processed via the udc but at least one spider likes to
@@ -1965,11 +1966,10 @@
19651966
*/
19661967
pd_rid = name_choice("dp","dp2",&zDPName);
19671968
if( pd_rid ){
19681969
p_rid = d_rid = pd_rid;
19691970
}
1970
- login_check_credentials();
19711971
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
19721972
|| (bisectLocal && !g.perm.Setup)
19731973
){
19741974
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
19751975
return;
@@ -2012,10 +2012,11 @@
20122012
zTagName = z;
20132013
zMatchStyle = "brlist";
20142014
}
20152015
if( (z = P("rl"))!=0 ){
20162016
zBrName = z;
2017
+ related = 1;
20172018
zMatchStyle = "brlist";
20182019
}
20192020
}
20202021
20212022
/* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
20222023
--- src/timeline.c
+++ src/timeline.c
@@ -1885,10 +1885,11 @@
1885 char *zPlural; /* Ending for plural forms */
1886 int showCherrypicks = 1; /* True to show cherrypick merges */
1887 int haveParameterN; /* True if n= query parameter present */
1888 int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
1889
 
1890 url_initialize(&url, "timeline");
1891 cgi_query_parameters_to_url(&url);
1892
1893 (void)P_NoBot("ss")
1894 /* "ss" is processed via the udc but at least one spider likes to
@@ -1965,11 +1966,10 @@
1965 */
1966 pd_rid = name_choice("dp","dp2",&zDPName);
1967 if( pd_rid ){
1968 p_rid = d_rid = pd_rid;
1969 }
1970 login_check_credentials();
1971 if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
1972 || (bisectLocal && !g.perm.Setup)
1973 ){
1974 login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
1975 return;
@@ -2012,10 +2012,11 @@
2012 zTagName = z;
2013 zMatchStyle = "brlist";
2014 }
2015 if( (z = P("rl"))!=0 ){
2016 zBrName = z;
 
2017 zMatchStyle = "brlist";
2018 }
2019 }
2020
2021 /* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
2022
--- src/timeline.c
+++ src/timeline.c
@@ -1885,10 +1885,11 @@
1885 char *zPlural; /* Ending for plural forms */
1886 int showCherrypicks = 1; /* True to show cherrypick merges */
1887 int haveParameterN; /* True if n= query parameter present */
1888 int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
1889
1890 login_check_credentials();
1891 url_initialize(&url, "timeline");
1892 cgi_query_parameters_to_url(&url);
1893
1894 (void)P_NoBot("ss")
1895 /* "ss" is processed via the udc but at least one spider likes to
@@ -1965,11 +1966,10 @@
1966 */
1967 pd_rid = name_choice("dp","dp2",&zDPName);
1968 if( pd_rid ){
1969 p_rid = d_rid = pd_rid;
1970 }
 
1971 if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
1972 || (bisectLocal && !g.perm.Setup)
1973 ){
1974 login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
1975 return;
@@ -2012,10 +2012,11 @@
2012 zTagName = z;
2013 zMatchStyle = "brlist";
2014 }
2015 if( (z = P("rl"))!=0 ){
2016 zBrName = z;
2017 related = 1;
2018 zMatchStyle = "brlist";
2019 }
2020 }
2021
2022 /* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
2023
+2 -1
--- src/timeline.c
+++ src/timeline.c
@@ -1885,10 +1885,11 @@
18851885
char *zPlural; /* Ending for plural forms */
18861886
int showCherrypicks = 1; /* True to show cherrypick merges */
18871887
int haveParameterN; /* True if n= query parameter present */
18881888
int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
18891889
1890
+ login_check_credentials();
18901891
url_initialize(&url, "timeline");
18911892
cgi_query_parameters_to_url(&url);
18921893
18931894
(void)P_NoBot("ss")
18941895
/* "ss" is processed via the udc but at least one spider likes to
@@ -1965,11 +1966,10 @@
19651966
*/
19661967
pd_rid = name_choice("dp","dp2",&zDPName);
19671968
if( pd_rid ){
19681969
p_rid = d_rid = pd_rid;
19691970
}
1970
- login_check_credentials();
19711971
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
19721972
|| (bisectLocal && !g.perm.Setup)
19731973
){
19741974
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
19751975
return;
@@ -2012,10 +2012,11 @@
20122012
zTagName = z;
20132013
zMatchStyle = "brlist";
20142014
}
20152015
if( (z = P("rl"))!=0 ){
20162016
zBrName = z;
2017
+ related = 1;
20172018
zMatchStyle = "brlist";
20182019
}
20192020
}
20202021
20212022
/* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
20222023
--- src/timeline.c
+++ src/timeline.c
@@ -1885,10 +1885,11 @@
1885 char *zPlural; /* Ending for plural forms */
1886 int showCherrypicks = 1; /* True to show cherrypick merges */
1887 int haveParameterN; /* True if n= query parameter present */
1888 int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
1889
 
1890 url_initialize(&url, "timeline");
1891 cgi_query_parameters_to_url(&url);
1892
1893 (void)P_NoBot("ss")
1894 /* "ss" is processed via the udc but at least one spider likes to
@@ -1965,11 +1966,10 @@
1965 */
1966 pd_rid = name_choice("dp","dp2",&zDPName);
1967 if( pd_rid ){
1968 p_rid = d_rid = pd_rid;
1969 }
1970 login_check_credentials();
1971 if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
1972 || (bisectLocal && !g.perm.Setup)
1973 ){
1974 login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
1975 return;
@@ -2012,10 +2012,11 @@
2012 zTagName = z;
2013 zMatchStyle = "brlist";
2014 }
2015 if( (z = P("rl"))!=0 ){
2016 zBrName = z;
 
2017 zMatchStyle = "brlist";
2018 }
2019 }
2020
2021 /* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
2022
--- src/timeline.c
+++ src/timeline.c
@@ -1885,10 +1885,11 @@
1885 char *zPlural; /* Ending for plural forms */
1886 int showCherrypicks = 1; /* True to show cherrypick merges */
1887 int haveParameterN; /* True if n= query parameter present */
1888 int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
1889
1890 login_check_credentials();
1891 url_initialize(&url, "timeline");
1892 cgi_query_parameters_to_url(&url);
1893
1894 (void)P_NoBot("ss")
1895 /* "ss" is processed via the udc but at least one spider likes to
@@ -1965,11 +1966,10 @@
1966 */
1967 pd_rid = name_choice("dp","dp2",&zDPName);
1968 if( pd_rid ){
1969 p_rid = d_rid = pd_rid;
1970 }
 
1971 if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
1972 || (bisectLocal && !g.perm.Setup)
1973 ){
1974 login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
1975 return;
@@ -2012,10 +2012,11 @@
2012 zTagName = z;
2013 zMatchStyle = "brlist";
2014 }
2015 if( (z = P("rl"))!=0 ){
2016 zBrName = z;
2017 related = 1;
2018 zMatchStyle = "brlist";
2019 }
2020 }
2021
2022 /* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
2023
+1 -1
--- src/tkt.c
+++ src/tkt.c
@@ -781,11 +781,11 @@
781781
782782
zFullName = db_text(0,
783783
"SELECT tkt_uuid FROM ticket"
784784
" WHERE tkt_uuid GLOB '%q*'", zUuid);
785785
if( zFullName ){
786
- attachment_list(zFullName, "<hr><h2>Attachments:</h2><ul>");
786
+ attachment_list(zFullName, "<h2>Attachments:</h2>", 1);
787787
}
788788
789789
style_finish_page();
790790
}
791791
792792
--- src/tkt.c
+++ src/tkt.c
@@ -781,11 +781,11 @@
781
782 zFullName = db_text(0,
783 "SELECT tkt_uuid FROM ticket"
784 " WHERE tkt_uuid GLOB '%q*'", zUuid);
785 if( zFullName ){
786 attachment_list(zFullName, "<hr><h2>Attachments:</h2><ul>");
787 }
788
789 style_finish_page();
790 }
791
792
--- src/tkt.c
+++ src/tkt.c
@@ -781,11 +781,11 @@
781
782 zFullName = db_text(0,
783 "SELECT tkt_uuid FROM ticket"
784 " WHERE tkt_uuid GLOB '%q*'", zUuid);
785 if( zFullName ){
786 attachment_list(zFullName, "<h2>Attachments:</h2>", 1);
787 }
788
789 style_finish_page();
790 }
791
792
+55 -3
--- src/update.c
+++ src/update.c
@@ -132,10 +132,13 @@
132132
int nUpdate = 0; /* Number of changes of any kind */
133133
int bNosync = 0; /* --nosync. Omit the auto-sync */
134134
int width; /* Width of printed comment lines */
135135
Stmt mtimeXfer; /* Statement to transfer mtimes */
136136
const char *zWidth; /* Width option string value */
137
+ const char *zCurBrName; /* Current branch name */
138
+ const char *zNewBrName; /* New branch name */
139
+ const char *zBrChgMsg = ""; /* Message to display if branch changes */
137140
138141
if( !internalUpdate ){
139142
undo_capture_command_line();
140143
url_proxy_options();
141144
}
@@ -163,10 +166,11 @@
163166
/* We should be done with options.. */
164167
verify_all_options();
165168
166169
db_must_be_within_tree();
167170
vid = db_lget_int("checkout", 0);
171
+ zCurBrName = branch_of_rid(vid);
168172
user_select();
169173
if( !dryRunFlag && !internalUpdate && !bNosync ){
170174
if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "update") ){
171175
fossil_fatal("update abandoned due to sync failure");
172176
}
@@ -403,10 +407,11 @@
403407
" WHERE id=:idt"
404408
);
405409
assert( g.zLocalRoot!=0 );
406410
assert( strlen(g.zLocalRoot)>0 );
407411
assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' );
412
+ merge_info_init();
408413
while( db_step(&q)==SQLITE_ROW ){
409414
const char *zName = db_column_text(&q, 0); /* The filename from root */
410415
int idv = db_column_int(&q, 1); /* VFILE entry for current */
411416
int ridv = db_column_int(&q, 2); /* RecordID for current */
412417
int idt = db_column_int(&q, 3); /* VFILE entry for target */
@@ -418,13 +423,18 @@
418423
int islinkt = db_column_int(&q, 9); /* Is target file is a link */
419424
int deleted = db_column_int(&q, 10); /* Marked for deletion */
420425
char *zFullPath; /* Full pathname of the file */
421426
char *zFullNewPath; /* Full pathname of dest */
422427
char nameChng; /* True if the name changed */
428
+ const char *zOp = 0; /* Type of change. */
429
+ i64 sz = 0; /* Size of the file */
430
+ int nc = 0; /* Number of conflicts */
431
+ const char *zErrMsg = 0; /* Error message */
423432
424433
zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
425434
zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
435
+ sz = file_size(zFullNewPath, ExtFILE);
426436
nameChng = fossil_strcmp(zName, zNewName);
427437
nUpdate++;
428438
if( deleted ){
429439
db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt);
430440
}
@@ -432,10 +442,13 @@
432442
/* Conflict. This file has been added to the current check-out
433443
** but also exists in the target check-out. Use the current version.
434444
*/
435445
fossil_print("CONFLICT %s\n", zName);
436446
nConflict++;
447
+ zOp = "CONFLICT";
448
+ nc = 1;
449
+ zErrMsg = "duplicate file";
437450
}else if( idt>0 && idv==0 ){
438451
/* File added in the target. */
439452
if( file_isfile_or_link(zFullPath) ){
440453
/* Name of backup file with Original content */
441454
char *zOrig = file_newname(zFullPath, "original", 1);
@@ -444,10 +457,13 @@
444457
fossil_free(zOrig);
445458
fossil_print("ADD %s - overwrites an unmanaged file", zName);
446459
if( !dryRunFlag ) fossil_print(", original copy backed up locally");
447460
fossil_print("\n");
448461
nOverwrite++;
462
+ nc = 1;
463
+ zOp = "CONFLICT";
464
+ zErrMsg = "new file overwrites unmanaged file";
449465
}else{
450466
fossil_print("ADD %s\n", zName);
451467
}
452468
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
453469
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
@@ -458,16 +474,18 @@
458474
}else{
459475
fossil_print("UPDATE %s\n", zName);
460476
}
461477
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
462478
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
479
+ zOp = "UPDATE";
463480
}else if( idt>0 && idv>0 && !deleted && file_size(zFullPath, RepoFILE)<0 ){
464481
/* The file missing from the local check-out. Restore it to the
465482
** version that appears in the target. */
466483
fossil_print("UPDATE %s\n", zName);
467484
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
468485
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
486
+ zOp = "UPDATE";
469487
}else if( idt==0 && idv>0 ){
470488
if( ridv==0 ){
471489
/* Added in current check-out. Continue to hold the file as
472490
** as an addition */
473491
db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
@@ -474,10 +492,13 @@
474492
}else if( chnged ){
475493
/* Edited locally but deleted from the target. Do not track the
476494
** file but keep the edited version around. */
477495
fossil_print("CONFLICT %s - edited locally but deleted by update\n",
478496
zName);
497
+ zOp = "CONFLICT";
498
+ zErrMsg = "edited locally but deleted by update";
499
+ nc = 1;
479500
nConflict++;
480501
}else{
481502
fossil_print("REMOVE %s\n", zName);
482503
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
483504
if( !dryRunFlag ){
@@ -496,17 +517,19 @@
496517
}
497518
}else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
498519
/* Merge the changes in the current tree into the target version */
499520
Blob r, t, v;
500521
int rc;
522
+
501523
if( nameChng ){
502524
fossil_print("MERGE %s -> %s\n", zName, zNewName);
503525
}else{
504526
fossil_print("MERGE %s\n", zName);
505527
}
506528
if( islinkv || islinkt ){
507529
fossil_print("***** Cannot merge symlink %s\n", zNewName);
530
+ zOp = "CONFLICT";
508531
nConflict++;
509532
}else{
510533
unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
511534
if(keepMergeFlag!=0) mergeFlags |= MERGE_KEEP_FILES;
512535
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
@@ -517,12 +540,17 @@
517540
if( !dryRunFlag ){
518541
blob_write_to_file(&r, zFullNewPath);
519542
file_setexe(zFullNewPath, isexe);
520543
}
521544
if( rc>0 ){
545
+ nc = rc;
546
+ zOp = "CONFLICT";
547
+ zErrMsg = "merge conflicts";
522548
fossil_print("***** %d merge conflicts in %s\n", rc, zNewName);
523549
nConflict++;
550
+ }else{
551
+ zOp = "MERGE";
524552
}
525553
}else{
526554
if( !dryRunFlag ){
527555
if( !keepMergeFlag ){
528556
/* Name of backup file with Original content */
@@ -539,10 +567,13 @@
539567
if( !dryRunFlag ){
540568
fossil_print(", original copy backed up locally");
541569
}
542570
fossil_print("\n");
543571
nConflict++;
572
+ zOp = "ERROR";
573
+ zErrMsg = "cannot merge binary file";
574
+ nc = 1;
544575
}
545576
}
546577
if( nameChng && !dryRunFlag ) file_delete(zFullPath);
547578
blob_reset(&v);
548579
blob_reset(&t);
@@ -556,27 +587,48 @@
556587
db_bind_int(&mtimeXfer, ":idt", idt);
557588
db_step(&mtimeXfer);
558589
db_reset(&mtimeXfer);
559590
if( verboseFlag ) fossil_print("UNCHANGED %s\n", zName);
560591
}
592
+ }
593
+ if( zOp!=0 ){
594
+ db_multi_exec(
595
+ "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,fnr,nc,msg)"
596
+ "VALUES(%Q,%Q,%d,%Q,NULL,%lld,%Q,%d,%Q,%d,%Q)",
597
+ /* op */ zOp,
598
+ /* fnp */ zName,
599
+ /* ridp */ ridv,
600
+ /* fn */ zNewName,
601
+ /* sz */ sz,
602
+ /* fnm */ zName,
603
+ /* ridm */ ridt,
604
+ /* fnr */ zNewName,
605
+ /* nc */ nc,
606
+ /* msg */ zErrMsg
607
+ );
561608
}
562609
free(zFullPath);
563610
free(zFullNewPath);
564611
}
565612
db_finalize(&q);
566613
db_finalize(&mtimeXfer);
567614
fossil_print("%.79c\n",'-');
615
+ zNewBrName = branch_of_rid(tid);
616
+ if( g.argc<3 && fossil_strcmp(zCurBrName, zNewBrName)!=0 ){
617
+ zBrChgMsg = mprintf(" Branch changed from %s to %s.",
618
+ zCurBrName, zNewBrName);
619
+ }
568620
if( nUpdate==0 ){
569621
show_common_info(tid, "checkout:", 1, 0);
570
- fossil_print("%-13s None. Already up-to-date\n", "changes:");
622
+ fossil_print("%-13s None. Already up-to-date.%s\n", "changes:", zBrChgMsg);
571623
}else{
572624
fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid),
573625
db_text("", "SELECT datetime(mtime) || ' UTC' FROM event "
574626
" WHERE objid=%d", vid));
575627
show_common_info(tid, "updated-to:", 1, 0);
576
- fossil_print("%-13s %d file%s modified.\n", "changes:",
577
- nUpdate, nUpdate>1 ? "s" : "");
628
+ fossil_print("%-13s %d file%s modified.%s\n", "changes:",
629
+ nUpdate, nUpdate>1 ? "s" : "", zBrChgMsg);
578630
}
579631
580632
/* Report on conflicts
581633
*/
582634
if( !dryRunFlag ){
583635
--- src/update.c
+++ src/update.c
@@ -132,10 +132,13 @@
132 int nUpdate = 0; /* Number of changes of any kind */
133 int bNosync = 0; /* --nosync. Omit the auto-sync */
134 int width; /* Width of printed comment lines */
135 Stmt mtimeXfer; /* Statement to transfer mtimes */
136 const char *zWidth; /* Width option string value */
 
 
 
137
138 if( !internalUpdate ){
139 undo_capture_command_line();
140 url_proxy_options();
141 }
@@ -163,10 +166,11 @@
163 /* We should be done with options.. */
164 verify_all_options();
165
166 db_must_be_within_tree();
167 vid = db_lget_int("checkout", 0);
 
168 user_select();
169 if( !dryRunFlag && !internalUpdate && !bNosync ){
170 if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "update") ){
171 fossil_fatal("update abandoned due to sync failure");
172 }
@@ -403,10 +407,11 @@
403 " WHERE id=:idt"
404 );
405 assert( g.zLocalRoot!=0 );
406 assert( strlen(g.zLocalRoot)>0 );
407 assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' );
 
408 while( db_step(&q)==SQLITE_ROW ){
409 const char *zName = db_column_text(&q, 0); /* The filename from root */
410 int idv = db_column_int(&q, 1); /* VFILE entry for current */
411 int ridv = db_column_int(&q, 2); /* RecordID for current */
412 int idt = db_column_int(&q, 3); /* VFILE entry for target */
@@ -418,13 +423,18 @@
418 int islinkt = db_column_int(&q, 9); /* Is target file is a link */
419 int deleted = db_column_int(&q, 10); /* Marked for deletion */
420 char *zFullPath; /* Full pathname of the file */
421 char *zFullNewPath; /* Full pathname of dest */
422 char nameChng; /* True if the name changed */
 
 
 
 
423
424 zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
425 zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
 
426 nameChng = fossil_strcmp(zName, zNewName);
427 nUpdate++;
428 if( deleted ){
429 db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt);
430 }
@@ -432,10 +442,13 @@
432 /* Conflict. This file has been added to the current check-out
433 ** but also exists in the target check-out. Use the current version.
434 */
435 fossil_print("CONFLICT %s\n", zName);
436 nConflict++;
 
 
 
437 }else if( idt>0 && idv==0 ){
438 /* File added in the target. */
439 if( file_isfile_or_link(zFullPath) ){
440 /* Name of backup file with Original content */
441 char *zOrig = file_newname(zFullPath, "original", 1);
@@ -444,10 +457,13 @@
444 fossil_free(zOrig);
445 fossil_print("ADD %s - overwrites an unmanaged file", zName);
446 if( !dryRunFlag ) fossil_print(", original copy backed up locally");
447 fossil_print("\n");
448 nOverwrite++;
 
 
 
449 }else{
450 fossil_print("ADD %s\n", zName);
451 }
452 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
453 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
@@ -458,16 +474,18 @@
458 }else{
459 fossil_print("UPDATE %s\n", zName);
460 }
461 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
462 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
 
463 }else if( idt>0 && idv>0 && !deleted && file_size(zFullPath, RepoFILE)<0 ){
464 /* The file missing from the local check-out. Restore it to the
465 ** version that appears in the target. */
466 fossil_print("UPDATE %s\n", zName);
467 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
468 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
 
469 }else if( idt==0 && idv>0 ){
470 if( ridv==0 ){
471 /* Added in current check-out. Continue to hold the file as
472 ** as an addition */
473 db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
@@ -474,10 +492,13 @@
474 }else if( chnged ){
475 /* Edited locally but deleted from the target. Do not track the
476 ** file but keep the edited version around. */
477 fossil_print("CONFLICT %s - edited locally but deleted by update\n",
478 zName);
 
 
 
479 nConflict++;
480 }else{
481 fossil_print("REMOVE %s\n", zName);
482 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
483 if( !dryRunFlag ){
@@ -496,17 +517,19 @@
496 }
497 }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
498 /* Merge the changes in the current tree into the target version */
499 Blob r, t, v;
500 int rc;
 
501 if( nameChng ){
502 fossil_print("MERGE %s -> %s\n", zName, zNewName);
503 }else{
504 fossil_print("MERGE %s\n", zName);
505 }
506 if( islinkv || islinkt ){
507 fossil_print("***** Cannot merge symlink %s\n", zNewName);
 
508 nConflict++;
509 }else{
510 unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
511 if(keepMergeFlag!=0) mergeFlags |= MERGE_KEEP_FILES;
512 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
@@ -517,12 +540,17 @@
517 if( !dryRunFlag ){
518 blob_write_to_file(&r, zFullNewPath);
519 file_setexe(zFullNewPath, isexe);
520 }
521 if( rc>0 ){
 
 
 
522 fossil_print("***** %d merge conflicts in %s\n", rc, zNewName);
523 nConflict++;
 
 
524 }
525 }else{
526 if( !dryRunFlag ){
527 if( !keepMergeFlag ){
528 /* Name of backup file with Original content */
@@ -539,10 +567,13 @@
539 if( !dryRunFlag ){
540 fossil_print(", original copy backed up locally");
541 }
542 fossil_print("\n");
543 nConflict++;
 
 
 
544 }
545 }
546 if( nameChng && !dryRunFlag ) file_delete(zFullPath);
547 blob_reset(&v);
548 blob_reset(&t);
@@ -556,27 +587,48 @@
556 db_bind_int(&mtimeXfer, ":idt", idt);
557 db_step(&mtimeXfer);
558 db_reset(&mtimeXfer);
559 if( verboseFlag ) fossil_print("UNCHANGED %s\n", zName);
560 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561 }
562 free(zFullPath);
563 free(zFullNewPath);
564 }
565 db_finalize(&q);
566 db_finalize(&mtimeXfer);
567 fossil_print("%.79c\n",'-');
 
 
 
 
 
568 if( nUpdate==0 ){
569 show_common_info(tid, "checkout:", 1, 0);
570 fossil_print("%-13s None. Already up-to-date\n", "changes:");
571 }else{
572 fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid),
573 db_text("", "SELECT datetime(mtime) || ' UTC' FROM event "
574 " WHERE objid=%d", vid));
575 show_common_info(tid, "updated-to:", 1, 0);
576 fossil_print("%-13s %d file%s modified.\n", "changes:",
577 nUpdate, nUpdate>1 ? "s" : "");
578 }
579
580 /* Report on conflicts
581 */
582 if( !dryRunFlag ){
583
--- src/update.c
+++ src/update.c
@@ -132,10 +132,13 @@
132 int nUpdate = 0; /* Number of changes of any kind */
133 int bNosync = 0; /* --nosync. Omit the auto-sync */
134 int width; /* Width of printed comment lines */
135 Stmt mtimeXfer; /* Statement to transfer mtimes */
136 const char *zWidth; /* Width option string value */
137 const char *zCurBrName; /* Current branch name */
138 const char *zNewBrName; /* New branch name */
139 const char *zBrChgMsg = ""; /* Message to display if branch changes */
140
141 if( !internalUpdate ){
142 undo_capture_command_line();
143 url_proxy_options();
144 }
@@ -163,10 +166,11 @@
166 /* We should be done with options.. */
167 verify_all_options();
168
169 db_must_be_within_tree();
170 vid = db_lget_int("checkout", 0);
171 zCurBrName = branch_of_rid(vid);
172 user_select();
173 if( !dryRunFlag && !internalUpdate && !bNosync ){
174 if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "update") ){
175 fossil_fatal("update abandoned due to sync failure");
176 }
@@ -403,10 +407,11 @@
407 " WHERE id=:idt"
408 );
409 assert( g.zLocalRoot!=0 );
410 assert( strlen(g.zLocalRoot)>0 );
411 assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' );
412 merge_info_init();
413 while( db_step(&q)==SQLITE_ROW ){
414 const char *zName = db_column_text(&q, 0); /* The filename from root */
415 int idv = db_column_int(&q, 1); /* VFILE entry for current */
416 int ridv = db_column_int(&q, 2); /* RecordID for current */
417 int idt = db_column_int(&q, 3); /* VFILE entry for target */
@@ -418,13 +423,18 @@
423 int islinkt = db_column_int(&q, 9); /* Is target file is a link */
424 int deleted = db_column_int(&q, 10); /* Marked for deletion */
425 char *zFullPath; /* Full pathname of the file */
426 char *zFullNewPath; /* Full pathname of dest */
427 char nameChng; /* True if the name changed */
428 const char *zOp = 0; /* Type of change. */
429 i64 sz = 0; /* Size of the file */
430 int nc = 0; /* Number of conflicts */
431 const char *zErrMsg = 0; /* Error message */
432
433 zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
434 zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
435 sz = file_size(zFullNewPath, ExtFILE);
436 nameChng = fossil_strcmp(zName, zNewName);
437 nUpdate++;
438 if( deleted ){
439 db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt);
440 }
@@ -432,10 +442,13 @@
442 /* Conflict. This file has been added to the current check-out
443 ** but also exists in the target check-out. Use the current version.
444 */
445 fossil_print("CONFLICT %s\n", zName);
446 nConflict++;
447 zOp = "CONFLICT";
448 nc = 1;
449 zErrMsg = "duplicate file";
450 }else if( idt>0 && idv==0 ){
451 /* File added in the target. */
452 if( file_isfile_or_link(zFullPath) ){
453 /* Name of backup file with Original content */
454 char *zOrig = file_newname(zFullPath, "original", 1);
@@ -444,10 +457,13 @@
457 fossil_free(zOrig);
458 fossil_print("ADD %s - overwrites an unmanaged file", zName);
459 if( !dryRunFlag ) fossil_print(", original copy backed up locally");
460 fossil_print("\n");
461 nOverwrite++;
462 nc = 1;
463 zOp = "CONFLICT";
464 zErrMsg = "new file overwrites unmanaged file";
465 }else{
466 fossil_print("ADD %s\n", zName);
467 }
468 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
469 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
@@ -458,16 +474,18 @@
474 }else{
475 fossil_print("UPDATE %s\n", zName);
476 }
477 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
478 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
479 zOp = "UPDATE";
480 }else if( idt>0 && idv>0 && !deleted && file_size(zFullPath, RepoFILE)<0 ){
481 /* The file missing from the local check-out. Restore it to the
482 ** version that appears in the target. */
483 fossil_print("UPDATE %s\n", zName);
484 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
485 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
486 zOp = "UPDATE";
487 }else if( idt==0 && idv>0 ){
488 if( ridv==0 ){
489 /* Added in current check-out. Continue to hold the file as
490 ** as an addition */
491 db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
@@ -474,10 +492,13 @@
492 }else if( chnged ){
493 /* Edited locally but deleted from the target. Do not track the
494 ** file but keep the edited version around. */
495 fossil_print("CONFLICT %s - edited locally but deleted by update\n",
496 zName);
497 zOp = "CONFLICT";
498 zErrMsg = "edited locally but deleted by update";
499 nc = 1;
500 nConflict++;
501 }else{
502 fossil_print("REMOVE %s\n", zName);
503 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
504 if( !dryRunFlag ){
@@ -496,17 +517,19 @@
517 }
518 }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
519 /* Merge the changes in the current tree into the target version */
520 Blob r, t, v;
521 int rc;
522
523 if( nameChng ){
524 fossil_print("MERGE %s -> %s\n", zName, zNewName);
525 }else{
526 fossil_print("MERGE %s\n", zName);
527 }
528 if( islinkv || islinkt ){
529 fossil_print("***** Cannot merge symlink %s\n", zNewName);
530 zOp = "CONFLICT";
531 nConflict++;
532 }else{
533 unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
534 if(keepMergeFlag!=0) mergeFlags |= MERGE_KEEP_FILES;
535 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
@@ -517,12 +540,17 @@
540 if( !dryRunFlag ){
541 blob_write_to_file(&r, zFullNewPath);
542 file_setexe(zFullNewPath, isexe);
543 }
544 if( rc>0 ){
545 nc = rc;
546 zOp = "CONFLICT";
547 zErrMsg = "merge conflicts";
548 fossil_print("***** %d merge conflicts in %s\n", rc, zNewName);
549 nConflict++;
550 }else{
551 zOp = "MERGE";
552 }
553 }else{
554 if( !dryRunFlag ){
555 if( !keepMergeFlag ){
556 /* Name of backup file with Original content */
@@ -539,10 +567,13 @@
567 if( !dryRunFlag ){
568 fossil_print(", original copy backed up locally");
569 }
570 fossil_print("\n");
571 nConflict++;
572 zOp = "ERROR";
573 zErrMsg = "cannot merge binary file";
574 nc = 1;
575 }
576 }
577 if( nameChng && !dryRunFlag ) file_delete(zFullPath);
578 blob_reset(&v);
579 blob_reset(&t);
@@ -556,27 +587,48 @@
587 db_bind_int(&mtimeXfer, ":idt", idt);
588 db_step(&mtimeXfer);
589 db_reset(&mtimeXfer);
590 if( verboseFlag ) fossil_print("UNCHANGED %s\n", zName);
591 }
592 }
593 if( zOp!=0 ){
594 db_multi_exec(
595 "INSERT INTO mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,fnr,nc,msg)"
596 "VALUES(%Q,%Q,%d,%Q,NULL,%lld,%Q,%d,%Q,%d,%Q)",
597 /* op */ zOp,
598 /* fnp */ zName,
599 /* ridp */ ridv,
600 /* fn */ zNewName,
601 /* sz */ sz,
602 /* fnm */ zName,
603 /* ridm */ ridt,
604 /* fnr */ zNewName,
605 /* nc */ nc,
606 /* msg */ zErrMsg
607 );
608 }
609 free(zFullPath);
610 free(zFullNewPath);
611 }
612 db_finalize(&q);
613 db_finalize(&mtimeXfer);
614 fossil_print("%.79c\n",'-');
615 zNewBrName = branch_of_rid(tid);
616 if( g.argc<3 && fossil_strcmp(zCurBrName, zNewBrName)!=0 ){
617 zBrChgMsg = mprintf(" Branch changed from %s to %s.",
618 zCurBrName, zNewBrName);
619 }
620 if( nUpdate==0 ){
621 show_common_info(tid, "checkout:", 1, 0);
622 fossil_print("%-13s None. Already up-to-date.%s\n", "changes:", zBrChgMsg);
623 }else{
624 fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid),
625 db_text("", "SELECT datetime(mtime) || ' UTC' FROM event "
626 " WHERE objid=%d", vid));
627 show_common_info(tid, "updated-to:", 1, 0);
628 fossil_print("%-13s %d file%s modified.%s\n", "changes:",
629 nUpdate, nUpdate>1 ? "s" : "", zBrChgMsg);
630 }
631
632 /* Report on conflicts
633 */
634 if( !dryRunFlag ){
635
+4 -4
--- src/wiki.c
+++ src/wiki.c
@@ -622,14 +622,14 @@
622622
wiki_render_by_mimetype(&wiki, zMimetype);
623623
blob_reset(&wiki);
624624
}
625625
manifest_destroy(pWiki);
626626
if( !isPopup ){
627
- char * zLabel = mprintf("<hr><h2><a href='%R/attachlist?name=%T'>"
628
- "Attachments</a>:</h2><ul>",
627
+ char * zLabel = mprintf("<h2><a href='%R/attachlist?page=%T'>"
628
+ "Attachments</a>:</h2>",
629629
zPageName);
630
- attachment_list(zPageName, zLabel);
630
+ attachment_list(zPageName, zLabel, 1);
631631
fossil_free(zLabel);
632632
document_emit_js(/*for optional pikchr support*/);
633633
style_finish_page();
634634
}
635635
}
@@ -1331,11 +1331,11 @@
13311331
CX("<div id='fossil-status-bar' "
13321332
"title='Status message area. Double-click to clear them.'>"
13331333
"Status messages will go here.</div>\n"
13341334
/* will be moved into the tab container via JS */);
13351335
1336
- CX("<div id='wikiedit-edit-status''>"
1336
+ CX("<div id='wikiedit-edit-status'>"
13371337
"<span class='name'></span>"
13381338
"<span class='links'></span>"
13391339
"</div>");
13401340
13411341
/* Main tab container... */
13421342
--- src/wiki.c
+++ src/wiki.c
@@ -622,14 +622,14 @@
622 wiki_render_by_mimetype(&wiki, zMimetype);
623 blob_reset(&wiki);
624 }
625 manifest_destroy(pWiki);
626 if( !isPopup ){
627 char * zLabel = mprintf("<hr><h2><a href='%R/attachlist?name=%T'>"
628 "Attachments</a>:</h2><ul>",
629 zPageName);
630 attachment_list(zPageName, zLabel);
631 fossil_free(zLabel);
632 document_emit_js(/*for optional pikchr support*/);
633 style_finish_page();
634 }
635 }
@@ -1331,11 +1331,11 @@
1331 CX("<div id='fossil-status-bar' "
1332 "title='Status message area. Double-click to clear them.'>"
1333 "Status messages will go here.</div>\n"
1334 /* will be moved into the tab container via JS */);
1335
1336 CX("<div id='wikiedit-edit-status''>"
1337 "<span class='name'></span>"
1338 "<span class='links'></span>"
1339 "</div>");
1340
1341 /* Main tab container... */
1342
--- src/wiki.c
+++ src/wiki.c
@@ -622,14 +622,14 @@
622 wiki_render_by_mimetype(&wiki, zMimetype);
623 blob_reset(&wiki);
624 }
625 manifest_destroy(pWiki);
626 if( !isPopup ){
627 char * zLabel = mprintf("<h2><a href='%R/attachlist?page=%T'>"
628 "Attachments</a>:</h2>",
629 zPageName);
630 attachment_list(zPageName, zLabel, 1);
631 fossil_free(zLabel);
632 document_emit_js(/*for optional pikchr support*/);
633 style_finish_page();
634 }
635 }
@@ -1331,11 +1331,11 @@
1331 CX("<div id='fossil-status-bar' "
1332 "title='Status message area. Double-click to clear them.'>"
1333 "Status messages will go here.</div>\n"
1334 /* will be moved into the tab container via JS */);
1335
1336 CX("<div id='wikiedit-edit-status'>"
1337 "<span class='name'></span>"
1338 "<span class='links'></span>"
1339 "</div>");
1340
1341 /* Main tab container... */
1342
+229
--- src/winfile.c
+++ src/winfile.c
@@ -290,6 +290,235 @@
290290
fossil_free(zWide);
291291
for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
292292
strncpy(zBuf, zUtf8, nBuf);
293293
fossil_path_free(zUtf8);
294294
}
295
+
296
+/* Perform case-insensitive comparison of two UTF-16 file names. Try to load the
297
+** CompareStringOrdinal() function on Windows Vista and newer, and resort to the
298
+** RtlEqualUnicodeString() function on Windows XP.
299
+** The dance to invoke RtlEqualUnicodeString() is necessary because lstrcmpiW()
300
+** performs linguistic comparison, while the former performs binary comparison.
301
+** As an example, matching "ß" (U+00DF Latin Small Letter Sharp S) with "ss" is
302
+** undesirable in file name comparison, so lstrcmpiW() is only invoked in cases
303
+** that are technically impossible and contradicting all known laws of physics.
304
+*/
305
+int win32_filenames_equal_nocase(
306
+ const wchar_t *fn1,
307
+ const wchar_t *fn2
308
+){
309
+ static FARPROC fnCompareStringOrdinal;
310
+ static FARPROC fnRtlInitUnicodeString;
311
+ static FARPROC fnRtlEqualUnicodeString;
312
+ static int loaded_CompareStringOrdinal;
313
+ static int loaded_RtlUnicodeStringAPIs;
314
+ if( !loaded_CompareStringOrdinal ){
315
+ fnCompareStringOrdinal =
316
+ GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal");
317
+ loaded_CompareStringOrdinal = 1;
318
+ }
319
+ if( fnCompareStringOrdinal ){
320
+ return fnCompareStringOrdinal(fn1,-1,fn2,-1,1)-2==0;
321
+ }
322
+ if( !loaded_RtlUnicodeStringAPIs ){
323
+ fnRtlInitUnicodeString =
324
+ GetProcAddress(GetModuleHandleA("ntdll"),"RtlInitUnicodeString");
325
+ fnRtlEqualUnicodeString =
326
+ GetProcAddress(GetModuleHandleA("ntdll"),"RtlEqualUnicodeString");
327
+ loaded_RtlUnicodeStringAPIs = 1;
328
+ }
329
+ if( fnRtlInitUnicodeString && fnRtlEqualUnicodeString ){
330
+ struct { /* UNICODE_STRING from <ntdef.h> */
331
+ unsigned short Length;
332
+ unsigned short MaximumLength;
333
+ wchar_t *Buffer;
334
+ } u1, u2;
335
+ fnRtlInitUnicodeString(&u1,fn1);
336
+ fnRtlInitUnicodeString(&u2,fn2);
337
+ return (unsigned char)fnRtlEqualUnicodeString(&u1,&u2,1);
338
+ }
339
+ /* In what kind of strange parallel universe are we? */
340
+ return lstrcmpiW(fn1,fn2)==0;
341
+}
342
+
343
+/* Helper macros to deal with directory separators. */
344
+#define IS_DIRSEP(s,i) ( s[i]=='/' || s[i]=='\\' )
345
+#define NEXT_DIRSEP(s,i) while( s[i] && s[i]!='/' && s[i]!='\\' ){i++;}
346
+
347
+/* The Win32 version of file_case_preferred_name() from file.c, which is able to
348
+** find case-preserved file names containing non-ASCII characters. The result is
349
+** allocated by fossil_malloc() and *should* be free'd by the caller. While this
350
+** function usually gets canonicalized paths, it is able to handle any input and
351
+** figure out more cases than the original:
352
+**
353
+** fossil test-case-filename C:/ .//..\WINDOWS\/.//.\SYSTEM32\.\NOTEPAD.EXE
354
+** → Original: .//..\WINDOWS\/.//.\SYSTEM32\.\NOTEPAD.EXE
355
+** → Modified: .//..\Windows\/.//.\System32\.\notepad.exe
356
+**
357
+** md ÄÖÜ
358
+** fossil test-case-filename ./\ .\äöü\/[empty]\\/
359
+** → Original: ./äöü\/[empty]\\/
360
+** → Modified: .\ÄÖÜ\/[empty]\\/
361
+**
362
+** The function preserves slashes and backslashes: only single file or directory
363
+** components without directory separators ("basenames") are converted to UTF-16
364
+** using fossil_utf8_to_path(), so bypassing its slash ↔ backslash translations.
365
+** Note that the original function doesn't preserve all slashes and backslashes,
366
+** for example in the second example above.
367
+**
368
+** NOTE: As of Windows 10, version 1803, case sensitivity may be enabled on a
369
+** per-directory basis, as returned by NtQueryInformationFile() with the file
370
+** information class FILE_CASE_SENSITIVE_INFORMATION. So this function may be
371
+** changed to act like fossil_strdup() for files located in such directories.
372
+*/
373
+char *win32_file_case_preferred_name(
374
+ const char *zBase,
375
+ const char *zPath
376
+){
377
+ int cchBase;
378
+ int cchPath;
379
+ int cchBuf;
380
+ int cchRes;
381
+ char *zBuf;
382
+ char *zRes;
383
+ int ncUsed;
384
+ int i, j;
385
+ if( filenames_are_case_sensitive() ){
386
+ return fossil_strdup(zPath);
387
+ }
388
+ cchBase = strlen(zBase);
389
+ cchPath = strlen(zPath);
390
+ cchBuf = cchBase + cchPath + 2; /* + NULL + optional directory slash */
391
+ cchRes = cchPath + 1; /* + NULL */
392
+ zBuf = fossil_malloc(cchBuf);
393
+ zRes = fossil_malloc(cchRes);
394
+ ncUsed = 0;
395
+ memcpy(zBuf,zBase,cchBase);
396
+ if( !IS_DIRSEP(zBuf,cchBase-1) ){
397
+ zBuf[cchBase++]=L'/';
398
+ }
399
+ memcpy(zBuf+cchBase,zPath,cchPath+1);
400
+ i = j = cchBase;
401
+ while( 1 ){
402
+ WIN32_FIND_DATAW fd;
403
+ HANDLE hFind;
404
+ wchar_t *wzBuf;
405
+ char *zCompBuf = 0;
406
+ char *zComp = &zBuf[i];
407
+ int cchComp;
408
+ char chSep;
409
+ int fDone;
410
+ if( IS_DIRSEP(zBuf,i) ){
411
+ if( ncUsed+2>cchRes ){ /* Directory slash + NULL*/
412
+ cchRes += 32; /* Overprovisioning. */
413
+ zRes = fossil_realloc(zRes,cchRes);
414
+ }
415
+ zRes[ncUsed++] = zBuf[i];
416
+ i = j = i+1;
417
+ continue;
418
+ }
419
+ NEXT_DIRSEP(zBuf,j);
420
+ fDone = zBuf[j]==0;
421
+ chSep = zBuf[j];
422
+ zBuf[j] = 0; /* Truncate working buffer. */
423
+ wzBuf = fossil_utf8_to_path(zBuf,0);
424
+ hFind = FindFirstFileW(wzBuf,&fd);
425
+ if( hFind!=INVALID_HANDLE_VALUE ){
426
+ wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
427
+ FindClose(hFind);
428
+ /* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
429
+ if( win32_filenames_equal_nocase(wzComp,fd.cFileName) ){
430
+ zCompBuf = fossil_path_to_utf8(fd.cFileName);
431
+ zComp = zCompBuf;
432
+ }
433
+ fossil_path_free(wzComp);
434
+ }
435
+ fossil_path_free(wzBuf);
436
+ cchComp = strlen(zComp);
437
+ if( ncUsed+cchComp+1>cchRes ){ /* Current component + NULL */
438
+ cchRes += cchComp + 32; /* Overprovisioning. */
439
+ zRes = fossil_realloc(zRes,cchRes);
440
+ }
441
+ memcpy(zRes+ncUsed,zComp,cchComp);
442
+ ncUsed += cchComp;
443
+ if( zCompBuf ){
444
+ fossil_path_free(zCompBuf);
445
+ }
446
+ if( fDone ){
447
+ zRes[ncUsed] = 0;
448
+ break;
449
+ }
450
+ zBuf[j] = chSep; /* Undo working buffer truncation. */
451
+ i = j;
452
+ }
453
+ fossil_free(zBuf);
454
+ return zRes;
455
+}
456
+
457
+/* Return the unique identifier (UID) for a file, made up of the file identifier
458
+** (equal to "inode" for Unix-style file systems) plus the volume serial number.
459
+** Call the GetFileInformationByHandleEx() function on Windows Vista, and resort
460
+** to the GetFileInformationByHandle() function on Windows XP. The result string
461
+** is allocated by mprintf(), or NULL on failure.
462
+*/
463
+char *win32_file_id(
464
+ const char *zFileName
465
+){
466
+ static FARPROC fnGetFileInformationByHandleEx;
467
+ static int loaded_fnGetFileInformationByHandleEx;
468
+ wchar_t *wzFileName = fossil_utf8_to_path(zFileName,0);
469
+ HANDLE hFile;
470
+ char *zFileId = 0;
471
+ hFile = CreateFileW(
472
+ wzFileName,
473
+ 0,
474
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
475
+ NULL,
476
+ OPEN_EXISTING,
477
+ FILE_FLAG_BACKUP_SEMANTICS,
478
+ NULL);
479
+ if( hFile!=INVALID_HANDLE_VALUE ){
480
+ BY_HANDLE_FILE_INFORMATION fi;
481
+ struct { /* FILE_ID_INFO from <winbase.h> */
482
+ u64 VolumeSerialNumber;
483
+ unsigned char FileId[16];
484
+ } fi2;
485
+ if( !loaded_fnGetFileInformationByHandleEx ){
486
+ fnGetFileInformationByHandleEx = GetProcAddress(
487
+ GetModuleHandleA("kernel32"),"GetFileInformationByHandleEx");
488
+ loaded_fnGetFileInformationByHandleEx = 1;
489
+ }
490
+ if( fnGetFileInformationByHandleEx ){
491
+ if( fnGetFileInformationByHandleEx(
492
+ hFile,/*FileIdInfo*/0x12,&fi2,sizeof(fi2)) ){
493
+ zFileId = mprintf(
494
+ "%016llx/"
495
+ "%02x%02x%02x%02x%02x%02x%02x%02x"
496
+ "%02x%02x%02x%02x%02x%02x%02x%02x",
497
+ fi2.VolumeSerialNumber,
498
+ fi2.FileId[15], fi2.FileId[14],
499
+ fi2.FileId[13], fi2.FileId[12],
500
+ fi2.FileId[11], fi2.FileId[10],
501
+ fi2.FileId[9], fi2.FileId[8],
502
+ fi2.FileId[7], fi2.FileId[6],
503
+ fi2.FileId[5], fi2.FileId[4],
504
+ fi2.FileId[3], fi2.FileId[2],
505
+ fi2.FileId[1], fi2.FileId[0]);
506
+ }
507
+ }
508
+ if( zFileId==0 ){
509
+ if( GetFileInformationByHandle(hFile,&fi) ){
510
+ ULARGE_INTEGER FileId = {
511
+ /*.LowPart = */ fi.nFileIndexLow,
512
+ /*.HighPart = */ fi.nFileIndexHigh
513
+ };
514
+ zFileId = mprintf(
515
+ "%08x/%016llx",
516
+ fi.dwVolumeSerialNumber,(u64)FileId.QuadPart);
517
+ }
518
+ }
519
+ CloseHandle(hFile);
520
+ }
521
+ fossil_path_free(wzFileName);
522
+ return zFileId;
523
+}
295524
#endif /* _WIN32 -- This code is for win32 only */
296525
--- src/winfile.c
+++ src/winfile.c
@@ -290,6 +290,235 @@
290 fossil_free(zWide);
291 for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
292 strncpy(zBuf, zUtf8, nBuf);
293 fossil_path_free(zUtf8);
294 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295 #endif /* _WIN32 -- This code is for win32 only */
296
--- src/winfile.c
+++ src/winfile.c
@@ -290,6 +290,235 @@
290 fossil_free(zWide);
291 for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
292 strncpy(zBuf, zUtf8, nBuf);
293 fossil_path_free(zUtf8);
294 }
295
296 /* Perform case-insensitive comparison of two UTF-16 file names. Try to load the
297 ** CompareStringOrdinal() function on Windows Vista and newer, and resort to the
298 ** RtlEqualUnicodeString() function on Windows XP.
299 ** The dance to invoke RtlEqualUnicodeString() is necessary because lstrcmpiW()
300 ** performs linguistic comparison, while the former performs binary comparison.
301 ** As an example, matching "ß" (U+00DF Latin Small Letter Sharp S) with "ss" is
302 ** undesirable in file name comparison, so lstrcmpiW() is only invoked in cases
303 ** that are technically impossible and contradicting all known laws of physics.
304 */
305 int win32_filenames_equal_nocase(
306 const wchar_t *fn1,
307 const wchar_t *fn2
308 ){
309 static FARPROC fnCompareStringOrdinal;
310 static FARPROC fnRtlInitUnicodeString;
311 static FARPROC fnRtlEqualUnicodeString;
312 static int loaded_CompareStringOrdinal;
313 static int loaded_RtlUnicodeStringAPIs;
314 if( !loaded_CompareStringOrdinal ){
315 fnCompareStringOrdinal =
316 GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal");
317 loaded_CompareStringOrdinal = 1;
318 }
319 if( fnCompareStringOrdinal ){
320 return fnCompareStringOrdinal(fn1,-1,fn2,-1,1)-2==0;
321 }
322 if( !loaded_RtlUnicodeStringAPIs ){
323 fnRtlInitUnicodeString =
324 GetProcAddress(GetModuleHandleA("ntdll"),"RtlInitUnicodeString");
325 fnRtlEqualUnicodeString =
326 GetProcAddress(GetModuleHandleA("ntdll"),"RtlEqualUnicodeString");
327 loaded_RtlUnicodeStringAPIs = 1;
328 }
329 if( fnRtlInitUnicodeString && fnRtlEqualUnicodeString ){
330 struct { /* UNICODE_STRING from <ntdef.h> */
331 unsigned short Length;
332 unsigned short MaximumLength;
333 wchar_t *Buffer;
334 } u1, u2;
335 fnRtlInitUnicodeString(&u1,fn1);
336 fnRtlInitUnicodeString(&u2,fn2);
337 return (unsigned char)fnRtlEqualUnicodeString(&u1,&u2,1);
338 }
339 /* In what kind of strange parallel universe are we? */
340 return lstrcmpiW(fn1,fn2)==0;
341 }
342
343 /* Helper macros to deal with directory separators. */
344 #define IS_DIRSEP(s,i) ( s[i]=='/' || s[i]=='\\' )
345 #define NEXT_DIRSEP(s,i) while( s[i] && s[i]!='/' && s[i]!='\\' ){i++;}
346
347 /* The Win32 version of file_case_preferred_name() from file.c, which is able to
348 ** find case-preserved file names containing non-ASCII characters. The result is
349 ** allocated by fossil_malloc() and *should* be free'd by the caller. While this
350 ** function usually gets canonicalized paths, it is able to handle any input and
351 ** figure out more cases than the original:
352 **
353 ** fossil test-case-filename C:/ .//..\WINDOWS\/.//.\SYSTEM32\.\NOTEPAD.EXE
354 ** → Original: .//..\WINDOWS\/.//.\SYSTEM32\.\NOTEPAD.EXE
355 ** → Modified: .//..\Windows\/.//.\System32\.\notepad.exe
356 **
357 ** md ÄÖÜ
358 ** fossil test-case-filename ./\ .\äöü\/[empty]\\/
359 ** → Original: ./äöü\/[empty]\\/
360 ** → Modified: .\ÄÖÜ\/[empty]\\/
361 **
362 ** The function preserves slashes and backslashes: only single file or directory
363 ** components without directory separators ("basenames") are converted to UTF-16
364 ** using fossil_utf8_to_path(), so bypassing its slash ↔ backslash translations.
365 ** Note that the original function doesn't preserve all slashes and backslashes,
366 ** for example in the second example above.
367 **
368 ** NOTE: As of Windows 10, version 1803, case sensitivity may be enabled on a
369 ** per-directory basis, as returned by NtQueryInformationFile() with the file
370 ** information class FILE_CASE_SENSITIVE_INFORMATION. So this function may be
371 ** changed to act like fossil_strdup() for files located in such directories.
372 */
373 char *win32_file_case_preferred_name(
374 const char *zBase,
375 const char *zPath
376 ){
377 int cchBase;
378 int cchPath;
379 int cchBuf;
380 int cchRes;
381 char *zBuf;
382 char *zRes;
383 int ncUsed;
384 int i, j;
385 if( filenames_are_case_sensitive() ){
386 return fossil_strdup(zPath);
387 }
388 cchBase = strlen(zBase);
389 cchPath = strlen(zPath);
390 cchBuf = cchBase + cchPath + 2; /* + NULL + optional directory slash */
391 cchRes = cchPath + 1; /* + NULL */
392 zBuf = fossil_malloc(cchBuf);
393 zRes = fossil_malloc(cchRes);
394 ncUsed = 0;
395 memcpy(zBuf,zBase,cchBase);
396 if( !IS_DIRSEP(zBuf,cchBase-1) ){
397 zBuf[cchBase++]=L'/';
398 }
399 memcpy(zBuf+cchBase,zPath,cchPath+1);
400 i = j = cchBase;
401 while( 1 ){
402 WIN32_FIND_DATAW fd;
403 HANDLE hFind;
404 wchar_t *wzBuf;
405 char *zCompBuf = 0;
406 char *zComp = &zBuf[i];
407 int cchComp;
408 char chSep;
409 int fDone;
410 if( IS_DIRSEP(zBuf,i) ){
411 if( ncUsed+2>cchRes ){ /* Directory slash + NULL*/
412 cchRes += 32; /* Overprovisioning. */
413 zRes = fossil_realloc(zRes,cchRes);
414 }
415 zRes[ncUsed++] = zBuf[i];
416 i = j = i+1;
417 continue;
418 }
419 NEXT_DIRSEP(zBuf,j);
420 fDone = zBuf[j]==0;
421 chSep = zBuf[j];
422 zBuf[j] = 0; /* Truncate working buffer. */
423 wzBuf = fossil_utf8_to_path(zBuf,0);
424 hFind = FindFirstFileW(wzBuf,&fd);
425 if( hFind!=INVALID_HANDLE_VALUE ){
426 wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
427 FindClose(hFind);
428 /* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
429 if( win32_filenames_equal_nocase(wzComp,fd.cFileName) ){
430 zCompBuf = fossil_path_to_utf8(fd.cFileName);
431 zComp = zCompBuf;
432 }
433 fossil_path_free(wzComp);
434 }
435 fossil_path_free(wzBuf);
436 cchComp = strlen(zComp);
437 if( ncUsed+cchComp+1>cchRes ){ /* Current component + NULL */
438 cchRes += cchComp + 32; /* Overprovisioning. */
439 zRes = fossil_realloc(zRes,cchRes);
440 }
441 memcpy(zRes+ncUsed,zComp,cchComp);
442 ncUsed += cchComp;
443 if( zCompBuf ){
444 fossil_path_free(zCompBuf);
445 }
446 if( fDone ){
447 zRes[ncUsed] = 0;
448 break;
449 }
450 zBuf[j] = chSep; /* Undo working buffer truncation. */
451 i = j;
452 }
453 fossil_free(zBuf);
454 return zRes;
455 }
456
457 /* Return the unique identifier (UID) for a file, made up of the file identifier
458 ** (equal to "inode" for Unix-style file systems) plus the volume serial number.
459 ** Call the GetFileInformationByHandleEx() function on Windows Vista, and resort
460 ** to the GetFileInformationByHandle() function on Windows XP. The result string
461 ** is allocated by mprintf(), or NULL on failure.
462 */
463 char *win32_file_id(
464 const char *zFileName
465 ){
466 static FARPROC fnGetFileInformationByHandleEx;
467 static int loaded_fnGetFileInformationByHandleEx;
468 wchar_t *wzFileName = fossil_utf8_to_path(zFileName,0);
469 HANDLE hFile;
470 char *zFileId = 0;
471 hFile = CreateFileW(
472 wzFileName,
473 0,
474 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
475 NULL,
476 OPEN_EXISTING,
477 FILE_FLAG_BACKUP_SEMANTICS,
478 NULL);
479 if( hFile!=INVALID_HANDLE_VALUE ){
480 BY_HANDLE_FILE_INFORMATION fi;
481 struct { /* FILE_ID_INFO from <winbase.h> */
482 u64 VolumeSerialNumber;
483 unsigned char FileId[16];
484 } fi2;
485 if( !loaded_fnGetFileInformationByHandleEx ){
486 fnGetFileInformationByHandleEx = GetProcAddress(
487 GetModuleHandleA("kernel32"),"GetFileInformationByHandleEx");
488 loaded_fnGetFileInformationByHandleEx = 1;
489 }
490 if( fnGetFileInformationByHandleEx ){
491 if( fnGetFileInformationByHandleEx(
492 hFile,/*FileIdInfo*/0x12,&fi2,sizeof(fi2)) ){
493 zFileId = mprintf(
494 "%016llx/"
495 "%02x%02x%02x%02x%02x%02x%02x%02x"
496 "%02x%02x%02x%02x%02x%02x%02x%02x",
497 fi2.VolumeSerialNumber,
498 fi2.FileId[15], fi2.FileId[14],
499 fi2.FileId[13], fi2.FileId[12],
500 fi2.FileId[11], fi2.FileId[10],
501 fi2.FileId[9], fi2.FileId[8],
502 fi2.FileId[7], fi2.FileId[6],
503 fi2.FileId[5], fi2.FileId[4],
504 fi2.FileId[3], fi2.FileId[2],
505 fi2.FileId[1], fi2.FileId[0]);
506 }
507 }
508 if( zFileId==0 ){
509 if( GetFileInformationByHandle(hFile,&fi) ){
510 ULARGE_INTEGER FileId = {
511 /*.LowPart = */ fi.nFileIndexLow,
512 /*.HighPart = */ fi.nFileIndexHigh
513 };
514 zFileId = mprintf(
515 "%08x/%016llx",
516 fi.dwVolumeSerialNumber,(u64)FileId.QuadPart);
517 }
518 }
519 CloseHandle(hFile);
520 }
521 fossil_path_free(wzFileName);
522 return zFileId;
523 }
524 #endif /* _WIN32 -- This code is for win32 only */
525
+40 -1
--- src/xfer.c
+++ src/xfer.c
@@ -336,10 +336,11 @@
336336
|| !blob_is_filename(&pXfer->aToken[1])
337337
|| !blob_is_int64(&pXfer->aToken[2], &mtime)
338338
|| (!blob_eq(pHash,"-") && !blob_is_hname(pHash))
339339
|| !blob_is_int(&pXfer->aToken[4], &sz)
340340
|| !blob_is_int(&pXfer->aToken[5], &flags)
341
+ || (mtime<0 || sz<0 || flags<0)
341342
){
342343
blob_appendf(&pXfer->err, "malformed uvfile line");
343344
return;
344345
}
345346
blob_init(&content, 0, 0);
@@ -1119,10 +1120,24 @@
11191120
** Return the TH1 code to evaluate when a ticket change is processed.
11201121
*/
11211122
const char *xfer_ticket_code(void){
11221123
return db_get("xfer-ticket-script", 0);
11231124
}
1125
+
1126
+/*
1127
+** Reset the CGI content, roll back any pending db transaction, and
1128
+** emit an "error" xfer message. The message text gets fossil-encoded
1129
+** by this function. This is only intended for use with
1130
+** fail-fast/fatal errors, not ones which can be skipped over.
1131
+*/
1132
+static void xfer_fatal_error(const char *zMsg){
1133
+ cgi_reset_content();
1134
+ if( db_transaction_nesting_depth()>0 ){
1135
+ db_rollback_transaction();
1136
+ }
1137
+ @ error %F(zMsg)
1138
+}
11241139
11251140
/*
11261141
** Run the specified TH1 script, if any, and returns 1 on error.
11271142
*/
11281143
int xfer_run_script(
@@ -1461,10 +1476,14 @@
14611476
int seqno, max;
14621477
if( iVers>=3 ){
14631478
cgi_set_content_type("application/x-fossil-uncompressed");
14641479
}
14651480
blob_is_int(&xfer.aToken[2], &seqno);
1481
+ if( seqno<=0 ){
1482
+ xfer_fatal_error("invalid clone sequence number");
1483
+ return;
1484
+ }
14661485
max = db_int(0, "SELECT max(rid) FROM blob");
14671486
while( xfer.mxSend>(int)blob_size(xfer.pOut) && seqno<=max){
14681487
if( time(NULL) >= xfer.maxTime ) break;
14691488
if( iVers>=3 ){
14701489
send_compressed_file(&xfer, seqno);
@@ -1532,10 +1551,14 @@
15321551
*/
15331552
if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
15341553
&& blob_is_int(&xfer.aToken[2], &size) ){
15351554
const char *zName = blob_str(&xfer.aToken[1]);
15361555
Blob content;
1556
+ if( size<0 ){
1557
+ xfer_fatal_error("invalid config record");
1558
+ return;
1559
+ }
15371560
blob_zero(&content);
15381561
blob_extract(xfer.pIn, size, &content);
15391562
if( !g.perm.Admin ){
15401563
cgi_reset_content();
15411564
@ error not\sauthorized\sto\spush\sconfiguration
@@ -1844,11 +1867,11 @@
18441867
/* Send the server timestamp last, in case prior processing happened
18451868
** to use up a significant fraction of our time window.
18461869
*/
18471870
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
18481871
@ # timestamp %s(zNow) errors %d(nErr)
1849
- free(zNow);
1872
+ fossil_free(zNow);
18501873
18511874
db_commit_transaction();
18521875
configure_rebuild();
18531876
}
18541877
@@ -2487,10 +2510,14 @@
24872510
&& (blob_eq(&xfer.aToken[3],"-") || blob_is_hname(&xfer.aToken[3]))
24882511
){
24892512
const char *zName = blob_str(&xfer.aToken[1]);
24902513
const char *zHash = blob_str(&xfer.aToken[3]);
24912514
int iStatus;
2515
+ if( mtime<0 || size<0 ){
2516
+ xfer_fatal_error("invalid uvigot");
2517
+ return ++nErr;
2518
+ }
24922519
iStatus = unversioned_status(zName, mtime, zHash);
24932520
if( (syncFlags & SYNC_UV_REVERT)!=0 ){
24942521
if( iStatus==4 ) iStatus = 2;
24952522
if( iStatus==5 ) iStatus = 1;
24962523
}
@@ -2573,10 +2600,14 @@
25732600
*/
25742601
if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
25752602
&& blob_is_int(&xfer.aToken[2], &size) ){
25762603
const char *zName = blob_str(&xfer.aToken[1]);
25772604
Blob content;
2605
+ if( size<0 ){
2606
+ xfer_fatal_error("invalid config record");
2607
+ return ++nErr;
2608
+ }
25782609
blob_zero(&content);
25792610
blob_extract(xfer.pIn, size, &content);
25802611
g.perm.Admin = g.perm.RdAddr = 1;
25812612
configure_receive(zName, &content, origConfigRcvMask);
25822613
nCardRcvd++;
@@ -2617,10 +2648,14 @@
26172648
** blob that needs to be sent. If N<=0 that indicates that all blobs
26182649
** have been sent.
26192650
*/
26202651
if( blob_eq(&xfer.aToken[0], "clone_seqno") && xfer.nToken==2 ){
26212652
blob_is_int(&xfer.aToken[1], &cloneSeqno);
2653
+ if( cloneSeqno<0 ){
2654
+ xfer_fatal_error("invalid clone_seqno");
2655
+ return ++nErr;
2656
+ }
26222657
}else
26232658
26242659
/* message MESSAGE
26252660
**
26262661
** A message is received from the server. Print it.
@@ -2694,10 +2729,14 @@
26942729
char *zUser = blob_terminate(&xfer.aToken[2]);
26952730
sqlite3_int64 mtime, iNow;
26962731
defossilize(zUser);
26972732
iNow = time(NULL);
26982733
if( blob_is_int64(&xfer.aToken[3], &mtime) && iNow>mtime ){
2734
+ if( mtime<0 ){
2735
+ xfer_fatal_error("invalid ci-lock-fail time");
2736
+ return ++nErr;
2737
+ }
26992738
iNow = time(NULL);
27002739
fossil_print("\nParent check-in locked by %s %s ago\n",
27012740
zUser, human_readable_age((iNow+1-mtime)/86400.0));
27022741
}else{
27032742
fossil_print("\nParent check-in locked by %s\n", zUser);
27042743
--- src/xfer.c
+++ src/xfer.c
@@ -336,10 +336,11 @@
336 || !blob_is_filename(&pXfer->aToken[1])
337 || !blob_is_int64(&pXfer->aToken[2], &mtime)
338 || (!blob_eq(pHash,"-") && !blob_is_hname(pHash))
339 || !blob_is_int(&pXfer->aToken[4], &sz)
340 || !blob_is_int(&pXfer->aToken[5], &flags)
 
341 ){
342 blob_appendf(&pXfer->err, "malformed uvfile line");
343 return;
344 }
345 blob_init(&content, 0, 0);
@@ -1119,10 +1120,24 @@
1119 ** Return the TH1 code to evaluate when a ticket change is processed.
1120 */
1121 const char *xfer_ticket_code(void){
1122 return db_get("xfer-ticket-script", 0);
1123 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
1125 /*
1126 ** Run the specified TH1 script, if any, and returns 1 on error.
1127 */
1128 int xfer_run_script(
@@ -1461,10 +1476,14 @@
1461 int seqno, max;
1462 if( iVers>=3 ){
1463 cgi_set_content_type("application/x-fossil-uncompressed");
1464 }
1465 blob_is_int(&xfer.aToken[2], &seqno);
 
 
 
 
1466 max = db_int(0, "SELECT max(rid) FROM blob");
1467 while( xfer.mxSend>(int)blob_size(xfer.pOut) && seqno<=max){
1468 if( time(NULL) >= xfer.maxTime ) break;
1469 if( iVers>=3 ){
1470 send_compressed_file(&xfer, seqno);
@@ -1532,10 +1551,14 @@
1532 */
1533 if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
1534 && blob_is_int(&xfer.aToken[2], &size) ){
1535 const char *zName = blob_str(&xfer.aToken[1]);
1536 Blob content;
 
 
 
 
1537 blob_zero(&content);
1538 blob_extract(xfer.pIn, size, &content);
1539 if( !g.perm.Admin ){
1540 cgi_reset_content();
1541 @ error not\sauthorized\sto\spush\sconfiguration
@@ -1844,11 +1867,11 @@
1844 /* Send the server timestamp last, in case prior processing happened
1845 ** to use up a significant fraction of our time window.
1846 */
1847 zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
1848 @ # timestamp %s(zNow) errors %d(nErr)
1849 free(zNow);
1850
1851 db_commit_transaction();
1852 configure_rebuild();
1853 }
1854
@@ -2487,10 +2510,14 @@
2487 && (blob_eq(&xfer.aToken[3],"-") || blob_is_hname(&xfer.aToken[3]))
2488 ){
2489 const char *zName = blob_str(&xfer.aToken[1]);
2490 const char *zHash = blob_str(&xfer.aToken[3]);
2491 int iStatus;
 
 
 
 
2492 iStatus = unversioned_status(zName, mtime, zHash);
2493 if( (syncFlags & SYNC_UV_REVERT)!=0 ){
2494 if( iStatus==4 ) iStatus = 2;
2495 if( iStatus==5 ) iStatus = 1;
2496 }
@@ -2573,10 +2600,14 @@
2573 */
2574 if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
2575 && blob_is_int(&xfer.aToken[2], &size) ){
2576 const char *zName = blob_str(&xfer.aToken[1]);
2577 Blob content;
 
 
 
 
2578 blob_zero(&content);
2579 blob_extract(xfer.pIn, size, &content);
2580 g.perm.Admin = g.perm.RdAddr = 1;
2581 configure_receive(zName, &content, origConfigRcvMask);
2582 nCardRcvd++;
@@ -2617,10 +2648,14 @@
2617 ** blob that needs to be sent. If N<=0 that indicates that all blobs
2618 ** have been sent.
2619 */
2620 if( blob_eq(&xfer.aToken[0], "clone_seqno") && xfer.nToken==2 ){
2621 blob_is_int(&xfer.aToken[1], &cloneSeqno);
 
 
 
 
2622 }else
2623
2624 /* message MESSAGE
2625 **
2626 ** A message is received from the server. Print it.
@@ -2694,10 +2729,14 @@
2694 char *zUser = blob_terminate(&xfer.aToken[2]);
2695 sqlite3_int64 mtime, iNow;
2696 defossilize(zUser);
2697 iNow = time(NULL);
2698 if( blob_is_int64(&xfer.aToken[3], &mtime) && iNow>mtime ){
 
 
 
 
2699 iNow = time(NULL);
2700 fossil_print("\nParent check-in locked by %s %s ago\n",
2701 zUser, human_readable_age((iNow+1-mtime)/86400.0));
2702 }else{
2703 fossil_print("\nParent check-in locked by %s\n", zUser);
2704
--- src/xfer.c
+++ src/xfer.c
@@ -336,10 +336,11 @@
336 || !blob_is_filename(&pXfer->aToken[1])
337 || !blob_is_int64(&pXfer->aToken[2], &mtime)
338 || (!blob_eq(pHash,"-") && !blob_is_hname(pHash))
339 || !blob_is_int(&pXfer->aToken[4], &sz)
340 || !blob_is_int(&pXfer->aToken[5], &flags)
341 || (mtime<0 || sz<0 || flags<0)
342 ){
343 blob_appendf(&pXfer->err, "malformed uvfile line");
344 return;
345 }
346 blob_init(&content, 0, 0);
@@ -1119,10 +1120,24 @@
1120 ** Return the TH1 code to evaluate when a ticket change is processed.
1121 */
1122 const char *xfer_ticket_code(void){
1123 return db_get("xfer-ticket-script", 0);
1124 }
1125
1126 /*
1127 ** Reset the CGI content, roll back any pending db transaction, and
1128 ** emit an "error" xfer message. The message text gets fossil-encoded
1129 ** by this function. This is only intended for use with
1130 ** fail-fast/fatal errors, not ones which can be skipped over.
1131 */
1132 static void xfer_fatal_error(const char *zMsg){
1133 cgi_reset_content();
1134 if( db_transaction_nesting_depth()>0 ){
1135 db_rollback_transaction();
1136 }
1137 @ error %F(zMsg)
1138 }
1139
1140 /*
1141 ** Run the specified TH1 script, if any, and returns 1 on error.
1142 */
1143 int xfer_run_script(
@@ -1461,10 +1476,14 @@
1476 int seqno, max;
1477 if( iVers>=3 ){
1478 cgi_set_content_type("application/x-fossil-uncompressed");
1479 }
1480 blob_is_int(&xfer.aToken[2], &seqno);
1481 if( seqno<=0 ){
1482 xfer_fatal_error("invalid clone sequence number");
1483 return;
1484 }
1485 max = db_int(0, "SELECT max(rid) FROM blob");
1486 while( xfer.mxSend>(int)blob_size(xfer.pOut) && seqno<=max){
1487 if( time(NULL) >= xfer.maxTime ) break;
1488 if( iVers>=3 ){
1489 send_compressed_file(&xfer, seqno);
@@ -1532,10 +1551,14 @@
1551 */
1552 if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
1553 && blob_is_int(&xfer.aToken[2], &size) ){
1554 const char *zName = blob_str(&xfer.aToken[1]);
1555 Blob content;
1556 if( size<0 ){
1557 xfer_fatal_error("invalid config record");
1558 return;
1559 }
1560 blob_zero(&content);
1561 blob_extract(xfer.pIn, size, &content);
1562 if( !g.perm.Admin ){
1563 cgi_reset_content();
1564 @ error not\sauthorized\sto\spush\sconfiguration
@@ -1844,11 +1867,11 @@
1867 /* Send the server timestamp last, in case prior processing happened
1868 ** to use up a significant fraction of our time window.
1869 */
1870 zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
1871 @ # timestamp %s(zNow) errors %d(nErr)
1872 fossil_free(zNow);
1873
1874 db_commit_transaction();
1875 configure_rebuild();
1876 }
1877
@@ -2487,10 +2510,14 @@
2510 && (blob_eq(&xfer.aToken[3],"-") || blob_is_hname(&xfer.aToken[3]))
2511 ){
2512 const char *zName = blob_str(&xfer.aToken[1]);
2513 const char *zHash = blob_str(&xfer.aToken[3]);
2514 int iStatus;
2515 if( mtime<0 || size<0 ){
2516 xfer_fatal_error("invalid uvigot");
2517 return ++nErr;
2518 }
2519 iStatus = unversioned_status(zName, mtime, zHash);
2520 if( (syncFlags & SYNC_UV_REVERT)!=0 ){
2521 if( iStatus==4 ) iStatus = 2;
2522 if( iStatus==5 ) iStatus = 1;
2523 }
@@ -2573,10 +2600,14 @@
2600 */
2601 if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
2602 && blob_is_int(&xfer.aToken[2], &size) ){
2603 const char *zName = blob_str(&xfer.aToken[1]);
2604 Blob content;
2605 if( size<0 ){
2606 xfer_fatal_error("invalid config record");
2607 return ++nErr;
2608 }
2609 blob_zero(&content);
2610 blob_extract(xfer.pIn, size, &content);
2611 g.perm.Admin = g.perm.RdAddr = 1;
2612 configure_receive(zName, &content, origConfigRcvMask);
2613 nCardRcvd++;
@@ -2617,10 +2648,14 @@
2648 ** blob that needs to be sent. If N<=0 that indicates that all blobs
2649 ** have been sent.
2650 */
2651 if( blob_eq(&xfer.aToken[0], "clone_seqno") && xfer.nToken==2 ){
2652 blob_is_int(&xfer.aToken[1], &cloneSeqno);
2653 if( cloneSeqno<0 ){
2654 xfer_fatal_error("invalid clone_seqno");
2655 return ++nErr;
2656 }
2657 }else
2658
2659 /* message MESSAGE
2660 **
2661 ** A message is received from the server. Print it.
@@ -2694,10 +2729,14 @@
2729 char *zUser = blob_terminate(&xfer.aToken[2]);
2730 sqlite3_int64 mtime, iNow;
2731 defossilize(zUser);
2732 iNow = time(NULL);
2733 if( blob_is_int64(&xfer.aToken[3], &mtime) && iNow>mtime ){
2734 if( mtime<0 ){
2735 xfer_fatal_error("invalid ci-lock-fail time");
2736 return ++nErr;
2737 }
2738 iNow = time(NULL);
2739 fossil_print("\nParent check-in locked by %s %s ago\n",
2740 zUser, human_readable_age((iNow+1-mtime)/86400.0));
2741 }else{
2742 fossil_print("\nParent check-in locked by %s\n", zUser);
2743
--- test/comment.test
+++ test/comment.test
@@ -319,8 +319,28 @@
319319
###############################################################################
320320
321321
fossil test-comment-format --width 81 --indent 9 --decode --trimcrlf --origbreak "00:00:00 " "\[0000000000\] *CURRENT* $orig" $orig
322322
test comment-60 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \n xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(6 lines output)"}
323323
324
+###############################################################################
325
+
326
+fossil test-comment-format --width 72 --file "" [file join $testdir "utf8-comment.txt"]
327
+test comment-61 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\] an\nd symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
328
+
329
+###############################################################################
330
+
331
+fossil test-comment-format --width 72 --wordbreak --file "" [file join $testdir "utf8-comment.txt"]
332
+test comment-62 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\]\nand symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
333
+
334
+###############################################################################
335
+
336
+fossil test-comment-format --width 72 --legacy --file "" [file join $testdir "utf8-comment.txt"]
337
+test comment-63 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\]\nand symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
338
+
339
+###############################################################################
340
+
341
+fossil test-comment-format --width 72 --legacy --wordbreak --file "" [file join $testdir "utf8-comment.txt"]
342
+test comment-64 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\]\nand symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
343
+
324344
###############################################################################
325345
326346
test_cleanup
327347
--- test/comment.test
+++ test/comment.test
@@ -319,8 +319,28 @@
319 ###############################################################################
320
321 fossil test-comment-format --width 81 --indent 9 --decode --trimcrlf --origbreak "00:00:00 " "\[0000000000\] *CURRENT* $orig" $orig
322 test comment-60 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \n xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(6 lines output)"}
323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324 ###############################################################################
325
326 test_cleanup
327
--- test/comment.test
+++ test/comment.test
@@ -319,8 +319,28 @@
319 ###############################################################################
320
321 fossil test-comment-format --width 81 --indent 9 --decode --trimcrlf --origbreak "00:00:00 " "\[0000000000\] *CURRENT* $orig" $orig
322 test comment-60 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \n xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(6 lines output)"}
323
324 ###############################################################################
325
326 fossil test-comment-format --width 72 --file "" [file join $testdir "utf8-comment.txt"]
327 test comment-61 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\] an\nd symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
328
329 ###############################################################################
330
331 fossil test-comment-format --width 72 --wordbreak --file "" [file join $testdir "utf8-comment.txt"]
332 test comment-62 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\]\nand symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
333
334 ###############################################################################
335
336 fossil test-comment-format --width 72 --legacy --file "" [file join $testdir "utf8-comment.txt"]
337 test comment-63 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\]\nand symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
338
339 ###############################################################################
340
341 fossil test-comment-format --width 72 --legacy --wordbreak --file "" [file join $testdir "utf8-comment.txt"]
342 test comment-64 {$RESULT eq "The comment formatter handles fullwidth and multi-byte \[äöü\]\nand symbols \[☃\] and emoji \[💾\] characters!\n(2 lines output)"}
343
344 ###############################################################################
345
346 test_cleanup
347
+20 -20
--- test/glob.test
+++ test/glob.test
@@ -30,40 +30,40 @@
3030
}
3131
3232
glob-parse 100 test test [string map [list \r\n \n] \
3333
{SQL expression: (x GLOB 'test')
3434
pattern[0] = [test]
35
-1 test}]
35
+1 1 test}]
3636
3737
glob-parse 101 "one two" one [string map [list \r\n \n] \
3838
{SQL expression: (x GLOB 'one' OR x GLOB 'two')
3939
pattern[0] = [one]
4040
pattern[1] = [two]
41
-1 one}]
41
+1 1 one}]
4242
4343
glob-parse 102 t* test [string map [list \r\n \n] \
4444
{SQL expression: (x GLOB 't*')
4545
pattern[0] = [t*]
46
-1 test}]
46
+1 1 test}]
4747
4848
glob-parse 103 "o* two" one [string map [list \r\n \n] \
4949
{SQL expression: (x GLOB 'o*' OR x GLOB 'two')
5050
pattern[0] = [o*]
5151
pattern[1] = [two]
52
-1 one}]
52
+1 1 one}]
5353
5454
glob-parse 104 {"o* two" "three four"} "one two" [string map [list \r\n \n] \
5555
{SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
5656
pattern[0] = [o* two]
5757
pattern[1] = [three four]
58
-1 one two}]
58
+1 1 one two}]
5959
6060
glob-parse 105 {"o* two" "three four"} "two one" [string map [list \r\n \n] \
6161
{SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
6262
pattern[0] = [o* two]
6363
pattern[1] = [three four]
64
-0 two one}]
64
+0 0 two one}]
6565
6666
glob-parse 106 "\"o*\ntwo\" \"three\nfour\"" "one\ntwo" \
6767
[string map [list \r\n \n] \
6868
{SQL expression: (x GLOB 'o*
6969
two' OR x GLOB 'three
@@ -70,11 +70,11 @@
7070
four')
7171
pattern[0] = [o*
7272
two]
7373
pattern[1] = [three
7474
four]
75
-1 one
75
+1 1 one
7676
two}]
7777
7878
glob-parse 107 "\"o*\ntwo\" \"three\nfour\"" "two\none" \
7979
[string map [list \r\n \n] \
8080
{SQL expression: (x GLOB 'o*
@@ -82,11 +82,11 @@
8282
four')
8383
pattern[0] = [o*
8484
two]
8585
pattern[1] = [three
8686
four]
87
-0 two
87
+0 0 two
8888
one}]
8989
9090
glob-parse 108 "\"o*\rtwo\" \"three\rfour\"" "one\rtwo" \
9191
[string map [list \r\n \n] \
9292
{SQL expression: (x GLOB 'o*
@@ -94,11 +94,11 @@
9494
four')
9595
pattern[0] = [o*
9696
two]
9797
pattern[1] = [three
9898
four]
99
-1 one
99
+1 1 one
100100
two}]
101101
102102
glob-parse 109 "\"o*\rtwo\" \"three\rfour\"" "two\rone" \
103103
[string map [list \r\n \n] \
104104
{SQL expression: (x GLOB 'o*
@@ -106,11 +106,11 @@
106106
four')
107107
pattern[0] = [o*
108108
two]
109109
pattern[1] = [three
110110
four]
111
-0 two
111
+0 0 two
112112
one}]
113113
114114
glob-parse 110 "'o*\ntwo' 'three\nfour'" "one\ntwo" \
115115
[string map [list \r\n \n] \
116116
{SQL expression: (x GLOB 'o*
@@ -118,11 +118,11 @@
118118
four')
119119
pattern[0] = [o*
120120
two]
121121
pattern[1] = [three
122122
four]
123
-1 one
123
+1 1 one
124124
two}]
125125
126126
glob-parse 111 "'o*\ntwo' 'three\nfour'" "two\none" \
127127
[string map [list \r\n \n] \
128128
{SQL expression: (x GLOB 'o*
@@ -130,61 +130,61 @@
130130
four')
131131
pattern[0] = [o*
132132
two]
133133
pattern[1] = [three
134134
four]
135
-0 two
135
+0 0 two
136136
one}]
137137
138138
glob-parse 112 "\"'o*' 'two'\" \"'three' 'four'\"" "'one' 'two'" \
139139
[string map [list \r\n \n] \
140140
{SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''')
141141
pattern[0] = ['o*' 'two']
142142
pattern[1] = ['three' 'four']
143
-1 'one' 'two'}]
143
+1 1 'one' 'two'}]
144144
145145
glob-parse 113 "\"'o*' 'two'\" \"'three' 'four'\"" "two one" \
146146
[string map [list \r\n \n] \
147147
{SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''')
148148
pattern[0] = ['o*' 'two']
149149
pattern[1] = ['three' 'four']
150
-0 two one}]
150
+0 0 two one}]
151151
152152
glob-parse 114 o*,two one [string map [list \r\n \n] \
153153
{SQL expression: (x GLOB 'o*' OR x GLOB 'two')
154154
pattern[0] = [o*]
155155
pattern[1] = [two]
156
-1 one}]
156
+1 1 one}]
157157
158158
glob-parse 115 "o*,two three,four" "one two" [string map [list \r\n \n] \
159159
{SQL expression: (x GLOB 'o*' OR x GLOB 'two' OR x GLOB 'three' OR x GLOB 'four')
160160
pattern[0] = [o*]
161161
pattern[1] = [two]
162162
pattern[2] = [three]
163163
pattern[3] = [four]
164
-1 one two}]
164
+1 1 one two}]
165165
166166
glob-parse 116 'o*,two' one [string map [list \r\n \n] \
167167
{SQL expression: (x GLOB 'o*,two')
168168
pattern[0] = [o*,two]
169
-0 one}]
169
+0 0 one}]
170170
171171
glob-parse 117 'o*,two' one,two [string map [list \r\n \n] \
172172
{SQL expression: (x GLOB 'o*,two')
173173
pattern[0] = [o*,two]
174
-1 one,two}]
174
+1 1 one,two}]
175175
176176
glob-parse 118 "'o*,two three,four'" "one two three,four" \
177177
[string map [list \r\n \n] \
178178
{SQL expression: (x GLOB 'o*,two three,four')
179179
pattern[0] = [o*,two three,four]
180
-0 one two three,four}]
180
+0 0 one two three,four}]
181181
182182
glob-parse 119 "'o*,two three,four'" "one,two three,four" \
183183
[string map [list \r\n \n] \
184184
{SQL expression: (x GLOB 'o*,two three,four')
185185
pattern[0] = [o*,two three,four]
186
-1 one,two three,four}]
186
+1 1 one,two three,four}]
187187
188188
###############################################################################
189189
190190
test_cleanup
191191
--- test/glob.test
+++ test/glob.test
@@ -30,40 +30,40 @@
30 }
31
32 glob-parse 100 test test [string map [list \r\n \n] \
33 {SQL expression: (x GLOB 'test')
34 pattern[0] = [test]
35 1 test}]
36
37 glob-parse 101 "one two" one [string map [list \r\n \n] \
38 {SQL expression: (x GLOB 'one' OR x GLOB 'two')
39 pattern[0] = [one]
40 pattern[1] = [two]
41 1 one}]
42
43 glob-parse 102 t* test [string map [list \r\n \n] \
44 {SQL expression: (x GLOB 't*')
45 pattern[0] = [t*]
46 1 test}]
47
48 glob-parse 103 "o* two" one [string map [list \r\n \n] \
49 {SQL expression: (x GLOB 'o*' OR x GLOB 'two')
50 pattern[0] = [o*]
51 pattern[1] = [two]
52 1 one}]
53
54 glob-parse 104 {"o* two" "three four"} "one two" [string map [list \r\n \n] \
55 {SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
56 pattern[0] = [o* two]
57 pattern[1] = [three four]
58 1 one two}]
59
60 glob-parse 105 {"o* two" "three four"} "two one" [string map [list \r\n \n] \
61 {SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
62 pattern[0] = [o* two]
63 pattern[1] = [three four]
64 0 two one}]
65
66 glob-parse 106 "\"o*\ntwo\" \"three\nfour\"" "one\ntwo" \
67 [string map [list \r\n \n] \
68 {SQL expression: (x GLOB 'o*
69 two' OR x GLOB 'three
@@ -70,11 +70,11 @@
70 four')
71 pattern[0] = [o*
72 two]
73 pattern[1] = [three
74 four]
75 1 one
76 two}]
77
78 glob-parse 107 "\"o*\ntwo\" \"three\nfour\"" "two\none" \
79 [string map [list \r\n \n] \
80 {SQL expression: (x GLOB 'o*
@@ -82,11 +82,11 @@
82 four')
83 pattern[0] = [o*
84 two]
85 pattern[1] = [three
86 four]
87 0 two
88 one}]
89
90 glob-parse 108 "\"o*\rtwo\" \"three\rfour\"" "one\rtwo" \
91 [string map [list \r\n \n] \
92 {SQL expression: (x GLOB 'o*
@@ -94,11 +94,11 @@
94 four')
95 pattern[0] = [o*
96 two]
97 pattern[1] = [three
98 four]
99 1 one
100 two}]
101
102 glob-parse 109 "\"o*\rtwo\" \"three\rfour\"" "two\rone" \
103 [string map [list \r\n \n] \
104 {SQL expression: (x GLOB 'o*
@@ -106,11 +106,11 @@
106 four')
107 pattern[0] = [o*
108 two]
109 pattern[1] = [three
110 four]
111 0 two
112 one}]
113
114 glob-parse 110 "'o*\ntwo' 'three\nfour'" "one\ntwo" \
115 [string map [list \r\n \n] \
116 {SQL expression: (x GLOB 'o*
@@ -118,11 +118,11 @@
118 four')
119 pattern[0] = [o*
120 two]
121 pattern[1] = [three
122 four]
123 1 one
124 two}]
125
126 glob-parse 111 "'o*\ntwo' 'three\nfour'" "two\none" \
127 [string map [list \r\n \n] \
128 {SQL expression: (x GLOB 'o*
@@ -130,61 +130,61 @@
130 four')
131 pattern[0] = [o*
132 two]
133 pattern[1] = [three
134 four]
135 0 two
136 one}]
137
138 glob-parse 112 "\"'o*' 'two'\" \"'three' 'four'\"" "'one' 'two'" \
139 [string map [list \r\n \n] \
140 {SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''')
141 pattern[0] = ['o*' 'two']
142 pattern[1] = ['three' 'four']
143 1 'one' 'two'}]
144
145 glob-parse 113 "\"'o*' 'two'\" \"'three' 'four'\"" "two one" \
146 [string map [list \r\n \n] \
147 {SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''')
148 pattern[0] = ['o*' 'two']
149 pattern[1] = ['three' 'four']
150 0 two one}]
151
152 glob-parse 114 o*,two one [string map [list \r\n \n] \
153 {SQL expression: (x GLOB 'o*' OR x GLOB 'two')
154 pattern[0] = [o*]
155 pattern[1] = [two]
156 1 one}]
157
158 glob-parse 115 "o*,two three,four" "one two" [string map [list \r\n \n] \
159 {SQL expression: (x GLOB 'o*' OR x GLOB 'two' OR x GLOB 'three' OR x GLOB 'four')
160 pattern[0] = [o*]
161 pattern[1] = [two]
162 pattern[2] = [three]
163 pattern[3] = [four]
164 1 one two}]
165
166 glob-parse 116 'o*,two' one [string map [list \r\n \n] \
167 {SQL expression: (x GLOB 'o*,two')
168 pattern[0] = [o*,two]
169 0 one}]
170
171 glob-parse 117 'o*,two' one,two [string map [list \r\n \n] \
172 {SQL expression: (x GLOB 'o*,two')
173 pattern[0] = [o*,two]
174 1 one,two}]
175
176 glob-parse 118 "'o*,two three,four'" "one two three,four" \
177 [string map [list \r\n \n] \
178 {SQL expression: (x GLOB 'o*,two three,four')
179 pattern[0] = [o*,two three,four]
180 0 one two three,four}]
181
182 glob-parse 119 "'o*,two three,four'" "one,two three,four" \
183 [string map [list \r\n \n] \
184 {SQL expression: (x GLOB 'o*,two three,four')
185 pattern[0] = [o*,two three,four]
186 1 one,two three,four}]
187
188 ###############################################################################
189
190 test_cleanup
191
--- test/glob.test
+++ test/glob.test
@@ -30,40 +30,40 @@
30 }
31
32 glob-parse 100 test test [string map [list \r\n \n] \
33 {SQL expression: (x GLOB 'test')
34 pattern[0] = [test]
35 1 1 test}]
36
37 glob-parse 101 "one two" one [string map [list \r\n \n] \
38 {SQL expression: (x GLOB 'one' OR x GLOB 'two')
39 pattern[0] = [one]
40 pattern[1] = [two]
41 1 1 one}]
42
43 glob-parse 102 t* test [string map [list \r\n \n] \
44 {SQL expression: (x GLOB 't*')
45 pattern[0] = [t*]
46 1 1 test}]
47
48 glob-parse 103 "o* two" one [string map [list \r\n \n] \
49 {SQL expression: (x GLOB 'o*' OR x GLOB 'two')
50 pattern[0] = [o*]
51 pattern[1] = [two]
52 1 1 one}]
53
54 glob-parse 104 {"o* two" "three four"} "one two" [string map [list \r\n \n] \
55 {SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
56 pattern[0] = [o* two]
57 pattern[1] = [three four]
58 1 1 one two}]
59
60 glob-parse 105 {"o* two" "three four"} "two one" [string map [list \r\n \n] \
61 {SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
62 pattern[0] = [o* two]
63 pattern[1] = [three four]
64 0 0 two one}]
65
66 glob-parse 106 "\"o*\ntwo\" \"three\nfour\"" "one\ntwo" \
67 [string map [list \r\n \n] \
68 {SQL expression: (x GLOB 'o*
69 two' OR x GLOB 'three
@@ -70,11 +70,11 @@
70 four')
71 pattern[0] = [o*
72 two]
73 pattern[1] = [three
74 four]
75 1 1 one
76 two}]
77
78 glob-parse 107 "\"o*\ntwo\" \"three\nfour\"" "two\none" \
79 [string map [list \r\n \n] \
80 {SQL expression: (x GLOB 'o*
@@ -82,11 +82,11 @@
82 four')
83 pattern[0] = [o*
84 two]
85 pattern[1] = [three
86 four]
87 0 0 two
88 one}]
89
90 glob-parse 108 "\"o*\rtwo\" \"three\rfour\"" "one\rtwo" \
91 [string map [list \r\n \n] \
92 {SQL expression: (x GLOB 'o*
@@ -94,11 +94,11 @@
94 four')
95 pattern[0] = [o*
96 two]
97 pattern[1] = [three
98 four]
99 1 1 one
100 two}]
101
102 glob-parse 109 "\"o*\rtwo\" \"three\rfour\"" "two\rone" \
103 [string map [list \r\n \n] \
104 {SQL expression: (x GLOB 'o*
@@ -106,11 +106,11 @@
106 four')
107 pattern[0] = [o*
108 two]
109 pattern[1] = [three
110 four]
111 0 0 two
112 one}]
113
114 glob-parse 110 "'o*\ntwo' 'three\nfour'" "one\ntwo" \
115 [string map [list \r\n \n] \
116 {SQL expression: (x GLOB 'o*
@@ -118,11 +118,11 @@
118 four')
119 pattern[0] = [o*
120 two]
121 pattern[1] = [three
122 four]
123 1 1 one
124 two}]
125
126 glob-parse 111 "'o*\ntwo' 'three\nfour'" "two\none" \
127 [string map [list \r\n \n] \
128 {SQL expression: (x GLOB 'o*
@@ -130,61 +130,61 @@
130 four')
131 pattern[0] = [o*
132 two]
133 pattern[1] = [three
134 four]
135 0 0 two
136 one}]
137
138 glob-parse 112 "\"'o*' 'two'\" \"'three' 'four'\"" "'one' 'two'" \
139 [string map [list \r\n \n] \
140 {SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''')
141 pattern[0] = ['o*' 'two']
142 pattern[1] = ['three' 'four']
143 1 1 'one' 'two'}]
144
145 glob-parse 113 "\"'o*' 'two'\" \"'three' 'four'\"" "two one" \
146 [string map [list \r\n \n] \
147 {SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''')
148 pattern[0] = ['o*' 'two']
149 pattern[1] = ['three' 'four']
150 0 0 two one}]
151
152 glob-parse 114 o*,two one [string map [list \r\n \n] \
153 {SQL expression: (x GLOB 'o*' OR x GLOB 'two')
154 pattern[0] = [o*]
155 pattern[1] = [two]
156 1 1 one}]
157
158 glob-parse 115 "o*,two three,four" "one two" [string map [list \r\n \n] \
159 {SQL expression: (x GLOB 'o*' OR x GLOB 'two' OR x GLOB 'three' OR x GLOB 'four')
160 pattern[0] = [o*]
161 pattern[1] = [two]
162 pattern[2] = [three]
163 pattern[3] = [four]
164 1 1 one two}]
165
166 glob-parse 116 'o*,two' one [string map [list \r\n \n] \
167 {SQL expression: (x GLOB 'o*,two')
168 pattern[0] = [o*,two]
169 0 0 one}]
170
171 glob-parse 117 'o*,two' one,two [string map [list \r\n \n] \
172 {SQL expression: (x GLOB 'o*,two')
173 pattern[0] = [o*,two]
174 1 1 one,two}]
175
176 glob-parse 118 "'o*,two three,four'" "one two three,four" \
177 [string map [list \r\n \n] \
178 {SQL expression: (x GLOB 'o*,two three,four')
179 pattern[0] = [o*,two three,four]
180 0 0 one two three,four}]
181
182 glob-parse 119 "'o*,two three,four'" "one,two three,four" \
183 [string map [list \r\n \n] \
184 {SQL expression: (x GLOB 'o*,two three,four')
185 pattern[0] = [o*,two three,four]
186 1 1 one,two three,four}]
187
188 ###############################################################################
189
190 test_cleanup
191
--- test/settings.test
+++ test/settings.test
@@ -26,10 +26,16 @@
2626
#
2727
# fossil settings ?PROPERTY? ?VALUE? ?OPTIONS?
2828
# fossil unset PROPERTY ?OPTIONS?
2929
#
3030
# Where the only supported options are "--global" and "--exact".
31
+#
32
+###############################################################################
33
+#
34
+# NOTE: The [get_all_settings] procedure from test/tester.tcl returns the list
35
+# of settings to test and needs to be manually updated when new settings
36
+# are added.
3137
#
3238
###############################################################################
3339
#
3440
# NOTE: The [extract_setting_names] procedure extracts the list of setting
3541
# names from the line-ending normalized output of the "fossil settings"
3642
--- test/settings.test
+++ test/settings.test
@@ -26,10 +26,16 @@
26 #
27 # fossil settings ?PROPERTY? ?VALUE? ?OPTIONS?
28 # fossil unset PROPERTY ?OPTIONS?
29 #
30 # Where the only supported options are "--global" and "--exact".
 
 
 
 
 
 
31 #
32 ###############################################################################
33 #
34 # NOTE: The [extract_setting_names] procedure extracts the list of setting
35 # names from the line-ending normalized output of the "fossil settings"
36
--- test/settings.test
+++ test/settings.test
@@ -26,10 +26,16 @@
26 #
27 # fossil settings ?PROPERTY? ?VALUE? ?OPTIONS?
28 # fossil unset PROPERTY ?OPTIONS?
29 #
30 # Where the only supported options are "--global" and "--exact".
31 #
32 ###############################################################################
33 #
34 # NOTE: The [get_all_settings] procedure from test/tester.tcl returns the list
35 # of settings to test and needs to be manually updated when new settings
36 # are added.
37 #
38 ###############################################################################
39 #
40 # NOTE: The [extract_setting_names] procedure extracts the list of setting
41 # names from the line-ending normalized output of the "fossil settings"
42
--- test/tester.tcl
+++ test/tester.tcl
@@ -359,10 +359,12 @@
359359
proxy \
360360
redirect-to-https \
361361
relative-paths \
362362
repo-cksum \
363363
repolist-skin \
364
+ robot-restrict \
365
+ robots-txt \
364366
safe-html \
365367
self-pw-reset \
366368
self-register \
367369
sitemap-extra \
368370
ssh-command \
369371
370372
ADDED test/utf8-comment.txt
--- test/tester.tcl
+++ test/tester.tcl
@@ -359,10 +359,12 @@
359 proxy \
360 redirect-to-https \
361 relative-paths \
362 repo-cksum \
363 repolist-skin \
 
 
364 safe-html \
365 self-pw-reset \
366 self-register \
367 sitemap-extra \
368 ssh-command \
369
370 DDED test/utf8-comment.txt
--- test/tester.tcl
+++ test/tester.tcl
@@ -359,10 +359,12 @@
359 proxy \
360 redirect-to-https \
361 relative-paths \
362 repo-cksum \
363 repolist-skin \
364 robot-restrict \
365 robots-txt \
366 safe-html \
367 self-pw-reset \
368 self-register \
369 sitemap-extra \
370 ssh-command \
371
372 DDED test/utf8-comment.txt
--- a/test/utf8-comment.txt
+++ b/test/utf8-comment.txt
@@ -0,0 +1 @@
1
+The comment formatter handles fullwidth and multi-byte [äöü] and symbols [☃] and emoji [💾] characters!
--- a/test/utf8-comment.txt
+++ b/test/utf8-comment.txt
@@ -0,0 +1 @@
 
--- a/test/utf8-comment.txt
+++ b/test/utf8-comment.txt
@@ -0,0 +1 @@
1 The comment formatter handles fullwidth and multi-byte [äöü] and symbols [☃] and emoji [💾] characters!
--- tools/makemake.tcl
+++ tools/makemake.tcl
@@ -209,10 +209,11 @@
209209
# Additional resource files that get built into the executable.
210210
# These paths are all resolved from the src/ directory, so must
211211
# be relative to that.
212212
set extra_files {
213213
diff.tcl
214
+ merge.tcl
214215
markdown.md
215216
wiki.wiki
216217
*.js
217218
default.css
218219
style.*.css
@@ -445,11 +446,11 @@
445446
446447
# The USE_LINENOISE variable may be undefined, set to 0, or set
447448
# to 1. If it is set to 0, then there is no need to build or link
448449
# the linenoise.o object.
449450
LINENOISE_DEF.0 =
450
-LINENOISE_DEF.1 = -DHAVE_LINENOISE
451
+LINENOISE_DEF.1 = -DHAVE_LINENOISE=2
451452
LINENOISE_DEF. = $(LINENOISE_DEF.0)
452453
LINENOISE_OBJ.0 =
453454
LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
454455
LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
455456
456457
--- tools/makemake.tcl
+++ tools/makemake.tcl
@@ -209,10 +209,11 @@
209 # Additional resource files that get built into the executable.
210 # These paths are all resolved from the src/ directory, so must
211 # be relative to that.
212 set extra_files {
213 diff.tcl
 
214 markdown.md
215 wiki.wiki
216 *.js
217 default.css
218 style.*.css
@@ -445,11 +446,11 @@
445
446 # The USE_LINENOISE variable may be undefined, set to 0, or set
447 # to 1. If it is set to 0, then there is no need to build or link
448 # the linenoise.o object.
449 LINENOISE_DEF.0 =
450 LINENOISE_DEF.1 = -DHAVE_LINENOISE
451 LINENOISE_DEF. = $(LINENOISE_DEF.0)
452 LINENOISE_OBJ.0 =
453 LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
454 LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
455
456
--- tools/makemake.tcl
+++ tools/makemake.tcl
@@ -209,10 +209,11 @@
209 # Additional resource files that get built into the executable.
210 # These paths are all resolved from the src/ directory, so must
211 # be relative to that.
212 set extra_files {
213 diff.tcl
214 merge.tcl
215 markdown.md
216 wiki.wiki
217 *.js
218 default.css
219 style.*.css
@@ -445,11 +446,11 @@
446
447 # The USE_LINENOISE variable may be undefined, set to 0, or set
448 # to 1. If it is set to 0, then there is no need to build or link
449 # the linenoise.o object.
450 LINENOISE_DEF.0 =
451 LINENOISE_DEF.1 = -DHAVE_LINENOISE=2
452 LINENOISE_DEF. = $(LINENOISE_DEF.0)
453 LINENOISE_OBJ.0 =
454 LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
455 LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
456
457
--- tools/man_page_command_list.tcl
+++ tools/man_page_command_list.tcl
@@ -10,11 +10,11 @@
1010
set file [lindex $argv 0]
1111
}
1212
1313
# Get list of common commands.
1414
set commands [exec fossil help]
15
-regsub -nocase {.*?\ncommon commands:.*\n} $commands {} commands
15
+regsub -nocase {.*?\nfrequently used commands:.*\n} $commands {} commands
1616
regsub -nocase {\nthis is fossil version.*} $commands {} commands
1717
regsub -all {\s+} $commands " " commands
1818
set commands [lsort $commands]
1919
2020
# Compute number of rows.
2121
--- tools/man_page_command_list.tcl
+++ tools/man_page_command_list.tcl
@@ -10,11 +10,11 @@
10 set file [lindex $argv 0]
11 }
12
13 # Get list of common commands.
14 set commands [exec fossil help]
15 regsub -nocase {.*?\ncommon commands:.*\n} $commands {} commands
16 regsub -nocase {\nthis is fossil version.*} $commands {} commands
17 regsub -all {\s+} $commands " " commands
18 set commands [lsort $commands]
19
20 # Compute number of rows.
21
--- tools/man_page_command_list.tcl
+++ tools/man_page_command_list.tcl
@@ -10,11 +10,11 @@
10 set file [lindex $argv 0]
11 }
12
13 # Get list of common commands.
14 set commands [exec fossil help]
15 regsub -nocase {.*?\nfrequently used commands:.*\n} $commands {} commands
16 regsub -nocase {\nthis is fossil version.*} $commands {} commands
17 regsub -all {\s+} $commands " " commands
18 set commands [lsort $commands]
19
20 # Compute number of rows.
21
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -634,10 +634,11 @@
634634
$(SRCDIR)/hbmenu.js \
635635
$(SRCDIR)/href.js \
636636
$(SRCDIR)/login.js \
637637
$(SRCDIR)/markdown.md \
638638
$(SRCDIR)/menu.js \
639
+ $(SRCDIR)/merge.tcl \
639640
$(SRCDIR)/scroll.js \
640641
$(SRCDIR)/skin.js \
641642
$(SRCDIR)/sorttable.js \
642643
$(SRCDIR)/sounds/0.wav \
643644
$(SRCDIR)/sounds/1.wav \
644645
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -634,10 +634,11 @@
634 $(SRCDIR)/hbmenu.js \
635 $(SRCDIR)/href.js \
636 $(SRCDIR)/login.js \
637 $(SRCDIR)/markdown.md \
638 $(SRCDIR)/menu.js \
 
639 $(SRCDIR)/scroll.js \
640 $(SRCDIR)/skin.js \
641 $(SRCDIR)/sorttable.js \
642 $(SRCDIR)/sounds/0.wav \
643 $(SRCDIR)/sounds/1.wav \
644
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -634,10 +634,11 @@
634 $(SRCDIR)/hbmenu.js \
635 $(SRCDIR)/href.js \
636 $(SRCDIR)/login.js \
637 $(SRCDIR)/markdown.md \
638 $(SRCDIR)/menu.js \
639 $(SRCDIR)/merge.tcl \
640 $(SRCDIR)/scroll.js \
641 $(SRCDIR)/skin.js \
642 $(SRCDIR)/sorttable.js \
643 $(SRCDIR)/sounds/0.wav \
644 $(SRCDIR)/sounds/1.wav \
645
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -592,10 +592,11 @@
592592
"$(SRCDIR)\hbmenu.js" \
593593
"$(SRCDIR)\href.js" \
594594
"$(SRCDIR)\login.js" \
595595
"$(SRCDIR)\markdown.md" \
596596
"$(SRCDIR)\menu.js" \
597
+ "$(SRCDIR)\merge.tcl" \
597598
"$(SRCDIR)\scroll.js" \
598599
"$(SRCDIR)\skin.js" \
599600
"$(SRCDIR)\sorttable.js" \
600601
"$(SRCDIR)\sounds\0.wav" \
601602
"$(SRCDIR)\sounds\1.wav" \
@@ -1222,10 +1223,11 @@
12221223
echo "$(SRCDIR)\hbmenu.js" >> $@
12231224
echo "$(SRCDIR)\href.js" >> $@
12241225
echo "$(SRCDIR)\login.js" >> $@
12251226
echo "$(SRCDIR)\markdown.md" >> $@
12261227
echo "$(SRCDIR)\menu.js" >> $@
1228
+ echo "$(SRCDIR)\merge.tcl" >> $@
12271229
echo "$(SRCDIR)\scroll.js" >> $@
12281230
echo "$(SRCDIR)\skin.js" >> $@
12291231
echo "$(SRCDIR)\sorttable.js" >> $@
12301232
echo "$(SRCDIR)\sounds/0.wav" >> $@
12311233
echo "$(SRCDIR)\sounds/1.wav" >> $@
12321234
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -592,10 +592,11 @@
592 "$(SRCDIR)\hbmenu.js" \
593 "$(SRCDIR)\href.js" \
594 "$(SRCDIR)\login.js" \
595 "$(SRCDIR)\markdown.md" \
596 "$(SRCDIR)\menu.js" \
 
597 "$(SRCDIR)\scroll.js" \
598 "$(SRCDIR)\skin.js" \
599 "$(SRCDIR)\sorttable.js" \
600 "$(SRCDIR)\sounds\0.wav" \
601 "$(SRCDIR)\sounds\1.wav" \
@@ -1222,10 +1223,11 @@
1222 echo "$(SRCDIR)\hbmenu.js" >> $@
1223 echo "$(SRCDIR)\href.js" >> $@
1224 echo "$(SRCDIR)\login.js" >> $@
1225 echo "$(SRCDIR)\markdown.md" >> $@
1226 echo "$(SRCDIR)\menu.js" >> $@
 
1227 echo "$(SRCDIR)\scroll.js" >> $@
1228 echo "$(SRCDIR)\skin.js" >> $@
1229 echo "$(SRCDIR)\sorttable.js" >> $@
1230 echo "$(SRCDIR)\sounds/0.wav" >> $@
1231 echo "$(SRCDIR)\sounds/1.wav" >> $@
1232
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -592,10 +592,11 @@
592 "$(SRCDIR)\hbmenu.js" \
593 "$(SRCDIR)\href.js" \
594 "$(SRCDIR)\login.js" \
595 "$(SRCDIR)\markdown.md" \
596 "$(SRCDIR)\menu.js" \
597 "$(SRCDIR)\merge.tcl" \
598 "$(SRCDIR)\scroll.js" \
599 "$(SRCDIR)\skin.js" \
600 "$(SRCDIR)\sorttable.js" \
601 "$(SRCDIR)\sounds\0.wav" \
602 "$(SRCDIR)\sounds\1.wav" \
@@ -1222,10 +1223,11 @@
1223 echo "$(SRCDIR)\hbmenu.js" >> $@
1224 echo "$(SRCDIR)\href.js" >> $@
1225 echo "$(SRCDIR)\login.js" >> $@
1226 echo "$(SRCDIR)\markdown.md" >> $@
1227 echo "$(SRCDIR)\menu.js" >> $@
1228 echo "$(SRCDIR)\merge.tcl" >> $@
1229 echo "$(SRCDIR)\scroll.js" >> $@
1230 echo "$(SRCDIR)\skin.js" >> $@
1231 echo "$(SRCDIR)\sorttable.js" >> $@
1232 echo "$(SRCDIR)\sounds/0.wav" >> $@
1233 echo "$(SRCDIR)\sounds/1.wav" >> $@
1234
--- www/aboutcgi.wiki
+++ www/aboutcgi.wiki
@@ -8,30 +8,30 @@
88
99
This is a "how it works" guide. This document provides background
1010
information on the CGI protocol so that you can better understand what
1111
is going on behind the scenes. If you just want to set up Fossil
1212
as a CGI server, see the [./server/ | Fossil Server Setup] page. Or
13
-if you want to development CGI-based extensions to Fossil, see
13
+if you want to develop CGI-based extensions to Fossil, see
1414
the [./serverext.wiki|CGI Server Extensions] page.
1515
1616
<h2>A Quick Review Of CGI</h2>
1717
1818
An HTTP request is a block of text that is sent by a client application
1919
(usually a web browser) and arrives at the web server over a network
2020
connection. The HTTP request contains a URL that describes the information
2121
being requested. The URL in the HTTP request is typically the same URL
2222
that appears in the URL bar at the top of the web browser that is making
23
-the request. The URL might contain a "?" character followed
23
+the request. The URL might contain a "?" character followed by
2424
query parameters. The HTTP will usually also contain other information
2525
such as the name of the application that made the request, whether or
2626
not the requesting application can accept a compressed reply, POST
2727
parameters from forms, and so forth.
2828
2929
The job of the web server is to interpret the HTTP request and formulate
3030
an appropriate reply.
31
-The web server is free to interpret the HTTP request in any way it wants.
32
-But most web servers follow a similar pattern, described below.
31
+The web server is free to interpret the HTTP request in any way it wants,
32
+but most web servers follow a similar pattern, described below.
3333
(Note: details may vary from one web server to another.)
3434
3535
Suppose the filename component of the URL in the HTTP request looks like this:
3636
3737
<pre>/one/two/timeline/four</pre>
3838
--- www/aboutcgi.wiki
+++ www/aboutcgi.wiki
@@ -8,30 +8,30 @@
8
9 This is a "how it works" guide. This document provides background
10 information on the CGI protocol so that you can better understand what
11 is going on behind the scenes. If you just want to set up Fossil
12 as a CGI server, see the [./server/ | Fossil Server Setup] page. Or
13 if you want to development CGI-based extensions to Fossil, see
14 the [./serverext.wiki|CGI Server Extensions] page.
15
16 <h2>A Quick Review Of CGI</h2>
17
18 An HTTP request is a block of text that is sent by a client application
19 (usually a web browser) and arrives at the web server over a network
20 connection. The HTTP request contains a URL that describes the information
21 being requested. The URL in the HTTP request is typically the same URL
22 that appears in the URL bar at the top of the web browser that is making
23 the request. The URL might contain a "?" character followed
24 query parameters. The HTTP will usually also contain other information
25 such as the name of the application that made the request, whether or
26 not the requesting application can accept a compressed reply, POST
27 parameters from forms, and so forth.
28
29 The job of the web server is to interpret the HTTP request and formulate
30 an appropriate reply.
31 The web server is free to interpret the HTTP request in any way it wants.
32 But most web servers follow a similar pattern, described below.
33 (Note: details may vary from one web server to another.)
34
35 Suppose the filename component of the URL in the HTTP request looks like this:
36
37 <pre>/one/two/timeline/four</pre>
38
--- www/aboutcgi.wiki
+++ www/aboutcgi.wiki
@@ -8,30 +8,30 @@
8
9 This is a "how it works" guide. This document provides background
10 information on the CGI protocol so that you can better understand what
11 is going on behind the scenes. If you just want to set up Fossil
12 as a CGI server, see the [./server/ | Fossil Server Setup] page. Or
13 if you want to develop CGI-based extensions to Fossil, see
14 the [./serverext.wiki|CGI Server Extensions] page.
15
16 <h2>A Quick Review Of CGI</h2>
17
18 An HTTP request is a block of text that is sent by a client application
19 (usually a web browser) and arrives at the web server over a network
20 connection. The HTTP request contains a URL that describes the information
21 being requested. The URL in the HTTP request is typically the same URL
22 that appears in the URL bar at the top of the web browser that is making
23 the request. The URL might contain a "?" character followed by
24 query parameters. The HTTP will usually also contain other information
25 such as the name of the application that made the request, whether or
26 not the requesting application can accept a compressed reply, POST
27 parameters from forms, and so forth.
28
29 The job of the web server is to interpret the HTTP request and formulate
30 an appropriate reply.
31 The web server is free to interpret the HTTP request in any way it wants,
32 but most web servers follow a similar pattern, described below.
33 (Note: details may vary from one web server to another.)
34
35 Suppose the filename component of the URL in the HTTP request looks like this:
36
37 <pre>/one/two/timeline/four</pre>
38
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -37,11 +37,11 @@
3737
The [./makefile.wiki|Makefile] for Fossil takes care of running these
3838
preprocessors with all the right arguments and in the right order. So it is
3939
not necessary to understand the details of how these preprocessors work.
4040
(Though, the sources for all three preprocessors are included in the source
4141
tree and are well commented, if you want to dig deeper.) It is only necessary
42
-to know that these preprocessors exist and hence will effect the way you
42
+to know that these preprocessors exist and hence will affect the way you
4343
write code.
4444
4545
<h2>3.0 Adding New Source Code Files</h2>
4646
4747
New source code files are added in the "src/" subdirectory of the Fossil
@@ -98,11 +98,11 @@
9898
files. See [../tools/makeheaders.html | makeheaders.html] for additional
9999
information.
100100
101101
After creating a template file such as shown above, and after updating
102102
the makefiles, you should be able to recompile Fossil and have it include
103
-your new source file, even before you source file contains any code.
103
+your new source file, even before your source file contains any code.
104104
It is recommended that you try this.
105105
106106
Be sure to [/help/add|fossil add] your new source file to the self-hosting
107107
Fossil repository and then [/help/commit|commit] your changes!
108108
@@ -212,11 +212,11 @@
212212
non-HTML content. In the unlikely event that you need to generate
213213
non-HTML content, look at existing webpage implementations
214214
(ex: "logo" or "style.css") to see how that is done.
215215
216216
There are lots of other things that a real web-page implementation will
217
-need to do, such verifying user credentials, parsing query parameters,
217
+need to do, such as verifying user credentials, parsing query parameters,
218218
and interacting with the repository. But now that you have the general
219219
idea of how webpages are implemented, you can look at the many other
220220
webpage implementations already built into Fossil to see how all that
221221
works.
222222
223223
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -37,11 +37,11 @@
37 The [./makefile.wiki|Makefile] for Fossil takes care of running these
38 preprocessors with all the right arguments and in the right order. So it is
39 not necessary to understand the details of how these preprocessors work.
40 (Though, the sources for all three preprocessors are included in the source
41 tree and are well commented, if you want to dig deeper.) It is only necessary
42 to know that these preprocessors exist and hence will effect the way you
43 write code.
44
45 <h2>3.0 Adding New Source Code Files</h2>
46
47 New source code files are added in the "src/" subdirectory of the Fossil
@@ -98,11 +98,11 @@
98 files. See [../tools/makeheaders.html | makeheaders.html] for additional
99 information.
100
101 After creating a template file such as shown above, and after updating
102 the makefiles, you should be able to recompile Fossil and have it include
103 your new source file, even before you source file contains any code.
104 It is recommended that you try this.
105
106 Be sure to [/help/add|fossil add] your new source file to the self-hosting
107 Fossil repository and then [/help/commit|commit] your changes!
108
@@ -212,11 +212,11 @@
212 non-HTML content. In the unlikely event that you need to generate
213 non-HTML content, look at existing webpage implementations
214 (ex: "logo" or "style.css") to see how that is done.
215
216 There are lots of other things that a real web-page implementation will
217 need to do, such verifying user credentials, parsing query parameters,
218 and interacting with the repository. But now that you have the general
219 idea of how webpages are implemented, you can look at the many other
220 webpage implementations already built into Fossil to see how all that
221 works.
222
223
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -37,11 +37,11 @@
37 The [./makefile.wiki|Makefile] for Fossil takes care of running these
38 preprocessors with all the right arguments and in the right order. So it is
39 not necessary to understand the details of how these preprocessors work.
40 (Though, the sources for all three preprocessors are included in the source
41 tree and are well commented, if you want to dig deeper.) It is only necessary
42 to know that these preprocessors exist and hence will affect the way you
43 write code.
44
45 <h2>3.0 Adding New Source Code Files</h2>
46
47 New source code files are added in the "src/" subdirectory of the Fossil
@@ -98,11 +98,11 @@
98 files. See [../tools/makeheaders.html | makeheaders.html] for additional
99 information.
100
101 After creating a template file such as shown above, and after updating
102 the makefiles, you should be able to recompile Fossil and have it include
103 your new source file, even before your source file contains any code.
104 It is recommended that you try this.
105
106 Be sure to [/help/add|fossil add] your new source file to the self-hosting
107 Fossil repository and then [/help/commit|commit] your changes!
108
@@ -212,11 +212,11 @@
212 non-HTML content. In the unlikely event that you need to generate
213 non-HTML content, look at existing webpage implementations
214 (ex: "logo" or "style.css") to see how that is done.
215
216 There are lots of other things that a real web-page implementation will
217 need to do, such as verifying user credentials, parsing query parameters,
218 and interacting with the repository. But now that you have the general
219 idea of how webpages are implemented, you can look at the many other
220 webpage implementations already built into Fossil to see how all that
221 works.
222
223
+2 -2
--- www/alerts.md
+++ www/alerts.md
@@ -311,11 +311,11 @@
311311
## Advanced Email Setups
312312
313313
Fossil offers several methods of sending email:
314314
315315
1. Pipe the email message text into a command.
316
- 2. Store email messages as entries in a SQLite database.
316
+ 2. Store email messages as entries in an SQLite database.
317317
3. Store email messages as individual files in a directory.
318318
4. Send emails to an SMTP relay.
319319
5. Send emails directly to the recipients via SMTP.
320320
321321
This wide range of options allows Fossil to talk to pretty much any
@@ -390,11 +390,11 @@
390390
currently uses this method rather than [the pipe method](#pipe) because
391391
it is running inside of a restrictive [chroot jail][cj] which is unable
392392
to hand off messages to the local MTA directly.
393393
394394
When you configure a Fossil server this way, it adds outgoing email
395
-messages to a SQLite database file. A separate daemon process can then
395
+messages to an SQLite database file. A separate daemon process can then
396396
extract those messages for further disposition.
397397
398398
Fossil includes a copy of [the daemon](/file/tools/email-sender.tcl)
399399
used on `fossil-scm.org`: it is just a short Tcl script that
400400
continuously monitors this database for new messages and hands any that
401401
--- www/alerts.md
+++ www/alerts.md
@@ -311,11 +311,11 @@
311 ## Advanced Email Setups
312
313 Fossil offers several methods of sending email:
314
315 1. Pipe the email message text into a command.
316 2. Store email messages as entries in a SQLite database.
317 3. Store email messages as individual files in a directory.
318 4. Send emails to an SMTP relay.
319 5. Send emails directly to the recipients via SMTP.
320
321 This wide range of options allows Fossil to talk to pretty much any
@@ -390,11 +390,11 @@
390 currently uses this method rather than [the pipe method](#pipe) because
391 it is running inside of a restrictive [chroot jail][cj] which is unable
392 to hand off messages to the local MTA directly.
393
394 When you configure a Fossil server this way, it adds outgoing email
395 messages to a SQLite database file. A separate daemon process can then
396 extract those messages for further disposition.
397
398 Fossil includes a copy of [the daemon](/file/tools/email-sender.tcl)
399 used on `fossil-scm.org`: it is just a short Tcl script that
400 continuously monitors this database for new messages and hands any that
401
--- www/alerts.md
+++ www/alerts.md
@@ -311,11 +311,11 @@
311 ## Advanced Email Setups
312
313 Fossil offers several methods of sending email:
314
315 1. Pipe the email message text into a command.
316 2. Store email messages as entries in an SQLite database.
317 3. Store email messages as individual files in a directory.
318 4. Send emails to an SMTP relay.
319 5. Send emails directly to the recipients via SMTP.
320
321 This wide range of options allows Fossil to talk to pretty much any
@@ -390,11 +390,11 @@
390 currently uses this method rather than [the pipe method](#pipe) because
391 it is running inside of a restrictive [chroot jail][cj] which is unable
392 to hand off messages to the local MTA directly.
393
394 When you configure a Fossil server this way, it adds outgoing email
395 messages to an SQLite database file. A separate daemon process can then
396 extract those messages for further disposition.
397
398 Fossil includes a copy of [the daemon](/file/tools/email-sender.tcl)
399 used on `fossil-scm.org`: it is just a short Tcl script that
400 continuously monitors this database for new messages and hands any that
401
--- www/antibot.wiki
+++ www/antibot.wiki
@@ -73,17 +73,17 @@
7373
In Fossil, under the Admin/Robot-Defense menu, there is a setting entitled
7474
"<b>Enable hyperlinks based on User-Agent and/or Javascript</b>".
7575
If this setting is set to "UserAgent only" or "UserAgent and Javascript",
7676
and if the UserAgent string looks like a human and not a robot, then
7777
Fossil will enable hyperlinks even if the <b>Hyperlink</b> capability
78
-is omitted from the user permissions. This settingn gives humans easy
78
+is omitted from the user permissions. This setting gives humans easy
7979
access to the hyperlinks while preventing robots
8080
from walking the billions of pages on a typical Fossil site.
8181
8282
If the setting is "UserAgent only", then the hyperlinks are simply
8383
enabled and that is all. But if the setting is "UserAgent and Javascript",
84
-then the hyperlinks are not enabled directly .
84
+then the hyperlinks are not enabled directly.
8585
Instead, the HTML code that is generated contains anchor tags ("&lt;a&gt;")
8686
with "href=" attributes that point to [/honeypot] rather than the correct
8787
link. JavaScript code is added to the end of the page that goes back and
8888
fills in the correct "href=" attributes of
8989
the anchor tags with the true hyperlink targets, thus enabling the hyperlinks.
9090
--- www/antibot.wiki
+++ www/antibot.wiki
@@ -73,17 +73,17 @@
73 In Fossil, under the Admin/Robot-Defense menu, there is a setting entitled
74 "<b>Enable hyperlinks based on User-Agent and/or Javascript</b>".
75 If this setting is set to "UserAgent only" or "UserAgent and Javascript",
76 and if the UserAgent string looks like a human and not a robot, then
77 Fossil will enable hyperlinks even if the <b>Hyperlink</b> capability
78 is omitted from the user permissions. This settingn gives humans easy
79 access to the hyperlinks while preventing robots
80 from walking the billions of pages on a typical Fossil site.
81
82 If the setting is "UserAgent only", then the hyperlinks are simply
83 enabled and that is all. But if the setting is "UserAgent and Javascript",
84 then the hyperlinks are not enabled directly .
85 Instead, the HTML code that is generated contains anchor tags ("&lt;a&gt;")
86 with "href=" attributes that point to [/honeypot] rather than the correct
87 link. JavaScript code is added to the end of the page that goes back and
88 fills in the correct "href=" attributes of
89 the anchor tags with the true hyperlink targets, thus enabling the hyperlinks.
90
--- www/antibot.wiki
+++ www/antibot.wiki
@@ -73,17 +73,17 @@
73 In Fossil, under the Admin/Robot-Defense menu, there is a setting entitled
74 "<b>Enable hyperlinks based on User-Agent and/or Javascript</b>".
75 If this setting is set to "UserAgent only" or "UserAgent and Javascript",
76 and if the UserAgent string looks like a human and not a robot, then
77 Fossil will enable hyperlinks even if the <b>Hyperlink</b> capability
78 is omitted from the user permissions. This setting gives humans easy
79 access to the hyperlinks while preventing robots
80 from walking the billions of pages on a typical Fossil site.
81
82 If the setting is "UserAgent only", then the hyperlinks are simply
83 enabled and that is all. But if the setting is "UserAgent and Javascript",
84 then the hyperlinks are not enabled directly.
85 Instead, the HTML code that is generated contains anchor tags ("&lt;a&gt;")
86 with "href=" attributes that point to [/honeypot] rather than the correct
87 link. JavaScript code is added to the end of the page that goes back and
88 fills in the correct "href=" attributes of
89 the anchor tags with the true hyperlink targets, thus enabling the hyperlinks.
90
--- www/backoffice.md
+++ www/backoffice.md
@@ -115,14 +115,14 @@
115115
launching the backoffice for all of them. There are additional useful
116116
command-line options. See the "[fossil backoffice](/help?cmd=backoffice)"
117117
documentation for details.
118118
119119
The backoffice processes run manually using the "fossil backoffice"
120
-command do not normally use a lease. That means that you run the
120
+command do not normally use a lease. That means that if you run the
121121
"fossil backoffice" command with --poll and you forget to disable
122122
automatic backoffice by setting the "backoffice-disable" flag, then
123
-you might have one backoffice running due command and another due
123
+you might have one backoffice running due to a command and another due
124124
to a webpage access, both at the same time. This is harmless. The
125125
only downside is that it uses extra CPU time.
126126
127127
How Backoffice Is Implemented
128128
-----------------------------
@@ -210,11 +210,11 @@
210210
backoffice processes to exit either immediately or after doing whatever
211211
backoffice works needs to be done. If something is going wrong and
212212
backoffice leases are causing delays in webpage processing, then setting
213213
"backoffice-nodelay" to true can work around the problem until the bug
214214
can be fixed. The "backoffice-logfile" setting is the name of a log
215
-file onto which is appended a short message everything a backoffice
215
+file onto which is appended a short message every time a backoffice
216216
process actually starts to do the backoffice work. This log file can
217217
be used to verify that backoffice really is running, if there is any
218218
doubt. The "backoffice-disable" setting prevents automatic backoffice
219219
processing, if true. Use this to completely disable backoffice processing
220220
that occurs automatically after each HTTP request. The "backoffice-disable"
221221
--- www/backoffice.md
+++ www/backoffice.md
@@ -115,14 +115,14 @@
115 launching the backoffice for all of them. There are additional useful
116 command-line options. See the "[fossil backoffice](/help?cmd=backoffice)"
117 documentation for details.
118
119 The backoffice processes run manually using the "fossil backoffice"
120 command do not normally use a lease. That means that you run the
121 "fossil backoffice" command with --poll and you forget to disable
122 automatic backoffice by setting the "backoffice-disable" flag, then
123 you might have one backoffice running due command and another due
124 to a webpage access, both at the same time. This is harmless. The
125 only downside is that it uses extra CPU time.
126
127 How Backoffice Is Implemented
128 -----------------------------
@@ -210,11 +210,11 @@
210 backoffice processes to exit either immediately or after doing whatever
211 backoffice works needs to be done. If something is going wrong and
212 backoffice leases are causing delays in webpage processing, then setting
213 "backoffice-nodelay" to true can work around the problem until the bug
214 can be fixed. The "backoffice-logfile" setting is the name of a log
215 file onto which is appended a short message everything a backoffice
216 process actually starts to do the backoffice work. This log file can
217 be used to verify that backoffice really is running, if there is any
218 doubt. The "backoffice-disable" setting prevents automatic backoffice
219 processing, if true. Use this to completely disable backoffice processing
220 that occurs automatically after each HTTP request. The "backoffice-disable"
221
--- www/backoffice.md
+++ www/backoffice.md
@@ -115,14 +115,14 @@
115 launching the backoffice for all of them. There are additional useful
116 command-line options. See the "[fossil backoffice](/help?cmd=backoffice)"
117 documentation for details.
118
119 The backoffice processes run manually using the "fossil backoffice"
120 command do not normally use a lease. That means that if you run the
121 "fossil backoffice" command with --poll and you forget to disable
122 automatic backoffice by setting the "backoffice-disable" flag, then
123 you might have one backoffice running due to a command and another due
124 to a webpage access, both at the same time. This is harmless. The
125 only downside is that it uses extra CPU time.
126
127 How Backoffice Is Implemented
128 -----------------------------
@@ -210,11 +210,11 @@
210 backoffice processes to exit either immediately or after doing whatever
211 backoffice works needs to be done. If something is going wrong and
212 backoffice leases are causing delays in webpage processing, then setting
213 "backoffice-nodelay" to true can work around the problem until the bug
214 can be fixed. The "backoffice-logfile" setting is the name of a log
215 file onto which is appended a short message every time a backoffice
216 process actually starts to do the backoffice work. This log file can
217 be used to verify that backoffice really is running, if there is any
218 doubt. The "backoffice-disable" setting prevents automatic backoffice
219 processing, if true. Use this to completely disable backoffice processing
220 that occurs automatically after each HTTP request. The "backoffice-disable"
221
+2 -2
--- www/blame.wiki
+++ www/blame.wiki
@@ -19,11 +19,11 @@
1919
annotated. Call this check-in C0.
2020
<li>Find all direct ancestors of C0. A direct ancestor is the closure
2121
of the primary parent of C0. Merged in branches are not part of
2222
the direct ancestors of C0.
2323
<li>Prune the list of ancestors of C0 so that it contains only
24
- check-in in which the file to be annotated was modified.
24
+ check-ins in which the file to be annotated was modified.
2525
<li>Load the complete text of the file to be annotated from check-in C0.
2626
Call this version of the file F0.
2727
<li>Parse F0 into lines. Mark each line as "unchanged".
2828
<li>For each ancestor of C0 on the pruned list (call the ancestor CX),
2929
beginning with the most
@@ -45,11 +45,11 @@
4545
4646
The time-consuming part of this algorithm is step 6b - computing the
4747
diff from all historical versions of the file to the version of the file
4848
under analysis. For a large file that has many historical changes, this
4949
can take several seconds. For this reason, the default
50
-[/help?cmd=/annotate|/annotate] webpage only shows those lines that where
50
+[/help?cmd=/annotate|/annotate] webpage only shows those lines that were
5151
changed by the 20 most recent modifications to the file. This allows
5252
the loop on step 6 to terminate after only 19 diffs instead of the hundreds
5353
or thousands of diffs that might be required for a frequently modified file.
5454
5555
As currently implemented (as of 2015-12-12) the annotate algorithm does not
5656
--- www/blame.wiki
+++ www/blame.wiki
@@ -19,11 +19,11 @@
19 annotated. Call this check-in C0.
20 <li>Find all direct ancestors of C0. A direct ancestor is the closure
21 of the primary parent of C0. Merged in branches are not part of
22 the direct ancestors of C0.
23 <li>Prune the list of ancestors of C0 so that it contains only
24 check-in in which the file to be annotated was modified.
25 <li>Load the complete text of the file to be annotated from check-in C0.
26 Call this version of the file F0.
27 <li>Parse F0 into lines. Mark each line as "unchanged".
28 <li>For each ancestor of C0 on the pruned list (call the ancestor CX),
29 beginning with the most
@@ -45,11 +45,11 @@
45
46 The time-consuming part of this algorithm is step 6b - computing the
47 diff from all historical versions of the file to the version of the file
48 under analysis. For a large file that has many historical changes, this
49 can take several seconds. For this reason, the default
50 [/help?cmd=/annotate|/annotate] webpage only shows those lines that where
51 changed by the 20 most recent modifications to the file. This allows
52 the loop on step 6 to terminate after only 19 diffs instead of the hundreds
53 or thousands of diffs that might be required for a frequently modified file.
54
55 As currently implemented (as of 2015-12-12) the annotate algorithm does not
56
--- www/blame.wiki
+++ www/blame.wiki
@@ -19,11 +19,11 @@
19 annotated. Call this check-in C0.
20 <li>Find all direct ancestors of C0. A direct ancestor is the closure
21 of the primary parent of C0. Merged in branches are not part of
22 the direct ancestors of C0.
23 <li>Prune the list of ancestors of C0 so that it contains only
24 check-ins in which the file to be annotated was modified.
25 <li>Load the complete text of the file to be annotated from check-in C0.
26 Call this version of the file F0.
27 <li>Parse F0 into lines. Mark each line as "unchanged".
28 <li>For each ancestor of C0 on the pruned list (call the ancestor CX),
29 beginning with the most
@@ -45,11 +45,11 @@
45
46 The time-consuming part of this algorithm is step 6b - computing the
47 diff from all historical versions of the file to the version of the file
48 under analysis. For a large file that has many historical changes, this
49 can take several seconds. For this reason, the default
50 [/help?cmd=/annotate|/annotate] webpage only shows those lines that were
51 changed by the 20 most recent modifications to the file. This allows
52 the loop on step 6 to terminate after only 19 diffs instead of the hundreds
53 or thousands of diffs that might be required for a frequently modified file.
54
55 As currently implemented (as of 2015-12-12) the annotate algorithm does not
56
--- www/bugtheory.wiki
+++ www/bugtheory.wiki
@@ -112,13 +112,13 @@
112112
and is not shared with other repositories during a sync, push, or pull.
113113
114114
Each repository also defines scripts used to generate web pages for
115115
creating new tickets, viewing existing tickets, and modifying an
116116
existing ticket. These scripts consist of HTML with an embedded
117
-scripts written a Tcl-like language called "[./th1.md|TH1]". Every new fossil
118
-repository is created with default scripts. Administrators wishing to
119
-customize their ticket entry, viewing, and editing screens should
120
-modify the default scripts to suit their needs. These screen generator
121
-scripts are part of the local state of a repository and are not shared
122
-with other repositories during a sync, push, or pull.
117
+scripts written in a Tcl-like language called "[./th1.md|TH1]". Every
118
+new fossil repository is created with default scripts. Administrators
119
+wishing to customize their ticket entry, viewing, and editing screens
120
+should modify the default scripts to suit their needs. These screen
121
+generator scripts are part of the local state of a repository and are
122
+not shared with other repositories during a sync, push, or pull.
123123
124124
<i>To be continued...</i>
125125
--- www/bugtheory.wiki
+++ www/bugtheory.wiki
@@ -112,13 +112,13 @@
112 and is not shared with other repositories during a sync, push, or pull.
113
114 Each repository also defines scripts used to generate web pages for
115 creating new tickets, viewing existing tickets, and modifying an
116 existing ticket. These scripts consist of HTML with an embedded
117 scripts written a Tcl-like language called "[./th1.md|TH1]". Every new fossil
118 repository is created with default scripts. Administrators wishing to
119 customize their ticket entry, viewing, and editing screens should
120 modify the default scripts to suit their needs. These screen generator
121 scripts are part of the local state of a repository and are not shared
122 with other repositories during a sync, push, or pull.
123
124 <i>To be continued...</i>
125
--- www/bugtheory.wiki
+++ www/bugtheory.wiki
@@ -112,13 +112,13 @@
112 and is not shared with other repositories during a sync, push, or pull.
113
114 Each repository also defines scripts used to generate web pages for
115 creating new tickets, viewing existing tickets, and modifying an
116 existing ticket. These scripts consist of HTML with an embedded
117 scripts written in a Tcl-like language called "[./th1.md|TH1]". Every
118 new fossil repository is created with default scripts. Administrators
119 wishing to customize their ticket entry, viewing, and editing screens
120 should modify the default scripts to suit their needs. These screen
121 generator scripts are part of the local state of a repository and are
122 not shared with other repositories during a sync, push, or pull.
123
124 <i>To be continued...</i>
125
+2 -2
--- www/build.wiki
+++ www/build.wiki
@@ -55,11 +55,11 @@
5555
<h2>Aside: Is it really safe to use an unreleased development version of
5656
the Fossil source code?</h2>
5757
5858
Yes! Any check-in on the
5959
[/timeline?t=trunk | trunk branch] of the Fossil
60
-[https://fossil-scm.org/ | Fossil self-hosting repository]
60
+[https://fossil-scm.org/ | self-hosting repository]
6161
will work fine. (Dodgy code is always on a branch.) In the unlikely
6262
event that you pick a version with a serious bug, it still won't
6363
clobber your files. Fossil uses several
6464
[./selfcheck.wiki | self-checks] prior to committing any
6565
repository change that prevent loss-of-work due to bugs.
@@ -475,11 +475,11 @@
475475
environment variables which are required by <tt>emcc</tt> and will
476476
fail if it cannot do so. Once it's set up the environment, it passes
477477
on all of its arguments to <tt>emcc</tt>.
478478
479479
The WASM-related build parts are set up such that none of them should
480
-ever trigger implicity (e.g. via dependencies resolution) in a normal
480
+ever trigger implicitly (e.g. via dependencies resolution) in a normal
481481
build cycle. They are instead explicitly built as described below.
482482
483483
From the top of the source tree, all WASM-related components can be
484484
built with:
485485
486486
--- www/build.wiki
+++ www/build.wiki
@@ -55,11 +55,11 @@
55 <h2>Aside: Is it really safe to use an unreleased development version of
56 the Fossil source code?</h2>
57
58 Yes! Any check-in on the
59 [/timeline?t=trunk | trunk branch] of the Fossil
60 [https://fossil-scm.org/ | Fossil self-hosting repository]
61 will work fine. (Dodgy code is always on a branch.) In the unlikely
62 event that you pick a version with a serious bug, it still won't
63 clobber your files. Fossil uses several
64 [./selfcheck.wiki | self-checks] prior to committing any
65 repository change that prevent loss-of-work due to bugs.
@@ -475,11 +475,11 @@
475 environment variables which are required by <tt>emcc</tt> and will
476 fail if it cannot do so. Once it's set up the environment, it passes
477 on all of its arguments to <tt>emcc</tt>.
478
479 The WASM-related build parts are set up such that none of them should
480 ever trigger implicity (e.g. via dependencies resolution) in a normal
481 build cycle. They are instead explicitly built as described below.
482
483 From the top of the source tree, all WASM-related components can be
484 built with:
485
486
--- www/build.wiki
+++ www/build.wiki
@@ -55,11 +55,11 @@
55 <h2>Aside: Is it really safe to use an unreleased development version of
56 the Fossil source code?</h2>
57
58 Yes! Any check-in on the
59 [/timeline?t=trunk | trunk branch] of the Fossil
60 [https://fossil-scm.org/ | self-hosting repository]
61 will work fine. (Dodgy code is always on a branch.) In the unlikely
62 event that you pick a version with a serious bug, it still won't
63 clobber your files. Fossil uses several
64 [./selfcheck.wiki | self-checks] prior to committing any
65 repository change that prevent loss-of-work due to bugs.
@@ -475,11 +475,11 @@
475 environment variables which are required by <tt>emcc</tt> and will
476 fail if it cannot do so. Once it's set up the environment, it passes
477 on all of its arguments to <tt>emcc</tt>.
478
479 The WASM-related build parts are set up such that none of them should
480 ever trigger implicitly (e.g. via dependencies resolution) in a normal
481 build cycle. They are instead explicitly built as described below.
482
483 From the top of the source tree, all WASM-related components can be
484 built with:
485
486
--- www/caps/index.md
+++ www/caps/index.md
@@ -294,11 +294,11 @@
294294
Fossil requires write access to a repo DB while cloning from it, so you
295295
can’t clone from a read-only repo DB file over a local file path.
296296
297297
Even more surprising to you may be the fact that user caps do not affect
298298
cloning and syncing over SSH! (Not unless you go [out of your way][sshfc]
299
-patch around it, at any rate.) When you make a change to such a
299
+to patch around it, at any rate.) When you make a change to such a
300300
repository, the stock Fossil behavior is that the change first goes to the
301301
local repo clone where file system
302302
permissions are all that matter, but then upon sync, the situation is
303303
effectively the same as when the parent repo is on the local file
304304
system. The reason behind this is that if you can log into the remote
305305
--- www/caps/index.md
+++ www/caps/index.md
@@ -294,11 +294,11 @@
294 Fossil requires write access to a repo DB while cloning from it, so you
295 can’t clone from a read-only repo DB file over a local file path.
296
297 Even more surprising to you may be the fact that user caps do not affect
298 cloning and syncing over SSH! (Not unless you go [out of your way][sshfc]
299 patch around it, at any rate.) When you make a change to such a
300 repository, the stock Fossil behavior is that the change first goes to the
301 local repo clone where file system
302 permissions are all that matter, but then upon sync, the situation is
303 effectively the same as when the parent repo is on the local file
304 system. The reason behind this is that if you can log into the remote
305
--- www/caps/index.md
+++ www/caps/index.md
@@ -294,11 +294,11 @@
294 Fossil requires write access to a repo DB while cloning from it, so you
295 can’t clone from a read-only repo DB file over a local file path.
296
297 Even more surprising to you may be the fact that user caps do not affect
298 cloning and syncing over SSH! (Not unless you go [out of your way][sshfc]
299 to patch around it, at any rate.) When you make a change to such a
300 repository, the stock Fossil behavior is that the change first goes to the
301 local repo clone where file system
302 permissions are all that matter, but then upon sync, the situation is
303 effectively the same as when the parent repo is on the local file
304 system. The reason behind this is that if you can log into the remote
305
--- www/caps/ref.html
+++ www/caps/ref.html
@@ -252,11 +252,11 @@
252252
Create new ticket report formats. Note that although this allows
253253
the user to provide SQL code to be run in the server’s context,
254254
and this capability is given to the untrusted “anonymous” user
255255
category by default, this is a safe capability to give to users
256256
because it is internally restricted to read-only queries on the
257
- tickets table only. (This restriction is done with a SQLite
257
+ tickets table only. (This restriction is done with an SQLite
258258
authorization hook, not by any method so weak as SQL text
259259
filtering.) Mnemonic: new <b>t</b>icket report.
260260
</td>
261261
</tr>
262262
263263
--- www/caps/ref.html
+++ www/caps/ref.html
@@ -252,11 +252,11 @@
252 Create new ticket report formats. Note that although this allows
253 the user to provide SQL code to be run in the server’s context,
254 and this capability is given to the untrusted “anonymous” user
255 category by default, this is a safe capability to give to users
256 because it is internally restricted to read-only queries on the
257 tickets table only. (This restriction is done with a SQLite
258 authorization hook, not by any method so weak as SQL text
259 filtering.) Mnemonic: new <b>t</b>icket report.
260 </td>
261 </tr>
262
263
--- www/caps/ref.html
+++ www/caps/ref.html
@@ -252,11 +252,11 @@
252 Create new ticket report formats. Note that although this allows
253 the user to provide SQL code to be run in the server’s context,
254 and this capability is given to the untrusted “anonymous” user
255 category by default, this is a safe capability to give to users
256 because it is internally restricted to read-only queries on the
257 tickets table only. (This restriction is done with an SQLite
258 authorization hook, not by any method so weak as SQL text
259 filtering.) Mnemonic: new <b>t</b>icket report.
260 </td>
261 </tr>
262
263
+2 -2
--- www/cgi.wiki
+++ www/cgi.wiki
@@ -13,11 +13,11 @@
1313
setting up a Fossil server, one of which is [./server/any/cgi.md | as a CGI
1414
script]. CGI is the technique that the three
1515
[./selfhost.wiki|self-hosting Fossil repositories] all use.
1616
1717
Setting up a Fossil server using CGI is mostly about writing a short
18
-script (usually just 2 lines line) in the cgi-bin folder of an ordinary
18
+script (usually just 2 lines) in the cgi-bin folder of an ordinary
1919
web-server. But there are a lot of extra options that can be added
2020
to this script, to customize the configuration. This article describes
2121
those options.
2222
2323
<h1>CGI Script Options</h1>
@@ -191,11 +191,11 @@
191191
192192
193193
<h2 id="mainmenu">mainmenu: <i>FILE</i></h2>
194194
195195
This parameter causes the contents of the given file to override the
196
-site's <tt>mainmenu</tt> configuration setting, much in the same way
196
+site's <tt>mainmenu</tt> configuration setting, in much the same way
197197
that the <tt>skin</tt> setting overrides the skin. This can be used to
198198
apply a common main menu to a number of sites, and centrally maintain
199199
it, without having to copy its contents into each site. Note, however,
200200
that the contents of this setting are not stored in the repository and
201201
will not be cloned along with the repository.
202202
--- www/cgi.wiki
+++ www/cgi.wiki
@@ -13,11 +13,11 @@
13 setting up a Fossil server, one of which is [./server/any/cgi.md | as a CGI
14 script]. CGI is the technique that the three
15 [./selfhost.wiki|self-hosting Fossil repositories] all use.
16
17 Setting up a Fossil server using CGI is mostly about writing a short
18 script (usually just 2 lines line) in the cgi-bin folder of an ordinary
19 web-server. But there are a lot of extra options that can be added
20 to this script, to customize the configuration. This article describes
21 those options.
22
23 <h1>CGI Script Options</h1>
@@ -191,11 +191,11 @@
191
192
193 <h2 id="mainmenu">mainmenu: <i>FILE</i></h2>
194
195 This parameter causes the contents of the given file to override the
196 site's <tt>mainmenu</tt> configuration setting, much in the same way
197 that the <tt>skin</tt> setting overrides the skin. This can be used to
198 apply a common main menu to a number of sites, and centrally maintain
199 it, without having to copy its contents into each site. Note, however,
200 that the contents of this setting are not stored in the repository and
201 will not be cloned along with the repository.
202
--- www/cgi.wiki
+++ www/cgi.wiki
@@ -13,11 +13,11 @@
13 setting up a Fossil server, one of which is [./server/any/cgi.md | as a CGI
14 script]. CGI is the technique that the three
15 [./selfhost.wiki|self-hosting Fossil repositories] all use.
16
17 Setting up a Fossil server using CGI is mostly about writing a short
18 script (usually just 2 lines) in the cgi-bin folder of an ordinary
19 web-server. But there are a lot of extra options that can be added
20 to this script, to customize the configuration. This article describes
21 those options.
22
23 <h1>CGI Script Options</h1>
@@ -191,11 +191,11 @@
191
192
193 <h2 id="mainmenu">mainmenu: <i>FILE</i></h2>
194
195 This parameter causes the contents of the given file to override the
196 site's <tt>mainmenu</tt> configuration setting, in much the same way
197 that the <tt>skin</tt> setting overrides the skin. This can be used to
198 apply a common main menu to a number of sites, and centrally maintain
199 it, without having to copy its contents into each site. Note, however,
200 that the contents of this setting are not stored in the repository and
201 will not be cloned along with the repository.
202
+26 -4
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,8 +1,22 @@
11
<title>Change Log</title>
22
3
-<h2 id='v2_25'>Changes for version 2.25 (pending)</h2>
3
+<h2 id='v2_26'>Changes for version 2.26 (pending)</h2>
4
+
5
+ * Added the [/help?cmd=/ckout|/ckout web page] to provide information
6
+ about pending changes in a working check-out
7
+ * The [/help?cmd=ui|fossil ui] command defaults to using the /ckout
8
+ page as its start page.
9
+ * Added the [/help?cmd=merge-info|fossil merge-info] command and especially
10
+ the --tk option to that command, to provide analysis of the most recent
11
+ merge or update operation.
12
+ * Issue a warning if a user tries to commit on a check-in where the
13
+ branch has been changed.
14
+ * When a merge conflict occurs, a new section is added to the conflict
15
+ text that shows Fossil's suggested resolution to the conflict.
16
+
17
+<h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
418
519
* The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
620
that have non-ASCII filenames
721
* Add the [/help?cmd=tree|fossil tree] command.
822
* On case-insensitive filesystems, store files using the filesystem's
@@ -11,12 +25,21 @@
1125
which is more familiar to Git users. Retain the legacy name for
1226
compatibility.
1327
* Add new query parameters to the [/help?cmd=/timeline|/timeline page]:
1428
d2=, p2=, and dp2=.
1529
* Add options to the [/help?cmd=tag|fossil tag] command that will list tag values.
30
+ * Add the -b|--brief option to the [/help?cmd=status|fossil status] command.
1631
* Add ability to upload unversioned files via the [/help?cmd=/uvlist|/uvlist page].
1732
* Add history search to the [/help?cmd=/chat|/chat page].
33
+ * Add Unix socket support to the [/help?cmd=server|server command].
34
+ * On Windows, use the root certificates managed by the operating system
35
+ (requires OpenSSL 3.2.0 or greater).
36
+ * Take into account zero-width and double-width unicode characters when
37
+ formatting the command-line timeline.
38
+ * Update the built-in SQLite to version 3.47.0. Precompiled binaries are
39
+ linked against OpenSSL 3.4.0.
40
+ * Numerous minor fixes and additions.
1841
1942
2043
<h2 id='v2_24'>Changes for version 2.24 (2024-04-23)</h2>
2144
2245
* Apache change work-around &rarr; As part of a security fix, the Apache webserver
@@ -85,11 +108,11 @@
85108
* Add ability to "close" forum threads, such that unprivileged users
86109
may no longer respond to them. Only administrators can close
87110
threads or respond to them by default, and the
88111
[/help?cmd=forum-close-policy|forum-close-policy setting] can be
89112
used to add that capability to moderators.
90
- * Add the [/help?cmd=all|fossil all whatis] command.
113
+ * Add the [/help?cmd=all|fossil all whatis] command.
91114
* The [/help?cmd=status|fossil status] command and relevant UI pages now
92115
correctly report files which were both renamed <b>and</b> edited as such.
93116
* Show default value of settings that have a default in
94117
[/help?cmd=help|fossil help SETTING] output.
95118
* On timeline graphs, show closed check-ins using an X in the middle of the
@@ -127,11 +150,10 @@
127150
they work when the "remote" machine is a Mac and the "fossil"
128151
executable is in the $HOME/bin directory.
129152
</ul>
130153
* Update built-in libraries SQLite, ZLib, Pikchr to their latest versions.
131154
* Documentation enhancements and typo fixes.
132
-
133155
134156
135157
<h2 id='v2_22'>Changes for version 2.22 (2023-05-31)</h2>
136158
* Enhancements to the [/help?cmd=/timeline|/timeline webpage]: <ol type="a">
137159
<li> Add the ft=TAG query parameter which in combination with d=Y
@@ -155,11 +177,11 @@
155177
frees us from needing to build and install the container as root,
156178
since it no longer has to create a private <tt>/dev</tt> tree
157179
inside the jail for Fossil's use.
158180
* Add support for the trigram tokenizer for FTS5 search to enable
159181
searching in Chinese.
160
- * Comment lines (starting with a '#') are now supported inside
182
+ * Comment lines (starting with a '#') are now supported inside
161183
[./settings.wiki#versionable|versioned settings].
162184
* Default permissions for anonymous users in new repositories are
163185
changed to "hz".
164186
* The [/help?cmd=status|fossil status] command now detects when a
165187
file used to be a symlink and has been replaced by a regular file.
166188
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,8 +1,22 @@
1 <title>Change Log</title>
2
3 <h2 id='v2_25'>Changes for version 2.25 (pending)</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
5 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
6 that have non-ASCII filenames
7 * Add the [/help?cmd=tree|fossil tree] command.
8 * On case-insensitive filesystems, store files using the filesystem's
@@ -11,12 +25,21 @@
11 which is more familiar to Git users. Retain the legacy name for
12 compatibility.
13 * Add new query parameters to the [/help?cmd=/timeline|/timeline page]:
14 d2=, p2=, and dp2=.
15 * Add options to the [/help?cmd=tag|fossil tag] command that will list tag values.
 
16 * Add ability to upload unversioned files via the [/help?cmd=/uvlist|/uvlist page].
17 * Add history search to the [/help?cmd=/chat|/chat page].
 
 
 
 
 
 
 
 
18
19
20 <h2 id='v2_24'>Changes for version 2.24 (2024-04-23)</h2>
21
22 * Apache change work-around &rarr; As part of a security fix, the Apache webserver
@@ -85,11 +108,11 @@
85 * Add ability to "close" forum threads, such that unprivileged users
86 may no longer respond to them. Only administrators can close
87 threads or respond to them by default, and the
88 [/help?cmd=forum-close-policy|forum-close-policy setting] can be
89 used to add that capability to moderators.
90 * Add the [/help?cmd=all|fossil all whatis] command.
91 * The [/help?cmd=status|fossil status] command and relevant UI pages now
92 correctly report files which were both renamed <b>and</b> edited as such.
93 * Show default value of settings that have a default in
94 [/help?cmd=help|fossil help SETTING] output.
95 * On timeline graphs, show closed check-ins using an X in the middle of the
@@ -127,11 +150,10 @@
127 they work when the "remote" machine is a Mac and the "fossil"
128 executable is in the $HOME/bin directory.
129 </ul>
130 * Update built-in libraries SQLite, ZLib, Pikchr to their latest versions.
131 * Documentation enhancements and typo fixes.
132
133
134
135 <h2 id='v2_22'>Changes for version 2.22 (2023-05-31)</h2>
136 * Enhancements to the [/help?cmd=/timeline|/timeline webpage]: <ol type="a">
137 <li> Add the ft=TAG query parameter which in combination with d=Y
@@ -155,11 +177,11 @@
155 frees us from needing to build and install the container as root,
156 since it no longer has to create a private <tt>/dev</tt> tree
157 inside the jail for Fossil's use.
158 * Add support for the trigram tokenizer for FTS5 search to enable
159 searching in Chinese.
160 * Comment lines (starting with a '#') are now supported inside
161 [./settings.wiki#versionable|versioned settings].
162 * Default permissions for anonymous users in new repositories are
163 changed to "hz".
164 * The [/help?cmd=status|fossil status] command now detects when a
165 file used to be a symlink and has been replaced by a regular file.
166
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,8 +1,22 @@
1 <title>Change Log</title>
2
3 <h2 id='v2_26'>Changes for version 2.26 (pending)</h2>
4
5 * Added the [/help?cmd=/ckout|/ckout web page] to provide information
6 about pending changes in a working check-out
7 * The [/help?cmd=ui|fossil ui] command defaults to using the /ckout
8 page as its start page.
9 * Added the [/help?cmd=merge-info|fossil merge-info] command and especially
10 the --tk option to that command, to provide analysis of the most recent
11 merge or update operation.
12 * Issue a warning if a user tries to commit on a check-in where the
13 branch has been changed.
14 * When a merge conflict occurs, a new section is added to the conflict
15 text that shows Fossil's suggested resolution to the conflict.
16
17 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
18
19 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
20 that have non-ASCII filenames
21 * Add the [/help?cmd=tree|fossil tree] command.
22 * On case-insensitive filesystems, store files using the filesystem's
@@ -11,12 +25,21 @@
25 which is more familiar to Git users. Retain the legacy name for
26 compatibility.
27 * Add new query parameters to the [/help?cmd=/timeline|/timeline page]:
28 d2=, p2=, and dp2=.
29 * Add options to the [/help?cmd=tag|fossil tag] command that will list tag values.
30 * Add the -b|--brief option to the [/help?cmd=status|fossil status] command.
31 * Add ability to upload unversioned files via the [/help?cmd=/uvlist|/uvlist page].
32 * Add history search to the [/help?cmd=/chat|/chat page].
33 * Add Unix socket support to the [/help?cmd=server|server command].
34 * On Windows, use the root certificates managed by the operating system
35 (requires OpenSSL 3.2.0 or greater).
36 * Take into account zero-width and double-width unicode characters when
37 formatting the command-line timeline.
38 * Update the built-in SQLite to version 3.47.0. Precompiled binaries are
39 linked against OpenSSL 3.4.0.
40 * Numerous minor fixes and additions.
41
42
43 <h2 id='v2_24'>Changes for version 2.24 (2024-04-23)</h2>
44
45 * Apache change work-around &rarr; As part of a security fix, the Apache webserver
@@ -85,11 +108,11 @@
108 * Add ability to "close" forum threads, such that unprivileged users
109 may no longer respond to them. Only administrators can close
110 threads or respond to them by default, and the
111 [/help?cmd=forum-close-policy|forum-close-policy setting] can be
112 used to add that capability to moderators.
113 * Add the [/help?cmd=all|fossil all whatis] command.
114 * The [/help?cmd=status|fossil status] command and relevant UI pages now
115 correctly report files which were both renamed <b>and</b> edited as such.
116 * Show default value of settings that have a default in
117 [/help?cmd=help|fossil help SETTING] output.
118 * On timeline graphs, show closed check-ins using an X in the middle of the
@@ -127,11 +150,10 @@
150 they work when the "remote" machine is a Mac and the "fossil"
151 executable is in the $HOME/bin directory.
152 </ul>
153 * Update built-in libraries SQLite, ZLib, Pikchr to their latest versions.
154 * Documentation enhancements and typo fixes.
 
155
156
157 <h2 id='v2_22'>Changes for version 2.22 (2023-05-31)</h2>
158 * Enhancements to the [/help?cmd=/timeline|/timeline webpage]: <ol type="a">
159 <li> Add the ft=TAG query parameter which in combination with d=Y
@@ -155,11 +177,11 @@
177 frees us from needing to build and install the container as root,
178 since it no longer has to create a private <tt>/dev</tt> tree
179 inside the jail for Fossil's use.
180 * Add support for the trigram tokenizer for FTS5 search to enable
181 searching in Chinese.
182 * Comment lines (starting with a '#') are now supported inside
183 [./settings.wiki#versionable|versioned settings].
184 * Default permissions for anonymous users in new repositories are
185 changed to "hz".
186 * The [/help?cmd=status|fossil status] command now detects when a
187 file used to be a symlink and has been replaced by a regular file.
188
+2 -2
--- www/chat.md
+++ www/chat.md
@@ -155,11 +155,11 @@
155155
Substitute the appropriate project URL, robot account
156156
name and password, message text and file attachment, of course.
157157
158158
### <a id="chat-robot"></a> Chat Messages For Timeline Events
159159
160
-If the [chat-timeline-user setting](/help?cmd=chat-timeline-user) is not a
160
+If the [chat-timeline-user setting](/help?cmd=chat-timeline-user) is not an
161161
empty string, then any change to the repository that would normally result
162162
in a new timeline entry is announced in the chatroom. The announcement
163163
appears to come from a user whose name is given by the chat-timeline-user
164164
setting.
165165
@@ -193,11 +193,11 @@
193193
* [/chat-delete](/help?name=/chat-delete) &rarr;
194194
Deletes a chat message.
195195
196196
Fossil chat uses the venerable "hanging GET" or
197197
"[long polling](wikipedia:/wiki/Push_technology#Long_polling)"
198
-technique to recieve asynchronous notification of new messages.
198
+technique to receive asynchronous notification of new messages.
199199
This is done because long polling works well with CGI and SCGI,
200200
which are the usual mechanisms for setting up a Fossil server.
201201
More advanced notification techniques such as
202202
[Server-sent events](wikipedia:/wiki/Server-sent_events) and especially
203203
[WebSockets](wikipedia:/wiki/WebSocket) might seem more appropriate for
204204
--- www/chat.md
+++ www/chat.md
@@ -155,11 +155,11 @@
155 Substitute the appropriate project URL, robot account
156 name and password, message text and file attachment, of course.
157
158 ### <a id="chat-robot"></a> Chat Messages For Timeline Events
159
160 If the [chat-timeline-user setting](/help?cmd=chat-timeline-user) is not a
161 empty string, then any change to the repository that would normally result
162 in a new timeline entry is announced in the chatroom. The announcement
163 appears to come from a user whose name is given by the chat-timeline-user
164 setting.
165
@@ -193,11 +193,11 @@
193 * [/chat-delete](/help?name=/chat-delete) &rarr;
194 Deletes a chat message.
195
196 Fossil chat uses the venerable "hanging GET" or
197 "[long polling](wikipedia:/wiki/Push_technology#Long_polling)"
198 technique to recieve asynchronous notification of new messages.
199 This is done because long polling works well with CGI and SCGI,
200 which are the usual mechanisms for setting up a Fossil server.
201 More advanced notification techniques such as
202 [Server-sent events](wikipedia:/wiki/Server-sent_events) and especially
203 [WebSockets](wikipedia:/wiki/WebSocket) might seem more appropriate for
204
--- www/chat.md
+++ www/chat.md
@@ -155,11 +155,11 @@
155 Substitute the appropriate project URL, robot account
156 name and password, message text and file attachment, of course.
157
158 ### <a id="chat-robot"></a> Chat Messages For Timeline Events
159
160 If the [chat-timeline-user setting](/help?cmd=chat-timeline-user) is not an
161 empty string, then any change to the repository that would normally result
162 in a new timeline entry is announced in the chatroom. The announcement
163 appears to come from a user whose name is given by the chat-timeline-user
164 setting.
165
@@ -193,11 +193,11 @@
193 * [/chat-delete](/help?name=/chat-delete) &rarr;
194 Deletes a chat message.
195
196 Fossil chat uses the venerable "hanging GET" or
197 "[long polling](wikipedia:/wiki/Push_technology#Long_polling)"
198 technique to receive asynchronous notification of new messages.
199 This is done because long polling works well with CGI and SCGI,
200 which are the usual mechanisms for setting up a Fossil server.
201 More advanced notification techniques such as
202 [Server-sent events](wikipedia:/wiki/Server-sent_events) and especially
203 [WebSockets](wikipedia:/wiki/WebSocket) might seem more appropriate for
204
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -246,11 +246,11 @@
246246
247247
<pre>
248248
fossil info merge-in:xyzzy:2022-03-01
249249
</pre>
250250
251
-to get informations about the most recent merge-in point on the branch
251
+to get information about the most recent merge-in point on the branch
252252
"xyzzy" that happened on or before March 1, 2022.
253253
254254
<h2 id="special">Special Tags</h2>
255255
256256
The tag "tip" means the most recent check-in. The "tip" tag is practically
257257
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -246,11 +246,11 @@
246
247 <pre>
248 fossil info merge-in:xyzzy:2022-03-01
249 </pre>
250
251 to get informations about the most recent merge-in point on the branch
252 "xyzzy" that happened on or before March 1, 2022.
253
254 <h2 id="special">Special Tags</h2>
255
256 The tag "tip" means the most recent check-in. The "tip" tag is practically
257
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -246,11 +246,11 @@
246
247 <pre>
248 fossil info merge-in:xyzzy:2022-03-01
249 </pre>
250
251 to get information about the most recent merge-in point on the branch
252 "xyzzy" that happened on or before March 1, 2022.
253
254 <h2 id="special">Special Tags</h2>
255
256 The tag "tip" means the most recent check-in. The "tip" tag is practically
257
--- www/concepts.wiki
+++ www/concepts.wiki
@@ -163,11 +163,11 @@
163163
The manifest file is not normally a real file on disk. Instead,
164164
the manifest is computed in memory by Fossil whenever it needs it.
165165
However, the "fossil setting manifest on" command will cause the
166166
manifest file to be materialized to disk, if desired. Both Fossil
167167
itself, and SQLite cause the manifest file to be materialized to disk
168
-so that the makefiles for these project can read the manifest and
168
+so that the makefiles for these projects can read the manifest and
169169
embed version information in generated binaries.
170170
171171
Fossil automatically generates a manifest whenever you "commit"
172172
a new check-in. So this is not something that you, the developer,
173173
need to worry with. The format of a manifest is intentionally
@@ -178,11 +178,11 @@
178178
179179
In addition to identifying all files in the check-in, a
180180
manifest also contains a check-in comment, the date and time
181181
when the check-in was established, who created the check-in,
182182
and links to other check-ins from which the current check-in
183
-is derived. There is also a couple of checksums used to verify
183
+is derived. There are also a couple of checksums used to verify
184184
the integrity of the check-in. And the whole manifest might
185185
be PGP clearsigned.
186186
187187
<h3 id="keyconc">2.3 Key concepts</h3>
188188
@@ -217,11 +217,11 @@
217217
SQLite, patch, or any similar software on your system in order to use
218218
Fossil effectively. You will want to have some kind of text editor
219219
for entering check-in comments. Fossil will use whatever text editor
220220
is identified by your VISUAL environment variable. Fossil will also
221221
use GPG to clearsign your manifests if you happen to have it installed,
222
-but Fossil will skip that step if GPG missing from your system.
222
+but Fossil will skip that step if GPG is missing from your system.
223223
You can optionally set up Fossil to use external "diff" programs,
224224
though Fossil has an excellent built-in "diff" algorithm that works
225225
fine for most people. If you happen to have Tcl/Tk installed on your
226226
system, Fossil will use it to generate a graphical "diff" display when
227227
you use the --tk option to the "diff" command, but this too is entirely
@@ -286,11 +286,11 @@
286286
fossil setting autosync off
287287
fossil settings
288288
</pre>
289289
290290
By default, Fossil runs with autosync mode turned on. The
291
-authors finds that projects run more smoothly in autosync mode since
291
+authors find that projects run more smoothly in autosync mode since
292292
autosync helps to prevent pointless forking and merging and helps keeps
293293
all collaborators working on exactly the same code rather than on their
294294
own personal forks of the code. In the author's view, manual-merge mode
295295
should be reserved for disconnected operation.
296296
297297
--- www/concepts.wiki
+++ www/concepts.wiki
@@ -163,11 +163,11 @@
163 The manifest file is not normally a real file on disk. Instead,
164 the manifest is computed in memory by Fossil whenever it needs it.
165 However, the "fossil setting manifest on" command will cause the
166 manifest file to be materialized to disk, if desired. Both Fossil
167 itself, and SQLite cause the manifest file to be materialized to disk
168 so that the makefiles for these project can read the manifest and
169 embed version information in generated binaries.
170
171 Fossil automatically generates a manifest whenever you "commit"
172 a new check-in. So this is not something that you, the developer,
173 need to worry with. The format of a manifest is intentionally
@@ -178,11 +178,11 @@
178
179 In addition to identifying all files in the check-in, a
180 manifest also contains a check-in comment, the date and time
181 when the check-in was established, who created the check-in,
182 and links to other check-ins from which the current check-in
183 is derived. There is also a couple of checksums used to verify
184 the integrity of the check-in. And the whole manifest might
185 be PGP clearsigned.
186
187 <h3 id="keyconc">2.3 Key concepts</h3>
188
@@ -217,11 +217,11 @@
217 SQLite, patch, or any similar software on your system in order to use
218 Fossil effectively. You will want to have some kind of text editor
219 for entering check-in comments. Fossil will use whatever text editor
220 is identified by your VISUAL environment variable. Fossil will also
221 use GPG to clearsign your manifests if you happen to have it installed,
222 but Fossil will skip that step if GPG missing from your system.
223 You can optionally set up Fossil to use external "diff" programs,
224 though Fossil has an excellent built-in "diff" algorithm that works
225 fine for most people. If you happen to have Tcl/Tk installed on your
226 system, Fossil will use it to generate a graphical "diff" display when
227 you use the --tk option to the "diff" command, but this too is entirely
@@ -286,11 +286,11 @@
286 fossil setting autosync off
287 fossil settings
288 </pre>
289
290 By default, Fossil runs with autosync mode turned on. The
291 authors finds that projects run more smoothly in autosync mode since
292 autosync helps to prevent pointless forking and merging and helps keeps
293 all collaborators working on exactly the same code rather than on their
294 own personal forks of the code. In the author's view, manual-merge mode
295 should be reserved for disconnected operation.
296
297
--- www/concepts.wiki
+++ www/concepts.wiki
@@ -163,11 +163,11 @@
163 The manifest file is not normally a real file on disk. Instead,
164 the manifest is computed in memory by Fossil whenever it needs it.
165 However, the "fossil setting manifest on" command will cause the
166 manifest file to be materialized to disk, if desired. Both Fossil
167 itself, and SQLite cause the manifest file to be materialized to disk
168 so that the makefiles for these projects can read the manifest and
169 embed version information in generated binaries.
170
171 Fossil automatically generates a manifest whenever you "commit"
172 a new check-in. So this is not something that you, the developer,
173 need to worry with. The format of a manifest is intentionally
@@ -178,11 +178,11 @@
178
179 In addition to identifying all files in the check-in, a
180 manifest also contains a check-in comment, the date and time
181 when the check-in was established, who created the check-in,
182 and links to other check-ins from which the current check-in
183 is derived. There are also a couple of checksums used to verify
184 the integrity of the check-in. And the whole manifest might
185 be PGP clearsigned.
186
187 <h3 id="keyconc">2.3 Key concepts</h3>
188
@@ -217,11 +217,11 @@
217 SQLite, patch, or any similar software on your system in order to use
218 Fossil effectively. You will want to have some kind of text editor
219 for entering check-in comments. Fossil will use whatever text editor
220 is identified by your VISUAL environment variable. Fossil will also
221 use GPG to clearsign your manifests if you happen to have it installed,
222 but Fossil will skip that step if GPG is missing from your system.
223 You can optionally set up Fossil to use external "diff" programs,
224 though Fossil has an excellent built-in "diff" algorithm that works
225 fine for most people. If you happen to have Tcl/Tk installed on your
226 system, Fossil will use it to generate a graphical "diff" display when
227 you use the --tk option to the "diff" command, but this too is entirely
@@ -286,11 +286,11 @@
286 fossil setting autosync off
287 fossil settings
288 </pre>
289
290 By default, Fossil runs with autosync mode turned on. The
291 authors find that projects run more smoothly in autosync mode since
292 autosync helps to prevent pointless forking and merging and helps keeps
293 all collaborators working on exactly the same code rather than on their
294 own personal forks of the code. In the author's view, manual-merge mode
295 should be reserved for disconnected operation.
296
297
--- www/contribute.wiki
+++ www/contribute.wiki
@@ -1,8 +1,8 @@
11
<title>Contributing To Fossil</title>
22
3
-Fossil users are encouraged to contributed enhancements back to the
3
+Fossil users are encouraged to contribute enhancements back to the
44
project. This note outlines some of the procedures for making
55
useful contributions.
66
77
<h2>1.0 Contributor Agreement</h2>
88
99
--- www/contribute.wiki
+++ www/contribute.wiki
@@ -1,8 +1,8 @@
1 <title>Contributing To Fossil</title>
2
3 Fossil users are encouraged to contributed enhancements back to the
4 project. This note outlines some of the procedures for making
5 useful contributions.
6
7 <h2>1.0 Contributor Agreement</h2>
8
9
--- www/contribute.wiki
+++ www/contribute.wiki
@@ -1,8 +1,8 @@
1 <title>Contributing To Fossil</title>
2
3 Fossil users are encouraged to contribute enhancements back to the
4 project. This note outlines some of the procedures for making
5 useful contributions.
6
7 <h2>1.0 Contributor Agreement</h2>
8
9
--- www/custom_ticket.wiki
+++ www/custom_ticket.wiki
@@ -82,16 +82,18 @@
8282
8383
Look for the text "Contact:" (about halfway through). Then insert these lines
8484
after the closing tr tag and before the "enable_output" line:
8585
8686
<verbatim>
87
-<td align="right">Assigned to:</td><td bgcolor="#d0d0d0">
88
- $<assigned_to>
89
-</td>
90
-<td align="right">Opened by:</td><td bgcolor="#d0d0d0">
91
- $<opened_by>
92
-</td>
87
+<tr>
88
+ <td align="right">Assigned to:</td><td bgcolor="#d0d0d0">
89
+ $<assigned_to>
90
+ </td>
91
+ <td align="right">Opened by:</td><td bgcolor="#d0d0d0">
92
+ $<opened_by>
93
+ </td>
94
+</tr>
9395
</verbatim>
9496
9597
This will add a row which displays these two fields, in the event the user has
9698
<a href="./caps/ref.html#w">ticket "edit" capability</a>.
9799
@@ -109,12 +111,12 @@
109111
</verbatim>
110112
111113
That will give you a drop-down list of assignees. The first argument to the TH1
112114
command 'combobox' is the database field which the combobox is associated to.
113115
The next argument is the list of choices you want to show in the combobox (and
114
-that you specified in the second step above. The last argument should be 1 for a
115
-true combobox (see the <a href="th1.md#combobox">TH1 documentation</a> for
116
+that you specified in the second step above.) The last argument should be 1 for
117
+a true combobox (see the <a href="th1.md#combobox">TH1 documentation</a> for
116118
details).
117119
118120
Now, similar to the previous
119121
section, look for "Contact:" and add this:
120122
121123
--- www/custom_ticket.wiki
+++ www/custom_ticket.wiki
@@ -82,16 +82,18 @@
82
83 Look for the text "Contact:" (about halfway through). Then insert these lines
84 after the closing tr tag and before the "enable_output" line:
85
86 <verbatim>
87 <td align="right">Assigned to:</td><td bgcolor="#d0d0d0">
88 $<assigned_to>
89 </td>
90 <td align="right">Opened by:</td><td bgcolor="#d0d0d0">
91 $<opened_by>
92 </td>
 
 
93 </verbatim>
94
95 This will add a row which displays these two fields, in the event the user has
96 <a href="./caps/ref.html#w">ticket "edit" capability</a>.
97
@@ -109,12 +111,12 @@
109 </verbatim>
110
111 That will give you a drop-down list of assignees. The first argument to the TH1
112 command 'combobox' is the database field which the combobox is associated to.
113 The next argument is the list of choices you want to show in the combobox (and
114 that you specified in the second step above. The last argument should be 1 for a
115 true combobox (see the <a href="th1.md#combobox">TH1 documentation</a> for
116 details).
117
118 Now, similar to the previous
119 section, look for "Contact:" and add this:
120
121
--- www/custom_ticket.wiki
+++ www/custom_ticket.wiki
@@ -82,16 +82,18 @@
82
83 Look for the text "Contact:" (about halfway through). Then insert these lines
84 after the closing tr tag and before the "enable_output" line:
85
86 <verbatim>
87 <tr>
88 <td align="right">Assigned to:</td><td bgcolor="#d0d0d0">
89 $<assigned_to>
90 </td>
91 <td align="right">Opened by:</td><td bgcolor="#d0d0d0">
92 $<opened_by>
93 </td>
94 </tr>
95 </verbatim>
96
97 This will add a row which displays these two fields, in the event the user has
98 <a href="./caps/ref.html#w">ticket "edit" capability</a>.
99
@@ -109,12 +111,12 @@
111 </verbatim>
112
113 That will give you a drop-down list of assignees. The first argument to the TH1
114 command 'combobox' is the database field which the combobox is associated to.
115 The next argument is the list of choices you want to show in the combobox (and
116 that you specified in the second step above.) The last argument should be 1 for
117 a true combobox (see the <a href="th1.md#combobox">TH1 documentation</a> for
118 details).
119
120 Now, similar to the previous
121 section, look for "Contact:" and add this:
122
123
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -178,17 +178,25 @@
178178
As with "$ROOT", this substitution only works for Markdown and HTML
179179
documents. For Wiki documents, you would need to use a relative URL.
180180
181181
<h2 id="th1">2.3 TH1 Documents</h2>
182182
183
-Fossil will substitute the value of [./th1.md | TH1 expressions] within
184
-<tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have
185
-configured it with the <tt>--with-th1-docs</tt> option, which is
186
-disabled by default.
183
+Enabling TH1 document support requires the following:
184
+
185
+ * Configure the build with the <code>--with-th1-docs</code> flag.
186
+ * Enable the <code>th1-docs</code> setting, which is only available
187
+ after building with <code>--with-th1-docs</code>.
188
+ * Affected files must have a <code>.th1</code> file extension.
189
+ * The code to run must be embedded in blocks of
190
+ <code>&lt;th1>...&lt;/th1></code>.
191
+
192
+Fossil will substitute the value of [./th1.md | TH1 expressions]
193
+within the <code>&lt;th1>...&lt;/th1></code> blocks into
194
+the output HTML.
187195
188196
Since TH1 is a full scripting language, this feature essential grants
189
-the ability to execute code on the server to anyone with check-in
197
+the ability to execute code on the server to anyone with check-in
190198
privilege for the project.
191199
This is a security risk that needs to be carefully managed.
192200
The feature is off by default.
193201
Administrators should understand and carefully assess the risks
194202
before enabling the use of TH1 within embedded documentation.
195203
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -178,17 +178,25 @@
178 As with "$ROOT", this substitution only works for Markdown and HTML
179 documents. For Wiki documents, you would need to use a relative URL.
180
181 <h2 id="th1">2.3 TH1 Documents</h2>
182
183 Fossil will substitute the value of [./th1.md | TH1 expressions] within
184 <tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have
185 configured it with the <tt>--with-th1-docs</tt> option, which is
186 disabled by default.
 
 
 
 
 
 
 
 
187
188 Since TH1 is a full scripting language, this feature essential grants
189 the ability to execute code on the server to anyone with check-in
190 privilege for the project.
191 This is a security risk that needs to be carefully managed.
192 The feature is off by default.
193 Administrators should understand and carefully assess the risks
194 before enabling the use of TH1 within embedded documentation.
195
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -178,17 +178,25 @@
178 As with "$ROOT", this substitution only works for Markdown and HTML
179 documents. For Wiki documents, you would need to use a relative URL.
180
181 <h2 id="th1">2.3 TH1 Documents</h2>
182
183 Enabling TH1 document support requires the following:
184
185 * Configure the build with the <code>--with-th1-docs</code> flag.
186 * Enable the <code>th1-docs</code> setting, which is only available
187 after building with <code>--with-th1-docs</code>.
188 * Affected files must have a <code>.th1</code> file extension.
189 * The code to run must be embedded in blocks of
190 <code>&lt;th1>...&lt;/th1></code>.
191
192 Fossil will substitute the value of [./th1.md | TH1 expressions]
193 within the <code>&lt;th1>...&lt;/th1></code> blocks into
194 the output HTML.
195
196 Since TH1 is a full scripting language, this feature essential grants
197 the ability to execute code on the server to anyone with check-in
198 privilege for the project.
199 This is a security risk that needs to be carefully managed.
200 The feature is off by default.
201 Administrators should understand and carefully assess the risks
202 before enabling the use of TH1 within embedded documentation.
203
+3 -3
--- www/env-opts.md
+++ www/env-opts.md
@@ -468,21 +468,21 @@
468468
obviously as part of the `fossil ui` command. In that specific case,
469469
the browser is launched pointing at the web server started by `fossil
470470
ui` listening on a private TCP port.
471471
472472
On all platforms, if the local or global settings `web-browser` is
473
-set, that is the command used to open an URL.
473
+set, that is the command used to open a URL.
474474
475475
Otherwise, the specific actions vary by platform.
476476
477477
On Unix-like platforms other than Apple's, it looks for the first
478478
program from the list `xdg-open`, `gnome-open`, `firefox`, and
479479
`google-chrome` that it can find on the `PATH`.
480480
481
-On Apple platforms, it assumes that `open` is the command to open an
481
+On Apple platforms, it assumes that `open` is the command to open a
482482
URL in the user's configured default browser.
483483
484484
On Windows platforms, it assumes that `start` is the command to open
485
-an URL in the user's configured default browser.
485
+a URL in the user's configured default browser.
486486
487487
[configdb]: ./tech_overview.wiki#configdb
488488
[configloc]: ./tech_overview.wiki#configloc
489489
--- www/env-opts.md
+++ www/env-opts.md
@@ -468,21 +468,21 @@
468 obviously as part of the `fossil ui` command. In that specific case,
469 the browser is launched pointing at the web server started by `fossil
470 ui` listening on a private TCP port.
471
472 On all platforms, if the local or global settings `web-browser` is
473 set, that is the command used to open an URL.
474
475 Otherwise, the specific actions vary by platform.
476
477 On Unix-like platforms other than Apple's, it looks for the first
478 program from the list `xdg-open`, `gnome-open`, `firefox`, and
479 `google-chrome` that it can find on the `PATH`.
480
481 On Apple platforms, it assumes that `open` is the command to open an
482 URL in the user's configured default browser.
483
484 On Windows platforms, it assumes that `start` is the command to open
485 an URL in the user's configured default browser.
486
487 [configdb]: ./tech_overview.wiki#configdb
488 [configloc]: ./tech_overview.wiki#configloc
489
--- www/env-opts.md
+++ www/env-opts.md
@@ -468,21 +468,21 @@
468 obviously as part of the `fossil ui` command. In that specific case,
469 the browser is launched pointing at the web server started by `fossil
470 ui` listening on a private TCP port.
471
472 On all platforms, if the local or global settings `web-browser` is
473 set, that is the command used to open a URL.
474
475 Otherwise, the specific actions vary by platform.
476
477 On Unix-like platforms other than Apple's, it looks for the first
478 program from the list `xdg-open`, `gnome-open`, `firefox`, and
479 `google-chrome` that it can find on the `PATH`.
480
481 On Apple platforms, it assumes that `open` is the command to open a
482 URL in the user's configured default browser.
483
484 On Windows platforms, it assumes that `start` is the command to open
485 a URL in the user's configured default browser.
486
487 [configdb]: ./tech_overview.wiki#configdb
488 [configloc]: ./tech_overview.wiki#configloc
489
+1 -1
--- www/event.wiki
+++ www/event.wiki
@@ -115,6 +115,6 @@
115115
create or edit technotes. In addition, users must have create-wiki
116116
privilege (permission "f") to create new technotes and edit-wiki
117117
privilege (permission "k") in order to edit existing technotes.
118118
119119
Technote content may be formatted as [/wiki_rules | Fossil wiki],
120
-[/md_rules | Markdown], or a plain text.
120
+[/md_rules | Markdown], or plain text.
121121
--- www/event.wiki
+++ www/event.wiki
@@ -115,6 +115,6 @@
115 create or edit technotes. In addition, users must have create-wiki
116 privilege (permission "f") to create new technotes and edit-wiki
117 privilege (permission "k") in order to edit existing technotes.
118
119 Technote content may be formatted as [/wiki_rules | Fossil wiki],
120 [/md_rules | Markdown], or a plain text.
121
--- www/event.wiki
+++ www/event.wiki
@@ -115,6 +115,6 @@
115 create or edit technotes. In addition, users must have create-wiki
116 privilege (permission "f") to create new technotes and edit-wiki
117 privilege (permission "k") in order to edit existing technotes.
118
119 Technote content may be formatted as [/wiki_rules | Fossil wiki],
120 [/md_rules | Markdown], or plain text.
121
--- www/fileedit-page.md
+++ www/fileedit-page.md
@@ -1,11 +1,11 @@
11
# The fileedit Page
22
33
This document describes the limitations of, caveats for, and
44
disclaimers for the [](/fileedit) page, which provides users with
5
-[checkin privileges](./caps/index.md) basic editing features for files
6
-via the web interface.
5
+ basic editing features for files via the web interface when they
6
+ have [checkin privileges](./caps/index.md).
77
88
# Important Caveats and Disclaimers
99
1010
Predictably, the ability to edit files in a repository from a web
1111
browser halfway around the world comes with several obligatory caveats
@@ -219,11 +219,11 @@
219219
- `element`: the DOM element in which the preview is rendered.
220220
- `mimetype`: the mimetype of the being-previewed content, as determined
221221
by Fossil (by its file extension).
222222
223223
The event listener callback shown above doesn't use the `mimetype`,
224
-but makes used of the other two. It fishes all `code` blocks out of
224
+but makes use of the other two. It fishes all `code` blocks out of
225225
the preview which explicitly have a CSS class named
226226
`language-`something, and then asks highlightjs to highlight them.
227227
228228
## <a id="editor"></a> Integrating a Custom Editor Widget
229229
230230
--- www/fileedit-page.md
+++ www/fileedit-page.md
@@ -1,11 +1,11 @@
1 # The fileedit Page
2
3 This document describes the limitations of, caveats for, and
4 disclaimers for the [](/fileedit) page, which provides users with
5 [checkin privileges](./caps/index.md) basic editing features for files
6 via the web interface.
7
8 # Important Caveats and Disclaimers
9
10 Predictably, the ability to edit files in a repository from a web
11 browser halfway around the world comes with several obligatory caveats
@@ -219,11 +219,11 @@
219 - `element`: the DOM element in which the preview is rendered.
220 - `mimetype`: the mimetype of the being-previewed content, as determined
221 by Fossil (by its file extension).
222
223 The event listener callback shown above doesn't use the `mimetype`,
224 but makes used of the other two. It fishes all `code` blocks out of
225 the preview which explicitly have a CSS class named
226 `language-`something, and then asks highlightjs to highlight them.
227
228 ## <a id="editor"></a> Integrating a Custom Editor Widget
229
230
--- www/fileedit-page.md
+++ www/fileedit-page.md
@@ -1,11 +1,11 @@
1 # The fileedit Page
2
3 This document describes the limitations of, caveats for, and
4 disclaimers for the [](/fileedit) page, which provides users with
5 basic editing features for files via the web interface when they
6 have [checkin privileges](./caps/index.md).
7
8 # Important Caveats and Disclaimers
9
10 Predictably, the ability to edit files in a repository from a web
11 browser halfway around the world comes with several obligatory caveats
@@ -219,11 +219,11 @@
219 - `element`: the DOM element in which the preview is rendered.
220 - `mimetype`: the mimetype of the being-previewed content, as determined
221 by Fossil (by its file extension).
222
223 The event listener callback shown above doesn't use the `mimetype`,
224 but makes use of the other two. It fishes all `code` blocks out of
225 the preview which explicitly have a CSS class named
226 `language-`something, and then asks highlightjs to highlight them.
227
228 ## <a id="editor"></a> Integrating a Custom Editor Widget
229
230
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -360,11 +360,11 @@
360360
of text in the wiki page. That text follows the newline character
361361
that terminates the <b>W</b> card. The wiki text is always followed by one
362362
extra newline.
363363
364364
The <b>C</b> card on a wiki page is optional. The argument is a comment
365
-that explains why the changes was made. The ability to have a <b>C</b>
365
+that explains why the changes were made. The ability to have a <b>C</b>
366366
card on a wiki page artifact was added on 2019-12-02 at the suggestion
367367
of user George Krivov and is not currently used or generated by the
368368
implementation. Older versions of Fossil will reject a wiki-page
369369
artifact that includes a <b>C</b> card.
370370
@@ -396,14 +396,14 @@
396396
ticket into existence.
397397
398398
<b>J</b> cards specify changes to the "value" of "fields" in the ticket.
399399
If the <i>value</i> parameter of the <b>J</b> card is omitted, then the
400400
field is set to an empty string.
401
-Each fossil server has a ticket configuration which specifies the fields its
401
+Each fossil server has a ticket configuration which specifies the fields it
402402
understands. The ticket configuration is part of the local state for
403403
the repository and thus can vary from one repository to another.
404
-Hence a <b>J</b> card might specify a <i>field</i> that do not exist in the
404
+Hence a <b>J</b> card might specify a <i>field</i> that does not exist in the
405405
local ticket configuration. If a <b>J</b> card specifies a <i>field</i> that
406406
is not in the local configuration, then that <b>J</b> card
407407
is simply ignored.
408408
409409
The first argument of the <b>J</b> card is the field name. The second
@@ -462,11 +462,11 @@
462462
A technical note or "technote" artifact (formerly known as an "event" artifact)
463463
associates a timeline comment and a page of text
464464
(similar to a wiki page) with a point in time. Technotes can be used
465465
to record project milestones, release notes, blog entries, process
466466
checkpoints, or news articles.
467
-The following cards are allowed on an technote artifact:
467
+The following cards are allowed on a technote artifact:
468468
469469
<div class="indent">
470470
<b>C</b> <i>comment</i><br>
471471
<b>D</b> <i>time-and-date-stamp</i><br />
472472
<b>E</b> <i>technote-time</i> <i>technote-id</i><br />
@@ -510,15 +510,15 @@
510510
The <b>*</b> in place of the artifact ID indicates that
511511
the tag or property applies to the current artifact. It is not
512512
possible to encode the current artifact ID as part of an artifact,
513513
since the act of inserting the artifact ID would change the artifact ID,
514514
hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the
515
-name means that tags can only be add and they can only be non-propagating
515
+name means that tags can only be "add" and they can only be non-propagating
516516
tags. In a technote, <b>T</b> cards are normally used to set the background
517517
display color for timelines.
518518
519
-The optional <b>U</b> card gives name of the user who entered the technote.
519
+The optional <b>U</b> card gives the name of the user who entered the technote.
520520
521521
A single <b>W</b> card provides wiki text for the document associated with the
522522
technote. The format of the <b>W</b> card is exactly the same as for a
523523
[#wikichng | wiki artifact].
524524
525525
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -360,11 +360,11 @@
360 of text in the wiki page. That text follows the newline character
361 that terminates the <b>W</b> card. The wiki text is always followed by one
362 extra newline.
363
364 The <b>C</b> card on a wiki page is optional. The argument is a comment
365 that explains why the changes was made. The ability to have a <b>C</b>
366 card on a wiki page artifact was added on 2019-12-02 at the suggestion
367 of user George Krivov and is not currently used or generated by the
368 implementation. Older versions of Fossil will reject a wiki-page
369 artifact that includes a <b>C</b> card.
370
@@ -396,14 +396,14 @@
396 ticket into existence.
397
398 <b>J</b> cards specify changes to the "value" of "fields" in the ticket.
399 If the <i>value</i> parameter of the <b>J</b> card is omitted, then the
400 field is set to an empty string.
401 Each fossil server has a ticket configuration which specifies the fields its
402 understands. The ticket configuration is part of the local state for
403 the repository and thus can vary from one repository to another.
404 Hence a <b>J</b> card might specify a <i>field</i> that do not exist in the
405 local ticket configuration. If a <b>J</b> card specifies a <i>field</i> that
406 is not in the local configuration, then that <b>J</b> card
407 is simply ignored.
408
409 The first argument of the <b>J</b> card is the field name. The second
@@ -462,11 +462,11 @@
462 A technical note or "technote" artifact (formerly known as an "event" artifact)
463 associates a timeline comment and a page of text
464 (similar to a wiki page) with a point in time. Technotes can be used
465 to record project milestones, release notes, blog entries, process
466 checkpoints, or news articles.
467 The following cards are allowed on an technote artifact:
468
469 <div class="indent">
470 <b>C</b> <i>comment</i><br>
471 <b>D</b> <i>time-and-date-stamp</i><br />
472 <b>E</b> <i>technote-time</i> <i>technote-id</i><br />
@@ -510,15 +510,15 @@
510 The <b>*</b> in place of the artifact ID indicates that
511 the tag or property applies to the current artifact. It is not
512 possible to encode the current artifact ID as part of an artifact,
513 since the act of inserting the artifact ID would change the artifact ID,
514 hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the
515 name means that tags can only be add and they can only be non-propagating
516 tags. In a technote, <b>T</b> cards are normally used to set the background
517 display color for timelines.
518
519 The optional <b>U</b> card gives name of the user who entered the technote.
520
521 A single <b>W</b> card provides wiki text for the document associated with the
522 technote. The format of the <b>W</b> card is exactly the same as for a
523 [#wikichng | wiki artifact].
524
525
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -360,11 +360,11 @@
360 of text in the wiki page. That text follows the newline character
361 that terminates the <b>W</b> card. The wiki text is always followed by one
362 extra newline.
363
364 The <b>C</b> card on a wiki page is optional. The argument is a comment
365 that explains why the changes were made. The ability to have a <b>C</b>
366 card on a wiki page artifact was added on 2019-12-02 at the suggestion
367 of user George Krivov and is not currently used or generated by the
368 implementation. Older versions of Fossil will reject a wiki-page
369 artifact that includes a <b>C</b> card.
370
@@ -396,14 +396,14 @@
396 ticket into existence.
397
398 <b>J</b> cards specify changes to the "value" of "fields" in the ticket.
399 If the <i>value</i> parameter of the <b>J</b> card is omitted, then the
400 field is set to an empty string.
401 Each fossil server has a ticket configuration which specifies the fields it
402 understands. The ticket configuration is part of the local state for
403 the repository and thus can vary from one repository to another.
404 Hence a <b>J</b> card might specify a <i>field</i> that does not exist in the
405 local ticket configuration. If a <b>J</b> card specifies a <i>field</i> that
406 is not in the local configuration, then that <b>J</b> card
407 is simply ignored.
408
409 The first argument of the <b>J</b> card is the field name. The second
@@ -462,11 +462,11 @@
462 A technical note or "technote" artifact (formerly known as an "event" artifact)
463 associates a timeline comment and a page of text
464 (similar to a wiki page) with a point in time. Technotes can be used
465 to record project milestones, release notes, blog entries, process
466 checkpoints, or news articles.
467 The following cards are allowed on a technote artifact:
468
469 <div class="indent">
470 <b>C</b> <i>comment</i><br>
471 <b>D</b> <i>time-and-date-stamp</i><br />
472 <b>E</b> <i>technote-time</i> <i>technote-id</i><br />
@@ -510,15 +510,15 @@
510 The <b>*</b> in place of the artifact ID indicates that
511 the tag or property applies to the current artifact. It is not
512 possible to encode the current artifact ID as part of an artifact,
513 since the act of inserting the artifact ID would change the artifact ID,
514 hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the
515 name means that tags can only be "add" and they can only be non-propagating
516 tags. In a technote, <b>T</b> cards are normally used to set the background
517 display color for timelines.
518
519 The optional <b>U</b> card gives the name of the user who entered the technote.
520
521 A single <b>W</b> card provides wiki text for the document associated with the
522 technote. The format of the <b>W</b> card is exactly the same as for a
523 [#wikichng | wiki artifact].
524
525
+1 -1
--- www/forum.wiki
+++ www/forum.wiki
@@ -405,7 +405,7 @@
405405
406406
Though forum users are permitted to delete their own posts, they are
407407
not permitted, without appropriate permissions, to close their own
408408
posts. This is intentional, as closing one's own post can be used to
409409
antagonize other forum users. For example, by posting something
410
-trollish or highly contraversial in nature and closing the post to
410
+trollish or highly controversial in nature and closing the post to
411411
further responses.
412412
--- www/forum.wiki
+++ www/forum.wiki
@@ -405,7 +405,7 @@
405
406 Though forum users are permitted to delete their own posts, they are
407 not permitted, without appropriate permissions, to close their own
408 posts. This is intentional, as closing one's own post can be used to
409 antagonize other forum users. For example, by posting something
410 trollish or highly contraversial in nature and closing the post to
411 further responses.
412
--- www/forum.wiki
+++ www/forum.wiki
@@ -405,7 +405,7 @@
405
406 Though forum users are permitted to delete their own posts, they are
407 not permitted, without appropriate permissions, to close their own
408 posts. This is intentional, as closing one's own post can be used to
409 antagonize other forum users. For example, by posting something
410 trollish or highly controversial in nature and closing the post to
411 further responses.
412
--- www/fossil-is-not-relational.md
+++ www/fossil-is-not-relational.md
@@ -131,11 +131,11 @@
131131
metadata.
132132
133133
- Raw file content of versioned files. These data are external to
134134
artifacts, which refer to them by their hashes. How they are stored
135135
is not the concern of the data model, but (spoiler alert!) Fossil
136
- stores in them an sqlite database, one record per distinct hash, in
136
+ stores them in an SQLite database, one record per distinct hash, in
137137
its `blob` table (which we will cover more very soon).
138138
139139
Non-SCM-relevant state includes:
140140
141141
- Fossil's list of users and their metadata (permissions, email
142142
--- www/fossil-is-not-relational.md
+++ www/fossil-is-not-relational.md
@@ -131,11 +131,11 @@
131 metadata.
132
133 - Raw file content of versioned files. These data are external to
134 artifacts, which refer to them by their hashes. How they are stored
135 is not the concern of the data model, but (spoiler alert!) Fossil
136 stores in them an sqlite database, one record per distinct hash, in
137 its `blob` table (which we will cover more very soon).
138
139 Non-SCM-relevant state includes:
140
141 - Fossil's list of users and their metadata (permissions, email
142
--- www/fossil-is-not-relational.md
+++ www/fossil-is-not-relational.md
@@ -131,11 +131,11 @@
131 metadata.
132
133 - Raw file content of versioned files. These data are external to
134 artifacts, which refer to them by their hashes. How they are stored
135 is not the concern of the data model, but (spoiler alert!) Fossil
136 stores them in an SQLite database, one record per distinct hash, in
137 its `blob` table (which we will cover more very soon).
138
139 Non-SCM-relevant state includes:
140
141 - Fossil's list of users and their metadata (permissions, email
142
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -70,18 +70,13 @@
7070
<td>Designed for Linux kernel development</td>
7171
<td>Designed for SQLite development</td>
7272
<td><a href="#scale">2.5.2&nbsp;&darr;</a></td>
7373
</tr>
7474
<tr>
75
- <td>Many contributors</td>
76
- <td>Select contributors</td>
77
- <td><a href="#contrib">2.5.3&nbsp;&darr;</a></td>
78
-</tr>
79
-<tr>
8075
<td>Focus on individual branches</td>
8176
<td>Focus on the entire tree of changes</td>
82
- <td><a href="#branches">2.5.4&nbsp;&darr;</a></td>
77
+ <td><a href="#branches">2.5.3&nbsp;&darr;</a></td>
8378
</tr>
8479
<tr>
8580
<td>One check-out per repository</td>
8681
<td>Many check-outs per repository</td>
8782
<td><a href="#checkouts">2.6&nbsp;&darr;</a></td>
@@ -591,18 +586,21 @@
591586
and its handful of active committers. Seeing all
592587
changes on all branches all at once helps keep the whole team
593588
up-to-date with what everybody else is doing, resulting in a more
594589
tightly focused and cohesive implementation.
595590
591
+Parts of this section are [https://fossil-scm.org/forum/forumpost/5961e969fa|disputed]
592
+by [https://github.com/olorin37|Jakub A. G.].
593
+
596594
597595
<h3 id="checkouts">2.6 One vs. Many Check-outs per Repository</h3>
598596
599597
Because Git commingles the repository data with the initial checkout of
600598
that repository, the default mode of operation in Git is to stick to that
601599
single work/repo tree, even when that's a shortsighted way of working.
602600
603
-Fossil doesn't work that way. A Fossil repository is a SQLite database
601
+Fossil doesn't work that way. A Fossil repository is an SQLite database
604602
file which is normally stored outside the working checkout directory. You can
605603
[/help?cmd=open | open] a Fossil repository any number of times into
606604
any number of working directories. A common usage pattern is to have one
607605
working directory per active working branch, so that switching branches
608606
is done with a <tt>cd</tt> command rather than by checking out the
@@ -660,10 +658,12 @@
660658
661659
Plus,
662660
<tt>cd</tt> is faster to type than <tt>git checkout</tt> or <tt>fossil
663661
update</tt>.
664662
663
+Parts of this section are [https://fossil-scm.org/forum/forumpost/5961e969fa|disputed]
664
+by [https://github.com/olorin37|Jakub A. G.].
665665
666666
<h3 id="history">2.7 What you should have done vs. What you actually did</h3>
667667
668668
Git puts a lot of emphasis on maintaining
669669
a "clean" check-in history. Extraneous and experimental branches by
@@ -861,13 +861,12 @@
861861
as this author is aware, but there is now
862862
[https://lwn.net/ml/git/[email protected]/
863863
| a competing SHA-256 based plan] which requires complete repository
864864
conversion from SHA-1 to SHA-256, breaking all public hashes in the
865865
repo. One way to characterize such a massive upheaval in Git terms is a
866
-whole-project rebase, which violates
867
-[https://blog.axosoft.com/golden-rule-of-rebasing-in-git/ | Git's own
868
-Golden Rule of Rebasing].
866
+whole-project rebase, which violates the
867
+[https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing|Golden Rule of Rebasing].
869868
870869
Regardless of the eventual implementation details, we fully expect Git
871870
to move off SHA-1 eventually and for the changes to take years more to
872871
percolate through the community.
873872
874873
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -70,18 +70,13 @@
70 <td>Designed for Linux kernel development</td>
71 <td>Designed for SQLite development</td>
72 <td><a href="#scale">2.5.2&nbsp;&darr;</a></td>
73 </tr>
74 <tr>
75 <td>Many contributors</td>
76 <td>Select contributors</td>
77 <td><a href="#contrib">2.5.3&nbsp;&darr;</a></td>
78 </tr>
79 <tr>
80 <td>Focus on individual branches</td>
81 <td>Focus on the entire tree of changes</td>
82 <td><a href="#branches">2.5.4&nbsp;&darr;</a></td>
83 </tr>
84 <tr>
85 <td>One check-out per repository</td>
86 <td>Many check-outs per repository</td>
87 <td><a href="#checkouts">2.6&nbsp;&darr;</a></td>
@@ -591,18 +586,21 @@
591 and its handful of active committers. Seeing all
592 changes on all branches all at once helps keep the whole team
593 up-to-date with what everybody else is doing, resulting in a more
594 tightly focused and cohesive implementation.
595
 
 
 
596
597 <h3 id="checkouts">2.6 One vs. Many Check-outs per Repository</h3>
598
599 Because Git commingles the repository data with the initial checkout of
600 that repository, the default mode of operation in Git is to stick to that
601 single work/repo tree, even when that's a shortsighted way of working.
602
603 Fossil doesn't work that way. A Fossil repository is a SQLite database
604 file which is normally stored outside the working checkout directory. You can
605 [/help?cmd=open | open] a Fossil repository any number of times into
606 any number of working directories. A common usage pattern is to have one
607 working directory per active working branch, so that switching branches
608 is done with a <tt>cd</tt> command rather than by checking out the
@@ -660,10 +658,12 @@
660
661 Plus,
662 <tt>cd</tt> is faster to type than <tt>git checkout</tt> or <tt>fossil
663 update</tt>.
664
 
 
665
666 <h3 id="history">2.7 What you should have done vs. What you actually did</h3>
667
668 Git puts a lot of emphasis on maintaining
669 a "clean" check-in history. Extraneous and experimental branches by
@@ -861,13 +861,12 @@
861 as this author is aware, but there is now
862 [https://lwn.net/ml/git/[email protected]/
863 | a competing SHA-256 based plan] which requires complete repository
864 conversion from SHA-1 to SHA-256, breaking all public hashes in the
865 repo. One way to characterize such a massive upheaval in Git terms is a
866 whole-project rebase, which violates
867 [https://blog.axosoft.com/golden-rule-of-rebasing-in-git/ | Git's own
868 Golden Rule of Rebasing].
869
870 Regardless of the eventual implementation details, we fully expect Git
871 to move off SHA-1 eventually and for the changes to take years more to
872 percolate through the community.
873
874
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -70,18 +70,13 @@
70 <td>Designed for Linux kernel development</td>
71 <td>Designed for SQLite development</td>
72 <td><a href="#scale">2.5.2&nbsp;&darr;</a></td>
73 </tr>
74 <tr>
 
 
 
 
 
75 <td>Focus on individual branches</td>
76 <td>Focus on the entire tree of changes</td>
77 <td><a href="#branches">2.5.3&nbsp;&darr;</a></td>
78 </tr>
79 <tr>
80 <td>One check-out per repository</td>
81 <td>Many check-outs per repository</td>
82 <td><a href="#checkouts">2.6&nbsp;&darr;</a></td>
@@ -591,18 +586,21 @@
586 and its handful of active committers. Seeing all
587 changes on all branches all at once helps keep the whole team
588 up-to-date with what everybody else is doing, resulting in a more
589 tightly focused and cohesive implementation.
590
591 Parts of this section are [https://fossil-scm.org/forum/forumpost/5961e969fa|disputed]
592 by [https://github.com/olorin37|Jakub A. G.].
593
594
595 <h3 id="checkouts">2.6 One vs. Many Check-outs per Repository</h3>
596
597 Because Git commingles the repository data with the initial checkout of
598 that repository, the default mode of operation in Git is to stick to that
599 single work/repo tree, even when that's a shortsighted way of working.
600
601 Fossil doesn't work that way. A Fossil repository is an SQLite database
602 file which is normally stored outside the working checkout directory. You can
603 [/help?cmd=open | open] a Fossil repository any number of times into
604 any number of working directories. A common usage pattern is to have one
605 working directory per active working branch, so that switching branches
606 is done with a <tt>cd</tt> command rather than by checking out the
@@ -660,10 +658,12 @@
658
659 Plus,
660 <tt>cd</tt> is faster to type than <tt>git checkout</tt> or <tt>fossil
661 update</tt>.
662
663 Parts of this section are [https://fossil-scm.org/forum/forumpost/5961e969fa|disputed]
664 by [https://github.com/olorin37|Jakub A. G.].
665
666 <h3 id="history">2.7 What you should have done vs. What you actually did</h3>
667
668 Git puts a lot of emphasis on maintaining
669 a "clean" check-in history. Extraneous and experimental branches by
@@ -861,13 +861,12 @@
861 as this author is aware, but there is now
862 [https://lwn.net/ml/git/[email protected]/
863 | a competing SHA-256 based plan] which requires complete repository
864 conversion from SHA-1 to SHA-256, breaking all public hashes in the
865 repo. One way to characterize such a massive upheaval in Git terms is a
866 whole-project rebase, which violates the
867 [https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing|Golden Rule of Rebasing].
 
868
869 Regardless of the eventual implementation details, we fully expect Git
870 to move off SHA-1 eventually and for the changes to take years more to
871 percolate through the community.
872
873
--- www/fossil_prompt.wiki
+++ www/fossil_prompt.wiki
@@ -17,6 +17,6 @@
1717
1818
For a permanent installation, you can graft the code into your
1919
<tt>.bashrc</tt> file in your home directory.
2020
2121
The code is very simple (only 32 non-comment lines, as of this writing)
22
-and hence easy to customized.
22
+and hence easy to customize.
2323
--- www/fossil_prompt.wiki
+++ www/fossil_prompt.wiki
@@ -17,6 +17,6 @@
17
18 For a permanent installation, you can graft the code into your
19 <tt>.bashrc</tt> file in your home directory.
20
21 The code is very simple (only 32 non-comment lines, as of this writing)
22 and hence easy to customized.
23
--- www/fossil_prompt.wiki
+++ www/fossil_prompt.wiki
@@ -17,6 +17,6 @@
17
18 For a permanent installation, you can graft the code into your
19 <tt>.bashrc</tt> file in your home directory.
20
21 The code is very simple (only 32 non-comment lines, as of this writing)
22 and hence easy to customize.
23
+3 -3
--- www/gitusers.md
+++ www/gitusers.md
@@ -56,11 +56,11 @@
5656
5757
5858
5959
#### <a id="cwork" name="scw"></a> Checkout Workflows
6060
61
-A Fossil repository is a SQLite database storing the entire history of a
61
+A Fossil repository is an SQLite database storing the entire history of a
6262
project. It is not normally stored inside the working tree.
6363
A Fossil working tree — [also called a check-out](./glossary.md#check-out) — is a directory
6464
that contains a snapshot of your project that you are currently working
6565
on, extracted for you from the repository database file by the `fossil`
6666
program.
@@ -148,11 +148,11 @@
148148
option, it won’t let you close the check-out with uncommitted changes to
149149
those managed files.
150150
151151
The `close` command also refuses to run without `--force` when you have
152152
certain other precious per-checkout data that Fossil stores in the
153
-`.fslckout` file at the root of a check-out directory. This is a SQLite
153
+`.fslckout` file at the root of a check-out directory. This is an SQLite
154154
database that keeps track of local state such as what version you have
155155
checked out, the contents of the [stash] for that working directory, the
156156
[undo] buffers, per-checkout [settings][set], and so forth. The stash
157157
and undo buffers are considered precious uncommitted changes,
158158
so you have to force Fossil to discard these as part of closing the
@@ -773,11 +773,11 @@
773773
hashes.)
774774
775775
In this scheme, Alice then needs to say “`fossil update trunk`” in order
776776
to return her check-out’s parent commit to the previous version lest her
777777
next attempted commit land atop this mistake branch. The fact that Bob
778
-marked the branch as closed will prevent that from going thru, cluing
778
+marked the branch as closed will prevent that from going through, cluing
779779
Alice into what she needs to do to remedy the situation, but that merely
780780
shows why it’s a better workflow if Alice makes the amendment herself:
781781
782782
```
783783
fossil amend --branch MISTAKE --hide --close \
784784
--- www/gitusers.md
+++ www/gitusers.md
@@ -56,11 +56,11 @@
56
57
58
59 #### <a id="cwork" name="scw"></a> Checkout Workflows
60
61 A Fossil repository is a SQLite database storing the entire history of a
62 project. It is not normally stored inside the working tree.
63 A Fossil working tree — [also called a check-out](./glossary.md#check-out) — is a directory
64 that contains a snapshot of your project that you are currently working
65 on, extracted for you from the repository database file by the `fossil`
66 program.
@@ -148,11 +148,11 @@
148 option, it won’t let you close the check-out with uncommitted changes to
149 those managed files.
150
151 The `close` command also refuses to run without `--force` when you have
152 certain other precious per-checkout data that Fossil stores in the
153 `.fslckout` file at the root of a check-out directory. This is a SQLite
154 database that keeps track of local state such as what version you have
155 checked out, the contents of the [stash] for that working directory, the
156 [undo] buffers, per-checkout [settings][set], and so forth. The stash
157 and undo buffers are considered precious uncommitted changes,
158 so you have to force Fossil to discard these as part of closing the
@@ -773,11 +773,11 @@
773 hashes.)
774
775 In this scheme, Alice then needs to say “`fossil update trunk`” in order
776 to return her check-out’s parent commit to the previous version lest her
777 next attempted commit land atop this mistake branch. The fact that Bob
778 marked the branch as closed will prevent that from going thru, cluing
779 Alice into what she needs to do to remedy the situation, but that merely
780 shows why it’s a better workflow if Alice makes the amendment herself:
781
782 ```
783 fossil amend --branch MISTAKE --hide --close \
784
--- www/gitusers.md
+++ www/gitusers.md
@@ -56,11 +56,11 @@
56
57
58
59 #### <a id="cwork" name="scw"></a> Checkout Workflows
60
61 A Fossil repository is an SQLite database storing the entire history of a
62 project. It is not normally stored inside the working tree.
63 A Fossil working tree — [also called a check-out](./glossary.md#check-out) — is a directory
64 that contains a snapshot of your project that you are currently working
65 on, extracted for you from the repository database file by the `fossil`
66 program.
@@ -148,11 +148,11 @@
148 option, it won’t let you close the check-out with uncommitted changes to
149 those managed files.
150
151 The `close` command also refuses to run without `--force` when you have
152 certain other precious per-checkout data that Fossil stores in the
153 `.fslckout` file at the root of a check-out directory. This is an SQLite
154 database that keeps track of local state such as what version you have
155 checked out, the contents of the [stash] for that working directory, the
156 [undo] buffers, per-checkout [settings][set], and so forth. The stash
157 and undo buffers are considered precious uncommitted changes,
158 so you have to force Fossil to discard these as part of closing the
@@ -773,11 +773,11 @@
773 hashes.)
774
775 In this scheme, Alice then needs to say “`fossil update trunk`” in order
776 to return her check-out’s parent commit to the previous version lest her
777 next attempted commit land atop this mistake branch. The fact that Bob
778 marked the branch as closed will prevent that from going through, cluing
779 Alice into what she needs to do to remedy the situation, but that merely
780 shows why it’s a better workflow if Alice makes the amendment herself:
781
782 ```
783 fossil amend --branch MISTAKE --hide --close \
784
+2 -2
--- www/glossary.md
+++ www/glossary.md
@@ -73,11 +73,11 @@
7373
because you’ll have all of your OS’s *other* files intermixed.
7474
Worse, Fossil doesn’t track OS permissions, so even if you were to
7575
try to use Fossil as a system deployment tool by archiving versions
7676
of the OS configuration files and then unpacking them on a new
7777
system, the extracted project files would have read/write access by
78
- the user who did the extraction, which probably isn’t want you were
78
+ the user who did the extraction, which probably isn’t what you were
7979
wanting.
8080
8181
Even with these problems aside, do you really want a `.fslckout`
8282
SQLite database at the root of your filesystem? Are you prepared for
8383
the consequences of saying `fossil clean --verily` on such a system?
@@ -348,11 +348,11 @@
348348
349349
* In the same way that one cannot extract files from a zip archive
350350
without having a copy of that zip file, one cannot make check-outs
351351
without access to the repository file or a clone thereof.
352352
353
-* Because a Fossil repository is a SQLite database file, the same
353
+* Because a Fossil repository is an SQLite database file, the same
354354
rules for avoiding data corruption apply to it. In particular, it is
355355
[nearly a hard requirement][h2cflp] that the repository clone be on
356356
the same machine as the one where you make check-outs and the
357357
subsequent check-ins.
358358
359359
--- www/glossary.md
+++ www/glossary.md
@@ -73,11 +73,11 @@
73 because you’ll have all of your OS’s *other* files intermixed.
74 Worse, Fossil doesn’t track OS permissions, so even if you were to
75 try to use Fossil as a system deployment tool by archiving versions
76 of the OS configuration files and then unpacking them on a new
77 system, the extracted project files would have read/write access by
78 the user who did the extraction, which probably isn’t want you were
79 wanting.
80
81 Even with these problems aside, do you really want a `.fslckout`
82 SQLite database at the root of your filesystem? Are you prepared for
83 the consequences of saying `fossil clean --verily` on such a system?
@@ -348,11 +348,11 @@
348
349 * In the same way that one cannot extract files from a zip archive
350 without having a copy of that zip file, one cannot make check-outs
351 without access to the repository file or a clone thereof.
352
353 * Because a Fossil repository is a SQLite database file, the same
354 rules for avoiding data corruption apply to it. In particular, it is
355 [nearly a hard requirement][h2cflp] that the repository clone be on
356 the same machine as the one where you make check-outs and the
357 subsequent check-ins.
358
359
--- www/glossary.md
+++ www/glossary.md
@@ -73,11 +73,11 @@
73 because you’ll have all of your OS’s *other* files intermixed.
74 Worse, Fossil doesn’t track OS permissions, so even if you were to
75 try to use Fossil as a system deployment tool by archiving versions
76 of the OS configuration files and then unpacking them on a new
77 system, the extracted project files would have read/write access by
78 the user who did the extraction, which probably isn’t what you were
79 wanting.
80
81 Even with these problems aside, do you really want a `.fslckout`
82 SQLite database at the root of your filesystem? Are you prepared for
83 the consequences of saying `fossil clean --verily` on such a system?
@@ -348,11 +348,11 @@
348
349 * In the same way that one cannot extract files from a zip archive
350 without having a copy of that zip file, one cannot make check-outs
351 without access to the repository file or a clone thereof.
352
353 * Because a Fossil repository is an SQLite database file, the same
354 rules for avoiding data corruption apply to it. In particular, it is
355 [nearly a hard requirement][h2cflp] that the repository clone be on
356 the same machine as the one where you make check-outs and the
357 subsequent check-ins.
358
359
+1 -1
--- www/grep.md
+++ www/grep.md
@@ -49,11 +49,11 @@
4949
5050
$ fossil grep COMMAND: $(fossil ls src)
5151
5252
If you run that in a check-out of the [Fossil self-hosting source
5353
repository][fshsr], that returns the first line of the built-in
54
-documentation for each Fossil command, across all historical verisons.
54
+documentation for each Fossil command, across all historical versions.
5555
5656
Fossil `grep` has extensions relative to these other `grep` standards,
5757
such as `--verbose` to print each checkin ID considered, regardless of
5858
whether it matches. This one is noteworthy here because the behavior
5959
used to be under `-v` before we reassigned it to give POSIX-like `grep
6060
--- www/grep.md
+++ www/grep.md
@@ -49,11 +49,11 @@
49
50 $ fossil grep COMMAND: $(fossil ls src)
51
52 If you run that in a check-out of the [Fossil self-hosting source
53 repository][fshsr], that returns the first line of the built-in
54 documentation for each Fossil command, across all historical verisons.
55
56 Fossil `grep` has extensions relative to these other `grep` standards,
57 such as `--verbose` to print each checkin ID considered, regardless of
58 whether it matches. This one is noteworthy here because the behavior
59 used to be under `-v` before we reassigned it to give POSIX-like `grep
60
--- www/grep.md
+++ www/grep.md
@@ -49,11 +49,11 @@
49
50 $ fossil grep COMMAND: $(fossil ls src)
51
52 If you run that in a check-out of the [Fossil self-hosting source
53 repository][fshsr], that returns the first line of the built-in
54 documentation for each Fossil command, across all historical versions.
55
56 Fossil `grep` has extensions relative to these other `grep` standards,
57 such as `--verbose` to print each checkin ID considered, regardless of
58 whether it matches. This one is noteworthy here because the behavior
59 used to be under `-v` before we reassigned it to give POSIX-like `grep
60
--- www/hashpolicy.wiki
+++ www/hashpolicy.wiki
@@ -78,11 +78,11 @@
7878
Version 2.0 extended the [./fileformat.wiki|Fossil file format]
7979
to allow artifacts to be named by either SHA1 or SHA3-256 hashes.
8080
(SHA3-256 is the only variant of SHA3 that
8181
Fossil uses for artifact naming, so for the remainder of this article
8282
it will be called simply "SHA3". Similarly, "Hardened SHA1" will
83
-shortened to "SHA1" in the remaining text.)
83
+be shortened to "SHA1" in the remaining text.)
8484
8585
To be clear: Fossil (version 2.0 and later)
8686
allows the SHA1 and SHA3 hashes to be mixed within
8787
the same repository. Older check-ins, created years ago,
8888
continue to be named using their legacy SHA1 hashes while
8989
--- www/hashpolicy.wiki
+++ www/hashpolicy.wiki
@@ -78,11 +78,11 @@
78 Version 2.0 extended the [./fileformat.wiki|Fossil file format]
79 to allow artifacts to be named by either SHA1 or SHA3-256 hashes.
80 (SHA3-256 is the only variant of SHA3 that
81 Fossil uses for artifact naming, so for the remainder of this article
82 it will be called simply "SHA3". Similarly, "Hardened SHA1" will
83 shortened to "SHA1" in the remaining text.)
84
85 To be clear: Fossil (version 2.0 and later)
86 allows the SHA1 and SHA3 hashes to be mixed within
87 the same repository. Older check-ins, created years ago,
88 continue to be named using their legacy SHA1 hashes while
89
--- www/hashpolicy.wiki
+++ www/hashpolicy.wiki
@@ -78,11 +78,11 @@
78 Version 2.0 extended the [./fileformat.wiki|Fossil file format]
79 to allow artifacts to be named by either SHA1 or SHA3-256 hashes.
80 (SHA3-256 is the only variant of SHA3 that
81 Fossil uses for artifact naming, so for the remainder of this article
82 it will be called simply "SHA3". Similarly, "Hardened SHA1" will
83 be shortened to "SHA1" in the remaining text.)
84
85 To be clear: Fossil (version 2.0 and later)
86 allows the SHA1 and SHA3 hashes to be mixed within
87 the same repository. Older check-ins, created years ago,
88 continue to be named using their legacy SHA1 hashes while
89
+1 -1
--- www/hints.wiki
+++ www/hints.wiki
@@ -8,11 +8,11 @@
88
2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
99
to get a pop-up
1010
window containing a complete side-by-side diff. (NB: The pop-up
1111
window is run as a separate Tcl/Tk process, so you will need to
1212
have Tcl/Tk installed on your machine for this to work. Visit
13
- [http://www.activestate.com/activetcl] to for a quick download of
13
+ [http://www.activestate.com/activetcl] for a quick download of
1414
Tcl/Tk if you do not already have it on your system.)
1515
1616
3. The "[/help/clean | fossil clean -x]" command is a great
1717
alternative to "make clean". You can use "[/help/clean | fossil clean -f]"
1818
as a slightly safer alternative if the "ignore-glob" setting is
1919
--- www/hints.wiki
+++ www/hints.wiki
@@ -8,11 +8,11 @@
8 2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
9 to get a pop-up
10 window containing a complete side-by-side diff. (NB: The pop-up
11 window is run as a separate Tcl/Tk process, so you will need to
12 have Tcl/Tk installed on your machine for this to work. Visit
13 [http://www.activestate.com/activetcl] to for a quick download of
14 Tcl/Tk if you do not already have it on your system.)
15
16 3. The "[/help/clean | fossil clean -x]" command is a great
17 alternative to "make clean". You can use "[/help/clean | fossil clean -f]"
18 as a slightly safer alternative if the "ignore-glob" setting is
19
--- www/hints.wiki
+++ www/hints.wiki
@@ -8,11 +8,11 @@
8 2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
9 to get a pop-up
10 window containing a complete side-by-side diff. (NB: The pop-up
11 window is run as a separate Tcl/Tk process, so you will need to
12 have Tcl/Tk installed on your machine for this to work. Visit
13 [http://www.activestate.com/activetcl] for a quick download of
14 Tcl/Tk if you do not already have it on your system.)
15
16 3. The "[/help/clean | fossil clean -x]" command is a great
17 alternative to "make clean". You can use "[/help/clean | fossil clean -f]"
18 as a slightly safer alternative if the "ignore-glob" setting is
19
+1 -1
--- www/history.md
+++ www/history.md
@@ -16,11 +16,11 @@
1616
1717
[120]: /reports?type=ci&view=byuser
1818
1919
## History
2020
21
-The SQLite project start out using [CVS][300], as CVS was the most
21
+The SQLite project started out using [CVS][300], as CVS was the most
2222
commonly used version control system in that era (circa 2000). CVS
2323
was an amazing version control system for its day in that it allowed
2424
multiple developers to be editing the same file at the same time.
2525
2626
[300]: https://en.wikipedia.org/wiki/Concurrent_Versions_System
2727
--- www/history.md
+++ www/history.md
@@ -16,11 +16,11 @@
16
17 [120]: /reports?type=ci&view=byuser
18
19 ## History
20
21 The SQLite project start out using [CVS][300], as CVS was the most
22 commonly used version control system in that era (circa 2000). CVS
23 was an amazing version control system for its day in that it allowed
24 multiple developers to be editing the same file at the same time.
25
26 [300]: https://en.wikipedia.org/wiki/Concurrent_Versions_System
27
--- www/history.md
+++ www/history.md
@@ -16,11 +16,11 @@
16
17 [120]: /reports?type=ci&view=byuser
18
19 ## History
20
21 The SQLite project started out using [CVS][300], as CVS was the most
22 commonly used version control system in that era (circa 2000). CVS
23 was an amazing version control system for its day in that it allowed
24 multiple developers to be editing the same file at the same time.
25
26 [300]: https://en.wikipedia.org/wiki/Concurrent_Versions_System
27
+4 -4
--- www/hooks.md
+++ www/hooks.md
@@ -5,11 +5,11 @@
55
a continuous integration (CI) system.
66
77
## Interim Documentation.
88
99
* This is a work-in-progress. The interface is in flux.
10
- For the time being, the documentation as a list of
10
+ For the time being, the documentation is a list of
1111
bullet points. We hope to transform this into a proper document
1212
later, after things settle down.
1313
1414
* Contributions and suggestions to the hook system and/or the
1515
documentation are welcomed.
@@ -35,14 +35,14 @@
3535
that the original script can return.
3636
3737
* The "%F" sequence inside the script is translated into the
3838
name of the fossil executable.
3939
40
- * The "%R" sequence in the script is translated in to the name of
40
+ * The "%R" sequence in the script is translated into the name of
4141
the repository.
4242
43
- * The "%A" sequence becomes the name of an auxiliary input files,
43
+ * The "%A" sequence becomes the name of an auxiliary input file,
4444
the meaning of which depends on the hook type. The auxiliary filename
4545
might be an empty string. Take care to use appropriate quoting!
4646
4747
## Disabled Hooks
4848
@@ -144,11 +144,11 @@
144144
## Commit-Msg Hooks
145145
146146
* Commit-msg hooks are not yet implemented.
147147
148148
* The commit-msg hooks run during "fossil commit" after the check-in
149
- messages has been entered by the user. The "%A" argument to the
149
+ message has been entered by the user. The "%A" argument to the
150150
commit-msg hook is the text of the commit message. The intent
151151
of the commit-msg hook is to validate the text of the commit
152152
message to (for example) check for typos or ensure that it
153153
conforms to standards.
154154
155155
--- www/hooks.md
+++ www/hooks.md
@@ -5,11 +5,11 @@
5 a continuous integration (CI) system.
6
7 ## Interim Documentation.
8
9 * This is a work-in-progress. The interface is in flux.
10 For the time being, the documentation as a list of
11 bullet points. We hope to transform this into a proper document
12 later, after things settle down.
13
14 * Contributions and suggestions to the hook system and/or the
15 documentation are welcomed.
@@ -35,14 +35,14 @@
35 that the original script can return.
36
37 * The "%F" sequence inside the script is translated into the
38 name of the fossil executable.
39
40 * The "%R" sequence in the script is translated in to the name of
41 the repository.
42
43 * The "%A" sequence becomes the name of an auxiliary input files,
44 the meaning of which depends on the hook type. The auxiliary filename
45 might be an empty string. Take care to use appropriate quoting!
46
47 ## Disabled Hooks
48
@@ -144,11 +144,11 @@
144 ## Commit-Msg Hooks
145
146 * Commit-msg hooks are not yet implemented.
147
148 * The commit-msg hooks run during "fossil commit" after the check-in
149 messages has been entered by the user. The "%A" argument to the
150 commit-msg hook is the text of the commit message. The intent
151 of the commit-msg hook is to validate the text of the commit
152 message to (for example) check for typos or ensure that it
153 conforms to standards.
154
155
--- www/hooks.md
+++ www/hooks.md
@@ -5,11 +5,11 @@
5 a continuous integration (CI) system.
6
7 ## Interim Documentation.
8
9 * This is a work-in-progress. The interface is in flux.
10 For the time being, the documentation is a list of
11 bullet points. We hope to transform this into a proper document
12 later, after things settle down.
13
14 * Contributions and suggestions to the hook system and/or the
15 documentation are welcomed.
@@ -35,14 +35,14 @@
35 that the original script can return.
36
37 * The "%F" sequence inside the script is translated into the
38 name of the fossil executable.
39
40 * The "%R" sequence in the script is translated into the name of
41 the repository.
42
43 * The "%A" sequence becomes the name of an auxiliary input file,
44 the meaning of which depends on the hook type. The auxiliary filename
45 might be an empty string. Take care to use appropriate quoting!
46
47 ## Disabled Hooks
48
@@ -144,11 +144,11 @@
144 ## Commit-Msg Hooks
145
146 * Commit-msg hooks are not yet implemented.
147
148 * The commit-msg hooks run during "fossil commit" after the check-in
149 message has been entered by the user. The "%A" argument to the
150 commit-msg hook is the text of the commit message. The intent
151 of the commit-msg hook is to validate the text of the commit
152 message to (for example) check for typos or ensure that it
153 conforms to standards.
154
155
+4 -4
--- www/index.wiki
+++ www/index.wiki
@@ -84,16 +84,16 @@
8484
the repository are consistent prior to each commit.
8585
8686
8. <b>Free and Open-Source</b> — [../COPYRIGHT-BSD2.txt|2-clause BSD license].
8787
8888
<hr>
89
-<h3>Latest Release: 2.24 ([/timeline?c=version-2.24|2024-04-23])</h3>
89
+<h3>Latest Release: 2.25 ([/timeline?c=version-2.25|2024-11-06])</h3>
9090
9191
* [/uv/download.html|Download]
92
- * [./changes.wiki#v2_24|Change Summary]
93
- * [/timeline?p=version-2.24&bt=version-2.23&y=ci|Check-ins in version 2.24]
94
- * [/timeline?df=version-2.24&y=ci|Check-ins derived from the 2.24 release]
92
+ * [./changes.wiki#v2_25|Change Summary]
93
+ * [/timeline?p=version-2.25&bt=version-2.24&y=ci|Check-ins in version 2.25]
94
+ * [/timeline?df=version-2.25&y=ci|Check-ins derived from the 2.25 release]
9595
* [/timeline?t=release|Timeline of all past releases]
9696
9797
<hr>
9898
<h3>Quick Start</h3>
9999
100100
--- www/index.wiki
+++ www/index.wiki
@@ -84,16 +84,16 @@
84 the repository are consistent prior to each commit.
85
86 8. <b>Free and Open-Source</b> — [../COPYRIGHT-BSD2.txt|2-clause BSD license].
87
88 <hr>
89 <h3>Latest Release: 2.24 ([/timeline?c=version-2.24|2024-04-23])</h3>
90
91 * [/uv/download.html|Download]
92 * [./changes.wiki#v2_24|Change Summary]
93 * [/timeline?p=version-2.24&bt=version-2.23&y=ci|Check-ins in version 2.24]
94 * [/timeline?df=version-2.24&y=ci|Check-ins derived from the 2.24 release]
95 * [/timeline?t=release|Timeline of all past releases]
96
97 <hr>
98 <h3>Quick Start</h3>
99
100
--- www/index.wiki
+++ www/index.wiki
@@ -84,16 +84,16 @@
84 the repository are consistent prior to each commit.
85
86 8. <b>Free and Open-Source</b> — [../COPYRIGHT-BSD2.txt|2-clause BSD license].
87
88 <hr>
89 <h3>Latest Release: 2.25 ([/timeline?c=version-2.25|2024-11-06])</h3>
90
91 * [/uv/download.html|Download]
92 * [./changes.wiki#v2_25|Change Summary]
93 * [/timeline?p=version-2.25&bt=version-2.24&y=ci|Check-ins in version 2.25]
94 * [/timeline?df=version-2.25&y=ci|Check-ins derived from the 2.25 release]
95 * [/timeline?t=release|Timeline of all past releases]
96
97 <hr>
98 <h3>Quick Start</h3>
99
100
+2 -2
--- www/inout.wiki
+++ www/inout.wiki
@@ -48,11 +48,11 @@
4848
emitted by "<tt>git fast-export</tt>" before sending it along to Fossil,
4949
but we've seen the problem recur on multiple machines.
5050
5151
While one workaround is to fall back to <tt>cmd.exe</tt> — which doesn't
5252
seem to be affected by this problem — we instead recommend using
53
-Mirosoft's own [https://learn.microsoft.com/en-us/windows/wsl/ | Windows
53
+Microsoft's own [https://learn.microsoft.com/en-us/windows/wsl/ | Windows
5454
Subsystem for Linux] or either of the two popular "Git for Windows"
5555
distributions based on MSYS2. They handle pipes the POSIX way, avoiding
5656
any dependency on the amount of data involved.
5757
5858
<h2>Fossil → Git</h2>
@@ -76,11 +76,11 @@
7676
As with the "import" command, the --git option is not required
7777
since the git-fast-export file format is currently the only VCS interchange
7878
format that Fossil will generate. However,
7979
future versions of Fossil might add the ability to generate other
8080
VCS interchange formats, and so for compatibility, the use of the --git
81
-option recommended.
81
+option is recommended.
8282
8383
<h2>Mirror A Fossil Repository In Git</h2>
8484
8585
Fossil version 2.9 and later supports a simple mechanism for
8686
doing a Git or
8787
--- www/inout.wiki
+++ www/inout.wiki
@@ -48,11 +48,11 @@
48 emitted by "<tt>git fast-export</tt>" before sending it along to Fossil,
49 but we've seen the problem recur on multiple machines.
50
51 While one workaround is to fall back to <tt>cmd.exe</tt> — which doesn't
52 seem to be affected by this problem — we instead recommend using
53 Mirosoft's own [https://learn.microsoft.com/en-us/windows/wsl/ | Windows
54 Subsystem for Linux] or either of the two popular "Git for Windows"
55 distributions based on MSYS2. They handle pipes the POSIX way, avoiding
56 any dependency on the amount of data involved.
57
58 <h2>Fossil → Git</h2>
@@ -76,11 +76,11 @@
76 As with the "import" command, the --git option is not required
77 since the git-fast-export file format is currently the only VCS interchange
78 format that Fossil will generate. However,
79 future versions of Fossil might add the ability to generate other
80 VCS interchange formats, and so for compatibility, the use of the --git
81 option recommended.
82
83 <h2>Mirror A Fossil Repository In Git</h2>
84
85 Fossil version 2.9 and later supports a simple mechanism for
86 doing a Git or
87
--- www/inout.wiki
+++ www/inout.wiki
@@ -48,11 +48,11 @@
48 emitted by "<tt>git fast-export</tt>" before sending it along to Fossil,
49 but we've seen the problem recur on multiple machines.
50
51 While one workaround is to fall back to <tt>cmd.exe</tt> — which doesn't
52 seem to be affected by this problem — we instead recommend using
53 Microsoft's own [https://learn.microsoft.com/en-us/windows/wsl/ | Windows
54 Subsystem for Linux] or either of the two popular "Git for Windows"
55 distributions based on MSYS2. They handle pipes the POSIX way, avoiding
56 any dependency on the amount of data involved.
57
58 <h2>Fossil → Git</h2>
@@ -76,11 +76,11 @@
76 As with the "import" command, the --git option is not required
77 since the git-fast-export file format is currently the only VCS interchange
78 format that Fossil will generate. However,
79 future versions of Fossil might add the ability to generate other
80 VCS interchange formats, and so for compatibility, the use of the --git
81 option is recommended.
82
83 <h2>Mirror A Fossil Repository In Git</h2>
84
85 Fossil version 2.9 and later supports a simple mechanism for
86 doing a Git or
87
--- www/interwiki.md
+++ www/interwiki.md
@@ -50,11 +50,11 @@
5050
or is an empty string.
5151
5252
2. <b>Hash Links</b> &rarr; the PageName is a hexadecimal number with
5353
at least four digits.
5454
55
- 3. <b>Wiki Links</b> &rarr; An PageName that is not a Path or Hash.
55
+ 3. <b>Wiki Links</b> &rarr; A PageName that is not a Path or Hash.
5656
5757
The Intermap defines a base URL for each Tag. Path links are appended
5858
directly to the URL contained in the Intermap. The Intermap can define
5959
additional text to put in between the base URL and the PageName for
6060
Hash and Wiki links, respectively.
@@ -62,11 +62,11 @@
6262
<a id="intermap"></a>
6363
## Intermap
6464
6565
The intermap defines a mapping from interwiki Tags to full URLs. The
6666
Intermap can be viewed and managed using the [fossil interwiki][iwiki]
67
-command or the [/intermap][imap] webpages.
67
+command or the [/intermap][imap] webpage.
6868
6969
[iwiki]: /help?cmd=interwiki
7070
[imap]: /intermap
7171
7272
The current intermap for a server is seen on the [/intermap][imap] page
@@ -77,19 +77,19 @@
7777
Each intermap entry stores, at a minimum, the base URL for the remote
7878
wiki. The intermap entry might also store additional path text that
7979
is used for Hash and Wiki links. If only the base URL is provided,
8080
then the intermap will only allow Path style interwiki links. The
8181
Hash and Wiki style interwiki links are only allowed if the necessary
82
-extensions for provided in the intermap.
82
+extensions are provided in the intermap.
8383
8484
8585
## Disadvantages and Limitations
8686
8787
* Configuration is required. The intermap must be set up correctly
8888
before interwiki links will work. This contrasts with ordinary
8989
links that just work without any configuration. Cloning a repository
90
- copies the intermap, but normal syncs to not keep the intermap in
90
+ copies the intermap, but normal syncs do not keep the intermap in
9191
sync. Use the "[fossil config pull interwiki][fcfg]" command to
9292
synchronize the intermap.
9393
9494
* The is no backlink tracking. For ordinary intrawiki links, Fossil keeps
9595
track of both the source and target, and when displaying targets it
@@ -96,11 +96,11 @@
9696
commonly shows links to that target. For example, if you mention a
9797
check-in as part of a comment of another check-in, that new check-in
9898
shows up in the "References" section of the target check-in.
9999
([example](31af805348690958). In other words, Fossil tracks not just
100100
"_source&rarr;target_", but it also tracks "_target&rarr;source_".
101
- But backtracking do not work for interwiki links, since the Fossil
101
+ But backtracking does not work for interwiki links, since the Fossil
102102
running on the target has no way of scanning the source text and
103103
hence has no way of knowing that it is a target of a link from the source.
104104
105105
[fcfg]: /help?cmd=config
106106
107107
--- www/interwiki.md
+++ www/interwiki.md
@@ -50,11 +50,11 @@
50 or is an empty string.
51
52 2. <b>Hash Links</b> &rarr; the PageName is a hexadecimal number with
53 at least four digits.
54
55 3. <b>Wiki Links</b> &rarr; An PageName that is not a Path or Hash.
56
57 The Intermap defines a base URL for each Tag. Path links are appended
58 directly to the URL contained in the Intermap. The Intermap can define
59 additional text to put in between the base URL and the PageName for
60 Hash and Wiki links, respectively.
@@ -62,11 +62,11 @@
62 <a id="intermap"></a>
63 ## Intermap
64
65 The intermap defines a mapping from interwiki Tags to full URLs. The
66 Intermap can be viewed and managed using the [fossil interwiki][iwiki]
67 command or the [/intermap][imap] webpages.
68
69 [iwiki]: /help?cmd=interwiki
70 [imap]: /intermap
71
72 The current intermap for a server is seen on the [/intermap][imap] page
@@ -77,19 +77,19 @@
77 Each intermap entry stores, at a minimum, the base URL for the remote
78 wiki. The intermap entry might also store additional path text that
79 is used for Hash and Wiki links. If only the base URL is provided,
80 then the intermap will only allow Path style interwiki links. The
81 Hash and Wiki style interwiki links are only allowed if the necessary
82 extensions for provided in the intermap.
83
84
85 ## Disadvantages and Limitations
86
87 * Configuration is required. The intermap must be set up correctly
88 before interwiki links will work. This contrasts with ordinary
89 links that just work without any configuration. Cloning a repository
90 copies the intermap, but normal syncs to not keep the intermap in
91 sync. Use the "[fossil config pull interwiki][fcfg]" command to
92 synchronize the intermap.
93
94 * The is no backlink tracking. For ordinary intrawiki links, Fossil keeps
95 track of both the source and target, and when displaying targets it
@@ -96,11 +96,11 @@
96 commonly shows links to that target. For example, if you mention a
97 check-in as part of a comment of another check-in, that new check-in
98 shows up in the "References" section of the target check-in.
99 ([example](31af805348690958). In other words, Fossil tracks not just
100 "_source&rarr;target_", but it also tracks "_target&rarr;source_".
101 But backtracking do not work for interwiki links, since the Fossil
102 running on the target has no way of scanning the source text and
103 hence has no way of knowing that it is a target of a link from the source.
104
105 [fcfg]: /help?cmd=config
106
107
--- www/interwiki.md
+++ www/interwiki.md
@@ -50,11 +50,11 @@
50 or is an empty string.
51
52 2. <b>Hash Links</b> &rarr; the PageName is a hexadecimal number with
53 at least four digits.
54
55 3. <b>Wiki Links</b> &rarr; A PageName that is not a Path or Hash.
56
57 The Intermap defines a base URL for each Tag. Path links are appended
58 directly to the URL contained in the Intermap. The Intermap can define
59 additional text to put in between the base URL and the PageName for
60 Hash and Wiki links, respectively.
@@ -62,11 +62,11 @@
62 <a id="intermap"></a>
63 ## Intermap
64
65 The intermap defines a mapping from interwiki Tags to full URLs. The
66 Intermap can be viewed and managed using the [fossil interwiki][iwiki]
67 command or the [/intermap][imap] webpage.
68
69 [iwiki]: /help?cmd=interwiki
70 [imap]: /intermap
71
72 The current intermap for a server is seen on the [/intermap][imap] page
@@ -77,19 +77,19 @@
77 Each intermap entry stores, at a minimum, the base URL for the remote
78 wiki. The intermap entry might also store additional path text that
79 is used for Hash and Wiki links. If only the base URL is provided,
80 then the intermap will only allow Path style interwiki links. The
81 Hash and Wiki style interwiki links are only allowed if the necessary
82 extensions are provided in the intermap.
83
84
85 ## Disadvantages and Limitations
86
87 * Configuration is required. The intermap must be set up correctly
88 before interwiki links will work. This contrasts with ordinary
89 links that just work without any configuration. Cloning a repository
90 copies the intermap, but normal syncs do not keep the intermap in
91 sync. Use the "[fossil config pull interwiki][fcfg]" command to
92 synchronize the intermap.
93
94 * The is no backlink tracking. For ordinary intrawiki links, Fossil keeps
95 track of both the source and target, and when displaying targets it
@@ -96,11 +96,11 @@
96 commonly shows links to that target. For example, if you mention a
97 check-in as part of a comment of another check-in, that new check-in
98 shows up in the "References" section of the target check-in.
99 ([example](31af805348690958). In other words, Fossil tracks not just
100 "_source&rarr;target_", but it also tracks "_target&rarr;source_".
101 But backtracking does not work for interwiki links, since the Fossil
102 running on the target has no way of scanning the source text and
103 hence has no way of knowing that it is a target of a link from the source.
104
105 [fcfg]: /help?cmd=config
106
107
--- www/json-api/api-artifact.md
+++ www/json-api/api-artifact.md
@@ -71,11 +71,11 @@
7171
# File Artifacts
7272
7373
Fetches information about file artifacts.
7474
7575
**FIXME:** the content type guessing is currently very primitive, and
76
-may (but i haven't seen this) mis-diagnose some non-binary files as
76
+may (but I haven't seen this) mis-diagnose some non-binary files as
7777
binary. Fossil doesn't yet have a mechanism for mime-type mappings.
7878
7979
**Status:** implemented 20111020
8080
8181
**Required permissions:** "o"
8282
--- www/json-api/api-artifact.md
+++ www/json-api/api-artifact.md
@@ -71,11 +71,11 @@
71 # File Artifacts
72
73 Fetches information about file artifacts.
74
75 **FIXME:** the content type guessing is currently very primitive, and
76 may (but i haven't seen this) mis-diagnose some non-binary files as
77 binary. Fossil doesn't yet have a mechanism for mime-type mappings.
78
79 **Status:** implemented 20111020
80
81 **Required permissions:** "o"
82
--- www/json-api/api-artifact.md
+++ www/json-api/api-artifact.md
@@ -71,11 +71,11 @@
71 # File Artifacts
72
73 Fetches information about file artifacts.
74
75 **FIXME:** the content type guessing is currently very primitive, and
76 may (but I haven't seen this) mis-diagnose some non-binary files as
77 binary. Fossil doesn't yet have a mechanism for mime-type mappings.
78
79 **Status:** implemented 20111020
80
81 **Required permissions:** "o"
82
--- www/json-api/api-auth.md
+++ www/json-api/api-auth.md
@@ -33,11 +33,11 @@
3333
purposes, the "auth token" and the "login cookie" are the same thing (or
3434
serve the same purpose), and the auth token is in fact just the value
3535
part of the login cookie (which has a project-specific key).
3636
3737
Note that fossil has two conventional user names which can show up in
38
-various response but do not refer to specific people: nobody and
38
+various responses but do not refer to specific people: nobody and
3939
anonymous. The nobody user is anyone who is not logged in. The anonymous
4040
user is logged in but has no persistent user data (no associated user
4141
name, email address, or similar). Normally the guest (nobody) user has
4242
more access restrictions. The distinction between the two is largely
4343
historical - it is a mechanism to keep bots from following the
@@ -158,11 +158,11 @@
158158
tickets is disabled for the guest user then all non-guest users must
159159
send authentication info in their requests in order to be able to fetch
160160
ticket info.
161161
162162
Cookie-aware clients should send the login-generated cookie with each
163
-request, in which case they do not need explicitly include the
163
+request, in which case they do not need to explicitly include the
164164
`authToken` in the JSON envelope/GET arguments. If submitted, the
165165
`authToken` is used, otherwise the cookie, if set, is used. Note that
166166
fossil uses a project-dependent cookie name in order to help thwart
167167
attacks, so there is no simple mapping of cookie *name* to auth
168168
token. That said, the cookie's *value* is also the auth token's value.
@@ -200,11 +200,11 @@
200200
201201
The password value *may* be time-limited, and *may* eventually become
202202
invalidated due to old age. This is unspecified.
203203
204204
***Potential***** (low-probability) bug regarding the seed value:** from
205
-what i hear, some unusual JSON platforms don't support full 32-bit
205
+what I hear, some unusual JSON platforms don't support full 32-bit
206206
precision. If absolutely necessary we could chop off a bit or two from
207207
the seed value (*if* it ever becomes a problem and if DRH blesses it).
208208
Or we could just make it a double.
209209
210210
211211
--- www/json-api/api-auth.md
+++ www/json-api/api-auth.md
@@ -33,11 +33,11 @@
33 purposes, the "auth token" and the "login cookie" are the same thing (or
34 serve the same purpose), and the auth token is in fact just the value
35 part of the login cookie (which has a project-specific key).
36
37 Note that fossil has two conventional user names which can show up in
38 various response but do not refer to specific people: nobody and
39 anonymous. The nobody user is anyone who is not logged in. The anonymous
40 user is logged in but has no persistent user data (no associated user
41 name, email address, or similar). Normally the guest (nobody) user has
42 more access restrictions. The distinction between the two is largely
43 historical - it is a mechanism to keep bots from following the
@@ -158,11 +158,11 @@
158 tickets is disabled for the guest user then all non-guest users must
159 send authentication info in their requests in order to be able to fetch
160 ticket info.
161
162 Cookie-aware clients should send the login-generated cookie with each
163 request, in which case they do not need explicitly include the
164 `authToken` in the JSON envelope/GET arguments. If submitted, the
165 `authToken` is used, otherwise the cookie, if set, is used. Note that
166 fossil uses a project-dependent cookie name in order to help thwart
167 attacks, so there is no simple mapping of cookie *name* to auth
168 token. That said, the cookie's *value* is also the auth token's value.
@@ -200,11 +200,11 @@
200
201 The password value *may* be time-limited, and *may* eventually become
202 invalidated due to old age. This is unspecified.
203
204 ***Potential***** (low-probability) bug regarding the seed value:** from
205 what i hear, some unusual JSON platforms don't support full 32-bit
206 precision. If absolutely necessary we could chop off a bit or two from
207 the seed value (*if* it ever becomes a problem and if DRH blesses it).
208 Or we could just make it a double.
209
210
211
--- www/json-api/api-auth.md
+++ www/json-api/api-auth.md
@@ -33,11 +33,11 @@
33 purposes, the "auth token" and the "login cookie" are the same thing (or
34 serve the same purpose), and the auth token is in fact just the value
35 part of the login cookie (which has a project-specific key).
36
37 Note that fossil has two conventional user names which can show up in
38 various responses but do not refer to specific people: nobody and
39 anonymous. The nobody user is anyone who is not logged in. The anonymous
40 user is logged in but has no persistent user data (no associated user
41 name, email address, or similar). Normally the guest (nobody) user has
42 more access restrictions. The distinction between the two is largely
43 historical - it is a mechanism to keep bots from following the
@@ -158,11 +158,11 @@
158 tickets is disabled for the guest user then all non-guest users must
159 send authentication info in their requests in order to be able to fetch
160 ticket info.
161
162 Cookie-aware clients should send the login-generated cookie with each
163 request, in which case they do not need to explicitly include the
164 `authToken` in the JSON envelope/GET arguments. If submitted, the
165 `authToken` is used, otherwise the cookie, if set, is used. Note that
166 fossil uses a project-dependent cookie name in order to help thwart
167 attacks, so there is no simple mapping of cookie *name* to auth
168 token. That said, the cookie's *value* is also the auth token's value.
@@ -200,11 +200,11 @@
200
201 The password value *may* be time-limited, and *may* eventually become
202 invalidated due to old age. This is unspecified.
203
204 ***Potential***** (low-probability) bug regarding the seed value:** from
205 what I hear, some unusual JSON platforms don't support full 32-bit
206 precision. If absolutely necessary we could chop off a bit or two from
207 the seed value (*if* it ever becomes a problem and if DRH blesses it).
208 Or we could just make it a double.
209
210
211
--- www/json-api/api-checkout.md
+++ www/json-api/api-checkout.md
@@ -7,11 +7,11 @@
77
88
**Required permissions:** n/a (local access only)
99
1010
**Request:** `/json/status`
1111
12
-This command requires a local checkout and is analog to the "fossil
12
+This command requires a local checkout and is the analog to the "fossil
1313
status" command.
1414
1515
**Request Options:** currently none.
1616
1717
Payload example:
1818
--- www/json-api/api-checkout.md
+++ www/json-api/api-checkout.md
@@ -7,11 +7,11 @@
7
8 **Required permissions:** n/a (local access only)
9
10 **Request:** `/json/status`
11
12 This command requires a local checkout and is analog to the "fossil
13 status" command.
14
15 **Request Options:** currently none.
16
17 Payload example:
18
--- www/json-api/api-checkout.md
+++ www/json-api/api-checkout.md
@@ -7,11 +7,11 @@
7
8 **Required permissions:** n/a (local access only)
9
10 **Request:** `/json/status`
11
12 This command requires a local checkout and is the analog to the "fossil
13 status" command.
14
15 **Request Options:** currently none.
16
17 Payload example:
18
--- www/json-api/api-finfo.md
+++ www/json-api/api-finfo.md
@@ -20,11 +20,11 @@
2020
as opposed to listing all checkins. If set, neither "before" nor
2121
"after" have any effect.\
2222
CLI mode: `--checkin|-ci`
2323
- `before=DATETIME` only lists checkins from on or before this time.\
2424
CLI mode: `--before|-b`
25
-- `after=DATETIME` only lists checkins from on or before this time.
25
+- `after=DATETIME` only lists checkins from on or after this time.
2626
Using this option swaps the sort order, to provide reasonable
2727
behaviour in conjunction with the limit option.\
2828
Only one of "before" and "after" may be specified, and if both are
2929
specified then which one takes precedence is unspecified.\
3030
CLI mode: `--after|-a`
3131
--- www/json-api/api-finfo.md
+++ www/json-api/api-finfo.md
@@ -20,11 +20,11 @@
20 as opposed to listing all checkins. If set, neither "before" nor
21 "after" have any effect.\
22 CLI mode: `--checkin|-ci`
23 - `before=DATETIME` only lists checkins from on or before this time.\
24 CLI mode: `--before|-b`
25 - `after=DATETIME` only lists checkins from on or before this time.
26 Using this option swaps the sort order, to provide reasonable
27 behaviour in conjunction with the limit option.\
28 Only one of "before" and "after" may be specified, and if both are
29 specified then which one takes precedence is unspecified.\
30 CLI mode: `--after|-a`
31
--- www/json-api/api-finfo.md
+++ www/json-api/api-finfo.md
@@ -20,11 +20,11 @@
20 as opposed to listing all checkins. If set, neither "before" nor
21 "after" have any effect.\
22 CLI mode: `--checkin|-ci`
23 - `before=DATETIME` only lists checkins from on or before this time.\
24 CLI mode: `--before|-b`
25 - `after=DATETIME` only lists checkins from on or after this time.
26 Using this option swaps the sort order, to provide reasonable
27 behaviour in conjunction with the limit option.\
28 Only one of "before" and "after" may be specified, and if both are
29 specified then which one takes precedence is unspecified.\
30 CLI mode: `--after|-a`
31
--- www/json-api/api-query.md
+++ www/json-api/api-query.md
@@ -60,11 +60,11 @@
6060
6161
]
6262
}
6363
```
6464
65
-The column names are provided in a separate field is because their order
65
+The column names are provided in a separate field because their order
6666
is guaranteed to match the order of the query columns, whereas object
6767
key/value pairs might get reordered (typically sorted by key) when
6868
travelling through different JSON implementations. In this manner,
6969
clients can e.g. be sure to render the columns in the proper
7070
(query-specified) order.
@@ -76,10 +76,10 @@
7676
7777
Note the column *names* are never *guaranteed* to be exactly as they
7878
appear in the SQL *unless* they are qualified with an AS, e.g. `SELECT
7979
foo AS foo...`. When generating reports which need fixed column names, it
8080
is highly recommended to use an AS qualifier for every column, even if
81
-they use the same name as the column. This is the only way to guaranty
81
+they use the same name as the column. This is the only way to guarantee
8282
that the result column names will be stable. (FYI: that behaviour comes
8383
from sqlite3, not the JSON bits, and this behaviour *has* been known to
8484
change between sqlite3 versions (so this is not just an idle threat of
8585
*potential* future incompatibility).)
8686
--- www/json-api/api-query.md
+++ www/json-api/api-query.md
@@ -60,11 +60,11 @@
60
61 ]
62 }
63 ```
64
65 The column names are provided in a separate field is because their order
66 is guaranteed to match the order of the query columns, whereas object
67 key/value pairs might get reordered (typically sorted by key) when
68 travelling through different JSON implementations. In this manner,
69 clients can e.g. be sure to render the columns in the proper
70 (query-specified) order.
@@ -76,10 +76,10 @@
76
77 Note the column *names* are never *guaranteed* to be exactly as they
78 appear in the SQL *unless* they are qualified with an AS, e.g. `SELECT
79 foo AS foo...`. When generating reports which need fixed column names, it
80 is highly recommended to use an AS qualifier for every column, even if
81 they use the same name as the column. This is the only way to guaranty
82 that the result column names will be stable. (FYI: that behaviour comes
83 from sqlite3, not the JSON bits, and this behaviour *has* been known to
84 change between sqlite3 versions (so this is not just an idle threat of
85 *potential* future incompatibility).)
86
--- www/json-api/api-query.md
+++ www/json-api/api-query.md
@@ -60,11 +60,11 @@
60
61 ]
62 }
63 ```
64
65 The column names are provided in a separate field because their order
66 is guaranteed to match the order of the query columns, whereas object
67 key/value pairs might get reordered (typically sorted by key) when
68 travelling through different JSON implementations. In this manner,
69 clients can e.g. be sure to render the columns in the proper
70 (query-specified) order.
@@ -76,10 +76,10 @@
76
77 Note the column *names* are never *guaranteed* to be exactly as they
78 appear in the SQL *unless* they are qualified with an AS, e.g. `SELECT
79 foo AS foo...`. When generating reports which need fixed column names, it
80 is highly recommended to use an AS qualifier for every column, even if
81 they use the same name as the column. This is the only way to guarantee
82 that the result column names will be stable. (FYI: that behaviour comes
83 from sqlite3, not the JSON bits, and this behaviour *has* been known to
84 change between sqlite3 versions (so this is not just an idle threat of
85 *potential* future incompatibility).)
86
--- www/json-api/api-tag.md
+++ www/json-api/api-tag.md
@@ -98,15 +98,15 @@
9898
path element.
9999
- `limit=int` (defalt=0) Limits the number of results (0=no limit).
100100
Since they are ordered from oldest to newest, the newest N results
101101
will be returned.
102102
- `type=string` (default=`*`) Searches only for the given type of
103
- artifact (using fossil's conventional type naming: ci, e, t, w.
103
+ artifact (using fossil's conventional type naming: ci, e, t, w.)
104104
- `raw=bool` (=false) If enabled, the response is an array of hashes
105105
of the requested artifact type; otherwise,
106106
it is an array of higher-level objects. If this is
107
- true, the "name" property is interpretted as-is. If it is false, the
107
+ true, the "name" property is interpreted as-is. If it is false, the
108108
name is automatically prepended with "sym-" (meaning a branch).
109109
(FIXME: the current semantics are confusing and hard to remember.
110110
Re-do them.)
111111
112112
**Response payload example, in RAW mode: (expect this format to change
113113
--- www/json-api/api-tag.md
+++ www/json-api/api-tag.md
@@ -98,15 +98,15 @@
98 path element.
99 - `limit=int` (defalt=0) Limits the number of results (0=no limit).
100 Since they are ordered from oldest to newest, the newest N results
101 will be returned.
102 - `type=string` (default=`*`) Searches only for the given type of
103 artifact (using fossil's conventional type naming: ci, e, t, w.
104 - `raw=bool` (=false) If enabled, the response is an array of hashes
105 of the requested artifact type; otherwise,
106 it is an array of higher-level objects. If this is
107 true, the "name" property is interpretted as-is. If it is false, the
108 name is automatically prepended with "sym-" (meaning a branch).
109 (FIXME: the current semantics are confusing and hard to remember.
110 Re-do them.)
111
112 **Response payload example, in RAW mode: (expect this format to change
113
--- www/json-api/api-tag.md
+++ www/json-api/api-tag.md
@@ -98,15 +98,15 @@
98 path element.
99 - `limit=int` (defalt=0) Limits the number of results (0=no limit).
100 Since they are ordered from oldest to newest, the newest N results
101 will be returned.
102 - `type=string` (default=`*`) Searches only for the given type of
103 artifact (using fossil's conventional type naming: ci, e, t, w.)
104 - `raw=bool` (=false) If enabled, the response is an array of hashes
105 of the requested artifact type; otherwise,
106 it is an array of higher-level objects. If this is
107 true, the "name" property is interpreted as-is. If it is false, the
108 name is automatically prepended with "sym-" (meaning a branch).
109 (FIXME: the current semantics are confusing and hard to remember.
110 Re-do them.)
111
112 **Response payload example, in RAW mode: (expect this format to change
113
--- www/json-api/conventions.md
+++ www/json-api/conventions.md
@@ -100,11 +100,11 @@
100100
101101
The API allows most of those (normally all but the payload) to come in
102102
as either GET parameters or properties of the top-level POSTed request
103103
JSON envelope, with GET taking priority over POST. (Reminder to self: we
104104
could potentially also use values from cookies. Fossil currently only
105
-uses 1 cookie (the login token), and i'd prefer to keep it that way.)
105
+uses 1 cookie (the login token), and I'd prefer to keep it that way.)
106106
107107
POST requests without such an envelope will be rejected, generating a
108108
Fossil/JSON error response (as opposed to an HTTP error response). GET
109109
requests, by definition, never have an envelope.
110110
@@ -169,11 +169,11 @@
169169
No higher-level constructs, e.g. JSON **arrays** or **objects**, are
170170
accepted in string form. Such parameters must be set in the POST
171171
envelope or payload, as specified by the specific API.
172172
173173
This API does not currently use any **floating-point** parameters, but
174
-does return floating-point results in a couple places.
174
+does return floating-point results in a couple of places.
175175
176176
For **integer** parameters we use a conventional string-to-int algorithm
177177
and assume base 10 (analog to atoi(3)). The API may err on the side of
178178
usability when given technically invalid values. e.g. "123abc" will
179179
likely be interpreted as the integer 123. No APIs currently rely on
@@ -205,11 +205,11 @@
205205
cause inconsistencies vis-a-vis the HTML interface).
206206
207207
<a id="response-envelope"></a>
208208
# Response Envelope
209209
210
-Every response comes in the form of a HTTP response or (in CLI mode)
210
+Every response comes in the form of an HTTP response or (in CLI mode)
211211
JSON sent to stdout. The body of the response is a JSON object following
212212
a common envelope format. The envelope has the following properties:
213213
214214
215215
- `fossil`: Fossil server version string. This property is basically
@@ -216,11 +216,11 @@
216216
"the official response envelope marker" - if it is set, clients can
217217
"probably safely assume" that the object indeed came from one of the
218218
Fossil/JSON APIs. This API never creates responses which do not
219219
contain this property.
220220
- `requestId`: Only set if the request contained it, and then it is
221
- echoed back to the caller as-is. This can be use to determine
221
+ echoed back to the caller as-is. This can be used to determine
222222
(client-side) which request a given response is coming in for
223223
(assuming multiple asynchronous requests are pending). In practice
224224
this generally isn’t needed because response handling tends to be
225225
done by closures associated with the original request object (at
226226
least in JavaScript code). In languages without closures it might
@@ -235,11 +235,11 @@
235235
- `payload`: Request-specific response payload (data type/structure is
236236
request-specific). The payload is never set for error responses,
237237
only for success responses (and only those which actually have a
238238
payload - not all do).
239239
- `timestamp`: Response timestamp (GMT Unix Epoch). We use seconds
240
- precision because i did not know at the time that Fossil actually
240
+ precision because I did not know at the time that Fossil actually
241241
records millisecond precision.
242242
- `payloadVersion`: Not initially needed, but reserved for future use
243243
in maintaining version compatibility when the format of a given
244244
response type's payload changes. If needed, the "first version"
245245
value is assumed to be 0, for semantic [near-]compatibility with the
@@ -402,11 +402,11 @@
402402
(they are represented by `\t`) there is no chance that such a global
403403
replacement will corrupt JSON string contents - only the formatting will
404404
be affected.
405405
406406
Potential TODO: because extraneous indention "could potentially" be used
407
-as a form DoS, the option *might* be subject to later removed from HTTP
407
+as a form of DoS, the option *might* be subject to later removal from HTTP
408408
mode (in CLI it's fine).
409409
410410
In HTTP mode no trailing newline is added to the output, whereas in CLI
411411
mode one is normally appended (exception: in JSONP mode no newline is
412412
appended, to (rather pedantically and arbitraily) allow the client to
@@ -482,11 +482,11 @@
482482
normally want to see very specific error codes when tracking down a
483483
problem. We can offer a configuration option to "dumb down" error
484484
codes to their generic category by simply doing a modulo 100
485485
(or 1000) against the native error code number. e.g. FOSSIL-1271
486486
could (via a simple modulo) be reduced to FOSSIL-1200 or
487
- FOSSIL-1000, depending on the paranoia level of the sysadmin. i have
487
+ FOSSIL-1000, depending on the paranoia level of the sysadmin. I have
488488
tried to order the result code numbers so that a dumb-down level of
489489
2 provides reasonably usable results without giving away too much
490490
detail to malicious clients.\
491491
(**TODO:** `g.json.errorDetailParanoia` is used to set the
492492
default dumb-down level, but it is currently set at compile-time.
@@ -533,11 +533,11 @@
533533
can actually implement this one, though.)
534534
- `FOSSIL-1106`: Assertion failed (or would have had we
535535
continued). Note: if an `assert()` fails in CGI/server modes, the HTTP
536536
response will be code 500 (Internal Server Error). We want to avoid
537537
that and return a JSON response instead. All of that said - there seems
538
- to be little reason to implementi this, since assertions are "truly
538
+ to be little reason to implement this, since assertions are "truly
539539
serious" errors.
540540
- `FOSSIL-1107`: Allocation/out of memory error. This cannot be reasonably
541541
reported because fossil aborts if an allocation fails.
542542
- `FOSSIL-1108`: Requested API is not yet implemented.
543543
- `FOSSIL-1109`: Panic! Fossil's `fossil_panic()` or `cgi_panic()` was
544544
--- www/json-api/conventions.md
+++ www/json-api/conventions.md
@@ -100,11 +100,11 @@
100
101 The API allows most of those (normally all but the payload) to come in
102 as either GET parameters or properties of the top-level POSTed request
103 JSON envelope, with GET taking priority over POST. (Reminder to self: we
104 could potentially also use values from cookies. Fossil currently only
105 uses 1 cookie (the login token), and i'd prefer to keep it that way.)
106
107 POST requests without such an envelope will be rejected, generating a
108 Fossil/JSON error response (as opposed to an HTTP error response). GET
109 requests, by definition, never have an envelope.
110
@@ -169,11 +169,11 @@
169 No higher-level constructs, e.g. JSON **arrays** or **objects**, are
170 accepted in string form. Such parameters must be set in the POST
171 envelope or payload, as specified by the specific API.
172
173 This API does not currently use any **floating-point** parameters, but
174 does return floating-point results in a couple places.
175
176 For **integer** parameters we use a conventional string-to-int algorithm
177 and assume base 10 (analog to atoi(3)). The API may err on the side of
178 usability when given technically invalid values. e.g. "123abc" will
179 likely be interpreted as the integer 123. No APIs currently rely on
@@ -205,11 +205,11 @@
205 cause inconsistencies vis-a-vis the HTML interface).
206
207 <a id="response-envelope"></a>
208 # Response Envelope
209
210 Every response comes in the form of a HTTP response or (in CLI mode)
211 JSON sent to stdout. The body of the response is a JSON object following
212 a common envelope format. The envelope has the following properties:
213
214
215 - `fossil`: Fossil server version string. This property is basically
@@ -216,11 +216,11 @@
216 "the official response envelope marker" - if it is set, clients can
217 "probably safely assume" that the object indeed came from one of the
218 Fossil/JSON APIs. This API never creates responses which do not
219 contain this property.
220 - `requestId`: Only set if the request contained it, and then it is
221 echoed back to the caller as-is. This can be use to determine
222 (client-side) which request a given response is coming in for
223 (assuming multiple asynchronous requests are pending). In practice
224 this generally isn’t needed because response handling tends to be
225 done by closures associated with the original request object (at
226 least in JavaScript code). In languages without closures it might
@@ -235,11 +235,11 @@
235 - `payload`: Request-specific response payload (data type/structure is
236 request-specific). The payload is never set for error responses,
237 only for success responses (and only those which actually have a
238 payload - not all do).
239 - `timestamp`: Response timestamp (GMT Unix Epoch). We use seconds
240 precision because i did not know at the time that Fossil actually
241 records millisecond precision.
242 - `payloadVersion`: Not initially needed, but reserved for future use
243 in maintaining version compatibility when the format of a given
244 response type's payload changes. If needed, the "first version"
245 value is assumed to be 0, for semantic [near-]compatibility with the
@@ -402,11 +402,11 @@
402 (they are represented by `\t`) there is no chance that such a global
403 replacement will corrupt JSON string contents - only the formatting will
404 be affected.
405
406 Potential TODO: because extraneous indention "could potentially" be used
407 as a form DoS, the option *might* be subject to later removed from HTTP
408 mode (in CLI it's fine).
409
410 In HTTP mode no trailing newline is added to the output, whereas in CLI
411 mode one is normally appended (exception: in JSONP mode no newline is
412 appended, to (rather pedantically and arbitraily) allow the client to
@@ -482,11 +482,11 @@
482 normally want to see very specific error codes when tracking down a
483 problem. We can offer a configuration option to "dumb down" error
484 codes to their generic category by simply doing a modulo 100
485 (or 1000) against the native error code number. e.g. FOSSIL-1271
486 could (via a simple modulo) be reduced to FOSSIL-1200 or
487 FOSSIL-1000, depending on the paranoia level of the sysadmin. i have
488 tried to order the result code numbers so that a dumb-down level of
489 2 provides reasonably usable results without giving away too much
490 detail to malicious clients.\
491 (**TODO:** `g.json.errorDetailParanoia` is used to set the
492 default dumb-down level, but it is currently set at compile-time.
@@ -533,11 +533,11 @@
533 can actually implement this one, though.)
534 - `FOSSIL-1106`: Assertion failed (or would have had we
535 continued). Note: if an `assert()` fails in CGI/server modes, the HTTP
536 response will be code 500 (Internal Server Error). We want to avoid
537 that and return a JSON response instead. All of that said - there seems
538 to be little reason to implementi this, since assertions are "truly
539 serious" errors.
540 - `FOSSIL-1107`: Allocation/out of memory error. This cannot be reasonably
541 reported because fossil aborts if an allocation fails.
542 - `FOSSIL-1108`: Requested API is not yet implemented.
543 - `FOSSIL-1109`: Panic! Fossil's `fossil_panic()` or `cgi_panic()` was
544
--- www/json-api/conventions.md
+++ www/json-api/conventions.md
@@ -100,11 +100,11 @@
100
101 The API allows most of those (normally all but the payload) to come in
102 as either GET parameters or properties of the top-level POSTed request
103 JSON envelope, with GET taking priority over POST. (Reminder to self: we
104 could potentially also use values from cookies. Fossil currently only
105 uses 1 cookie (the login token), and I'd prefer to keep it that way.)
106
107 POST requests without such an envelope will be rejected, generating a
108 Fossil/JSON error response (as opposed to an HTTP error response). GET
109 requests, by definition, never have an envelope.
110
@@ -169,11 +169,11 @@
169 No higher-level constructs, e.g. JSON **arrays** or **objects**, are
170 accepted in string form. Such parameters must be set in the POST
171 envelope or payload, as specified by the specific API.
172
173 This API does not currently use any **floating-point** parameters, but
174 does return floating-point results in a couple of places.
175
176 For **integer** parameters we use a conventional string-to-int algorithm
177 and assume base 10 (analog to atoi(3)). The API may err on the side of
178 usability when given technically invalid values. e.g. "123abc" will
179 likely be interpreted as the integer 123. No APIs currently rely on
@@ -205,11 +205,11 @@
205 cause inconsistencies vis-a-vis the HTML interface).
206
207 <a id="response-envelope"></a>
208 # Response Envelope
209
210 Every response comes in the form of an HTTP response or (in CLI mode)
211 JSON sent to stdout. The body of the response is a JSON object following
212 a common envelope format. The envelope has the following properties:
213
214
215 - `fossil`: Fossil server version string. This property is basically
@@ -216,11 +216,11 @@
216 "the official response envelope marker" - if it is set, clients can
217 "probably safely assume" that the object indeed came from one of the
218 Fossil/JSON APIs. This API never creates responses which do not
219 contain this property.
220 - `requestId`: Only set if the request contained it, and then it is
221 echoed back to the caller as-is. This can be used to determine
222 (client-side) which request a given response is coming in for
223 (assuming multiple asynchronous requests are pending). In practice
224 this generally isn’t needed because response handling tends to be
225 done by closures associated with the original request object (at
226 least in JavaScript code). In languages without closures it might
@@ -235,11 +235,11 @@
235 - `payload`: Request-specific response payload (data type/structure is
236 request-specific). The payload is never set for error responses,
237 only for success responses (and only those which actually have a
238 payload - not all do).
239 - `timestamp`: Response timestamp (GMT Unix Epoch). We use seconds
240 precision because I did not know at the time that Fossil actually
241 records millisecond precision.
242 - `payloadVersion`: Not initially needed, but reserved for future use
243 in maintaining version compatibility when the format of a given
244 response type's payload changes. If needed, the "first version"
245 value is assumed to be 0, for semantic [near-]compatibility with the
@@ -402,11 +402,11 @@
402 (they are represented by `\t`) there is no chance that such a global
403 replacement will corrupt JSON string contents - only the formatting will
404 be affected.
405
406 Potential TODO: because extraneous indention "could potentially" be used
407 as a form of DoS, the option *might* be subject to later removal from HTTP
408 mode (in CLI it's fine).
409
410 In HTTP mode no trailing newline is added to the output, whereas in CLI
411 mode one is normally appended (exception: in JSONP mode no newline is
412 appended, to (rather pedantically and arbitraily) allow the client to
@@ -482,11 +482,11 @@
482 normally want to see very specific error codes when tracking down a
483 problem. We can offer a configuration option to "dumb down" error
484 codes to their generic category by simply doing a modulo 100
485 (or 1000) against the native error code number. e.g. FOSSIL-1271
486 could (via a simple modulo) be reduced to FOSSIL-1200 or
487 FOSSIL-1000, depending on the paranoia level of the sysadmin. I have
488 tried to order the result code numbers so that a dumb-down level of
489 2 provides reasonably usable results without giving away too much
490 detail to malicious clients.\
491 (**TODO:** `g.json.errorDetailParanoia` is used to set the
492 default dumb-down level, but it is currently set at compile-time.
@@ -533,11 +533,11 @@
533 can actually implement this one, though.)
534 - `FOSSIL-1106`: Assertion failed (or would have had we
535 continued). Note: if an `assert()` fails in CGI/server modes, the HTTP
536 response will be code 500 (Internal Server Error). We want to avoid
537 that and return a JSON response instead. All of that said - there seems
538 to be little reason to implement this, since assertions are "truly
539 serious" errors.
540 - `FOSSIL-1107`: Allocation/out of memory error. This cannot be reasonably
541 reported because fossil aborts if an allocation fails.
542 - `FOSSIL-1108`: Requested API is not yet implemented.
543 - `FOSSIL-1109`: Panic! Fossil's `fossil_panic()` or `cgi_panic()` was
544
--- www/json-api/hacking.md
+++ www/json-api/hacking.md
@@ -79,11 +79,11 @@
7979
core. The disadvantages of this are that we lose fossil's conventional
8080
help text mechanism (which is based on code comments in the
8181
command/path's dispatcher impl) and the ability to write abbreviated
8282
command names in CLI mode ("json" itself may be abbreviated, but not the
8383
subcommands). The advantages are that we can handle CLI/HTTP modes
84
-almost identically (there are a couple minor differences) by unifying
84
+almost identically (there are a couple of minor differences) by unifying
8585
them under the same callback functions much more easily.
8686
8787
The top-level "json" command/path uses its own dispatching mechanism
8888
which uses either the path (in HTTP mode) or CLI positional arguments to
8989
dispatch commands (stopping at the first "flag option" (e.g. -foo) in
@@ -125,11 +125,11 @@
125125
(e.g. `db_prepare()` can be fatal, and callbacks may call `fossil_panic()`
126126
if they really want to). One exception is `fossil_exit()`, which does
127127
_not_ generate any extra output and will `exit()` the app. In the JSON
128128
API, as a rule of thumb, `fossil_exit()` is only used when we *want* a
129129
failed request to cause an HTTP 500 error, and it is reserved for
130
-allocation errors and similar truly catostrophic failures. That said...
130
+allocation errors and similar truly catastrophic failures. That said...
131131
libcson has been hacked to use `fossil_alloc()` and friends for memory
132132
management, and those routines exit on error, so alloc error handling in
133133
the JSON command handler code can afford to be a little lax (the
134134
majority of *potential* errors clients get from the cson API have
135135
allocation failure as their root cause).
@@ -259,11 +259,11 @@
259259
- `json_getenv()` and `json_getenv_TYPE()` search the so-called "JSON
260260
environment," which is a superset of the GET/POST/`POST.payload` (if
261261
`POST.payload` is-a Object).
262262
- `json_find_option_TYPE()`: searches the CLI args (only when in CLI
263263
mode) and the JSON environment.
264
-- The use of fossil's `P()` and `PD()` macros is discourages in JSON
264
+- The use of fossil's `P()` and `PD()` macros is discouraged in JSON
265265
callbacks because they can only handle String data from the CLI or
266266
GET parameters (not POST/`POST.payload`). (Note that `P()` and `PD()`
267267
*normally* also handle POSTed keys, but they only "see" values
268268
posted as form-urlencoded fields, and not JSON format.)
269269
- `find_option()` (from `src/main.c`) "should" also be avoided in
@@ -280,11 +280,11 @@
280280
281281
<a href="creating-json-values"></a>
282282
## Creating JSON Values
283283
284284
cson has a fairly rich API for creating and manipulating the various
285
-JSON-defined value types. For a detailed overview and demonstration i
285
+JSON-defined value types. For a detailed overview and demonstration I
286286
recommend reading:
287287
288288
[](https://fossil.wanderinghorse.net/wikis/cson/?page=HowTo)
289289
290290
That said, the Fossil/JSON API has several convenience wrappers to save
@@ -310,15 +310,15 @@
310310
to Arrays or Objects, or convert single columns to a JSON-compatible
311311
form. See `json_stmt_to_array_of_obj()`,
312312
`json_stmt_to_array_of_array()` (both in `src/json.c`), and
313313
`cson_sqlite3_column_to_value()` and friends (in
314314
`extsrc/cson_amalgamation.h`). They work in an intuitive way for numeric
315
-types, but they optimistically/natively *assume* that any fields of type
315
+types, but they optimistically/naively *assume* that any fields of type
316316
TEXT or BLOB are actually UTF8 data, and treat them as such. cson's
317317
string class only handles UTF8 data and it is semantically illegal to
318318
feed them anything but UTF8. Violating this will likely result in
319
-down-stream errors (e.g. when emiting the JSON string output). **The
319
+down-stream errors (e.g. when emitting the JSON string output). **The
320320
moral of this story is:** *do not use these APIs to fetch binary data*.
321321
JSON doesn't do binary and the `cson_string` class does not
322322
protect itself against clients feeding it non-UTF8 data.
323323
324324
Here's a basic example of using these features:
@@ -347,7 +347,7 @@
347347
AS clauses to be guaranteed that the db driver will return the column
348348
names we want. Note that the AS clause is often used to translate column
349349
names into something more JSON-conventional or user-friendly, e.g.
350350
"SELECT cap AS capabilities...". Alternately, we can convert the
351351
individual `sqlite3_stmt` column values to JSON using
352
-`cson_sqlite3_column_to_value()`, without refering directly to the
352
+`cson_sqlite3_column_to_value()`, without referring directly to the
353353
db-reported column name.
354354
--- www/json-api/hacking.md
+++ www/json-api/hacking.md
@@ -79,11 +79,11 @@
79 core. The disadvantages of this are that we lose fossil's conventional
80 help text mechanism (which is based on code comments in the
81 command/path's dispatcher impl) and the ability to write abbreviated
82 command names in CLI mode ("json" itself may be abbreviated, but not the
83 subcommands). The advantages are that we can handle CLI/HTTP modes
84 almost identically (there are a couple minor differences) by unifying
85 them under the same callback functions much more easily.
86
87 The top-level "json" command/path uses its own dispatching mechanism
88 which uses either the path (in HTTP mode) or CLI positional arguments to
89 dispatch commands (stopping at the first "flag option" (e.g. -foo) in
@@ -125,11 +125,11 @@
125 (e.g. `db_prepare()` can be fatal, and callbacks may call `fossil_panic()`
126 if they really want to). One exception is `fossil_exit()`, which does
127 _not_ generate any extra output and will `exit()` the app. In the JSON
128 API, as a rule of thumb, `fossil_exit()` is only used when we *want* a
129 failed request to cause an HTTP 500 error, and it is reserved for
130 allocation errors and similar truly catostrophic failures. That said...
131 libcson has been hacked to use `fossil_alloc()` and friends for memory
132 management, and those routines exit on error, so alloc error handling in
133 the JSON command handler code can afford to be a little lax (the
134 majority of *potential* errors clients get from the cson API have
135 allocation failure as their root cause).
@@ -259,11 +259,11 @@
259 - `json_getenv()` and `json_getenv_TYPE()` search the so-called "JSON
260 environment," which is a superset of the GET/POST/`POST.payload` (if
261 `POST.payload` is-a Object).
262 - `json_find_option_TYPE()`: searches the CLI args (only when in CLI
263 mode) and the JSON environment.
264 - The use of fossil's `P()` and `PD()` macros is discourages in JSON
265 callbacks because they can only handle String data from the CLI or
266 GET parameters (not POST/`POST.payload`). (Note that `P()` and `PD()`
267 *normally* also handle POSTed keys, but they only "see" values
268 posted as form-urlencoded fields, and not JSON format.)
269 - `find_option()` (from `src/main.c`) "should" also be avoided in
@@ -280,11 +280,11 @@
280
281 <a href="creating-json-values"></a>
282 ## Creating JSON Values
283
284 cson has a fairly rich API for creating and manipulating the various
285 JSON-defined value types. For a detailed overview and demonstration i
286 recommend reading:
287
288 [](https://fossil.wanderinghorse.net/wikis/cson/?page=HowTo)
289
290 That said, the Fossil/JSON API has several convenience wrappers to save
@@ -310,15 +310,15 @@
310 to Arrays or Objects, or convert single columns to a JSON-compatible
311 form. See `json_stmt_to_array_of_obj()`,
312 `json_stmt_to_array_of_array()` (both in `src/json.c`), and
313 `cson_sqlite3_column_to_value()` and friends (in
314 `extsrc/cson_amalgamation.h`). They work in an intuitive way for numeric
315 types, but they optimistically/natively *assume* that any fields of type
316 TEXT or BLOB are actually UTF8 data, and treat them as such. cson's
317 string class only handles UTF8 data and it is semantically illegal to
318 feed them anything but UTF8. Violating this will likely result in
319 down-stream errors (e.g. when emiting the JSON string output). **The
320 moral of this story is:** *do not use these APIs to fetch binary data*.
321 JSON doesn't do binary and the `cson_string` class does not
322 protect itself against clients feeding it non-UTF8 data.
323
324 Here's a basic example of using these features:
@@ -347,7 +347,7 @@
347 AS clauses to be guaranteed that the db driver will return the column
348 names we want. Note that the AS clause is often used to translate column
349 names into something more JSON-conventional or user-friendly, e.g.
350 "SELECT cap AS capabilities...". Alternately, we can convert the
351 individual `sqlite3_stmt` column values to JSON using
352 `cson_sqlite3_column_to_value()`, without refering directly to the
353 db-reported column name.
354
--- www/json-api/hacking.md
+++ www/json-api/hacking.md
@@ -79,11 +79,11 @@
79 core. The disadvantages of this are that we lose fossil's conventional
80 help text mechanism (which is based on code comments in the
81 command/path's dispatcher impl) and the ability to write abbreviated
82 command names in CLI mode ("json" itself may be abbreviated, but not the
83 subcommands). The advantages are that we can handle CLI/HTTP modes
84 almost identically (there are a couple of minor differences) by unifying
85 them under the same callback functions much more easily.
86
87 The top-level "json" command/path uses its own dispatching mechanism
88 which uses either the path (in HTTP mode) or CLI positional arguments to
89 dispatch commands (stopping at the first "flag option" (e.g. -foo) in
@@ -125,11 +125,11 @@
125 (e.g. `db_prepare()` can be fatal, and callbacks may call `fossil_panic()`
126 if they really want to). One exception is `fossil_exit()`, which does
127 _not_ generate any extra output and will `exit()` the app. In the JSON
128 API, as a rule of thumb, `fossil_exit()` is only used when we *want* a
129 failed request to cause an HTTP 500 error, and it is reserved for
130 allocation errors and similar truly catastrophic failures. That said...
131 libcson has been hacked to use `fossil_alloc()` and friends for memory
132 management, and those routines exit on error, so alloc error handling in
133 the JSON command handler code can afford to be a little lax (the
134 majority of *potential* errors clients get from the cson API have
135 allocation failure as their root cause).
@@ -259,11 +259,11 @@
259 - `json_getenv()` and `json_getenv_TYPE()` search the so-called "JSON
260 environment," which is a superset of the GET/POST/`POST.payload` (if
261 `POST.payload` is-a Object).
262 - `json_find_option_TYPE()`: searches the CLI args (only when in CLI
263 mode) and the JSON environment.
264 - The use of fossil's `P()` and `PD()` macros is discouraged in JSON
265 callbacks because they can only handle String data from the CLI or
266 GET parameters (not POST/`POST.payload`). (Note that `P()` and `PD()`
267 *normally* also handle POSTed keys, but they only "see" values
268 posted as form-urlencoded fields, and not JSON format.)
269 - `find_option()` (from `src/main.c`) "should" also be avoided in
@@ -280,11 +280,11 @@
280
281 <a href="creating-json-values"></a>
282 ## Creating JSON Values
283
284 cson has a fairly rich API for creating and manipulating the various
285 JSON-defined value types. For a detailed overview and demonstration I
286 recommend reading:
287
288 [](https://fossil.wanderinghorse.net/wikis/cson/?page=HowTo)
289
290 That said, the Fossil/JSON API has several convenience wrappers to save
@@ -310,15 +310,15 @@
310 to Arrays or Objects, or convert single columns to a JSON-compatible
311 form. See `json_stmt_to_array_of_obj()`,
312 `json_stmt_to_array_of_array()` (both in `src/json.c`), and
313 `cson_sqlite3_column_to_value()` and friends (in
314 `extsrc/cson_amalgamation.h`). They work in an intuitive way for numeric
315 types, but they optimistically/naively *assume* that any fields of type
316 TEXT or BLOB are actually UTF8 data, and treat them as such. cson's
317 string class only handles UTF8 data and it is semantically illegal to
318 feed them anything but UTF8. Violating this will likely result in
319 down-stream errors (e.g. when emitting the JSON string output). **The
320 moral of this story is:** *do not use these APIs to fetch binary data*.
321 JSON doesn't do binary and the `cson_string` class does not
322 protect itself against clients feeding it non-UTF8 data.
323
324 Here's a basic example of using these features:
@@ -347,7 +347,7 @@
347 AS clauses to be guaranteed that the db driver will return the column
348 names we want. Note that the AS clause is often used to translate column
349 names into something more JSON-conventional or user-friendly, e.g.
350 "SELECT cap AS capabilities...". Alternately, we can convert the
351 individual `sqlite3_stmt` column values to JSON using
352 `cson_sqlite3_column_to_value()`, without referring directly to the
353 db-reported column name.
354
--- www/makefile.wiki
+++ www/makefile.wiki
@@ -7,11 +7,11 @@
77
before it is compiled. Most users will download a
88
[https://fossil-scm.org/home/uv/download.html | precompiled binary]
99
so this is of no consequence to them, and even those who
1010
want to compile the code themselves can use one of the
1111
[./build.wiki | existing makefiles].
12
-So must people do not need to be concerned with the
12
+So most people do not need to be concerned with the
1313
build complexities of Fossil. But hard-core developers who desire
1414
a deep understanding of how Fossil is put together can benefit
1515
from reviewing this article.
1616
1717
<h1 id="srctour">2.0 Source Code Tour</h1>
@@ -56,21 +56,21 @@
5656
The TH1 script engine is implemented using files:
5757
5858
9. th.c
5959
10. th.h
6060
61
-The proprocessing steps are omitted for all of these imported
61
+The preprocessing steps are omitted for all of these imported
6262
files.
6363
6464
The VERSION.h header file is generated from other information sources
6565
using a small program called:
6666
6767
11. [/file/tools/mkversion.c | mkversion.c]
6868
6969
The builtin_data.h header file contains the definitions of C-language
7070
byte-array constants that contain various resources such as scripts and
71
-images. The builtin_data.h header file is generate from the original
71
+images. The builtin_data.h header file is generated from the original
7272
resource files using a small program called:
7373
7474
12 [/file/tools/mkbuiltin.c | mkbuiltin.c]
7575
7676
Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl]
@@ -132,11 +132,11 @@
132132
the exceptions described above.
133133
134134
<h1>3.0 Automatically generated files</h1>
135135
136136
The "VERSION.h" header file contains some C preprocessor macros that
137
-identify the version of Fossil that is to be build. The VERSION.h file is
137
+identify the version of Fossil that is to be built. The VERSION.h file is
138138
generated automatically from information extracted from the "manifest",
139139
"manifest.uuid", and "VERSION" source files in the root directory of the
140140
source tree.
141141
(The "manifest" and "manifest.uuid" files are automatically generated and
142142
updated by Fossil itself. See the [/help/setting | fossil set manifest]
@@ -294,12 +294,12 @@
294294
link against the standard C library. No other libraries or external
295295
dependences are used.
296296
297297
<h1>7.0 Debugging</h1>
298298
299
-Debug mode is controlled via FOSSIL_DEBUG preprocessor macro which could be
300
-set explicitly at the make command for the target platform.
299
+Debug mode is controlled via a FOSSIL_DEBUG preprocessor macro. This can be
300
+set explicitly with the make command for the target platform.
301301
302302
However, in practice it is instead recommended to add a respective configure
303303
option for the target platform and then perform a clean build. This way the
304304
Debug flags are consistently applied across the whole build process. For
305305
example, use these Debug flags in addition to other flags passed to the
@@ -313,14 +313,15 @@
313313
On Windows:
314314
<pre>
315315
win\buildmsvc.bat FOSSIL_DEBUG=1
316316
</pre>
317317
318
-The resulting fossil binary could then be loaded into a platform-specific
318
+The resulting fossil binary can then be loaded into a platform-specific
319319
debugger. Source files displayed in the debugger correspond to the ones
320
-generated from the translation stage of the build process, that is what was
321
-actually compiled into the object files.
320
+generated from the translation stage of the build process, as that is what
321
+was actually compiled into the respective object files that make up the
322
+fossil binary.
322323
323324
<h1>8.0 See Also</h1>
324325
325326
* [./tech_overview.wiki | A Technical Overview Of Fossil]
326327
* [./adding_code.wiki | How To Add Features To Fossil]
327328
--- www/makefile.wiki
+++ www/makefile.wiki
@@ -7,11 +7,11 @@
7 before it is compiled. Most users will download a
8 [https://fossil-scm.org/home/uv/download.html | precompiled binary]
9 so this is of no consequence to them, and even those who
10 want to compile the code themselves can use one of the
11 [./build.wiki | existing makefiles].
12 So must people do not need to be concerned with the
13 build complexities of Fossil. But hard-core developers who desire
14 a deep understanding of how Fossil is put together can benefit
15 from reviewing this article.
16
17 <h1 id="srctour">2.0 Source Code Tour</h1>
@@ -56,21 +56,21 @@
56 The TH1 script engine is implemented using files:
57
58 9. th.c
59 10. th.h
60
61 The proprocessing steps are omitted for all of these imported
62 files.
63
64 The VERSION.h header file is generated from other information sources
65 using a small program called:
66
67 11. [/file/tools/mkversion.c | mkversion.c]
68
69 The builtin_data.h header file contains the definitions of C-language
70 byte-array constants that contain various resources such as scripts and
71 images. The builtin_data.h header file is generate from the original
72 resource files using a small program called:
73
74 12 [/file/tools/mkbuiltin.c | mkbuiltin.c]
75
76 Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl]
@@ -132,11 +132,11 @@
132 the exceptions described above.
133
134 <h1>3.0 Automatically generated files</h1>
135
136 The "VERSION.h" header file contains some C preprocessor macros that
137 identify the version of Fossil that is to be build. The VERSION.h file is
138 generated automatically from information extracted from the "manifest",
139 "manifest.uuid", and "VERSION" source files in the root directory of the
140 source tree.
141 (The "manifest" and "manifest.uuid" files are automatically generated and
142 updated by Fossil itself. See the [/help/setting | fossil set manifest]
@@ -294,12 +294,12 @@
294 link against the standard C library. No other libraries or external
295 dependences are used.
296
297 <h1>7.0 Debugging</h1>
298
299 Debug mode is controlled via FOSSIL_DEBUG preprocessor macro which could be
300 set explicitly at the make command for the target platform.
301
302 However, in practice it is instead recommended to add a respective configure
303 option for the target platform and then perform a clean build. This way the
304 Debug flags are consistently applied across the whole build process. For
305 example, use these Debug flags in addition to other flags passed to the
@@ -313,14 +313,15 @@
313 On Windows:
314 <pre>
315 win\buildmsvc.bat FOSSIL_DEBUG=1
316 </pre>
317
318 The resulting fossil binary could then be loaded into a platform-specific
319 debugger. Source files displayed in the debugger correspond to the ones
320 generated from the translation stage of the build process, that is what was
321 actually compiled into the object files.
 
322
323 <h1>8.0 See Also</h1>
324
325 * [./tech_overview.wiki | A Technical Overview Of Fossil]
326 * [./adding_code.wiki | How To Add Features To Fossil]
327
--- www/makefile.wiki
+++ www/makefile.wiki
@@ -7,11 +7,11 @@
7 before it is compiled. Most users will download a
8 [https://fossil-scm.org/home/uv/download.html | precompiled binary]
9 so this is of no consequence to them, and even those who
10 want to compile the code themselves can use one of the
11 [./build.wiki | existing makefiles].
12 So most people do not need to be concerned with the
13 build complexities of Fossil. But hard-core developers who desire
14 a deep understanding of how Fossil is put together can benefit
15 from reviewing this article.
16
17 <h1 id="srctour">2.0 Source Code Tour</h1>
@@ -56,21 +56,21 @@
56 The TH1 script engine is implemented using files:
57
58 9. th.c
59 10. th.h
60
61 The preprocessing steps are omitted for all of these imported
62 files.
63
64 The VERSION.h header file is generated from other information sources
65 using a small program called:
66
67 11. [/file/tools/mkversion.c | mkversion.c]
68
69 The builtin_data.h header file contains the definitions of C-language
70 byte-array constants that contain various resources such as scripts and
71 images. The builtin_data.h header file is generated from the original
72 resource files using a small program called:
73
74 12 [/file/tools/mkbuiltin.c | mkbuiltin.c]
75
76 Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl]
@@ -132,11 +132,11 @@
132 the exceptions described above.
133
134 <h1>3.0 Automatically generated files</h1>
135
136 The "VERSION.h" header file contains some C preprocessor macros that
137 identify the version of Fossil that is to be built. The VERSION.h file is
138 generated automatically from information extracted from the "manifest",
139 "manifest.uuid", and "VERSION" source files in the root directory of the
140 source tree.
141 (The "manifest" and "manifest.uuid" files are automatically generated and
142 updated by Fossil itself. See the [/help/setting | fossil set manifest]
@@ -294,12 +294,12 @@
294 link against the standard C library. No other libraries or external
295 dependences are used.
296
297 <h1>7.0 Debugging</h1>
298
299 Debug mode is controlled via a FOSSIL_DEBUG preprocessor macro. This can be
300 set explicitly with the make command for the target platform.
301
302 However, in practice it is instead recommended to add a respective configure
303 option for the target platform and then perform a clean build. This way the
304 Debug flags are consistently applied across the whole build process. For
305 example, use these Debug flags in addition to other flags passed to the
@@ -313,14 +313,15 @@
313 On Windows:
314 <pre>
315 win\buildmsvc.bat FOSSIL_DEBUG=1
316 </pre>
317
318 The resulting fossil binary can then be loaded into a platform-specific
319 debugger. Source files displayed in the debugger correspond to the ones
320 generated from the translation stage of the build process, as that is what
321 was actually compiled into the respective object files that make up the
322 fossil binary.
323
324 <h1>8.0 See Also</h1>
325
326 * [./tech_overview.wiki | A Technical Overview Of Fossil]
327 * [./adding_code.wiki | How To Add Features To Fossil]
328
--- www/mdtest/test1.md
+++ www/mdtest/test1.md
@@ -1,8 +1,8 @@
11
# Markdown Link-test
22
3
-This document exist solely as a test for some of the hyperlinking
3
+This document exists solely as a test for some of the hyperlinking
44
capabilities of Markdown as implemented by Fossil.
55
66
## Relative-Path Links
77
88
* The index: [](../index.wiki)
99
--- www/mdtest/test1.md
+++ www/mdtest/test1.md
@@ -1,8 +1,8 @@
1 # Markdown Link-test
2
3 This document exist solely as a test for some of the hyperlinking
4 capabilities of Markdown as implemented by Fossil.
5
6 ## Relative-Path Links
7
8 * The index: [](../index.wiki)
9
--- www/mdtest/test1.md
+++ www/mdtest/test1.md
@@ -1,8 +1,8 @@
1 # Markdown Link-test
2
3 This document exists solely as a test for some of the hyperlinking
4 capabilities of Markdown as implemented by Fossil.
5
6 ## Relative-Path Links
7
8 * The index: [](../index.wiki)
9
--- www/newrepo.wiki
+++ www/newrepo.wiki
@@ -57,11 +57,12 @@
5757
$ fossil open ../demo.fossil
5858
</verbatim>
5959
6060
That creates a file called <tt>_FOSSIL_</tt> in the current
6161
directory, and this file contains all kinds of fossil-related
62
-information about your local repository. You can ignore it
62
+information about your local repository. Under Linux, the BSDs or
63
+macOS, this will instead be called <tt>.fslckout</tt>. You can ignore it
6364
for all purposes, but be sure not to accidentally remove it
6465
or otherwise damage it - it belongs to fossil, not you.
6566
6667
The next thing we need to do is add files to our repository. As it
6768
happens, we have a few C source files lying around, which we'll
6869
--- www/newrepo.wiki
+++ www/newrepo.wiki
@@ -57,11 +57,12 @@
57 $ fossil open ../demo.fossil
58 </verbatim>
59
60 That creates a file called <tt>_FOSSIL_</tt> in the current
61 directory, and this file contains all kinds of fossil-related
62 information about your local repository. You can ignore it
 
63 for all purposes, but be sure not to accidentally remove it
64 or otherwise damage it - it belongs to fossil, not you.
65
66 The next thing we need to do is add files to our repository. As it
67 happens, we have a few C source files lying around, which we'll
68
--- www/newrepo.wiki
+++ www/newrepo.wiki
@@ -57,11 +57,12 @@
57 $ fossil open ../demo.fossil
58 </verbatim>
59
60 That creates a file called <tt>_FOSSIL_</tt> in the current
61 directory, and this file contains all kinds of fossil-related
62 information about your local repository. Under Linux, the BSDs or
63 macOS, this will instead be called <tt>.fslckout</tt>. You can ignore it
64 for all purposes, but be sure not to accidentally remove it
65 or otherwise damage it - it belongs to fossil, not you.
66
67 The next thing we need to do is add files to our repository. As it
68 happens, we have a few C source files lying around, which we'll
69
--- www/password.wiki
+++ www/password.wiki
@@ -63,17 +63,21 @@
6363
for "anonymous" uses one-time captchas not persistent passwords.
6464
6565
<h2>Web Interface Authentication</h2>
6666
6767
When a user logs into Fossil using the web interface, the login name
68
-and password are sent in the clear to the server. The server then
68
+and password are sent in the clear to the server. For most modern fossil
69
+server setups with [/help?cmd=redirect-to-https|redirect-to-https] enabled,
70
+this will be protected by the
71
+SSL connection over HTTPS so it cannot be easily viewed. The server then
6972
hashes the password and compares it against the value stored in USER.PW.
7073
If they match, the server sets a cookie on the client to record the
7174
login. This cookie contains a large amount of high-quality randomness
7275
and is thus intractable to guess. The value of the cookie and the IP
7376
address of the client is stored in the USER.COOKIE and USER.IPADDR fields
7477
of the USER table on the server.
78
+
7579
The USER.CEXPIRE field holds an expiration date
7680
for the cookie, encoded as a Julian day number. On all subsequent
7781
HTTP requests, the cookie value is matched against the USER table to
7882
enable access to the repository.
7983
@@ -123,11 +127,11 @@
123127
</pre>
124128
125129
For older clients, the password is used for the shared secret as stated
126130
in the URL and with no encoding.
127131
For newer clients, the shared secret is derived from the password
128
-by transformed the password using the SHA1 hash encoding
132
+by transforming the password using the SHA1 hash encoding
129133
described above. However, if the first character of the password is
130134
"*" (ASCII 0x2a) then the "*" is skipped and the rest of the password
131135
is used directly as the share secret without the SHA1 encoding.
132136
133137
<pre>
134138
--- www/password.wiki
+++ www/password.wiki
@@ -63,17 +63,21 @@
63 for "anonymous" uses one-time captchas not persistent passwords.
64
65 <h2>Web Interface Authentication</h2>
66
67 When a user logs into Fossil using the web interface, the login name
68 and password are sent in the clear to the server. The server then
 
 
 
69 hashes the password and compares it against the value stored in USER.PW.
70 If they match, the server sets a cookie on the client to record the
71 login. This cookie contains a large amount of high-quality randomness
72 and is thus intractable to guess. The value of the cookie and the IP
73 address of the client is stored in the USER.COOKIE and USER.IPADDR fields
74 of the USER table on the server.
 
75 The USER.CEXPIRE field holds an expiration date
76 for the cookie, encoded as a Julian day number. On all subsequent
77 HTTP requests, the cookie value is matched against the USER table to
78 enable access to the repository.
79
@@ -123,11 +127,11 @@
123 </pre>
124
125 For older clients, the password is used for the shared secret as stated
126 in the URL and with no encoding.
127 For newer clients, the shared secret is derived from the password
128 by transformed the password using the SHA1 hash encoding
129 described above. However, if the first character of the password is
130 "*" (ASCII 0x2a) then the "*" is skipped and the rest of the password
131 is used directly as the share secret without the SHA1 encoding.
132
133 <pre>
134
--- www/password.wiki
+++ www/password.wiki
@@ -63,17 +63,21 @@
63 for "anonymous" uses one-time captchas not persistent passwords.
64
65 <h2>Web Interface Authentication</h2>
66
67 When a user logs into Fossil using the web interface, the login name
68 and password are sent in the clear to the server. For most modern fossil
69 server setups with [/help?cmd=redirect-to-https|redirect-to-https] enabled,
70 this will be protected by the
71 SSL connection over HTTPS so it cannot be easily viewed. The server then
72 hashes the password and compares it against the value stored in USER.PW.
73 If they match, the server sets a cookie on the client to record the
74 login. This cookie contains a large amount of high-quality randomness
75 and is thus intractable to guess. The value of the cookie and the IP
76 address of the client is stored in the USER.COOKIE and USER.IPADDR fields
77 of the USER table on the server.
78
79 The USER.CEXPIRE field holds an expiration date
80 for the cookie, encoded as a Julian day number. On all subsequent
81 HTTP requests, the cookie value is matched against the USER table to
82 enable access to the repository.
83
@@ -123,11 +127,11 @@
127 </pre>
128
129 For older clients, the password is used for the shared secret as stated
130 in the URL and with no encoding.
131 For newer clients, the shared secret is derived from the password
132 by transforming the password using the SHA1 hash encoding
133 described above. However, if the first character of the password is
134 "*" (ASCII 0x2a) then the "*" is skipped and the rest of the password
135 is used directly as the share secret without the SHA1 encoding.
136
137 <pre>
138
+4 -4
--- www/patchcmd.md
+++ www/patchcmd.md
@@ -9,11 +9,11 @@
99
"fossil patch push" command to make a copy of all your changes on the
1010
remote Linux server:
1111
1212
fossil patch push linuxserver:/path/to/checkout
1313
14
-In the previous "linuxserver" is the name of the remote machine and
14
+In the previous line "linuxserver" is the name of the remote machine and
1515
"/path/to/checkout" is an existing checkout directory for the same project
1616
on the remote machine.
1717
1818
The "fossil patch push" command works by first creating a patch file,
1919
then transfering that patch file to the remote machine using "ssh", then
@@ -85,11 +85,11 @@
8585
The "fossil patch create" command records all of the local, uncommitted
8686
changes in an SQLite database file. If the argument to "fossil patch create"
8787
is a filename, then the patch-file database is written into that file.
8888
If the argument is "-" then the database is written on standard output.
8989
90
-The "fossil patch apply" command reads the database that is the patch file
90
+The "fossil patch apply" command reads the patch-file database
9191
and applies it to the local check-out. If a filename is given as an
9292
argument, then the database is read from that file. If the argument is "-"
9393
then the database is read from standard input.
9494
9595
Hence the command:
@@ -102,11 +102,11 @@
102102
103103
Likewise, a command like this:
104104
105105
fossil patch pull remote:projB
106106
107
-Could be entered like this:
107
+could be entered like this:
108108
109109
ssh -T remote 'cd projB;fossil patch create -' | fossil patch apply -
110110
111
-The "fossil patch view" command just opens the database file and prints
111
+The "fossil patch view" command just opens the patch-file database and prints
112112
a summary of its contents on standard output.
113113
--- www/patchcmd.md
+++ www/patchcmd.md
@@ -9,11 +9,11 @@
9 "fossil patch push" command to make a copy of all your changes on the
10 remote Linux server:
11
12 fossil patch push linuxserver:/path/to/checkout
13
14 In the previous "linuxserver" is the name of the remote machine and
15 "/path/to/checkout" is an existing checkout directory for the same project
16 on the remote machine.
17
18 The "fossil patch push" command works by first creating a patch file,
19 then transfering that patch file to the remote machine using "ssh", then
@@ -85,11 +85,11 @@
85 The "fossil patch create" command records all of the local, uncommitted
86 changes in an SQLite database file. If the argument to "fossil patch create"
87 is a filename, then the patch-file database is written into that file.
88 If the argument is "-" then the database is written on standard output.
89
90 The "fossil patch apply" command reads the database that is the patch file
91 and applies it to the local check-out. If a filename is given as an
92 argument, then the database is read from that file. If the argument is "-"
93 then the database is read from standard input.
94
95 Hence the command:
@@ -102,11 +102,11 @@
102
103 Likewise, a command like this:
104
105 fossil patch pull remote:projB
106
107 Could be entered like this:
108
109 ssh -T remote 'cd projB;fossil patch create -' | fossil patch apply -
110
111 The "fossil patch view" command just opens the database file and prints
112 a summary of its contents on standard output.
113
--- www/patchcmd.md
+++ www/patchcmd.md
@@ -9,11 +9,11 @@
9 "fossil patch push" command to make a copy of all your changes on the
10 remote Linux server:
11
12 fossil patch push linuxserver:/path/to/checkout
13
14 In the previous line "linuxserver" is the name of the remote machine and
15 "/path/to/checkout" is an existing checkout directory for the same project
16 on the remote machine.
17
18 The "fossil patch push" command works by first creating a patch file,
19 then transfering that patch file to the remote machine using "ssh", then
@@ -85,11 +85,11 @@
85 The "fossil patch create" command records all of the local, uncommitted
86 changes in an SQLite database file. If the argument to "fossil patch create"
87 is a filename, then the patch-file database is written into that file.
88 If the argument is "-" then the database is written on standard output.
89
90 The "fossil patch apply" command reads the patch-file database
91 and applies it to the local check-out. If a filename is given as an
92 argument, then the database is read from that file. If the argument is "-"
93 then the database is read from standard input.
94
95 Hence the command:
@@ -102,11 +102,11 @@
102
103 Likewise, a command like this:
104
105 fossil patch pull remote:projB
106
107 could be entered like this:
108
109 ssh -T remote 'cd projB;fossil patch create -' | fossil patch apply -
110
111 The "fossil patch view" command just opens the patch-file database and prints
112 a summary of its contents on standard output.
113
+2 -2
--- www/pikchr.md
+++ www/pikchr.md
@@ -1,9 +1,9 @@
11
# The Pikchr Diagram Language
22
33
Pikchr (pronounced "picture") is a [PIC][1]-like markup language for creating
4
-diagrams in technical documentation. Pikchr diagrams source text
4
+diagrams in technical documentation. Source text for Pikchr diagrams
55
can be embedded directly in either [Markdown][2] or [Fossil Wiki][3].
66
Fossil translates the Pikchr source text into SVG which is displayed as
77
part of the rendered wiki.
88
99
[1]: wikipedia:/wiki/Pic_language
@@ -134,6 +134,6 @@
134134
135135
* **float-right** &rarr; The diagram is shown at the right margin and
136136
text fills in around the diagram.
137137
138138
* **source** &rarr; The display starts out showing the Pikchr source text.
139
- The reader must click (or Alt-click or Ctrl-click) to set the diagram.
139
+ The reader must click (or Alt-click or Ctrl-click) to show the diagram.
140140
--- www/pikchr.md
+++ www/pikchr.md
@@ -1,9 +1,9 @@
1 # The Pikchr Diagram Language
2
3 Pikchr (pronounced "picture") is a [PIC][1]-like markup language for creating
4 diagrams in technical documentation. Pikchr diagrams source text
5 can be embedded directly in either [Markdown][2] or [Fossil Wiki][3].
6 Fossil translates the Pikchr source text into SVG which is displayed as
7 part of the rendered wiki.
8
9 [1]: wikipedia:/wiki/Pic_language
@@ -134,6 +134,6 @@
134
135 * **float-right** &rarr; The diagram is shown at the right margin and
136 text fills in around the diagram.
137
138 * **source** &rarr; The display starts out showing the Pikchr source text.
139 The reader must click (or Alt-click or Ctrl-click) to set the diagram.
140
--- www/pikchr.md
+++ www/pikchr.md
@@ -1,9 +1,9 @@
1 # The Pikchr Diagram Language
2
3 Pikchr (pronounced "picture") is a [PIC][1]-like markup language for creating
4 diagrams in technical documentation. Source text for Pikchr diagrams
5 can be embedded directly in either [Markdown][2] or [Fossil Wiki][3].
6 Fossil translates the Pikchr source text into SVG which is displayed as
7 part of the rendered wiki.
8
9 [1]: wikipedia:/wiki/Pic_language
@@ -134,6 +134,6 @@
134
135 * **float-right** &rarr; The diagram is shown at the right margin and
136 text fills in around the diagram.
137
138 * **source** &rarr; The display starts out showing the Pikchr source text.
139 The reader must click (or Alt-click or Ctrl-click) to show the diagram.
140
+1 -1
--- www/qandc.wiki
+++ www/qandc.wiki
@@ -142,11 +142,11 @@
142142
fossil supports disconnected operation.
143143
144144
As for bloat: Fossil is a single self-contained executable.
145145
You do not need any other packages
146146
(diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache,
147
-sqlite, and so forth)
147
+SQLite, and so forth)
148148
in order to run fossil. Fossil runs just fine in a chroot jail all
149149
by itself. And the self-contained fossil
150150
executable is much less than 1MB in size. (Update 2015-01-12: Fossil has
151151
grown in the years since the previous sentence was written but is still
152152
much less than 2MB according to "size" when compiled using -Os on x64 Linux.)
153153
--- www/qandc.wiki
+++ www/qandc.wiki
@@ -142,11 +142,11 @@
142 fossil supports disconnected operation.
143
144 As for bloat: Fossil is a single self-contained executable.
145 You do not need any other packages
146 (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache,
147 sqlite, and so forth)
148 in order to run fossil. Fossil runs just fine in a chroot jail all
149 by itself. And the self-contained fossil
150 executable is much less than 1MB in size. (Update 2015-01-12: Fossil has
151 grown in the years since the previous sentence was written but is still
152 much less than 2MB according to "size" when compiled using -Os on x64 Linux.)
153
--- www/qandc.wiki
+++ www/qandc.wiki
@@ -142,11 +142,11 @@
142 fossil supports disconnected operation.
143
144 As for bloat: Fossil is a single self-contained executable.
145 You do not need any other packages
146 (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache,
147 SQLite, and so forth)
148 in order to run fossil. Fossil runs just fine in a chroot jail all
149 by itself. And the self-contained fossil
150 executable is much less than 1MB in size. (Update 2015-01-12: Fossil has
151 grown in the years since the previous sentence was written but is still
152 much less than 2MB according to "size" when compiled using -Os on x64 Linux.)
153
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -364,11 +364,11 @@
364364
abbreviation to the 40-character
365365
artifact identifier for a particular check-in, or it can be a
366366
date/time stamp. ([./checkin_names.wiki | more info])
367367
If you omit
368368
the <i>VERSION</i>, then fossil moves you to the
369
-latest version of the branch your are currently on.
369
+latest version of the branch you are currently on.
370370
371371
The default behavior is for [./concepts.wiki#workflow|autosync] to
372372
be turned on. That means that a [/help/pull|pull] automatically occurs
373373
when you run [/help/update|update] and a [/help/push|push] happens
374374
automatically after you [/help/commit|commit]. So in normal practice,
375375
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -364,11 +364,11 @@
364 abbreviation to the 40-character
365 artifact identifier for a particular check-in, or it can be a
366 date/time stamp. ([./checkin_names.wiki | more info])
367 If you omit
368 the <i>VERSION</i>, then fossil moves you to the
369 latest version of the branch your are currently on.
370
371 The default behavior is for [./concepts.wiki#workflow|autosync] to
372 be turned on. That means that a [/help/pull|pull] automatically occurs
373 when you run [/help/update|update] and a [/help/push|push] happens
374 automatically after you [/help/commit|commit]. So in normal practice,
375
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -364,11 +364,11 @@
364 abbreviation to the 40-character
365 artifact identifier for a particular check-in, or it can be a
366 date/time stamp. ([./checkin_names.wiki | more info])
367 If you omit
368 the <i>VERSION</i>, then fossil moves you to the
369 latest version of the branch you are currently on.
370
371 The default behavior is for [./concepts.wiki#workflow|autosync] to
372 be turned on. That means that a [/help/pull|pull] automatically occurs
373 when you run [/help/update|update] and a [/help/push|push] happens
374 automatically after you [/help/commit|commit]. So in normal practice,
375
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -224,16 +224,16 @@
224224
you are keeping private branches. Or, to put it another way, you are
225225
doing siloed development. You are not sharing your intermediate work
226226
with collaborators. This is not good for product quality.
227227
228228
[Nagappan, et. al][nagappan] studied bugs in Windows Vista and found
229
-that best predictor of bugs is the distance on the org-chart between
229
+that the best predictor of bugs is the distance on the org-chart between
230230
the stake-holders. The bug rate is inversely related to the
231231
amount of communication among the engineers.
232232
Similar findings arise in other disciplines. Keeping
233233
private branches does not prove that developers are communicating
234
-insufficiently, but it is a key symptom that problem.
234
+insufficiently, but it is a key symptom of that problem.
235235
236236
[Weinberg][weinberg] argues programming should be "egoless." That
237237
is to say, programmers should avoid linking their code with their sense of
238238
self, as that makes it more difficult for them to find and respond
239239
to bugs, and hence makes them less productive. Many developers are
240240
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -224,16 +224,16 @@
224 you are keeping private branches. Or, to put it another way, you are
225 doing siloed development. You are not sharing your intermediate work
226 with collaborators. This is not good for product quality.
227
228 [Nagappan, et. al][nagappan] studied bugs in Windows Vista and found
229 that best predictor of bugs is the distance on the org-chart between
230 the stake-holders. The bug rate is inversely related to the
231 amount of communication among the engineers.
232 Similar findings arise in other disciplines. Keeping
233 private branches does not prove that developers are communicating
234 insufficiently, but it is a key symptom that problem.
235
236 [Weinberg][weinberg] argues programming should be "egoless." That
237 is to say, programmers should avoid linking their code with their sense of
238 self, as that makes it more difficult for them to find and respond
239 to bugs, and hence makes them less productive. Many developers are
240
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -224,16 +224,16 @@
224 you are keeping private branches. Or, to put it another way, you are
225 doing siloed development. You are not sharing your intermediate work
226 with collaborators. This is not good for product quality.
227
228 [Nagappan, et. al][nagappan] studied bugs in Windows Vista and found
229 that the best predictor of bugs is the distance on the org-chart between
230 the stake-holders. The bug rate is inversely related to the
231 amount of communication among the engineers.
232 Similar findings arise in other disciplines. Keeping
233 private branches does not prove that developers are communicating
234 insufficiently, but it is a key symptom of that problem.
235
236 [Weinberg][weinberg] argues programming should be "egoless." That
237 is to say, programmers should avoid linking their code with their sense of
238 self, as that makes it more difficult for them to find and respond
239 to bugs, and hence makes them less productive. Many developers are
240
--- www/selfcheck.wiki
+++ www/selfcheck.wiki
@@ -13,11 +13,11 @@
1313
1414
<h2>Atomic Check-ins With Rollback</h2>
1515
1616
The Fossil repository is stored in an
1717
<a href="http://www.sqlite.org/">SQLite</a> database file.
18
-([./tech_overview.wiki | Addition information] about the repository
18
+([./tech_overview.wiki | Additional information] about the repository
1919
file format.)
2020
SQLite is very mature and stable and has been in wide-spread use for many
2121
years, so we are confident it will not cause repository
2222
corruption. SQLite
2323
databases do not corrupt even if a program or system crash or power
2424
--- www/selfcheck.wiki
+++ www/selfcheck.wiki
@@ -13,11 +13,11 @@
13
14 <h2>Atomic Check-ins With Rollback</h2>
15
16 The Fossil repository is stored in an
17 <a href="http://www.sqlite.org/">SQLite</a> database file.
18 ([./tech_overview.wiki | Addition information] about the repository
19 file format.)
20 SQLite is very mature and stable and has been in wide-spread use for many
21 years, so we are confident it will not cause repository
22 corruption. SQLite
23 databases do not corrupt even if a program or system crash or power
24
--- www/selfcheck.wiki
+++ www/selfcheck.wiki
@@ -13,11 +13,11 @@
13
14 <h2>Atomic Check-ins With Rollback</h2>
15
16 The Fossil repository is stored in an
17 <a href="http://www.sqlite.org/">SQLite</a> database file.
18 ([./tech_overview.wiki | Additional information] about the repository
19 file format.)
20 SQLite is very mature and stable and has been in wide-spread use for many
21 years, so we are confident it will not cause repository
22 corruption. SQLite
23 databases do not corrupt even if a program or system crash or power
24
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -27,11 +27,11 @@
2727
hosts <a href="http://www.sqlite.org/">SQLite</a> and over a
2828
dozen other smaller projects. This demonstrates that Fossil can run on
2929
a low-power host processor.
3030
Multiple fossil-based projects can easily be hosted on the same machine,
3131
even if that machine is itself one of several dozen virtual machines on
32
-single physical box. The CGI script that runs the canonical Fossil
32
+a single physical box. The CGI script that runs the canonical Fossil
3333
self-hosting repository is as follows:
3434
3535
<pre>
3636
#!/usr/bin/fossil
3737
repository: /fossil/fossil.fossil
3838
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -27,11 +27,11 @@
27 hosts <a href="http://www.sqlite.org/">SQLite</a> and over a
28 dozen other smaller projects. This demonstrates that Fossil can run on
29 a low-power host processor.
30 Multiple fossil-based projects can easily be hosted on the same machine,
31 even if that machine is itself one of several dozen virtual machines on
32 single physical box. The CGI script that runs the canonical Fossil
33 self-hosting repository is as follows:
34
35 <pre>
36 #!/usr/bin/fossil
37 repository: /fossil/fossil.fossil
38
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -27,11 +27,11 @@
27 hosts <a href="http://www.sqlite.org/">SQLite</a> and over a
28 dozen other smaller projects. This demonstrates that Fossil can run on
29 a low-power host processor.
30 Multiple fossil-based projects can easily be hosted on the same machine,
31 even if that machine is itself one of several dozen virtual machines on
32 a single physical box. The CGI script that runs the canonical Fossil
33 self-hosting repository is as follows:
34
35 <pre>
36 #!/usr/bin/fossil
37 repository: /fossil/fossil.fossil
38
--- www/server/debian/service.md
+++ www/server/debian/service.md
@@ -183,11 +183,11 @@
183183
to the system level. We need to start this socket listener at the root
184184
level because of the low-numbered TCP port restriction we brought up
185185
above.
186186
187187
This configuration says more or less the same thing as the socket part
188
-of an `inted` entry [exemplified elsewhere in this
188
+of an `inetd` entry [exemplified elsewhere in this
189189
documentation](../any/inetd.md).
190190
191191
Next, create the service definition file in that same directory as
192192
`[email protected]`:
193193
194194
--- www/server/debian/service.md
+++ www/server/debian/service.md
@@ -183,11 +183,11 @@
183 to the system level. We need to start this socket listener at the root
184 level because of the low-numbered TCP port restriction we brought up
185 above.
186
187 This configuration says more or less the same thing as the socket part
188 of an `inted` entry [exemplified elsewhere in this
189 documentation](../any/inetd.md).
190
191 Next, create the service definition file in that same directory as
192 `[email protected]`:
193
194
--- www/server/debian/service.md
+++ www/server/debian/service.md
@@ -183,11 +183,11 @@
183 to the system level. We need to start this socket listener at the root
184 level because of the low-numbered TCP port restriction we brought up
185 above.
186
187 This configuration says more or less the same thing as the socket part
188 of an `inetd` entry [exemplified elsewhere in this
189 documentation](../any/inetd.md).
190
191 Next, create the service definition file in that same directory as
192 `[email protected]`:
193
194
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -172,11 +172,11 @@
172172
setting, raising the limit to 100 MiB.
173173
174174
[dlim]: https://man.openbsd.org/httpd.conf.5#connection
175175
[uv]: ../../unvers.wiki
176176
177
-**NOTE:** If not already in possession of a HTTPS certificate, comment
177
+**NOTE:** If not already in possession of an HTTPS certificate, comment
178178
out the `https` server block and proceed to securing a free
179179
[Let's Encrypt Certificate](#letsencrypt); otherwise skip to
180180
[Start `httpd`](#starthttpd).
181181
182182
183183
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -172,11 +172,11 @@
172 setting, raising the limit to 100 MiB.
173
174 [dlim]: https://man.openbsd.org/httpd.conf.5#connection
175 [uv]: ../../unvers.wiki
176
177 **NOTE:** If not already in possession of a HTTPS certificate, comment
178 out the `https` server block and proceed to securing a free
179 [Let's Encrypt Certificate](#letsencrypt); otherwise skip to
180 [Start `httpd`](#starthttpd).
181
182
183
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -172,11 +172,11 @@
172 setting, raising the limit to 100 MiB.
173
174 [dlim]: https://man.openbsd.org/httpd.conf.5#connection
175 [uv]: ../../unvers.wiki
176
177 **NOTE:** If not already in possession of an HTTPS certificate, comment
178 out the `https` server block and proceed to securing a free
179 [Let's Encrypt Certificate](#letsencrypt); otherwise skip to
180 [Start `httpd`](#starthttpd).
181
182
183
--- www/server/windows/service.md
+++ www/server/windows/service.md
@@ -39,11 +39,11 @@
3939
This will create a windows service named 'Fossil-DSCM' running under the local
4040
system account and accessible on port 8080 by default. `fossil winsrv` can also
4141
start, stop, and delete the service. For all available options, please execute
4242
`fossil help winsrv` on a windows install of Fossil.
4343
44
-If you wish to server a directory of repositories, the `fossil winsrv` command
44
+If you wish to serve a directory of repositories, the `fossil winsrv` command
4545
requires a slightly different set of options vs. `fossil server`:
4646
4747
```
4848
fossil winsrv create --repository D:/Path/to/Repos --repolist
4949
```
5050
--- www/server/windows/service.md
+++ www/server/windows/service.md
@@ -39,11 +39,11 @@
39 This will create a windows service named 'Fossil-DSCM' running under the local
40 system account and accessible on port 8080 by default. `fossil winsrv` can also
41 start, stop, and delete the service. For all available options, please execute
42 `fossil help winsrv` on a windows install of Fossil.
43
44 If you wish to server a directory of repositories, the `fossil winsrv` command
45 requires a slightly different set of options vs. `fossil server`:
46
47 ```
48 fossil winsrv create --repository D:/Path/to/Repos --repolist
49 ```
50
--- www/server/windows/service.md
+++ www/server/windows/service.md
@@ -39,11 +39,11 @@
39 This will create a windows service named 'Fossil-DSCM' running under the local
40 system account and accessible on port 8080 by default. `fossil winsrv` can also
41 start, stop, and delete the service. For all available options, please execute
42 `fossil help winsrv` on a windows install of Fossil.
43
44 If you wish to serve a directory of repositories, the `fossil winsrv` command
45 requires a slightly different set of options vs. `fossil server`:
46
47 ```
48 fossil winsrv create --repository D:/Path/to/Repos --repolist
49 ```
50
--- www/settings.wiki
+++ www/settings.wiki
@@ -44,13 +44,12 @@
4444
Because these options can change over time, and the inconvenience of
4545
replicating changes, these settings are "versionable". As well as being
4646
able to be set using the <tt>settings</tt> command or the web interface,
4747
you can create versioned files in the <tt>.fossil-settings</tt>
4848
subdirectory of the check-out root, named with the setting name.
49
-The contents of the file is the
50
-value of the setting, and these files are checked in, committed, merged,
51
-and so on, as with any other file.
49
+Each file holds the value of a setting, and these files are checked in,
50
+committed, merged, and so on, as with any other file.
5251
5352
Where a setting is a list of values, such as <tt>ignore-glob</tt>, you
5453
can use a newline as a separator as well as a comma.
5554
5655
For example, to set the list of ignored files, create a
5756
--- www/settings.wiki
+++ www/settings.wiki
@@ -44,13 +44,12 @@
44 Because these options can change over time, and the inconvenience of
45 replicating changes, these settings are "versionable". As well as being
46 able to be set using the <tt>settings</tt> command or the web interface,
47 you can create versioned files in the <tt>.fossil-settings</tt>
48 subdirectory of the check-out root, named with the setting name.
49 The contents of the file is the
50 value of the setting, and these files are checked in, committed, merged,
51 and so on, as with any other file.
52
53 Where a setting is a list of values, such as <tt>ignore-glob</tt>, you
54 can use a newline as a separator as well as a comma.
55
56 For example, to set the list of ignored files, create a
57
--- www/settings.wiki
+++ www/settings.wiki
@@ -44,13 +44,12 @@
44 Because these options can change over time, and the inconvenience of
45 replicating changes, these settings are "versionable". As well as being
46 able to be set using the <tt>settings</tt> command or the web interface,
47 you can create versioned files in the <tt>.fossil-settings</tt>
48 subdirectory of the check-out root, named with the setting name.
49 Each file holds the value of a setting, and these files are checked in,
50 committed, merged, and so on, as with any other file.
 
51
52 Where a setting is a list of values, such as <tt>ignore-glob</tt>, you
53 can use a newline as a separator as well as a comma.
54
55 For example, to set the list of ignored files, create a
56
--- www/shunning.wiki
+++ www/shunning.wiki
@@ -33,11 +33,11 @@
3333
3434
All of these are rare cases: Fossil is [./antibot.wiki | designed to
3535
foil spammers up front], legally problematic check-ins should range from
3636
rare to nonexistent, and you have to go way out of your way to force
3737
Fossil to insert bad control artifacts. Therefore, before we get to
38
-methods of permanently deleting content from a Fossil repos, let's give
38
+methods of permanently deleting content from a Fossil repo, let's give
3939
some alternatives that usually suffice, which don't damage the project's
4040
fossil record:
4141
4242
* When a forum post or wiki article is "deleted," what actually
4343
happens is that a new empty version is added to the Fossil repository.
@@ -133,11 +133,11 @@
133133
using the "configuration" command:
134134
135135
<b>fossil configuration pull shun</b> <i>remote-url</i><br>
136136
<b>fossil configuration push shun</b> <i>remote-url</i>
137137
138
-The two command above will pull or push shunning lists from or to
138
+The two commands above will pull or push shunning lists from or to
139139
the <i>remote-url</i> indicated and merge the lists on the receiving
140140
end. "Admin" privilege on the remote server is required in order to
141141
push a shun list. In contrast, the shunning list will be automatically
142142
received by default as part of a normal client "pull" operation unless
143143
disabled by the "<tt>auto-shun</tt>" setting.
144144
--- www/shunning.wiki
+++ www/shunning.wiki
@@ -33,11 +33,11 @@
33
34 All of these are rare cases: Fossil is [./antibot.wiki | designed to
35 foil spammers up front], legally problematic check-ins should range from
36 rare to nonexistent, and you have to go way out of your way to force
37 Fossil to insert bad control artifacts. Therefore, before we get to
38 methods of permanently deleting content from a Fossil repos, let's give
39 some alternatives that usually suffice, which don't damage the project's
40 fossil record:
41
42 * When a forum post or wiki article is "deleted," what actually
43 happens is that a new empty version is added to the Fossil repository.
@@ -133,11 +133,11 @@
133 using the "configuration" command:
134
135 <b>fossil configuration pull shun</b> <i>remote-url</i><br>
136 <b>fossil configuration push shun</b> <i>remote-url</i>
137
138 The two command above will pull or push shunning lists from or to
139 the <i>remote-url</i> indicated and merge the lists on the receiving
140 end. "Admin" privilege on the remote server is required in order to
141 push a shun list. In contrast, the shunning list will be automatically
142 received by default as part of a normal client "pull" operation unless
143 disabled by the "<tt>auto-shun</tt>" setting.
144
--- www/shunning.wiki
+++ www/shunning.wiki
@@ -33,11 +33,11 @@
33
34 All of these are rare cases: Fossil is [./antibot.wiki | designed to
35 foil spammers up front], legally problematic check-ins should range from
36 rare to nonexistent, and you have to go way out of your way to force
37 Fossil to insert bad control artifacts. Therefore, before we get to
38 methods of permanently deleting content from a Fossil repo, let's give
39 some alternatives that usually suffice, which don't damage the project's
40 fossil record:
41
42 * When a forum post or wiki article is "deleted," what actually
43 happens is that a new empty version is added to the Fossil repository.
@@ -133,11 +133,11 @@
133 using the "configuration" command:
134
135 <b>fossil configuration pull shun</b> <i>remote-url</i><br>
136 <b>fossil configuration push shun</b> <i>remote-url</i>
137
138 The two commands above will pull or push shunning lists from or to
139 the <i>remote-url</i> indicated and merge the lists on the receiving
140 end. "Admin" privilege on the remote server is required in order to
141 push a shun list. In contrast, the shunning list will be automatically
142 received by default as part of a normal client "pull" operation unless
143 disabled by the "<tt>auto-shun</tt>" setting.
144
+2 -2
--- www/stats.wiki
+++ www/stats.wiki
@@ -1,11 +1,11 @@
11
<title>Fossil Performance</title>
22
33
The questions will inevitably arise: How does Fossil perform?
44
Does it use a lot of disk space or bandwidth? Is it scalable?
55
6
-In an attempt to answers these questions, this report looks at several
6
+In an attempt to answer these questions, this report looks at several
77
projects that use fossil for configuration management and examines how
88
well they are working. The following table is a summary of the results.
99
(Last updated on 2018-06-04.)
1010
Explanation and analysis follows the table.
1111
@@ -100,11 +100,11 @@
100100
is the unordered collection of artifacts. In fact, one of the key
101101
characteristics of Fossil is that the entire project history can be
102102
reconstructed simply by scanning the artifacts in an arbitrary order.
103103
104104
The number of check-ins is the number of times that the "commit" command
105
-has been run. A single check-in might change a 3 or 4 files, or it might
105
+has been run. A single check-in might change 3 or 4 files, or it might
106106
change dozens or hundreds of files. Regardless of the number of files
107107
changed, it still only counts as one check-in.
108108
109109
The "Uncompressed Size" is the total size of all the artifacts within
110110
the repository assuming they were all uncompressed and stored
111111
--- www/stats.wiki
+++ www/stats.wiki
@@ -1,11 +1,11 @@
1 <title>Fossil Performance</title>
2
3 The questions will inevitably arise: How does Fossil perform?
4 Does it use a lot of disk space or bandwidth? Is it scalable?
5
6 In an attempt to answers these questions, this report looks at several
7 projects that use fossil for configuration management and examines how
8 well they are working. The following table is a summary of the results.
9 (Last updated on 2018-06-04.)
10 Explanation and analysis follows the table.
11
@@ -100,11 +100,11 @@
100 is the unordered collection of artifacts. In fact, one of the key
101 characteristics of Fossil is that the entire project history can be
102 reconstructed simply by scanning the artifacts in an arbitrary order.
103
104 The number of check-ins is the number of times that the "commit" command
105 has been run. A single check-in might change a 3 or 4 files, or it might
106 change dozens or hundreds of files. Regardless of the number of files
107 changed, it still only counts as one check-in.
108
109 The "Uncompressed Size" is the total size of all the artifacts within
110 the repository assuming they were all uncompressed and stored
111
--- www/stats.wiki
+++ www/stats.wiki
@@ -1,11 +1,11 @@
1 <title>Fossil Performance</title>
2
3 The questions will inevitably arise: How does Fossil perform?
4 Does it use a lot of disk space or bandwidth? Is it scalable?
5
6 In an attempt to answer these questions, this report looks at several
7 projects that use fossil for configuration management and examines how
8 well they are working. The following table is a summary of the results.
9 (Last updated on 2018-06-04.)
10 Explanation and analysis follows the table.
11
@@ -100,11 +100,11 @@
100 is the unordered collection of artifacts. In fact, one of the key
101 characteristics of Fossil is that the entire project history can be
102 reconstructed simply by scanning the artifacts in an arbitrary order.
103
104 The number of check-ins is the number of times that the "commit" command
105 has been run. A single check-in might change 3 or 4 files, or it might
106 change dozens or hundreds of files. Regardless of the number of files
107 changed, it still only counts as one check-in.
108
109 The "Uncompressed Size" is the total size of all the artifacts within
110 the repository assuming they were all uncompressed and stored
111
+6 -5
--- www/style.wiki
+++ www/style.wiki
@@ -1,8 +1,8 @@
11
<title>Coding Style</title>
22
3
-Fossil source code should following the style guidelines below.
3
+Fossil source code should follow the style guidelines below.
44
55
<em> The Fossil source tree includes a few files taken from external
66
sources
77
(examples: [https://github.com/antirez/linenoise|linenoise] and
88
[http://zlib.net/|zLib])
@@ -38,13 +38,14 @@
3838
3939
<li> -Wno-long-long: Fossil uses the 'long long' integer type, which is not strictly ANSI C-89 (defined in C99).
4040
The use of 'long long' resolves many problems with 64-bit arithmetics, especially on 32-bit machines.
4141
(http_ssl.c, sha3.c, shell.c, util.c)
4242
43
- <li> alloca(): By default, sqlite3.c is compiled with the -DSQLITE_USE_ALLOCA flag to use the alloca() function.
44
- alloca() is not considered ANSI C, and normally not recommended due to portability issues, but
45
- performance and/or memory consumption improvement may be a stronger argument in favor of its usage.
43
+ <li> alloca(): By default, sqlite3.c was compiled with the -DSQLITE_USE_ALLOCA flag to use the alloca() function.
44
+ This is no longer the case as of 20220119. alloca() is not considered ANSI C, and normally not
45
+ recommended due to portability issues, but performance and/or memory consumption
46
+ improvement may have been a stronger argument in favor of its usage.
4647
(sqlite3.c)
4748
</ol>
4849
4950
<li> All comments and identifiers are in English.
5051
@@ -75,11 +76,11 @@
7576
7677
<ol>
7778
<li value=30> Every function has a header comment describing the purpose and use
7879
of the function.
7980
80
- <li> Function header comment defines the behavior of the function in
81
+ <li> A function header comment defines the behavior of the function in
8182
sufficient detail to allow the function to be re-implemented from
8283
scratch without reference to the original code.
8384
8485
<li> Functions that perform dynamic memory allocation (either directly
8586
or indirectly via subfunctions) say so in their header comments.
8687
--- www/style.wiki
+++ www/style.wiki
@@ -1,8 +1,8 @@
1 <title>Coding Style</title>
2
3 Fossil source code should following the style guidelines below.
4
5 <em> The Fossil source tree includes a few files taken from external
6 sources
7 (examples: [https://github.com/antirez/linenoise|linenoise] and
8 [http://zlib.net/|zLib])
@@ -38,13 +38,14 @@
38
39 <li> -Wno-long-long: Fossil uses the 'long long' integer type, which is not strictly ANSI C-89 (defined in C99).
40 The use of 'long long' resolves many problems with 64-bit arithmetics, especially on 32-bit machines.
41 (http_ssl.c, sha3.c, shell.c, util.c)
42
43 <li> alloca(): By default, sqlite3.c is compiled with the -DSQLITE_USE_ALLOCA flag to use the alloca() function.
44 alloca() is not considered ANSI C, and normally not recommended due to portability issues, but
45 performance and/or memory consumption improvement may be a stronger argument in favor of its usage.
 
46 (sqlite3.c)
47 </ol>
48
49 <li> All comments and identifiers are in English.
50
@@ -75,11 +76,11 @@
75
76 <ol>
77 <li value=30> Every function has a header comment describing the purpose and use
78 of the function.
79
80 <li> Function header comment defines the behavior of the function in
81 sufficient detail to allow the function to be re-implemented from
82 scratch without reference to the original code.
83
84 <li> Functions that perform dynamic memory allocation (either directly
85 or indirectly via subfunctions) say so in their header comments.
86
--- www/style.wiki
+++ www/style.wiki
@@ -1,8 +1,8 @@
1 <title>Coding Style</title>
2
3 Fossil source code should follow the style guidelines below.
4
5 <em> The Fossil source tree includes a few files taken from external
6 sources
7 (examples: [https://github.com/antirez/linenoise|linenoise] and
8 [http://zlib.net/|zLib])
@@ -38,13 +38,14 @@
38
39 <li> -Wno-long-long: Fossil uses the 'long long' integer type, which is not strictly ANSI C-89 (defined in C99).
40 The use of 'long long' resolves many problems with 64-bit arithmetics, especially on 32-bit machines.
41 (http_ssl.c, sha3.c, shell.c, util.c)
42
43 <li> alloca(): By default, sqlite3.c was compiled with the -DSQLITE_USE_ALLOCA flag to use the alloca() function.
44 This is no longer the case as of 20220119. alloca() is not considered ANSI C, and normally not
45 recommended due to portability issues, but performance and/or memory consumption
46 improvement may have been a stronger argument in favor of its usage.
47 (sqlite3.c)
48 </ol>
49
50 <li> All comments and identifiers are in English.
51
@@ -75,11 +76,11 @@
76
77 <ol>
78 <li value=30> Every function has a header comment describing the purpose and use
79 of the function.
80
81 <li> A function header comment defines the behavior of the function in
82 sufficient detail to allow the function to be re-implemented from
83 scratch without reference to the original code.
84
85 <li> Functions that perform dynamic memory allocation (either directly
86 or indirectly via subfunctions) say so in their header comments.
87
+33 -13
--- www/sync.wiki
+++ www/sync.wiki
@@ -518,11 +518,11 @@
518518
pronounced as if it were a single word "gimme" in some dialects of
519519
English (including the dialect spoken by the original author of Fossil).
520520
521521
<h4>3.7.1 Unversioned Gimme Cards</h4>
522522
523
-Sync synchronizing unversioned content, the client may send "uvgimme"
523
+When synchronizing unversioned content, the client may send "uvgimme"
524524
cards to the server. A uvgimme card requests that the server send
525525
unversioned content to the client. The format of a uvgimme card is
526526
as follows:
527527
528528
<pre>
@@ -570,77 +570,97 @@
570570
571571
<pre>
572572
<b>reqconfig</b> <i>configuration-name</i>
573573
</pre>
574574
575
-As of 2018-06-04, the configuration-name must be one of the
575
+As of 2024-10-22, the configuration-name must be one of the
576576
following values:
577577
578578
<table border=0 align="center">
579579
<tr><td valign="top">
580580
<ul>
581581
<li> css
582582
<li> header
583
+<li> mainmenu
583584
<li> footer
584585
<li> details
586
+<li> js
587
+<li> default-skin
585588
<li> logo-mimetype
586589
<li> logo-image
587590
<li> background-mimetype
588591
<li> background-image
589
-<li> index-page
592
+<li> icon-mimetype
593
+<li> icon-image
590594
<li> timeline-block-markup
595
+<li> timeline-date-format
596
+<li> timeline-default-style
597
+<ul></td><td valign="top"><ul>
598
+<li> timeline-dwelltime
599
+<li> timeline-closetime
600
+<li> timeline-hard-newlines
591601
<li> timeline-max-comment
592602
<li> timeline-plaintext
603
+<li> timeline-truncate-at-blank
604
+<li> timeline-tslink-info
605
+<li> timeline-utc
593606
<li> adunit
594607
<li> adunit-omit-if-admin
595608
<li> adunit-omit-if-user
596
-<ul></td><td valign="top"><ul>
597
-<li> th1-docs
609
+<li> default-csp
610
+<li> sitemap-extra
611
+<li> safe-html
598612
<li> th1-hooks
599
-<li> th1-setup
600
-<li> tcl
601
-<li> tcl-setup
613
+<li> th1-uri-regexp
602614
<li> project-name
615
+<ul></td><td valign="top"><ul>
603616
<li> short-project-name
604617
<li> project-description
605618
<li> index-page
606619
<li> manifest
607620
<li> binary-glob
608621
<li> clean-glob
609622
<li> ignore-glob
610623
<li> keep-glob
611624
<li> crlf-glob
612
-<ul></td><td valign="top"><ul>
613625
<li> crnl-glob
614626
<li> encoding-glob
615627
<li> empty-dirs
616628
<li> <s title="removed 2020-08, version 2.12.1">allow-symlinks</s>
617629
<li> dotfiles
618630
<li> parent-project-code
619
-<li> parent-projet-name
631
+<li> parent-project-name
632
+<ul></td><td valign="top"><ul>
620633
<li> hash-policy
634
+<li> comment-format
635
+<li> mimetypes
636
+<li> forbid-delta-manifests
621637
<li> mv-rm-files
622638
<li> ticket-table
623639
<li> ticket-common
624640
<li> ticket-change
625641
<li> ticket-newpage
626642
<li> ticket-viewpage
627643
<li> ticket-editpage
628
-<ul></td><td valign="top"><ul>
629644
<li> ticket-reportlist
630645
<li> ticket-report-template
631646
<li> ticket-key-template
632647
<li> ticket-title-expr
633648
<li> ticket-closed-expr
649
+<ul></td><td valign="top"><ul>
650
+<li> user-color-map
634651
<li> xfer-common-script
635652
<li> xfer-push-script
636653
<li> xfer-commit-script
637654
<li> xfer-ticket-script
638655
<li> @reportfmt
639656
<li> @user
640657
<li> @concealed
641658
<li> @shun
659
+<li> @alias
660
+<li> @subscriber
661
+<li> @interwiki
642662
</ul></td></tr>
643663
</table>
644664
645665
New configuration-names are likely to be added in future releases of
646666
Fossil. If the server receives a configuration-name that it does not
@@ -861,11 +881,11 @@
861881
<h2 id="strategies">5.0 Synchronization Strategies</h2>
862882
863883
<h3 id="pull-strategy">5.1 Pull</h3>
864884
865885
A typical pull operation proceeds as shown below. Details
866
-of the actual implementation may very slightly but the gist of
886
+of the actual implementation may vary slightly but the gist of
867887
a pull is captured in the following steps:
868888
869889
<ol>
870890
<li>The client sends login and pull cards.
871891
<li>The client sends a cookie card if it has previously received a cookie.
@@ -1071,6 +1091,6 @@
10711091
</ol>
10721092
10731093
In a complex debugging situation, you can run the command
10741094
"fossil sync --transport-command ./debugging_script" where
10751095
"debugging_script" is some script of your own that invokes
1076
-the anomolous behavior your are trying to debug.
1096
+the anomalous behavior you are trying to debug.
10771097
--- www/sync.wiki
+++ www/sync.wiki
@@ -518,11 +518,11 @@
518 pronounced as if it were a single word "gimme" in some dialects of
519 English (including the dialect spoken by the original author of Fossil).
520
521 <h4>3.7.1 Unversioned Gimme Cards</h4>
522
523 Sync synchronizing unversioned content, the client may send "uvgimme"
524 cards to the server. A uvgimme card requests that the server send
525 unversioned content to the client. The format of a uvgimme card is
526 as follows:
527
528 <pre>
@@ -570,77 +570,97 @@
570
571 <pre>
572 <b>reqconfig</b> <i>configuration-name</i>
573 </pre>
574
575 As of 2018-06-04, the configuration-name must be one of the
576 following values:
577
578 <table border=0 align="center">
579 <tr><td valign="top">
580 <ul>
581 <li> css
582 <li> header
 
583 <li> footer
584 <li> details
 
 
585 <li> logo-mimetype
586 <li> logo-image
587 <li> background-mimetype
588 <li> background-image
589 <li> index-page
 
590 <li> timeline-block-markup
 
 
 
 
 
 
591 <li> timeline-max-comment
592 <li> timeline-plaintext
 
 
 
593 <li> adunit
594 <li> adunit-omit-if-admin
595 <li> adunit-omit-if-user
596 <ul></td><td valign="top"><ul>
597 <li> th1-docs
 
598 <li> th1-hooks
599 <li> th1-setup
600 <li> tcl
601 <li> tcl-setup
602 <li> project-name
 
603 <li> short-project-name
604 <li> project-description
605 <li> index-page
606 <li> manifest
607 <li> binary-glob
608 <li> clean-glob
609 <li> ignore-glob
610 <li> keep-glob
611 <li> crlf-glob
612 <ul></td><td valign="top"><ul>
613 <li> crnl-glob
614 <li> encoding-glob
615 <li> empty-dirs
616 <li> <s title="removed 2020-08, version 2.12.1">allow-symlinks</s>
617 <li> dotfiles
618 <li> parent-project-code
619 <li> parent-projet-name
 
620 <li> hash-policy
 
 
 
621 <li> mv-rm-files
622 <li> ticket-table
623 <li> ticket-common
624 <li> ticket-change
625 <li> ticket-newpage
626 <li> ticket-viewpage
627 <li> ticket-editpage
628 <ul></td><td valign="top"><ul>
629 <li> ticket-reportlist
630 <li> ticket-report-template
631 <li> ticket-key-template
632 <li> ticket-title-expr
633 <li> ticket-closed-expr
 
 
634 <li> xfer-common-script
635 <li> xfer-push-script
636 <li> xfer-commit-script
637 <li> xfer-ticket-script
638 <li> @reportfmt
639 <li> @user
640 <li> @concealed
641 <li> @shun
 
 
 
642 </ul></td></tr>
643 </table>
644
645 New configuration-names are likely to be added in future releases of
646 Fossil. If the server receives a configuration-name that it does not
@@ -861,11 +881,11 @@
861 <h2 id="strategies">5.0 Synchronization Strategies</h2>
862
863 <h3 id="pull-strategy">5.1 Pull</h3>
864
865 A typical pull operation proceeds as shown below. Details
866 of the actual implementation may very slightly but the gist of
867 a pull is captured in the following steps:
868
869 <ol>
870 <li>The client sends login and pull cards.
871 <li>The client sends a cookie card if it has previously received a cookie.
@@ -1071,6 +1091,6 @@
1071 </ol>
1072
1073 In a complex debugging situation, you can run the command
1074 "fossil sync --transport-command ./debugging_script" where
1075 "debugging_script" is some script of your own that invokes
1076 the anomolous behavior your are trying to debug.
1077
--- www/sync.wiki
+++ www/sync.wiki
@@ -518,11 +518,11 @@
518 pronounced as if it were a single word "gimme" in some dialects of
519 English (including the dialect spoken by the original author of Fossil).
520
521 <h4>3.7.1 Unversioned Gimme Cards</h4>
522
523 When synchronizing unversioned content, the client may send "uvgimme"
524 cards to the server. A uvgimme card requests that the server send
525 unversioned content to the client. The format of a uvgimme card is
526 as follows:
527
528 <pre>
@@ -570,77 +570,97 @@
570
571 <pre>
572 <b>reqconfig</b> <i>configuration-name</i>
573 </pre>
574
575 As of 2024-10-22, the configuration-name must be one of the
576 following values:
577
578 <table border=0 align="center">
579 <tr><td valign="top">
580 <ul>
581 <li> css
582 <li> header
583 <li> mainmenu
584 <li> footer
585 <li> details
586 <li> js
587 <li> default-skin
588 <li> logo-mimetype
589 <li> logo-image
590 <li> background-mimetype
591 <li> background-image
592 <li> icon-mimetype
593 <li> icon-image
594 <li> timeline-block-markup
595 <li> timeline-date-format
596 <li> timeline-default-style
597 <ul></td><td valign="top"><ul>
598 <li> timeline-dwelltime
599 <li> timeline-closetime
600 <li> timeline-hard-newlines
601 <li> timeline-max-comment
602 <li> timeline-plaintext
603 <li> timeline-truncate-at-blank
604 <li> timeline-tslink-info
605 <li> timeline-utc
606 <li> adunit
607 <li> adunit-omit-if-admin
608 <li> adunit-omit-if-user
609 <li> default-csp
610 <li> sitemap-extra
611 <li> safe-html
612 <li> th1-hooks
613 <li> th1-uri-regexp
 
 
614 <li> project-name
615 <ul></td><td valign="top"><ul>
616 <li> short-project-name
617 <li> project-description
618 <li> index-page
619 <li> manifest
620 <li> binary-glob
621 <li> clean-glob
622 <li> ignore-glob
623 <li> keep-glob
624 <li> crlf-glob
 
625 <li> crnl-glob
626 <li> encoding-glob
627 <li> empty-dirs
628 <li> <s title="removed 2020-08, version 2.12.1">allow-symlinks</s>
629 <li> dotfiles
630 <li> parent-project-code
631 <li> parent-project-name
632 <ul></td><td valign="top"><ul>
633 <li> hash-policy
634 <li> comment-format
635 <li> mimetypes
636 <li> forbid-delta-manifests
637 <li> mv-rm-files
638 <li> ticket-table
639 <li> ticket-common
640 <li> ticket-change
641 <li> ticket-newpage
642 <li> ticket-viewpage
643 <li> ticket-editpage
 
644 <li> ticket-reportlist
645 <li> ticket-report-template
646 <li> ticket-key-template
647 <li> ticket-title-expr
648 <li> ticket-closed-expr
649 <ul></td><td valign="top"><ul>
650 <li> user-color-map
651 <li> xfer-common-script
652 <li> xfer-push-script
653 <li> xfer-commit-script
654 <li> xfer-ticket-script
655 <li> @reportfmt
656 <li> @user
657 <li> @concealed
658 <li> @shun
659 <li> @alias
660 <li> @subscriber
661 <li> @interwiki
662 </ul></td></tr>
663 </table>
664
665 New configuration-names are likely to be added in future releases of
666 Fossil. If the server receives a configuration-name that it does not
@@ -861,11 +881,11 @@
881 <h2 id="strategies">5.0 Synchronization Strategies</h2>
882
883 <h3 id="pull-strategy">5.1 Pull</h3>
884
885 A typical pull operation proceeds as shown below. Details
886 of the actual implementation may vary slightly but the gist of
887 a pull is captured in the following steps:
888
889 <ol>
890 <li>The client sends login and pull cards.
891 <li>The client sends a cookie card if it has previously received a cookie.
@@ -1071,6 +1091,6 @@
1091 </ol>
1092
1093 In a complex debugging situation, you can run the command
1094 "fossil sync --transport-command ./debugging_script" where
1095 "debugging_script" is some script of your own that invokes
1096 the anomalous behavior you are trying to debug.
1097
--- www/tech_overview.wiki
+++ www/tech_overview.wiki
@@ -142,11 +142,11 @@
142142
if the ~/.fossil file does not already exist
143143
* Otherwise, use the traditional unix name of "~/.fossil"
144144
145145
This algorithm is complex due to the need for historical compatibility.
146146
Originally, the database was always just "~/.fossil". Then support
147
-for the FOSSIL_HOME environment variable as added. Later, support for the
147
+for the FOSSIL_HOME environment variable was added. Later, support for the
148148
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html|XDG-compatible configation filenames]
149149
was added. Each of these changes needed to continue to support legacy
150150
installations.
151151
152152
On Windows, the configuration database is the first of the following
153153
--- www/tech_overview.wiki
+++ www/tech_overview.wiki
@@ -142,11 +142,11 @@
142 if the ~/.fossil file does not already exist
143 * Otherwise, use the traditional unix name of "~/.fossil"
144
145 This algorithm is complex due to the need for historical compatibility.
146 Originally, the database was always just "~/.fossil". Then support
147 for the FOSSIL_HOME environment variable as added. Later, support for the
148 [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html|XDG-compatible configation filenames]
149 was added. Each of these changes needed to continue to support legacy
150 installations.
151
152 On Windows, the configuration database is the first of the following
153
--- www/tech_overview.wiki
+++ www/tech_overview.wiki
@@ -142,11 +142,11 @@
142 if the ~/.fossil file does not already exist
143 * Otherwise, use the traditional unix name of "~/.fossil"
144
145 This algorithm is complex due to the need for historical compatibility.
146 Originally, the database was always just "~/.fossil". Then support
147 for the FOSSIL_HOME environment variable was added. Later, support for the
148 [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html|XDG-compatible configation filenames]
149 was added. Each of these changes needed to continue to support legacy
150 installations.
151
152 On Windows, the configuration database is the first of the following
153
+5 -5
--- www/th1.md
+++ www/th1.md
@@ -32,11 +32,11 @@
3232
the computation, then converting the result back into a string. (This might
3333
seem inefficient, but it is faster than people imagine, and numeric
3434
computations do not come up very often for the kinds of work that TH1 does,
3535
so it has never been a factor.)
3636
37
-A TH1 script consist of a sequence of commands.
37
+A TH1 script consists of a sequence of commands.
3838
Each command is terminated by the first *unescaped* newline or ";" character.
3939
The text of the command (excluding the newline or semicolon terminator)
4040
is broken into space-separated tokens. The first token is the command
4141
name and subsequent tokens are the arguments. In this sense, TH1 syntax
4242
is similar to the familiar command-line shell syntax.
@@ -288,11 +288,11 @@
288288
The capability expression is a list. Each term of the list is a
289289
cluster of [capability letters](./caps/ref.html).
290290
The overall expression is true if any
291291
one term is true. A single term is true if all letters within that
292292
term are true. Or, if the term begins with "!", then the term is true
293
-if none of the terms or true. Or, if the term begins with "@" then
293
+if none of the terms are true. Or, if the term begins with "@" then
294294
the term is true if all of the capability letters in that term are
295295
available to the "anonymous" user. Or, if the term is "*" then it is
296296
always true.
297297
298298
Examples:
@@ -383,11 +383,11 @@
383383
<a id="date"></a>TH1 date Command
384384
-----------------------------------
385385
386386
* date ?-local?
387387
388
-Return a strings which is the current time and date. If the -local
388
+Return a string which is the current time and date. If the -local
389389
option is used, the date appears using localtime instead of UTC.
390390
391391
<a id="decorate"></a>TH1 decorate Command
392392
-------------------------------------------
393393
@@ -570,11 +570,11 @@
570570
<a id="linecount"></a>TH1 linecount Command
571571
---------------------------------------------
572572
573573
* linecount STRING MAX MIN
574574
575
-Returns one more than the number of \n characters in STRING. But
575
+Returns one more than the number of `\n` characters in STRING. But
576576
never returns less than MIN or more than MAX.
577577
578578
<a id="markdown"></a>TH1 markdown Command
579579
-------------------------------------------
580580
@@ -842,11 +842,11 @@
842842
-----------------------------------------------
843843
844844
* verifyCsrf
845845
846846
Before using the results of a form, first call this command to verify
847
-that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
847
+that the Anti-CSRF token is present and is valid. If the Anti-CSRF token
848848
is missing or is incorrect, that indicates a cross-site scripting attack.
849849
If the event of an attack is detected, an error message is generated and
850850
all further processing is aborted.
851851
852852
<a id="verifyLogin"></a>TH1 verifyLogin Command
853853
--- www/th1.md
+++ www/th1.md
@@ -32,11 +32,11 @@
32 the computation, then converting the result back into a string. (This might
33 seem inefficient, but it is faster than people imagine, and numeric
34 computations do not come up very often for the kinds of work that TH1 does,
35 so it has never been a factor.)
36
37 A TH1 script consist of a sequence of commands.
38 Each command is terminated by the first *unescaped* newline or ";" character.
39 The text of the command (excluding the newline or semicolon terminator)
40 is broken into space-separated tokens. The first token is the command
41 name and subsequent tokens are the arguments. In this sense, TH1 syntax
42 is similar to the familiar command-line shell syntax.
@@ -288,11 +288,11 @@
288 The capability expression is a list. Each term of the list is a
289 cluster of [capability letters](./caps/ref.html).
290 The overall expression is true if any
291 one term is true. A single term is true if all letters within that
292 term are true. Or, if the term begins with "!", then the term is true
293 if none of the terms or true. Or, if the term begins with "@" then
294 the term is true if all of the capability letters in that term are
295 available to the "anonymous" user. Or, if the term is "*" then it is
296 always true.
297
298 Examples:
@@ -383,11 +383,11 @@
383 <a id="date"></a>TH1 date Command
384 -----------------------------------
385
386 * date ?-local?
387
388 Return a strings which is the current time and date. If the -local
389 option is used, the date appears using localtime instead of UTC.
390
391 <a id="decorate"></a>TH1 decorate Command
392 -------------------------------------------
393
@@ -570,11 +570,11 @@
570 <a id="linecount"></a>TH1 linecount Command
571 ---------------------------------------------
572
573 * linecount STRING MAX MIN
574
575 Returns one more than the number of \n characters in STRING. But
576 never returns less than MIN or more than MAX.
577
578 <a id="markdown"></a>TH1 markdown Command
579 -------------------------------------------
580
@@ -842,11 +842,11 @@
842 -----------------------------------------------
843
844 * verifyCsrf
845
846 Before using the results of a form, first call this command to verify
847 that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
848 is missing or is incorrect, that indicates a cross-site scripting attack.
849 If the event of an attack is detected, an error message is generated and
850 all further processing is aborted.
851
852 <a id="verifyLogin"></a>TH1 verifyLogin Command
853
--- www/th1.md
+++ www/th1.md
@@ -32,11 +32,11 @@
32 the computation, then converting the result back into a string. (This might
33 seem inefficient, but it is faster than people imagine, and numeric
34 computations do not come up very often for the kinds of work that TH1 does,
35 so it has never been a factor.)
36
37 A TH1 script consists of a sequence of commands.
38 Each command is terminated by the first *unescaped* newline or ";" character.
39 The text of the command (excluding the newline or semicolon terminator)
40 is broken into space-separated tokens. The first token is the command
41 name and subsequent tokens are the arguments. In this sense, TH1 syntax
42 is similar to the familiar command-line shell syntax.
@@ -288,11 +288,11 @@
288 The capability expression is a list. Each term of the list is a
289 cluster of [capability letters](./caps/ref.html).
290 The overall expression is true if any
291 one term is true. A single term is true if all letters within that
292 term are true. Or, if the term begins with "!", then the term is true
293 if none of the terms are true. Or, if the term begins with "@" then
294 the term is true if all of the capability letters in that term are
295 available to the "anonymous" user. Or, if the term is "*" then it is
296 always true.
297
298 Examples:
@@ -383,11 +383,11 @@
383 <a id="date"></a>TH1 date Command
384 -----------------------------------
385
386 * date ?-local?
387
388 Return a string which is the current time and date. If the -local
389 option is used, the date appears using localtime instead of UTC.
390
391 <a id="decorate"></a>TH1 decorate Command
392 -------------------------------------------
393
@@ -570,11 +570,11 @@
570 <a id="linecount"></a>TH1 linecount Command
571 ---------------------------------------------
572
573 * linecount STRING MAX MIN
574
575 Returns one more than the number of `\n` characters in STRING. But
576 never returns less than MIN or more than MAX.
577
578 <a id="markdown"></a>TH1 markdown Command
579 -------------------------------------------
580
@@ -842,11 +842,11 @@
842 -----------------------------------------------
843
844 * verifyCsrf
845
846 Before using the results of a form, first call this command to verify
847 that the Anti-CSRF token is present and is valid. If the Anti-CSRF token
848 is missing or is incorrect, that indicates a cross-site scripting attack.
849 If the event of an attack is detected, an error message is generated and
850 all further processing is aborted.
851
852 <a id="verifyLogin"></a>TH1 verifyLogin Command
853
--- www/theory1.wiki
+++ www/theory1.wiki
@@ -73,14 +73,14 @@
7373
implementation detail which currently happens to use SQLite.
7474
7575
Another way to think of the relational tables in a Fossil repository is
7676
as an index for the artifacts. Without the relational tables,
7777
to generate a report like a timeline would require scanning every artifact -
78
-the equivalent of a full table scan. The relational tables hold pointers
78
+the equivalent of a full table scan. The relational tables hold pointers to
7979
the relevant artifacts in presorted order so that generating a timeline
8080
is much more efficient. So like an index in a relational database, the
81
-relational tables in an Fossil repository do not add any new information,
81
+relational tables in a Fossil repository do not add any new information,
8282
they merely make the information in the artifacts faster and easier to
8383
look up.
8484
8585
Fossil is not "based" on SQLite. Fossil simply exploits SQLite as
8686
a powerful tool to make the implementation easier.
8787
--- www/theory1.wiki
+++ www/theory1.wiki
@@ -73,14 +73,14 @@
73 implementation detail which currently happens to use SQLite.
74
75 Another way to think of the relational tables in a Fossil repository is
76 as an index for the artifacts. Without the relational tables,
77 to generate a report like a timeline would require scanning every artifact -
78 the equivalent of a full table scan. The relational tables hold pointers
79 the relevant artifacts in presorted order so that generating a timeline
80 is much more efficient. So like an index in a relational database, the
81 relational tables in an Fossil repository do not add any new information,
82 they merely make the information in the artifacts faster and easier to
83 look up.
84
85 Fossil is not "based" on SQLite. Fossil simply exploits SQLite as
86 a powerful tool to make the implementation easier.
87
--- www/theory1.wiki
+++ www/theory1.wiki
@@ -73,14 +73,14 @@
73 implementation detail which currently happens to use SQLite.
74
75 Another way to think of the relational tables in a Fossil repository is
76 as an index for the artifacts. Without the relational tables,
77 to generate a report like a timeline would require scanning every artifact -
78 the equivalent of a full table scan. The relational tables hold pointers to
79 the relevant artifacts in presorted order so that generating a timeline
80 is much more efficient. So like an index in a relational database, the
81 relational tables in a Fossil repository do not add any new information,
82 they merely make the information in the artifacts faster and easier to
83 look up.
84
85 Fossil is not "based" on SQLite. Fossil simply exploits SQLite as
86 a powerful tool to make the implementation easier.
87
--- www/tickets.wiki
+++ www/tickets.wiki
@@ -27,11 +27,11 @@
2727
that key, or the value may be appended to the prior value.
2828
2929
<h2>2.0 Ticket Tables</h2>
3030
3131
The low-level artifact format for ticket content is tedious and
32
-cumbersome to access in real time. To facility reporting and display
32
+cumbersome to access in real time. To facilitate reporting and display
3333
of tickets, the low-level artifact information is collected and
3434
summarized in a pair of SQL tables in each local repository. Display
3535
and reporting of tickets is accomplished by querying these two tables.
3636
3737
Note that only the low-level ticket change artifacts are synced. The
@@ -191,9 +191,9 @@
191191
comment according to its chosen format. Hence, Fossil was enhanced to
192192
support the "new-style" tickets.
193193
194194
The TICKETCHNG table was added to support new-style tickets. In the new
195195
style, comment text is stored with the "icomment" (for "Incremental Comment")
196
-key and appears separately, and with its on mimetype, in multiple rows
196
+key and appears separately, and with its own mimetype, in multiple rows
197197
of the TICKETCHNG table. It then falls to the TH1 script code on the
198198
View Ticket Page to query the TICKETCHNG table and extract and format
199199
the various comments in time stamp order.
200200
--- www/tickets.wiki
+++ www/tickets.wiki
@@ -27,11 +27,11 @@
27 that key, or the value may be appended to the prior value.
28
29 <h2>2.0 Ticket Tables</h2>
30
31 The low-level artifact format for ticket content is tedious and
32 cumbersome to access in real time. To facility reporting and display
33 of tickets, the low-level artifact information is collected and
34 summarized in a pair of SQL tables in each local repository. Display
35 and reporting of tickets is accomplished by querying these two tables.
36
37 Note that only the low-level ticket change artifacts are synced. The
@@ -191,9 +191,9 @@
191 comment according to its chosen format. Hence, Fossil was enhanced to
192 support the "new-style" tickets.
193
194 The TICKETCHNG table was added to support new-style tickets. In the new
195 style, comment text is stored with the "icomment" (for "Incremental Comment")
196 key and appears separately, and with its on mimetype, in multiple rows
197 of the TICKETCHNG table. It then falls to the TH1 script code on the
198 View Ticket Page to query the TICKETCHNG table and extract and format
199 the various comments in time stamp order.
200
--- www/tickets.wiki
+++ www/tickets.wiki
@@ -27,11 +27,11 @@
27 that key, or the value may be appended to the prior value.
28
29 <h2>2.0 Ticket Tables</h2>
30
31 The low-level artifact format for ticket content is tedious and
32 cumbersome to access in real time. To facilitate reporting and display
33 of tickets, the low-level artifact information is collected and
34 summarized in a pair of SQL tables in each local repository. Display
35 and reporting of tickets is accomplished by querying these two tables.
36
37 Note that only the low-level ticket change artifacts are synced. The
@@ -191,9 +191,9 @@
191 comment according to its chosen format. Hence, Fossil was enhanced to
192 support the "new-style" tickets.
193
194 The TICKETCHNG table was added to support new-style tickets. In the new
195 style, comment text is stored with the "icomment" (for "Incremental Comment")
196 key and appears separately, and with its own mimetype, in multiple rows
197 of the TICKETCHNG table. It then falls to the TH1 script code on the
198 View Ticket Page to query the TICKETCHNG table and extract and format
199 the various comments in time stamp order.
200
+2 -2
--- www/unvers.wiki
+++ www/unvers.wiki
@@ -53,12 +53,12 @@
5353
[/help?cmd=push|fossil push] or [/help?cmd=pull|fossil pull].
5454
The "-u" option is only available on "sync" and "clone".
5555
A rough equivalent of an unversioned pull would be the
5656
[/help?cmd=unversioned|fossil unversioned revert] command. The
5757
"unversioned revert"
58
-command causes the unversioned content on the local repository to overwritten
59
-by the unversioned content found on the remote repository.
58
+command causes the unversioned content on the local repository to be
59
+overwritten by the unversioned content found on the remote repository.
6060
6161
Beware that because unversioned file sync is an uncommonly dangerous
6262
capability — there being no history to revert to in the case of human
6363
error — even the all-powerful Fossil "setup" user does not get
6464
unversioned file sync capability by default. See
6565
--- www/unvers.wiki
+++ www/unvers.wiki
@@ -53,12 +53,12 @@
53 [/help?cmd=push|fossil push] or [/help?cmd=pull|fossil pull].
54 The "-u" option is only available on "sync" and "clone".
55 A rough equivalent of an unversioned pull would be the
56 [/help?cmd=unversioned|fossil unversioned revert] command. The
57 "unversioned revert"
58 command causes the unversioned content on the local repository to overwritten
59 by the unversioned content found on the remote repository.
60
61 Beware that because unversioned file sync is an uncommonly dangerous
62 capability — there being no history to revert to in the case of human
63 error — even the all-powerful Fossil "setup" user does not get
64 unversioned file sync capability by default. See
65
--- www/unvers.wiki
+++ www/unvers.wiki
@@ -53,12 +53,12 @@
53 [/help?cmd=push|fossil push] or [/help?cmd=pull|fossil pull].
54 The "-u" option is only available on "sync" and "clone".
55 A rough equivalent of an unversioned pull would be the
56 [/help?cmd=unversioned|fossil unversioned revert] command. The
57 "unversioned revert"
58 command causes the unversioned content on the local repository to be
59 overwritten by the unversioned content found on the remote repository.
60
61 Beware that because unversioned file sync is an uncommonly dangerous
62 capability — there being no history to revert to in the case of human
63 error — even the all-powerful Fossil "setup" user does not get
64 unversioned file sync capability by default. See
65
--- www/userlinks.wiki
+++ www/userlinks.wiki
@@ -23,11 +23,11 @@
2323
* Fossil contains a [./wikitheory.wiki | built-in wiki].
2424
* An [./event.wiki | Event] is a special kind of wiki page associated
2525
with a point in time rather than a name.
2626
* [./settings.wiki | Settings] control the behaviour of Fossil.
2727
* [./ssl.wiki | Use SSL] to encrypt communication with the server.
28
- * The [https://fossil-scm.org/forum|Fossil forum] is, as of mid-2018,
28
+ * The [https://fossil-scm.org/forum|Fossil forum] is, as of late-2024,
2929
the project's central communication channel. The
3030
[https://www.mail-archive.com/[email protected]
3131
| read-only mailing list archives] house discussions spanning Fossil's
3232
first decade.
3333
* [./stats.wiki | Performance statistics] taken from real-world projects
3434
--- www/userlinks.wiki
+++ www/userlinks.wiki
@@ -23,11 +23,11 @@
23 * Fossil contains a [./wikitheory.wiki | built-in wiki].
24 * An [./event.wiki | Event] is a special kind of wiki page associated
25 with a point in time rather than a name.
26 * [./settings.wiki | Settings] control the behaviour of Fossil.
27 * [./ssl.wiki | Use SSL] to encrypt communication with the server.
28 * The [https://fossil-scm.org/forum|Fossil forum] is, as of mid-2018,
29 the project's central communication channel. The
30 [https://www.mail-archive.com/[email protected]
31 | read-only mailing list archives] house discussions spanning Fossil's
32 first decade.
33 * [./stats.wiki | Performance statistics] taken from real-world projects
34
--- www/userlinks.wiki
+++ www/userlinks.wiki
@@ -23,11 +23,11 @@
23 * Fossil contains a [./wikitheory.wiki | built-in wiki].
24 * An [./event.wiki | Event] is a special kind of wiki page associated
25 with a point in time rather than a name.
26 * [./settings.wiki | Settings] control the behaviour of Fossil.
27 * [./ssl.wiki | Use SSL] to encrypt communication with the server.
28 * The [https://fossil-scm.org/forum|Fossil forum] is, as of late-2024,
29 the project's central communication channel. The
30 [https://www.mail-archive.com/[email protected]
31 | read-only mailing list archives] house discussions spanning Fossil's
32 first decade.
33 * [./stats.wiki | Performance statistics] taken from real-world projects
34
+5 -5
--- www/webui.wiki
+++ www/webui.wiki
@@ -116,15 +116,15 @@
116116
The "Files" link on the menu allows you to browse through the <b>file
117117
hierarchy</b> of the project and to view complete changes histories on
118118
individual files, with hyperlinks to the check-ins that made those
119119
changes, and with diffs and annotated diffs between versions.
120120
121
-The web interface supports [./embeddeddoc.wiki | embedded documentation].
122
-Embedded documentation is documentation files (usually in wiki format)
123
-that are checked into project as part of the source tree. Such files
124
-can be viewed as if they were ordinary web pages. This document that
125
-you are now reading is an example of embedded documentation.
121
+The web interface supports [./embeddeddoc.wiki | embedded documentation]
122
+files (usually in wiki format) that are checked into the project as
123
+part of the source tree. Such files can be viewed as if they were
124
+ordinary web pages. This document that you are now reading is an
125
+example of embedded documentation.
126126
127127
<h2>Customizing The Web Interface Appearance</h2>
128128
129129
Users with appropriate permissions can customize the look and feel of
130130
the web interface using the "Admin" link on the main menu of the web
131131
--- www/webui.wiki
+++ www/webui.wiki
@@ -116,15 +116,15 @@
116 The "Files" link on the menu allows you to browse through the <b>file
117 hierarchy</b> of the project and to view complete changes histories on
118 individual files, with hyperlinks to the check-ins that made those
119 changes, and with diffs and annotated diffs between versions.
120
121 The web interface supports [./embeddeddoc.wiki | embedded documentation].
122 Embedded documentation is documentation files (usually in wiki format)
123 that are checked into project as part of the source tree. Such files
124 can be viewed as if they were ordinary web pages. This document that
125 you are now reading is an example of embedded documentation.
126
127 <h2>Customizing The Web Interface Appearance</h2>
128
129 Users with appropriate permissions can customize the look and feel of
130 the web interface using the "Admin" link on the main menu of the web
131
--- www/webui.wiki
+++ www/webui.wiki
@@ -116,15 +116,15 @@
116 The "Files" link on the menu allows you to browse through the <b>file
117 hierarchy</b> of the project and to view complete changes histories on
118 individual files, with hyperlinks to the check-ins that made those
119 changes, and with diffs and annotated diffs between versions.
120
121 The web interface supports [./embeddeddoc.wiki | embedded documentation]
122 files (usually in wiki format) that are checked into the project as
123 part of the source tree. Such files can be viewed as if they were
124 ordinary web pages. This document that you are now reading is an
125 example of embedded documentation.
126
127 <h2>Customizing The Web Interface Appearance</h2>
128
129 Users with appropriate permissions can customize the look and feel of
130 the web interface using the "Admin" link on the main menu of the web
131
--- www/whyallinone.md
+++ www/whyallinone.md
@@ -141,11 +141,11 @@
141141
142142
7. Hosting all of these elements within a single service gives a
143143
consistent look-and-feel across all aspects of the project.
144144
145145
Skinning independent software packages’ web interfaces to make
146
- them appear unified is more work than skinning everything once, as
146
+ them appear unified is more work than [skinning] everything once, as
147147
in Fossil, and even then, you can’t make independently-developed
148148
software look like it was produced by a single entity without
149149
resorting to heroic levels of customization. If you use a separate
150150
DVCS web front end, chat system, forum manager, documentation
151151
system, ticket tracker, and so on, you are likely to be relegated
@@ -217,16 +217,19 @@
217217
configuration change to its [role-based access control system](./caps/).
218218
When you’re ready to turn these additional features on, you can do so
219219
with a few mouse clicks.
220220
221221
Because Fossil is web-native out of the box, if you’ve delegated these
222
-features to outside systems to flesh out Git’s DVCS-only nature, Fossil
223
-can link out to these systems, and they back into Fossil, letting you
224
-use Fossil in the same DVCS-only mode.
222
+features to outside systems to flesh out Git’s DVCS-only nature, you are
223
+free to do the same with Fossil. One of the many things the [skinning]
224
+facility allows is replacing the built-in links to the wiki, forum,
225
+ticket system, etc. with links to external systems. How easy those
226
+systems make it to link back into Fossil is up to their developers.
225227
226228
[Discord]: https://discord.com/
227229
[edoc]: ./embeddeddoc.wiki
228230
[Jira]: https://www.atlassian.com/software/jira
229231
[MediaWiki]: https://www.mediawiki.org/
232
+[skinning]: ./customskin.md
230233
[Sphinx]: https://www.sphinx-doc.org/en/master/
231234
[SSO]: https://en.wikipedia.org/wiki/Single_sign-on
232235
[srckl]: https://www.sqlite.org/src/ext/checklist/top/index
233236
--- www/whyallinone.md
+++ www/whyallinone.md
@@ -141,11 +141,11 @@
141
142 7. Hosting all of these elements within a single service gives a
143 consistent look-and-feel across all aspects of the project.
144
145 Skinning independent software packages’ web interfaces to make
146 them appear unified is more work than skinning everything once, as
147 in Fossil, and even then, you can’t make independently-developed
148 software look like it was produced by a single entity without
149 resorting to heroic levels of customization. If you use a separate
150 DVCS web front end, chat system, forum manager, documentation
151 system, ticket tracker, and so on, you are likely to be relegated
@@ -217,16 +217,19 @@
217 configuration change to its [role-based access control system](./caps/).
218 When you’re ready to turn these additional features on, you can do so
219 with a few mouse clicks.
220
221 Because Fossil is web-native out of the box, if you’ve delegated these
222 features to outside systems to flesh out Git’s DVCS-only nature, Fossil
223 can link out to these systems, and they back into Fossil, letting you
224 use Fossil in the same DVCS-only mode.
 
 
225
226 [Discord]: https://discord.com/
227 [edoc]: ./embeddeddoc.wiki
228 [Jira]: https://www.atlassian.com/software/jira
229 [MediaWiki]: https://www.mediawiki.org/
 
230 [Sphinx]: https://www.sphinx-doc.org/en/master/
231 [SSO]: https://en.wikipedia.org/wiki/Single_sign-on
232 [srckl]: https://www.sqlite.org/src/ext/checklist/top/index
233
--- www/whyallinone.md
+++ www/whyallinone.md
@@ -141,11 +141,11 @@
141
142 7. Hosting all of these elements within a single service gives a
143 consistent look-and-feel across all aspects of the project.
144
145 Skinning independent software packages’ web interfaces to make
146 them appear unified is more work than [skinning] everything once, as
147 in Fossil, and even then, you can’t make independently-developed
148 software look like it was produced by a single entity without
149 resorting to heroic levels of customization. If you use a separate
150 DVCS web front end, chat system, forum manager, documentation
151 system, ticket tracker, and so on, you are likely to be relegated
@@ -217,16 +217,19 @@
217 configuration change to its [role-based access control system](./caps/).
218 When you’re ready to turn these additional features on, you can do so
219 with a few mouse clicks.
220
221 Because Fossil is web-native out of the box, if you’ve delegated these
222 features to outside systems to flesh out Git’s DVCS-only nature, you are
223 free to do the same with Fossil. One of the many things the [skinning]
224 facility allows is replacing the built-in links to the wiki, forum,
225 ticket system, etc. with links to external systems. How easy those
226 systems make it to link back into Fossil is up to their developers.
227
228 [Discord]: https://discord.com/
229 [edoc]: ./embeddeddoc.wiki
230 [Jira]: https://www.atlassian.com/software/jira
231 [MediaWiki]: https://www.mediawiki.org/
232 [skinning]: ./customskin.md
233 [Sphinx]: https://www.sphinx-doc.org/en/master/
234 [SSO]: https://en.wikipedia.org/wiki/Single_sign-on
235 [srckl]: https://www.sqlite.org/src/ext/checklist/top/index
236
--- www/wikitheory.wiki
+++ www/wikitheory.wiki
@@ -84,7 +84,7 @@
8484
wiki page at the top of the timeline
8585
* [/info/19c60b7fc9e2] shows the text of the
8686
[/wiki?name=checkin/19c60b7fc9e2400e56a6f938bbad0e34ca746ca2eabdecac10945539f1f5e8c6&p|checkin/19c60b7fc9e2...]
8787
wiki page in the "About" section.
8888
89
-This special wiki pages are very useful for recording historical
89
+These special wiki pages are very useful for recording historical
9090
notes.
9191
--- www/wikitheory.wiki
+++ www/wikitheory.wiki
@@ -84,7 +84,7 @@
84 wiki page at the top of the timeline
85 * [/info/19c60b7fc9e2] shows the text of the
86 [/wiki?name=checkin/19c60b7fc9e2400e56a6f938bbad0e34ca746ca2eabdecac10945539f1f5e8c6&p|checkin/19c60b7fc9e2...]
87 wiki page in the "About" section.
88
89 This special wiki pages are very useful for recording historical
90 notes.
91
--- www/wikitheory.wiki
+++ www/wikitheory.wiki
@@ -84,7 +84,7 @@
84 wiki page at the top of the timeline
85 * [/info/19c60b7fc9e2] shows the text of the
86 [/wiki?name=checkin/19c60b7fc9e2400e56a6f938bbad0e34ca746ca2eabdecac10945539f1f5e8c6&p|checkin/19c60b7fc9e2...]
87 wiki page in the "About" section.
88
89 These special wiki pages are very useful for recording historical
90 notes.
91

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button