Fossil SCM

Merge from trunk.

jan 2016-02-04 15:22 UTC jan-manifest-tags merge
Commit ea7f3297046747a1ba92630cdd75304e854d594f
--- Makefile.in
+++ Makefile.in
@@ -40,10 +40,11 @@
4040
4141
LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
4242
TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H
4343
INSTALLDIR = $(DESTDIR)@prefix@/bin
4444
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
45
+USE_LINENOISE = @USE_LINENOISE@
4546
FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@
4647
4748
include $(SRCDIR)/main.mk
4849
4950
distclean: clean
5051
--- Makefile.in
+++ Makefile.in
@@ -40,10 +40,11 @@
40
41 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
42 TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H
43 INSTALLDIR = $(DESTDIR)@prefix@/bin
44 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
 
45 FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@
46
47 include $(SRCDIR)/main.mk
48
49 distclean: clean
50
--- Makefile.in
+++ Makefile.in
@@ -40,10 +40,11 @@
40
41 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
42 TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H
43 INSTALLDIR = $(DESTDIR)@prefix@/bin
44 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
45 USE_LINENOISE = @USE_LINENOISE@
46 FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@
47
48 include $(SRCDIR)/main.mk
49
50 distclean: clean
51
+237 -93
--- auto.def
+++ auto.def
@@ -1,14 +1,15 @@
11
# System autoconfiguration. Try: ./configure --help
22
33
use cc cc-lib
44
55
options {
6
- with-openssl:path|auto|none
7
- => {Look for OpenSSL in the given path, or auto or none}
6
+ with-openssl:path|auto|tree|none
7
+ => {Look for OpenSSL in the given path, automatically, in the source tree, or none}
88
with-miniz=0 => {Use miniz from the source tree}
9
- with-zlib:path => {Look for zlib in the given path}
9
+ with-zlib:path|auto|tree
10
+ => {Look for zlib in the given path, automatically, or in the source tree}
1011
with-exec-rel-paths=0
1112
=> {Enable relative paths for external diff/gdiff}
1213
with-legacy-mv-rm=0 => {Enable legacy behavior for mv/rm (skip checkout files)}
1314
with-th1-docs=0 => {Enable TH1 for embedded documentation pages}
1415
with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages}
@@ -35,10 +36,47 @@
3536
cc-check-progs tclsh
3637
3738
define EXTRA_CFLAGS ""
3839
define EXTRA_LDFLAGS ""
3940
define USE_SYSTEM_SQLITE 0
41
+define USE_LINENOISE 0
42
+
43
+# This procedure is a customized version of "cc-check-function-in-lib",
44
+# that does not modify the LIBS variable. Its use prevents prematurely
45
+# pulling in libraries that will be added later anyhow (e.g. "-ldl").
46
+proc check-function-in-lib {function libs {otherlibs {}}} {
47
+ if {[string length $otherlibs]} {
48
+ msg-checking "Checking for $function in $libs with $otherlibs..."
49
+ } else {
50
+ msg-checking "Checking for $function in $libs..."
51
+ }
52
+ set found 0
53
+ cc-with [list -libs $otherlibs] {
54
+ if {[cctest_function $function]} {
55
+ msg-result "none needed"
56
+ define lib_$function ""
57
+ incr found
58
+ } else {
59
+ foreach lib $libs {
60
+ cc-with [list -libs -l$lib] {
61
+ if {[cctest_function $function]} {
62
+ msg-result -l$lib
63
+ define lib_$function -l$lib
64
+ incr found
65
+ break
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ if {$found} {
72
+ define [feature-define-name $function]
73
+ } else {
74
+ msg-result "no"
75
+ }
76
+ return $found
77
+}
4078
4179
if {![opt-bool internal-sqlite]} {
4280
proc find_internal_sqlite {} {
4381
4482
# On some systems (slackware), libsqlite3 requires -ldl to link. So
@@ -51,27 +89,43 @@
5189
# Locate the system SQLite by searching for sqlite3_open(). Then check
5290
# if sqlite3_strglob() can be found as well. If we can find open() but
5391
# not strglob(), then the system SQLite is too old to link against
5492
# fossil.
5593
#
56
- if {[cc-check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
57
- if {![cc-check-function-in-lib sqlite3_malloc64 sqlite3 $extralibs]} {
94
+ if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
95
+ if {![check-function-in-lib sqlite3_malloc64 sqlite3 $extralibs]} {
5896
user-error "system sqlite3 too old (require >= 3.8.7)"
5997
}
6098
6199
# Success. Update symbols and return.
62100
#
63101
define USE_SYSTEM_SQLITE 1
102
+ define-append LIBS -lsqlite3
64103
define-append LIBS $extralibs
65104
return
66105
}
67106
}
68107
user-error "system sqlite3 not found"
69108
}
70109
71110
find_internal_sqlite
72111
}
112
+
113
+proc is_mingw {} {
114
+ return [string match *mingw* [get-define host]]
115
+}
116
+
117
+if {[is_mingw]} {
118
+ define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
119
+ define-append LIBS -lkernel32 -lws2_32
120
+} else {
121
+ #
122
+ # NOTE: All platforms except MinGW should use the linenoise
123
+ # package. It is currently unsupported on Win32.
124
+ #
125
+ define USE_LINENOISE 1
126
+}
73127
74128
if {[string match *-solaris* [get-define host]]} {
75129
define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__}
76130
}
77131
@@ -125,26 +179,169 @@
125179
msg-result "Trying to link statically"
126180
} else {
127181
define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
128182
define FOSSIL_DYNAMIC_BUILD
129183
}
184
+
185
+# Helper for OpenSSL checking
186
+proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto}}} {
187
+ msg-checking "Checking for $msg..."
188
+ set rc 0
189
+ if {[is_mingw]} {
190
+ lappend libs -lgdi32 -lwsock32
191
+ }
192
+ if {[info exists ::zlib_lib]} {
193
+ lappend libs $::zlib_lib
194
+ }
195
+ msg-quiet cc-with [list -cflags $cflags -libs $libs] {
196
+ if {[cc-check-includes openssl/ssl.h] && \
197
+ [cc-check-functions SSL_new]} {
198
+ incr rc
199
+ }
200
+ }
201
+ if {!$rc && ![is_mingw]} {
202
+ # On some systems, OpenSSL appears to require -ldl to link.
203
+ lappend libs -ldl
204
+ msg-quiet cc-with [list -cflags $cflags -libs $libs] {
205
+ if {[cc-check-includes openssl/ssl.h] && \
206
+ [cc-check-functions SSL_new]} {
207
+ incr rc
208
+ }
209
+ }
210
+ }
211
+ if {$rc} {
212
+ msg-result "ok"
213
+ return 1
214
+ } else {
215
+ msg-result "no"
216
+ return 0
217
+ }
218
+}
219
+
220
+if {[opt-bool with-miniz]} {
221
+ define FOSSIL_ENABLE_MINIZ 1
222
+ msg-result "Using miniz for compression"
223
+} else {
224
+ # Check for zlib, using the given location if specified
225
+ set zlibpath [opt-val with-zlib]
226
+ if {$zlibpath eq "tree"} {
227
+ set zlibdir [file dirname $autosetup(dir)]/compat/zlib
228
+ if {![file isdirectory $zlibdir]} {
229
+ user-error "The zlib in source tree directory does not exist"
230
+ }
231
+ cc-with [list -cflags "-I$zlibdir -L$zlibdir"]
232
+ define-append EXTRA_CFLAGS -I$zlibdir
233
+ define-append LIBS $zlibdir/libz.a
234
+ set ::zlib_lib $zlibdir/libz.a
235
+ msg-result "Using zlib in source tree"
236
+ } else {
237
+ if {$zlibpath ni {auto ""}} {
238
+ cc-with [list -cflags "-I$zlibpath -L$zlibpath"]
239
+ define-append EXTRA_CFLAGS -I$zlibpath
240
+ define-append EXTRA_LDFLAGS -L$zlibpath
241
+ msg-result "Using zlib from $zlibpath"
242
+ }
243
+ if {![cc-check-includes zlib.h] || ![check-function-in-lib inflateEnd z]} {
244
+ user-error "zlib not found please install it or specify the location with --with-zlib"
245
+ }
246
+ set ::zlib_lib -lz
247
+ }
248
+}
249
+
250
+set ssldirs [opt-val with-openssl]
251
+if {$ssldirs ne "none"} {
252
+ if {[opt-bool with-miniz]} {
253
+ user-error "The --with-miniz option is incompatible with OpenSSL"
254
+ }
255
+ set found 0
256
+ if {$ssldirs eq "tree"} {
257
+ set ssldir [file dirname $autosetup(dir)]/compat/openssl
258
+ if {![file isdirectory $ssldir]} {
259
+ user-error "The OpenSSL in source tree directory does not exist"
260
+ }
261
+ set msg "ssl in $ssldir"
262
+ set cflags "-I$ssldir/include"
263
+ set ldflags "-L$ssldir"
264
+ set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a"
265
+ set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs]
266
+ } else {
267
+ if {$ssldirs in {auto ""}} {
268
+ catch {
269
+ set cflags [exec pkg-config openssl --cflags-only-I]
270
+ set ldflags [exec pkg-config openssl --libs-only-L]
271
+ set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
272
+ } msg
273
+ if {!$found} {
274
+ set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
275
+ }
276
+ }
277
+ if {!$found} {
278
+ foreach dir $ssldirs {
279
+ if {$dir eq ""} {
280
+ set msg "system ssl"
281
+ set cflags ""
282
+ set ldflags ""
283
+ } else {
284
+ set msg "ssl in $dir"
285
+ set cflags "-I$dir/include"
286
+ set ldflags "-L$dir/lib"
287
+ }
288
+ if {[check-for-openssl $msg "$cflags $ldflags"]} {
289
+ incr found
290
+ break
291
+ }
292
+ }
293
+ }
294
+ }
295
+ if {$found} {
296
+ define FOSSIL_ENABLE_SSL
297
+ define-append EXTRA_CFLAGS $cflags
298
+ define-append EXTRA_LDFLAGS $ldflags
299
+ if {[info exists ssllibs]} {
300
+ define-append LIBS $ssllibs
301
+ } else {
302
+ define-append LIBS -lssl -lcrypto
303
+ }
304
+ if {[info exists ::zlib_lib]} {
305
+ define-append LIBS $::zlib_lib
306
+ }
307
+ if {[is_mingw]} {
308
+ define-append LIBS -lgdi32 -lwsock32
309
+ }
310
+ msg-result "HTTPS support enabled"
311
+
312
+ # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
313
+ if {[string match *-darwin* [get-define host]]} {
314
+ if {[cctest -cflags {-Wdeprecated-declarations}]} {
315
+ define-append EXTRA_CFLAGS -Wdeprecated-declarations
316
+ }
317
+ }
318
+ } else {
319
+ user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
320
+ }
321
+} else {
322
+ if {[info exists ::zlib_lib]} {
323
+ define-append LIBS $::zlib_lib
324
+ }
325
+}
130326
131327
set tclpath [opt-val with-tcl]
132328
if {$tclpath ne ""} {
133329
set tclprivatestubs [opt-bool with-tcl-private-stubs]
134330
# Note parse-tclconfig-sh is in autosetup/local.tcl
135331
if {$tclpath eq "1"} {
332
+ set tcldir [file dirname $autosetup(dir)]/compat/tcl-8.6
136333
if {$tclprivatestubs} {
137
- set tclconfig(TCL_INCLUDE_SPEC) -Icompat/tcl-8.6/generic
334
+ set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
138335
set tclconfig(TCL_VERSION) {Private Stubs}
139336
set tclconfig(TCL_PATCH_LEVEL) {}
140
- set tclconfig(TCL_PREFIX) {compat/tcl-8.6}
337
+ set tclconfig(TCL_PREFIX) $tcldir
141338
set tclconfig(TCL_LD_FLAGS) { }
142339
} else {
143340
# Use the system Tcl. Look in some likely places.
144341
array set tclconfig [parse-tclconfig-sh \
145
- compat/tcl-8.6/unix compat/tcl-8.6/win \
342
+ $tcldir/unix $tcldir/win \
146343
/usr /usr/local /usr/share /opt/local]
147344
set msg "on your system"
148345
}
149346
} else {
150347
array set tclconfig [parse-tclconfig-sh $tclpath]
@@ -192,10 +389,27 @@
192389
if {[cc-check-functions Tcl_CreateInterp]} {
193390
set foundtcl 1
194391
}
195392
}
196393
}
394
+ }
395
+ if {!$foundtcl && ![string match *-lpthread* $libs]} {
396
+ # On some systems, TCL_LIB_SPEC appears to be missing
397
+ # "-lpthread". Try adding it.
398
+ msg-result "Adding \"-lpthread\" and retrying for Tcl..."
399
+ set libs "$libs -lpthread"
400
+ cc-with [list -cflags $cflags -libs $libs] {
401
+ if {$tclstubs} {
402
+ if {[cc-check-functions Tcl_InitStubs]} {
403
+ set foundtcl 1
404
+ }
405
+ } else {
406
+ if {[cc-check-functions Tcl_CreateInterp]} {
407
+ set foundtcl 1
408
+ }
409
+ }
410
+ }
197411
}
198412
if {!$foundtcl} {
199413
if {$tclstubs} {
200414
user-error "Cannot find a usable Tcl stubs library $msg"
201415
} else {
@@ -207,103 +421,33 @@
207421
msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
208422
if {!$tclprivatestubs} {
209423
define-append LIBS $libs
210424
}
211425
define-append EXTRA_CFLAGS $cflags
426
+ if {[info exists zlibpath] && $zlibpath eq "tree"} {
427
+ #
428
+ # NOTE: When using zlib in the source tree, prevent Tcl from
429
+ # pulling in the system one.
430
+ #
431
+ set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
432
+ $tclconfig(TCL_LD_FLAGS)]
433
+ }
434
+ #
435
+ # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
436
+ # be checked for near the bottom of this file.
437
+ #
438
+ set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
439
+ $tclconfig(TCL_LD_FLAGS)]
212440
define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
213441
define FOSSIL_ENABLE_TCL
214442
}
215443
216
-# Helper for OpenSSL checking
217
-proc check-for-openssl {msg {cflags {}}} {
218
- msg-checking "Checking for $msg..."
219
- set rc 0
220
- msg-quiet cc-with [list -cflags $cflags -libs {-lssl -lcrypto}] {
221
- if {[cc-check-includes openssl/ssl.h] && [cc-check-functions SSL_new]} {
222
- incr rc
223
- }
224
- }
225
- if {$rc} {
226
- msg-result "ok"
227
- return 1
228
- } else {
229
- msg-result "no"
230
- return 0
231
- }
232
-}
233
-
234
-set ssldirs [opt-val with-openssl]
235
-if {$ssldirs ne "none"} {
236
- set found 0
237
- if {$ssldirs in {auto ""}} {
238
- catch {
239
- set cflags [exec pkg-config openssl --cflags-only-I]
240
- set ldflags [exec pkg-config openssl --libs-only-L]
241
-
242
- set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
243
- } msg
244
- if {!$found} {
245
- set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
246
- }
247
- }
248
- if {!$found} {
249
- foreach dir $ssldirs {
250
- if {$dir eq ""} {
251
- set msg "system ssl"
252
- set cflags ""
253
- set ldflags ""
254
- } else {
255
- set msg "ssl in $dir"
256
- set cflags "-I$dir/include"
257
- set ldflags "-L$dir/lib"
258
- }
259
- if {[check-for-openssl $msg "$cflags $ldflags"]} {
260
- incr found
261
- break
262
- }
263
- }
264
- }
265
- if {$found} {
266
- define FOSSIL_ENABLE_SSL
267
- define-append EXTRA_CFLAGS $cflags
268
- define-append EXTRA_LDFLAGS $ldflags
269
- define-append LIBS -lssl -lcrypto
270
- msg-result "HTTPS support enabled"
271
-
272
- # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
273
- if {[string match *-darwin* [get-define host]]} {
274
- if {[cctest -cflags {-Wdeprecated-declarations}]} {
275
- define-append EXTRA_CFLAGS -Wdeprecated-declarations
276
- }
277
- }
278
- } else {
279
- user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
280
- }
281
-}
282
-
283
-if {[opt-bool with-miniz]} {
284
- define FOSSIL_ENABLE_MINIZ 1
285
- msg-result "Using miniz for compression"
286
-} else {
287
- # Check for zlib, using the given location if specified
288
- set zlibpath [opt-val with-zlib]
289
- if {$zlibpath ne ""} {
290
- cc-with [list -cflags "-I$zlibpath -L$zlibpath"]
291
- define-append EXTRA_CFLAGS -I$zlibpath
292
- define-append EXTRA_LDFLAGS -L$zlibpath
293
- msg-result "Using zlib from $zlibpath"
294
- }
295
- if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
296
- user-error "zlib not found please install it or specify the location with --with-zlib"
297
- }
298
-}
299
-
300444
# Network functions require libraries on some systems
301445
cc-check-function-in-lib gethostbyname nsl
302446
if {![cc-check-function-in-lib socket {socket network}]} {
303447
# Last resort, may be Windows
304
- if {[string match *mingw* [get-define host]]} {
448
+ if {[is_mingw]} {
305449
define-append LIBS -lwsock32
306450
}
307451
}
308452
cc-check-function-in-lib iconv iconv
309453
cc-check-functions utime
310454
--- auto.def
+++ auto.def
@@ -1,14 +1,15 @@
1 # System autoconfiguration. Try: ./configure --help
2
3 use cc cc-lib
4
5 options {
6 with-openssl:path|auto|none
7 => {Look for OpenSSL in the given path, or auto or none}
8 with-miniz=0 => {Use miniz from the source tree}
9 with-zlib:path => {Look for zlib in the given path}
 
10 with-exec-rel-paths=0
11 => {Enable relative paths for external diff/gdiff}
12 with-legacy-mv-rm=0 => {Enable legacy behavior for mv/rm (skip checkout files)}
13 with-th1-docs=0 => {Enable TH1 for embedded documentation pages}
14 with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages}
@@ -35,10 +36,47 @@
35 cc-check-progs tclsh
36
37 define EXTRA_CFLAGS ""
38 define EXTRA_LDFLAGS ""
39 define USE_SYSTEM_SQLITE 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
41 if {![opt-bool internal-sqlite]} {
42 proc find_internal_sqlite {} {
43
44 # On some systems (slackware), libsqlite3 requires -ldl to link. So
@@ -51,27 +89,43 @@
51 # Locate the system SQLite by searching for sqlite3_open(). Then check
52 # if sqlite3_strglob() can be found as well. If we can find open() but
53 # not strglob(), then the system SQLite is too old to link against
54 # fossil.
55 #
56 if {[cc-check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
57 if {![cc-check-function-in-lib sqlite3_malloc64 sqlite3 $extralibs]} {
58 user-error "system sqlite3 too old (require >= 3.8.7)"
59 }
60
61 # Success. Update symbols and return.
62 #
63 define USE_SYSTEM_SQLITE 1
 
64 define-append LIBS $extralibs
65 return
66 }
67 }
68 user-error "system sqlite3 not found"
69 }
70
71 find_internal_sqlite
72 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
74 if {[string match *-solaris* [get-define host]]} {
75 define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__}
76 }
77
@@ -125,26 +179,169 @@
125 msg-result "Trying to link statically"
126 } else {
127 define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
128 define FOSSIL_DYNAMIC_BUILD
129 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
131 set tclpath [opt-val with-tcl]
132 if {$tclpath ne ""} {
133 set tclprivatestubs [opt-bool with-tcl-private-stubs]
134 # Note parse-tclconfig-sh is in autosetup/local.tcl
135 if {$tclpath eq "1"} {
 
136 if {$tclprivatestubs} {
137 set tclconfig(TCL_INCLUDE_SPEC) -Icompat/tcl-8.6/generic
138 set tclconfig(TCL_VERSION) {Private Stubs}
139 set tclconfig(TCL_PATCH_LEVEL) {}
140 set tclconfig(TCL_PREFIX) {compat/tcl-8.6}
141 set tclconfig(TCL_LD_FLAGS) { }
142 } else {
143 # Use the system Tcl. Look in some likely places.
144 array set tclconfig [parse-tclconfig-sh \
145 compat/tcl-8.6/unix compat/tcl-8.6/win \
146 /usr /usr/local /usr/share /opt/local]
147 set msg "on your system"
148 }
149 } else {
150 array set tclconfig [parse-tclconfig-sh $tclpath]
@@ -192,10 +389,27 @@
192 if {[cc-check-functions Tcl_CreateInterp]} {
193 set foundtcl 1
194 }
195 }
196 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197 }
198 if {!$foundtcl} {
199 if {$tclstubs} {
200 user-error "Cannot find a usable Tcl stubs library $msg"
201 } else {
@@ -207,103 +421,33 @@
207 msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
208 if {!$tclprivatestubs} {
209 define-append LIBS $libs
210 }
211 define-append EXTRA_CFLAGS $cflags
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212 define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
213 define FOSSIL_ENABLE_TCL
214 }
215
216 # Helper for OpenSSL checking
217 proc check-for-openssl {msg {cflags {}}} {
218 msg-checking "Checking for $msg..."
219 set rc 0
220 msg-quiet cc-with [list -cflags $cflags -libs {-lssl -lcrypto}] {
221 if {[cc-check-includes openssl/ssl.h] && [cc-check-functions SSL_new]} {
222 incr rc
223 }
224 }
225 if {$rc} {
226 msg-result "ok"
227 return 1
228 } else {
229 msg-result "no"
230 return 0
231 }
232 }
233
234 set ssldirs [opt-val with-openssl]
235 if {$ssldirs ne "none"} {
236 set found 0
237 if {$ssldirs in {auto ""}} {
238 catch {
239 set cflags [exec pkg-config openssl --cflags-only-I]
240 set ldflags [exec pkg-config openssl --libs-only-L]
241
242 set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
243 } msg
244 if {!$found} {
245 set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
246 }
247 }
248 if {!$found} {
249 foreach dir $ssldirs {
250 if {$dir eq ""} {
251 set msg "system ssl"
252 set cflags ""
253 set ldflags ""
254 } else {
255 set msg "ssl in $dir"
256 set cflags "-I$dir/include"
257 set ldflags "-L$dir/lib"
258 }
259 if {[check-for-openssl $msg "$cflags $ldflags"]} {
260 incr found
261 break
262 }
263 }
264 }
265 if {$found} {
266 define FOSSIL_ENABLE_SSL
267 define-append EXTRA_CFLAGS $cflags
268 define-append EXTRA_LDFLAGS $ldflags
269 define-append LIBS -lssl -lcrypto
270 msg-result "HTTPS support enabled"
271
272 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
273 if {[string match *-darwin* [get-define host]]} {
274 if {[cctest -cflags {-Wdeprecated-declarations}]} {
275 define-append EXTRA_CFLAGS -Wdeprecated-declarations
276 }
277 }
278 } else {
279 user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
280 }
281 }
282
283 if {[opt-bool with-miniz]} {
284 define FOSSIL_ENABLE_MINIZ 1
285 msg-result "Using miniz for compression"
286 } else {
287 # Check for zlib, using the given location if specified
288 set zlibpath [opt-val with-zlib]
289 if {$zlibpath ne ""} {
290 cc-with [list -cflags "-I$zlibpath -L$zlibpath"]
291 define-append EXTRA_CFLAGS -I$zlibpath
292 define-append EXTRA_LDFLAGS -L$zlibpath
293 msg-result "Using zlib from $zlibpath"
294 }
295 if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
296 user-error "zlib not found please install it or specify the location with --with-zlib"
297 }
298 }
299
300 # Network functions require libraries on some systems
301 cc-check-function-in-lib gethostbyname nsl
302 if {![cc-check-function-in-lib socket {socket network}]} {
303 # Last resort, may be Windows
304 if {[string match *mingw* [get-define host]]} {
305 define-append LIBS -lwsock32
306 }
307 }
308 cc-check-function-in-lib iconv iconv
309 cc-check-functions utime
310
--- auto.def
+++ auto.def
@@ -1,14 +1,15 @@
1 # System autoconfiguration. Try: ./configure --help
2
3 use cc cc-lib
4
5 options {
6 with-openssl:path|auto|tree|none
7 => {Look for OpenSSL in the given path, automatically, in the source tree, or none}
8 with-miniz=0 => {Use miniz from the source tree}
9 with-zlib:path|auto|tree
10 => {Look for zlib in the given path, automatically, or in the source tree}
11 with-exec-rel-paths=0
12 => {Enable relative paths for external diff/gdiff}
13 with-legacy-mv-rm=0 => {Enable legacy behavior for mv/rm (skip checkout files)}
14 with-th1-docs=0 => {Enable TH1 for embedded documentation pages}
15 with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages}
@@ -35,10 +36,47 @@
36 cc-check-progs tclsh
37
38 define EXTRA_CFLAGS ""
39 define EXTRA_LDFLAGS ""
40 define USE_SYSTEM_SQLITE 0
41 define USE_LINENOISE 0
42
43 # This procedure is a customized version of "cc-check-function-in-lib",
44 # that does not modify the LIBS variable. Its use prevents prematurely
45 # pulling in libraries that will be added later anyhow (e.g. "-ldl").
46 proc check-function-in-lib {function libs {otherlibs {}}} {
47 if {[string length $otherlibs]} {
48 msg-checking "Checking for $function in $libs with $otherlibs..."
49 } else {
50 msg-checking "Checking for $function in $libs..."
51 }
52 set found 0
53 cc-with [list -libs $otherlibs] {
54 if {[cctest_function $function]} {
55 msg-result "none needed"
56 define lib_$function ""
57 incr found
58 } else {
59 foreach lib $libs {
60 cc-with [list -libs -l$lib] {
61 if {[cctest_function $function]} {
62 msg-result -l$lib
63 define lib_$function -l$lib
64 incr found
65 break
66 }
67 }
68 }
69 }
70 }
71 if {$found} {
72 define [feature-define-name $function]
73 } else {
74 msg-result "no"
75 }
76 return $found
77 }
78
79 if {![opt-bool internal-sqlite]} {
80 proc find_internal_sqlite {} {
81
82 # On some systems (slackware), libsqlite3 requires -ldl to link. So
@@ -51,27 +89,43 @@
89 # Locate the system SQLite by searching for sqlite3_open(). Then check
90 # if sqlite3_strglob() can be found as well. If we can find open() but
91 # not strglob(), then the system SQLite is too old to link against
92 # fossil.
93 #
94 if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
95 if {![check-function-in-lib sqlite3_malloc64 sqlite3 $extralibs]} {
96 user-error "system sqlite3 too old (require >= 3.8.7)"
97 }
98
99 # Success. Update symbols and return.
100 #
101 define USE_SYSTEM_SQLITE 1
102 define-append LIBS -lsqlite3
103 define-append LIBS $extralibs
104 return
105 }
106 }
107 user-error "system sqlite3 not found"
108 }
109
110 find_internal_sqlite
111 }
112
113 proc is_mingw {} {
114 return [string match *mingw* [get-define host]]
115 }
116
117 if {[is_mingw]} {
118 define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
119 define-append LIBS -lkernel32 -lws2_32
120 } else {
121 #
122 # NOTE: All platforms except MinGW should use the linenoise
123 # package. It is currently unsupported on Win32.
124 #
125 define USE_LINENOISE 1
126 }
127
128 if {[string match *-solaris* [get-define host]]} {
129 define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__}
130 }
131
@@ -125,26 +179,169 @@
179 msg-result "Trying to link statically"
180 } else {
181 define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
182 define FOSSIL_DYNAMIC_BUILD
183 }
184
185 # Helper for OpenSSL checking
186 proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto}}} {
187 msg-checking "Checking for $msg..."
188 set rc 0
189 if {[is_mingw]} {
190 lappend libs -lgdi32 -lwsock32
191 }
192 if {[info exists ::zlib_lib]} {
193 lappend libs $::zlib_lib
194 }
195 msg-quiet cc-with [list -cflags $cflags -libs $libs] {
196 if {[cc-check-includes openssl/ssl.h] && \
197 [cc-check-functions SSL_new]} {
198 incr rc
199 }
200 }
201 if {!$rc && ![is_mingw]} {
202 # On some systems, OpenSSL appears to require -ldl to link.
203 lappend libs -ldl
204 msg-quiet cc-with [list -cflags $cflags -libs $libs] {
205 if {[cc-check-includes openssl/ssl.h] && \
206 [cc-check-functions SSL_new]} {
207 incr rc
208 }
209 }
210 }
211 if {$rc} {
212 msg-result "ok"
213 return 1
214 } else {
215 msg-result "no"
216 return 0
217 }
218 }
219
220 if {[opt-bool with-miniz]} {
221 define FOSSIL_ENABLE_MINIZ 1
222 msg-result "Using miniz for compression"
223 } else {
224 # Check for zlib, using the given location if specified
225 set zlibpath [opt-val with-zlib]
226 if {$zlibpath eq "tree"} {
227 set zlibdir [file dirname $autosetup(dir)]/compat/zlib
228 if {![file isdirectory $zlibdir]} {
229 user-error "The zlib in source tree directory does not exist"
230 }
231 cc-with [list -cflags "-I$zlibdir -L$zlibdir"]
232 define-append EXTRA_CFLAGS -I$zlibdir
233 define-append LIBS $zlibdir/libz.a
234 set ::zlib_lib $zlibdir/libz.a
235 msg-result "Using zlib in source tree"
236 } else {
237 if {$zlibpath ni {auto ""}} {
238 cc-with [list -cflags "-I$zlibpath -L$zlibpath"]
239 define-append EXTRA_CFLAGS -I$zlibpath
240 define-append EXTRA_LDFLAGS -L$zlibpath
241 msg-result "Using zlib from $zlibpath"
242 }
243 if {![cc-check-includes zlib.h] || ![check-function-in-lib inflateEnd z]} {
244 user-error "zlib not found please install it or specify the location with --with-zlib"
245 }
246 set ::zlib_lib -lz
247 }
248 }
249
250 set ssldirs [opt-val with-openssl]
251 if {$ssldirs ne "none"} {
252 if {[opt-bool with-miniz]} {
253 user-error "The --with-miniz option is incompatible with OpenSSL"
254 }
255 set found 0
256 if {$ssldirs eq "tree"} {
257 set ssldir [file dirname $autosetup(dir)]/compat/openssl
258 if {![file isdirectory $ssldir]} {
259 user-error "The OpenSSL in source tree directory does not exist"
260 }
261 set msg "ssl in $ssldir"
262 set cflags "-I$ssldir/include"
263 set ldflags "-L$ssldir"
264 set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a"
265 set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs]
266 } else {
267 if {$ssldirs in {auto ""}} {
268 catch {
269 set cflags [exec pkg-config openssl --cflags-only-I]
270 set ldflags [exec pkg-config openssl --libs-only-L]
271 set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
272 } msg
273 if {!$found} {
274 set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
275 }
276 }
277 if {!$found} {
278 foreach dir $ssldirs {
279 if {$dir eq ""} {
280 set msg "system ssl"
281 set cflags ""
282 set ldflags ""
283 } else {
284 set msg "ssl in $dir"
285 set cflags "-I$dir/include"
286 set ldflags "-L$dir/lib"
287 }
288 if {[check-for-openssl $msg "$cflags $ldflags"]} {
289 incr found
290 break
291 }
292 }
293 }
294 }
295 if {$found} {
296 define FOSSIL_ENABLE_SSL
297 define-append EXTRA_CFLAGS $cflags
298 define-append EXTRA_LDFLAGS $ldflags
299 if {[info exists ssllibs]} {
300 define-append LIBS $ssllibs
301 } else {
302 define-append LIBS -lssl -lcrypto
303 }
304 if {[info exists ::zlib_lib]} {
305 define-append LIBS $::zlib_lib
306 }
307 if {[is_mingw]} {
308 define-append LIBS -lgdi32 -lwsock32
309 }
310 msg-result "HTTPS support enabled"
311
312 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
313 if {[string match *-darwin* [get-define host]]} {
314 if {[cctest -cflags {-Wdeprecated-declarations}]} {
315 define-append EXTRA_CFLAGS -Wdeprecated-declarations
316 }
317 }
318 } else {
319 user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
320 }
321 } else {
322 if {[info exists ::zlib_lib]} {
323 define-append LIBS $::zlib_lib
324 }
325 }
326
327 set tclpath [opt-val with-tcl]
328 if {$tclpath ne ""} {
329 set tclprivatestubs [opt-bool with-tcl-private-stubs]
330 # Note parse-tclconfig-sh is in autosetup/local.tcl
331 if {$tclpath eq "1"} {
332 set tcldir [file dirname $autosetup(dir)]/compat/tcl-8.6
333 if {$tclprivatestubs} {
334 set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
335 set tclconfig(TCL_VERSION) {Private Stubs}
336 set tclconfig(TCL_PATCH_LEVEL) {}
337 set tclconfig(TCL_PREFIX) $tcldir
338 set tclconfig(TCL_LD_FLAGS) { }
339 } else {
340 # Use the system Tcl. Look in some likely places.
341 array set tclconfig [parse-tclconfig-sh \
342 $tcldir/unix $tcldir/win \
343 /usr /usr/local /usr/share /opt/local]
344 set msg "on your system"
345 }
346 } else {
347 array set tclconfig [parse-tclconfig-sh $tclpath]
@@ -192,10 +389,27 @@
389 if {[cc-check-functions Tcl_CreateInterp]} {
390 set foundtcl 1
391 }
392 }
393 }
394 }
395 if {!$foundtcl && ![string match *-lpthread* $libs]} {
396 # On some systems, TCL_LIB_SPEC appears to be missing
397 # "-lpthread". Try adding it.
398 msg-result "Adding \"-lpthread\" and retrying for Tcl..."
399 set libs "$libs -lpthread"
400 cc-with [list -cflags $cflags -libs $libs] {
401 if {$tclstubs} {
402 if {[cc-check-functions Tcl_InitStubs]} {
403 set foundtcl 1
404 }
405 } else {
406 if {[cc-check-functions Tcl_CreateInterp]} {
407 set foundtcl 1
408 }
409 }
410 }
411 }
412 if {!$foundtcl} {
413 if {$tclstubs} {
414 user-error "Cannot find a usable Tcl stubs library $msg"
415 } else {
@@ -207,103 +421,33 @@
421 msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
422 if {!$tclprivatestubs} {
423 define-append LIBS $libs
424 }
425 define-append EXTRA_CFLAGS $cflags
426 if {[info exists zlibpath] && $zlibpath eq "tree"} {
427 #
428 # NOTE: When using zlib in the source tree, prevent Tcl from
429 # pulling in the system one.
430 #
431 set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
432 $tclconfig(TCL_LD_FLAGS)]
433 }
434 #
435 # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
436 # be checked for near the bottom of this file.
437 #
438 set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
439 $tclconfig(TCL_LD_FLAGS)]
440 define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
441 define FOSSIL_ENABLE_TCL
442 }
443
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444 # Network functions require libraries on some systems
445 cc-check-function-in-lib gethostbyname nsl
446 if {![cc-check-function-in-lib socket {socket network}]} {
447 # Last resort, may be Windows
448 if {[is_mingw]} {
449 define-append LIBS -lwsock32
450 }
451 }
452 cc-check-function-in-lib iconv iconv
453 cc-check-functions utime
454
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -816,11 +816,11 @@
816816
817817
# Follow symlinks until we get to something which is not a symlink
818818
proc realpath {path} {
819819
while {1} {
820820
if {[catch {
821
- set path [file link $path]
821
+ set path [file readlink $path]
822822
}]} {
823823
# Not a link
824824
break
825825
}
826826
}
@@ -1188,12 +1188,18 @@
11881188
11891189
# If not already paged and stdout is a tty, pipe the output through the pager
11901190
# This is done by reinvoking autosetup with --nopager added
11911191
proc use_pager {} {
11921192
if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
1193
- catch {
1194
- exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& [getenv PAGER] >@stdout <@stdin
1193
+ if {[catch {
1194
+ exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
1195
+ } msg opts] == 1} {
1196
+ if {[dict get $opts -errorcode] eq "NONE"} {
1197
+ # an internal/exec error
1198
+ puts stderr $msg
1199
+ exit 1
1200
+ }
11951201
}
11961202
exit 0
11971203
}
11981204
}
11991205
12001206
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -816,11 +816,11 @@
816
817 # Follow symlinks until we get to something which is not a symlink
818 proc realpath {path} {
819 while {1} {
820 if {[catch {
821 set path [file link $path]
822 }]} {
823 # Not a link
824 break
825 }
826 }
@@ -1188,12 +1188,18 @@
1188
1189 # If not already paged and stdout is a tty, pipe the output through the pager
1190 # This is done by reinvoking autosetup with --nopager added
1191 proc use_pager {} {
1192 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
1193 catch {
1194 exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& [getenv PAGER] >@stdout <@stdin
 
 
 
 
 
 
1195 }
1196 exit 0
1197 }
1198 }
1199
1200
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -816,11 +816,11 @@
816
817 # Follow symlinks until we get to something which is not a symlink
818 proc realpath {path} {
819 while {1} {
820 if {[catch {
821 set path [file readlink $path]
822 }]} {
823 # Not a link
824 break
825 }
826 }
@@ -1188,12 +1188,18 @@
1188
1189 # If not already paged and stdout is a tty, pipe the output through the pager
1190 # This is done by reinvoking autosetup with --nopager added
1191 proc use_pager {} {
1192 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
1193 if {[catch {
1194 exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
1195 } msg opts] == 1} {
1196 if {[dict get $opts -errorcode] eq "NONE"} {
1197 # an internal/exec error
1198 puts stderr $msg
1199 exit 1
1200 }
1201 }
1202 exit 0
1203 }
1204 }
1205
1206
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -107,13 +107,14 @@
107107
# is removed to create the output file name.
108108
#
109109
# Each pattern of the form @define@ is replaced the the corresponding
110110
# define, if it exists, or left unchanged if not.
111111
#
112
-# The special value @srcdir@ is subsituted with the relative
112
+# The special value @srcdir@ is substituted with the relative
113113
# path to the source directory from the directory where the output
114
-# file is created. Use @top_srcdir@ for the absolute path.
114
+# file is created, while the special value @top_srcdir@ is substituted
115
+# with the relative path to the top level source directory.
115116
#
116117
# Conditional sections may be specified as follows:
117118
## @if name == value
118119
## lines
119120
## @else
@@ -151,12 +152,13 @@
151152
set outdir [file dirname $out]
152153
153154
# Make sure the directory exists
154155
file mkdir $outdir
155156
156
- # Set up srcdir to be relative to the target dir
157
+ # Set up srcdir and top_srcdir to be relative to the target dir
157158
define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
159
+ define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
158160
159161
set mapping {}
160162
foreach {n v} [array get ::define] {
161163
lappend mapping @$n@ $v
162164
}
163165
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -107,13 +107,14 @@
107 # is removed to create the output file name.
108 #
109 # Each pattern of the form @define@ is replaced the the corresponding
110 # define, if it exists, or left unchanged if not.
111 #
112 # The special value @srcdir@ is subsituted with the relative
113 # path to the source directory from the directory where the output
114 # file is created. Use @top_srcdir@ for the absolute path.
 
115 #
116 # Conditional sections may be specified as follows:
117 ## @if name == value
118 ## lines
119 ## @else
@@ -151,12 +152,13 @@
151 set outdir [file dirname $out]
152
153 # Make sure the directory exists
154 file mkdir $outdir
155
156 # Set up srcdir to be relative to the target dir
157 define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
 
158
159 set mapping {}
160 foreach {n v} [array get ::define] {
161 lappend mapping @$n@ $v
162 }
163
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -107,13 +107,14 @@
107 # is removed to create the output file name.
108 #
109 # Each pattern of the form @define@ is replaced the the corresponding
110 # define, if it exists, or left unchanged if not.
111 #
112 # The special value @srcdir@ is substituted with the relative
113 # path to the source directory from the directory where the output
114 # file is created, while the special value @top_srcdir@ is substituted
115 # with the relative path to the top level source directory.
116 #
117 # Conditional sections may be specified as follows:
118 ## @if name == value
119 ## lines
120 ## @else
@@ -151,12 +152,13 @@
152 set outdir [file dirname $out]
153
154 # Make sure the directory exists
155 file mkdir $outdir
156
157 # Set up srcdir and top_srcdir to be relative to the target dir
158 define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
159 define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
160
161 set mapping {}
162 foreach {n v} [array get ::define] {
163 lappend mapping @$n@ $v
164 }
165
+1 -1
--- src/cache.c
+++ src/cache.c
@@ -252,11 +252,11 @@
252252
** all entries currently in the cache
253253
**
254254
** status Show a summary of cache status.
255255
**
256256
** The cache is stored in a file that is distinct from the repository
257
-** but that is held in the same directory as the repository. To cache
257
+** but that is held in the same directory as the repository. The cache
258258
** file can be deleted in order to completely disable the cache.
259259
*/
260260
void cache_cmd(void){
261261
const char *zCmd;
262262
int nCmd;
263263
--- src/cache.c
+++ src/cache.c
@@ -252,11 +252,11 @@
252 ** all entries currently in the cache
253 **
254 ** status Show a summary of cache status.
255 **
256 ** The cache is stored in a file that is distinct from the repository
257 ** but that is held in the same directory as the repository. To cache
258 ** file can be deleted in order to completely disable the cache.
259 */
260 void cache_cmd(void){
261 const char *zCmd;
262 int nCmd;
263
--- src/cache.c
+++ src/cache.c
@@ -252,11 +252,11 @@
252 ** all entries currently in the cache
253 **
254 ** status Show a summary of cache status.
255 **
256 ** The cache is stored in a file that is distinct from the repository
257 ** but that is held in the same directory as the repository. The cache
258 ** file can be deleted in order to completely disable the cache.
259 */
260 void cache_cmd(void){
261 const char *zCmd;
262 int nCmd;
263
--- src/checkin.c
+++ src/checkin.c
@@ -396,10 +396,12 @@
396396
if( zRev!=0 ){
397397
db_find_and_open_repository(0, 0);
398398
verify_all_options();
399399
ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder);
400400
return;
401
+ }else if( find_option("R",0,1)!=0 ){
402
+ fossil_fatal("the -r is required in addition to -R");
401403
}
402404
403405
db_must_be_within_tree();
404406
vid = db_lget_int("checkout", 0);
405407
if( timeOrder ){
406408
--- src/checkin.c
+++ src/checkin.c
@@ -396,10 +396,12 @@
396 if( zRev!=0 ){
397 db_find_and_open_repository(0, 0);
398 verify_all_options();
399 ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder);
400 return;
 
 
401 }
402
403 db_must_be_within_tree();
404 vid = db_lget_int("checkout", 0);
405 if( timeOrder ){
406
--- src/checkin.c
+++ src/checkin.c
@@ -396,10 +396,12 @@
396 if( zRev!=0 ){
397 db_find_and_open_repository(0, 0);
398 verify_all_options();
399 ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder);
400 return;
401 }else if( find_option("R",0,1)!=0 ){
402 fossil_fatal("the -r is required in addition to -R");
403 }
404
405 db_must_be_within_tree();
406 vid = db_lget_int("checkout", 0);
407 if( timeOrder ){
408
--- src/checkin.c
+++ src/checkin.c
@@ -396,10 +396,12 @@
396396
if( zRev!=0 ){
397397
db_find_and_open_repository(0, 0);
398398
verify_all_options();
399399
ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder);
400400
return;
401
+ }else if( find_option("R",0,1)!=0 ){
402
+ fossil_fatal("the -r is required in addition to -R");
401403
}
402404
403405
db_must_be_within_tree();
404406
vid = db_lget_int("checkout", 0);
405407
if( timeOrder ){
406408
--- src/checkin.c
+++ src/checkin.c
@@ -396,10 +396,12 @@
396 if( zRev!=0 ){
397 db_find_and_open_repository(0, 0);
398 verify_all_options();
399 ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder);
400 return;
 
 
401 }
402
403 db_must_be_within_tree();
404 vid = db_lget_int("checkout", 0);
405 if( timeOrder ){
406
--- src/checkin.c
+++ src/checkin.c
@@ -396,10 +396,12 @@
396 if( zRev!=0 ){
397 db_find_and_open_repository(0, 0);
398 verify_all_options();
399 ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder);
400 return;
401 }else if( find_option("R",0,1)!=0 ){
402 fossil_fatal("the -r is required in addition to -R");
403 }
404
405 db_must_be_within_tree();
406 vid = db_lget_int("checkout", 0);
407 if( timeOrder ){
408
+51 -2
--- src/content.c
+++ src/content.c
@@ -709,11 +709,11 @@
709709
**
710710
** Make sure the content at RECORDID is not a delta
711711
*/
712712
void test_content_undelta_cmd(void){
713713
int rid;
714
- if( g.argc!=2 ) usage("RECORDID");
714
+ if( g.argc!=3 ) usage("RECORDID");
715715
db_must_be_within_tree();
716716
rid = atoi(g.argv[2]);
717717
content_undelta(rid);
718718
}
719719
@@ -905,11 +905,11 @@
905905
rid, size, blob_size(&content));
906906
nErr++;
907907
}
908908
sha1sum_blob(&content, &cksum);
909909
if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
910
- fossil_print("checksum mismatch on artifact %d: wanted %s but got %s\n",
910
+ fossil_print("wrong hash on artifact %d: wanted %s but got %s\n",
911911
rid, zUuid, blob_str(&cksum));
912912
nErr++;
913913
}
914914
if( bParse && looks_like_control_artifact(&content) ){
915915
Blob err;
@@ -953,10 +953,12 @@
953953
fossil_print("%d total control artifacts\n", nCA);
954954
for(i=1; i<count(azType); i++){
955955
if( anCA[i] ) fossil_print(" %d %ss\n", anCA[i], azType[i]);
956956
}
957957
}
958
+ fossil_print("low-level database integrity-check: ");
959
+ fossil_print("%s\n", db_text(0, "PRAGMA integrity_check(10)"));
958960
}
959961
960962
/*
961963
** COMMAND: test-orphans
962964
**
@@ -1124,5 +1126,52 @@
11241126
if( nErr>0 || quietFlag==0 ){
11251127
fossil_print("%d missing or shunned references in %d control artifacts\n",
11261128
nErr, nArtifact);
11271129
}
11281130
}
1131
+
1132
+/*
1133
+** COMMAND: test-content-erase
1134
+**
1135
+** Usage: %fossil test-content-erase RID ....
1136
+**
1137
+** Remove all traces of one or more artifacts from the local repository.
1138
+**
1139
+** WARNING: This command destroys data and can cause you to lose work.
1140
+** Make sure you have a backup copy before using this command!
1141
+**
1142
+** WARNING: You must run "fossil rebuild" after this command to rebuild
1143
+** the metadata.
1144
+**
1145
+** Note that the arguments are the integer raw RID values from the BLOB table,
1146
+** not SHA1 hashs or labels.
1147
+*/
1148
+void test_content_erase(void){
1149
+ int i;
1150
+ Blob x;
1151
+ char c;
1152
+ Stmt q;
1153
+ prompt_user("This command erases information from the repository and\n"
1154
+ "might irrecoverably damage the repository. Make sure you\n"
1155
+ "have a backup copy!\n"
1156
+ "Continue? (y/N)? ", &x);
1157
+ c = blob_str(&x)[0];
1158
+ blob_reset(&x);
1159
+ if( c!='y' && c!='Y' ) return;
1160
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1161
+ db_begin_transaction();
1162
+ db_prepare(&q, "SELECT rid FROM delta WHERE srcid=:rid");
1163
+ for(i=2; i<g.argc; i++){
1164
+ int rid = atoi(g.argv[i]);
1165
+ fossil_print("Erasing artifact %d (%s)\n",
1166
+ rid, db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid));
1167
+ db_bind_int(&q, ":rid", rid);
1168
+ while( db_step(&q)==SQLITE_ROW ){
1169
+ content_undelta(db_column_int(&q,0));
1170
+ }
1171
+ db_reset(&q);
1172
+ db_multi_exec("DELETE FROM blob WHERE rid=%d", rid);
1173
+ db_multi_exec("DELETE FROM delta WHERE rid=%d", rid);
1174
+ }
1175
+ db_finalize(&q);
1176
+ db_end_transaction(0);
1177
+}
11291178
--- src/content.c
+++ src/content.c
@@ -709,11 +709,11 @@
709 **
710 ** Make sure the content at RECORDID is not a delta
711 */
712 void test_content_undelta_cmd(void){
713 int rid;
714 if( g.argc!=2 ) usage("RECORDID");
715 db_must_be_within_tree();
716 rid = atoi(g.argv[2]);
717 content_undelta(rid);
718 }
719
@@ -905,11 +905,11 @@
905 rid, size, blob_size(&content));
906 nErr++;
907 }
908 sha1sum_blob(&content, &cksum);
909 if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
910 fossil_print("checksum mismatch on artifact %d: wanted %s but got %s\n",
911 rid, zUuid, blob_str(&cksum));
912 nErr++;
913 }
914 if( bParse && looks_like_control_artifact(&content) ){
915 Blob err;
@@ -953,10 +953,12 @@
953 fossil_print("%d total control artifacts\n", nCA);
954 for(i=1; i<count(azType); i++){
955 if( anCA[i] ) fossil_print(" %d %ss\n", anCA[i], azType[i]);
956 }
957 }
 
 
958 }
959
960 /*
961 ** COMMAND: test-orphans
962 **
@@ -1124,5 +1126,52 @@
1124 if( nErr>0 || quietFlag==0 ){
1125 fossil_print("%d missing or shunned references in %d control artifacts\n",
1126 nErr, nArtifact);
1127 }
1128 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1129
--- src/content.c
+++ src/content.c
@@ -709,11 +709,11 @@
709 **
710 ** Make sure the content at RECORDID is not a delta
711 */
712 void test_content_undelta_cmd(void){
713 int rid;
714 if( g.argc!=3 ) usage("RECORDID");
715 db_must_be_within_tree();
716 rid = atoi(g.argv[2]);
717 content_undelta(rid);
718 }
719
@@ -905,11 +905,11 @@
905 rid, size, blob_size(&content));
906 nErr++;
907 }
908 sha1sum_blob(&content, &cksum);
909 if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
910 fossil_print("wrong hash on artifact %d: wanted %s but got %s\n",
911 rid, zUuid, blob_str(&cksum));
912 nErr++;
913 }
914 if( bParse && looks_like_control_artifact(&content) ){
915 Blob err;
@@ -953,10 +953,12 @@
953 fossil_print("%d total control artifacts\n", nCA);
954 for(i=1; i<count(azType); i++){
955 if( anCA[i] ) fossil_print(" %d %ss\n", anCA[i], azType[i]);
956 }
957 }
958 fossil_print("low-level database integrity-check: ");
959 fossil_print("%s\n", db_text(0, "PRAGMA integrity_check(10)"));
960 }
961
962 /*
963 ** COMMAND: test-orphans
964 **
@@ -1124,5 +1126,52 @@
1126 if( nErr>0 || quietFlag==0 ){
1127 fossil_print("%d missing or shunned references in %d control artifacts\n",
1128 nErr, nArtifact);
1129 }
1130 }
1131
1132 /*
1133 ** COMMAND: test-content-erase
1134 **
1135 ** Usage: %fossil test-content-erase RID ....
1136 **
1137 ** Remove all traces of one or more artifacts from the local repository.
1138 **
1139 ** WARNING: This command destroys data and can cause you to lose work.
1140 ** Make sure you have a backup copy before using this command!
1141 **
1142 ** WARNING: You must run "fossil rebuild" after this command to rebuild
1143 ** the metadata.
1144 **
1145 ** Note that the arguments are the integer raw RID values from the BLOB table,
1146 ** not SHA1 hashs or labels.
1147 */
1148 void test_content_erase(void){
1149 int i;
1150 Blob x;
1151 char c;
1152 Stmt q;
1153 prompt_user("This command erases information from the repository and\n"
1154 "might irrecoverably damage the repository. Make sure you\n"
1155 "have a backup copy!\n"
1156 "Continue? (y/N)? ", &x);
1157 c = blob_str(&x)[0];
1158 blob_reset(&x);
1159 if( c!='y' && c!='Y' ) return;
1160 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1161 db_begin_transaction();
1162 db_prepare(&q, "SELECT rid FROM delta WHERE srcid=:rid");
1163 for(i=2; i<g.argc; i++){
1164 int rid = atoi(g.argv[i]);
1165 fossil_print("Erasing artifact %d (%s)\n",
1166 rid, db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid));
1167 db_bind_int(&q, ":rid", rid);
1168 while( db_step(&q)==SQLITE_ROW ){
1169 content_undelta(db_column_int(&q,0));
1170 }
1171 db_reset(&q);
1172 db_multi_exec("DELETE FROM blob WHERE rid=%d", rid);
1173 db_multi_exec("DELETE FROM delta WHERE rid=%d", rid);
1174 }
1175 db_finalize(&q);
1176 db_end_transaction(0);
1177 }
1178
--- src/json_detail.h
+++ src/json_detail.h
@@ -184,11 +184,11 @@
184184
**
185185
** Now that we can simulate POST in CLI mode, the distinction
186186
** between them has disappeared in most (or all) cases, so 0 is
187187
** the standard value.
188188
*/
189
- char runMode;
189
+ int runMode;
190190
} JsonPageDef;
191191
192192
/*
193193
** Holds common keys used for various JSON API properties.
194194
*/
195195
--- src/json_detail.h
+++ src/json_detail.h
@@ -184,11 +184,11 @@
184 **
185 ** Now that we can simulate POST in CLI mode, the distinction
186 ** between them has disappeared in most (or all) cases, so 0 is
187 ** the standard value.
188 */
189 char runMode;
190 } JsonPageDef;
191
192 /*
193 ** Holds common keys used for various JSON API properties.
194 */
195
--- src/json_detail.h
+++ src/json_detail.h
@@ -184,11 +184,11 @@
184 **
185 ** Now that we can simulate POST in CLI mode, the distinction
186 ** between them has disappeared in most (or all) cases, so 0 is
187 ** the standard value.
188 */
189 int runMode;
190 } JsonPageDef;
191
192 /*
193 ** Holds common keys used for various JSON API properties.
194 */
195
+14 -12
--- src/login.c
+++ src/login.c
@@ -1075,29 +1075,30 @@
10751075
if(NULL==zCap){
10761076
return;
10771077
}
10781078
for(i=0; zCap[i]; i++){
10791079
switch( zCap[i] ){
1080
- case 's': p->Setup = 1; /* Fall thru into Admin */
1080
+ case 's': p->Setup = 1; /* Fall thru into Admin */
10811081
case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip =
1082
- p->RdWiki = p->WrWiki = p->NewWiki =
1083
- p->ApndWiki = p->Hyperlink = p->Clone =
1084
- p->NewTkt = p->Password = p->RdAddr =
1085
- p->TktFmt = p->Attach = p->ApndTkt =
1086
- p->ModWiki = p->ModTkt = 1;
1087
- /* Fall thru into Read/Write */
1088
- case 'i': p->Read = p->Write = 1; break;
1082
+ p->RdWiki = p->WrWiki = p->NewWiki =
1083
+ p->ApndWiki = p->Hyperlink = p->Clone =
1084
+ p->NewTkt = p->Password = p->RdAddr =
1085
+ p->TktFmt = p->Attach = p->ApndTkt =
1086
+ p->ModWiki = p->ModTkt = p->Delete =
1087
+ p->Private = 1;
1088
+ /* Fall thru into Read/Write */
1089
+ case 'i': p->Read = p->Write = 1; break;
10891090
case 'o': p->Read = 1; break;
10901091
case 'z': p->Zip = 1; break;
10911092
10921093
case 'd': p->Delete = 1; break;
10931094
case 'h': p->Hyperlink = 1; break;
10941095
case 'g': p->Clone = 1; break;
10951096
case 'p': p->Password = 1; break;
10961097
10971098
case 'j': p->RdWiki = 1; break;
1098
- case 'k': p->WrWiki = p->RdWiki = p->ApndWiki =1; break;
1099
+ case 'k': p->WrWiki = p->RdWiki = p->ApndWiki =1; break;
10991100
case 'm': p->ApndWiki = 1; break;
11001101
case 'f': p->NewWiki = 1; break;
11011102
case 'l': p->ModWiki = 1; break;
11021103
11031104
case 'e': p->RdAddr = 1; break;
@@ -1181,11 +1182,11 @@
11811182
/* case 'v': DEVELOPER */
11821183
case 'w': rc = p->WrTkt; break;
11831184
case 'x': rc = p->Private; break;
11841185
/* case 'y': */
11851186
case 'z': rc = p->Zip; break;
1186
- default: rc = 0; break;
1187
+ default: rc = 0; break;
11871188
}
11881189
}
11891190
return rc;
11901191
}
11911192
@@ -1289,12 +1290,13 @@
12891290
}
12901291
12911292
/*
12921293
** Before using the results of a form, first call this routine to verify
12931294
** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
1294
-** is missing or is incorrect, that indicates a cross-site scripting attach
1295
-** so emits an error message and abort.
1295
+** is missing or is incorrect, that indicates a cross-site scripting attack.
1296
+** If the event of an attack is detected, an error message is generated and
1297
+** all further processing is aborted.
12961298
*/
12971299
void login_verify_csrf_secret(void){
12981300
if( g.okCsrf ) return;
12991301
if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
13001302
g.okCsrf = 1;
13011303
--- src/login.c
+++ src/login.c
@@ -1075,29 +1075,30 @@
1075 if(NULL==zCap){
1076 return;
1077 }
1078 for(i=0; zCap[i]; i++){
1079 switch( zCap[i] ){
1080 case 's': p->Setup = 1; /* Fall thru into Admin */
1081 case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip =
1082 p->RdWiki = p->WrWiki = p->NewWiki =
1083 p->ApndWiki = p->Hyperlink = p->Clone =
1084 p->NewTkt = p->Password = p->RdAddr =
1085 p->TktFmt = p->Attach = p->ApndTkt =
1086 p->ModWiki = p->ModTkt = 1;
1087 /* Fall thru into Read/Write */
1088 case 'i': p->Read = p->Write = 1; break;
 
1089 case 'o': p->Read = 1; break;
1090 case 'z': p->Zip = 1; break;
1091
1092 case 'd': p->Delete = 1; break;
1093 case 'h': p->Hyperlink = 1; break;
1094 case 'g': p->Clone = 1; break;
1095 case 'p': p->Password = 1; break;
1096
1097 case 'j': p->RdWiki = 1; break;
1098 case 'k': p->WrWiki = p->RdWiki = p->ApndWiki =1; break;
1099 case 'm': p->ApndWiki = 1; break;
1100 case 'f': p->NewWiki = 1; break;
1101 case 'l': p->ModWiki = 1; break;
1102
1103 case 'e': p->RdAddr = 1; break;
@@ -1181,11 +1182,11 @@
1181 /* case 'v': DEVELOPER */
1182 case 'w': rc = p->WrTkt; break;
1183 case 'x': rc = p->Private; break;
1184 /* case 'y': */
1185 case 'z': rc = p->Zip; break;
1186 default: rc = 0; break;
1187 }
1188 }
1189 return rc;
1190 }
1191
@@ -1289,12 +1290,13 @@
1289 }
1290
1291 /*
1292 ** Before using the results of a form, first call this routine to verify
1293 ** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
1294 ** is missing or is incorrect, that indicates a cross-site scripting attach
1295 ** so emits an error message and abort.
 
1296 */
1297 void login_verify_csrf_secret(void){
1298 if( g.okCsrf ) return;
1299 if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
1300 g.okCsrf = 1;
1301
--- src/login.c
+++ src/login.c
@@ -1075,29 +1075,30 @@
1075 if(NULL==zCap){
1076 return;
1077 }
1078 for(i=0; zCap[i]; i++){
1079 switch( zCap[i] ){
1080 case 's': p->Setup = 1; /* Fall thru into Admin */
1081 case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip =
1082 p->RdWiki = p->WrWiki = p->NewWiki =
1083 p->ApndWiki = p->Hyperlink = p->Clone =
1084 p->NewTkt = p->Password = p->RdAddr =
1085 p->TktFmt = p->Attach = p->ApndTkt =
1086 p->ModWiki = p->ModTkt = p->Delete =
1087 p->Private = 1;
1088 /* Fall thru into Read/Write */
1089 case 'i': p->Read = p->Write = 1; break;
1090 case 'o': p->Read = 1; break;
1091 case 'z': p->Zip = 1; break;
1092
1093 case 'd': p->Delete = 1; break;
1094 case 'h': p->Hyperlink = 1; break;
1095 case 'g': p->Clone = 1; break;
1096 case 'p': p->Password = 1; break;
1097
1098 case 'j': p->RdWiki = 1; break;
1099 case 'k': p->WrWiki = p->RdWiki = p->ApndWiki =1; break;
1100 case 'm': p->ApndWiki = 1; break;
1101 case 'f': p->NewWiki = 1; break;
1102 case 'l': p->ModWiki = 1; break;
1103
1104 case 'e': p->RdAddr = 1; break;
@@ -1181,11 +1182,11 @@
1182 /* case 'v': DEVELOPER */
1183 case 'w': rc = p->WrTkt; break;
1184 case 'x': rc = p->Private; break;
1185 /* case 'y': */
1186 case 'z': rc = p->Zip; break;
1187 default: rc = 0; break;
1188 }
1189 }
1190 return rc;
1191 }
1192
@@ -1289,12 +1290,13 @@
1290 }
1291
1292 /*
1293 ** Before using the results of a form, first call this routine to verify
1294 ** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
1295 ** is missing or is incorrect, that indicates a cross-site scripting attack.
1296 ** If the event of an attack is detected, an error message is generated and
1297 ** all further processing is aborted.
1298 */
1299 void login_verify_csrf_secret(void){
1300 if( g.okCsrf ) return;
1301 if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
1302 g.okCsrf = 1;
1303
+119 -69
--- src/main.c
+++ src/main.c
@@ -1009,10 +1009,83 @@
10091009
const char *get_version(){
10101010
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
10111011
MANIFEST_DATE " UTC";
10121012
return version;
10131013
}
1014
+
1015
+/*
1016
+** This function populates a blob with version information. It is used by
1017
+** the "version" command and "test-version" web page. It assumes the blob
1018
+** passed to it is uninitialized; otherwise, it will leak memory.
1019
+*/
1020
+static void get_version_blob(
1021
+ Blob *pOut, /* Write the manifest here */
1022
+ int bVerbose /* Non-zero for full information. */
1023
+){
1024
+#if defined(FOSSIL_ENABLE_TCL)
1025
+ int rc;
1026
+ const char *zRc;
1027
+#endif
1028
+ blob_zero(pOut);
1029
+ blob_appendf(pOut, "This is fossil version %s\n", get_version());
1030
+ if( !bVerbose ) return;
1031
+ blob_appendf(pOut, "Compiled on %s %s using %s (%d-bit)\n",
1032
+ __DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
1033
+ blob_appendf(pOut, "SQLite %s %.30s\n", sqlite3_libversion(),
1034
+ sqlite3_sourceid());
1035
+ blob_appendf(pOut, "Schema version %s\n", AUX_SCHEMA_MAX);
1036
+#if defined(FOSSIL_ENABLE_MINIZ)
1037
+ blob_appendf(pOut, "miniz %s, loaded %s\n", MZ_VERSION, mz_version());
1038
+#else
1039
+ blob_appendf(pOut, "zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
1040
+#endif
1041
+#if defined(FOSSIL_ENABLE_SSL)
1042
+ blob_appendf(pOut, "SSL (%s)\n", SSLeay_version(SSLEAY_VERSION));
1043
+#endif
1044
+#if defined(FOSSIL_ENABLE_LEGACY_MV_RM)
1045
+ blob_append(pOut, "LEGACY_MV_RM\n", -1);
1046
+#endif
1047
+#if defined(FOSSIL_ENABLE_EXEC_REL_PATHS)
1048
+ blob_append(pOut, "EXEC_REL_PATHS\n", -1);
1049
+#endif
1050
+#if defined(FOSSIL_ENABLE_TH1_DOCS)
1051
+ blob_append(pOut, "TH1_DOCS\n", -1);
1052
+#endif
1053
+#if defined(FOSSIL_ENABLE_TH1_HOOKS)
1054
+ blob_append(pOut, "TH1_HOOKS\n", -1);
1055
+#endif
1056
+#if defined(FOSSIL_ENABLE_TCL)
1057
+ Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
1058
+ rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
1059
+ zRc = Th_ReturnCodeName(rc, 0);
1060
+ blob_appendf(pOut, "TCL (Tcl %s, loaded %s: %s)\n",
1061
+ TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
1062
+ );
1063
+#endif
1064
+#if defined(USE_TCL_STUBS)
1065
+ blob_append(pOut, "USE_TCL_STUBS\n", -1);
1066
+#endif
1067
+#if defined(FOSSIL_ENABLE_TCL_STUBS)
1068
+ blob_append(pOut, "TCL_STUBS\n", -1);
1069
+#endif
1070
+#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
1071
+ blob_append(pOut, "TCL_PRIVATE_STUBS\n", -1);
1072
+#endif
1073
+#if defined(FOSSIL_ENABLE_JSON)
1074
+ blob_appendf(pOut, "JSON (API %s)\n", FOSSIL_JSON_API_VERSION);
1075
+#endif
1076
+#if defined(BROKEN_MINGW_CMDLINE)
1077
+ blob_append(pOut, "MBCS_COMMAND_LINE\n", -1);
1078
+#else
1079
+ blob_append(pOut, "UNICODE_COMMAND_LINE\n", -1);
1080
+#endif
1081
+#if defined(FOSSIL_DYNAMIC_BUILD)
1082
+ blob_append(pOut, "DYNAMIC_BUILD\n", -1);
1083
+#else
1084
+ blob_append(pOut, "STATIC_BUILD\n", -1);
1085
+#endif
1086
+}
10141087
10151088
/*
10161089
** This function returns the user-agent string for Fossil, for
10171090
** use in HTTP(S) requests.
10181091
*/
@@ -1019,10 +1092,11 @@
10191092
const char *get_user_agent(){
10201093
static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
10211094
" " MANIFEST_VERSION ")";
10221095
return version;
10231096
}
1097
+
10241098
10251099
/*
10261100
** COMMAND: version
10271101
**
10281102
** Usage: %fossil version ?-verbose|-v?
@@ -1031,80 +1105,42 @@
10311105
** If the verbose option is specified, additional details will
10321106
** be output about what optional features this binary was compiled
10331107
** with
10341108
*/
10351109
void version_cmd(void){
1036
- int verboseFlag = 0;
1037
-
1038
- fossil_print("This is fossil version %s\n", get_version());
1039
- verboseFlag = find_option("verbose","v",0)!=0;
1110
+ Blob versionInfo;
1111
+ int verboseFlag = find_option("verbose","v",0)!=0;
10401112
10411113
/* We should be done with options.. */
10421114
verify_all_options();
1043
-
1044
- if(!verboseFlag){
1045
- return;
1046
- }else{
1047
-#if defined(FOSSIL_ENABLE_TCL)
1048
- int rc;
1049
- const char *zRc;
1050
-#endif
1051
- fossil_print("Compiled on %s %s using %s (%d-bit)\n",
1052
- __DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
1053
- fossil_print("SQLite %s %.30s\n", sqlite3_libversion(), sqlite3_sourceid());
1054
- fossil_print("Schema version %s\n", AUX_SCHEMA_MAX);
1055
-#if defined(FOSSIL_ENABLE_MINIZ)
1056
- fossil_print("miniz %s, loaded %s\n", MZ_VERSION, mz_version());
1057
-#else
1058
- fossil_print("zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
1059
-#endif
1060
-#if defined(FOSSIL_ENABLE_SSL)
1061
- fossil_print("SSL (%s)\n", SSLeay_version(SSLEAY_VERSION));
1062
-#endif
1063
-#if defined(FOSSIL_ENABLE_LEGACY_MV_RM)
1064
- fossil_print("LEGACY_MV_RM\n");
1065
-#endif
1066
-#if defined(FOSSIL_ENABLE_EXEC_REL_PATHS)
1067
- fossil_print("EXEC_REL_PATHS\n");
1068
-#endif
1069
-#if defined(FOSSIL_ENABLE_TH1_DOCS)
1070
- fossil_print("TH1_DOCS\n");
1071
-#endif
1072
-#if defined(FOSSIL_ENABLE_TH1_HOOKS)
1073
- fossil_print("TH1_HOOKS\n");
1074
-#endif
1075
-#if defined(FOSSIL_ENABLE_TCL)
1076
- Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
1077
- rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
1078
- zRc = Th_ReturnCodeName(rc, 0);
1079
- fossil_print("TCL (Tcl %s, loaded %s: %s)\n",
1080
- TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
1081
- );
1082
-#endif
1083
-#if defined(USE_TCL_STUBS)
1084
- fossil_print("USE_TCL_STUBS\n");
1085
-#endif
1086
-#if defined(FOSSIL_ENABLE_TCL_STUBS)
1087
- fossil_print("TCL_STUBS\n");
1088
-#endif
1089
-#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
1090
- fossil_print("TCL_PRIVATE_STUBS\n");
1091
-#endif
1092
-#if defined(FOSSIL_ENABLE_JSON)
1093
- fossil_print("JSON (API %s)\n", FOSSIL_JSON_API_VERSION);
1094
-#endif
1095
-#if defined(BROKEN_MINGW_CMDLINE)
1096
- fossil_print("MBCS_COMMAND_LINE\n");
1097
-#else
1098
- fossil_print("UNICODE_COMMAND_LINE\n");
1099
-#endif
1100
-#if defined(FOSSIL_DYNAMIC_BUILD)
1101
- fossil_print("DYNAMIC_BUILD\n");
1102
-#else
1103
- fossil_print("STATIC_BUILD\n");
1104
-#endif
1105
- }
1115
+ get_version_blob(&versionInfo, verboseFlag);
1116
+ fossil_print("%s", blob_str(&versionInfo));
1117
+}
1118
+
1119
+
1120
+/*
1121
+** WEBPAGE: test-version
1122
+**
1123
+** Show the version information for Fossil.
1124
+**
1125
+** Query parameters:
1126
+**
1127
+** verbose Show all available details.
1128
+*/
1129
+void test_version_page(void){
1130
+ Blob versionInfo;
1131
+ int verboseFlag;
1132
+
1133
+ login_check_credentials();
1134
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1135
+ verboseFlag = P("verbose")!=0;
1136
+ style_header("Version Information");
1137
+ get_version_blob(&versionInfo, verboseFlag);
1138
+ @ <blockquote><pre>
1139
+ @ %h(blob_str(&versionInfo))
1140
+ @ </pre></blockquote>
1141
+ style_footer();
11061142
}
11071143
11081144
11091145
/*
11101146
** COMMAND: help
@@ -1361,11 +1397,17 @@
13611397
13621398
if( g.zBaseURL!=0 ) return;
13631399
if( zAltBase ){
13641400
int i, n, c;
13651401
g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
1366
- if( memcmp(g.zTop, "http://", 7)!=0 && memcmp(g.zTop,"https://",8)!=0 ){
1402
+ if( strncmp(g.zTop, "http://", 7)==0 ){
1403
+ /* it is HTTP, replace prefix with HTTPS. */
1404
+ g.zHttpsURL = mprintf("https://%s", &g.zTop[7]);
1405
+ }else if( strncmp(g.zTop, "https://", 8)==0 ){
1406
+ /* it is already HTTPS, use it. */
1407
+ g.zHttpsURL = mprintf("%s", g.zTop);
1408
+ }else{
13671409
fossil_fatal("argument to --baseurl should be 'http://host/path'"
13681410
" or 'https://host/path'");
13691411
}
13701412
for(i=n=0; (c = g.zTop[i])!=0; i++){
13711413
if( c=='/' ){
@@ -2393,11 +2435,13 @@
23932435
** --create Create a new REPOSITORY if it does not already exist
23942436
** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
23952437
** --files GLOBLIST Comma-separated list of glob patterns for static files
23962438
** --localauth enable automatic login for requests from localhost
23972439
** --localhost listen on 127.0.0.1 only (always true for "ui")
2440
+** --https signal a request coming in via https
23982441
** --nojail Drop root privileges but do not enter the chroot jail
2442
+** --nossl signal that no SSL connections are available
23992443
** --notfound URL Redirect
24002444
** -P|--port TCPPORT listen to request on port TCPPORT
24012445
** --th-trace trace TH1 execution (for debugging purposes)
24022446
** --repolist If REPOSITORY is dir, URL "/" lists repos.
24032447
** --scgi Accept SCGI rather than HTTP
@@ -2454,10 +2498,17 @@
24542498
zAltBase = find_option("baseurl", 0, 1);
24552499
fCreate = find_option("create",0,0)!=0;
24562500
if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
24572501
if( zAltBase ){
24582502
set_base_url(zAltBase);
2503
+ }
2504
+ g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
2505
+ if( find_option("https",0,0)!=0 ){
2506
+ cgi_replace_parameter("HTTPS","on");
2507
+ }else{
2508
+ /* without --https, defaults to not available. */
2509
+ g.sslNotAvailable = 1;
24592510
}
24602511
if( find_option("localhost", 0, 0)!=0 ){
24612512
flags |= HTTP_SERVER_LOCALHOST;
24622513
}
24632514
@@ -2515,11 +2566,10 @@
25152566
if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
25162567
db_close(1);
25172568
if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
25182569
fossil_fatal("unable to listen on TCP socket %d", iPort);
25192570
}
2520
- g.sslNotAvailable = 1;
25212571
g.httpIn = stdin;
25222572
g.httpOut = stdout;
25232573
if( g.fHttpTrace || g.fSqlTrace ){
25242574
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
25252575
}
25262576
--- src/main.c
+++ src/main.c
@@ -1009,10 +1009,83 @@
1009 const char *get_version(){
1010 static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
1011 MANIFEST_DATE " UTC";
1012 return version;
1013 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1014
1015 /*
1016 ** This function returns the user-agent string for Fossil, for
1017 ** use in HTTP(S) requests.
1018 */
@@ -1019,10 +1092,11 @@
1019 const char *get_user_agent(){
1020 static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
1021 " " MANIFEST_VERSION ")";
1022 return version;
1023 }
 
1024
1025 /*
1026 ** COMMAND: version
1027 **
1028 ** Usage: %fossil version ?-verbose|-v?
@@ -1031,80 +1105,42 @@
1031 ** If the verbose option is specified, additional details will
1032 ** be output about what optional features this binary was compiled
1033 ** with
1034 */
1035 void version_cmd(void){
1036 int verboseFlag = 0;
1037
1038 fossil_print("This is fossil version %s\n", get_version());
1039 verboseFlag = find_option("verbose","v",0)!=0;
1040
1041 /* We should be done with options.. */
1042 verify_all_options();
1043
1044 if(!verboseFlag){
1045 return;
1046 }else{
1047 #if defined(FOSSIL_ENABLE_TCL)
1048 int rc;
1049 const char *zRc;
1050 #endif
1051 fossil_print("Compiled on %s %s using %s (%d-bit)\n",
1052 __DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
1053 fossil_print("SQLite %s %.30s\n", sqlite3_libversion(), sqlite3_sourceid());
1054 fossil_print("Schema version %s\n", AUX_SCHEMA_MAX);
1055 #if defined(FOSSIL_ENABLE_MINIZ)
1056 fossil_print("miniz %s, loaded %s\n", MZ_VERSION, mz_version());
1057 #else
1058 fossil_print("zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
1059 #endif
1060 #if defined(FOSSIL_ENABLE_SSL)
1061 fossil_print("SSL (%s)\n", SSLeay_version(SSLEAY_VERSION));
1062 #endif
1063 #if defined(FOSSIL_ENABLE_LEGACY_MV_RM)
1064 fossil_print("LEGACY_MV_RM\n");
1065 #endif
1066 #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS)
1067 fossil_print("EXEC_REL_PATHS\n");
1068 #endif
1069 #if defined(FOSSIL_ENABLE_TH1_DOCS)
1070 fossil_print("TH1_DOCS\n");
1071 #endif
1072 #if defined(FOSSIL_ENABLE_TH1_HOOKS)
1073 fossil_print("TH1_HOOKS\n");
1074 #endif
1075 #if defined(FOSSIL_ENABLE_TCL)
1076 Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
1077 rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
1078 zRc = Th_ReturnCodeName(rc, 0);
1079 fossil_print("TCL (Tcl %s, loaded %s: %s)\n",
1080 TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
1081 );
1082 #endif
1083 #if defined(USE_TCL_STUBS)
1084 fossil_print("USE_TCL_STUBS\n");
1085 #endif
1086 #if defined(FOSSIL_ENABLE_TCL_STUBS)
1087 fossil_print("TCL_STUBS\n");
1088 #endif
1089 #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
1090 fossil_print("TCL_PRIVATE_STUBS\n");
1091 #endif
1092 #if defined(FOSSIL_ENABLE_JSON)
1093 fossil_print("JSON (API %s)\n", FOSSIL_JSON_API_VERSION);
1094 #endif
1095 #if defined(BROKEN_MINGW_CMDLINE)
1096 fossil_print("MBCS_COMMAND_LINE\n");
1097 #else
1098 fossil_print("UNICODE_COMMAND_LINE\n");
1099 #endif
1100 #if defined(FOSSIL_DYNAMIC_BUILD)
1101 fossil_print("DYNAMIC_BUILD\n");
1102 #else
1103 fossil_print("STATIC_BUILD\n");
1104 #endif
1105 }
1106 }
1107
1108
1109 /*
1110 ** COMMAND: help
@@ -1361,11 +1397,17 @@
1361
1362 if( g.zBaseURL!=0 ) return;
1363 if( zAltBase ){
1364 int i, n, c;
1365 g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
1366 if( memcmp(g.zTop, "http://", 7)!=0 && memcmp(g.zTop,"https://",8)!=0 ){
 
 
 
 
 
 
1367 fossil_fatal("argument to --baseurl should be 'http://host/path'"
1368 " or 'https://host/path'");
1369 }
1370 for(i=n=0; (c = g.zTop[i])!=0; i++){
1371 if( c=='/' ){
@@ -2393,11 +2435,13 @@
2393 ** --create Create a new REPOSITORY if it does not already exist
2394 ** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
2395 ** --files GLOBLIST Comma-separated list of glob patterns for static files
2396 ** --localauth enable automatic login for requests from localhost
2397 ** --localhost listen on 127.0.0.1 only (always true for "ui")
 
2398 ** --nojail Drop root privileges but do not enter the chroot jail
 
2399 ** --notfound URL Redirect
2400 ** -P|--port TCPPORT listen to request on port TCPPORT
2401 ** --th-trace trace TH1 execution (for debugging purposes)
2402 ** --repolist If REPOSITORY is dir, URL "/" lists repos.
2403 ** --scgi Accept SCGI rather than HTTP
@@ -2454,10 +2498,17 @@
2454 zAltBase = find_option("baseurl", 0, 1);
2455 fCreate = find_option("create",0,0)!=0;
2456 if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
2457 if( zAltBase ){
2458 set_base_url(zAltBase);
 
 
 
 
 
 
 
2459 }
2460 if( find_option("localhost", 0, 0)!=0 ){
2461 flags |= HTTP_SERVER_LOCALHOST;
2462 }
2463
@@ -2515,11 +2566,10 @@
2515 if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
2516 db_close(1);
2517 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
2518 fossil_fatal("unable to listen on TCP socket %d", iPort);
2519 }
2520 g.sslNotAvailable = 1;
2521 g.httpIn = stdin;
2522 g.httpOut = stdout;
2523 if( g.fHttpTrace || g.fSqlTrace ){
2524 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
2525 }
2526
--- src/main.c
+++ src/main.c
@@ -1009,10 +1009,83 @@
1009 const char *get_version(){
1010 static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
1011 MANIFEST_DATE " UTC";
1012 return version;
1013 }
1014
1015 /*
1016 ** This function populates a blob with version information. It is used by
1017 ** the "version" command and "test-version" web page. It assumes the blob
1018 ** passed to it is uninitialized; otherwise, it will leak memory.
1019 */
1020 static void get_version_blob(
1021 Blob *pOut, /* Write the manifest here */
1022 int bVerbose /* Non-zero for full information. */
1023 ){
1024 #if defined(FOSSIL_ENABLE_TCL)
1025 int rc;
1026 const char *zRc;
1027 #endif
1028 blob_zero(pOut);
1029 blob_appendf(pOut, "This is fossil version %s\n", get_version());
1030 if( !bVerbose ) return;
1031 blob_appendf(pOut, "Compiled on %s %s using %s (%d-bit)\n",
1032 __DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
1033 blob_appendf(pOut, "SQLite %s %.30s\n", sqlite3_libversion(),
1034 sqlite3_sourceid());
1035 blob_appendf(pOut, "Schema version %s\n", AUX_SCHEMA_MAX);
1036 #if defined(FOSSIL_ENABLE_MINIZ)
1037 blob_appendf(pOut, "miniz %s, loaded %s\n", MZ_VERSION, mz_version());
1038 #else
1039 blob_appendf(pOut, "zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
1040 #endif
1041 #if defined(FOSSIL_ENABLE_SSL)
1042 blob_appendf(pOut, "SSL (%s)\n", SSLeay_version(SSLEAY_VERSION));
1043 #endif
1044 #if defined(FOSSIL_ENABLE_LEGACY_MV_RM)
1045 blob_append(pOut, "LEGACY_MV_RM\n", -1);
1046 #endif
1047 #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS)
1048 blob_append(pOut, "EXEC_REL_PATHS\n", -1);
1049 #endif
1050 #if defined(FOSSIL_ENABLE_TH1_DOCS)
1051 blob_append(pOut, "TH1_DOCS\n", -1);
1052 #endif
1053 #if defined(FOSSIL_ENABLE_TH1_HOOKS)
1054 blob_append(pOut, "TH1_HOOKS\n", -1);
1055 #endif
1056 #if defined(FOSSIL_ENABLE_TCL)
1057 Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
1058 rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
1059 zRc = Th_ReturnCodeName(rc, 0);
1060 blob_appendf(pOut, "TCL (Tcl %s, loaded %s: %s)\n",
1061 TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
1062 );
1063 #endif
1064 #if defined(USE_TCL_STUBS)
1065 blob_append(pOut, "USE_TCL_STUBS\n", -1);
1066 #endif
1067 #if defined(FOSSIL_ENABLE_TCL_STUBS)
1068 blob_append(pOut, "TCL_STUBS\n", -1);
1069 #endif
1070 #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
1071 blob_append(pOut, "TCL_PRIVATE_STUBS\n", -1);
1072 #endif
1073 #if defined(FOSSIL_ENABLE_JSON)
1074 blob_appendf(pOut, "JSON (API %s)\n", FOSSIL_JSON_API_VERSION);
1075 #endif
1076 #if defined(BROKEN_MINGW_CMDLINE)
1077 blob_append(pOut, "MBCS_COMMAND_LINE\n", -1);
1078 #else
1079 blob_append(pOut, "UNICODE_COMMAND_LINE\n", -1);
1080 #endif
1081 #if defined(FOSSIL_DYNAMIC_BUILD)
1082 blob_append(pOut, "DYNAMIC_BUILD\n", -1);
1083 #else
1084 blob_append(pOut, "STATIC_BUILD\n", -1);
1085 #endif
1086 }
1087
1088 /*
1089 ** This function returns the user-agent string for Fossil, for
1090 ** use in HTTP(S) requests.
1091 */
@@ -1019,10 +1092,11 @@
1092 const char *get_user_agent(){
1093 static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
1094 " " MANIFEST_VERSION ")";
1095 return version;
1096 }
1097
1098
1099 /*
1100 ** COMMAND: version
1101 **
1102 ** Usage: %fossil version ?-verbose|-v?
@@ -1031,80 +1105,42 @@
1105 ** If the verbose option is specified, additional details will
1106 ** be output about what optional features this binary was compiled
1107 ** with
1108 */
1109 void version_cmd(void){
1110 Blob versionInfo;
1111 int verboseFlag = find_option("verbose","v",0)!=0;
 
 
1112
1113 /* We should be done with options.. */
1114 verify_all_options();
1115 get_version_blob(&versionInfo, verboseFlag);
1116 fossil_print("%s", blob_str(&versionInfo));
1117 }
1118
1119
1120 /*
1121 ** WEBPAGE: test-version
1122 **
1123 ** Show the version information for Fossil.
1124 **
1125 ** Query parameters:
1126 **
1127 ** verbose Show all available details.
1128 */
1129 void test_version_page(void){
1130 Blob versionInfo;
1131 int verboseFlag;
1132
1133 login_check_credentials();
1134 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1135 verboseFlag = P("verbose")!=0;
1136 style_header("Version Information");
1137 get_version_blob(&versionInfo, verboseFlag);
1138 @ <blockquote><pre>
1139 @ %h(blob_str(&versionInfo))
1140 @ </pre></blockquote>
1141 style_footer();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1142 }
1143
1144
1145 /*
1146 ** COMMAND: help
@@ -1361,11 +1397,17 @@
1397
1398 if( g.zBaseURL!=0 ) return;
1399 if( zAltBase ){
1400 int i, n, c;
1401 g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
1402 if( strncmp(g.zTop, "http://", 7)==0 ){
1403 /* it is HTTP, replace prefix with HTTPS. */
1404 g.zHttpsURL = mprintf("https://%s", &g.zTop[7]);
1405 }else if( strncmp(g.zTop, "https://", 8)==0 ){
1406 /* it is already HTTPS, use it. */
1407 g.zHttpsURL = mprintf("%s", g.zTop);
1408 }else{
1409 fossil_fatal("argument to --baseurl should be 'http://host/path'"
1410 " or 'https://host/path'");
1411 }
1412 for(i=n=0; (c = g.zTop[i])!=0; i++){
1413 if( c=='/' ){
@@ -2393,11 +2435,13 @@
2435 ** --create Create a new REPOSITORY if it does not already exist
2436 ** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
2437 ** --files GLOBLIST Comma-separated list of glob patterns for static files
2438 ** --localauth enable automatic login for requests from localhost
2439 ** --localhost listen on 127.0.0.1 only (always true for "ui")
2440 ** --https signal a request coming in via https
2441 ** --nojail Drop root privileges but do not enter the chroot jail
2442 ** --nossl signal that no SSL connections are available
2443 ** --notfound URL Redirect
2444 ** -P|--port TCPPORT listen to request on port TCPPORT
2445 ** --th-trace trace TH1 execution (for debugging purposes)
2446 ** --repolist If REPOSITORY is dir, URL "/" lists repos.
2447 ** --scgi Accept SCGI rather than HTTP
@@ -2454,10 +2498,17 @@
2498 zAltBase = find_option("baseurl", 0, 1);
2499 fCreate = find_option("create",0,0)!=0;
2500 if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
2501 if( zAltBase ){
2502 set_base_url(zAltBase);
2503 }
2504 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
2505 if( find_option("https",0,0)!=0 ){
2506 cgi_replace_parameter("HTTPS","on");
2507 }else{
2508 /* without --https, defaults to not available. */
2509 g.sslNotAvailable = 1;
2510 }
2511 if( find_option("localhost", 0, 0)!=0 ){
2512 flags |= HTTP_SERVER_LOCALHOST;
2513 }
2514
@@ -2515,11 +2566,10 @@
2566 if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
2567 db_close(1);
2568 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
2569 fossil_fatal("unable to listen on TCP socket %d", iPort);
2570 }
 
2571 g.httpIn = stdin;
2572 g.httpOut = stdout;
2573 if( g.fHttpTrace || g.fSqlTrace ){
2574 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
2575 }
2576
+12 -2
--- src/main.mk
+++ src/main.mk
@@ -508,15 +508,25 @@
508508
# source tree should be used; otherwise, it should not.
509509
MINIZ_OBJ.0 =
510510
MINIZ_OBJ.1 = $(OBJDIR)/miniz.o
511511
MINIZ_OBJ. = $(MINIZ_OBJ.0)
512512
513
+# The USE_LINENOISE variable may be undefined, set to 0, or set
514
+# to 1. If it is set to 0, then there is no need to build or link
515
+# the linenoise.o object.
516
+LINENOISE_DEF.0 =
517
+LINENOISE_DEF.1 = -DHAVE_LINENOISE
518
+LINENOISE_DEF. = $(LINENOISE_DEF.0)
519
+LINENOISE_OBJ.0 =
520
+LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
521
+LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
522
+
513523
514524
EXTRAOBJ = \
515525
$(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
516526
$(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) \
517
- $(OBJDIR)/linenoise.o \
527
+ $(LINENOISE_OBJ.$(USE_LINENOISE)) \
518528
$(OBJDIR)/shell.o \
519529
$(OBJDIR)/th.o \
520530
$(OBJDIR)/th_lang.o \
521531
$(OBJDIR)/th_tcl.o \
522532
$(OBJDIR)/cson_amalgamation.o
@@ -1623,11 +1633,11 @@
16231633
16241634
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
16251635
$(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $@
16261636
16271637
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1628
- $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -DHAVE_LINENOISE -c $(SRCDIR)/shell.c -o $@
1638
+ $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(LINENOISE_DEF.$(USE_LINENOISE)) -c $(SRCDIR)/shell.c -o $@
16291639
16301640
$(OBJDIR)/linenoise.o: $(SRCDIR)/linenoise.c $(SRCDIR)/linenoise.h
16311641
$(XTCC) -c $(SRCDIR)/linenoise.c -o $@
16321642
16331643
$(OBJDIR)/th.o: $(SRCDIR)/th.c
16341644
--- src/main.mk
+++ src/main.mk
@@ -508,15 +508,25 @@
508 # source tree should be used; otherwise, it should not.
509 MINIZ_OBJ.0 =
510 MINIZ_OBJ.1 = $(OBJDIR)/miniz.o
511 MINIZ_OBJ. = $(MINIZ_OBJ.0)
512
 
 
 
 
 
 
 
 
 
 
513
514 EXTRAOBJ = \
515 $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
516 $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) \
517 $(OBJDIR)/linenoise.o \
518 $(OBJDIR)/shell.o \
519 $(OBJDIR)/th.o \
520 $(OBJDIR)/th_lang.o \
521 $(OBJDIR)/th_tcl.o \
522 $(OBJDIR)/cson_amalgamation.o
@@ -1623,11 +1633,11 @@
1623
1624 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1625 $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $@
1626
1627 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1628 $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -DHAVE_LINENOISE -c $(SRCDIR)/shell.c -o $@
1629
1630 $(OBJDIR)/linenoise.o: $(SRCDIR)/linenoise.c $(SRCDIR)/linenoise.h
1631 $(XTCC) -c $(SRCDIR)/linenoise.c -o $@
1632
1633 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1634
--- src/main.mk
+++ src/main.mk
@@ -508,15 +508,25 @@
508 # source tree should be used; otherwise, it should not.
509 MINIZ_OBJ.0 =
510 MINIZ_OBJ.1 = $(OBJDIR)/miniz.o
511 MINIZ_OBJ. = $(MINIZ_OBJ.0)
512
513 # The USE_LINENOISE variable may be undefined, set to 0, or set
514 # to 1. If it is set to 0, then there is no need to build or link
515 # the linenoise.o object.
516 LINENOISE_DEF.0 =
517 LINENOISE_DEF.1 = -DHAVE_LINENOISE
518 LINENOISE_DEF. = $(LINENOISE_DEF.0)
519 LINENOISE_OBJ.0 =
520 LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
521 LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
522
523
524 EXTRAOBJ = \
525 $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
526 $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) \
527 $(LINENOISE_OBJ.$(USE_LINENOISE)) \
528 $(OBJDIR)/shell.o \
529 $(OBJDIR)/th.o \
530 $(OBJDIR)/th_lang.o \
531 $(OBJDIR)/th_tcl.o \
532 $(OBJDIR)/cson_amalgamation.o
@@ -1623,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $@
1636
1637 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1638 $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(LINENOISE_DEF.$(USE_LINENOISE)) -c $(SRCDIR)/shell.c -o $@
1639
1640 $(OBJDIR)/linenoise.o: $(SRCDIR)/linenoise.c $(SRCDIR)/linenoise.h
1641 $(XTCC) -c $(SRCDIR)/linenoise.c -o $@
1642
1643 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1644
+15 -5
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -337,17 +337,27 @@
337337
# set to 1. If it is set to 1, the miniz library included in the
338338
# source tree should be used; otherwise, it should not.
339339
MINIZ_OBJ.0 =
340340
MINIZ_OBJ.1 = $(OBJDIR)/miniz.o
341341
MINIZ_OBJ. = $(MINIZ_OBJ.0)
342
+
343
+# The USE_LINENOISE variable may be undefined, set to 0, or set
344
+# to 1. If it is set to 0, then there is no need to build or link
345
+# the linenoise.o object.
346
+LINENOISE_DEF.0 =
347
+LINENOISE_DEF.1 = -DHAVE_LINENOISE
348
+LINENOISE_DEF. = $(LINENOISE_DEF.0)
349
+LINENOISE_OBJ.0 =
350
+LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
351
+LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
342352
}]
343353
344354
writeln [string map [list <<<NEXT_LINE>>> \\] {
345355
EXTRAOBJ = <<<NEXT_LINE>>>
346356
$(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) <<<NEXT_LINE>>>
347357
$(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) <<<NEXT_LINE>>>
348
- $(OBJDIR)/linenoise.o <<<NEXT_LINE>>>
358
+ $(LINENOISE_OBJ.$(USE_LINENOISE)) <<<NEXT_LINE>>>
349359
$(OBJDIR)/shell.o <<<NEXT_LINE>>>
350360
$(OBJDIR)/th.o <<<NEXT_LINE>>>
351361
$(OBJDIR)/th_lang.o <<<NEXT_LINE>>>
352362
$(OBJDIR)/th_tcl.o <<<NEXT_LINE>>>
353363
$(OBJDIR)/cson_amalgamation.o
@@ -404,11 +414,11 @@
404414
405415
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
406416
writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$@\n"
407417
408418
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
409
-writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -DHAVE_LINENOISE -c \$(SRCDIR)/shell.c -o \$@\n"
419
+writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) \$(LINENOISE_DEF.\$(USE_LINENOISE)) -c \$(SRCDIR)/shell.c -o \$@\n"
410420
411421
writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR)/linenoise.c \$(SRCDIR)/linenoise.h"
412422
writeln "\t\$(XTCC) -c \$(SRCDIR)/linenoise.c -o \$@\n"
413423
414424
writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
@@ -607,11 +617,11 @@
607617
#### The directories where the OpenSSL include and library files are located.
608618
# The recommended usage here is to use the Sysinternals junction tool
609619
# to create a hard link between an "openssl-1.x" sub-directory of the
610620
# Fossil source code directory and the target OpenSSL source directory.
611621
#
612
-OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2e
622
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2f
613623
OPENSSLINCDIR = $(OPENSSLDIR)/include
614624
OPENSSLLIBDIR = $(OPENSSLDIR)
615625
616626
#### Either the directory where the Tcl library is installed or the Tcl
617627
# source code directory resides (depending on the value of the macro
@@ -1030,11 +1040,11 @@
10301040
APPTARGETS += openssl
10311041
endif
10321042
10331043
$(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
10341044
$(CODECHECK1) $(TRANS_SRC)
1035
- $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
1045
+ $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB)
10361046
10371047
# This rule prevents make from using its default rules to try build
10381048
# an executable named "manifest" out of the file named "manifest.c"
10391049
#
10401050
$(SRCDIR)/../manifest:
@@ -1396,11 +1406,11 @@
13961406
!ifndef FOSSIL_ENABLE_WINXP
13971407
FOSSIL_ENABLE_WINXP = 0
13981408
!endif
13991409
14001410
!if $(FOSSIL_ENABLE_SSL)!=0
1401
-SSLDIR = $(B)\compat\openssl-1.0.2e
1411
+SSLDIR = $(B)\compat\openssl-1.0.2f
14021412
SSLINCDIR = $(SSLDIR)\inc32
14031413
!if $(FOSSIL_DYNAMIC_BUILD)!=0
14041414
SSLLIBDIR = $(SSLDIR)\out32dll
14051415
!else
14061416
SSLLIBDIR = $(SSLDIR)\out32
14071417
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -337,17 +337,27 @@
337 # set to 1. If it is set to 1, the miniz library included in the
338 # source tree should be used; otherwise, it should not.
339 MINIZ_OBJ.0 =
340 MINIZ_OBJ.1 = $(OBJDIR)/miniz.o
341 MINIZ_OBJ. = $(MINIZ_OBJ.0)
 
 
 
 
 
 
 
 
 
 
342 }]
343
344 writeln [string map [list <<<NEXT_LINE>>> \\] {
345 EXTRAOBJ = <<<NEXT_LINE>>>
346 $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) <<<NEXT_LINE>>>
347 $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) <<<NEXT_LINE>>>
348 $(OBJDIR)/linenoise.o <<<NEXT_LINE>>>
349 $(OBJDIR)/shell.o <<<NEXT_LINE>>>
350 $(OBJDIR)/th.o <<<NEXT_LINE>>>
351 $(OBJDIR)/th_lang.o <<<NEXT_LINE>>>
352 $(OBJDIR)/th_tcl.o <<<NEXT_LINE>>>
353 $(OBJDIR)/cson_amalgamation.o
@@ -404,11 +414,11 @@
404
405 writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
406 writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$@\n"
407
408 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
409 writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -DHAVE_LINENOISE -c \$(SRCDIR)/shell.c -o \$@\n"
410
411 writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR)/linenoise.c \$(SRCDIR)/linenoise.h"
412 writeln "\t\$(XTCC) -c \$(SRCDIR)/linenoise.c -o \$@\n"
413
414 writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
@@ -607,11 +617,11 @@
607 #### The directories where the OpenSSL include and library files are located.
608 # The recommended usage here is to use the Sysinternals junction tool
609 # to create a hard link between an "openssl-1.x" sub-directory of the
610 # Fossil source code directory and the target OpenSSL source directory.
611 #
612 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2e
613 OPENSSLINCDIR = $(OPENSSLDIR)/include
614 OPENSSLLIBDIR = $(OPENSSLDIR)
615
616 #### Either the directory where the Tcl library is installed or the Tcl
617 # source code directory resides (depending on the value of the macro
@@ -1030,11 +1040,11 @@
1030 APPTARGETS += openssl
1031 endif
1032
1033 $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
1034 $(CODECHECK1) $(TRANS_SRC)
1035 $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
1036
1037 # This rule prevents make from using its default rules to try build
1038 # an executable named "manifest" out of the file named "manifest.c"
1039 #
1040 $(SRCDIR)/../manifest:
@@ -1396,11 +1406,11 @@
1396 !ifndef FOSSIL_ENABLE_WINXP
1397 FOSSIL_ENABLE_WINXP = 0
1398 !endif
1399
1400 !if $(FOSSIL_ENABLE_SSL)!=0
1401 SSLDIR = $(B)\compat\openssl-1.0.2e
1402 SSLINCDIR = $(SSLDIR)\inc32
1403 !if $(FOSSIL_DYNAMIC_BUILD)!=0
1404 SSLLIBDIR = $(SSLDIR)\out32dll
1405 !else
1406 SSLLIBDIR = $(SSLDIR)\out32
1407
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -337,17 +337,27 @@
337 # set to 1. If it is set to 1, the miniz library included in the
338 # source tree should be used; otherwise, it should not.
339 MINIZ_OBJ.0 =
340 MINIZ_OBJ.1 = $(OBJDIR)/miniz.o
341 MINIZ_OBJ. = $(MINIZ_OBJ.0)
342
343 # The USE_LINENOISE variable may be undefined, set to 0, or set
344 # to 1. If it is set to 0, then there is no need to build or link
345 # the linenoise.o object.
346 LINENOISE_DEF.0 =
347 LINENOISE_DEF.1 = -DHAVE_LINENOISE
348 LINENOISE_DEF. = $(LINENOISE_DEF.0)
349 LINENOISE_OBJ.0 =
350 LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o
351 LINENOISE_OBJ. = $(LINENOISE_OBJ.0)
352 }]
353
354 writeln [string map [list <<<NEXT_LINE>>> \\] {
355 EXTRAOBJ = <<<NEXT_LINE>>>
356 $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) <<<NEXT_LINE>>>
357 $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) <<<NEXT_LINE>>>
358 $(LINENOISE_OBJ.$(USE_LINENOISE)) <<<NEXT_LINE>>>
359 $(OBJDIR)/shell.o <<<NEXT_LINE>>>
360 $(OBJDIR)/th.o <<<NEXT_LINE>>>
361 $(OBJDIR)/th_lang.o <<<NEXT_LINE>>>
362 $(OBJDIR)/th_tcl.o <<<NEXT_LINE>>>
363 $(OBJDIR)/cson_amalgamation.o
@@ -404,11 +414,11 @@
414
415 writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
416 writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$@\n"
417
418 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
419 writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) \$(LINENOISE_DEF.\$(USE_LINENOISE)) -c \$(SRCDIR)/shell.c -o \$@\n"
420
421 writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR)/linenoise.c \$(SRCDIR)/linenoise.h"
422 writeln "\t\$(XTCC) -c \$(SRCDIR)/linenoise.c -o \$@\n"
423
424 writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
@@ -607,11 +617,11 @@
617 #### The directories where the OpenSSL include and library files are located.
618 # The recommended usage here is to use the Sysinternals junction tool
619 # to create a hard link between an "openssl-1.x" sub-directory of the
620 # Fossil source code directory and the target OpenSSL source directory.
621 #
622 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2f
623 OPENSSLINCDIR = $(OPENSSLDIR)/include
624 OPENSSLLIBDIR = $(OPENSSLDIR)
625
626 #### Either the directory where the Tcl library is installed or the Tcl
627 # source code directory resides (depending on the value of the macro
@@ -1030,11 +1040,11 @@
1040 APPTARGETS += openssl
1041 endif
1042
1043 $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
1044 $(CODECHECK1) $(TRANS_SRC)
1045 $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB)
1046
1047 # This rule prevents make from using its default rules to try build
1048 # an executable named "manifest" out of the file named "manifest.c"
1049 #
1050 $(SRCDIR)/../manifest:
@@ -1396,11 +1406,11 @@
1406 !ifndef FOSSIL_ENABLE_WINXP
1407 FOSSIL_ENABLE_WINXP = 0
1408 !endif
1409
1410 !if $(FOSSIL_ENABLE_SSL)!=0
1411 SSLDIR = $(B)\compat\openssl-1.0.2f
1412 SSLINCDIR = $(SSLDIR)\inc32
1413 !if $(FOSSIL_DYNAMIC_BUILD)!=0
1414 SSLLIBDIR = $(SSLDIR)\out32dll
1415 !else
1416 SSLLIBDIR = $(SSLDIR)\out32
1417
+6
--- src/name.c
+++ src/name.c
@@ -670,10 +670,16 @@
670670
** Usage: %fossil whatis NAME
671671
**
672672
** Resolve the symbol NAME into its canonical 40-character SHA1-hash
673673
** artifact name and provide a description of what role that artifact
674674
** plays.
675
+**
676
+** Options:
677
+**
678
+** --type TYPE Only find artifacts of TYPE (one of: 'ci', 't',
679
+** 'w', 'g', or 'e').
680
+** -v|--verbose Provide extra information (such as the RID)
675681
*/
676682
void whatis_cmd(void){
677683
int rid;
678684
const char *zName;
679685
int verboseFlag;
680686
--- src/name.c
+++ src/name.c
@@ -670,10 +670,16 @@
670 ** Usage: %fossil whatis NAME
671 **
672 ** Resolve the symbol NAME into its canonical 40-character SHA1-hash
673 ** artifact name and provide a description of what role that artifact
674 ** plays.
 
 
 
 
 
 
675 */
676 void whatis_cmd(void){
677 int rid;
678 const char *zName;
679 int verboseFlag;
680
--- src/name.c
+++ src/name.c
@@ -670,10 +670,16 @@
670 ** Usage: %fossil whatis NAME
671 **
672 ** Resolve the symbol NAME into its canonical 40-character SHA1-hash
673 ** artifact name and provide a description of what role that artifact
674 ** plays.
675 **
676 ** Options:
677 **
678 ** --type TYPE Only find artifacts of TYPE (one of: 'ci', 't',
679 ** 'w', 'g', or 'e').
680 ** -v|--verbose Provide extra information (such as the RID)
681 */
682 void whatis_cmd(void){
683 int rid;
684 const char *zName;
685 int verboseFlag;
686
+1 -9
--- src/printf.c
+++ src/printf.c
@@ -232,19 +232,11 @@
232232
233233
/*
234234
** The root program. All variations call this core.
235235
**
236236
** INPUTS:
237
-** func This is a pointer to a function taking three arguments
238
-** 1. A pointer to anything. Same as the "arg" parameter.
239
-** 2. A pointer to the list of characters to be output
240
-** (Note, this list is NOT null terminated.)
241
-** 3. An integer number of characters to be output.
242
-** (Note: This number might be zero.)
243
-**
244
-** arg This is the pointer to anything which will be passed as the
245
-** first argument to "func". Use it for whatever you like.
237
+** pBlob This is the blob where the output will be built.
246238
**
247239
** fmt This is the format string, as in the usual print.
248240
**
249241
** ap This is a pointer to a list of arguments. Same as in
250242
** vfprint.
251243
--- src/printf.c
+++ src/printf.c
@@ -232,19 +232,11 @@
232
233 /*
234 ** The root program. All variations call this core.
235 **
236 ** INPUTS:
237 ** func This is a pointer to a function taking three arguments
238 ** 1. A pointer to anything. Same as the "arg" parameter.
239 ** 2. A pointer to the list of characters to be output
240 ** (Note, this list is NOT null terminated.)
241 ** 3. An integer number of characters to be output.
242 ** (Note: This number might be zero.)
243 **
244 ** arg This is the pointer to anything which will be passed as the
245 ** first argument to "func". Use it for whatever you like.
246 **
247 ** fmt This is the format string, as in the usual print.
248 **
249 ** ap This is a pointer to a list of arguments. Same as in
250 ** vfprint.
251
--- src/printf.c
+++ src/printf.c
@@ -232,19 +232,11 @@
232
233 /*
234 ** The root program. All variations call this core.
235 **
236 ** INPUTS:
237 ** pBlob This is the blob where the output will be built.
 
 
 
 
 
 
 
 
238 **
239 ** fmt This is the format string, as in the usual print.
240 **
241 ** ap This is a pointer to a list of arguments. Same as in
242 ** vfprint.
243
+19
--- src/shell.c
+++ src/shell.c
@@ -1919,10 +1919,11 @@
19191919
" LIKE pattern TABLE.\n"
19201920
".timeout MS Try opening locked tables for MS milliseconds\n"
19211921
".timer on|off Turn SQL timer on or off\n"
19221922
".trace FILE|off Output each SQL statement as it is run\n"
19231923
".vfsinfo ?AUX? Information about the top-level VFS\n"
1924
+ ".vfslist List all available VFSes\n"
19241925
".vfsname ?AUX? Print the name of the VFS stack\n"
19251926
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
19261927
" Negative values right-justify\n"
19271928
;
19281929
@@ -4165,10 +4166,28 @@
41654166
utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
41664167
raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
41674168
raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
41684169
raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
41694170
}
4171
+ }
4172
+ }else
4173
+
4174
+ if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
4175
+ sqlite3_vfs *pVfs;
4176
+ sqlite3_vfs *pCurrent = 0;
4177
+ if( p->db ){
4178
+ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
4179
+ }
4180
+ for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
4181
+ utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
4182
+ pVfs==pCurrent ? " <--- CURRENT" : "");
4183
+ raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
4184
+ raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
4185
+ raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4186
+ if( pVfs->pNext ){
4187
+ raw_printf(p->out, "-----------------------------------\n");
4188
+ }
41704189
}
41714190
}else
41724191
41734192
if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
41744193
const char *zDbName = nArg==2 ? azArg[1] : "main";
41754194
--- src/shell.c
+++ src/shell.c
@@ -1919,10 +1919,11 @@
1919 " LIKE pattern TABLE.\n"
1920 ".timeout MS Try opening locked tables for MS milliseconds\n"
1921 ".timer on|off Turn SQL timer on or off\n"
1922 ".trace FILE|off Output each SQL statement as it is run\n"
1923 ".vfsinfo ?AUX? Information about the top-level VFS\n"
 
1924 ".vfsname ?AUX? Print the name of the VFS stack\n"
1925 ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
1926 " Negative values right-justify\n"
1927 ;
1928
@@ -4165,10 +4166,28 @@
4165 utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
4166 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
4167 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
4168 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4169 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4170 }
4171 }else
4172
4173 if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
4174 const char *zDbName = nArg==2 ? azArg[1] : "main";
4175
--- src/shell.c
+++ src/shell.c
@@ -1919,10 +1919,11 @@
1919 " LIKE pattern TABLE.\n"
1920 ".timeout MS Try opening locked tables for MS milliseconds\n"
1921 ".timer on|off Turn SQL timer on or off\n"
1922 ".trace FILE|off Output each SQL statement as it is run\n"
1923 ".vfsinfo ?AUX? Information about the top-level VFS\n"
1924 ".vfslist List all available VFSes\n"
1925 ".vfsname ?AUX? Print the name of the VFS stack\n"
1926 ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
1927 " Negative values right-justify\n"
1928 ;
1929
@@ -4165,10 +4166,28 @@
4166 utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
4167 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
4168 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
4169 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4170 }
4171 }
4172 }else
4173
4174 if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
4175 sqlite3_vfs *pVfs;
4176 sqlite3_vfs *pCurrent = 0;
4177 if( p->db ){
4178 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
4179 }
4180 for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
4181 utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
4182 pVfs==pCurrent ? " <--- CURRENT" : "");
4183 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
4184 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
4185 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4186 if( pVfs->pNext ){
4187 raw_printf(p->out, "-----------------------------------\n");
4188 }
4189 }
4190 }else
4191
4192 if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
4193 const char *zDbName = nArg==2 ? azArg[1] : "main";
4194
+10 -4
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -152,17 +152,21 @@
152152
}
153153
154154
/*
155155
** COMMAND: sqlite3
156156
**
157
-** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
157
+** Usage: %fossil sqlite3 ?FOSSIL_OPTS? ?DATABASE? ?SHELL_OPTS?
158158
**
159
-** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
159
+** Run the standalone sqlite3 command-line shell on DATABASE with SHELL_OPTS.
160160
** If DATABASE is omitted, then the repository that serves the working
161161
** directory is opened. See https://www.sqlite.org/cli.html for additional
162162
** information.
163163
**
164
+** Fossil Options:
165
+**
166
+** --no-repository Skip opening the repository database.
167
+**
164168
** WARNING: Careless use of this command can corrupt a Fossil repository
165169
** in ways that are unrecoverable. Be sure you know what you are doing before
166170
** running any SQL commands that modifies the repository database.
167171
**
168172
** The following extensions to the usual SQLite commands are provided:
@@ -194,12 +198,14 @@
194198
** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
195199
** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
196200
*/
197201
void cmd_sqlite3(void){
198202
extern int sqlite3_shell(int, char**);
199
- db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
200
- db_close(1);
203
+ if( find_option("no-repository", 0, 0)==0 ){
204
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
205
+ db_close(1);
206
+ }
201207
sqlite3_shutdown();
202208
sqlite3_shell(g.argc-1, g.argv+1);
203209
sqlite3_cancel_auto_extension((void(*)(void))sqlcmd_autoinit);
204210
g.db = 0;
205211
g.zMainDbType = 0;
206212
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -152,17 +152,21 @@
152 }
153
154 /*
155 ** COMMAND: sqlite3
156 **
157 ** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
158 **
159 ** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
160 ** If DATABASE is omitted, then the repository that serves the working
161 ** directory is opened. See https://www.sqlite.org/cli.html for additional
162 ** information.
163 **
 
 
 
 
164 ** WARNING: Careless use of this command can corrupt a Fossil repository
165 ** in ways that are unrecoverable. Be sure you know what you are doing before
166 ** running any SQL commands that modifies the repository database.
167 **
168 ** The following extensions to the usual SQLite commands are provided:
@@ -194,12 +198,14 @@
194 ** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
195 ** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
196 */
197 void cmd_sqlite3(void){
198 extern int sqlite3_shell(int, char**);
199 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
200 db_close(1);
 
 
201 sqlite3_shutdown();
202 sqlite3_shell(g.argc-1, g.argv+1);
203 sqlite3_cancel_auto_extension((void(*)(void))sqlcmd_autoinit);
204 g.db = 0;
205 g.zMainDbType = 0;
206
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -152,17 +152,21 @@
152 }
153
154 /*
155 ** COMMAND: sqlite3
156 **
157 ** Usage: %fossil sqlite3 ?FOSSIL_OPTS? ?DATABASE? ?SHELL_OPTS?
158 **
159 ** Run the standalone sqlite3 command-line shell on DATABASE with SHELL_OPTS.
160 ** If DATABASE is omitted, then the repository that serves the working
161 ** directory is opened. See https://www.sqlite.org/cli.html for additional
162 ** information.
163 **
164 ** Fossil Options:
165 **
166 ** --no-repository Skip opening the repository database.
167 **
168 ** WARNING: Careless use of this command can corrupt a Fossil repository
169 ** in ways that are unrecoverable. Be sure you know what you are doing before
170 ** running any SQL commands that modifies the repository database.
171 **
172 ** The following extensions to the usual SQLite commands are provided:
@@ -194,12 +198,14 @@
198 ** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
199 ** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
200 */
201 void cmd_sqlite3(void){
202 extern int sqlite3_shell(int, char**);
203 if( find_option("no-repository", 0, 0)==0 ){
204 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
205 db_close(1);
206 }
207 sqlite3_shutdown();
208 sqlite3_shell(g.argc-1, g.argv+1);
209 sqlite3_cancel_auto_extension((void(*)(void))sqlcmd_autoinit);
210 g.db = 0;
211 g.zMainDbType = 0;
212
+2717 -1298
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
11
/******************************************************************************
22
** This file is an amalgamation of many separate C source files from SQLite
3
-** version 3.10.0. By combining all the individual C code files into this
3
+** version 3.11.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.
@@ -119,10 +119,12 @@
119119
#define SQLITE_ENABLE_LOCKING_STYLE 0
120120
#define HAVE_UTIME 1
121121
#else
122122
/* This is not VxWorks. */
123123
#define OS_VXWORKS 0
124
+#define HAVE_FCHOWN 1
125
+#define HAVE_READLINK 1
124126
#endif /* defined(_WRS_KERNEL) */
125127
126128
/************** End of vxworks.h *********************************************/
127129
/************** Continuing where we left off in sqliteInt.h ******************/
128130
@@ -323,13 +325,13 @@
323325
**
324326
** See also: [sqlite3_libversion()],
325327
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
326328
** [sqlite_version()] and [sqlite_source_id()].
327329
*/
328
-#define SQLITE_VERSION "3.10.0"
329
-#define SQLITE_VERSION_NUMBER 3010000
330
-#define SQLITE_SOURCE_ID "2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566"
330
+#define SQLITE_VERSION "3.11.0"
331
+#define SQLITE_VERSION_NUMBER 3011000
332
+#define SQLITE_SOURCE_ID "2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1"
331333
332334
/*
333335
** CAPI3REF: Run-Time Library Version Numbers
334336
** KEYWORDS: sqlite3_version, sqlite3_sourceid
335337
**
@@ -1006,12 +1008,17 @@
10061008
** improve performance on some systems.
10071009
**
10081010
** <li>[[SQLITE_FCNTL_FILE_POINTER]]
10091011
** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
10101012
** to the [sqlite3_file] object associated with a particular database
1011
-** connection. See the [sqlite3_file_control()] documentation for
1012
-** additional information.
1013
+** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
1014
+**
1015
+** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
1016
+** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
1017
+** to the [sqlite3_file] object associated with the journal file (either
1018
+** the [rollback journal] or the [write-ahead log]) for a particular database
1019
+** connection. See also [SQLITE_FCNTL_FILE_POINTER].
10131020
**
10141021
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
10151022
** No longer in use.
10161023
**
10171024
** <li>[[SQLITE_FCNTL_SYNC]]
@@ -1222,10 +1229,11 @@
12221229
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
12231230
#define SQLITE_FCNTL_WAL_BLOCK 24
12241231
#define SQLITE_FCNTL_ZIPVFS 25
12251232
#define SQLITE_FCNTL_RBU 26
12261233
#define SQLITE_FCNTL_VFS_POINTER 27
1234
+#define SQLITE_FCNTL_JOURNAL_POINTER 28
12271235
12281236
/* deprecated names */
12291237
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
12301238
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
12311239
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -8399,10 +8407,13 @@
83998407
** If parameter iCol is greater than or equal to the number of columns
84008408
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
84018409
** an OOM condition or IO error), an appropriate SQLite error code is
84028410
** returned.
84038411
**
8412
+** This function may be quite inefficient if used with an FTS5 table
8413
+** created with the "columnsize=0" option.
8414
+**
84048415
** xColumnText:
84058416
** This function attempts to retrieve the text of column iCol of the
84068417
** current document. If successful, (*pz) is set to point to a buffer
84078418
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
84088419
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -8419,18 +8430,32 @@
84198430
** xInstCount:
84208431
** Set *pnInst to the total number of occurrences of all phrases within
84218432
** the query within the current row. Return SQLITE_OK if successful, or
84228433
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
84238434
**
8435
+** This API can be quite slow if used with an FTS5 table created with the
8436
+** "detail=none" or "detail=column" option. If the FTS5 table is created
8437
+** with either "detail=none" or "detail=column" and "content=" option
8438
+** (i.e. if it is a contentless table), then this API always returns 0.
8439
+**
84248440
** xInst:
84258441
** Query for the details of phrase match iIdx within the current row.
84268442
** Phrase matches are numbered starting from zero, so the iIdx argument
84278443
** should be greater than or equal to zero and smaller than the value
84288444
** output by xInstCount().
8445
+**
8446
+** Usually, output parameter *piPhrase is set to the phrase number, *piCol
8447
+** to the column in which it occurs and *piOff the token offset of the
8448
+** first token of the phrase. The exception is if the table was created
8449
+** with the offsets=0 option specified. In this case *piOff is always
8450
+** set to -1.
84298451
**
84308452
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
84318453
** if an error occurs.
8454
+**
8455
+** This API can be quite slow if used with an FTS5 table created with the
8456
+** "detail=none" or "detail=column" option.
84328457
**
84338458
** xRowid:
84348459
** Returns the rowid of the current row.
84358460
**
84368461
** xTokenize:
@@ -8511,25 +8536,63 @@
85118536
** through instances of phrase iPhrase, use the following code:
85128537
**
85138538
** Fts5PhraseIter iter;
85148539
** int iCol, iOff;
85158540
** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
8516
-** iOff>=0;
8541
+** iCol>=0;
85178542
** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
85188543
** ){
85198544
** // An instance of phrase iPhrase at offset iOff of column iCol
85208545
** }
85218546
**
85228547
** The Fts5PhraseIter structure is defined above. Applications should not
85238548
** modify this structure directly - it should only be used as shown above
8524
-** with the xPhraseFirst() and xPhraseNext() API methods.
8549
+** with the xPhraseFirst() and xPhraseNext() API methods (and by
8550
+** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
8551
+**
8552
+** This API can be quite slow if used with an FTS5 table created with the
8553
+** "detail=none" or "detail=column" option. If the FTS5 table is created
8554
+** with either "detail=none" or "detail=column" and "content=" option
8555
+** (i.e. if it is a contentless table), then this API always iterates
8556
+** through an empty set (all calls to xPhraseFirst() set iCol to -1).
85258557
**
85268558
** xPhraseNext()
85278559
** See xPhraseFirst above.
8560
+**
8561
+** xPhraseFirstColumn()
8562
+** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
8563
+** and xPhraseNext() APIs described above. The difference is that instead
8564
+** of iterating through all instances of a phrase in the current row, these
8565
+** APIs are used to iterate through the set of columns in the current row
8566
+** that contain one or more instances of a specified phrase. For example:
8567
+**
8568
+** Fts5PhraseIter iter;
8569
+** int iCol;
8570
+** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
8571
+** iCol>=0;
8572
+** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
8573
+** ){
8574
+** // Column iCol contains at least one instance of phrase iPhrase
8575
+** }
8576
+**
8577
+** This API can be quite slow if used with an FTS5 table created with the
8578
+** "detail=none" option. If the FTS5 table is created with either
8579
+** "detail=none" "content=" option (i.e. if it is a contentless table),
8580
+** then this API always iterates through an empty set (all calls to
8581
+** xPhraseFirstColumn() set iCol to -1).
8582
+**
8583
+** The information accessed using this API and its companion
8584
+** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
8585
+** (or xInst/xInstCount). The chief advantage of this API is that it is
8586
+** significantly more efficient than those alternatives when used with
8587
+** "detail=column" tables.
8588
+**
8589
+** xPhraseNextColumn()
8590
+** See xPhraseFirstColumn above.
85288591
*/
85298592
struct Fts5ExtensionApi {
8530
- int iVersion; /* Currently always set to 1 */
8593
+ int iVersion; /* Currently always set to 3 */
85318594
85328595
void *(*xUserData)(Fts5Context*);
85338596
85348597
int (*xColumnCount)(Fts5Context*);
85358598
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -8555,12 +8618,15 @@
85558618
int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
85568619
);
85578620
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
85588621
void *(*xGetAuxdata)(Fts5Context*, int bClear);
85598622
8560
- void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
8623
+ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
85618624
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
8625
+
8626
+ int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
8627
+ void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
85628628
};
85638629
85648630
/*
85658631
** CUSTOM AUXILIARY FUNCTIONS
85668632
*************************************************************************/
@@ -9340,10 +9406,25 @@
93409406
#else
93419407
# define ALWAYS(X) (X)
93429408
# define NEVER(X) (X)
93439409
#endif
93449410
9411
+/*
9412
+** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
9413
+** defined. We need to defend against those failures when testing with
9414
+** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
9415
+** during a normal build. The following macro can be used to disable tests
9416
+** that are always false except when SQLITE_TEST_REALLOC_STRESS is set.
9417
+*/
9418
+#if defined(SQLITE_TEST_REALLOC_STRESS)
9419
+# define ONLY_IF_REALLOC_STRESS(X) (X)
9420
+#elif !defined(NDEBUG)
9421
+# define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0)
9422
+#else
9423
+# define ONLY_IF_REALLOC_STRESS(X) (0)
9424
+#endif
9425
+
93459426
/*
93469427
** Declarations used for tracing the operating system interfaces.
93479428
*/
93489429
#if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \
93499430
(defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
@@ -9976,14 +10057,10 @@
997610057
/*
997710058
** Default maximum size of memory used by memory-mapped I/O in the VFS
997810059
*/
997910060
#ifdef __APPLE__
998010061
# include <TargetConditionals.h>
9981
-# if TARGET_OS_IPHONE
9982
-# undef SQLITE_MAX_MMAP_SIZE
9983
-# define SQLITE_MAX_MMAP_SIZE 0
9984
-# endif
998510062
#endif
998610063
#ifndef SQLITE_MAX_MMAP_SIZE
998710064
# if defined(__linux__) \
998810065
|| defined(_WIN32) \
998910066
|| (defined(__APPLE__) && defined(__MACH__)) \
@@ -10479,19 +10556,21 @@
1047910556
** Enter and Leave procedures no-ops.
1048010557
*/
1048110558
#ifndef SQLITE_OMIT_SHARED_CACHE
1048210559
SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*);
1048310560
SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*);
10561
+SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
10562
+SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
1048410563
#else
1048510564
# define sqlite3BtreeEnter(X)
1048610565
# define sqlite3BtreeEnterAll(X)
10566
+# define sqlite3BtreeSharable(X) 0
10567
+# define sqlite3BtreeEnterCursor(X)
1048710568
#endif
1048810569
1048910570
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
10490
-SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
1049110571
SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*);
10492
-SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
1049310572
SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*);
1049410573
SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*);
1049510574
#ifndef NDEBUG
1049610575
/* These routines are used inside assert() statements only. */
1049710576
SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*);
@@ -10498,13 +10577,11 @@
1049810577
SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*);
1049910578
SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
1050010579
#endif
1050110580
#else
1050210581
10503
-# define sqlite3BtreeSharable(X) 0
1050410582
# define sqlite3BtreeLeave(X)
10505
-# define sqlite3BtreeEnterCursor(X)
1050610583
# define sqlite3BtreeLeaveCursor(X)
1050710584
# define sqlite3BtreeLeaveAll(X)
1050810585
1050910586
# define sqlite3BtreeHoldsMutex(X) 1
1051010587
# define sqlite3BtreeHoldsAllMutexes(X) 1
@@ -10899,19 +10976,24 @@
1089910976
SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
1090010977
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
1090110978
SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
1090210979
SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
1090310980
SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
10904
-SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
10981
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
10982
+SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
10983
+#else
10984
+# define sqlite3VdbeVerifyNoMallocRequired(A,B)
10985
+#endif
10986
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
1090510987
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
1090610988
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
1090710989
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
1090810990
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
1090910991
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
1091010992
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
1091110993
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
10912
-SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
10994
+SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
1091310995
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
1091410996
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
1091510997
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
1091610998
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
1091710999
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
@@ -11215,10 +11297,11 @@
1121511297
#endif
1121611298
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
1121711299
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
1121811300
SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
1121911301
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
11302
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
1122011303
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
1122111304
SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
1122211305
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
1122311306
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
1122411307
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
@@ -11309,10 +11392,12 @@
1130911392
#define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before
1131011393
** writing this page to the database */
1131111394
#define PGHDR_NEED_READ 0x010 /* Content is unread */
1131211395
#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
1131311396
#define PGHDR_MMAP 0x040 /* This is an mmap page object */
11397
+
11398
+#define PGHDR_WAL_APPEND 0x080 /* Appended to wal file */
1131411399
1131511400
/* Initialize and shutdown the page cache subsystem */
1131611401
SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
1131711402
SQLITE_PRIVATE void sqlite3PcacheShutdown(void);
1131811403
@@ -12162,13 +12247,12 @@
1216212247
struct FuncDef {
1216312248
i16 nArg; /* Number of arguments. -1 means unlimited */
1216412249
u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
1216512250
void *pUserData; /* User data parameter */
1216612251
FuncDef *pNext; /* Next function with same name */
12167
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
12168
- void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
12169
- void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */
12252
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
12253
+ void (*xFinalize)(sqlite3_context*); /* Agg finalizer */
1217012254
char *zName; /* SQL name of the function. */
1217112255
FuncDef *pHash; /* Next with a different name but the same hash */
1217212256
FuncDestructor *pDestructor; /* Reference counted destructor function */
1217312257
};
1217412258
@@ -12247,32 +12331,32 @@
1224712331
** FuncDef.flags variable is set to the value passed as the flags
1224812332
** parameter.
1224912333
*/
1225012334
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
1225112335
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12252
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12336
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
1225312337
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
1225412338
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12255
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12339
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
1225612340
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
1225712341
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12258
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12342
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
1225912343
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
1226012344
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
12261
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12345
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
1226212346
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
1226312347
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12264
- pArg, 0, xFunc, 0, 0, #zName, 0, 0}
12348
+ pArg, 0, xFunc, 0, #zName, 0, 0}
1226512349
#define LIKEFUNC(zName, nArg, arg, flags) \
1226612350
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
12267
- (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
12351
+ (void *)arg, 0, likeFunc, 0, #zName, 0, 0}
1226812352
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
1226912353
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
12270
- SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
12354
+ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
1227112355
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
1227212356
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
12273
- SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
12357
+ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
1227412358
1227512359
/*
1227612360
** All current savepoints are stored in a linked list starting at
1227712361
** sqlite3.pSavepoint. The first element in the list is the most recently
1227812362
** opened savepoint. Savepoints are added to the list by the vdbe
@@ -13579,11 +13663,11 @@
1357913663
** each recursion. The boundary between these two regions is determined
1358013664
** using offsetof(Parse,nVar) so the nVar field must be the first field
1358113665
** in the recursive region.
1358213666
************************************************************************/
1358313667
13584
- int nVar; /* Number of '?' variables seen in the SQL so far */
13668
+ ynVar nVar; /* Number of '?' variables seen in the SQL so far */
1358513669
int nzVar; /* Number of available slots in azVar[] */
1358613670
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
1358713671
u8 explain; /* True if the EXPLAIN flag is found on the query */
1358813672
#ifndef SQLITE_OMIT_VIRTUALTABLE
1358913673
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
@@ -13861,14 +13945,14 @@
1386113945
1386213946
/*
1386313947
** Context pointer passed down through the tree-walk.
1386413948
*/
1386513949
struct Walker {
13950
+ Parse *pParse; /* Parser context. */
1386613951
int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */
1386713952
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
1386813953
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
13869
- Parse *pParse; /* Parser context. */
1387013954
int walkerDepth; /* Number of subqueries */
1387113955
u8 eCode; /* A small processing code */
1387213956
union { /* Extra data for callback */
1387313957
NameContext *pNC; /* Naming context */
1387413958
int n; /* A counter */
@@ -14135,11 +14219,10 @@
1413514219
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
1413614220
SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
1413714221
SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
1413814222
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
1413914223
SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
14140
-SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int);
1414114224
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
1414214225
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
1414314226
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
1414414227
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
1414514228
SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
@@ -16066,15 +16149,19 @@
1606616149
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
1606716150
SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
1606816151
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
1606916152
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
1607016153
16071
-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
16154
+#if !defined(SQLITE_OMIT_SHARED_CACHE)
1607216155
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
16073
-SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
1607416156
#else
1607516157
# define sqlite3VdbeEnter(X)
16158
+#endif
16159
+
16160
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
16161
+SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
16162
+#else
1607616163
# define sqlite3VdbeLeave(X)
1607716164
#endif
1607816165
1607916166
#ifdef SQLITE_DEBUG
1608016167
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
@@ -16508,52 +16595,68 @@
1650816595
char tzSet; /* Timezone was set explicitly */
1650916596
};
1651016597
1651116598
1651216599
/*
16513
-** Convert zDate into one or more integers. Additional arguments
16514
-** come in groups of 5 as follows:
16515
-**
16516
-** N number of digits in the integer
16517
-** min minimum allowed value of the integer
16518
-** max maximum allowed value of the integer
16519
-** nextC first character after the integer
16520
-** pVal where to write the integers value.
16521
-**
16522
-** Conversions continue until one with nextC==0 is encountered.
16600
+** Convert zDate into one or more integers according to the conversion
16601
+** specifier zFormat.
16602
+**
16603
+** zFormat[] contains 4 characters for each integer converted, except for
16604
+** the last integer which is specified by three characters. The meaning
16605
+** of a four-character format specifiers ABCD is:
16606
+**
16607
+** A: number of digits to convert. Always "2" or "4".
16608
+** B: minimum value. Always "0" or "1".
16609
+** C: maximum value, decoded as:
16610
+** a: 12
16611
+** b: 14
16612
+** c: 24
16613
+** d: 31
16614
+** e: 59
16615
+** f: 9999
16616
+** D: the separator character, or \000 to indicate this is the
16617
+** last number to convert.
16618
+**
16619
+** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would
16620
+** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-".
16621
+** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates
16622
+** the 2-digit day which is the last integer in the set.
16623
+**
1652316624
** The function returns the number of successful conversions.
1652416625
*/
16525
-static int getDigits(const char *zDate, ...){
16626
+static int getDigits(const char *zDate, const char *zFormat, ...){
16627
+ /* The aMx[] array translates the 3rd character of each format
16628
+ ** spec into a max size: a b c d e f */
16629
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
1652616630
va_list ap;
16527
- int val;
16528
- int N;
16529
- int min;
16530
- int max;
16531
- int nextC;
16532
- int *pVal;
1653316631
int cnt = 0;
16534
- va_start(ap, zDate);
16632
+ char nextC;
16633
+ va_start(ap, zFormat);
1653516634
do{
16536
- N = va_arg(ap, int);
16537
- min = va_arg(ap, int);
16538
- max = va_arg(ap, int);
16539
- nextC = va_arg(ap, int);
16540
- pVal = va_arg(ap, int*);
16635
+ char N = zFormat[0] - '0';
16636
+ char min = zFormat[1] - '0';
16637
+ int val = 0;
16638
+ u16 max;
16639
+
16640
+ assert( zFormat[2]>='a' && zFormat[2]<='f' );
16641
+ max = aMx[zFormat[2] - 'a'];
16642
+ nextC = zFormat[3];
1654116643
val = 0;
1654216644
while( N-- ){
1654316645
if( !sqlite3Isdigit(*zDate) ){
1654416646
goto end_getDigits;
1654516647
}
1654616648
val = val*10 + *zDate - '0';
1654716649
zDate++;
1654816650
}
16549
- if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
16651
+ if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){
1655016652
goto end_getDigits;
1655116653
}
16552
- *pVal = val;
16654
+ *va_arg(ap,int*) = val;
1655316655
zDate++;
1655416656
cnt++;
16657
+ zFormat += 4;
1655516658
}while( nextC );
1655616659
end_getDigits:
1655716660
va_end(ap);
1655816661
return cnt;
1655916662
}
@@ -16590,11 +16693,11 @@
1659016693
goto zulu_time;
1659116694
}else{
1659216695
return c!=0;
1659316696
}
1659416697
zDate++;
16595
- if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
16698
+ if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
1659616699
return 1;
1659716700
}
1659816701
zDate += 5;
1659916702
p->tz = sgn*(nMn + nHr*60);
1660016703
zulu_time:
@@ -16611,17 +16714,17 @@
1661116714
** Return 1 if there is a parsing error and 0 on success.
1661216715
*/
1661316716
static int parseHhMmSs(const char *zDate, DateTime *p){
1661416717
int h, m, s;
1661516718
double ms = 0.0;
16616
- if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
16719
+ if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){
1661716720
return 1;
1661816721
}
1661916722
zDate += 5;
1662016723
if( *zDate==':' ){
1662116724
zDate++;
16622
- if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
16725
+ if( getDigits(zDate, "20e", &s)!=1 ){
1662316726
return 1;
1662416727
}
1662516728
zDate += 2;
1662616729
if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){
1662716730
double rScale = 1.0;
@@ -16705,11 +16808,11 @@
1670516808
zDate++;
1670616809
neg = 1;
1670716810
}else{
1670816811
neg = 0;
1670916812
}
16710
- if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
16813
+ if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){
1671116814
return 1;
1671216815
}
1671316816
zDate += 10;
1671416817
while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; }
1671516818
if( parseHhMmSs(zDate, p)==0 ){
@@ -19758,10 +19861,11 @@
1975819861
/*
1975919862
** Mutex to control access to the memory allocation subsystem.
1976019863
*/
1976119864
sqlite3_mutex *mutex;
1976219865
19866
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
1976319867
/*
1976419868
** Performance statistics
1976519869
*/
1976619870
u64 nAlloc; /* Total number of calls to malloc */
1976719871
u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
@@ -19769,10 +19873,11 @@
1976919873
u32 currentOut; /* Current checkout, including internal fragmentation */
1977019874
u32 currentCount; /* Current number of distinct checkouts */
1977119875
u32 maxOut; /* Maximum instantaneous currentOut */
1977219876
u32 maxCount; /* Maximum instantaneous currentCount */
1977319877
u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
19878
+#endif
1977419879
1977519880
/*
1977619881
** Lists of free blocks. aiFreelist[0] is a list of free blocks of
1977719882
** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
1977819883
** aiFreelist[2] holds free blocks of size szAtom*4. And so forth.
@@ -19880,18 +19985,21 @@
1988019985
int iLogsize; /* Log2 of iFullSz/POW2_MIN */
1988119986
1988219987
/* nByte must be a positive */
1988319988
assert( nByte>0 );
1988419989
19990
+ /* No more than 1GiB per allocation */
19991
+ if( nByte > 0x40000000 ) return 0;
19992
+
19993
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
1988519994
/* Keep track of the maximum allocation request. Even unfulfilled
1988619995
** requests are counted */
1988719996
if( (u32)nByte>mem5.maxRequest ){
19888
- /* Abort if the requested allocation size is larger than the largest
19889
- ** power of two that we can represent using 32-bit signed integers. */
19890
- if( nByte > 0x40000000 ) return 0;
1989119997
mem5.maxRequest = nByte;
1989219998
}
19999
+#endif
20000
+
1989320001
1989420002
/* Round nByte up to the next valid power of two */
1989520003
for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){}
1989620004
1989720005
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
@@ -19914,18 +20022,20 @@
1991420022
mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
1991520023
memsys5Link(i+newSize, iBin);
1991620024
}
1991720025
mem5.aCtrl[i] = iLogsize;
1991820026
20027
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
1991920028
/* Update allocator performance statistics. */
1992020029
mem5.nAlloc++;
1992120030
mem5.totalAlloc += iFullSz;
1992220031
mem5.totalExcess += iFullSz - nByte;
1992320032
mem5.currentCount++;
1992420033
mem5.currentOut += iFullSz;
1992520034
if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
1992620035
if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
20036
+#endif
1992720037
1992820038
#ifdef SQLITE_DEBUG
1992920039
/* Make sure the allocated memory does not assume that it is set to zero
1993020040
** or retains a value from a previous allocation */
1993120041
memset(&mem5.zPool[i*mem5.szAtom], 0xAA, iFullSz);
@@ -19956,16 +20066,19 @@
1995620066
size = 1<<iLogsize;
1995720067
assert( iBlock+size-1<(u32)mem5.nBlock );
1995820068
1995920069
mem5.aCtrl[iBlock] |= CTRL_FREE;
1996020070
mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
20071
+
20072
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
1996120073
assert( mem5.currentCount>0 );
1996220074
assert( mem5.currentOut>=(size*mem5.szAtom) );
1996320075
mem5.currentCount--;
1996420076
mem5.currentOut -= size*mem5.szAtom;
1996520077
assert( mem5.currentOut>0 || mem5.currentCount==0 );
1996620078
assert( mem5.currentCount>0 || mem5.currentOut==0 );
20079
+#endif
1996720080
1996820081
mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
1996920082
while( ALWAYS(iLogsize<LOGMAX) ){
1997020083
int iBuddy;
1997120084
if( (iBlock>>iLogsize) & 1 ){
@@ -22281,12 +22394,13 @@
2228122394
}
2228222395
return p;
2228322396
}
2228422397
2228522398
/*
22286
-** Allocate and zero memory. If the allocation fails, make
22287
-** the mallocFailed flag in the connection pointer.
22399
+** Allocate memory, either lookaside (if possible) or heap.
22400
+** If the allocation fails, set the mallocFailed flag in
22401
+** the connection pointer.
2228822402
**
2228922403
** If db!=0 and db->mallocFailed is true (indicating a prior malloc
2229022404
** failure on the same database connection) then always return 0.
2229122405
** Hence for a particular database connection, once malloc starts
2229222406
** failing, it fails consistently until mallocFailed is reset.
@@ -22298,12 +22412,12 @@
2229822412
** if( b ) a[10] = 9;
2229922413
**
2230022414
** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
2230122415
** that all prior mallocs (ex: "a") worked too.
2230222416
*/
22417
+static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n);
2230322418
SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
22304
- void *p;
2230522419
assert( db==0 || sqlite3_mutex_held(db->mutex) );
2230622420
assert( db==0 || db->pnBytesFreed==0 );
2230722421
#ifndef SQLITE_OMIT_LOOKASIDE
2230822422
if( db ){
2230922423
LookasideSlot *pBuf;
@@ -22329,11 +22443,14 @@
2232922443
#else
2233022444
if( db && db->mallocFailed ){
2233122445
return 0;
2233222446
}
2233322447
#endif
22334
- p = sqlite3Malloc(n);
22448
+ return dbMallocRawFinish(db, n);
22449
+}
22450
+static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
22451
+ void *p = sqlite3Malloc(n);
2233522452
if( !p && db ){
2233622453
db->mallocFailed = 1;
2233722454
}
2233822455
sqlite3MemdebugSetType(p,
2233922456
(db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
@@ -27479,37 +27596,55 @@
2747927596
#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
2748027597
2748127598
{ "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
2748227599
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
2748327600
27601
+#if defined(HAVE_FCHOWN)
2748427602
{ "fchown", (sqlite3_syscall_ptr)fchown, 0 },
27603
+#else
27604
+ { "fchown", (sqlite3_syscall_ptr)0, 0 },
27605
+#endif
2748527606
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
2748627607
2748727608
{ "geteuid", (sqlite3_syscall_ptr)geteuid, 0 },
2748827609
#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
2748927610
2749027611
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
27491
- { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
27612
+ { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
27613
+#else
27614
+ { "mmap", (sqlite3_syscall_ptr)0, 0 },
27615
+#endif
2749227616
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
2749327617
27618
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
2749427619
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
27620
+#else
27621
+ { "munmap", (sqlite3_syscall_ptr)0, 0 },
27622
+#endif
2749527623
#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
2749627624
27497
-#if HAVE_MREMAP
27625
+#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
2749827626
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
2749927627
#else
2750027628
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
2750127629
#endif
2750227630
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
2750327631
27632
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
2750427633
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
27634
+#else
27635
+ { "getpagesize", (sqlite3_syscall_ptr)0, 0 },
27636
+#endif
2750527637
#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
2750627638
27639
+#if defined(HAVE_READLINK)
2750727640
{ "readlink", (sqlite3_syscall_ptr)readlink, 0 },
27641
+#else
27642
+ { "readlink", (sqlite3_syscall_ptr)0, 0 },
27643
+#endif
2750827644
#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
2750927645
27510
-#endif
2751127646
2751227647
}; /* End of the overrideable system calls */
2751327648
2751427649
2751527650
/*
@@ -27516,14 +27651,14 @@
2751627651
** On some systems, calls to fchown() will trigger a message in a security
2751727652
** log if they come from non-root processes. So avoid calling fchown() if
2751827653
** we are not running as root.
2751927654
*/
2752027655
static int robustFchown(int fd, uid_t uid, gid_t gid){
27521
-#if OS_VXWORKS
27522
- return 0;
27523
-#else
27656
+#if defined(HAVE_FCHOWN)
2752427657
return osGeteuid() ? 0 : osFchown(fd,uid,gid);
27658
+#else
27659
+ return 0;
2752527660
#endif
2752627661
}
2752727662
2752827663
/*
2752927664
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -32986,10 +33121,11 @@
3298633121
SimulateIOError( return SQLITE_ERROR );
3298733122
3298833123
assert( pVfs->mxPathname==MAX_PATHNAME );
3298933124
UNUSED_PARAMETER(pVfs);
3299033125
33126
+#if defined(HAVE_READLINK)
3299133127
/* Attempt to resolve the path as if it were a symbolic link. If it is
3299233128
** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if
3299333129
** the identified file is not a symbolic link or does not exist, then
3299433130
** zPath is copied directly into zOut. Either way, nByte is left set to
3299533131
** the size of the string copied into zOut[] in bytes. */
@@ -33001,10 +33137,11 @@
3300133137
sqlite3_snprintf(nOut, zOut, "%s", zPath);
3300233138
nByte = sqlite3Strlen30(zOut);
3300333139
}else{
3300433140
zOut[nByte] = '\0';
3300533141
}
33142
+#endif
3300633143
3300733144
/* If buffer zOut[] now contains an absolute path there is nothing more
3300833145
** to do. If it contains a relative path, do the following:
3300933146
**
3301033147
** * move the relative path string so that it is at the end of th
@@ -43327,10 +43464,11 @@
4332743464
# define sqlite3WalCallback(z) 0
4332843465
# define sqlite3WalExclusiveMode(y,z) 0
4332943466
# define sqlite3WalHeapMemory(z) 0
4333043467
# define sqlite3WalFramesize(z) 0
4333143468
# define sqlite3WalFindFrame(x,y,z) 0
43469
+# define sqlite3WalFile(x) 0
4333243470
#else
4333343471
4333443472
#define WAL_SAVEPOINT_NDATA 4
4333543473
4333643474
/* Connection to a write-ahead log (WAL) file.
@@ -43421,10 +43559,13 @@
4342143559
** stored in each frame (i.e. the db page-size when the WAL was created).
4342243560
*/
4342343561
SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
4342443562
#endif
4342543563
43564
+/* Return the sqlite3_file object for the WAL file */
43565
+SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
43566
+
4342643567
#endif /* ifndef SQLITE_OMIT_WAL */
4342743568
#endif /* _WAL_H_ */
4342843569
4342943570
/************** End of wal.h *************************************************/
4343043571
/************** Continuing where we left off in pager.c **********************/
@@ -49032,11 +49173,11 @@
4903249173
if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
4903349174
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
4903449175
if( rc!=SQLITE_OK ){
4903549176
return rc;
4903649177
}
49037
- sqlite3WalExclusiveMode(pPager->pWal, 1);
49178
+ (void)sqlite3WalExclusiveMode(pPager->pWal, 1);
4903849179
}
4903949180
4904049181
/* Grab the write lock on the log file. If successful, upgrade to
4904149182
** PAGER_RESERVED state. Otherwise, return an error code to the caller.
4904249183
** The busy-handler is not invoked if another connection already
@@ -50096,10 +50237,22 @@
5009650237
** not yet been opened.
5009750238
*/
5009850239
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
5009950240
return pPager->fd;
5010050241
}
50242
+
50243
+/*
50244
+** Return the file handle for the journal file (if it exists).
50245
+** This will be either the rollback journal or the WAL file.
50246
+*/
50247
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
50248
+#if SQLITE_OMIT_WAL
50249
+ return pPager->jfd;
50250
+#else
50251
+ return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
50252
+#endif
50253
+}
5010150254
5010250255
/*
5010350256
** Return the full pathname of the journal file.
5010450257
*/
5010550258
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
@@ -51202,10 +51355,11 @@
5120251355
u8 truncateOnCommit; /* True to truncate WAL file on commit */
5120351356
u8 syncHeader; /* Fsync the WAL header if true */
5120451357
u8 padToSectorBoundary; /* Pad transactions out to the next sector */
5120551358
WalIndexHdr hdr; /* Wal-index header for current transaction */
5120651359
u32 minFrame; /* Ignore wal frames before this one */
51360
+ u32 iReCksum; /* On commit, recalculate checksums from here */
5120751361
const char *zWalName; /* Name of WAL file */
5120851362
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
5120951363
#ifdef SQLITE_DEBUG
5121051364
u8 lockError; /* True if a locking error has occurred */
5121151365
#endif
@@ -51455,18 +51609,22 @@
5145551609
int nativeCksum; /* True for native byte-order checksums */
5145651610
u32 *aCksum = pWal->hdr.aFrameCksum;
5145751611
assert( WAL_FRAME_HDRSIZE==24 );
5145851612
sqlite3Put4byte(&aFrame[0], iPage);
5145951613
sqlite3Put4byte(&aFrame[4], nTruncate);
51460
- memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
51461
-
51462
- nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
51463
- walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
51464
- walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
51465
-
51466
- sqlite3Put4byte(&aFrame[16], aCksum[0]);
51467
- sqlite3Put4byte(&aFrame[20], aCksum[1]);
51614
+ if( pWal->iReCksum==0 ){
51615
+ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
51616
+
51617
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
51618
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
51619
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
51620
+
51621
+ sqlite3Put4byte(&aFrame[16], aCksum[0]);
51622
+ sqlite3Put4byte(&aFrame[20], aCksum[1]);
51623
+ }else{
51624
+ memset(&aFrame[8], 0, 16);
51625
+ }
5146851626
}
5146951627
5147051628
/*
5147151629
** Check to see if the frame with header in aFrame[] and content
5147251630
** in aData[] is valid. If it is a valid frame, fill *piPage and
@@ -53389,10 +53547,11 @@
5338953547
int rc;
5339053548
5339153549
/* Cannot start a write transaction without first holding a read
5339253550
** transaction. */
5339353551
assert( pWal->readLock>=0 );
53552
+ assert( pWal->writeLock==0 && pWal->iReCksum==0 );
5339453553
5339553554
if( pWal->readOnly ){
5339653555
return SQLITE_READONLY;
5339753556
}
5339853557
@@ -53424,10 +53583,11 @@
5342453583
*/
5342553584
SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
5342653585
if( pWal->writeLock ){
5342753586
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
5342853587
pWal->writeLock = 0;
53588
+ pWal->iReCksum = 0;
5342953589
pWal->truncateOnCommit = 0;
5343053590
}
5343153591
return SQLITE_OK;
5343253592
}
5343353593
@@ -53641,10 +53801,63 @@
5364153801
if( rc ) return rc;
5364253802
/* Write the page data */
5364353803
rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
5364453804
return rc;
5364553805
}
53806
+
53807
+/*
53808
+** This function is called as part of committing a transaction within which
53809
+** one or more frames have been overwritten. It updates the checksums for
53810
+** all frames written to the wal file by the current transaction starting
53811
+** with the earliest to have been overwritten.
53812
+**
53813
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
53814
+*/
53815
+static int walRewriteChecksums(Wal *pWal, u32 iLast){
53816
+ const int szPage = pWal->szPage;/* Database page size */
53817
+ int rc = SQLITE_OK; /* Return code */
53818
+ u8 *aBuf; /* Buffer to load data from wal file into */
53819
+ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */
53820
+ u32 iRead; /* Next frame to read from wal file */
53821
+ i64 iCksumOff;
53822
+
53823
+ aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
53824
+ if( aBuf==0 ) return SQLITE_NOMEM;
53825
+
53826
+ /* Find the checksum values to use as input for the recalculating the
53827
+ ** first checksum. If the first frame is frame 1 (implying that the current
53828
+ ** transaction restarted the wal file), these values must be read from the
53829
+ ** wal-file header. Otherwise, read them from the frame header of the
53830
+ ** previous frame. */
53831
+ assert( pWal->iReCksum>0 );
53832
+ if( pWal->iReCksum==1 ){
53833
+ iCksumOff = 24;
53834
+ }else{
53835
+ iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16;
53836
+ }
53837
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff);
53838
+ pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf);
53839
+ pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]);
53840
+
53841
+ iRead = pWal->iReCksum;
53842
+ pWal->iReCksum = 0;
53843
+ for(; rc==SQLITE_OK && iRead<=iLast; iRead++){
53844
+ i64 iOff = walFrameOffset(iRead, szPage);
53845
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff);
53846
+ if( rc==SQLITE_OK ){
53847
+ u32 iPgno, nDbSize;
53848
+ iPgno = sqlite3Get4byte(aBuf);
53849
+ nDbSize = sqlite3Get4byte(&aBuf[4]);
53850
+
53851
+ walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame);
53852
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff);
53853
+ }
53854
+ }
53855
+
53856
+ sqlite3_free(aBuf);
53857
+ return rc;
53858
+}
5364653859
5364753860
/*
5364853861
** Write a set of frames to the log. The caller must hold the write-lock
5364953862
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
5365053863
*/
@@ -53662,10 +53875,12 @@
5366253875
PgHdr *pLast = 0; /* Last frame in list */
5366353876
int nExtra = 0; /* Number of extra copies of last page */
5366453877
int szFrame; /* The size of a single frame */
5366553878
i64 iOffset; /* Next byte to write in WAL file */
5366653879
WalWriter w; /* The writer */
53880
+ u32 iFirst = 0; /* First frame that may be overwritten */
53881
+ WalIndexHdr *pLive; /* Pointer to shared header */
5366753882
5366853883
assert( pList );
5366953884
assert( pWal->writeLock );
5367053885
5367153886
/* If this frame set completes a transaction, then nTruncate>0. If
@@ -53676,10 +53891,15 @@
5367653891
{ int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
5367753892
WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
5367853893
pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
5367953894
}
5368053895
#endif
53896
+
53897
+ pLive = (WalIndexHdr*)walIndexHdr(pWal);
53898
+ if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){
53899
+ iFirst = pLive->mxFrame+1;
53900
+ }
5368153901
5368253902
/* See if it is possible to write these frames into the start of the
5368353903
** log file, instead of appending to it at pWal->hdr.mxFrame.
5368453904
*/
5368553905
if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
@@ -53741,17 +53961,45 @@
5374153961
szFrame = szPage + WAL_FRAME_HDRSIZE;
5374253962
5374353963
/* Write all frames into the log file exactly once */
5374453964
for(p=pList; p; p=p->pDirty){
5374553965
int nDbSize; /* 0 normally. Positive == commit flag */
53966
+
53967
+ /* Check if this page has already been written into the wal file by
53968
+ ** the current transaction. If so, overwrite the existing frame and
53969
+ ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
53970
+ ** checksums must be recomputed when the transaction is committed. */
53971
+ if( iFirst && (p->pDirty || isCommit==0) ){
53972
+ u32 iWrite = 0;
53973
+ VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
53974
+ assert( rc==SQLITE_OK || iWrite==0 );
53975
+ if( iWrite>=iFirst ){
53976
+ i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
53977
+ if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
53978
+ pWal->iReCksum = iWrite;
53979
+ }
53980
+ rc = sqlite3OsWrite(pWal->pWalFd, p->pData, szPage, iOff);
53981
+ if( rc ) return rc;
53982
+ p->flags &= ~PGHDR_WAL_APPEND;
53983
+ continue;
53984
+ }
53985
+ }
53986
+
5374653987
iFrame++;
5374753988
assert( iOffset==walFrameOffset(iFrame, szPage) );
5374853989
nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
5374953990
rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
5375053991
if( rc ) return rc;
5375153992
pLast = p;
5375253993
iOffset += szFrame;
53994
+ p->flags |= PGHDR_WAL_APPEND;
53995
+ }
53996
+
53997
+ /* Recalculate checksums within the wal file if required. */
53998
+ if( isCommit && pWal->iReCksum ){
53999
+ rc = walRewriteChecksums(pWal, iFrame);
54000
+ if( rc ) return rc;
5375354001
}
5375454002
5375554003
/* If this is the end of a transaction, then we might need to pad
5375654004
** the transaction and/or sync the WAL file.
5375754005
**
@@ -53799,10 +54047,11 @@
5379954047
** guarantees that there are no other writers, and no data that may
5380054048
** be in use by existing readers is being overwritten.
5380154049
*/
5380254050
iFrame = pWal->hdr.mxFrame;
5380354051
for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
54052
+ if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue;
5380454053
iFrame++;
5380554054
rc = walIndexAppend(pWal, iFrame, p->pgno);
5380654055
}
5380754056
while( rc==SQLITE_OK && nExtra>0 ){
5380854057
iFrame++;
@@ -53911,10 +54160,11 @@
5391154160
}
5391254161
}
5391354162
5391454163
/* Copy data from the log to the database file. */
5391554164
if( rc==SQLITE_OK ){
54165
+
5391654166
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
5391754167
rc = SQLITE_CORRUPT_BKPT;
5391854168
}else{
5391954169
rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
5392054170
}
@@ -54066,10 +54316,16 @@
5406654316
SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
5406754317
assert( pWal==0 || pWal->readLock>=0 );
5406854318
return (pWal ? pWal->szPage : 0);
5406954319
}
5407054320
#endif
54321
+
54322
+/* Return the sqlite3_file object for the WAL file
54323
+*/
54324
+SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
54325
+ return pWal->pWalFd;
54326
+}
5407154327
5407254328
#endif /* #ifndef SQLITE_OMIT_WAL */
5407354329
5407454330
/************** End of wal.c *************************************************/
5407554331
/************** Begin file btmutex.c *****************************************/
@@ -54368,11 +54624,10 @@
5436854624
struct MemPage {
5436954625
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
5437054626
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
5437154627
u8 intKey; /* True if table b-trees. False for index b-trees */
5437254628
u8 intKeyLeaf; /* True if the leaf of an intKey table */
54373
- u8 noPayload; /* True if internal intKey page (thus w/o data) */
5437454629
u8 leaf; /* True if a leaf page */
5437554630
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
5437654631
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
5437754632
u8 max1bytePayload; /* min(maxLocal,127) */
5437854633
u8 bBusy; /* Prevent endless loops on corrupt database files */
@@ -54955,25 +55210,10 @@
5495555210
5495655211
return (p->sharable==0 || p->locked);
5495755212
}
5495855213
#endif
5495955214
54960
-
54961
-#ifndef SQLITE_OMIT_INCRBLOB
54962
-/*
54963
-** Enter and leave a mutex on a Btree given a cursor owned by that
54964
-** Btree. These entry points are used by incremental I/O and can be
54965
-** omitted if that module is not used.
54966
-*/
54967
-SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
54968
- sqlite3BtreeEnter(pCur->pBtree);
54969
-}
54970
-SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
54971
- sqlite3BtreeLeave(pCur->pBtree);
54972
-}
54973
-#endif /* SQLITE_OMIT_INCRBLOB */
54974
-
5497555215
5497655216
/*
5497755217
** Enter the mutex on every Btree associated with a database
5497855218
** connection. This is needed (for example) prior to parsing
5497955219
** a statement since we will be comparing table and column names
@@ -55004,18 +55244,10 @@
5500455244
p = db->aDb[i].pBt;
5500555245
if( p ) sqlite3BtreeLeave(p);
5500655246
}
5500755247
}
5500855248
55009
-/*
55010
-** Return true if a particular Btree requires a lock. Return FALSE if
55011
-** no lock is ever required since it is not sharable.
55012
-*/
55013
-SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
55014
- return p->sharable;
55015
-}
55016
-
5501755249
#ifndef NDEBUG
5501855250
/*
5501955251
** Return true if the current thread holds the database connection
5502055252
** mutex and all required BtShared mutexes.
5502155253
**
@@ -55085,10 +55317,29 @@
5508555317
p->pBt->db = p->db;
5508655318
}
5508755319
}
5508855320
}
5508955321
#endif /* if SQLITE_THREADSAFE */
55322
+
55323
+#ifndef SQLITE_OMIT_INCRBLOB
55324
+/*
55325
+** Enter a mutex on a Btree given a cursor owned by that Btree.
55326
+**
55327
+** These entry points are used by incremental I/O only. Enter() is required
55328
+** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
55329
+** the build is threadsafe. Leave() is only required by threadsafe builds.
55330
+*/
55331
+SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
55332
+ sqlite3BtreeEnter(pCur->pBtree);
55333
+}
55334
+# if SQLITE_THREADSAFE
55335
+SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
55336
+ sqlite3BtreeLeave(pCur->pBtree);
55337
+}
55338
+# endif
55339
+#endif /* ifndef SQLITE_OMIT_INCRBLOB */
55340
+
5509055341
#endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
5509155342
5509255343
/************** End of btmutex.c *********************************************/
5509355344
/************** Begin file btree.c *******************************************/
5509455345
/*
@@ -55541,10 +55792,14 @@
5554155792
*/
5554255793
#ifdef SQLITE_DEBUG
5554355794
static int cursorHoldsMutex(BtCursor *p){
5554455795
return sqlite3_mutex_held(p->pBt->mutex);
5554555796
}
55797
+static int cursorOwnsBtShared(BtCursor *p){
55798
+ assert( cursorHoldsMutex(p) );
55799
+ return (p->pBtree->db==p->pBt->db);
55800
+}
5554655801
#endif
5554755802
5554855803
/*
5554955804
** Invalidate the overflow cache of the cursor passed as the first argument.
5555055805
** on the shared btree structure pBt.
@@ -55877,11 +56132,11 @@
5587756132
** saveCursorPosition().
5587856133
*/
5587956134
static int btreeRestoreCursorPosition(BtCursor *pCur){
5588056135
int rc;
5588156136
int skipNext;
55882
- assert( cursorHoldsMutex(pCur) );
56137
+ assert( cursorOwnsBtShared(pCur) );
5588356138
assert( pCur->eState>=CURSOR_REQUIRESEEK );
5588456139
if( pCur->eState==CURSOR_FAULT ){
5588556140
return pCur->skipNext;
5588656141
}
5588756142
pCur->eState = CURSOR_INVALID;
@@ -56166,11 +56421,10 @@
5616656421
u8 *pCell, /* Pointer to the cell text. */
5616756422
CellInfo *pInfo /* Fill in this structure */
5616856423
){
5616956424
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
5617056425
assert( pPage->leaf==0 );
56171
- assert( pPage->noPayload );
5617256426
assert( pPage->childPtrSize==4 );
5617356427
#ifndef SQLITE_DEBUG
5617456428
UNUSED_PARAMETER(pPage);
5617556429
#endif
5617656430
pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
@@ -56188,12 +56442,10 @@
5618856442
u32 nPayload; /* Number of bytes of cell payload */
5618956443
u64 iKey; /* Extracted Key value */
5619056444
5619156445
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
5619256446
assert( pPage->leaf==0 || pPage->leaf==1 );
56193
- assert( pPage->intKeyLeaf || pPage->noPayload );
56194
- assert( pPage->noPayload==0 );
5619556447
assert( pPage->intKeyLeaf );
5619656448
assert( pPage->childPtrSize==0 );
5619756449
pIter = pCell;
5619856450
5619956451
/* The next block of code is equivalent to:
@@ -56258,11 +56510,10 @@
5625856510
u32 nPayload; /* Number of bytes of cell payload */
5625956511
5626056512
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
5626156513
assert( pPage->leaf==0 || pPage->leaf==1 );
5626256514
assert( pPage->intKeyLeaf==0 );
56263
- assert( pPage->noPayload==0 );
5626456515
pIter = pCell + pPage->childPtrSize;
5626556516
nPayload = *pIter;
5626656517
if( nPayload>=0x80 ){
5626756518
u8 *pEnd = &pIter[8];
5626856519
nPayload &= 0x7f;
@@ -56319,11 +56570,10 @@
5631956570
** this function verifies that this invariant is not violated. */
5632056571
CellInfo debuginfo;
5632156572
pPage->xParseCell(pPage, pCell, &debuginfo);
5632256573
#endif
5632356574
56324
- assert( pPage->noPayload==0 );
5632556575
nSize = *pIter;
5632656576
if( nSize>=0x80 ){
5632756577
pEnd = &pIter[8];
5632856578
nSize &= 0x7f;
5632956579
do{
@@ -56777,15 +57027,13 @@
5677757027
** table b-tree page. */
5677857028
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
5677957029
pPage->intKey = 1;
5678057030
if( pPage->leaf ){
5678157031
pPage->intKeyLeaf = 1;
56782
- pPage->noPayload = 0;
5678357032
pPage->xParseCell = btreeParseCellPtr;
5678457033
}else{
5678557034
pPage->intKeyLeaf = 0;
56786
- pPage->noPayload = 1;
5678757035
pPage->xCellSize = cellSizePtrNoPayload;
5678857036
pPage->xParseCell = btreeParseCellPtrNoPayload;
5678957037
}
5679057038
pPage->maxLocal = pBt->maxLeaf;
5679157039
pPage->minLocal = pBt->minLeaf;
@@ -56796,11 +57044,10 @@
5679657044
/* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
5679757045
** index b-tree page. */
5679857046
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
5679957047
pPage->intKey = 0;
5680057048
pPage->intKeyLeaf = 0;
56801
- pPage->noPayload = 0;
5680257049
pPage->xParseCell = btreeParseCellPtrIndex;
5680357050
pPage->maxLocal = pBt->maxLocal;
5680457051
pPage->minLocal = pBt->minLocal;
5680557052
}else{
5680657053
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
@@ -58217,11 +58464,10 @@
5821758464
** no progress. By returning SQLITE_BUSY and not invoking the busy callback
5821858465
** when A already has a read lock, we encourage A to give up and let B
5821958466
** proceed.
5822058467
*/
5822158468
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
58222
- sqlite3 *pBlock = 0;
5822358469
BtShared *pBt = p->pBt;
5822458470
int rc = SQLITE_OK;
5822558471
5822658472
sqlite3BtreeEnter(p);
5822758473
btreeIntegrity(p);
@@ -58240,31 +58486,34 @@
5824058486
rc = SQLITE_READONLY;
5824158487
goto trans_begun;
5824258488
}
5824358489
5824458490
#ifndef SQLITE_OMIT_SHARED_CACHE
58245
- /* If another database handle has already opened a write transaction
58246
- ** on this shared-btree structure and a second write transaction is
58247
- ** requested, return SQLITE_LOCKED.
58248
- */
58249
- if( (wrflag && pBt->inTransaction==TRANS_WRITE)
58250
- || (pBt->btsFlags & BTS_PENDING)!=0
58251
- ){
58252
- pBlock = pBt->pWriter->db;
58253
- }else if( wrflag>1 ){
58254
- BtLock *pIter;
58255
- for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
58256
- if( pIter->pBtree!=p ){
58257
- pBlock = pIter->pBtree->db;
58258
- break;
58259
- }
58260
- }
58261
- }
58262
- if( pBlock ){
58263
- sqlite3ConnectionBlocked(p->db, pBlock);
58264
- rc = SQLITE_LOCKED_SHAREDCACHE;
58265
- goto trans_begun;
58491
+ {
58492
+ sqlite3 *pBlock = 0;
58493
+ /* If another database handle has already opened a write transaction
58494
+ ** on this shared-btree structure and a second write transaction is
58495
+ ** requested, return SQLITE_LOCKED.
58496
+ */
58497
+ if( (wrflag && pBt->inTransaction==TRANS_WRITE)
58498
+ || (pBt->btsFlags & BTS_PENDING)!=0
58499
+ ){
58500
+ pBlock = pBt->pWriter->db;
58501
+ }else if( wrflag>1 ){
58502
+ BtLock *pIter;
58503
+ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
58504
+ if( pIter->pBtree!=p ){
58505
+ pBlock = pIter->pBtree->db;
58506
+ break;
58507
+ }
58508
+ }
58509
+ }
58510
+ if( pBlock ){
58511
+ sqlite3ConnectionBlocked(p->db, pBlock);
58512
+ rc = SQLITE_LOCKED_SHAREDCACHE;
58513
+ goto trans_begun;
58514
+ }
5826658515
}
5826758516
#endif
5826858517
5826958518
/* Any read-only or read-write transaction implies a read-lock on
5827058519
** page 1. So if some other shared-cache client already has a write-lock
@@ -59377,11 +59626,11 @@
5937759626
** Failure is not possible. This function always returns SQLITE_OK.
5937859627
** It might just as well be a procedure (returning void) but we continue
5937959628
** to return an integer result code for historical reasons.
5938059629
*/
5938159630
SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
59382
- assert( cursorHoldsMutex(pCur) );
59631
+ assert( cursorOwnsBtShared(pCur) );
5938359632
assert( pCur->eState==CURSOR_VALID );
5938459633
assert( pCur->iPage>=0 );
5938559634
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
5938659635
assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
5938759636
getCellInfo(pCur);
@@ -59757,11 +60006,11 @@
5975760006
if ( pCur->eState==CURSOR_INVALID ){
5975860007
return SQLITE_ABORT;
5975960008
}
5976060009
#endif
5976160010
59762
- assert( cursorHoldsMutex(pCur) );
60011
+ assert( cursorOwnsBtShared(pCur) );
5976360012
rc = restoreCursorPosition(pCur);
5976460013
if( rc==SQLITE_OK ){
5976560014
assert( pCur->eState==CURSOR_VALID );
5976660015
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
5976760016
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
@@ -59795,11 +60044,11 @@
5979560044
){
5979660045
u32 amt;
5979760046
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
5979860047
assert( pCur->eState==CURSOR_VALID );
5979960048
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
59800
- assert( cursorHoldsMutex(pCur) );
60049
+ assert( cursorOwnsBtShared(pCur) );
5980160050
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
5980260051
assert( pCur->info.nSize>0 );
5980360052
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
5980460053
assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
5980560054
amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
@@ -59841,11 +60090,11 @@
5984160090
** vice-versa).
5984260091
*/
5984360092
static int moveToChild(BtCursor *pCur, u32 newPgno){
5984460093
BtShared *pBt = pCur->pBt;
5984560094
59846
- assert( cursorHoldsMutex(pCur) );
60095
+ assert( cursorOwnsBtShared(pCur) );
5984760096
assert( pCur->eState==CURSOR_VALID );
5984860097
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
5984960098
assert( pCur->iPage>=0 );
5985060099
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
5985160100
return SQLITE_CORRUPT_BKPT;
@@ -59887,11 +60136,11 @@
5988760136
** to the page we are coming from. If we are coming from the
5988860137
** right-most child page then pCur->idx is set to one more than
5988960138
** the largest cell index.
5989060139
*/
5989160140
static void moveToParent(BtCursor *pCur){
59892
- assert( cursorHoldsMutex(pCur) );
60141
+ assert( cursorOwnsBtShared(pCur) );
5989360142
assert( pCur->eState==CURSOR_VALID );
5989460143
assert( pCur->iPage>0 );
5989560144
assert( pCur->apPage[pCur->iPage] );
5989660145
assertParentIndex(
5989760146
pCur->apPage[pCur->iPage-1],
@@ -59927,11 +60176,11 @@
5992760176
*/
5992860177
static int moveToRoot(BtCursor *pCur){
5992960178
MemPage *pRoot;
5993060179
int rc = SQLITE_OK;
5993160180
59932
- assert( cursorHoldsMutex(pCur) );
60181
+ assert( cursorOwnsBtShared(pCur) );
5993360182
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
5993460183
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
5993560184
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
5993660185
if( pCur->eState>=CURSOR_REQUIRESEEK ){
5993760186
if( pCur->eState==CURSOR_FAULT ){
@@ -60006,11 +60255,11 @@
6000660255
static int moveToLeftmost(BtCursor *pCur){
6000760256
Pgno pgno;
6000860257
int rc = SQLITE_OK;
6000960258
MemPage *pPage;
6001060259
60011
- assert( cursorHoldsMutex(pCur) );
60260
+ assert( cursorOwnsBtShared(pCur) );
6001260261
assert( pCur->eState==CURSOR_VALID );
6001360262
while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
6001460263
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
6001560264
pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
6001660265
rc = moveToChild(pCur, pgno);
@@ -60031,11 +60280,11 @@
6003160280
static int moveToRightmost(BtCursor *pCur){
6003260281
Pgno pgno;
6003360282
int rc = SQLITE_OK;
6003460283
MemPage *pPage = 0;
6003560284
60036
- assert( cursorHoldsMutex(pCur) );
60285
+ assert( cursorOwnsBtShared(pCur) );
6003760286
assert( pCur->eState==CURSOR_VALID );
6003860287
while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
6003960288
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
6004060289
pCur->aiIdx[pCur->iPage] = pPage->nCell;
6004160290
rc = moveToChild(pCur, pgno);
@@ -60052,11 +60301,11 @@
6005260301
** or set *pRes to 1 if the table is empty.
6005360302
*/
6005460303
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
6005560304
int rc;
6005660305
60057
- assert( cursorHoldsMutex(pCur) );
60306
+ assert( cursorOwnsBtShared(pCur) );
6005860307
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
6005960308
rc = moveToRoot(pCur);
6006060309
if( rc==SQLITE_OK ){
6006160310
if( pCur->eState==CURSOR_INVALID ){
6006260311
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
@@ -60075,11 +60324,11 @@
6007560324
** or set *pRes to 1 if the table is empty.
6007660325
*/
6007760326
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
6007860327
int rc;
6007960328
60080
- assert( cursorHoldsMutex(pCur) );
60329
+ assert( cursorOwnsBtShared(pCur) );
6008160330
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
6008260331
6008360332
/* If the cursor already points to the last entry, this is a no-op. */
6008460333
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
6008560334
#ifdef SQLITE_DEBUG
@@ -60153,11 +60402,11 @@
6015360402
int *pRes /* Write search results here */
6015460403
){
6015560404
int rc;
6015660405
RecordCompare xRecordCompare;
6015760406
60158
- assert( cursorHoldsMutex(pCur) );
60407
+ assert( cursorOwnsBtShared(pCur) );
6015960408
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
6016060409
assert( pRes );
6016160410
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
6016260411
6016360412
/* If the cursor is already positioned at the point we are trying
@@ -60401,11 +60650,11 @@
6040160650
static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
6040260651
int rc;
6040360652
int idx;
6040460653
MemPage *pPage;
6040560654
60406
- assert( cursorHoldsMutex(pCur) );
60655
+ assert( cursorOwnsBtShared(pCur) );
6040760656
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
6040860657
assert( *pRes==0 );
6040960658
if( pCur->eState!=CURSOR_VALID ){
6041060659
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
6041160660
rc = restoreCursorPosition(pCur);
@@ -60465,11 +60714,11 @@
6046560714
return moveToLeftmost(pCur);
6046660715
}
6046760716
}
6046860717
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
6046960718
MemPage *pPage;
60470
- assert( cursorHoldsMutex(pCur) );
60719
+ assert( cursorOwnsBtShared(pCur) );
6047160720
assert( pRes!=0 );
6047260721
assert( *pRes==0 || *pRes==1 );
6047360722
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
6047460723
pCur->info.nSize = 0;
6047560724
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
@@ -60510,11 +60759,11 @@
6051060759
*/
6051160760
static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
6051260761
int rc;
6051360762
MemPage *pPage;
6051460763
60515
- assert( cursorHoldsMutex(pCur) );
60764
+ assert( cursorOwnsBtShared(pCur) );
6051660765
assert( pRes!=0 );
6051760766
assert( *pRes==0 );
6051860767
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
6051960768
assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
6052060769
assert( pCur->info.nSize==0 );
@@ -60566,11 +60815,11 @@
6056660815
}
6056760816
}
6056860817
return rc;
6056960818
}
6057060819
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
60571
- assert( cursorHoldsMutex(pCur) );
60820
+ assert( cursorOwnsBtShared(pCur) );
6057260821
assert( pRes!=0 );
6057360822
assert( *pRes==0 || *pRes==1 );
6057460823
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
6057560824
*pRes = 0;
6057660825
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
@@ -62279,13 +62528,12 @@
6227962528
** This must be done in advance. Once the balance starts, the cell
6228062529
** offset section of the btree page will be overwritten and we will no
6228162530
** long be able to find the cells if a pointer to each cell is not saved
6228262531
** first.
6228362532
*/
62284
- memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*limit);
62533
+ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
6228562534
if( pOld->nOverflow>0 ){
62286
- memset(&b.szCell[b.nCell+limit], 0, sizeof(b.szCell[0])*pOld->nOverflow);
6228762535
limit = pOld->aiOvfl[0];
6228862536
for(j=0; j<limit; j++){
6228962537
b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
6229062538
piCell += 2;
6229162539
b.nCell++;
@@ -63046,11 +63294,11 @@
6304663294
if( pCur->eState==CURSOR_FAULT ){
6304763295
assert( pCur->skipNext!=SQLITE_OK );
6304863296
return pCur->skipNext;
6304963297
}
6305063298
63051
- assert( cursorHoldsMutex(pCur) );
63299
+ assert( cursorOwnsBtShared(pCur) );
6305263300
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
6305363301
&& pBt->inTransaction==TRANS_WRITE
6305463302
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
6305563303
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
6305663304
@@ -63193,11 +63441,11 @@
6319363441
int iCellIdx; /* Index of cell to delete */
6319463442
int iCellDepth; /* Depth of node containing pCell */
6319563443
u16 szCell; /* Size of the cell being deleted */
6319663444
int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
6319763445
63198
- assert( cursorHoldsMutex(pCur) );
63446
+ assert( cursorOwnsBtShared(pCur) );
6319963447
assert( pBt->inTransaction==TRANS_WRITE );
6320063448
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
6320163449
assert( pCur->curFlags & BTCF_WriteFlag );
6320263450
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
6320363451
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
@@ -63633,10 +63881,18 @@
6363363881
*/
6363463882
if( NEVER(pBt->pCursor) ){
6363563883
sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
6363663884
return SQLITE_LOCKED_SHAREDCACHE;
6363763885
}
63886
+
63887
+ /*
63888
+ ** It is illegal to drop the sqlite_master table on page 1. But again,
63889
+ ** this error is caught long before reaching this point.
63890
+ */
63891
+ if( NEVER(iTable<2) ){
63892
+ return SQLITE_CORRUPT_BKPT;
63893
+ }
6363863894
6363963895
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
6364063896
if( rc ) return rc;
6364163897
rc = sqlite3BtreeClearTable(p, iTable, 0);
6364263898
if( rc ){
@@ -63644,80 +63900,71 @@
6364463900
return rc;
6364563901
}
6364663902
6364763903
*piMoved = 0;
6364863904
63649
- if( iTable>1 ){
63650
-#ifdef SQLITE_OMIT_AUTOVACUUM
63651
- freePage(pPage, &rc);
63652
- releasePage(pPage);
63653
-#else
63654
- if( pBt->autoVacuum ){
63655
- Pgno maxRootPgno;
63656
- sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
63657
-
63658
- if( iTable==maxRootPgno ){
63659
- /* If the table being dropped is the table with the largest root-page
63660
- ** number in the database, put the root page on the free list.
63661
- */
63662
- freePage(pPage, &rc);
63663
- releasePage(pPage);
63664
- if( rc!=SQLITE_OK ){
63665
- return rc;
63666
- }
63667
- }else{
63668
- /* The table being dropped does not have the largest root-page
63669
- ** number in the database. So move the page that does into the
63670
- ** gap left by the deleted root-page.
63671
- */
63672
- MemPage *pMove;
63673
- releasePage(pPage);
63674
- rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63675
- if( rc!=SQLITE_OK ){
63676
- return rc;
63677
- }
63678
- rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
63679
- releasePage(pMove);
63680
- if( rc!=SQLITE_OK ){
63681
- return rc;
63682
- }
63683
- pMove = 0;
63684
- rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63685
- freePage(pMove, &rc);
63686
- releasePage(pMove);
63687
- if( rc!=SQLITE_OK ){
63688
- return rc;
63689
- }
63690
- *piMoved = maxRootPgno;
63691
- }
63692
-
63693
- /* Set the new 'max-root-page' value in the database header. This
63694
- ** is the old value less one, less one more if that happens to
63695
- ** be a root-page number, less one again if that is the
63696
- ** PENDING_BYTE_PAGE.
63697
- */
63698
- maxRootPgno--;
63699
- while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
63700
- || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
63701
- maxRootPgno--;
63702
- }
63703
- assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
63704
-
63705
- rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
63706
- }else{
63707
- freePage(pPage, &rc);
63708
- releasePage(pPage);
63709
- }
63710
-#endif
63711
- }else{
63712
- /* If sqlite3BtreeDropTable was called on page 1.
63713
- ** This really never should happen except in a corrupt
63714
- ** database.
63715
- */
63716
- zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
63717
- releasePage(pPage);
63718
- }
63905
+#ifdef SQLITE_OMIT_AUTOVACUUM
63906
+ freePage(pPage, &rc);
63907
+ releasePage(pPage);
63908
+#else
63909
+ if( pBt->autoVacuum ){
63910
+ Pgno maxRootPgno;
63911
+ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
63912
+
63913
+ if( iTable==maxRootPgno ){
63914
+ /* If the table being dropped is the table with the largest root-page
63915
+ ** number in the database, put the root page on the free list.
63916
+ */
63917
+ freePage(pPage, &rc);
63918
+ releasePage(pPage);
63919
+ if( rc!=SQLITE_OK ){
63920
+ return rc;
63921
+ }
63922
+ }else{
63923
+ /* The table being dropped does not have the largest root-page
63924
+ ** number in the database. So move the page that does into the
63925
+ ** gap left by the deleted root-page.
63926
+ */
63927
+ MemPage *pMove;
63928
+ releasePage(pPage);
63929
+ rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63930
+ if( rc!=SQLITE_OK ){
63931
+ return rc;
63932
+ }
63933
+ rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
63934
+ releasePage(pMove);
63935
+ if( rc!=SQLITE_OK ){
63936
+ return rc;
63937
+ }
63938
+ pMove = 0;
63939
+ rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63940
+ freePage(pMove, &rc);
63941
+ releasePage(pMove);
63942
+ if( rc!=SQLITE_OK ){
63943
+ return rc;
63944
+ }
63945
+ *piMoved = maxRootPgno;
63946
+ }
63947
+
63948
+ /* Set the new 'max-root-page' value in the database header. This
63949
+ ** is the old value less one, less one more if that happens to
63950
+ ** be a root-page number, less one again if that is the
63951
+ ** PENDING_BYTE_PAGE.
63952
+ */
63953
+ maxRootPgno--;
63954
+ while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
63955
+ || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
63956
+ maxRootPgno--;
63957
+ }
63958
+ assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
63959
+
63960
+ rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
63961
+ }else{
63962
+ freePage(pPage, &rc);
63963
+ releasePage(pPage);
63964
+ }
63965
+#endif
6371963966
return rc;
6372063967
}
6372163968
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
6372263969
int rc;
6372363970
sqlite3BtreeEnter(p);
@@ -64655,11 +64902,11 @@
6465564902
** parameters that attempt to write past the end of the existing data,
6465664903
** no modifications are made and SQLITE_CORRUPT is returned.
6465764904
*/
6465864905
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
6465964906
int rc;
64660
- assert( cursorHoldsMutex(pCsr) );
64907
+ assert( cursorOwnsBtShared(pCsr) );
6466164908
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
6466264909
assert( pCsr->curFlags & BTCF_Incrblob );
6466364910
6466464911
rc = restoreCursorPosition(pCsr);
6466564912
if( rc!=SQLITE_OK ){
@@ -64762,10 +65009,19 @@
6476265009
6476365010
/*
6476465011
** Return the size of the header added to each page by this module.
6476565012
*/
6476665013
SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
65014
+
65015
+#if !defined(SQLITE_OMIT_SHARED_CACHE)
65016
+/*
65017
+** Return true if the Btree passed as the only argument is sharable.
65018
+*/
65019
+SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
65020
+ return p->sharable;
65021
+}
65022
+#endif
6476765023
6476865024
/************** End of btree.c ***********************************************/
6476965025
/************** Begin file backup.c ******************************************/
6477065026
/*
6477165027
** 2009 January 28
@@ -66791,11 +67047,11 @@
6679167047
6679267048
assert( pCtx->pParse->rc==SQLITE_OK );
6679367049
memset(&ctx, 0, sizeof(ctx));
6679467050
ctx.pOut = pVal;
6679567051
ctx.pFunc = pFunc;
66796
- pFunc->xFunc(&ctx, nVal, apVal);
67052
+ pFunc->xSFunc(&ctx, nVal, apVal);
6679767053
if( ctx.isError ){
6679867054
rc = ctx.isError;
6679967055
sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
6680067056
}else{
6680167057
sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
@@ -67538,12 +67794,11 @@
6753867794
char c;
6753967795
va_start(ap, zTypes);
6754067796
for(i=0; (c = zTypes[i])!=0; i++){
6754167797
if( c=='s' ){
6754267798
const char *z = va_arg(ap, const char*);
67543
- int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++);
67544
- if( z ) sqlite3VdbeChangeP4(p, addr, z, 0);
67799
+ sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0);
6754567800
}else{
6754667801
assert( c=='i' );
6754767802
sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
6754867803
}
6754967804
}
@@ -67593,12 +67848,11 @@
6759367848
** The zWhere string must have been obtained from sqlite3_malloc().
6759467849
** This routine will take ownership of the allocated memory.
6759567850
*/
6759667851
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
6759767852
int j;
67598
- int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
67599
- sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
67853
+ sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
6760067854
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
6760167855
}
6760267856
6760367857
/*
6760467858
** Add an opcode that includes the p4 value as an integer.
@@ -67895,10 +68149,24 @@
6789568149
SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
6789668150
assert( p->magic==VDBE_MAGIC_INIT );
6789768151
return p->nOp;
6789868152
}
6789968153
68154
+/*
68155
+** Verify that at least N opcode slots are available in p without
68156
+** having to malloc for more space (except when compiled using
68157
+** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing
68158
+** to verify that certain calls to sqlite3VdbeAddOpList() can never
68159
+** fail due to a OOM fault and hence that the return value from
68160
+** sqlite3VdbeAddOpList() will always be non-NULL.
68161
+*/
68162
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
68163
+SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){
68164
+ assert( p->nOp + N <= p->pParse->nOpAlloc );
68165
+}
68166
+#endif
68167
+
6790068168
/*
6790168169
** This function returns a pointer to the array of opcodes associated with
6790268170
** the Vdbe passed as the first argument. It is the callers responsibility
6790368171
** to arrange for the returned array to be eventually freed using the
6790468172
** vdbeFreeOpArray() function.
@@ -67920,23 +68188,27 @@
6792068188
p->aOp = 0;
6792168189
return aOp;
6792268190
}
6792368191
6792468192
/*
67925
-** Add a whole list of operations to the operation stack. Return the
67926
-** address of the first operation added.
68193
+** Add a whole list of operations to the operation stack. Return a
68194
+** pointer to the first operation inserted.
6792768195
*/
67928
-SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
67929
- int addr, i;
67930
- VdbeOp *pOut;
68196
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
68197
+ Vdbe *p, /* Add opcodes to the prepared statement */
68198
+ int nOp, /* Number of opcodes to add */
68199
+ VdbeOpList const *aOp, /* The opcodes to be added */
68200
+ int iLineno /* Source-file line number of first opcode */
68201
+){
68202
+ int i;
68203
+ VdbeOp *pOut, *pFirst;
6793168204
assert( nOp>0 );
6793268205
assert( p->magic==VDBE_MAGIC_INIT );
6793368206
if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
6793468207
return 0;
6793568208
}
67936
- addr = p->nOp;
67937
- pOut = &p->aOp[addr];
68209
+ pFirst = pOut = &p->aOp[p->nOp];
6793868210
for(i=0; i<nOp; i++, aOp++, pOut++){
6793968211
pOut->opcode = aOp->opcode;
6794068212
pOut->p1 = aOp->p1;
6794168213
pOut->p2 = aOp->p2;
6794268214
assert( aOp->p2>=0 );
@@ -67952,16 +68224,16 @@
6795268224
#else
6795368225
(void)iLineno;
6795468226
#endif
6795568227
#ifdef SQLITE_DEBUG
6795668228
if( p->db->flags & SQLITE_VdbeAddopTrace ){
67957
- sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
68229
+ sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]);
6795868230
}
6795968231
#endif
6796068232
}
6796168233
p->nOp += nOp;
67962
- return addr;
68234
+ return pFirst;
6796368235
}
6796468236
6796568237
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
6796668238
/*
6796768239
** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
@@ -68005,11 +68277,11 @@
6800568277
}
6800668278
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
6800768279
sqlite3VdbeGetOp(p,addr)->p3 = val;
6800868280
}
6800968281
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
68010
- sqlite3VdbeGetOp(p,-1)->p5 = p5;
68282
+ if( !p->db->mallocFailed ) p->aOp[p->nOp-1].p5 = p5;
6801168283
}
6801268284
6801368285
/*
6801468286
** Change the P2 operand of instruction addr so that it points to
6801568287
** the address of the next instruction to be coded.
@@ -68093,11 +68365,11 @@
6809368365
*/
6809468366
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
6809568367
if( aOp ){
6809668368
Op *pOp;
6809768369
for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
68098
- freeP4(db, pOp->p4type, pOp->p4.p);
68370
+ if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
6809968371
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
6810068372
sqlite3DbFree(db, pOp->zComment);
6810168373
#endif
6810268374
}
6810368375
}
@@ -68115,28 +68387,29 @@
6811568387
}
6811668388
6811768389
/*
6811868390
** Change the opcode at addr into OP_Noop
6811968391
*/
68120
-SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
68121
- if( addr<p->nOp ){
68122
- VdbeOp *pOp = &p->aOp[addr];
68123
- sqlite3 *db = p->db;
68124
- freeP4(db, pOp->p4type, pOp->p4.p);
68125
- memset(pOp, 0, sizeof(pOp[0]));
68126
- pOp->opcode = OP_Noop;
68127
- }
68392
+SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
68393
+ VdbeOp *pOp;
68394
+ if( p->db->mallocFailed ) return 0;
68395
+ assert( addr>=0 && addr<p->nOp );
68396
+ pOp = &p->aOp[addr];
68397
+ freeP4(p->db, pOp->p4type, pOp->p4.p);
68398
+ pOp->p4type = P4_NOTUSED;
68399
+ pOp->p4.z = 0;
68400
+ pOp->opcode = OP_Noop;
68401
+ return 1;
6812868402
}
6812968403
6813068404
/*
6813168405
** If the last opcode is "op" and it is not a jump destination,
6813268406
** then remove it. Return true if and only if an opcode was removed.
6813368407
*/
6813468408
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
6813568409
if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
68136
- sqlite3VdbeChangeToNoop(p, p->nOp-1);
68137
- return 1;
68410
+ return sqlite3VdbeChangeToNoop(p, p->nOp-1);
6813868411
}else{
6813968412
return 0;
6814068413
}
6814168414
}
6814268415
@@ -68155,65 +68428,60 @@
6815568428
** to a string or structure that is guaranteed to exist for the lifetime of
6815668429
** the Vdbe. In these cases we can just copy the pointer.
6815768430
**
6815868431
** If addr<0 then change P4 on the most recently inserted instruction.
6815968432
*/
68433
+static void SQLITE_NOINLINE vdbeChangeP4Full(
68434
+ Vdbe *p,
68435
+ Op *pOp,
68436
+ const char *zP4,
68437
+ int n
68438
+){
68439
+ if( pOp->p4type ){
68440
+ freeP4(p->db, pOp->p4type, pOp->p4.p);
68441
+ pOp->p4type = 0;
68442
+ pOp->p4.p = 0;
68443
+ }
68444
+ if( n<0 ){
68445
+ sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n);
68446
+ }else{
68447
+ if( n==0 ) n = sqlite3Strlen30(zP4);
68448
+ pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
68449
+ pOp->p4type = P4_DYNAMIC;
68450
+ }
68451
+}
6816068452
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
6816168453
Op *pOp;
6816268454
sqlite3 *db;
6816368455
assert( p!=0 );
6816468456
db = p->db;
6816568457
assert( p->magic==VDBE_MAGIC_INIT );
68166
- if( p->aOp==0 || db->mallocFailed ){
68167
- if( n!=P4_VTAB ){
68168
- freeP4(db, n, (void*)*(char**)&zP4);
68169
- }
68458
+ assert( p->aOp!=0 || db->mallocFailed );
68459
+ if( db->mallocFailed ){
68460
+ if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
6817068461
return;
6817168462
}
6817268463
assert( p->nOp>0 );
6817368464
assert( addr<p->nOp );
6817468465
if( addr<0 ){
6817568466
addr = p->nOp - 1;
6817668467
}
6817768468
pOp = &p->aOp[addr];
68178
- assert( pOp->p4type==P4_NOTUSED
68179
- || pOp->p4type==P4_INT32
68180
- || pOp->p4type==P4_KEYINFO );
68181
- freeP4(db, pOp->p4type, pOp->p4.p);
68182
- pOp->p4.p = 0;
68469
+ if( n>=0 || pOp->p4type ){
68470
+ vdbeChangeP4Full(p, pOp, zP4, n);
68471
+ return;
68472
+ }
6818368473
if( n==P4_INT32 ){
6818468474
/* Note: this cast is safe, because the origin data point was an int
6818568475
** that was cast to a (const char *). */
6818668476
pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
6818768477
pOp->p4type = P4_INT32;
68188
- }else if( zP4==0 ){
68189
- pOp->p4.p = 0;
68190
- pOp->p4type = P4_NOTUSED;
68191
- }else if( n==P4_KEYINFO ){
68192
- pOp->p4.p = (void*)zP4;
68193
- pOp->p4type = P4_KEYINFO;
68194
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
68195
- }else if( n==P4_EXPR ){
68196
- /* Responsibility for deleting the Expr tree is handed over to the
68197
- ** VDBE by this operation. The caller should have already invoked
68198
- ** sqlite3ExprDup() or whatever other routine is needed to make a
68199
- ** private copy of the tree. */
68200
- pOp->p4.pExpr = (Expr*)zP4;
68201
- pOp->p4type = P4_EXPR;
68202
-#endif
68203
- }else if( n==P4_VTAB ){
68204
- pOp->p4.p = (void*)zP4;
68205
- pOp->p4type = P4_VTAB;
68206
- sqlite3VtabLock((VTable *)zP4);
68207
- assert( ((VTable *)zP4)->db==p->db );
68208
- }else if( n<0 ){
68478
+ }else if( zP4!=0 ){
68479
+ assert( n<0 );
6820968480
pOp->p4.p = (void*)zP4;
6821068481
pOp->p4type = (signed char)n;
68211
- }else{
68212
- if( n==0 ) n = sqlite3Strlen30(zP4);
68213
- pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
68214
- pOp->p4type = P4_DYNAMIC;
68482
+ if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4);
6821568483
}
6821668484
}
6821768485
6821868486
/*
6821968487
** Set the P4 on the most recently added opcode to the KeyInfo for the
@@ -68605,11 +68873,11 @@
6860568873
if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
6860668874
DbMaskSet(p->lockMask, i);
6860768875
}
6860868876
}
6860968877
68610
-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
68878
+#if !defined(SQLITE_OMIT_SHARED_CACHE)
6861168879
/*
6861268880
** If SQLite is compiled to support shared-cache mode and to be threadsafe,
6861368881
** this routine obtains the mutex associated with each BtShared structure
6861468882
** that may be accessed by the VM passed as an argument. In doing so it also
6861568883
** sets the BtShared.db member of each of the BtShared structures, ensuring
@@ -69174,11 +69442,10 @@
6917469442
do {
6917569443
nByte = 0;
6917669444
p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte);
6917769445
p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte);
6917869446
p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte);
69179
- p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), zCsr, &nFree, &nByte);
6918069447
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
6918169448
zCsr, &nFree, &nByte);
6918269449
p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte);
6918369450
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
6918469451
p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte);
@@ -69197,15 +69464,14 @@
6919769464
for(n=0; n<nVar; n++){
6919869465
p->aVar[n].flags = MEM_Null;
6919969466
p->aVar[n].db = db;
6920069467
}
6920169468
}
69202
- if( p->azVar && pParse->nzVar>0 ){
69203
- p->nzVar = pParse->nzVar;
69204
- memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
69205
- memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
69206
- }
69469
+ p->nzVar = pParse->nzVar;
69470
+ p->azVar = pParse->azVar;
69471
+ pParse->nzVar = 0;
69472
+ pParse->azVar = 0;
6920769473
if( p->aMem ){
6920869474
p->aMem--; /* aMem[] goes from 1..nMem */
6920969475
p->nMem = nMem; /* not from 0..nMem-1 */
6921069476
for(n=1; n<=nMem; n++){
6921169477
p->aMem[n].flags = MEM_Undefined;
@@ -70188,10 +70454,11 @@
7018870454
pNext = pSub->pNext;
7018970455
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
7019070456
sqlite3DbFree(db, pSub);
7019170457
}
7019270458
for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
70459
+ sqlite3DbFree(db, p->azVar);
7019370460
vdbeFreeOpArray(db, p->aOp, p->nOp);
7019470461
sqlite3DbFree(db, p->aColName);
7019570462
sqlite3DbFree(db, p->zSql);
7019670463
sqlite3DbFree(db, p->pFree);
7019770464
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -70932,13 +71199,13 @@
7093271199
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
7093371200
n1 = v1==0 ? 0 : c1.n;
7093471201
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
7093571202
n2 = v2==0 ? 0 : c2.n;
7093671203
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
71204
+ if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
7093771205
sqlite3VdbeMemRelease(&c1);
7093871206
sqlite3VdbeMemRelease(&c2);
70939
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
7094071207
return rc;
7094171208
}
7094271209
}
7094371210
7094471211
/*
@@ -71722,15 +71989,17 @@
7172271989
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
7172371990
** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
7172471991
** in memory obtained from sqlite3DbMalloc).
7172571992
*/
7172671993
SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
71727
- sqlite3 *db = p->db;
71728
- sqlite3DbFree(db, p->zErrMsg);
71729
- p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
71730
- sqlite3_free(pVtab->zErrMsg);
71731
- pVtab->zErrMsg = 0;
71994
+ if( pVtab->zErrMsg ){
71995
+ sqlite3 *db = p->db;
71996
+ sqlite3DbFree(db, p->zErrMsg);
71997
+ p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
71998
+ sqlite3_free(pVtab->zErrMsg);
71999
+ pVtab->zErrMsg = 0;
72000
+ }
7173272001
}
7173372002
#endif /* SQLITE_OMIT_VIRTUALTABLE */
7173472003
7173572004
/************** End of vdbeaux.c *********************************************/
7173672005
/************** Begin file vdbeapi.c *****************************************/
@@ -72513,11 +72782,11 @@
7251372782
** Allocate or return the aggregate context for a user function. A new
7251472783
** context is allocated on the first call. Subsequent calls return the
7251572784
** same context that was returned on prior calls.
7251672785
*/
7251772786
SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
72518
- assert( p && p->pFunc && p->pFunc->xStep );
72787
+ assert( p && p->pFunc && p->pFunc->xFinalize );
7251972788
assert( sqlite3_mutex_held(p->pOut->db->mutex) );
7252072789
testcase( nByte<0 );
7252172790
if( (p->pMem->flags & MEM_Agg)==0 ){
7252272791
return createAggContext(p, nByte);
7252372792
}else{
@@ -72604,11 +72873,11 @@
7260472873
** provide only to avoid breaking legacy code. New aggregate function
7260572874
** implementations should keep their own counts within their aggregate
7260672875
** context.
7260772876
*/
7260872877
SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
72609
- assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
72878
+ assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize );
7261072879
return p->pMem->n;
7261172880
}
7261272881
#endif
7261372882
7261472883
/*
@@ -75347,12 +75616,12 @@
7534775616
}
7534875617
#endif
7534975618
MemSetTypeFlag(pCtx->pOut, MEM_Null);
7535075619
pCtx->fErrorOrAux = 0;
7535175620
db->lastRowid = lastRowid;
75352
- (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */
75353
- lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */
75621
+ (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
75622
+ lastRowid = db->lastRowid; /* Remember rowid changes made by xSFunc */
7535475623
7535575624
/* If the function returned an error, throw an exception */
7535675625
if( pCtx->fErrorOrAux ){
7535775626
if( pCtx->isError ){
7535875627
sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
@@ -76059,11 +76328,10 @@
7605976328
const u8 *zEndHdr; /* Pointer to first byte after the header */
7606076329
u32 offset; /* Offset into the data */
7606176330
u64 offset64; /* 64-bit offset */
7606276331
u32 avail; /* Number of bytes of available data */
7606376332
u32 t; /* A type code from the record header */
76064
- u16 fx; /* pDest->flags value */
7606576333
Mem *pReg; /* PseudoTable input register */
7606676334
7606776335
p2 = pOp->p2;
7606876336
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
7606976337
pDest = &aMem[pOp->p3];
@@ -76237,14 +76505,35 @@
7623776505
assert( p2<pC->nHdrParsed );
7623876506
assert( rc==SQLITE_OK );
7623976507
assert( sqlite3VdbeCheckMemInvariants(pDest) );
7624076508
if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
7624176509
assert( t==pC->aType[p2] );
76510
+ pDest->enc = encoding;
7624276511
if( pC->szRow>=aOffset[p2+1] ){
7624376512
/* This is the common case where the desired content fits on the original
7624476513
** page - where the content is not on an overflow page */
76245
- sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
76514
+ zData = pC->aRow + aOffset[p2];
76515
+ if( t<12 ){
76516
+ sqlite3VdbeSerialGet(zData, t, pDest);
76517
+ }else{
76518
+ /* If the column value is a string, we need a persistent value, not
76519
+ ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent
76520
+ ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize().
76521
+ */
76522
+ static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term };
76523
+ pDest->n = len = (t-12)/2;
76524
+ if( pDest->szMalloc < len+2 ){
76525
+ pDest->flags = MEM_Null;
76526
+ if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
76527
+ }else{
76528
+ pDest->z = pDest->zMalloc;
76529
+ }
76530
+ memcpy(pDest->z, zData, len);
76531
+ pDest->z[len] = 0;
76532
+ pDest->z[len+1] = 0;
76533
+ pDest->flags = aFlag[t&1];
76534
+ }
7624676535
}else{
7624776536
/* This branch happens only when content is on overflow pages */
7624876537
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
7624976538
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
7625076539
|| (len = sqlite3VdbeSerialTypeLen(t))==0
@@ -76252,42 +76541,24 @@
7625276541
/* Content is irrelevant for
7625376542
** 1. the typeof() function,
7625476543
** 2. the length(X) function if X is a blob, and
7625576544
** 3. if the content length is zero.
7625676545
** So we might as well use bogus content rather than reading
76257
- ** content from disk. NULL will work for the value for strings
76258
- ** and blobs and whatever is in the payloadSize64 variable
76259
- ** will work for everything else. */
76260
- sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
76546
+ ** content from disk. */
76547
+ static u8 aZero[8]; /* This is the bogus content */
76548
+ sqlite3VdbeSerialGet(aZero, t, pDest);
7626176549
}else{
7626276550
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
7626376551
pDest);
76264
- if( rc!=SQLITE_OK ){
76265
- goto op_column_error;
76266
- }
76267
- sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
76268
- pDest->flags &= ~MEM_Ephem;
76269
- }
76270
- }
76271
- pDest->enc = encoding;
76272
-
76273
-op_column_out:
76274
- /* If the column value is an ephemeral string, go ahead and persist
76275
- ** that string in case the cursor moves before the column value is
76276
- ** used. The following code does the equivalent of Deephemeralize()
76277
- ** but does it faster. */
76278
- if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
76279
- fx = pDest->flags & (MEM_Str|MEM_Blob);
76280
- assert( fx!=0 );
76281
- zData = (const u8*)pDest->z;
76282
- len = pDest->n;
76283
- if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
76284
- memcpy(pDest->z, zData, len);
76285
- pDest->z[len] = 0;
76286
- pDest->z[len+1] = 0;
76287
- pDest->flags = fx|MEM_Term;
76288
- }
76552
+ if( rc==SQLITE_OK ){
76553
+ sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
76554
+ pDest->flags &= ~MEM_Ephem;
76555
+ }
76556
+ }
76557
+ }
76558
+
76559
+op_column_out:
7628976560
op_column_error:
7629076561
UPDATE_MAX_BLOBSIZE(pDest);
7629176562
REGISTER_TRACE(pOp->p3, pDest);
7629276563
break;
7629376564
}
@@ -78782,10 +79053,11 @@
7878279053
case OP_Destroy: { /* out2 */
7878379054
int iMoved;
7878479055
int iDb;
7878579056
7878679057
assert( p->readOnly==0 );
79058
+ assert( pOp->p1>1 );
7878779059
pOut = out2Prerelease(p, pOp);
7878879060
pOut->flags = MEM_Null;
7878979061
if( db->nVdbeRead > db->nVDestroy+1 ){
7879079062
rc = SQLITE_LOCKED;
7879179063
p->errorAction = OE_Abort;
@@ -79586,11 +79858,11 @@
7958679858
pMem->n++;
7958779859
sqlite3VdbeMemInit(&t, db, MEM_Null);
7958879860
pCtx->pOut = &t;
7958979861
pCtx->fErrorOrAux = 0;
7959079862
pCtx->skipFlag = 0;
79591
- (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
79863
+ (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
7959279864
if( pCtx->fErrorOrAux ){
7959379865
if( pCtx->isError ){
7959479866
sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
7959579867
rc = pCtx->isError;
7959679868
}
@@ -80584,42 +80856,10 @@
8058480856
int flags, /* True -> read/write access, false -> read-only */
8058580857
sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
8058680858
){
8058780859
int nAttempt = 0;
8058880860
int iCol; /* Index of zColumn in row-record */
80589
-
80590
- /* This VDBE program seeks a btree cursor to the identified
80591
- ** db/table/row entry. The reason for using a vdbe program instead
80592
- ** of writing code to use the b-tree layer directly is that the
80593
- ** vdbe program will take advantage of the various transaction,
80594
- ** locking and error handling infrastructure built into the vdbe.
80595
- **
80596
- ** After seeking the cursor, the vdbe executes an OP_ResultRow.
80597
- ** Code external to the Vdbe then "borrows" the b-tree cursor and
80598
- ** uses it to implement the blob_read(), blob_write() and
80599
- ** blob_bytes() functions.
80600
- **
80601
- ** The sqlite3_blob_close() function finalizes the vdbe program,
80602
- ** which closes the b-tree cursor and (possibly) commits the
80603
- ** transaction.
80604
- */
80605
- static const int iLn = VDBE_OFFSET_LINENO(4);
80606
- static const VdbeOpList openBlob[] = {
80607
- /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
80608
- {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
80609
- /* One of the following two instructions is replaced by an OP_Noop. */
80610
- {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
80611
- {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
80612
- {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
80613
- {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
80614
- {OP_Column, 0, 0, 1}, /* 6 */
80615
- {OP_ResultRow, 1, 0, 0}, /* 7 */
80616
- {OP_Goto, 0, 4, 0}, /* 8 */
80617
- {OP_Close, 0, 0, 0}, /* 9 */
80618
- {OP_Halt, 0, 0, 0}, /* 10 */
80619
- };
80620
-
8062180861
int rc = SQLITE_OK;
8062280862
char *zErr = 0;
8062380863
Table *pTab;
8062480864
Parse *pParse = 0;
8062580865
Incrblob *pBlob = 0;
@@ -80734,49 +80974,84 @@
8073480974
}
8073580975
8073680976
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
8073780977
assert( pBlob->pStmt || db->mallocFailed );
8073880978
if( pBlob->pStmt ){
80979
+
80980
+ /* This VDBE program seeks a btree cursor to the identified
80981
+ ** db/table/row entry. The reason for using a vdbe program instead
80982
+ ** of writing code to use the b-tree layer directly is that the
80983
+ ** vdbe program will take advantage of the various transaction,
80984
+ ** locking and error handling infrastructure built into the vdbe.
80985
+ **
80986
+ ** After seeking the cursor, the vdbe executes an OP_ResultRow.
80987
+ ** Code external to the Vdbe then "borrows" the b-tree cursor and
80988
+ ** uses it to implement the blob_read(), blob_write() and
80989
+ ** blob_bytes() functions.
80990
+ **
80991
+ ** The sqlite3_blob_close() function finalizes the vdbe program,
80992
+ ** which closes the b-tree cursor and (possibly) commits the
80993
+ ** transaction.
80994
+ */
80995
+ static const int iLn = VDBE_OFFSET_LINENO(4);
80996
+ static const VdbeOpList openBlob[] = {
80997
+ /* addr/ofst */
80998
+ /* {OP_Transaction, 0, 0, 0}, // 0/ inserted separately */
80999
+ {OP_TableLock, 0, 0, 0}, /* 1/0: Acquire a read or write lock */
81000
+ {OP_OpenRead, 0, 0, 0}, /* 2/1: Open a cursor */
81001
+ {OP_Variable, 1, 1, 0}, /* 3/2: Move ?1 into reg[1] */
81002
+ {OP_NotExists, 0, 8, 1}, /* 4/3: Seek the cursor */
81003
+ {OP_Column, 0, 0, 1}, /* 5/4 */
81004
+ {OP_ResultRow, 1, 0, 0}, /* 6/5 */
81005
+ {OP_Goto, 0, 3, 0}, /* 7/6 */
81006
+ {OP_Close, 0, 0, 0}, /* 8/7 */
81007
+ {OP_Halt, 0, 0, 0}, /* 9/8 */
81008
+ };
8073981009
Vdbe *v = (Vdbe *)pBlob->pStmt;
8074081010
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
80741
-
81011
+ VdbeOp *aOp;
8074281012
8074381013
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
8074481014
pTab->pSchema->schema_cookie,
8074581015
pTab->pSchema->iGeneration);
8074681016
sqlite3VdbeChangeP5(v, 1);
80747
- sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
81017
+ aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
8074881018
8074981019
/* Make sure a mutex is held on the table to be accessed */
8075081020
sqlite3VdbeUsesBtree(v, iDb);
8075181021
80752
- /* Configure the OP_TableLock instruction */
81022
+ if( db->mallocFailed==0 ){
81023
+ assert( aOp!=0 );
81024
+ /* Configure the OP_TableLock instruction */
8075381025
#ifdef SQLITE_OMIT_SHARED_CACHE
80754
- sqlite3VdbeChangeToNoop(v, 1);
81026
+ aOp[0].opcode = OP_Noop;
8075581027
#else
80756
- sqlite3VdbeChangeP1(v, 1, iDb);
80757
- sqlite3VdbeChangeP2(v, 1, pTab->tnum);
80758
- sqlite3VdbeChangeP3(v, 1, flags);
80759
- sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
81028
+ aOp[0].p1 = iDb;
81029
+ aOp[0].p2 = pTab->tnum;
81030
+ aOp[0].p3 = flags;
81031
+ sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
81032
+ }
81033
+ if( db->mallocFailed==0 ){
8076081034
#endif
8076181035
80762
- /* Remove either the OP_OpenWrite or OpenRead. Set the P2
80763
- ** parameter of the other to pTab->tnum. */
80764
- sqlite3VdbeChangeToNoop(v, 3 - flags);
80765
- sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
80766
- sqlite3VdbeChangeP3(v, 2 + flags, iDb);
80767
-
80768
- /* Configure the number of columns. Configure the cursor to
80769
- ** think that the table has one more column than it really
80770
- ** does. An OP_Column to retrieve this imaginary column will
80771
- ** always return an SQL NULL. This is useful because it means
80772
- ** we can invoke OP_Column to fill in the vdbe cursors type
80773
- ** and offset cache without causing any IO.
80774
- */
80775
- sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
80776
- sqlite3VdbeChangeP2(v, 6, pTab->nCol);
80777
- if( !db->mallocFailed ){
81036
+ /* Remove either the OP_OpenWrite or OpenRead. Set the P2
81037
+ ** parameter of the other to pTab->tnum. */
81038
+ if( flags ) aOp[1].opcode = OP_OpenWrite;
81039
+ aOp[1].p2 = pTab->tnum;
81040
+ aOp[1].p3 = iDb;
81041
+
81042
+ /* Configure the number of columns. Configure the cursor to
81043
+ ** think that the table has one more column than it really
81044
+ ** does. An OP_Column to retrieve this imaginary column will
81045
+ ** always return an SQL NULL. This is useful because it means
81046
+ ** we can invoke OP_Column to fill in the vdbe cursors type
81047
+ ** and offset cache without causing any IO.
81048
+ */
81049
+ aOp[1].p4type = P4_INT32;
81050
+ aOp[1].p4.i = pTab->nCol+1;
81051
+ aOp[4].p2 = pTab->nCol;
81052
+
8077881053
pParse->nVar = 1;
8077981054
pParse->nMem = 1;
8078081055
pParse->nTab = 1;
8078181056
sqlite3VdbeMakeReady(v, pParse);
8078281057
}
@@ -81685,11 +81960,11 @@
8168581960
assert( pReadr->aBuffer==0 );
8168681961
assert( pReadr->aMap==0 );
8168781962
8168881963
rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
8168981964
if( rc==SQLITE_OK ){
81690
- u64 nByte; /* Size of PMA in bytes */
81965
+ u64 nByte = 0; /* Size of PMA in bytes */
8169181966
rc = vdbePmaReadVarint(pReadr, &nByte);
8169281967
pReadr->iEof = pReadr->iReadOff + nByte;
8169381968
*pnByte += nByte;
8169481969
}
8169581970
@@ -84243,13 +84518,12 @@
8424384518
** return the top-level walk call.
8424484519
**
8424584520
** The return value from this routine is WRC_Abort to abandon the tree walk
8424684521
** and WRC_Continue to continue.
8424784522
*/
84248
-SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
84523
+static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
8424984524
int rc;
84250
- if( pExpr==0 ) return WRC_Continue;
8425184525
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
8425284526
testcase( ExprHasProperty(pExpr, EP_Reduced) );
8425384527
rc = pWalker->xExprCallback(pWalker, pExpr);
8425484528
if( rc==WRC_Continue
8425584529
&& !ExprHasProperty(pExpr,EP_TokenOnly) ){
@@ -84260,10 +84534,13 @@
8426084534
}else{
8426184535
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
8426284536
}
8426384537
}
8426484538
return rc & WRC_Abort;
84539
+}
84540
+SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
84541
+ return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
8426584542
}
8426684543
8426784544
/*
8426884545
** Call sqlite3WalkExpr() for every expression in list p or until
8426984546
** an abort request is seen.
@@ -85034,11 +85311,11 @@
8503485311
no_such_func = 1;
8503585312
}else{
8503685313
wrong_num_args = 1;
8503785314
}
8503885315
}else{
85039
- is_agg = pDef->xFunc==0;
85316
+ is_agg = pDef->xFinalize!=0;
8504085317
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
8504185318
ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
8504285319
if( n==2 ){
8504385320
pExpr->iTable = exprProbability(pList->a[1].pExpr);
8504485321
if( pExpr->iTable<0 ){
@@ -85762,14 +86039,16 @@
8576286039
pParse->nHeight += pExpr->nHeight;
8576386040
}
8576486041
#endif
8576586042
savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
8576686043
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
85767
- memset(&w, 0, sizeof(w));
86044
+ w.pParse = pNC->pParse;
8576886045
w.xExprCallback = resolveExprStep;
8576986046
w.xSelectCallback = resolveSelectStep;
85770
- w.pParse = pNC->pParse;
86047
+ w.xSelectCallback2 = 0;
86048
+ w.walkerDepth = 0;
86049
+ w.eCode = 0;
8577186050
w.u.pNC = pNC;
8577286051
sqlite3WalkExpr(&w, pExpr);
8577386052
#if SQLITE_MAX_EXPR_DEPTH>0
8577486053
pNC->pParse->nHeight -= pExpr->nHeight;
8577586054
#endif
@@ -86327,12 +86606,13 @@
8632786606
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
8632886607
nExtra = pToken->n+1;
8632986608
assert( iValue>=0 );
8633086609
}
8633186610
}
86332
- pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
86611
+ pNew = sqlite3DbMallocRaw(db, sizeof(Expr)+nExtra);
8633386612
if( pNew ){
86613
+ memset(pNew, 0, sizeof(Expr));
8633486614
pNew->op = (u8)op;
8633586615
pNew->iAgg = -1;
8633686616
if( pToken ){
8633786617
if( nExtra==0 ){
8633886618
pNew->flags |= EP_IntValue;
@@ -87000,14 +87280,15 @@
8700087280
ExprList *pList, /* List to which to append. Might be NULL */
8700187281
Expr *pExpr /* Expression to be appended. Might be NULL */
8700287282
){
8700387283
sqlite3 *db = pParse->db;
8700487284
if( pList==0 ){
87005
- pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
87285
+ pList = sqlite3DbMallocRaw(db, sizeof(ExprList) );
8700687286
if( pList==0 ){
8700787287
goto no_mem;
8700887288
}
87289
+ pList->nExpr = 0;
8700987290
pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
8701087291
if( pList->a==0 ) goto no_mem;
8701187292
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
8701287293
struct ExprList_item *a;
8701387294
assert( pList->nExpr>0 );
@@ -88761,11 +89042,11 @@
8876189042
nFarg = pFarg ? pFarg->nExpr : 0;
8876289043
assert( !ExprHasProperty(pExpr, EP_IntValue) );
8876389044
zId = pExpr->u.zToken;
8876489045
nId = sqlite3Strlen30(zId);
8876589046
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
88766
- if( pDef==0 || pDef->xFunc==0 ){
89047
+ if( pDef==0 || pDef->xFinalize!=0 ){
8876789048
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
8876889049
break;
8876989050
}
8877089051
8877189052
/* Attempt a direct implementation of the built-in COALESCE() and
@@ -91433,12 +91714,11 @@
9143391714
static const FuncDef statInitFuncdef = {
9143491715
2+IsStat34, /* nArg */
9143591716
SQLITE_UTF8, /* funcFlags */
9143691717
0, /* pUserData */
9143791718
0, /* pNext */
91438
- statInit, /* xFunc */
91439
- 0, /* xStep */
91719
+ statInit, /* xSFunc */
9144091720
0, /* xFinalize */
9144191721
"stat_init", /* zName */
9144291722
0, /* pHash */
9144391723
0 /* pDestructor */
9144491724
};
@@ -91734,12 +92014,11 @@
9173492014
static const FuncDef statPushFuncdef = {
9173592015
2+IsStat34, /* nArg */
9173692016
SQLITE_UTF8, /* funcFlags */
9173792017
0, /* pUserData */
9173892018
0, /* pNext */
91739
- statPush, /* xFunc */
91740
- 0, /* xStep */
92019
+ statPush, /* xSFunc */
9174192020
0, /* xFinalize */
9174292021
"stat_push", /* zName */
9174392022
0, /* pHash */
9174492023
0 /* pDestructor */
9174592024
};
@@ -91881,12 +92160,11 @@
9188192160
static const FuncDef statGetFuncdef = {
9188292161
1+IsStat34, /* nArg */
9188392162
SQLITE_UTF8, /* funcFlags */
9188492163
0, /* pUserData */
9188592164
0, /* pNext */
91886
- statGet, /* xFunc */
91887
- 0, /* xStep */
92165
+ statGet, /* xSFunc */
9188892166
0, /* xFinalize */
9188992167
"stat_get", /* zName */
9189092168
0, /* pHash */
9189192169
0 /* pDestructor */
9189292170
};
@@ -91898,12 +92176,12 @@
9189892176
#elif SQLITE_DEBUG
9189992177
assert( iParam==STAT_GET_STAT1 );
9190092178
#else
9190192179
UNUSED_PARAMETER( iParam );
9190292180
#endif
91903
- sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut);
91904
- sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
92181
+ sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
92182
+ (char*)&statGetFuncdef, P4_FUNCDEF);
9190592183
sqlite3VdbeChangeP5(v, 1 + IsStat34);
9190692184
}
9190792185
9190892186
/*
9190992187
** Generate code to do an analysis of all indices associated with
@@ -92053,12 +92331,12 @@
9205392331
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
9205492332
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
9205592333
#endif
9205692334
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
9205792335
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
92058
- sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4);
92059
- sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
92336
+ sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
92337
+ (char*)&statInitFuncdef, P4_FUNCDEF);
9206092338
sqlite3VdbeChangeP5(v, 2+IsStat34);
9206192339
9206292340
/* Implementation of the following:
9206392341
**
9206492342
** Rewind csr
@@ -92150,12 +92428,12 @@
9215092428
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
9215192429
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
9215292430
}
9215392431
#endif
9215492432
assert( regChng==(regStat4+1) );
92155
- sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp);
92156
- sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
92433
+ sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
92434
+ (char*)&statPushFuncdef, P4_FUNCDEF);
9215792435
sqlite3VdbeChangeP5(v, 2+IsStat34);
9215892436
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
9215992437
9216092438
/* Add the entry to the stat1 table. */
9216192439
callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
@@ -93208,15 +93486,15 @@
9320893486
sqlite3ExprCode(pParse, pDbname, regArgs+1);
9320993487
sqlite3ExprCode(pParse, pKey, regArgs+2);
9321093488
9321193489
assert( v || db->mallocFailed );
9321293490
if( v ){
93213
- sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3);
93491
+ sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
93492
+ (char *)pFunc, P4_FUNCDEF);
9321493493
assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
9321593494
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
93216
- sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
93217
-
93495
+
9321893496
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
9321993497
** statement only). For DETACH, set it to false (expire all existing
9322093498
** statements).
9322193499
*/
9322293500
sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
@@ -93237,12 +93515,11 @@
9323793515
static const FuncDef detach_func = {
9323893516
1, /* nArg */
9323993517
SQLITE_UTF8, /* funcFlags */
9324093518
0, /* pUserData */
9324193519
0, /* pNext */
93242
- detachFunc, /* xFunc */
93243
- 0, /* xStep */
93520
+ detachFunc, /* xSFunc */
9324493521
0, /* xFinalize */
9324593522
"sqlite_detach", /* zName */
9324693523
0, /* pHash */
9324793524
0 /* pDestructor */
9324893525
};
@@ -93258,12 +93535,11 @@
9325893535
static const FuncDef attach_func = {
9325993536
3, /* nArg */
9326093537
SQLITE_UTF8, /* funcFlags */
9326193538
0, /* pUserData */
9326293539
0, /* pNext */
93263
- attachFunc, /* xFunc */
93264
- 0, /* xStep */
93540
+ attachFunc, /* xSFunc */
9326593541
0, /* xFinalize */
9326693542
"sqlite_attach", /* zName */
9326793543
0, /* pHash */
9326893544
0 /* pDestructor */
9326993545
};
@@ -93723,19 +93999,10 @@
9372393999
** COMMIT
9372494000
** ROLLBACK
9372594001
*/
9372694002
/* #include "sqliteInt.h" */
9372794003
93728
-/*
93729
-** This routine is called when a new SQL statement is beginning to
93730
-** be parsed. Initialize the pParse structure as needed.
93731
-*/
93732
-SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){
93733
- pParse->explain = (u8)explainFlag;
93734
- pParse->nVar = 0;
93735
-}
93736
-
9373794004
#ifndef SQLITE_OMIT_SHARED_CACHE
9373894005
/*
9373994006
** The TableLock structure is only used by the sqlite3TableLock() and
9374094007
** codeTableLocks() functions.
9374194008
*/
@@ -93936,19 +94203,23 @@
9393694203
/* A minimum of one cursor is required if autoincrement is used
9393794204
* See ticket [a696379c1f08866] */
9393894205
if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
9393994206
sqlite3VdbeMakeReady(v, pParse);
9394094207
pParse->rc = SQLITE_DONE;
93941
- pParse->colNamesSet = 0;
9394294208
}else{
9394394209
pParse->rc = SQLITE_ERROR;
9394494210
}
94211
+
94212
+ /* We are done with this Parse object. There is no need to de-initialize it */
94213
+#if 0
94214
+ pParse->colNamesSet = 0;
9394594215
pParse->nTab = 0;
9394694216
pParse->nMem = 0;
9394794217
pParse->nSet = 0;
9394894218
pParse->nVar = 0;
9394994219
DbMaskZero(pParse->cookieMask);
94220
+#endif
9395094221
}
9395194222
9395294223
/*
9395394224
** Run the parser and code generator recursively in order to generate
9395494225
** code for the SQL statement given onto the end of the pParse context
@@ -94203,11 +94474,10 @@
9420394474
if( j<i ){
9420494475
db->aDb[j] = db->aDb[i];
9420594476
}
9420694477
j++;
9420794478
}
94208
- memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
9420994479
db->nDb = j;
9421094480
if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
9421194481
memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
9421294482
sqlite3DbFree(db, db->aDb);
9421394483
db->aDb = db->aDbStatic;
@@ -94466,11 +94736,12 @@
9446694736
Token **pUnqual /* Write the unqualified object name here */
9446794737
){
9446894738
int iDb; /* Database holding the object */
9446994739
sqlite3 *db = pParse->db;
9447094740
94471
- if( ALWAYS(pName2!=0) && pName2->n>0 ){
94741
+ assert( pName2!=0 );
94742
+ if( pName2->n>0 ){
9447294743
if( db->init.busy ) {
9447394744
sqlite3ErrorMsg(pParse, "corrupt database");
9447494745
return -1;
9447594746
}
9447694747
*pUnqual = pName2;
@@ -94555,66 +94826,50 @@
9455594826
sqlite3 *db = pParse->db;
9455694827
Vdbe *v;
9455794828
int iDb; /* Database number to create the table in */
9455894829
Token *pName; /* Unqualified name of the table to create */
9455994830
94560
- /* The table or view name to create is passed to this routine via tokens
94561
- ** pName1 and pName2. If the table name was fully qualified, for example:
94562
- **
94563
- ** CREATE TABLE xxx.yyy (...);
94564
- **
94565
- ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
94566
- ** the table name is not fully qualified, i.e.:
94567
- **
94568
- ** CREATE TABLE yyy(...);
94569
- **
94570
- ** Then pName1 is set to "yyy" and pName2 is "".
94571
- **
94572
- ** The call below sets the pName pointer to point at the token (pName1 or
94573
- ** pName2) that stores the unqualified table name. The variable iDb is
94574
- ** set to the index of the database that the table or view is to be
94575
- ** created in.
94576
- */
94577
- iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
94578
- if( iDb<0 ) return;
94579
- if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
94580
- /* If creating a temp table, the name may not be qualified. Unless
94581
- ** the database name is "temp" anyway. */
94582
- sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
94583
- return;
94584
- }
94585
- if( !OMIT_TEMPDB && isTemp ) iDb = 1;
94586
-
94587
- pParse->sNameToken = *pName;
94588
- zName = sqlite3NameFromToken(db, pName);
94831
+ if( db->init.busy && db->init.newTnum==1 ){
94832
+ /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
94833
+ iDb = db->init.iDb;
94834
+ zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
94835
+ pName = pName1;
94836
+ }else{
94837
+ /* The common case */
94838
+ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
94839
+ if( iDb<0 ) return;
94840
+ if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
94841
+ /* If creating a temp table, the name may not be qualified. Unless
94842
+ ** the database name is "temp" anyway. */
94843
+ sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
94844
+ return;
94845
+ }
94846
+ if( !OMIT_TEMPDB && isTemp ) iDb = 1;
94847
+ zName = sqlite3NameFromToken(db, pName);
94848
+ }
94849
+ pParse->sNameToken = *pName;
9458994850
if( zName==0 ) return;
9459094851
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
9459194852
goto begin_table_error;
9459294853
}
9459394854
if( db->init.iDb==1 ) isTemp = 1;
9459494855
#ifndef SQLITE_OMIT_AUTHORIZATION
94595
- assert( (isTemp & 1)==isTemp );
94856
+ assert( isTemp==0 || isTemp==1 );
94857
+ assert( isView==0 || isView==1 );
9459694858
{
94597
- int code;
94859
+ static const u8 aCode[] = {
94860
+ SQLITE_CREATE_TABLE,
94861
+ SQLITE_CREATE_TEMP_TABLE,
94862
+ SQLITE_CREATE_VIEW,
94863
+ SQLITE_CREATE_TEMP_VIEW
94864
+ };
9459894865
char *zDb = db->aDb[iDb].zName;
9459994866
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
9460094867
goto begin_table_error;
9460194868
}
94602
- if( isView ){
94603
- if( !OMIT_TEMPDB && isTemp ){
94604
- code = SQLITE_CREATE_TEMP_VIEW;
94605
- }else{
94606
- code = SQLITE_CREATE_VIEW;
94607
- }
94608
- }else{
94609
- if( !OMIT_TEMPDB && isTemp ){
94610
- code = SQLITE_CREATE_TEMP_TABLE;
94611
- }else{
94612
- code = SQLITE_CREATE_TABLE;
94613
- }
94614
- }
94615
- if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
94869
+ if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView],
94870
+ zName, 0, zDb) ){
9461694871
goto begin_table_error;
9461794872
}
9461894873
}
9461994874
#endif
9462094875
@@ -95572,13 +95827,17 @@
9557295827
/* If the db->init.busy is 1 it means we are reading the SQL off the
9557395828
** "sqlite_master" or "sqlite_temp_master" table on the disk.
9557495829
** So do not write to the disk again. Extract the root page number
9557595830
** for the table from the db->init.newTnum field. (The page number
9557695831
** should have been put there by the sqliteOpenCb routine.)
95832
+ **
95833
+ ** If the root page number is 1, that means this is the sqlite_master
95834
+ ** table itself. So mark it read-only.
9557795835
*/
9557895836
if( db->init.busy ){
9557995837
p->tnum = db->init.newTnum;
95838
+ if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
9558095839
}
9558195840
9558295841
/* Special processing for WITHOUT ROWID Tables */
9558395842
if( tabOpts & TF_WithoutRowid ){
9558495843
if( (p->tabFlags & TF_Autoincrement) ){
@@ -96027,10 +96286,11 @@
9602796286
** erasing iTable (this can happen with an auto-vacuum database).
9602896287
*/
9602996288
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
9603096289
Vdbe *v = sqlite3GetVdbe(pParse);
9603196290
int r1 = sqlite3GetTempReg(pParse);
96291
+ assert( iTable>1 );
9603296292
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
9603396293
sqlite3MayAbort(pParse);
9603496294
#ifndef SQLITE_OMIT_AUTOVACUUM
9603596295
/* OP_Destroy stores an in integer r1. If this integer
9603696296
** is non-zero, then it is the root page number of a table moved to
@@ -97425,13 +97685,14 @@
9742597685
Token *pDatabase /* Database of the table */
9742697686
){
9742797687
struct SrcList_item *pItem;
9742897688
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
9742997689
if( pList==0 ){
97430
- pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
97690
+ pList = sqlite3DbMallocRaw(db, sizeof(SrcList) );
9743197691
if( pList==0 ) return 0;
9743297692
pList->nAlloc = 1;
97693
+ pList->nSrc = 0;
9743397694
}
9743497695
pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
9743597696
if( db->mallocFailed ){
9743697697
sqlite3SrcListDelete(db, pList);
9743797698
return 0;
@@ -97830,11 +98091,11 @@
9783098091
assert( (errCode&0xff)==SQLITE_CONSTRAINT );
9783198092
if( onError==OE_Abort ){
9783298093
sqlite3MayAbort(pParse);
9783398094
}
9783498095
sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
97835
- if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
98096
+ sqlite3VdbeChangeP5(v, p5Errmsg);
9783698097
}
9783798098
9783898099
/*
9783998100
** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation.
9784098101
*/
@@ -98371,12 +98632,12 @@
9837198632
** 3: encoding matches and function takes any number of arguments
9837298633
** 4: UTF8/16 conversion required - argument count matches exactly
9837398634
** 5: UTF16 byte order conversion required - argument count matches exactly
9837498635
** 6: Perfect match: encoding and argument count match exactly.
9837598636
**
98376
-** If nArg==(-2) then any function with a non-null xStep or xFunc is
98377
-** a perfect match and any function with both xStep and xFunc NULL is
98637
+** If nArg==(-2) then any function with a non-null xSFunc is
98638
+** a perfect match and any function with xSFunc NULL is
9837898639
** a non-match.
9837998640
*/
9838098641
#define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
9838198642
static int matchQuality(
9838298643
FuncDef *p, /* The function we are evaluating for match quality */
@@ -98384,11 +98645,11 @@
9838498645
u8 enc /* Desired text encoding */
9838598646
){
9838698647
int match;
9838798648
9838898649
/* nArg of -2 is a special case */
98389
- if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
98650
+ if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
9839098651
9839198652
/* Wrong number of arguments means "no match" */
9839298653
if( p->nArg!=nArg && p->nArg>=0 ) return 0;
9839398654
9839498655
/* Give a better score to a function with a specific number of arguments
@@ -98462,11 +98723,11 @@
9846298723
** If the createFlag argument is true, then a new (blank) FuncDef
9846398724
** structure is created and liked into the "db" structure if a
9846498725
** no matching function previously existed.
9846598726
**
9846698727
** If nArg is -2, then the first valid function found is returned. A
98467
-** function is valid if either xFunc or xStep is non-zero. The nArg==(-2)
98728
+** function is valid if xSFunc is non-zero. The nArg==(-2)
9846898729
** case is used to see if zName is a valid function name for some number
9846998730
** of arguments. If nArg is -2, then createFlag must be 0.
9847098731
**
9847198732
** If createFlag is false, then a function with the required name and
9847298733
** number of arguments may be returned even if the eTextRep flag does not
@@ -98539,11 +98800,11 @@
9853998800
memcpy(pBest->zName, zName, nName);
9854098801
pBest->zName[nName] = 0;
9854198802
sqlite3FuncDefInsert(&db->aFunc, pBest);
9854298803
}
9854398804
98544
- if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
98805
+ if( pBest && (pBest->xSFunc || createFlag) ){
9854598806
return pBest;
9854698807
}
9854798808
return 0;
9854898809
}
9854998810
@@ -100072,14 +100333,14 @@
100072100333
100073100334
/*
100074100335
** A structure defining how to do GLOB-style comparisons.
100075100336
*/
100076100337
struct compareInfo {
100077
- u8 matchAll;
100078
- u8 matchOne;
100079
- u8 matchSet;
100080
- u8 noCase;
100338
+ u8 matchAll; /* "*" or "%" */
100339
+ u8 matchOne; /* "?" or "_" */
100340
+ u8 matchSet; /* "[" or 0 */
100341
+ u8 noCase; /* true to ignore case differences */
100081100342
};
100082100343
100083100344
/*
100084100345
** For LIKE and GLOB matching on EBCDIC machines, assume that every
100085100346
** character is exactly one byte in size. Also, provde the Utf8Read()
@@ -100138,26 +100399,18 @@
100138100399
*/
100139100400
static int patternCompare(
100140100401
const u8 *zPattern, /* The glob pattern */
100141100402
const u8 *zString, /* The string to compare against the glob */
100142100403
const struct compareInfo *pInfo, /* Information about how to do the compare */
100143
- u32 esc /* The escape character */
100404
+ u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */
100144100405
){
100145100406
u32 c, c2; /* Next pattern and input string chars */
100146100407
u32 matchOne = pInfo->matchOne; /* "?" or "_" */
100147100408
u32 matchAll = pInfo->matchAll; /* "*" or "%" */
100148
- u32 matchOther; /* "[" or the escape character */
100149100409
u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
100150100410
const u8 *zEscaped = 0; /* One past the last escaped input char */
100151100411
100152
- /* The GLOB operator does not have an ESCAPE clause. And LIKE does not
100153
- ** have the matchSet operator. So we either have to look for one or
100154
- ** the other, never both. Hence the single variable matchOther is used
100155
- ** to store the one we have to look for.
100156
- */
100157
- matchOther = esc ? esc : pInfo->matchSet;
100158
-
100159100412
while( (c = Utf8Read(zPattern))!=0 ){
100160100413
if( c==matchAll ){ /* Match "*" */
100161100414
/* Skip over multiple "*" characters in the pattern. If there
100162100415
** are also "?" characters, skip those as well, but consume a
100163100416
** single character of the input string for each "?" skipped */
@@ -100167,19 +100420,19 @@
100167100420
}
100168100421
}
100169100422
if( c==0 ){
100170100423
return 1; /* "*" at the end of the pattern matches */
100171100424
}else if( c==matchOther ){
100172
- if( esc ){
100425
+ if( pInfo->matchSet==0 ){
100173100426
c = sqlite3Utf8Read(&zPattern);
100174100427
if( c==0 ) return 0;
100175100428
}else{
100176100429
/* "[...]" immediately follows the "*". We have to do a slow
100177100430
** recursive search in this case, but it is an unusual case. */
100178100431
assert( matchOther<0x80 ); /* '[' is a single-byte character */
100179100432
while( *zString
100180
- && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
100433
+ && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){
100181100434
SQLITE_SKIP_UTF8(zString);
100182100435
}
100183100436
return *zString!=0;
100184100437
}
100185100438
}
@@ -100201,22 +100454,22 @@
100201100454
}else{
100202100455
cx = c;
100203100456
}
100204100457
while( (c2 = *(zString++))!=0 ){
100205100458
if( c2!=c && c2!=cx ) continue;
100206
- if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
100459
+ if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
100207100460
}
100208100461
}else{
100209100462
while( (c2 = Utf8Read(zString))!=0 ){
100210100463
if( c2!=c ) continue;
100211
- if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
100464
+ if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
100212100465
}
100213100466
}
100214100467
return 0;
100215100468
}
100216100469
if( c==matchOther ){
100217
- if( esc ){
100470
+ if( pInfo->matchSet==0 ){
100218100471
c = sqlite3Utf8Read(&zPattern);
100219100472
if( c==0 ) return 0;
100220100473
zEscaped = zPattern;
100221100474
}else{
100222100475
u32 prior_c = 0;
@@ -100252,11 +100505,11 @@
100252100505
continue;
100253100506
}
100254100507
}
100255100508
c2 = Utf8Read(zString);
100256100509
if( c==c2 ) continue;
100257
- if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
100510
+ if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
100258100511
continue;
100259100512
}
100260100513
if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
100261100514
return 0;
100262100515
}
@@ -100265,11 +100518,11 @@
100265100518
100266100519
/*
100267100520
** The sqlite3_strglob() interface.
100268100521
*/
100269100522
SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
100270
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
100523
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0;
100271100524
}
100272100525
100273100526
/*
100274100527
** The sqlite3_strlike() interface.
100275100528
*/
@@ -100303,13 +100556,14 @@
100303100556
sqlite3_context *context,
100304100557
int argc,
100305100558
sqlite3_value **argv
100306100559
){
100307100560
const unsigned char *zA, *zB;
100308
- u32 escape = 0;
100561
+ u32 escape;
100309100562
int nPat;
100310100563
sqlite3 *db = sqlite3_context_db_handle(context);
100564
+ struct compareInfo *pInfo = sqlite3_user_data(context);
100311100565
100312100566
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
100313100567
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
100314100568
|| sqlite3_value_type(argv[1])==SQLITE_BLOB
100315100569
){
@@ -100345,17 +100599,17 @@
100345100599
sqlite3_result_error(context,
100346100600
"ESCAPE expression must be a single character", -1);
100347100601
return;
100348100602
}
100349100603
escape = sqlite3Utf8Read(&zEsc);
100604
+ }else{
100605
+ escape = pInfo->matchSet;
100350100606
}
100351100607
if( zA && zB ){
100352
- struct compareInfo *pInfo = sqlite3_user_data(context);
100353100608
#ifdef SQLITE_TEST
100354100609
sqlite3_like_count++;
100355100610
#endif
100356
-
100357100611
sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
100358100612
}
100359100613
}
100360100614
100361100615
/*
@@ -104328,11 +104582,11 @@
104328104582
if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
104329104583
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
104330104584
assert( pParse->nested==0 );
104331104585
pik_flags |= OPFLAG_NCHANGE;
104332104586
}
104333
- if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags);
104587
+ sqlite3VdbeChangeP5(v, pik_flags);
104334104588
}
104335104589
if( !HasRowid(pTab) ) return;
104336104590
regData = regNewData + 1;
104337104591
regRec = sqlite3GetTempReg(pParse);
104338104592
sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
@@ -104744,13 +104998,13 @@
104744104998
}else{
104745104999
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
104746105000
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
104747105001
}
104748105002
sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
104749
- sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
105003
+ sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
105004
+ pDest->zName, 0);
104750105005
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
104751
- sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
104752105006
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
104753105007
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
104754105008
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
104755105009
}else{
104756105010
sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName);
@@ -107199,19 +107453,21 @@
107199107453
{ OP_IfPos, 1, 8, 0},
107200107454
{ OP_Integer, 0, 1, 0}, /* 6 */
107201107455
{ OP_Noop, 0, 0, 0},
107202107456
{ OP_ResultRow, 1, 1, 0},
107203107457
};
107204
- int addr;
107458
+ VdbeOp *aOp;
107205107459
sqlite3VdbeUsesBtree(v, iDb);
107206107460
if( !zRight ){
107207107461
setOneColumnName(v, "cache_size");
107208107462
pParse->nMem += 2;
107209
- addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
107210
- sqlite3VdbeChangeP1(v, addr, iDb);
107211
- sqlite3VdbeChangeP1(v, addr+1, iDb);
107212
- sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
107463
+ sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
107464
+ aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
107465
+ if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
107466
+ aOp[0].p1 = iDb;
107467
+ aOp[1].p1 = iDb;
107468
+ aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE;
107213107469
}else{
107214107470
int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
107215107471
sqlite3BeginWriteOperation(pParse, 0, iDb);
107216107472
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
107217107473
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
@@ -107453,17 +107709,20 @@
107453107709
{ OP_If, 1, 0, 0}, /* 2 */
107454107710
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
107455107711
{ OP_Integer, 0, 1, 0}, /* 4 */
107456107712
{ OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
107457107713
};
107458
- int iAddr;
107459
- iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
107460
- sqlite3VdbeChangeP1(v, iAddr, iDb);
107461
- sqlite3VdbeChangeP1(v, iAddr+1, iDb);
107462
- sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
107463
- sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
107464
- sqlite3VdbeChangeP1(v, iAddr+5, iDb);
107714
+ VdbeOp *aOp;
107715
+ int iAddr = sqlite3VdbeCurrentAddr(v);
107716
+ sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6));
107717
+ aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
107718
+ if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
107719
+ aOp[0].p1 = iDb;
107720
+ aOp[1].p1 = iDb;
107721
+ aOp[2].p2 = iAddr+4;
107722
+ aOp[4].p1 = eAuto - 1;
107723
+ aOp[5].p1 = iDb;
107465107724
sqlite3VdbeUsesBtree(v, iDb);
107466107725
}
107467107726
}
107468107727
break;
107469107728
}
@@ -108165,22 +108424,10 @@
108165108424
** without most of the overhead of a full integrity-check.
108166108425
*/
108167108426
case PragTyp_INTEGRITY_CHECK: {
108168108427
int i, j, addr, mxErr;
108169108428
108170
- /* Code that appears at the end of the integrity check. If no error
108171
- ** messages have been generated, output OK. Otherwise output the
108172
- ** error message
108173
- */
108174
- static const int iLn = VDBE_OFFSET_LINENO(2);
108175
- static const VdbeOpList endCode[] = {
108176
- { OP_AddImm, 1, 0, 0}, /* 0 */
108177
- { OP_If, 1, 0, 0}, /* 1 */
108178
- { OP_String8, 0, 3, 0}, /* 2 */
108179
- { OP_ResultRow, 3, 1, 0},
108180
- };
108181
-
108182108429
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
108183108430
108184108431
/* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
108185108432
** then iDb is set to the index of the database identified by <db>.
108186108433
** In this case, the integrity of database iDb only is verified by
@@ -108373,14 +108620,28 @@
108373108620
sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
108374108621
}
108375108622
#endif /* SQLITE_OMIT_BTREECOUNT */
108376108623
}
108377108624
}
108378
- addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
108379
- sqlite3VdbeChangeP2(v, addr, -mxErr);
108380
- sqlite3VdbeJumpHere(v, addr+1);
108381
- sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
108625
+ {
108626
+ static const int iLn = VDBE_OFFSET_LINENO(2);
108627
+ static const VdbeOpList endCode[] = {
108628
+ { OP_AddImm, 1, 0, 0}, /* 0 */
108629
+ { OP_If, 1, 0, 0}, /* 1 */
108630
+ { OP_String8, 0, 3, 0}, /* 2 */
108631
+ { OP_ResultRow, 3, 1, 0},
108632
+ };
108633
+ VdbeOp *aOp;
108634
+
108635
+ aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
108636
+ if( aOp ){
108637
+ aOp[0].p2 = -mxErr;
108638
+ aOp[1].p2 = sqlite3VdbeCurrentAddr(v);
108639
+ aOp[2].p4type = P4_STATIC;
108640
+ aOp[2].p4.z = "ok";
108641
+ }
108642
+ }
108382108643
}
108383108644
break;
108384108645
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
108385108646
108386108647
#ifndef SQLITE_OMIT_UTF16
@@ -108493,26 +108754,32 @@
108493108754
static const VdbeOpList setCookie[] = {
108494108755
{ OP_Transaction, 0, 1, 0}, /* 0 */
108495108756
{ OP_Integer, 0, 1, 0}, /* 1 */
108496108757
{ OP_SetCookie, 0, 0, 1}, /* 2 */
108497108758
};
108498
- int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
108499
- sqlite3VdbeChangeP1(v, addr, iDb);
108500
- sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
108501
- sqlite3VdbeChangeP1(v, addr+2, iDb);
108502
- sqlite3VdbeChangeP2(v, addr+2, iCookie);
108759
+ VdbeOp *aOp;
108760
+ sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));
108761
+ aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
108762
+ if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
108763
+ aOp[0].p1 = iDb;
108764
+ aOp[1].p1 = sqlite3Atoi(zRight);
108765
+ aOp[2].p1 = iDb;
108766
+ aOp[2].p2 = iCookie;
108503108767
}else{
108504108768
/* Read the specified cookie value */
108505108769
static const VdbeOpList readCookie[] = {
108506108770
{ OP_Transaction, 0, 0, 0}, /* 0 */
108507108771
{ OP_ReadCookie, 0, 1, 0}, /* 1 */
108508108772
{ OP_ResultRow, 1, 1, 0}
108509108773
};
108510
- int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
108511
- sqlite3VdbeChangeP1(v, addr, iDb);
108512
- sqlite3VdbeChangeP1(v, addr+1, iDb);
108513
- sqlite3VdbeChangeP3(v, addr+1, iCookie);
108774
+ VdbeOp *aOp;
108775
+ sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie));
108776
+ aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0);
108777
+ if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
108778
+ aOp[0].p1 = iDb;
108779
+ aOp[1].p1 = iDb;
108780
+ aOp[1].p3 = iCookie;
108514108781
sqlite3VdbeSetNumCols(v, 1);
108515108782
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
108516108783
}
108517108784
}
108518108785
break;
@@ -108875,65 +109142,31 @@
108875109142
int rc;
108876109143
int i;
108877109144
#ifndef SQLITE_OMIT_DEPRECATED
108878109145
int size;
108879109146
#endif
108880
- Table *pTab;
108881109147
Db *pDb;
108882109148
char const *azArg[4];
108883109149
int meta[5];
108884109150
InitData initData;
108885
- char const *zMasterSchema;
108886
- char const *zMasterName;
109151
+ const char *zMasterName;
108887109152
int openedTransaction = 0;
108888109153
108889
- /*
108890
- ** The master database table has a structure like this
108891
- */
108892
- static const char master_schema[] =
108893
- "CREATE TABLE sqlite_master(\n"
108894
- " type text,\n"
108895
- " name text,\n"
108896
- " tbl_name text,\n"
108897
- " rootpage integer,\n"
108898
- " sql text\n"
108899
- ")"
108900
- ;
108901
-#ifndef SQLITE_OMIT_TEMPDB
108902
- static const char temp_master_schema[] =
108903
- "CREATE TEMP TABLE sqlite_temp_master(\n"
108904
- " type text,\n"
108905
- " name text,\n"
108906
- " tbl_name text,\n"
108907
- " rootpage integer,\n"
108908
- " sql text\n"
108909
- ")"
108910
- ;
108911
-#else
108912
- #define temp_master_schema 0
108913
-#endif
108914
-
108915109154
assert( iDb>=0 && iDb<db->nDb );
108916109155
assert( db->aDb[iDb].pSchema );
108917109156
assert( sqlite3_mutex_held(db->mutex) );
108918109157
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
108919109158
108920
- /* zMasterSchema and zInitScript are set to point at the master schema
108921
- ** and initialisation script appropriate for the database being
108922
- ** initialized. zMasterName is the name of the master table.
108923
- */
108924
- if( !OMIT_TEMPDB && iDb==1 ){
108925
- zMasterSchema = temp_master_schema;
108926
- }else{
108927
- zMasterSchema = master_schema;
108928
- }
108929
- zMasterName = SCHEMA_TABLE(iDb);
108930
-
108931
- /* Construct the schema tables. */
108932
- azArg[0] = zMasterName;
109159
+ /* Construct the in-memory representation schema tables (sqlite_master or
109160
+ ** sqlite_temp_master) by invoking the parser directly. The appropriate
109161
+ ** table name will be inserted automatically by the parser so we can just
109162
+ ** use the abbreviation "x" here. The parser will also automatically tag
109163
+ ** the schema table as read-only. */
109164
+ azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
108933109165
azArg[1] = "1";
108934
- azArg[2] = zMasterSchema;
109166
+ azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
109167
+ "rootpage integer,sql text)";
108935109168
azArg[3] = 0;
108936109169
initData.db = db;
108937109170
initData.iDb = iDb;
108938109171
initData.rc = SQLITE_OK;
108939109172
initData.pzErrMsg = pzErrMsg;
@@ -108940,14 +109173,10 @@
108940109173
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
108941109174
if( initData.rc ){
108942109175
rc = initData.rc;
108943109176
goto error_out;
108944109177
}
108945
- pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
108946
- if( ALWAYS(pTab) ){
108947
- pTab->tabFlags |= TF_Readonly;
108948
- }
108949109178
108950109179
/* Create a cursor to hold the database open
108951109180
*/
108952109181
pDb = &db->aDb[iDb];
108953109182
if( pDb->pBt==0 ){
@@ -109062,11 +109291,11 @@
109062109291
*/
109063109292
assert( db->init.busy );
109064109293
{
109065109294
char *zSql;
109066109295
zSql = sqlite3MPrintf(db,
109067
- "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
109296
+ "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
109068109297
db->aDb[iDb].zName, zMasterName);
109069109298
#ifndef SQLITE_OMIT_AUTHORIZATION
109070109299
{
109071109300
sqlite3_xauth xAuth;
109072109301
xAuth = db->xAuth;
@@ -109688,10 +109917,11 @@
109688109917
int nOBSat; /* Number of ORDER BY terms satisfied by indices */
109689109918
int iECursor; /* Cursor number for the sorter */
109690109919
int regReturn; /* Register holding block-output return address */
109691109920
int labelBkOut; /* Start label for the block-output subroutine */
109692109921
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
109922
+ int labelDone; /* Jump here when done, ex: LIMIT reached */
109693109923
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
109694109924
};
109695109925
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
109696109926
109697109927
/*
@@ -109745,33 +109975,41 @@
109745109975
Expr *pOffset /* OFFSET value. NULL means no offset */
109746109976
){
109747109977
Select *pNew;
109748109978
Select standin;
109749109979
sqlite3 *db = pParse->db;
109750
- pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
109980
+ pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
109751109981
if( pNew==0 ){
109752109982
assert( db->mallocFailed );
109753109983
pNew = &standin;
109754
- memset(pNew, 0, sizeof(*pNew));
109755109984
}
109756109985
if( pEList==0 ){
109757109986
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
109758109987
}
109759109988
pNew->pEList = pEList;
109989
+ pNew->op = TK_SELECT;
109990
+ pNew->selFlags = selFlags;
109991
+ pNew->iLimit = 0;
109992
+ pNew->iOffset = 0;
109993
+#if SELECTTRACE_ENABLED
109994
+ pNew->zSelName[0] = 0;
109995
+#endif
109996
+ pNew->addrOpenEphm[0] = -1;
109997
+ pNew->addrOpenEphm[1] = -1;
109998
+ pNew->nSelectRow = 0;
109760109999
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
109761110000
pNew->pSrc = pSrc;
109762110001
pNew->pWhere = pWhere;
109763110002
pNew->pGroupBy = pGroupBy;
109764110003
pNew->pHaving = pHaving;
109765110004
pNew->pOrderBy = pOrderBy;
109766
- pNew->selFlags = selFlags;
109767
- pNew->op = TK_SELECT;
110005
+ pNew->pPrior = 0;
110006
+ pNew->pNext = 0;
109768110007
pNew->pLimit = pLimit;
109769110008
pNew->pOffset = pOffset;
110009
+ pNew->pWith = 0;
109770110010
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
109771
- pNew->addrOpenEphm[0] = -1;
109772
- pNew->addrOpenEphm[1] = -1;
109773110011
if( db->mallocFailed ) {
109774110012
clearSelect(db, pNew, pNew!=&standin);
109775110013
pNew = 0;
109776110014
}else{
109777110015
assert( pNew->pSrc!=0 || pParse->nErr>0 );
@@ -110142,10 +110380,11 @@
110142110380
int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
110143110381
int regBase; /* Regs for sorter record */
110144110382
int regRecord = ++pParse->nMem; /* Assembled sorter record */
110145110383
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
110146110384
int op; /* Opcode to add sorter record to sorter */
110385
+ int iLimit; /* LIMIT counter */
110147110386
110148110387
assert( bSeq==0 || bSeq==1 );
110149110388
assert( nData==1 || regData==regOrigData );
110150110389
if( nPrefixReg ){
110151110390
assert( nPrefixReg==nExpr+bSeq );
@@ -110152,19 +110391,21 @@
110152110391
regBase = regData - nExpr - bSeq;
110153110392
}else{
110154110393
regBase = pParse->nMem + 1;
110155110394
pParse->nMem += nBase;
110156110395
}
110396
+ assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
110397
+ iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
110398
+ pSort->labelDone = sqlite3VdbeMakeLabel(v);
110157110399
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
110158110400
SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
110159110401
if( bSeq ){
110160110402
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
110161110403
}
110162110404
if( nPrefixReg==0 ){
110163110405
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
110164110406
}
110165
-
110166110407
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
110167110408
if( nOBSat>0 ){
110168110409
int regPrevKey; /* The first nOBSat columns of the previous row */
110169110410
int addrFirst; /* Address of the OP_IfNot opcode */
110170110411
int addrJmp; /* Address of the OP_Jump opcode */
@@ -110195,10 +110436,14 @@
110195110436
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
110196110437
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
110197110438
pSort->regReturn = ++pParse->nMem;
110198110439
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
110199110440
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
110441
+ if( iLimit ){
110442
+ sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
110443
+ VdbeCoverage(v);
110444
+ }
110200110445
sqlite3VdbeJumpHere(v, addrFirst);
110201110446
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
110202110447
sqlite3VdbeJumpHere(v, addrJmp);
110203110448
}
110204110449
if( pSort->sortFlags & SORTFLAG_UseSorter ){
@@ -110205,18 +110450,12 @@
110205110450
op = OP_SorterInsert;
110206110451
}else{
110207110452
op = OP_IdxInsert;
110208110453
}
110209110454
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
110210
- if( pSelect->iLimit ){
110455
+ if( iLimit ){
110211110456
int addr;
110212
- int iLimit;
110213
- if( pSelect->iOffset ){
110214
- iLimit = pSelect->iOffset+1;
110215
- }else{
110216
- iLimit = pSelect->iLimit;
110217
- }
110218110457
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
110219110458
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
110220110459
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
110221110460
sqlite3VdbeJumpHere(v, addr);
110222110461
}
@@ -110629,19 +110868,20 @@
110629110868
/*
110630110869
** Allocate a KeyInfo object sufficient for an index of N key columns and
110631110870
** X extra columns.
110632110871
*/
110633110872
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
110634
- KeyInfo *p = sqlite3DbMallocZero(0,
110635
- sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
110873
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1);
110874
+ KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra);
110636110875
if( p ){
110637110876
p->aSortOrder = (u8*)&p->aColl[N+X];
110638110877
p->nField = (u16)N;
110639110878
p->nXField = (u16)X;
110640110879
p->enc = ENC(db);
110641110880
p->db = db;
110642110881
p->nRef = 1;
110882
+ memset(&p[1], 0, nExtra);
110643110883
}else{
110644110884
db->mallocFailed = 1;
110645110885
}
110646110886
return p;
110647110887
}
@@ -110816,11 +111056,11 @@
110816111056
SortCtx *pSort, /* Information on the ORDER BY clause */
110817111057
int nColumn, /* Number of columns of data */
110818111058
SelectDest *pDest /* Write the sorted results here */
110819111059
){
110820111060
Vdbe *v = pParse->pVdbe; /* The prepared statement */
110821
- int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
111061
+ int addrBreak = pSort->labelDone; /* Jump here to exit loop */
110822111062
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
110823111063
int addr;
110824111064
int addrOnce = 0;
110825111065
int iTab;
110826111066
ExprList *pOrderBy = pSort->pOrderBy;
@@ -110835,10 +111075,11 @@
110835111075
int bSeq; /* True if sorter record includes seq. no. */
110836111076
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
110837111077
struct ExprList_item *aOutEx = p->pEList->a;
110838111078
#endif
110839111079
111080
+ assert( addrBreak<0 );
110840111081
if( pSort->labelBkOut ){
110841111082
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
110842111083
sqlite3VdbeGoto(v, addrBreak);
110843111084
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
110844111085
}
@@ -116425,12 +116666,12 @@
116425116666
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
116426116667
** is a pointer to the sub-vdbe containing the trigger program. */
116427116668
if( pPrg ){
116428116669
int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
116429116670
116430
- sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
116431
- sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
116671
+ sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem,
116672
+ (const char *)pPrg->pProgram, P4_SUBPROGRAM);
116432116673
VdbeComment(
116433116674
(v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
116434116675
116435116676
/* Set the P5 operand of the OP_Program instruction to non-zero if
116436116677
** recursive invocation of this trigger program is disallowed. Recursive
@@ -118780,11 +119021,11 @@
118780119021
Expr *pExpr /* First argument to the function */
118781119022
){
118782119023
Table *pTab;
118783119024
sqlite3_vtab *pVtab;
118784119025
sqlite3_module *pMod;
118785
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
119026
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
118786119027
void *pArg = 0;
118787119028
FuncDef *pNew;
118788119029
int rc = 0;
118789119030
char *zLowerName;
118790119031
unsigned char *z;
@@ -118808,11 +119049,11 @@
118808119049
zLowerName = sqlite3DbStrDup(db, pDef->zName);
118809119050
if( zLowerName ){
118810119051
for(z=(unsigned char*)zLowerName; *z; z++){
118811119052
*z = sqlite3UpperToLower[*z];
118812119053
}
118813
- rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
119054
+ rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
118814119055
sqlite3DbFree(db, zLowerName);
118815119056
}
118816119057
if( rc==0 ){
118817119058
return pDef;
118818119059
}
@@ -118825,11 +119066,11 @@
118825119066
return pDef;
118826119067
}
118827119068
*pNew = *pDef;
118828119069
pNew->zName = (char *)&pNew[1];
118829119070
memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
118830
- pNew->xFunc = xFunc;
119071
+ pNew->xSFunc = xSFunc;
118831119072
pNew->pUserData = pArg;
118832119073
pNew->funcFlags |= SQLITE_FUNC_EPHEM;
118833119074
return pNew;
118834119075
}
118835119076
@@ -119845,12 +120086,11 @@
119845120086
n--;
119846120087
}
119847120088
119848120089
/* Code the OP_Affinity opcode if there is anything left to do. */
119849120090
if( n>0 ){
119850
- sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
119851
- sqlite3VdbeChangeP4(v, -1, zAff, n);
120091
+ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
119852120092
sqlite3ExprCacheAffinityChange(pParse, base, n);
119853120093
}
119854120094
}
119855120095
119856120096
@@ -121398,10 +121638,11 @@
121398121638
int cnt; /* Number of non-wildcard prefix characters */
121399121639
char wc[3]; /* Wildcard characters */
121400121640
sqlite3 *db = pParse->db; /* Database connection */
121401121641
sqlite3_value *pVal = 0;
121402121642
int op; /* Opcode of pRight */
121643
+ int rc; /* Result code to return */
121403121644
121404121645
if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
121405121646
return 0;
121406121647
}
121407121648
#ifdef SQLITE_EBCDIC
@@ -121463,12 +121704,13 @@
121463121704
}else{
121464121705
z = 0;
121465121706
}
121466121707
}
121467121708
121709
+ rc = (z!=0);
121468121710
sqlite3ValueFree(pVal);
121469
- return (z!=0);
121711
+ return rc;
121470121712
}
121471121713
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
121472121714
121473121715
121474121716
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -126875,12 +127117,11 @@
126875127117
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
126876127118
if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){
126877127119
Bitmask b = pTabItem->colUsed;
126878127120
int n = 0;
126879127121
for(; b; b=b>>1, n++){}
126880
- sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1,
126881
- SQLITE_INT_TO_PTR(n), P4_INT32);
127122
+ sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32);
126882127123
assert( n<=pTab->nCol );
126883127124
}
126884127125
#ifdef SQLITE_ENABLE_CURSOR_HINTS
126885127126
if( pLoop->u.btree.pIndex!=0 ){
126886127127
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
@@ -129343,18 +129584,15 @@
129343129584
** { ... } // User supplied code
129344129585
** #line <lineno> <thisfile>
129345129586
** break;
129346129587
*/
129347129588
/********** Begin reduce actions **********************************************/
129348
- case 5: /* explain ::= */
129349
-{ sqlite3BeginParse(pParse, 0); }
129350
- break;
129351129589
case 6: /* explain ::= EXPLAIN */
129352
-{ sqlite3BeginParse(pParse, 1); }
129590
+{ pParse->explain = 1; }
129353129591
break;
129354129592
case 7: /* explain ::= EXPLAIN QUERY PLAN */
129355
-{ sqlite3BeginParse(pParse, 2); }
129593
+{ pParse->explain = 2; }
129356129594
break;
129357129595
case 8: /* cmdx ::= cmd */
129358129596
{ sqlite3FinishCoding(pParse); }
129359129597
break;
129360129598
case 9: /* cmd ::= BEGIN transtype trans_opt */
@@ -130525,10 +130763,11 @@
130525130763
/* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
130526130764
/* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
130527130765
/* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
130528130766
/* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
130529130767
/* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
130768
+ /* (5) explain ::= */ yytestcase(yyruleno==5);
130530130769
/* (10) trans_opt ::= */ yytestcase(yyruleno==10);
130531130770
/* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
130532130771
/* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
130533130772
/* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
130534130773
/* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
@@ -133601,11 +133840,11 @@
133601133840
sqlite3 *db,
133602133841
const char *zFunctionName,
133603133842
int nArg,
133604133843
int enc,
133605133844
void *pUserData,
133606
- void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
133845
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
133607133846
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133608133847
void (*xFinal)(sqlite3_context*),
133609133848
FuncDestructor *pDestructor
133610133849
){
133611133850
FuncDef *p;
@@ -133612,13 +133851,13 @@
133612133851
int nName;
133613133852
int extraFlags;
133614133853
133615133854
assert( sqlite3_mutex_held(db->mutex) );
133616133855
if( zFunctionName==0 ||
133617
- (xFunc && (xFinal || xStep)) ||
133618
- (!xFunc && (xFinal && !xStep)) ||
133619
- (!xFunc && (!xFinal && xStep)) ||
133856
+ (xSFunc && (xFinal || xStep)) ||
133857
+ (!xSFunc && (xFinal && !xStep)) ||
133858
+ (!xSFunc && (!xFinal && xStep)) ||
133620133859
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
133621133860
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
133622133861
return SQLITE_MISUSE_BKPT;
133623133862
}
133624133863
@@ -133637,14 +133876,14 @@
133637133876
if( enc==SQLITE_UTF16 ){
133638133877
enc = SQLITE_UTF16NATIVE;
133639133878
}else if( enc==SQLITE_ANY ){
133640133879
int rc;
133641133880
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
133642
- pUserData, xFunc, xStep, xFinal, pDestructor);
133881
+ pUserData, xSFunc, xStep, xFinal, pDestructor);
133643133882
if( rc==SQLITE_OK ){
133644133883
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
133645
- pUserData, xFunc, xStep, xFinal, pDestructor);
133884
+ pUserData, xSFunc, xStep, xFinal, pDestructor);
133646133885
}
133647133886
if( rc!=SQLITE_OK ){
133648133887
return rc;
133649133888
}
133650133889
enc = SQLITE_UTF16BE;
@@ -133684,12 +133923,11 @@
133684133923
pDestructor->nRef++;
133685133924
}
133686133925
p->pDestructor = pDestructor;
133687133926
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
133688133927
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
133689
- p->xFunc = xFunc;
133690
- p->xStep = xStep;
133928
+ p->xSFunc = xSFunc ? xSFunc : xStep;
133691133929
p->xFinalize = xFinal;
133692133930
p->pUserData = pUserData;
133693133931
p->nArg = (u16)nArg;
133694133932
return SQLITE_OK;
133695133933
}
@@ -133701,25 +133939,25 @@
133701133939
sqlite3 *db,
133702133940
const char *zFunc,
133703133941
int nArg,
133704133942
int enc,
133705133943
void *p,
133706
- void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
133944
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
133707133945
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133708133946
void (*xFinal)(sqlite3_context*)
133709133947
){
133710
- return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
133948
+ return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
133711133949
xFinal, 0);
133712133950
}
133713133951
133714133952
SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
133715133953
sqlite3 *db,
133716133954
const char *zFunc,
133717133955
int nArg,
133718133956
int enc,
133719133957
void *p,
133720
- void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
133958
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
133721133959
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133722133960
void (*xFinal)(sqlite3_context*),
133723133961
void (*xDestroy)(void *)
133724133962
){
133725133963
int rc = SQLITE_ERROR;
@@ -133738,11 +133976,11 @@
133738133976
goto out;
133739133977
}
133740133978
pArg->xDestroy = xDestroy;
133741133979
pArg->pUserData = p;
133742133980
}
133743
- rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
133981
+ rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
133744133982
if( pArg && pArg->nRef==0 ){
133745133983
assert( rc!=SQLITE_OK );
133746133984
xDestroy(p);
133747133985
sqlite3DbFree(db, pArg);
133748133986
}
@@ -133758,11 +133996,11 @@
133758133996
sqlite3 *db,
133759133997
const void *zFunctionName,
133760133998
int nArg,
133761133999
int eTextRep,
133762134000
void *p,
133763
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
134001
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
133764134002
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
133765134003
void (*xFinal)(sqlite3_context*)
133766134004
){
133767134005
int rc;
133768134006
char *zFunc8;
@@ -133771,11 +134009,11 @@
133771134009
if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT;
133772134010
#endif
133773134011
sqlite3_mutex_enter(db->mutex);
133774134012
assert( !db->mallocFailed );
133775134013
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
133776
- rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
134014
+ rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
133777134015
sqlite3DbFree(db, zFunc8);
133778134016
rc = sqlite3ApiExit(db, rc);
133779134017
sqlite3_mutex_leave(db->mutex);
133780134018
return rc;
133781134019
}
@@ -134996,11 +135234,10 @@
134996135234
sqlite3GlobalConfig.nLookaside);
134997135235
134998135236
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
134999135237
135000135238
opendb_out:
135001
- sqlite3_free(zOpen);
135002135239
if( db ){
135003135240
assert( db->mutex!=0 || isThreadsafe==0
135004135241
|| sqlite3GlobalConfig.bFullMutex==0 );
135005135242
sqlite3_mutex_leave(db->mutex);
135006135243
}
@@ -135033,10 +135270,11 @@
135033135270
}
135034135271
sqlite3_key_v2(db, 0, zKey, i/2);
135035135272
}
135036135273
}
135037135274
#endif
135275
+ sqlite3_free(zOpen);
135038135276
return rc & 0xff;
135039135277
}
135040135278
135041135279
/*
135042135280
** Open a new database handle.
@@ -135450,10 +135688,13 @@
135450135688
*(sqlite3_file**)pArg = fd;
135451135689
rc = SQLITE_OK;
135452135690
}else if( op==SQLITE_FCNTL_VFS_POINTER ){
135453135691
*(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
135454135692
rc = SQLITE_OK;
135693
+ }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
135694
+ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
135695
+ rc = SQLITE_OK;
135455135696
}else if( fd->pMethods ){
135456135697
rc = sqlite3OsFileControl(fd, op, pArg);
135457135698
}else{
135458135699
rc = SQLITE_NOTFOUND;
135459135700
}
@@ -161083,11 +161324,11 @@
161083161324
*/
161084161325
static void *rbuMalloc(sqlite3rbu *p, int nByte){
161085161326
void *pRet = 0;
161086161327
if( p->rc==SQLITE_OK ){
161087161328
assert( nByte>0 );
161088
- pRet = sqlite3_malloc(nByte);
161329
+ pRet = sqlite3_malloc64(nByte);
161089161330
if( pRet==0 ){
161090161331
p->rc = SQLITE_NOMEM;
161091161332
}else{
161092161333
memset(pRet, 0, nByte);
161093161334
}
@@ -161129,12 +161370,12 @@
161129161370
static char *rbuStrndup(const char *zStr, int *pRc){
161130161371
char *zRet = 0;
161131161372
161132161373
assert( *pRc==SQLITE_OK );
161133161374
if( zStr ){
161134
- int nCopy = strlen(zStr) + 1;
161135
- zRet = (char*)sqlite3_malloc(nCopy);
161375
+ size_t nCopy = strlen(zStr) + 1;
161376
+ zRet = (char*)sqlite3_malloc64(nCopy);
161136161377
if( zRet ){
161137161378
memcpy(zRet, zStr, nCopy);
161138161379
}else{
161139161380
*pRc = SQLITE_NOMEM;
161140161381
}
@@ -162478,11 +162719,11 @@
162478162719
162479162720
pRbu->pgsz = iAmt;
162480162721
if( pRbu->nFrame==pRbu->nFrameAlloc ){
162481162722
int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
162482162723
RbuFrame *aNew;
162483
- aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame));
162724
+ aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame));
162484162725
if( aNew==0 ) return SQLITE_NOMEM;
162485162726
pRbu->aFrame = aNew;
162486162727
pRbu->nFrameAlloc = nNew;
162487162728
}
162488162729
@@ -162543,11 +162784,11 @@
162543162784
162544162785
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
162545162786
if( nChar==0 ){
162546162787
return 0;
162547162788
}
162548
- zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
162789
+ zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
162549162790
if( zWideFilename==0 ){
162550162791
return 0;
162551162792
}
162552162793
memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
162553162794
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
@@ -163177,15 +163418,16 @@
163177163418
const char *zTarget,
163178163419
const char *zRbu,
163179163420
const char *zState
163180163421
){
163181163422
sqlite3rbu *p;
163182
- int nTarget = strlen(zTarget);
163183
- int nRbu = strlen(zRbu);
163184
- int nState = zState ? strlen(zState) : 0;
163423
+ size_t nTarget = strlen(zTarget);
163424
+ size_t nRbu = strlen(zRbu);
163425
+ size_t nState = zState ? strlen(zState) : 0;
163426
+ size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1;
163185163427
163186
- p = (sqlite3rbu*)sqlite3_malloc(sizeof(sqlite3rbu)+nTarget+1+nRbu+1+nState+1);
163428
+ p = (sqlite3rbu*)sqlite3_malloc64(nByte);
163187163429
if( p ){
163188163430
RbuState *pState = 0;
163189163431
163190163432
/* Create the custom VFS. */
163191163433
memset(p, 0, sizeof(sqlite3rbu));
@@ -163318,11 +163560,11 @@
163318163560
** the pattern "rbu_imp_[0-9]*".
163319163561
*/
163320163562
static void rbuEditErrmsg(sqlite3rbu *p){
163321163563
if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
163322163564
int i;
163323
- int nErrmsg = strlen(p->zErrmsg);
163565
+ size_t nErrmsg = strlen(p->zErrmsg);
163324163566
for(i=0; i<(nErrmsg-8); i++){
163325163567
if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
163326163568
int nDel = 8;
163327163569
while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
163328163570
memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
@@ -163782,11 +164024,11 @@
163782164024
** instead of a file on disk. */
163783164025
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
163784164026
if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
163785164027
if( iRegion<=p->nShm ){
163786164028
int nByte = (iRegion+1) * sizeof(char*);
163787
- char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
164029
+ char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
163788164030
if( apNew==0 ){
163789164031
rc = SQLITE_NOMEM;
163790164032
}else{
163791164033
memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
163792164034
p->apShm = apNew;
@@ -163793,11 +164035,11 @@
163793164035
p->nShm = iRegion+1;
163794164036
}
163795164037
}
163796164038
163797164039
if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
163798
- char *pNew = (char*)sqlite3_malloc(szRegion);
164040
+ char *pNew = (char*)sqlite3_malloc64(szRegion);
163799164041
if( pNew==0 ){
163800164042
rc = SQLITE_NOMEM;
163801164043
}else{
163802164044
memset(pNew, 0, szRegion);
163803164045
p->apShm[iRegion] = pNew;
@@ -163903,11 +164145,11 @@
163903164145
/* A main database has just been opened. The following block sets
163904164146
** (pFd->zWal) to point to a buffer owned by SQLite that contains
163905164147
** the name of the *-wal file this db connection will use. SQLite
163906164148
** happens to pass a pointer to this buffer when using xAccess()
163907164149
** or xOpen() to operate on the *-wal file. */
163908
- int n = strlen(zName);
164150
+ int n = (int)strlen(zName);
163909164151
const char *z = &zName[n];
163910164152
if( flags & SQLITE_OPEN_URI ){
163911164153
int odd = 0;
163912164154
while( 1 ){
163913164155
if( z[0]==0 ){
@@ -163929,12 +164171,12 @@
163929164171
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
163930164172
/* This call is to open a *-wal file. Intead, open the *-oal. This
163931164173
** code ensures that the string passed to xOpen() is terminated by a
163932164174
** pair of '\0' bytes in case the VFS attempts to extract a URI
163933164175
** parameter from it. */
163934
- int nCopy = strlen(zName);
163935
- char *zCopy = sqlite3_malloc(nCopy+2);
164176
+ size_t nCopy = strlen(zName);
164177
+ char *zCopy = sqlite3_malloc64(nCopy+2);
163936164178
if( zCopy ){
163937164179
memcpy(zCopy, zName, nCopy);
163938164180
zCopy[nCopy-3] = 'o';
163939164181
zCopy[nCopy] = '\0';
163940164182
zCopy[nCopy+1] = '\0';
@@ -164159,17 +164401,17 @@
164159164401
0, /* xCurrentTimeInt64 (version 2) */
164160164402
0, 0, 0 /* Unimplemented version 3 methods */
164161164403
};
164162164404
164163164405
rbu_vfs *pNew = 0; /* Newly allocated VFS */
164164
- int nName;
164165164406
int rc = SQLITE_OK;
164407
+ size_t nName;
164408
+ size_t nByte;
164166164409
164167
- int nByte;
164168164410
nName = strlen(zName);
164169164411
nByte = sizeof(rbu_vfs) + nName + 1;
164170
- pNew = (rbu_vfs*)sqlite3_malloc(nByte);
164412
+ pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
164171164413
if( pNew==0 ){
164172164414
rc = SQLITE_NOMEM;
164173164415
}else{
164174164416
sqlite3_vfs *pParent; /* Parent VFS */
164175164417
memset(pNew, 0, nByte);
@@ -167174,10 +167416,13 @@
167174167416
** If parameter iCol is greater than or equal to the number of columns
167175167417
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
167176167418
** an OOM condition or IO error), an appropriate SQLite error code is
167177167419
** returned.
167178167420
**
167421
+** This function may be quite inefficient if used with an FTS5 table
167422
+** created with the "columnsize=0" option.
167423
+**
167179167424
** xColumnText:
167180167425
** This function attempts to retrieve the text of column iCol of the
167181167426
** current document. If successful, (*pz) is set to point to a buffer
167182167427
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
167183167428
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -167194,18 +167439,32 @@
167194167439
** xInstCount:
167195167440
** Set *pnInst to the total number of occurrences of all phrases within
167196167441
** the query within the current row. Return SQLITE_OK if successful, or
167197167442
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
167198167443
**
167444
+** This API can be quite slow if used with an FTS5 table created with the
167445
+** "detail=none" or "detail=column" option. If the FTS5 table is created
167446
+** with either "detail=none" or "detail=column" and "content=" option
167447
+** (i.e. if it is a contentless table), then this API always returns 0.
167448
+**
167199167449
** xInst:
167200167450
** Query for the details of phrase match iIdx within the current row.
167201167451
** Phrase matches are numbered starting from zero, so the iIdx argument
167202167452
** should be greater than or equal to zero and smaller than the value
167203167453
** output by xInstCount().
167454
+**
167455
+** Usually, output parameter *piPhrase is set to the phrase number, *piCol
167456
+** to the column in which it occurs and *piOff the token offset of the
167457
+** first token of the phrase. The exception is if the table was created
167458
+** with the offsets=0 option specified. In this case *piOff is always
167459
+** set to -1.
167204167460
**
167205167461
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
167206167462
** if an error occurs.
167463
+**
167464
+** This API can be quite slow if used with an FTS5 table created with the
167465
+** "detail=none" or "detail=column" option.
167207167466
**
167208167467
** xRowid:
167209167468
** Returns the rowid of the current row.
167210167469
**
167211167470
** xTokenize:
@@ -167286,25 +167545,63 @@
167286167545
** through instances of phrase iPhrase, use the following code:
167287167546
**
167288167547
** Fts5PhraseIter iter;
167289167548
** int iCol, iOff;
167290167549
** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
167291
-** iOff>=0;
167550
+** iCol>=0;
167292167551
** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
167293167552
** ){
167294167553
** // An instance of phrase iPhrase at offset iOff of column iCol
167295167554
** }
167296167555
**
167297167556
** The Fts5PhraseIter structure is defined above. Applications should not
167298167557
** modify this structure directly - it should only be used as shown above
167299
-** with the xPhraseFirst() and xPhraseNext() API methods.
167558
+** with the xPhraseFirst() and xPhraseNext() API methods (and by
167559
+** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
167560
+**
167561
+** This API can be quite slow if used with an FTS5 table created with the
167562
+** "detail=none" or "detail=column" option. If the FTS5 table is created
167563
+** with either "detail=none" or "detail=column" and "content=" option
167564
+** (i.e. if it is a contentless table), then this API always iterates
167565
+** through an empty set (all calls to xPhraseFirst() set iCol to -1).
167300167566
**
167301167567
** xPhraseNext()
167302167568
** See xPhraseFirst above.
167569
+**
167570
+** xPhraseFirstColumn()
167571
+** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
167572
+** and xPhraseNext() APIs described above. The difference is that instead
167573
+** of iterating through all instances of a phrase in the current row, these
167574
+** APIs are used to iterate through the set of columns in the current row
167575
+** that contain one or more instances of a specified phrase. For example:
167576
+**
167577
+** Fts5PhraseIter iter;
167578
+** int iCol;
167579
+** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
167580
+** iCol>=0;
167581
+** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
167582
+** ){
167583
+** // Column iCol contains at least one instance of phrase iPhrase
167584
+** }
167585
+**
167586
+** This API can be quite slow if used with an FTS5 table created with the
167587
+** "detail=none" option. If the FTS5 table is created with either
167588
+** "detail=none" "content=" option (i.e. if it is a contentless table),
167589
+** then this API always iterates through an empty set (all calls to
167590
+** xPhraseFirstColumn() set iCol to -1).
167591
+**
167592
+** The information accessed using this API and its companion
167593
+** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
167594
+** (or xInst/xInstCount). The chief advantage of this API is that it is
167595
+** significantly more efficient than those alternatives when used with
167596
+** "detail=column" tables.
167597
+**
167598
+** xPhraseNextColumn()
167599
+** See xPhraseFirstColumn above.
167303167600
*/
167304167601
struct Fts5ExtensionApi {
167305
- int iVersion; /* Currently always set to 1 */
167602
+ int iVersion; /* Currently always set to 3 */
167306167603
167307167604
void *(*xUserData)(Fts5Context*);
167308167605
167309167606
int (*xColumnCount)(Fts5Context*);
167310167607
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -167330,12 +167627,15 @@
167330167627
int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
167331167628
);
167332167629
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
167333167630
void *(*xGetAuxdata)(Fts5Context*, int bClear);
167334167631
167335
- void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
167632
+ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
167336167633
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
167634
+
167635
+ int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
167636
+ void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
167337167637
};
167338167638
167339167639
/*
167340167640
** CUSTOM AUXILIARY FUNCTIONS
167341167641
*************************************************************************/
@@ -167762,10 +168062,11 @@
167762168062
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
167763168063
int eContent; /* An FTS5_CONTENT value */
167764168064
char *zContent; /* content table */
167765168065
char *zContentRowid; /* "content_rowid=" option value */
167766168066
int bColumnsize; /* "columnsize=" option value (dflt==1) */
168067
+ int eDetail; /* FTS5_DETAIL_XXX value */
167767168068
char *zContentExprlist;
167768168069
Fts5Tokenizer *pTok;
167769168070
fts5_tokenizer *pTokApi;
167770168071
167771168072
/* Values loaded from the %_config table */
@@ -167790,10 +168091,13 @@
167790168091
167791168092
#define FTS5_CONTENT_NORMAL 0
167792168093
#define FTS5_CONTENT_NONE 1
167793168094
#define FTS5_CONTENT_EXTERNAL 2
167794168095
168096
+#define FTS5_DETAIL_FULL 0
168097
+#define FTS5_DETAIL_NONE 1
168098
+#define FTS5_DETAIL_COLUMNS 2
167795168099
167796168100
167797168101
167798168102
static int sqlite3Fts5ConfigParse(
167799168103
Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
@@ -167832,17 +168136,17 @@
167832168136
** Buffer object for the incremental building of string data.
167833168137
*/
167834168138
typedef struct Fts5Buffer Fts5Buffer;
167835168139
struct Fts5Buffer {
167836168140
u8 *p;
167837
- int n;
167838
- int nSpace;
168141
+ u32 n;
168142
+ u32 nSpace;
167839168143
};
167840168144
167841
-static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, int);
168145
+static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32);
167842168146
static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
167843
-static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*);
168147
+static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*);
167844168148
static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
167845168149
static void sqlite3Fts5BufferFree(Fts5Buffer*);
167846168150
static void sqlite3Fts5BufferZero(Fts5Buffer*);
167847168151
static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
167848168152
static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
@@ -167903,10 +168207,17 @@
167903168207
static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
167904168208
167905168209
/* Character set tests (like isspace(), isalpha() etc.) */
167906168210
static int sqlite3Fts5IsBareword(char t);
167907168211
168212
+
168213
+/* Bucket of terms object used by the integrity-check in offsets=0 mode. */
168214
+typedef struct Fts5Termset Fts5Termset;
168215
+static int sqlite3Fts5TermsetNew(Fts5Termset**);
168216
+static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent);
168217
+static void sqlite3Fts5TermsetFree(Fts5Termset*);
168218
+
167908168219
/*
167909168220
** End of interface to code in fts5_buffer.c.
167910168221
**************************************************************************/
167911168222
167912168223
/**************************************************************************
@@ -167938,10 +168249,33 @@
167938168249
** sqlite3Fts5IterNext(pIter)
167939168250
** ){
167940168251
** i64 iRowid = sqlite3Fts5IterRowid(pIter);
167941168252
** }
167942168253
*/
168254
+
168255
+/*
168256
+** Return a simple checksum value based on the arguments.
168257
+*/
168258
+static u64 sqlite3Fts5IndexEntryCksum(
168259
+ i64 iRowid,
168260
+ int iCol,
168261
+ int iPos,
168262
+ int iIdx,
168263
+ const char *pTerm,
168264
+ int nTerm
168265
+);
168266
+
168267
+/*
168268
+** Argument p points to a buffer containing utf-8 text that is n bytes in
168269
+** size. Return the number of bytes in the nChar character prefix of the
168270
+** buffer, or 0 if there are less than nChar characters in total.
168271
+*/
168272
+static int sqlite3Fts5IndexCharlenToBytelen(
168273
+ const char *p,
168274
+ int nByte,
168275
+ int nChar
168276
+);
167943168277
167944168278
/*
167945168279
** Open a new iterator to iterate though all rowids that match the
167946168280
** specified token or token prefix.
167947168281
*/
@@ -168024,11 +168358,10 @@
168024168358
static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
168025168359
168026168360
/*
168027168361
** Functions called by the storage module as part of integrity-check.
168028168362
*/
168029
-static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int);
168030168363
static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
168031168364
168032168365
/*
168033168366
** Called during virtual module initialization to register UDF
168034168367
** fts5_decode() with SQLite
@@ -168046,10 +168379,12 @@
168046168379
static int sqlite3Fts5IndexReinit(Fts5Index *p);
168047168380
static int sqlite3Fts5IndexOptimize(Fts5Index *p);
168048168381
static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
168049168382
168050168383
static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
168384
+
168385
+static int sqlite3Fts5IterCollist(Fts5IndexIter*, const u8 **, int*);
168051168386
168052168387
/*
168053168388
** End of interface to code in fts5_index.c.
168054168389
**************************************************************************/
168055168390
@@ -168103,11 +168438,11 @@
168103168438
typedef struct Fts5Hash Fts5Hash;
168104168439
168105168440
/*
168106168441
** Create a hash table, free a hash table.
168107168442
*/
168108
-static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize);
168443
+static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize);
168109168444
static void sqlite3Fts5HashFree(Fts5Hash*);
168110168445
168111168446
static int sqlite3Fts5HashWrite(
168112168447
Fts5Hash*,
168113168448
i64 iRowid, /* Rowid for this entry */
@@ -168162,11 +168497,11 @@
168162168497
static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
168163168498
168164168499
static int sqlite3Fts5DropAll(Fts5Config*);
168165168500
static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
168166168501
168167
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64);
168502
+static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
168168168503
static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
168169168504
static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
168170168505
168171168506
static int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
168172168507
@@ -168182,12 +168517,10 @@
168182168517
168183168518
static int sqlite3Fts5StorageConfigValue(
168184168519
Fts5Storage *p, const char*, sqlite3_value*, int
168185168520
);
168186168521
168187
-static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**);
168188
-
168189168522
static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
168190168523
static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
168191168524
static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
168192168525
static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
168193168526
@@ -168239,12 +168572,22 @@
168239168572
static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
168240168573
168241168574
static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
168242168575
static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
168243168576
static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
168577
+
168578
+typedef struct Fts5PoslistPopulator Fts5PoslistPopulator;
168579
+static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int);
168580
+static int sqlite3Fts5ExprPopulatePoslists(
168581
+ Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
168582
+);
168583
+static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
168584
+static void sqlite3Fts5ExprClearEof(Fts5Expr*);
168244168585
168245168586
static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
168587
+
168588
+static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
168246168589
168247168590
/*******************************************
168248168591
** The fts5_expr.c API above this point is used by the other hand-written
168249168592
** C code in this module. The interfaces below this point are called by
168250168593
** the parser code in fts5parse.y. */
@@ -170120,12 +170463,12 @@
170120170463
170121170464
170122170465
170123170466
/* #include "fts5Int.h" */
170124170467
170125
-static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, int nByte){
170126
- int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
170468
+static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
170469
+ u32 nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
170127170470
u8 *pNew;
170128170471
while( nNew<nByte ){
170129170472
nNew = nNew * 2;
170130170473
}
170131170474
pNew = sqlite3_realloc(pBuf->p, nNew);
@@ -170166,14 +170509,14 @@
170166170509
** is called, it is a no-op.
170167170510
*/
170168170511
static void sqlite3Fts5BufferAppendBlob(
170169170512
int *pRc,
170170170513
Fts5Buffer *pBuf,
170171
- int nData,
170514
+ u32 nData,
170172170515
const u8 *pData
170173170516
){
170174
- assert( *pRc || nData>=0 );
170517
+ assert_nc( *pRc || nData>=0 );
170175170518
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
170176170519
memcpy(&pBuf->p[pBuf->n], pData, nData);
170177170520
pBuf->n += nData;
170178170521
}
170179170522
@@ -170397,10 +170740,96 @@
170397170740
170398170741
return (t & 0x80) || aBareword[(int)t];
170399170742
}
170400170743
170401170744
170745
+/*************************************************************************
170746
+*/
170747
+typedef struct Fts5TermsetEntry Fts5TermsetEntry;
170748
+struct Fts5TermsetEntry {
170749
+ char *pTerm;
170750
+ int nTerm;
170751
+ int iIdx; /* Index (main or aPrefix[] entry) */
170752
+ Fts5TermsetEntry *pNext;
170753
+};
170754
+
170755
+struct Fts5Termset {
170756
+ Fts5TermsetEntry *apHash[512];
170757
+};
170758
+
170759
+static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
170760
+ int rc = SQLITE_OK;
170761
+ *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset));
170762
+ return rc;
170763
+}
170764
+
170765
+static int sqlite3Fts5TermsetAdd(
170766
+ Fts5Termset *p,
170767
+ int iIdx,
170768
+ const char *pTerm, int nTerm,
170769
+ int *pbPresent
170770
+){
170771
+ int rc = SQLITE_OK;
170772
+ *pbPresent = 0;
170773
+ if( p ){
170774
+ int i;
170775
+ int hash = 13;
170776
+ Fts5TermsetEntry *pEntry;
170777
+
170778
+ /* Calculate a hash value for this term. This is the same hash checksum
170779
+ ** used by the fts5_hash.c module. This is not important for correct
170780
+ ** operation of the module, but is necessary to ensure that some tests
170781
+ ** designed to produce hash table collisions really do work. */
170782
+ for(i=nTerm-1; i>=0; i--){
170783
+ hash = (hash << 3) ^ hash ^ pTerm[i];
170784
+ }
170785
+ hash = (hash << 3) ^ hash ^ iIdx;
170786
+ hash = hash % ArraySize(p->apHash);
170787
+
170788
+ for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
170789
+ if( pEntry->iIdx==iIdx
170790
+ && pEntry->nTerm==nTerm
170791
+ && memcmp(pEntry->pTerm, pTerm, nTerm)==0
170792
+ ){
170793
+ *pbPresent = 1;
170794
+ break;
170795
+ }
170796
+ }
170797
+
170798
+ if( pEntry==0 ){
170799
+ pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm);
170800
+ if( pEntry ){
170801
+ pEntry->pTerm = (char*)&pEntry[1];
170802
+ pEntry->nTerm = nTerm;
170803
+ pEntry->iIdx = iIdx;
170804
+ memcpy(pEntry->pTerm, pTerm, nTerm);
170805
+ pEntry->pNext = p->apHash[hash];
170806
+ p->apHash[hash] = pEntry;
170807
+ }
170808
+ }
170809
+ }
170810
+
170811
+ return rc;
170812
+}
170813
+
170814
+static void sqlite3Fts5TermsetFree(Fts5Termset *p){
170815
+ if( p ){
170816
+ int i;
170817
+ for(i=0; i<ArraySize(p->apHash); i++){
170818
+ Fts5TermsetEntry *pEntry = p->apHash[i];
170819
+ while( pEntry ){
170820
+ Fts5TermsetEntry *pDel = pEntry;
170821
+ pEntry = pEntry->pNext;
170822
+ sqlite3_free(pDel);
170823
+ }
170824
+ }
170825
+ sqlite3_free(p);
170826
+ }
170827
+}
170828
+
170829
+
170830
+
170402170831
170403170832
/*
170404170833
** 2014 Jun 09
170405170834
**
170406170835
** The author disclaims copyright to this source code. In place of
@@ -170412,11 +170841,10 @@
170412170841
**
170413170842
******************************************************************************
170414170843
**
170415170844
** This is an SQLite module implementing full-text search.
170416170845
*/
170417
-
170418170846
170419170847
170420170848
/* #include "fts5Int.h" */
170421170849
170422170850
#define FTS5_DEFAULT_PAGE_SIZE 4050
@@ -170595,10 +171023,37 @@
170595171023
if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
170596171024
fts5Dequote(z);
170597171025
}
170598171026
}
170599171027
171028
+
171029
+struct Fts5Enum {
171030
+ const char *zName;
171031
+ int eVal;
171032
+};
171033
+typedef struct Fts5Enum Fts5Enum;
171034
+
171035
+static int fts5ConfigSetEnum(
171036
+ const Fts5Enum *aEnum,
171037
+ const char *zEnum,
171038
+ int *peVal
171039
+){
171040
+ int nEnum = strlen(zEnum);
171041
+ int i;
171042
+ int iVal = -1;
171043
+
171044
+ for(i=0; aEnum[i].zName; i++){
171045
+ if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){
171046
+ if( iVal>=0 ) return SQLITE_ERROR;
171047
+ iVal = aEnum[i].eVal;
171048
+ }
171049
+ }
171050
+
171051
+ *peVal = iVal;
171052
+ return iVal<0 ? SQLITE_ERROR : SQLITE_OK;
171053
+}
171054
+
170600171055
/*
170601171056
** Parse a "special" CREATE VIRTUAL TABLE directive and update
170602171057
** configuration object pConfig as appropriate.
170603171058
**
170604171059
** If successful, object pConfig is updated and SQLITE_OK returned. If
@@ -170652,11 +171107,11 @@
170652171107
while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
170653171108
nPre = nPre*10 + (p[0] - '0');
170654171109
p++;
170655171110
}
170656171111
170657
- if( rc==SQLITE_OK && (nPre<=0 || nPre>=1000) ){
171112
+ if( nPre<=0 || nPre>=1000 ){
170658171113
*pzErr = sqlite3_mprintf("prefix length out of range (max 999)");
170659171114
rc = SQLITE_ERROR;
170660171115
break;
170661171116
}
170662171117
@@ -170744,10 +171199,24 @@
170744171199
}else{
170745171200
pConfig->bColumnsize = (zArg[0]=='1');
170746171201
}
170747171202
return rc;
170748171203
}
171204
+
171205
+ if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
171206
+ const Fts5Enum aDetail[] = {
171207
+ { "none", FTS5_DETAIL_NONE },
171208
+ { "full", FTS5_DETAIL_FULL },
171209
+ { "columns", FTS5_DETAIL_COLUMNS },
171210
+ { 0, 0 }
171211
+ };
171212
+
171213
+ if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){
171214
+ *pzErr = sqlite3_mprintf("malformed detail=... directive");
171215
+ }
171216
+ return rc;
171217
+ }
170749171218
170750171219
*pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
170751171220
return SQLITE_ERROR;
170752171221
}
170753171222
@@ -170900,10 +171369,11 @@
170900171369
pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
170901171370
pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
170902171371
pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
170903171372
pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
170904171373
pRet->bColumnsize = 1;
171374
+ pRet->eDetail = FTS5_DETAIL_FULL;
170905171375
#ifdef SQLITE_DEBUG
170906171376
pRet->bPrefixIndex = 1;
170907171377
#endif
170908171378
if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
170909171379
*pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
@@ -171346,10 +171816,11 @@
171346171816
#endif
171347171817
171348171818
171349171819
struct Fts5Expr {
171350171820
Fts5Index *pIndex;
171821
+ Fts5Config *pConfig;
171351171822
Fts5ExprNode *pRoot;
171352171823
int bDesc; /* Iterate in descending rowid order */
171353171824
int nPhrase; /* Number of phrases in expression */
171354171825
Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */
171355171826
};
@@ -171541,10 +172012,11 @@
171541172012
sParse.rc = SQLITE_NOMEM;
171542172013
sqlite3Fts5ParseNodeFree(sParse.pExpr);
171543172014
}else{
171544172015
pNew->pRoot = sParse.pExpr;
171545172016
pNew->pIndex = 0;
172017
+ pNew->pConfig = pConfig;
171546172018
pNew->apExprPhrase = sParse.apPhrase;
171547172019
pNew->nPhrase = sParse.nPhrase;
171548172020
sParse.apPhrase = 0;
171549172021
}
171550172022
}
@@ -171605,12 +172077,13 @@
171605172077
}
171606172078
171607172079
/*
171608172080
** Argument pTerm must be a synonym iterator.
171609172081
*/
171610
-static int fts5ExprSynonymPoslist(
172082
+static int fts5ExprSynonymList(
171611172083
Fts5ExprTerm *pTerm,
172084
+ int bCollist,
171612172085
Fts5Colset *pColset,
171613172086
i64 iRowid,
171614172087
int *pbDel, /* OUT: Caller should sqlite3_free(*pa) */
171615172088
u8 **pa, int *pn
171616172089
){
@@ -171625,13 +172098,20 @@
171625172098
for(p=pTerm; p; p=p->pSynonym){
171626172099
Fts5IndexIter *pIter = p->pIter;
171627172100
if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){
171628172101
const u8 *a;
171629172102
int n;
171630
- i64 dummy;
171631
- rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
172103
+
172104
+ if( bCollist ){
172105
+ rc = sqlite3Fts5IterCollist(pIter, &a, &n);
172106
+ }else{
172107
+ i64 dummy;
172108
+ rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
172109
+ }
172110
+
171632172111
if( rc!=SQLITE_OK ) goto synonym_poslist_out;
172112
+ if( n==0 ) continue;
171633172113
if( nIter==nAlloc ){
171634172114
int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
171635172115
Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
171636172116
if( aNew==0 ){
171637172117
rc = SQLITE_NOMEM;
@@ -171728,12 +172208,12 @@
171728172208
i64 dummy;
171729172209
int n = 0;
171730172210
int bFlag = 0;
171731172211
const u8 *a = 0;
171732172212
if( pTerm->pSynonym ){
171733
- rc = fts5ExprSynonymPoslist(
171734
- pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
172213
+ rc = fts5ExprSynonymList(
172214
+ pTerm, 0, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
171735172215
);
171736172216
}else{
171737172217
rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
171738172218
}
171739172219
if( rc!=SQLITE_OK ) goto ismatch_out;
@@ -172063,34 +172543,55 @@
172063172543
Fts5Expr *pExpr, /* Expression that pNear is a part of */
172064172544
Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */
172065172545
){
172066172546
Fts5ExprNearset *pNear = pNode->pNear;
172067172547
int rc = *pRc;
172068
- int i;
172069
-
172070
- /* Check that each phrase in the nearset matches the current row.
172071
- ** Populate the pPhrase->poslist buffers at the same time. If any
172072
- ** phrase is not a match, break out of the loop early. */
172073
- for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
172074
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
172075
- if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
172076
- int bMatch = 0;
172077
- rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
172078
- if( bMatch==0 ) break;
172079
- }else{
172080
- rc = sqlite3Fts5IterPoslistBuffer(
172081
- pPhrase->aTerm[0].pIter, &pPhrase->poslist
172082
- );
172083
- }
172084
- }
172085
-
172086
- *pRc = rc;
172087
- if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
172088
- return 1;
172089
- }
172090
-
172091
- return 0;
172548
+
172549
+ if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){
172550
+ Fts5ExprTerm *pTerm;
172551
+ Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
172552
+ pPhrase->poslist.n = 0;
172553
+ for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
172554
+ Fts5IndexIter *pIter = pTerm->pIter;
172555
+ if( sqlite3Fts5IterEof(pIter)==0 ){
172556
+ int n;
172557
+ i64 iRowid;
172558
+ rc = sqlite3Fts5IterPoslist(pIter, pNear->pColset, 0, &n, &iRowid);
172559
+ if( rc!=SQLITE_OK ){
172560
+ *pRc = rc;
172561
+ return 0;
172562
+ }else if( iRowid==pNode->iRowid && n>0 ){
172563
+ pPhrase->poslist.n = 1;
172564
+ }
172565
+ }
172566
+ }
172567
+ return pPhrase->poslist.n;
172568
+ }else{
172569
+ int i;
172570
+
172571
+ /* Check that each phrase in the nearset matches the current row.
172572
+ ** Populate the pPhrase->poslist buffers at the same time. If any
172573
+ ** phrase is not a match, break out of the loop early. */
172574
+ for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
172575
+ Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
172576
+ if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
172577
+ int bMatch = 0;
172578
+ rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
172579
+ if( bMatch==0 ) break;
172580
+ }else{
172581
+ rc = sqlite3Fts5IterPoslistBuffer(
172582
+ pPhrase->aTerm[0].pIter, &pPhrase->poslist
172583
+ );
172584
+ }
172585
+ }
172586
+
172587
+ *pRc = rc;
172588
+ if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
172589
+ return 1;
172590
+ }
172591
+ return 0;
172592
+ }
172092172593
}
172093172594
172094172595
static int fts5ExprTokenTest(
172095172596
Fts5Expr *pExpr, /* Expression that pNear is a part of */
172096172597
Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */
@@ -172109,11 +172610,11 @@
172109172610
assert( pNode->eType==FTS5_TERM );
172110172611
assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
172111172612
assert( pPhrase->aTerm[0].pSynonym==0 );
172112172613
172113172614
rc = sqlite3Fts5IterPoslist(pIter, pColset,
172114
- (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
172615
+ (const u8**)&pPhrase->poslist.p, (int*)&pPhrase->poslist.n, &pNode->iRowid
172115172616
);
172116172617
pNode->bNomatch = (pPhrase->poslist.n==0);
172117172618
return rc;
172118172619
}
172119172620
@@ -172524,10 +173025,13 @@
172524173025
if( cmp || p2->bNomatch ) break;
172525173026
rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
172526173027
}
172527173028
pNode->bEof = p1->bEof;
172528173029
pNode->iRowid = p1->iRowid;
173030
+ if( p1->bEof ){
173031
+ fts5ExprNodeZeroPoslist(p2);
173032
+ }
172529173033
break;
172530173034
}
172531173035
}
172532173036
}
172533173037
return rc;
@@ -172909,10 +173413,11 @@
172909173413
}
172910173414
172911173415
if( rc==SQLITE_OK ){
172912173416
/* All the allocations succeeded. Put the expression object together. */
172913173417
pNew->pIndex = pExpr->pIndex;
173418
+ pNew->pConfig = pExpr->pConfig;
172914173419
pNew->nPhrase = 1;
172915173420
pNew->apExprPhrase[0] = sCtx.pPhrase;
172916173421
pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
172917173422
pNew->pRoot->pNear->nPhrase = 1;
172918173423
sCtx.pPhrase->pNode = pNew->pRoot;
@@ -173050,10 +173555,19 @@
173050173555
static void sqlite3Fts5ParseSetColset(
173051173556
Fts5Parse *pParse,
173052173557
Fts5ExprNearset *pNear,
173053173558
Fts5Colset *pColset
173054173559
){
173560
+ if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
173561
+ pParse->rc = SQLITE_ERROR;
173562
+ pParse->zErr = sqlite3_mprintf(
173563
+ "fts5: column queries are not supported (detail=none)"
173564
+ );
173565
+ sqlite3_free(pColset);
173566
+ return;
173567
+ }
173568
+
173055173569
if( pNear ){
173056173570
pNear->pColset = pColset;
173057173571
}else{
173058173572
sqlite3_free(pColset);
173059173573
}
@@ -173111,15 +173625,24 @@
173111173625
if( eType==FTS5_STRING ){
173112173626
int iPhrase;
173113173627
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
173114173628
pNear->apPhrase[iPhrase]->pNode = pRet;
173115173629
}
173116
- if( pNear->nPhrase==1
173117
- && pNear->apPhrase[0]->nTerm==1
173118
- && pNear->apPhrase[0]->aTerm[0].pSynonym==0
173119
- ){
173120
- pRet->eType = FTS5_TERM;
173630
+ if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 ){
173631
+ if( pNear->apPhrase[0]->aTerm[0].pSynonym==0 ){
173632
+ pRet->eType = FTS5_TERM;
173633
+ }
173634
+ }else if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
173635
+ assert( pParse->rc==SQLITE_OK );
173636
+ pParse->rc = SQLITE_ERROR;
173637
+ assert( pParse->zErr==0 );
173638
+ pParse->zErr = sqlite3_mprintf(
173639
+ "fts5: %s queries are not supported (detail!=full)",
173640
+ pNear->nPhrase==1 ? "phrase": "NEAR"
173641
+ );
173642
+ sqlite3_free(pRet);
173643
+ pRet = 0;
173121173644
}
173122173645
}else{
173123173646
fts5ExprAddChildren(pRet, pLeft);
173124173647
fts5ExprAddChildren(pRet, pRight);
173125173648
}
@@ -173229,10 +173752,13 @@
173229173752
173230173753
zRet = fts5PrintfAppend(zRet, " {");
173231173754
for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
173232173755
char *zTerm = pPhrase->aTerm[iTerm].zTerm;
173233173756
zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
173757
+ if( pPhrase->aTerm[iTerm].bPrefix ){
173758
+ zRet = fts5PrintfAppend(zRet, "*");
173759
+ }
173234173760
}
173235173761
173236173762
if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
173237173763
if( zRet==0 ) return 0;
173238173764
}
@@ -173541,10 +174067,232 @@
173541174067
*pa = 0;
173542174068
nRet = 0;
173543174069
}
173544174070
return nRet;
173545174071
}
174072
+
174073
+struct Fts5PoslistPopulator {
174074
+ Fts5PoslistWriter writer;
174075
+ int bOk; /* True if ok to populate */
174076
+ int bMiss;
174077
+};
174078
+
174079
+static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
174080
+ Fts5PoslistPopulator *pRet;
174081
+ pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
174082
+ if( pRet ){
174083
+ int i;
174084
+ memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
174085
+ for(i=0; i<pExpr->nPhrase; i++){
174086
+ Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
174087
+ Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
174088
+ assert( pExpr->apExprPhrase[i]->nTerm==1 );
174089
+ if( bLive &&
174090
+ (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
174091
+ ){
174092
+ pRet[i].bMiss = 1;
174093
+ }else{
174094
+ pBuf->n = 0;
174095
+ }
174096
+ }
174097
+ }
174098
+ return pRet;
174099
+}
174100
+
174101
+struct Fts5ExprCtx {
174102
+ Fts5Expr *pExpr;
174103
+ Fts5PoslistPopulator *aPopulator;
174104
+ i64 iOff;
174105
+};
174106
+typedef struct Fts5ExprCtx Fts5ExprCtx;
174107
+
174108
+/*
174109
+** TODO: Make this more efficient!
174110
+*/
174111
+static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
174112
+ int i;
174113
+ for(i=0; i<pColset->nCol; i++){
174114
+ if( pColset->aiCol[i]==iCol ) return 1;
174115
+ }
174116
+ return 0;
174117
+}
174118
+
174119
+static int fts5ExprPopulatePoslistsCb(
174120
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
174121
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
174122
+ const char *pToken, /* Pointer to buffer containing token */
174123
+ int nToken, /* Size of token in bytes */
174124
+ int iStart, /* Byte offset of token within input text */
174125
+ int iEnd /* Byte offset of end of token within input text */
174126
+){
174127
+ Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
174128
+ Fts5Expr *pExpr = p->pExpr;
174129
+ int i;
174130
+
174131
+ if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
174132
+ for(i=0; i<pExpr->nPhrase; i++){
174133
+ Fts5ExprTerm *pTerm;
174134
+ if( p->aPopulator[i].bOk==0 ) continue;
174135
+ for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
174136
+ int nTerm = strlen(pTerm->zTerm);
174137
+ if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
174138
+ && memcmp(pTerm->zTerm, pToken, nTerm)==0
174139
+ ){
174140
+ int rc = sqlite3Fts5PoslistWriterAppend(
174141
+ &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
174142
+ );
174143
+ if( rc ) return rc;
174144
+ break;
174145
+ }
174146
+ }
174147
+ }
174148
+ return SQLITE_OK;
174149
+}
174150
+
174151
+static int sqlite3Fts5ExprPopulatePoslists(
174152
+ Fts5Config *pConfig,
174153
+ Fts5Expr *pExpr,
174154
+ Fts5PoslistPopulator *aPopulator,
174155
+ int iCol,
174156
+ const char *z, int n
174157
+){
174158
+ int i;
174159
+ Fts5ExprCtx sCtx;
174160
+ sCtx.pExpr = pExpr;
174161
+ sCtx.aPopulator = aPopulator;
174162
+ sCtx.iOff = (((i64)iCol) << 32) - 1;
174163
+
174164
+ for(i=0; i<pExpr->nPhrase; i++){
174165
+ Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
174166
+ Fts5Colset *pColset = pNode->pNear->pColset;
174167
+ if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
174168
+ || aPopulator[i].bMiss
174169
+ ){
174170
+ aPopulator[i].bOk = 0;
174171
+ }else{
174172
+ aPopulator[i].bOk = 1;
174173
+ }
174174
+ }
174175
+
174176
+ return sqlite3Fts5Tokenize(pConfig,
174177
+ FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
174178
+ );
174179
+}
174180
+
174181
+static void fts5ExprClearPoslists(Fts5ExprNode *pNode){
174182
+ if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){
174183
+ pNode->pNear->apPhrase[0]->poslist.n = 0;
174184
+ }else{
174185
+ int i;
174186
+ for(i=0; i<pNode->nChild; i++){
174187
+ fts5ExprClearPoslists(pNode->apChild[i]);
174188
+ }
174189
+ }
174190
+}
174191
+
174192
+static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
174193
+ pNode->iRowid = iRowid;
174194
+ pNode->bEof = 0;
174195
+ switch( pNode->eType ){
174196
+ case FTS5_TERM:
174197
+ case FTS5_STRING:
174198
+ return (pNode->pNear->apPhrase[0]->poslist.n>0);
174199
+
174200
+ case FTS5_AND: {
174201
+ int i;
174202
+ for(i=0; i<pNode->nChild; i++){
174203
+ if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){
174204
+ fts5ExprClearPoslists(pNode);
174205
+ return 0;
174206
+ }
174207
+ }
174208
+ break;
174209
+ }
174210
+
174211
+ case FTS5_OR: {
174212
+ int i;
174213
+ int bRet = 0;
174214
+ for(i=0; i<pNode->nChild; i++){
174215
+ if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){
174216
+ bRet = 1;
174217
+ }
174218
+ }
174219
+ return bRet;
174220
+ }
174221
+
174222
+ default: {
174223
+ assert( pNode->eType==FTS5_NOT );
174224
+ if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid)
174225
+ || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid)
174226
+ ){
174227
+ fts5ExprClearPoslists(pNode);
174228
+ return 0;
174229
+ }
174230
+ break;
174231
+ }
174232
+ }
174233
+ return 1;
174234
+}
174235
+
174236
+static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
174237
+ fts5ExprCheckPoslists(pExpr->pRoot, iRowid);
174238
+}
174239
+
174240
+static void fts5ExprClearEof(Fts5ExprNode *pNode){
174241
+ int i;
174242
+ for(i=0; i<pNode->nChild; i++){
174243
+ fts5ExprClearEof(pNode->apChild[i]);
174244
+ }
174245
+ pNode->bEof = 0;
174246
+}
174247
+static void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){
174248
+ fts5ExprClearEof(pExpr->pRoot);
174249
+}
174250
+
174251
+/*
174252
+** This function is only called for detail=columns tables.
174253
+*/
174254
+static int sqlite3Fts5ExprPhraseCollist(
174255
+ Fts5Expr *pExpr,
174256
+ int iPhrase,
174257
+ const u8 **ppCollist,
174258
+ int *pnCollist
174259
+){
174260
+ Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
174261
+ Fts5ExprNode *pNode = pPhrase->pNode;
174262
+ int rc = SQLITE_OK;
174263
+
174264
+ assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
174265
+ if( pNode->bEof==0
174266
+ && pNode->iRowid==pExpr->pRoot->iRowid
174267
+ && pPhrase->poslist.n>0
174268
+ ){
174269
+ Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
174270
+ if( pTerm->pSynonym ){
174271
+ int bDel = 0;
174272
+ u8 *a;
174273
+ rc = fts5ExprSynonymList(
174274
+ pTerm, 1, 0, pNode->iRowid, &bDel, &a, pnCollist
174275
+ );
174276
+ if( bDel ){
174277
+ sqlite3Fts5BufferSet(&rc, &pPhrase->poslist, *pnCollist, a);
174278
+ *ppCollist = pPhrase->poslist.p;
174279
+ sqlite3_free(a);
174280
+ }else{
174281
+ *ppCollist = a;
174282
+ }
174283
+ }else{
174284
+ sqlite3Fts5IterCollist(pPhrase->aTerm[0].pIter, ppCollist, pnCollist);
174285
+ }
174286
+ }else{
174287
+ *ppCollist = 0;
174288
+ *pnCollist = 0;
174289
+ }
174290
+
174291
+ return rc;
174292
+}
174293
+
173546174294
173547174295
/*
173548174296
** 2014 August 11
173549174297
**
173550174298
** The author disclaims copyright to this source code. In place of
@@ -173570,10 +174318,11 @@
173570174318
** segment.
173571174319
*/
173572174320
173573174321
173574174322
struct Fts5Hash {
174323
+ int eDetail; /* Copy of Fts5Config.eDetail */
173575174324
int *pnByte; /* Pointer to bytes counter */
173576174325
int nEntry; /* Number of entries currently in hash */
173577174326
int nSlot; /* Size of aSlot[] array */
173578174327
Fts5HashEntry *pScan; /* Current ordered scan item */
173579174328
Fts5HashEntry **aSlot; /* Array of hash slots */
@@ -173606,10 +174355,11 @@
173606174355
173607174356
int nAlloc; /* Total size of allocation */
173608174357
int iSzPoslist; /* Offset of space for 4-byte poslist size */
173609174358
int nData; /* Total bytes of data (incl. structure) */
173610174359
u8 bDel; /* Set delete-flag @ iSzPoslist */
174360
+ u8 bContent; /* Set content-flag (detail=none mode) */
173611174361
173612174362
int iCol; /* Column of last value written */
173613174363
int iPos; /* Position of last value written */
173614174364
i64 iRowid; /* Rowid of last value written */
173615174365
char zKey[8]; /* Nul-terminated entry key */
@@ -173623,11 +174373,11 @@
173623174373
173624174374
173625174375
/*
173626174376
** Allocate a new hash table.
173627174377
*/
173628
-static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
174378
+static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
173629174379
int rc = SQLITE_OK;
173630174380
Fts5Hash *pNew;
173631174381
173632174382
*ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
173633174383
if( pNew==0 ){
@@ -173634,10 +174384,11 @@
173634174384
rc = SQLITE_NOMEM;
173635174385
}else{
173636174386
int nByte;
173637174387
memset(pNew, 0, sizeof(Fts5Hash));
173638174388
pNew->pnByte = pnByte;
174389
+ pNew->eDetail = pConfig->eDetail;
173639174390
173640174391
pNew->nSlot = 1024;
173641174392
nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
173642174393
pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
173643174394
if( pNew->aSlot==0 ){
@@ -173726,30 +174477,50 @@
173726174477
pHash->nSlot = nNew;
173727174478
pHash->aSlot = apNew;
173728174479
return SQLITE_OK;
173729174480
}
173730174481
173731
-static void fts5HashAddPoslistSize(Fts5HashEntry *p){
174482
+static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
173732174483
if( p->iSzPoslist ){
173733174484
u8 *pPtr = (u8*)p;
173734
- int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
173735
- int nPos = nSz*2 + p->bDel; /* Value of nPos field */
173736
-
173737
- assert( p->bDel==0 || p->bDel==1 );
173738
- if( nPos<=127 ){
173739
- pPtr[p->iSzPoslist] = (u8)nPos;
173740
- }else{
173741
- int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
173742
- memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
173743
- sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
173744
- p->nData += (nByte-1);
173745
- }
173746
- p->bDel = 0;
174485
+ if( pHash->eDetail==FTS5_DETAIL_NONE ){
174486
+ assert( p->nData==p->iSzPoslist );
174487
+ if( p->bDel ){
174488
+ pPtr[p->nData++] = 0x00;
174489
+ if( p->bContent ){
174490
+ pPtr[p->nData++] = 0x00;
174491
+ }
174492
+ }
174493
+ }else{
174494
+ int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
174495
+ int nPos = nSz*2 + p->bDel; /* Value of nPos field */
174496
+
174497
+ assert( p->bDel==0 || p->bDel==1 );
174498
+ if( nPos<=127 ){
174499
+ pPtr[p->iSzPoslist] = (u8)nPos;
174500
+ }else{
174501
+ int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
174502
+ memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
174503
+ sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
174504
+ p->nData += (nByte-1);
174505
+ }
174506
+ }
174507
+
173747174508
p->iSzPoslist = 0;
174509
+ p->bDel = 0;
174510
+ p->bContent = 0;
173748174511
}
173749174512
}
173750174513
174514
+/*
174515
+** Add an entry to the in-memory hash table. The key is the concatenation
174516
+** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos).
174517
+**
174518
+** (bByte || pToken) -> (iRowid,iCol,iPos)
174519
+**
174520
+** Or, if iCol is negative, then the value is a delete marker.
174521
+*/
173751174522
static int sqlite3Fts5HashWrite(
173752174523
Fts5Hash *pHash,
173753174524
i64 iRowid, /* Rowid for this entry */
173754174525
int iCol, /* Column token appears in (-ve -> delete) */
173755174526
int iPos, /* Position of token within column */
@@ -173758,10 +174529,13 @@
173758174529
){
173759174530
unsigned int iHash;
173760174531
Fts5HashEntry *p;
173761174532
u8 *pPtr;
173762174533
int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */
174534
+ int bNew; /* If non-delete entry should be written */
174535
+
174536
+ bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
173763174537
173764174538
/* Attempt to locate an existing hash entry */
173765174539
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
173766174540
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
173767174541
if( p->zKey[0]==bByte
@@ -173772,92 +174546,120 @@
173772174546
}
173773174547
}
173774174548
173775174549
/* If an existing hash entry cannot be found, create a new one. */
173776174550
if( p==0 ){
174551
+ /* Figure out how much space to allocate */
173777174552
int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
173778174553
if( nByte<128 ) nByte = 128;
173779174554
174555
+ /* Grow the Fts5Hash.aSlot[] array if necessary. */
173780174556
if( (pHash->nEntry*2)>=pHash->nSlot ){
173781174557
int rc = fts5HashResize(pHash);
173782174558
if( rc!=SQLITE_OK ) return rc;
173783174559
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
173784174560
}
173785174561
174562
+ /* Allocate new Fts5HashEntry and add it to the hash table. */
173786174563
p = (Fts5HashEntry*)sqlite3_malloc(nByte);
173787174564
if( !p ) return SQLITE_NOMEM;
173788174565
memset(p, 0, FTS5_HASHENTRYSIZE);
173789174566
p->nAlloc = nByte;
173790174567
p->zKey[0] = bByte;
173791174568
memcpy(&p->zKey[1], pToken, nToken);
173792174569
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
173793174570
p->zKey[nToken+1] = '\0';
173794174571
p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
173795
- p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
173796
- p->iSzPoslist = p->nData;
173797
- p->nData += 1;
173798
- p->iRowid = iRowid;
173799174572
p->pHashNext = pHash->aSlot[iHash];
173800174573
pHash->aSlot[iHash] = p;
173801174574
pHash->nEntry++;
174575
+
174576
+ /* Add the first rowid field to the hash-entry */
174577
+ p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
174578
+ p->iRowid = iRowid;
174579
+
174580
+ p->iSzPoslist = p->nData;
174581
+ if( pHash->eDetail!=FTS5_DETAIL_NONE ){
174582
+ p->nData += 1;
174583
+ p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
174584
+ }
174585
+
173802174586
nIncr += p->nData;
173803
- }
173804
-
173805
- /* Check there is enough space to append a new entry. Worst case scenario
173806
- ** is:
173807
- **
173808
- ** + 9 bytes for a new rowid,
173809
- ** + 4 byte reserved for the "poslist size" varint.
173810
- ** + 1 byte for a "new column" byte,
173811
- ** + 3 bytes for a new column number (16-bit max) as a varint,
173812
- ** + 5 bytes for the new position offset (32-bit max).
173813
- */
173814
- if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
173815
- int nNew = p->nAlloc * 2;
173816
- Fts5HashEntry *pNew;
173817
- Fts5HashEntry **pp;
173818
- pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
173819
- if( pNew==0 ) return SQLITE_NOMEM;
173820
- pNew->nAlloc = nNew;
173821
- for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
173822
- *pp = pNew;
173823
- p = pNew;
173824
- }
173825
- pPtr = (u8*)p;
173826
- nIncr -= p->nData;
174587
+ }else{
174588
+
174589
+ /* Appending to an existing hash-entry. Check that there is enough
174590
+ ** space to append the largest possible new entry. Worst case scenario
174591
+ ** is:
174592
+ **
174593
+ ** + 9 bytes for a new rowid,
174594
+ ** + 4 byte reserved for the "poslist size" varint.
174595
+ ** + 1 byte for a "new column" byte,
174596
+ ** + 3 bytes for a new column number (16-bit max) as a varint,
174597
+ ** + 5 bytes for the new position offset (32-bit max).
174598
+ */
174599
+ if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
174600
+ int nNew = p->nAlloc * 2;
174601
+ Fts5HashEntry *pNew;
174602
+ Fts5HashEntry **pp;
174603
+ pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
174604
+ if( pNew==0 ) return SQLITE_NOMEM;
174605
+ pNew->nAlloc = nNew;
174606
+ for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
174607
+ *pp = pNew;
174608
+ p = pNew;
174609
+ }
174610
+ nIncr -= p->nData;
174611
+ }
174612
+ assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) );
174613
+
174614
+ pPtr = (u8*)p;
173827174615
173828174616
/* If this is a new rowid, append the 4-byte size field for the previous
173829174617
** entry, and the new rowid for this entry. */
173830174618
if( iRowid!=p->iRowid ){
173831
- fts5HashAddPoslistSize(p);
174619
+ fts5HashAddPoslistSize(pHash, p);
173832174620
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
174621
+ p->iRowid = iRowid;
174622
+ bNew = 1;
173833174623
p->iSzPoslist = p->nData;
173834
- p->nData += 1;
173835
- p->iCol = 0;
173836
- p->iPos = 0;
173837
- p->iRowid = iRowid;
174624
+ if( pHash->eDetail!=FTS5_DETAIL_NONE ){
174625
+ p->nData += 1;
174626
+ p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
174627
+ p->iPos = 0;
174628
+ }
173838174629
}
173839174630
173840174631
if( iCol>=0 ){
173841
- /* Append a new column value, if necessary */
173842
- assert( iCol>=p->iCol );
173843
- if( iCol!=p->iCol ){
173844
- pPtr[p->nData++] = 0x01;
173845
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
173846
- p->iCol = iCol;
173847
- p->iPos = 0;
173848
- }
173849
-
173850
- /* Append the new position offset */
173851
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
173852
- p->iPos = iPos;
174632
+ if( pHash->eDetail==FTS5_DETAIL_NONE ){
174633
+ p->bContent = 1;
174634
+ }else{
174635
+ /* Append a new column value, if necessary */
174636
+ assert( iCol>=p->iCol );
174637
+ if( iCol!=p->iCol ){
174638
+ if( pHash->eDetail==FTS5_DETAIL_FULL ){
174639
+ pPtr[p->nData++] = 0x01;
174640
+ p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
174641
+ p->iCol = iCol;
174642
+ p->iPos = 0;
174643
+ }else{
174644
+ bNew = 1;
174645
+ p->iCol = iPos = iCol;
174646
+ }
174647
+ }
174648
+
174649
+ /* Append the new position offset, if necessary */
174650
+ if( bNew ){
174651
+ p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
174652
+ p->iPos = iPos;
174653
+ }
174654
+ }
173853174655
}else{
173854174656
/* This is a delete. Set the delete flag. */
173855174657
p->bDel = 1;
173856174658
}
174659
+
173857174660
nIncr += p->nData;
173858
-
173859174661
*pHash->pnByte += nIncr;
173860174662
return SQLITE_OK;
173861174663
}
173862174664
173863174665
@@ -173967,11 +174769,11 @@
173967174769
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
173968174770
if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
173969174771
}
173970174772
173971174773
if( p ){
173972
- fts5HashAddPoslistSize(p);
174774
+ fts5HashAddPoslistSize(pHash, p);
173973174775
*ppDoclist = (const u8*)&p->zKey[nTerm+1];
173974174776
*pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
173975174777
}else{
173976174778
*ppDoclist = 0;
173977174779
*pnDoclist = 0;
@@ -174003,11 +174805,11 @@
174003174805
int *pnDoclist /* OUT: size of doclist in bytes */
174004174806
){
174005174807
Fts5HashEntry *p;
174006174808
if( (p = pHash->pScan) ){
174007174809
int nTerm = (int)strlen(p->zKey);
174008
- fts5HashAddPoslistSize(p);
174810
+ fts5HashAddPoslistSize(pHash, p);
174009174811
*pzTerm = p->zKey;
174010174812
*ppDoclist = (const u8*)&p->zKey[nTerm+1];
174011174813
*pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
174012174814
}else{
174013174815
*pzTerm = 0;
@@ -174450,10 +175252,13 @@
174450175252
int iLeafPgno; /* Current leaf page number */
174451175253
Fts5Data *pLeaf; /* Current leaf data */
174452175254
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
174453175255
int iLeafOffset; /* Byte offset within current leaf */
174454175256
175257
+ /* Next method */
175258
+ void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
175259
+
174455175260
/* The page and offset from which the current term was read. The offset
174456175261
** is the offset of the first rowid in the current doclist. */
174457175262
int iTermLeafPgno;
174458175263
int iTermLeafOffset;
174459175264
@@ -174469,11 +175274,11 @@
174469175274
174470175275
/* Variables populated based on current entry. */
174471175276
Fts5Buffer term; /* Current term */
174472175277
i64 iRowid; /* Current rowid */
174473175278
int nPos; /* Number of bytes in current position list */
174474
- int bDel; /* True if the delete flag is set */
175279
+ u8 bDel; /* True if the delete flag is set */
174475175280
};
174476175281
174477175282
/*
174478175283
** Argument is a pointer to an Fts5Data structure that contains a
174479175284
** leaf page.
@@ -174482,11 +175287,10 @@
174482175287
(x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
174483175288
)
174484175289
174485175290
#define FTS5_SEGITER_ONETERM 0x01
174486175291
#define FTS5_SEGITER_REVERSE 0x02
174487
-
174488175292
174489175293
/*
174490175294
** Argument is a pointer to an Fts5Data structure that contains a leaf
174491175295
** page. This macro evaluates to true if the leaf contains no terms, or
174492175296
** false if it contains at least one term.
@@ -175509,17 +176313,33 @@
175509176313
** position list content (if any).
175510176314
*/
175511176315
static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
175512176316
if( p->rc==SQLITE_OK ){
175513176317
int iOff = pIter->iLeafOffset; /* Offset to read at */
175514
- int nSz;
175515176318
ASSERT_SZLEAF_OK(pIter->pLeaf);
175516
- fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
175517
- pIter->bDel = (nSz & 0x0001);
175518
- pIter->nPos = nSz>>1;
176319
+ if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
176320
+ int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf);
176321
+ pIter->bDel = 0;
176322
+ pIter->nPos = 1;
176323
+ if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
176324
+ pIter->bDel = 1;
176325
+ iOff++;
176326
+ if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
176327
+ pIter->nPos = 1;
176328
+ iOff++;
176329
+ }else{
176330
+ pIter->nPos = 0;
176331
+ }
176332
+ }
176333
+ }else{
176334
+ int nSz;
176335
+ fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
176336
+ pIter->bDel = (nSz & 0x0001);
176337
+ pIter->nPos = nSz>>1;
176338
+ assert_nc( pIter->nPos>=0 );
176339
+ }
175519176340
pIter->iLeafOffset = iOff;
175520
- assert_nc( pIter->nPos>=0 );
175521176341
}
175522176342
}
175523176343
175524176344
static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
175525176345
u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
@@ -175575,10 +176395,24 @@
175575176395
pIter->iEndofDoclist += nExtra;
175576176396
}
175577176397
175578176398
fts5SegIterLoadRowid(p, pIter);
175579176399
}
176400
+
176401
+static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*);
176402
+static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*);
176403
+static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*);
176404
+
176405
+static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
176406
+ if( pIter->flags & FTS5_SEGITER_REVERSE ){
176407
+ pIter->xNext = fts5SegIterNext_Reverse;
176408
+ }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
176409
+ pIter->xNext = fts5SegIterNext_None;
176410
+ }else{
176411
+ pIter->xNext = fts5SegIterNext;
176412
+ }
176413
+}
175580176414
175581176415
/*
175582176416
** Initialize the iterator object pIter to iterate through the entries in
175583176417
** segment pSeg. The iterator is left pointing to the first entry when
175584176418
** this function returns.
@@ -175601,10 +176435,11 @@
175601176435
return;
175602176436
}
175603176437
175604176438
if( p->rc==SQLITE_OK ){
175605176439
memset(pIter, 0, sizeof(*pIter));
176440
+ fts5SegIterSetNext(p, pIter);
175606176441
pIter->pSeg = pSeg;
175607176442
pIter->iLeafPgno = pSeg->pgnoFirst-1;
175608176443
fts5SegIterNextPage(p, pIter);
175609176444
}
175610176445
@@ -175632,10 +176467,11 @@
175632176467
** aRowidOffset[] and iRowidOffset variables. At this point the iterator
175633176468
** is in its regular state - Fts5SegIter.iLeafOffset points to the first
175634176469
** byte of the position list content associated with said rowid.
175635176470
*/
175636176471
static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
176472
+ int eDetail = p->pConfig->eDetail;
175637176473
int n = pIter->pLeaf->szLeaf;
175638176474
int i = pIter->iLeafOffset;
175639176475
u8 *a = pIter->pLeaf->p;
175640176476
int iRowidOffset = 0;
175641176477
@@ -175644,19 +176480,28 @@
175644176480
}
175645176481
175646176482
ASSERT_SZLEAF_OK(pIter->pLeaf);
175647176483
while( 1 ){
175648176484
i64 iDelta = 0;
175649
- int nPos;
175650
- int bDummy;
175651176485
175652
- i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
175653
- i += nPos;
176486
+ if( eDetail==FTS5_DETAIL_NONE ){
176487
+ /* todo */
176488
+ if( i<n && a[i]==0 ){
176489
+ i++;
176490
+ if( i<n && a[i]==0 ) i++;
176491
+ }
176492
+ }else{
176493
+ int nPos;
176494
+ int bDummy;
176495
+ i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
176496
+ i += nPos;
176497
+ }
175654176498
if( i>=n ) break;
175655176499
i += fts5GetVarint(&a[i], (u64*)&iDelta);
175656176500
pIter->iRowid += iDelta;
175657176501
176502
+ /* If necessary, grow the pIter->aRowidOffset[] array. */
175658176503
if( iRowidOffset>=pIter->nRowidOffset ){
175659176504
int nNew = pIter->nRowidOffset + 8;
175660176505
int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
175661176506
if( aNew==0 ){
175662176507
p->rc = SQLITE_NOMEM;
@@ -175730,10 +176575,112 @@
175730176575
*/
175731176576
static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){
175732176577
Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
175733176578
return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
175734176579
}
176580
+
176581
+/*
176582
+** Advance iterator pIter to the next entry.
176583
+**
176584
+** This version of fts5SegIterNext() is only used by reverse iterators.
176585
+*/
176586
+static void fts5SegIterNext_Reverse(
176587
+ Fts5Index *p, /* FTS5 backend object */
176588
+ Fts5SegIter *pIter, /* Iterator to advance */
176589
+ int *pbNewTerm /* OUT: Set for new term */
176590
+){
176591
+ assert( pIter->flags & FTS5_SEGITER_REVERSE );
176592
+ assert( pIter->pNextLeaf==0 );
176593
+ if( pIter->iRowidOffset>0 ){
176594
+ u8 *a = pIter->pLeaf->p;
176595
+ int iOff;
176596
+ i64 iDelta;
176597
+
176598
+ pIter->iRowidOffset--;
176599
+ pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
176600
+ fts5SegIterLoadNPos(p, pIter);
176601
+ iOff = pIter->iLeafOffset;
176602
+ if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
176603
+ iOff += pIter->nPos;
176604
+ }
176605
+ fts5GetVarint(&a[iOff], (u64*)&iDelta);
176606
+ pIter->iRowid -= iDelta;
176607
+ }else{
176608
+ fts5SegIterReverseNewPage(p, pIter);
176609
+ }
176610
+}
176611
+
176612
+/*
176613
+** Advance iterator pIter to the next entry.
176614
+**
176615
+** This version of fts5SegIterNext() is only used if detail=none and the
176616
+** iterator is not a reverse direction iterator.
176617
+*/
176618
+static void fts5SegIterNext_None(
176619
+ Fts5Index *p, /* FTS5 backend object */
176620
+ Fts5SegIter *pIter, /* Iterator to advance */
176621
+ int *pbNewTerm /* OUT: Set for new term */
176622
+){
176623
+ int iOff;
176624
+
176625
+ assert( p->rc==SQLITE_OK );
176626
+ assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 );
176627
+ assert( p->pConfig->eDetail==FTS5_DETAIL_NONE );
176628
+
176629
+ ASSERT_SZLEAF_OK(pIter->pLeaf);
176630
+ iOff = pIter->iLeafOffset;
176631
+
176632
+ /* Next entry is on the next page */
176633
+ if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
176634
+ fts5SegIterNextPage(p, pIter);
176635
+ if( p->rc || pIter->pLeaf==0 ) return;
176636
+ pIter->iRowid = 0;
176637
+ iOff = 4;
176638
+ }
176639
+
176640
+ if( iOff<pIter->iEndofDoclist ){
176641
+ /* Next entry is on the current page */
176642
+ i64 iDelta;
176643
+ iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
176644
+ pIter->iLeafOffset = iOff;
176645
+ pIter->iRowid += iDelta;
176646
+ }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
176647
+ if( pIter->pSeg ){
176648
+ int nKeep = 0;
176649
+ if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){
176650
+ iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep);
176651
+ }
176652
+ pIter->iLeafOffset = iOff;
176653
+ fts5SegIterLoadTerm(p, pIter, nKeep);
176654
+ }else{
176655
+ const u8 *pList = 0;
176656
+ const char *zTerm = 0;
176657
+ int nList;
176658
+ sqlite3Fts5HashScanNext(p->pHash);
176659
+ sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
176660
+ if( pList==0 ) goto next_none_eof;
176661
+ pIter->pLeaf->p = (u8*)pList;
176662
+ pIter->pLeaf->nn = nList;
176663
+ pIter->pLeaf->szLeaf = nList;
176664
+ pIter->iEndofDoclist = nList;
176665
+ sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
176666
+ pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
176667
+ }
176668
+
176669
+ if( pbNewTerm ) *pbNewTerm = 1;
176670
+ }else{
176671
+ goto next_none_eof;
176672
+ }
176673
+
176674
+ fts5SegIterLoadNPos(p, pIter);
176675
+
176676
+ return;
176677
+ next_none_eof:
176678
+ fts5DataRelease(pIter->pLeaf);
176679
+ pIter->pLeaf = 0;
176680
+}
176681
+
175735176682
175736176683
/*
175737176684
** Advance iterator pIter to the next entry.
175738176685
**
175739176686
** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
@@ -175743,144 +176690,135 @@
175743176690
static void fts5SegIterNext(
175744176691
Fts5Index *p, /* FTS5 backend object */
175745176692
Fts5SegIter *pIter, /* Iterator to advance */
175746176693
int *pbNewTerm /* OUT: Set for new term */
175747176694
){
175748
- assert( pbNewTerm==0 || *pbNewTerm==0 );
175749
- if( p->rc==SQLITE_OK ){
175750
- if( pIter->flags & FTS5_SEGITER_REVERSE ){
175751
- assert( pIter->pNextLeaf==0 );
175752
- if( pIter->iRowidOffset>0 ){
175753
- u8 *a = pIter->pLeaf->p;
175754
- int iOff;
175755
- int nPos;
175756
- int bDummy;
175757
- i64 iDelta;
175758
-
175759
- pIter->iRowidOffset--;
175760
- pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset];
175761
- iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
175762
- iOff += nPos;
175763
- fts5GetVarint(&a[iOff], (u64*)&iDelta);
175764
- pIter->iRowid -= iDelta;
175765
- fts5SegIterLoadNPos(p, pIter);
175766
- }else{
175767
- fts5SegIterReverseNewPage(p, pIter);
175768
- }
175769
- }else{
175770
- Fts5Data *pLeaf = pIter->pLeaf;
175771
- int iOff;
175772
- int bNewTerm = 0;
175773
- int nKeep = 0;
175774
-
175775
- /* Search for the end of the position list within the current page. */
175776
- u8 *a = pLeaf->p;
175777
- int n = pLeaf->szLeaf;
175778
-
175779
- ASSERT_SZLEAF_OK(pLeaf);
175780
- iOff = pIter->iLeafOffset + pIter->nPos;
175781
-
175782
- if( iOff<n ){
175783
- /* The next entry is on the current page. */
175784
- assert_nc( iOff<=pIter->iEndofDoclist );
175785
- if( iOff>=pIter->iEndofDoclist ){
175786
- bNewTerm = 1;
175787
- if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
175788
- iOff += fts5GetVarint32(&a[iOff], nKeep);
175789
- }
175790
- }else{
175791
- u64 iDelta;
175792
- iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
175793
- pIter->iRowid += iDelta;
175794
- assert_nc( iDelta>0 );
175795
- }
175796
- pIter->iLeafOffset = iOff;
175797
-
175798
- }else if( pIter->pSeg==0 ){
175799
- const u8 *pList = 0;
175800
- const char *zTerm = 0;
175801
- int nList = 0;
175802
- assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
175803
- if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
175804
- sqlite3Fts5HashScanNext(p->pHash);
175805
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
175806
- }
175807
- if( pList==0 ){
175808
- fts5DataRelease(pIter->pLeaf);
175809
- pIter->pLeaf = 0;
175810
- }else{
175811
- pIter->pLeaf->p = (u8*)pList;
175812
- pIter->pLeaf->nn = nList;
175813
- pIter->pLeaf->szLeaf = nList;
175814
- pIter->iEndofDoclist = nList+1;
175815
- sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
175816
- (u8*)zTerm);
175817
- pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
175818
- *pbNewTerm = 1;
175819
- }
175820
- }else{
175821
- iOff = 0;
175822
- /* Next entry is not on the current page */
175823
- while( iOff==0 ){
175824
- fts5SegIterNextPage(p, pIter);
175825
- pLeaf = pIter->pLeaf;
175826
- if( pLeaf==0 ) break;
175827
- ASSERT_SZLEAF_OK(pLeaf);
175828
- if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
175829
- iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
175830
- pIter->iLeafOffset = iOff;
175831
-
175832
- if( pLeaf->nn>pLeaf->szLeaf ){
175833
- pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
175834
- &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
175835
- );
175836
- }
175837
-
175838
- }
175839
- else if( pLeaf->nn>pLeaf->szLeaf ){
175840
- pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
175841
- &pLeaf->p[pLeaf->szLeaf], iOff
175842
- );
175843
- pIter->iLeafOffset = iOff;
175844
- pIter->iEndofDoclist = iOff;
175845
- bNewTerm = 1;
175846
- }
175847
- if( iOff>=pLeaf->szLeaf ){
175848
- p->rc = FTS5_CORRUPT;
175849
- return;
175850
- }
175851
- }
175852
- }
175853
-
175854
- /* Check if the iterator is now at EOF. If so, return early. */
175855
- if( pIter->pLeaf ){
175856
- if( bNewTerm ){
175857
- if( pIter->flags & FTS5_SEGITER_ONETERM ){
175858
- fts5DataRelease(pIter->pLeaf);
175859
- pIter->pLeaf = 0;
175860
- }else{
175861
- fts5SegIterLoadTerm(p, pIter, nKeep);
175862
- fts5SegIterLoadNPos(p, pIter);
175863
- if( pbNewTerm ) *pbNewTerm = 1;
175864
- }
175865
- }else{
175866
- /* The following could be done by calling fts5SegIterLoadNPos(). But
175867
- ** this block is particularly performance critical, so equivalent
175868
- ** code is inlined. */
175869
- int nSz;
175870
- assert( p->rc==SQLITE_OK );
175871
- fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
175872
- pIter->bDel = (nSz & 0x0001);
175873
- pIter->nPos = nSz>>1;
175874
- assert_nc( pIter->nPos>=0 );
175875
- }
175876
- }
176695
+ Fts5Data *pLeaf = pIter->pLeaf;
176696
+ int iOff;
176697
+ int bNewTerm = 0;
176698
+ int nKeep = 0;
176699
+ u8 *a;
176700
+ int n;
176701
+
176702
+ assert( pbNewTerm==0 || *pbNewTerm==0 );
176703
+ assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
176704
+
176705
+ /* Search for the end of the position list within the current page. */
176706
+ a = pLeaf->p;
176707
+ n = pLeaf->szLeaf;
176708
+
176709
+ ASSERT_SZLEAF_OK(pLeaf);
176710
+ iOff = pIter->iLeafOffset + pIter->nPos;
176711
+
176712
+ if( iOff<n ){
176713
+ /* The next entry is on the current page. */
176714
+ assert_nc( iOff<=pIter->iEndofDoclist );
176715
+ if( iOff>=pIter->iEndofDoclist ){
176716
+ bNewTerm = 1;
176717
+ if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
176718
+ iOff += fts5GetVarint32(&a[iOff], nKeep);
176719
+ }
176720
+ }else{
176721
+ u64 iDelta;
176722
+ iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
176723
+ pIter->iRowid += iDelta;
176724
+ assert_nc( iDelta>0 );
176725
+ }
176726
+ pIter->iLeafOffset = iOff;
176727
+
176728
+ }else if( pIter->pSeg==0 ){
176729
+ const u8 *pList = 0;
176730
+ const char *zTerm = 0;
176731
+ int nList = 0;
176732
+ assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
176733
+ if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
176734
+ sqlite3Fts5HashScanNext(p->pHash);
176735
+ sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
176736
+ }
176737
+ if( pList==0 ){
176738
+ fts5DataRelease(pIter->pLeaf);
176739
+ pIter->pLeaf = 0;
176740
+ }else{
176741
+ pIter->pLeaf->p = (u8*)pList;
176742
+ pIter->pLeaf->nn = nList;
176743
+ pIter->pLeaf->szLeaf = nList;
176744
+ pIter->iEndofDoclist = nList+1;
176745
+ sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
176746
+ (u8*)zTerm);
176747
+ pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
176748
+ *pbNewTerm = 1;
176749
+ }
176750
+ }else{
176751
+ iOff = 0;
176752
+ /* Next entry is not on the current page */
176753
+ while( iOff==0 ){
176754
+ fts5SegIterNextPage(p, pIter);
176755
+ pLeaf = pIter->pLeaf;
176756
+ if( pLeaf==0 ) break;
176757
+ ASSERT_SZLEAF_OK(pLeaf);
176758
+ if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
176759
+ iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
176760
+ pIter->iLeafOffset = iOff;
176761
+
176762
+ if( pLeaf->nn>pLeaf->szLeaf ){
176763
+ pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
176764
+ &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
176765
+ );
176766
+ }
176767
+
176768
+ }
176769
+ else if( pLeaf->nn>pLeaf->szLeaf ){
176770
+ pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
176771
+ &pLeaf->p[pLeaf->szLeaf], iOff
176772
+ );
176773
+ pIter->iLeafOffset = iOff;
176774
+ pIter->iEndofDoclist = iOff;
176775
+ bNewTerm = 1;
176776
+ }
176777
+ assert_nc( iOff<pLeaf->szLeaf );
176778
+ if( iOff>pLeaf->szLeaf ){
176779
+ p->rc = FTS5_CORRUPT;
176780
+ return;
176781
+ }
176782
+ }
176783
+ }
176784
+
176785
+ /* Check if the iterator is now at EOF. If so, return early. */
176786
+ if( pIter->pLeaf ){
176787
+ if( bNewTerm ){
176788
+ if( pIter->flags & FTS5_SEGITER_ONETERM ){
176789
+ fts5DataRelease(pIter->pLeaf);
176790
+ pIter->pLeaf = 0;
176791
+ }else{
176792
+ fts5SegIterLoadTerm(p, pIter, nKeep);
176793
+ fts5SegIterLoadNPos(p, pIter);
176794
+ if( pbNewTerm ) *pbNewTerm = 1;
176795
+ }
176796
+ }else{
176797
+ /* The following could be done by calling fts5SegIterLoadNPos(). But
176798
+ ** this block is particularly performance critical, so equivalent
176799
+ ** code is inlined.
176800
+ **
176801
+ ** Later: Switched back to fts5SegIterLoadNPos() because it supports
176802
+ ** detail=none mode. Not ideal.
176803
+ */
176804
+ int nSz;
176805
+ assert( p->rc==SQLITE_OK );
176806
+ fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
176807
+ pIter->bDel = (nSz & 0x0001);
176808
+ pIter->nPos = nSz>>1;
176809
+ assert_nc( pIter->nPos>=0 );
175877176810
}
175878176811
}
175879176812
}
175880176813
175881176814
#define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
176815
+
176816
+#define fts5IndexSkipVarint(a, iOff) { \
176817
+ int iEnd = iOff+9; \
176818
+ while( (a[iOff++] & 0x80) && iOff<iEnd ); \
176819
+}
175882176820
175883176821
/*
175884176822
** Iterator pIter currently points to the first rowid in a doclist. This
175885176823
** function sets the iterator up so that iterates in reverse order through
175886176824
** the doclist.
@@ -175898,11 +176836,21 @@
175898176836
Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
175899176837
175900176838
/* Currently, Fts5SegIter.iLeafOffset points to the first byte of
175901176839
** position-list content for the current rowid. Back it up so that it
175902176840
** points to the start of the position-list size field. */
175903
- pIter->iLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel);
176841
+ int iPoslist;
176842
+ if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
176843
+ iPoslist = pIter->iTermLeafOffset;
176844
+ }else{
176845
+ iPoslist = 4;
176846
+ }
176847
+ fts5IndexSkipVarint(pLeaf->p, iPoslist);
176848
+ assert( p->pConfig->eDetail==FTS5_DETAIL_NONE || iPoslist==(
176849
+ pIter->iLeafOffset - sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel)
176850
+ ));
176851
+ pIter->iLeafOffset = iPoslist;
175904176852
175905176853
/* If this condition is true then the largest rowid for the current
175906176854
** term may not be stored on the current page. So search forward to
175907176855
** see where said rowid really is. */
175908176856
if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
@@ -175982,15 +176930,10 @@
175982176930
}
175983176931
175984176932
pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
175985176933
}
175986176934
175987
-#define fts5IndexSkipVarint(a, iOff) { \
175988
- int iEnd = iOff+9; \
175989
- while( (a[iOff++] & 0x80) && iOff<iEnd ); \
175990
-}
175991
-
175992176935
/*
175993176936
** The iterator object passed as the second argument currently contains
175994176937
** no valid values except for the Fts5SegIter.pLeaf member variable. This
175995176938
** function searches the leaf page for a term matching (pTerm/nTerm).
175996176939
**
@@ -176189,10 +177132,12 @@
176189177132
fts5SegIterReverse(p, pIter);
176190177133
}
176191177134
}
176192177135
}
176193177136
177137
+ fts5SegIterSetNext(p, pIter);
177138
+
176194177139
/* Either:
176195177140
**
176196177141
** 1) an error has occurred, or
176197177142
** 2) the iterator points to EOF, or
176198177143
** 3) the iterator points to an entry with term (pTerm/nTerm), or
@@ -176246,19 +177191,21 @@
176246177191
if( pLeaf==0 ) return;
176247177192
pLeaf->p = (u8*)pList;
176248177193
pLeaf->nn = pLeaf->szLeaf = nList;
176249177194
pIter->pLeaf = pLeaf;
176250177195
pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
176251
- pIter->iEndofDoclist = pLeaf->nn+1;
177196
+ pIter->iEndofDoclist = pLeaf->nn;
176252177197
176253177198
if( flags & FTS5INDEX_QUERY_DESC ){
176254177199
pIter->flags |= FTS5_SEGITER_REVERSE;
176255177200
fts5SegIterReverseInitPage(p, pIter);
176256177201
}else{
176257177202
fts5SegIterLoadNPos(p, pIter);
176258177203
}
176259177204
}
177205
+
177206
+ fts5SegIterSetNext(p, pIter);
176260177207
}
176261177208
176262177209
/*
176263177210
** Zero the iterator passed as the only argument.
176264177211
*/
@@ -176498,11 +177445,11 @@
176498177445
bMove = 0;
176499177446
}
176500177447
}
176501177448
176502177449
do{
176503
- if( bMove ) fts5SegIterNext(p, pIter, 0);
177450
+ if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0);
176504177451
if( pIter->pLeaf==0 ) break;
176505177452
if( bRev==0 && pIter->iRowid>=iMatch ) break;
176506177453
if( bRev!=0 && pIter->iRowid<=iMatch ) break;
176507177454
bMove = 1;
176508177455
}while( p->rc==SQLITE_OK );
@@ -176532,11 +177479,13 @@
176532177479
){
176533177480
int i;
176534177481
for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
176535177482
int iEq;
176536177483
if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
176537
- fts5SegIterNext(p, &pIter->aSeg[iEq], 0);
177484
+ Fts5SegIter *pSeg = &pIter->aSeg[iEq];
177485
+ assert( p->rc==SQLITE_OK );
177486
+ pSeg->xNext(p, pSeg, 0);
176538177487
i = pIter->nSeg + iEq;
176539177488
}
176540177489
}
176541177490
}
176542177491
@@ -176619,11 +177568,11 @@
176619177568
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
176620177569
assert( p->rc==SQLITE_OK );
176621177570
if( bUseFrom && pSeg->pDlidx ){
176622177571
fts5SegIterNextFrom(p, pSeg, iFrom);
176623177572
}else{
176624
- fts5SegIterNext(p, pSeg, &bNewTerm);
177573
+ pSeg->xNext(p, pSeg, &bNewTerm);
176625177574
}
176626177575
176627177576
if( pSeg->pLeaf==0 || bNewTerm
176628177577
|| fts5MultiIterAdvanceRowid(p, pIter, iFirst)
176629177578
){
@@ -176647,11 +177596,12 @@
176647177596
do {
176648177597
int iFirst = pIter->aFirst[1].iFirst;
176649177598
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
176650177599
int bNewTerm = 0;
176651177600
176652
- fts5SegIterNext(p, pSeg, &bNewTerm);
177601
+ assert( p->rc==SQLITE_OK );
177602
+ pSeg->xNext(p, pSeg, &bNewTerm);
176653177603
if( pSeg->pLeaf==0 || bNewTerm
176654177604
|| fts5MultiIterAdvanceRowid(p, pIter, iFirst)
176655177605
){
176656177606
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
176657177607
fts5MultiIterSetEof(pIter);
@@ -176767,11 +177717,12 @@
176767177717
** object and set the output variable to NULL. */
176768177718
if( p->rc==SQLITE_OK ){
176769177719
for(iIter=pNew->nSeg-1; iIter>0; iIter--){
176770177720
int iEq;
176771177721
if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
176772
- fts5SegIterNext(p, &pNew->aSeg[iEq], 0);
177722
+ Fts5SegIter *pSeg = &pNew->aSeg[iEq];
177723
+ if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
176773177724
fts5MultiIterAdvanced(p, pNew, iEq, iIter);
176774177725
}
176775177726
}
176776177727
fts5MultiIterSetEof(pNew);
176777177728
fts5AssertMultiIterSetup(p, pNew);
@@ -176817,10 +177768,11 @@
176817177768
}
176818177769
pData = 0;
176819177770
}else{
176820177771
pNew->bEof = 1;
176821177772
}
177773
+ fts5SegIterSetNext(p, pIter);
176822177774
176823177775
*ppOut = pNew;
176824177776
}
176825177777
176826177778
fts5DataRelease(pData);
@@ -176885,10 +177837,13 @@
176885177837
Fts5Data *pData = 0;
176886177838
u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
176887177839
int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
176888177840
int pgno = pSeg->iLeafPgno;
176889177841
int pgnoSave = 0;
177842
+
177843
+ /* This function does notmwork with detail=none databases. */
177844
+ assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
176890177845
176891177846
if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
176892177847
pgnoSave = pgno+1;
176893177848
}
176894177849
@@ -177309,12 +178264,11 @@
177309178264
** Append a rowid and position-list size field to the writers output.
177310178265
*/
177311178266
static void fts5WriteAppendRowid(
177312178267
Fts5Index *p,
177313178268
Fts5SegWriter *pWriter,
177314
- i64 iRowid,
177315
- int nPos
178269
+ i64 iRowid
177316178270
){
177317178271
if( p->rc==SQLITE_OK ){
177318178272
Fts5PageWriter *pPage = &pWriter->writer;
177319178273
177320178274
if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){
@@ -177337,12 +178291,10 @@
177337178291
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
177338178292
}
177339178293
pWriter->iPrevRowid = iRowid;
177340178294
pWriter->bFirstRowidInDoclist = 0;
177341178295
pWriter->bFirstRowidInPage = 0;
177342
-
177343
- fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos);
177344178296
}
177345178297
}
177346178298
177347178299
static void fts5WriteAppendPoslistData(
177348178300
Fts5Index *p,
@@ -177534,10 +178486,11 @@
177534178486
int nInput; /* Number of input segments */
177535178487
Fts5SegWriter writer; /* Writer object */
177536178488
Fts5StructureSegment *pSeg; /* Output segment */
177537178489
Fts5Buffer term;
177538178490
int bOldest; /* True if the output segment is the oldest */
178491
+ int eDetail = p->pConfig->eDetail;
177539178492
177540178493
assert( iLvl<pStruct->nLevel );
177541178494
assert( pLvl->nMerge<=pLvl->nSeg );
177542178495
177543178496
memset(&writer, 0, sizeof(Fts5SegWriter));
@@ -177603,15 +178556,25 @@
177603178556
fts5BufferSet(&p->rc, &term, nTerm, pTerm);
177604178557
}
177605178558
177606178559
/* Append the rowid to the output */
177607178560
/* WRITEPOSLISTSIZE */
177608
- nPos = pSegIter->nPos*2 + pSegIter->bDel;
177609
- fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos);
178561
+ fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter));
177610178562
177611
- /* Append the position-list data to the output */
177612
- fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
178563
+ if( eDetail==FTS5_DETAIL_NONE ){
178564
+ if( pSegIter->bDel ){
178565
+ fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
178566
+ if( pSegIter->nPos>0 ){
178567
+ fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
178568
+ }
178569
+ }
178570
+ }else{
178571
+ /* Append the position-list data to the output */
178572
+ nPos = pSegIter->nPos*2 + pSegIter->bDel;
178573
+ fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos);
178574
+ fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
178575
+ }
177613178576
}
177614178577
177615178578
/* Flush the last leaf page to disk. Set the output segment b-tree height
177616178579
** and last leaf page number at the same time. */
177617178580
fts5WriteFinish(p, &writer, &pSeg->pgnoLast);
@@ -177795,11 +178758,11 @@
177795178758
pStruct = fts5StructureRead(p);
177796178759
iSegid = fts5AllocateSegid(p, pStruct);
177797178760
177798178761
if( iSegid ){
177799178762
const int pgsz = p->pConfig->pgsz;
177800
-
178763
+ int eDetail = p->pConfig->eDetail;
177801178764
Fts5StructureSegment *pSeg; /* New segment within pStruct */
177802178765
Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
177803178766
Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
177804178767
177805178768
Fts5SegWriter writer;
@@ -177838,16 +178801,11 @@
177838178801
177839178802
/* The entire doclist will not fit on this leaf. The following
177840178803
** loop iterates through the poslists that make up the current
177841178804
** doclist. */
177842178805
while( p->rc==SQLITE_OK && iOff<nDoclist ){
177843
- int nPos;
177844
- int nCopy;
177845
- int bDummy;
177846178806
iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
177847
- nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
177848
- nCopy += nPos;
177849178807
iRowid += iDelta;
177850178808
177851178809
if( writer.bFirstRowidInPage ){
177852178810
fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
177853178811
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
@@ -177856,38 +178814,56 @@
177856178814
}else{
177857178815
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
177858178816
}
177859178817
assert( pBuf->n<=pBuf->nSpace );
177860178818
177861
- if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
177862
- /* The entire poslist will fit on the current leaf. So copy
177863
- ** it in one go. */
177864
- fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
177865
- }else{
177866
- /* The entire poslist will not fit on this leaf. So it needs
177867
- ** to be broken into sections. The only qualification being
177868
- ** that each varint must be stored contiguously. */
177869
- const u8 *pPoslist = &pDoclist[iOff];
177870
- int iPos = 0;
177871
- while( p->rc==SQLITE_OK ){
177872
- int nSpace = pgsz - pBuf->n - pPgidx->n;
177873
- int n = 0;
177874
- if( (nCopy - iPos)<=nSpace ){
177875
- n = nCopy - iPos;
177876
- }else{
177877
- n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
177878
- }
177879
- assert( n>0 );
177880
- fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
177881
- iPos += n;
177882
- if( (pBuf->n + pPgidx->n)>=pgsz ){
177883
- fts5WriteFlushLeaf(p, &writer);
177884
- }
177885
- if( iPos>=nCopy ) break;
177886
- }
177887
- }
177888
- iOff += nCopy;
178819
+ if( eDetail==FTS5_DETAIL_NONE ){
178820
+ if( iOff<nDoclist && pDoclist[iOff]==0 ){
178821
+ pBuf->p[pBuf->n++] = 0;
178822
+ iOff++;
178823
+ if( iOff<nDoclist && pDoclist[iOff]==0 ){
178824
+ pBuf->p[pBuf->n++] = 0;
178825
+ iOff++;
178826
+ }
178827
+ }
178828
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
178829
+ fts5WriteFlushLeaf(p, &writer);
178830
+ }
178831
+ }else{
178832
+ int bDummy;
178833
+ int nPos;
178834
+ int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
178835
+ nCopy += nPos;
178836
+ if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
178837
+ /* The entire poslist will fit on the current leaf. So copy
178838
+ ** it in one go. */
178839
+ fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
178840
+ }else{
178841
+ /* The entire poslist will not fit on this leaf. So it needs
178842
+ ** to be broken into sections. The only qualification being
178843
+ ** that each varint must be stored contiguously. */
178844
+ const u8 *pPoslist = &pDoclist[iOff];
178845
+ int iPos = 0;
178846
+ while( p->rc==SQLITE_OK ){
178847
+ int nSpace = pgsz - pBuf->n - pPgidx->n;
178848
+ int n = 0;
178849
+ if( (nCopy - iPos)<=nSpace ){
178850
+ n = nCopy - iPos;
178851
+ }else{
178852
+ n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
178853
+ }
178854
+ assert( n>0 );
178855
+ fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
178856
+ iPos += n;
178857
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
178858
+ fts5WriteFlushLeaf(p, &writer);
178859
+ }
178860
+ if( iPos>=nCopy ) break;
178861
+ }
178862
+ }
178863
+ iOff += nCopy;
178864
+ }
177889178865
}
177890178866
}
177891178867
177892178868
/* TODO2: Doclist terminator written here. */
177893178869
/* pBuf->p[pBuf->n++] = '\0'; */
@@ -178018,10 +178994,18 @@
178018178994
Fts5Buffer *pBuf; /* Append to this buffer */
178019178995
Fts5Colset *pColset; /* Restrict matches to this column */
178020178996
int eState; /* See above */
178021178997
};
178022178998
178999
+typedef struct PoslistOffsetsCtx PoslistOffsetsCtx;
179000
+struct PoslistOffsetsCtx {
179001
+ Fts5Buffer *pBuf; /* Append to this buffer */
179002
+ Fts5Colset *pColset; /* Restrict matches to this column */
179003
+ int iRead;
179004
+ int iWrite;
179005
+};
179006
+
178023179007
/*
178024179008
** TODO: Make this more efficient!
178025179009
*/
178026179010
static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
178027179011
int i;
@@ -178028,10 +179012,32 @@
178028179012
for(i=0; i<pColset->nCol; i++){
178029179013
if( pColset->aiCol[i]==iCol ) return 1;
178030179014
}
178031179015
return 0;
178032179016
}
179017
+
179018
+static void fts5PoslistOffsetsCallback(
179019
+ Fts5Index *p,
179020
+ void *pContext,
179021
+ const u8 *pChunk, int nChunk
179022
+){
179023
+ PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
179024
+ assert_nc( nChunk>=0 );
179025
+ if( nChunk>0 ){
179026
+ int i = 0;
179027
+ while( i<nChunk ){
179028
+ int iVal;
179029
+ i += fts5GetVarint32(&pChunk[i], iVal);
179030
+ iVal += pCtx->iRead - 2;
179031
+ pCtx->iRead = iVal;
179032
+ if( fts5IndexColsetTest(pCtx->pColset, iVal) ){
179033
+ fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite);
179034
+ pCtx->iWrite = iVal;
179035
+ }
179036
+ }
179037
+ }
179038
+}
178033179039
178034179040
static void fts5PoslistFilterCallback(
178035179041
Fts5Index *p,
178036179042
void *pContext,
178037179043
const u8 *pChunk, int nChunk
@@ -178096,16 +179102,24 @@
178096179102
){
178097179103
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
178098179104
if( pColset==0 ){
178099179105
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
178100179106
}else{
178101
- PoslistCallbackCtx sCtx;
178102
- sCtx.pBuf = pBuf;
178103
- sCtx.pColset = pColset;
178104
- sCtx.eState = fts5IndexColsetTest(pColset, 0);
178105
- assert( sCtx.eState==0 || sCtx.eState==1 );
178106
- fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
179107
+ if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
179108
+ PoslistCallbackCtx sCtx;
179109
+ sCtx.pBuf = pBuf;
179110
+ sCtx.pColset = pColset;
179111
+ sCtx.eState = fts5IndexColsetTest(pColset, 0);
179112
+ assert( sCtx.eState==0 || sCtx.eState==1 );
179113
+ fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
179114
+ }else{
179115
+ PoslistOffsetsCtx sCtx;
179116
+ memset(&sCtx, 0, sizeof(sCtx));
179117
+ sCtx.pBuf = pBuf;
179118
+ sCtx.pColset = pColset;
179119
+ fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback);
179120
+ }
178107179121
}
178108179122
}
178109179123
}
178110179124
178111179125
/*
@@ -178144,10 +179158,20 @@
178144179158
prev = *p++;
178145179159
}
178146179160
return p - (*pa);
178147179161
}
178148179162
179163
+static int fts5AppendRowid(
179164
+ Fts5Index *p,
179165
+ i64 iDelta,
179166
+ Fts5IndexIter *pMulti,
179167
+ Fts5Colset *pColset,
179168
+ Fts5Buffer *pBuf
179169
+){
179170
+ fts5BufferAppendVarint(&p->rc, pBuf, iDelta);
179171
+ return 0;
179172
+}
178149179173
178150179174
/*
178151179175
** Iterator pMulti currently points to a valid entry (not EOF). This
178152179176
** function appends the following to buffer pBuf:
178153179177
**
@@ -178171,12 +179195,12 @@
178171179195
if( p->rc==SQLITE_OK ){
178172179196
Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
178173179197
assert( fts5MultiIterEof(p, pMulti)==0 );
178174179198
assert( pSeg->nPos>0 );
178175179199
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
178176
-
178177
- if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
179200
+ if( p->pConfig->eDetail==FTS5_DETAIL_FULL
179201
+ && pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
178178179202
&& (pColset==0 || pColset->nCol==1)
178179179203
){
178180179204
const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
178181179205
int nPos;
178182179206
if( pColset ){
@@ -178217,16 +179241,16 @@
178217179241
sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
178218179242
}
178219179243
}
178220179244
}
178221179245
}
178222
-
178223179246
}
178224179247
}
178225179248
178226179249
return 0;
178227179250
}
179251
+
178228179252
178229179253
static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
178230179254
u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
178231179255
178232179256
assert( pIter->aPoslist );
@@ -178283,10 +179307,73 @@
178283179307
#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
178284179308
assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
178285179309
fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
178286179310
(iLastRowid) = (iRowid); \
178287179311
}
179312
+
179313
+/*
179314
+** Swap the contents of buffer *p1 with that of *p2.
179315
+*/
179316
+static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
179317
+ Fts5Buffer tmp = *p1;
179318
+ *p1 = *p2;
179319
+ *p2 = tmp;
179320
+}
179321
+
179322
+static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
179323
+ int i = *piOff;
179324
+ if( i>=pBuf->n ){
179325
+ *piOff = -1;
179326
+ }else{
179327
+ u64 iVal;
179328
+ *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal);
179329
+ *piRowid += iVal;
179330
+ }
179331
+}
179332
+
179333
+/*
179334
+** This is the equivalent of fts5MergePrefixLists() for detail=none mode.
179335
+** In this case the buffers consist of a delta-encoded list of rowids only.
179336
+*/
179337
+static void fts5MergeRowidLists(
179338
+ Fts5Index *p, /* FTS5 backend object */
179339
+ Fts5Buffer *p1, /* First list to merge */
179340
+ Fts5Buffer *p2 /* Second list to merge */
179341
+){
179342
+ int i1 = 0;
179343
+ int i2 = 0;
179344
+ i64 iRowid1 = 0;
179345
+ i64 iRowid2 = 0;
179346
+ i64 iOut = 0;
179347
+
179348
+ Fts5Buffer out;
179349
+ memset(&out, 0, sizeof(out));
179350
+ sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
179351
+ if( p->rc ) return;
179352
+
179353
+ fts5NextRowid(p1, &i1, &iRowid1);
179354
+ fts5NextRowid(p2, &i2, &iRowid2);
179355
+ while( i1>=0 || i2>=0 ){
179356
+ if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){
179357
+ assert( iOut==0 || iRowid1>iOut );
179358
+ fts5BufferSafeAppendVarint(&out, iRowid1 - iOut);
179359
+ iOut = iRowid1;
179360
+ fts5NextRowid(p1, &i1, &iRowid1);
179361
+ }else{
179362
+ assert( iOut==0 || iRowid2>iOut );
179363
+ fts5BufferSafeAppendVarint(&out, iRowid2 - iOut);
179364
+ iOut = iRowid2;
179365
+ if( i1>=0 && iRowid1==iRowid2 ){
179366
+ fts5NextRowid(p1, &i1, &iRowid1);
179367
+ }
179368
+ fts5NextRowid(p2, &i2, &iRowid2);
179369
+ }
179370
+ }
179371
+
179372
+ fts5BufferSwap(&out, p1);
179373
+ fts5BufferFree(&out);
179374
+}
178288179375
178289179376
/*
178290179377
** Buffers p1 and p2 contain doclists. This function merges the content
178291179378
** of the two doclists together and sets buffer p1 to the result before
178292179379
** returning.
@@ -178352,11 +179439,13 @@
178352179439
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
178353179440
if( iPos1==iPos2 ){
178354179441
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
178355179442
}
178356179443
}
178357
- p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
179444
+ if( iNew!=writer.iPrev || tmp.n==0 ){
179445
+ p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
179446
+ }
178358179447
}
178359179448
178360179449
/* WRITEPOSLISTSIZE */
178361179450
fts5BufferSafeAppendVarint(&out, tmp.n * 2);
178362179451
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
@@ -178369,16 +179458,10 @@
178369179458
fts5BufferFree(&tmp);
178370179459
fts5BufferFree(&out);
178371179460
}
178372179461
}
178373179462
178374
-static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
178375
- Fts5Buffer tmp = *p1;
178376
- *p1 = *p2;
178377
- *p2 = tmp;
178378
-}
178379
-
178380179463
static void fts5SetupPrefixIter(
178381179464
Fts5Index *p, /* Index to read from */
178382179465
int bDesc, /* True for "ORDER BY rowid DESC" */
178383179466
const u8 *pToken, /* Buffer containing prefix to match */
178384179467
int nToken, /* Size of buffer pToken in bytes */
@@ -178386,10 +179469,20 @@
178386179469
Fts5IndexIter **ppIter /* OUT: New iterator */
178387179470
){
178388179471
Fts5Structure *pStruct;
178389179472
Fts5Buffer *aBuf;
178390179473
const int nBuf = 32;
179474
+
179475
+ void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
179476
+ int (*xAppend)(Fts5Index*, i64, Fts5IndexIter*, Fts5Colset*, Fts5Buffer*);
179477
+ if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
179478
+ xMerge = fts5MergeRowidLists;
179479
+ xAppend = fts5AppendRowid;
179480
+ }else{
179481
+ xMerge = fts5MergePrefixLists;
179482
+ xAppend = fts5AppendPoslist;
179483
+ }
178391179484
178392179485
aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
178393179486
pStruct = fts5StructureRead(p);
178394179487
178395179488
if( aBuf && pStruct ){
@@ -178419,25 +179512,25 @@
178419179512
assert( i<nBuf );
178420179513
if( aBuf[i].n==0 ){
178421179514
fts5BufferSwap(&doclist, &aBuf[i]);
178422179515
fts5BufferZero(&doclist);
178423179516
}else{
178424
- fts5MergePrefixLists(p, &doclist, &aBuf[i]);
179517
+ xMerge(p, &doclist, &aBuf[i]);
178425179518
fts5BufferZero(&aBuf[i]);
178426179519
}
178427179520
}
178428179521
iLastRowid = 0;
178429179522
}
178430179523
178431
- if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
179524
+ if( !xAppend(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
178432179525
iLastRowid = iRowid;
178433179526
}
178434179527
}
178435179528
178436179529
for(i=0; i<nBuf; i++){
178437179530
if( p->rc==SQLITE_OK ){
178438
- fts5MergePrefixLists(p, &doclist, &aBuf[i]);
179531
+ xMerge(p, &doclist, &aBuf[i]);
178439179532
}
178440179533
fts5BufferFree(&aBuf[i]);
178441179534
}
178442179535
fts5MultiIterFree(p, p1);
178443179536
@@ -178463,11 +179556,11 @@
178463179556
static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
178464179557
assert( p->rc==SQLITE_OK );
178465179558
178466179559
/* Allocate the hash table if it has not already been allocated */
178467179560
if( p->pHash==0 ){
178468
- p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData);
179561
+ p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
178469179562
}
178470179563
178471179564
/* Flush the hash table to disk if required */
178472179565
if( iRowid<p->iWriteRowid
178473179566
|| (iRowid==p->iWriteRowid && p->bDelete==0)
@@ -178584,11 +179677,15 @@
178584179677
/*
178585179678
** Argument p points to a buffer containing utf-8 text that is n bytes in
178586179679
** size. Return the number of bytes in the nChar character prefix of the
178587179680
** buffer, or 0 if there are less than nChar characters in total.
178588179681
*/
178589
-static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){
179682
+static int sqlite3Fts5IndexCharlenToBytelen(
179683
+ const char *p,
179684
+ int nByte,
179685
+ int nChar
179686
+){
178590179687
int n = 0;
178591179688
int i;
178592179689
for(i=0; i<nChar; i++){
178593179690
if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
178594179691
if( (unsigned char)p[n++]>=0xc0 ){
@@ -178641,11 +179738,12 @@
178641179738
rc = sqlite3Fts5HashWrite(
178642179739
p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken
178643179740
);
178644179741
178645179742
for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
178646
- int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]);
179743
+ const int nChar = pConfig->aPrefix[i];
179744
+ int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
178647179745
if( nByte ){
178648179746
rc = sqlite3Fts5HashWrite(p->pHash,
178649179747
p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
178650179748
nByte
178651179749
);
@@ -178819,13 +179917,20 @@
178819179917
const u8 **pp, /* OUT: Pointer to position-list data */
178820179918
int *pn, /* OUT: Size of position-list in bytes */
178821179919
i64 *piRowid /* OUT: Current rowid */
178822179920
){
178823179921
Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
179922
+ int eDetail = pIter->pIndex->pConfig->eDetail;
179923
+
178824179924
assert( pIter->pIndex->rc==SQLITE_OK );
178825179925
*piRowid = pSeg->iRowid;
178826
- if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
179926
+ if( eDetail==FTS5_DETAIL_NONE ){
179927
+ *pn = pSeg->nPos;
179928
+ }else
179929
+ if( eDetail==FTS5_DETAIL_FULL
179930
+ && pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
179931
+ ){
178827179932
u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
178828179933
if( pColset==0 || pIter->bFiltered ){
178829179934
*pn = pSeg->nPos;
178830179935
*pp = pPos;
178831179936
}else if( pColset->nCol==1 ){
@@ -178838,15 +179943,28 @@
178838179943
*pn = pIter->poslist.n;
178839179944
}
178840179945
}else{
178841179946
fts5BufferZero(&pIter->poslist);
178842179947
fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
178843
- *pp = pIter->poslist.p;
179948
+ if( eDetail==FTS5_DETAIL_FULL ){
179949
+ *pp = pIter->poslist.p;
179950
+ }
178844179951
*pn = pIter->poslist.n;
178845179952
}
178846179953
return fts5IndexReturn(pIter->pIndex);
178847179954
}
179955
+
179956
+static int sqlite3Fts5IterCollist(
179957
+ Fts5IndexIter *pIter,
179958
+ const u8 **pp, /* OUT: Pointer to position-list data */
179959
+ int *pn /* OUT: Size of position-list in bytes */
179960
+){
179961
+ assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
179962
+ *pp = pIter->poslist.p;
179963
+ *pn = pIter->poslist.n;
179964
+ return SQLITE_OK;
179965
+}
178848179966
178849179967
/*
178850179968
** This function is similar to sqlite3Fts5IterPoslist(), except that it
178851179969
** copies the position list into the buffer supplied as the second
178852179970
** argument.
@@ -178957,11 +180075,11 @@
178957180075
*/
178958180076
178959180077
/*
178960180078
** Return a simple checksum value based on the arguments.
178961180079
*/
178962
-static u64 fts5IndexEntryCksum(
180080
+static u64 sqlite3Fts5IndexEntryCksum(
178963180081
i64 iRowid,
178964180082
int iCol,
178965180083
int iPos,
178966180084
int iIdx,
178967180085
const char *pTerm,
@@ -179027,34 +180145,41 @@
179027180145
const char *z, /* Index key to query for */
179028180146
int n, /* Size of index key in bytes */
179029180147
int flags, /* Flags for Fts5IndexQuery */
179030180148
u64 *pCksum /* IN/OUT: Checksum value */
179031180149
){
180150
+ int eDetail = p->pConfig->eDetail;
179032180151
u64 cksum = *pCksum;
179033180152
Fts5IndexIter *pIdxIter = 0;
180153
+ Fts5Buffer buf = {0, 0, 0};
179034180154
int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
179035180155
179036180156
while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
179037
- i64 dummy;
179038
- const u8 *pPos;
179039
- int nPos;
179040180157
i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
179041
- rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
180158
+
180159
+ if( eDetail==FTS5_DETAIL_NONE ){
180160
+ cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
180161
+ }else{
180162
+ rc = sqlite3Fts5IterPoslistBuffer(pIdxIter, &buf);
180163
+ if( rc==SQLITE_OK ){
180164
+ Fts5PoslistReader sReader;
180165
+ for(sqlite3Fts5PoslistReaderInit(buf.p, buf.n, &sReader);
180166
+ sReader.bEof==0;
180167
+ sqlite3Fts5PoslistReaderNext(&sReader)
180168
+ ){
180169
+ int iCol = FTS5_POS2COLUMN(sReader.iPos);
180170
+ int iOff = FTS5_POS2OFFSET(sReader.iPos);
180171
+ cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
180172
+ }
180173
+ }
180174
+ }
179042180175
if( rc==SQLITE_OK ){
179043
- Fts5PoslistReader sReader;
179044
- for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
179045
- sReader.bEof==0;
179046
- sqlite3Fts5PoslistReaderNext(&sReader)
179047
- ){
179048
- int iCol = FTS5_POS2COLUMN(sReader.iPos);
179049
- int iOff = FTS5_POS2OFFSET(sReader.iPos);
179050
- cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
179051
- }
179052180176
rc = sqlite3Fts5IterNext(pIdxIter);
179053180177
}
179054180178
}
179055180179
sqlite3Fts5IterClose(pIdxIter);
180180
+ fts5BufferFree(&buf);
179056180181
179057180182
*pCksum = cksum;
179058180183
return rc;
179059180184
}
179060180185
@@ -179344,18 +180469,19 @@
179344180469
179345180470
179346180471
/*
179347180472
** Run internal checks to ensure that the FTS index (a) is internally
179348180473
** consistent and (b) contains entries for which the XOR of the checksums
179349
-** as calculated by fts5IndexEntryCksum() is cksum.
180474
+** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
179350180475
**
179351180476
** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
179352180477
** checksum does not match. Return SQLITE_OK if all checks pass without
179353180478
** error, or some other SQLite error code if another error (e.g. OOM)
179354180479
** occurs.
179355180480
*/
179356180481
static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
180482
+ int eDetail = p->pConfig->eDetail;
179357180483
u64 cksum2 = 0; /* Checksum based on contents of indexes */
179358180484
Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
179359180485
Fts5IndexIter *pIter; /* Used to iterate through entire index */
179360180486
Fts5Structure *pStruct; /* Index structure */
179361180487
@@ -179403,16 +180529,22 @@
179403180529
char *z = (char*)fts5MultiIterTerm(pIter, &n);
179404180530
179405180531
/* If this is a new term, query for it. Update cksum3 with the results. */
179406180532
fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
179407180533
179408
- poslist.n = 0;
179409
- fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist);
179410
- while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
179411
- int iCol = FTS5_POS2COLUMN(iPos);
179412
- int iTokOff = FTS5_POS2OFFSET(iPos);
179413
- cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
180534
+ if( eDetail==FTS5_DETAIL_NONE ){
180535
+ if( 0==fts5MultiIterIsEmpty(p, pIter) ){
180536
+ cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
180537
+ }
180538
+ }else{
180539
+ poslist.n = 0;
180540
+ fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
180541
+ while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
180542
+ int iCol = FTS5_POS2COLUMN(iPos);
180543
+ int iTokOff = FTS5_POS2OFFSET(iPos);
180544
+ cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
180545
+ }
179414180546
}
179415180547
}
179416180548
fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
179417180549
179418180550
fts5MultiIterFree(p, pIter);
@@ -179424,38 +180556,10 @@
179424180556
#endif
179425180557
fts5BufferFree(&poslist);
179426180558
return fts5IndexReturn(p);
179427180559
}
179428180560
179429
-
179430
-/*
179431
-** Calculate and return a checksum that is the XOR of the index entry
179432
-** checksum of all entries that would be generated by the token specified
179433
-** by the final 5 arguments.
179434
-*/
179435
-static u64 sqlite3Fts5IndexCksum(
179436
- Fts5Config *pConfig, /* Configuration object */
179437
- i64 iRowid, /* Document term appears in */
179438
- int iCol, /* Column term appears in */
179439
- int iPos, /* Position term appears in */
179440
- const char *pTerm, int nTerm /* Term at iPos */
179441
-){
179442
- u64 ret = 0; /* Return value */
179443
- int iIdx; /* For iterating through indexes */
179444
-
179445
- ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm);
179446
-
179447
- for(iIdx=0; iIdx<pConfig->nPrefix; iIdx++){
179448
- int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]);
179449
- if( nByte ){
179450
- ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte);
179451
- }
179452
- }
179453
-
179454
- return ret;
179455
-}
179456
-
179457180561
/*************************************************************************
179458180562
**************************************************************************
179459180563
** Below this point is the implementation of the fts5_decode() scalar
179460180564
** function only.
179461180565
*/
@@ -179618,10 +180722,51 @@
179618180722
}
179619180723
}
179620180724
179621180725
return iOff;
179622180726
}
180727
+
180728
+/*
180729
+** This function is part of the fts5_decode() debugging function. It is
180730
+** only ever used with detail=none tables.
180731
+**
180732
+** Buffer (pData/nData) contains a doclist in the format used by detail=none
180733
+** tables. This function appends a human-readable version of that list to
180734
+** buffer pBuf.
180735
+**
180736
+** If *pRc is other than SQLITE_OK when this function is called, it is a
180737
+** no-op. If an OOM or other error occurs within this function, *pRc is
180738
+** set to an SQLite error code before returning. The final state of buffer
180739
+** pBuf is undefined in this case.
180740
+*/
180741
+static void fts5DecodeRowidList(
180742
+ int *pRc, /* IN/OUT: Error code */
180743
+ Fts5Buffer *pBuf, /* Buffer to append text to */
180744
+ const u8 *pData, int nData /* Data to decode list-of-rowids from */
180745
+){
180746
+ int i = 0;
180747
+ i64 iRowid = 0;
180748
+
180749
+ while( i<nData ){
180750
+ const char *zApp = "";
180751
+ u64 iVal;
180752
+ i += sqlite3Fts5GetVarint(&pData[i], &iVal);
180753
+ iRowid += iVal;
180754
+
180755
+ if( i<nData && pData[i]==0x00 ){
180756
+ i++;
180757
+ if( i<nData && pData[i]==0x00 ){
180758
+ i++;
180759
+ zApp = "+";
180760
+ }else{
180761
+ zApp = "*";
180762
+ }
180763
+ }
180764
+
180765
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
180766
+ }
180767
+}
179623180768
179624180769
/*
179625180770
** The implementation of user-defined scalar function fts5_decode().
179626180771
*/
179627180772
static void fts5DecodeFunction(
@@ -179634,10 +180779,11 @@
179634180779
const u8 *aBlob; int n; /* Record to decode */
179635180780
u8 *a = 0;
179636180781
Fts5Buffer s; /* Build up text to return here */
179637180782
int rc = SQLITE_OK; /* Return code */
179638180783
int nSpace = 0;
180784
+ int eDetailNone = (sqlite3_user_data(pCtx)!=0);
179639180785
179640180786
assert( nArg==2 );
179641180787
memset(&s, 0, sizeof(Fts5Buffer));
179642180788
iRowid = sqlite3_value_int64(apVal[0]);
179643180789
@@ -179675,10 +180821,58 @@
179675180821
if( iRowid==FTS5_AVERAGES_ROWID ){
179676180822
fts5DecodeAverages(&rc, &s, a, n);
179677180823
}else{
179678180824
fts5DecodeStructure(&rc, &s, a, n);
179679180825
}
180826
+ }else if( eDetailNone ){
180827
+ Fts5Buffer term; /* Current term read from page */
180828
+ int szLeaf;
180829
+ int iPgidxOff = szLeaf = fts5GetU16(&a[2]);
180830
+ int iTermOff;
180831
+ int nKeep = 0;
180832
+ int iOff;
180833
+
180834
+ memset(&term, 0, sizeof(Fts5Buffer));
180835
+
180836
+ /* Decode any entries that occur before the first term. */
180837
+ if( szLeaf<n ){
180838
+ iPgidxOff += fts5GetVarint32(&a[iPgidxOff], iTermOff);
180839
+ }else{
180840
+ iTermOff = szLeaf;
180841
+ }
180842
+ fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
180843
+
180844
+ iOff = iTermOff;
180845
+ while( iOff<szLeaf ){
180846
+ int nAppend;
180847
+
180848
+ /* Read the term data for the next term*/
180849
+ iOff += fts5GetVarint32(&a[iOff], nAppend);
180850
+ term.n = nKeep;
180851
+ fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
180852
+ sqlite3Fts5BufferAppendPrintf(
180853
+ &rc, &s, " term=%.*s", term.n, (const char*)term.p
180854
+ );
180855
+ iOff += nAppend;
180856
+
180857
+ /* Figure out where the doclist for this term ends */
180858
+ if( iPgidxOff<n ){
180859
+ int nIncr;
180860
+ iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr);
180861
+ iTermOff += nIncr;
180862
+ }else{
180863
+ iTermOff = szLeaf;
180864
+ }
180865
+
180866
+ fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
180867
+ iOff = iTermOff;
180868
+ if( iOff<szLeaf ){
180869
+ iOff += fts5GetVarint32(&a[iOff], nKeep);
180870
+ }
180871
+ }
180872
+
180873
+ fts5BufferFree(&term);
179680180874
}else{
179681180875
Fts5Buffer term; /* Current term read from page */
179682180876
int szLeaf; /* Offset of pgidx in a[] */
179683180877
int iPgidxOff;
179684180878
int iPgidxPrev = 0; /* Previous value read from pgidx */
@@ -179802,18 +180996,25 @@
179802180996
*/
179803180997
static int sqlite3Fts5IndexInit(sqlite3 *db){
179804180998
int rc = sqlite3_create_function(
179805180999
db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
179806181000
);
181001
+
181002
+ if( rc==SQLITE_OK ){
181003
+ rc = sqlite3_create_function(
181004
+ db, "fts5_decode_none", 2,
181005
+ SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
181006
+ );
181007
+ }
181008
+
179807181009
if( rc==SQLITE_OK ){
179808181010
rc = sqlite3_create_function(
179809181011
db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
179810181012
);
179811181013
}
179812181014
return rc;
179813181015
}
179814
-
179815181016
179816181017
/*
179817181018
** 2014 Jun 09
179818181019
**
179819181020
** The author disclaims copyright to this source code. In place of
@@ -180039,10 +181240,11 @@
180039181240
#define FTS5CSR_REQUIRE_DOCSIZE 0x02
180040181241
#define FTS5CSR_REQUIRE_INST 0x04
180041181242
#define FTS5CSR_EOF 0x08
180042181243
#define FTS5CSR_FREE_ZRANK 0x10
180043181244
#define FTS5CSR_REQUIRE_RESEEK 0x20
181245
+#define FTS5CSR_REQUIRE_POSLIST 0x40
180044181246
180045181247
#define BitFlagAllTest(x,y) (((x) & (y))==(y))
180046181248
#define BitFlagTest(x,y) (((x) & (y))!=0)
180047181249
180048181250
@@ -180452,10 +181654,11 @@
180452181654
static void fts5CsrNewrow(Fts5Cursor *pCsr){
180453181655
CsrFlagSet(pCsr,
180454181656
FTS5CSR_REQUIRE_CONTENT
180455181657
| FTS5CSR_REQUIRE_DOCSIZE
180456181658
| FTS5CSR_REQUIRE_INST
181659
+ | FTS5CSR_REQUIRE_POSLIST
180457181660
);
180458181661
}
180459181662
180460181663
static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
180461181664
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
@@ -180534,19 +181737,22 @@
180534181737
180535181738
pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
180536181739
nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
180537181740
aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
180538181741
180539
- for(i=0; i<(pSorter->nIdx-1); i++){
180540
- int iVal;
180541
- a += fts5GetVarint32(a, iVal);
180542
- iOff += iVal;
180543
- pSorter->aIdx[i] = iOff;
180544
- }
180545
- pSorter->aIdx[i] = &aBlob[nBlob] - a;
180546
-
180547
- pSorter->aPoslist = a;
181742
+ /* nBlob==0 in detail=none mode. */
181743
+ if( nBlob>0 ){
181744
+ for(i=0; i<(pSorter->nIdx-1); i++){
181745
+ int iVal;
181746
+ a += fts5GetVarint32(a, iVal);
181747
+ iOff += iVal;
181748
+ pSorter->aIdx[i] = iOff;
181749
+ }
181750
+ pSorter->aIdx[i] = &aBlob[nBlob] - a;
181751
+ pSorter->aPoslist = a;
181752
+ }
181753
+
180548181754
fts5CsrNewrow(pCsr);
180549181755
}
180550181756
180551181757
return rc;
180552181758
}
@@ -180652,45 +181858,44 @@
180652181858
180653181859
return rc;
180654181860
}
180655181861
180656181862
180657
-static sqlite3_stmt *fts5PrepareStatement(
180658
- int *pRc,
181863
+static int fts5PrepareStatement(
181864
+ sqlite3_stmt **ppStmt,
180659181865
Fts5Config *pConfig,
180660181866
const char *zFmt,
180661181867
...
180662181868
){
180663181869
sqlite3_stmt *pRet = 0;
181870
+ int rc;
181871
+ char *zSql;
180664181872
va_list ap;
181873
+
180665181874
va_start(ap, zFmt);
180666
-
180667
- if( *pRc==SQLITE_OK ){
180668
- int rc;
180669
- char *zSql = sqlite3_vmprintf(zFmt, ap);
180670
- if( zSql==0 ){
180671
- rc = SQLITE_NOMEM;
180672
- }else{
180673
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
180674
- if( rc!=SQLITE_OK ){
180675
- *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
180676
- }
180677
- sqlite3_free(zSql);
180678
- }
180679
- *pRc = rc;
181875
+ zSql = sqlite3_vmprintf(zFmt, ap);
181876
+ if( zSql==0 ){
181877
+ rc = SQLITE_NOMEM;
181878
+ }else{
181879
+ rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
181880
+ if( rc!=SQLITE_OK ){
181881
+ *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
181882
+ }
181883
+ sqlite3_free(zSql);
180680181884
}
180681181885
180682181886
va_end(ap);
180683
- return pRet;
181887
+ *ppStmt = pRet;
181888
+ return rc;
180684181889
}
180685181890
180686181891
static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
180687181892
Fts5Config *pConfig = pTab->pConfig;
180688181893
Fts5Sorter *pSorter;
180689181894
int nPhrase;
180690181895
int nByte;
180691
- int rc = SQLITE_OK;
181896
+ int rc;
180692181897
const char *zRank = pCsr->zRank;
180693181898
const char *zRankArgs = pCsr->zRankArgs;
180694181899
180695181900
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
180696181901
nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
@@ -180704,11 +181909,11 @@
180704181909
** is not possible as SQLite reference counts the virtual table objects.
180705181910
** And since the statement required here reads from this very virtual
180706181911
** table, saving it creates a circular reference.
180707181912
**
180708181913
** If SQLite a built-in statement cache, this wouldn't be a problem. */
180709
- pSorter->pStmt = fts5PrepareStatement(&rc, pConfig,
181914
+ rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
180710181915
"SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
180711181916
pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
180712181917
(zRankArgs ? ", " : ""),
180713181918
(zRankArgs ? zRankArgs : ""),
180714181919
bDesc ? "DESC" : "ASC"
@@ -180980,10 +182185,11 @@
180980182185
assert( pCsr->iLastRowid==LARGEST_INT64 );
180981182186
assert( pCsr->iFirstRowid==SMALLEST_INT64 );
180982182187
pCsr->ePlan = FTS5_PLAN_SOURCE;
180983182188
pCsr->pExpr = pTab->pSortCsr->pExpr;
180984182189
rc = fts5CursorFirst(pTab, pCsr, bDesc);
182190
+ sqlite3Fts5ExprClearEof(pCsr->pExpr);
180985182191
}else if( pMatch ){
180986182192
const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
180987182193
if( zExpr==0 ) zExpr = "";
180988182194
180989182195
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
@@ -181212,11 +182418,11 @@
181212182418
){
181213182419
int rc = SQLITE_OK;
181214182420
int eType1 = sqlite3_value_type(apVal[1]);
181215182421
if( eType1==SQLITE_INTEGER ){
181216182422
sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
181217
- rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]);
182423
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
181218182424
}
181219182425
return rc;
181220182426
}
181221182427
181222182428
static void fts5StorageInsert(
@@ -181319,21 +182525,21 @@
181319182525
}
181320182526
181321182527
/* Case 1: DELETE */
181322182528
else if( nArg==1 ){
181323182529
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
181324
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
182530
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
181325182531
}
181326182532
181327182533
/* Case 2: INSERT */
181328182534
else if( eType0!=SQLITE_INTEGER ){
181329182535
/* If this is a REPLACE, first remove the current entry (if any) */
181330182536
if( eConflict==SQLITE_REPLACE
181331182537
&& sqlite3_value_type(apVal[1])==SQLITE_INTEGER
181332182538
){
181333182539
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
181334
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
182540
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
181335182541
}
181336182542
fts5StorageInsert(&rc, pTab, apVal, pRowid);
181337182543
}
181338182544
181339182545
/* Case 2: UPDATE */
@@ -181340,26 +182546,26 @@
181340182546
else{
181341182547
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
181342182548
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
181343182549
if( iOld!=iNew ){
181344182550
if( eConflict==SQLITE_REPLACE ){
181345
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
182551
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
181346182552
if( rc==SQLITE_OK ){
181347
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
182553
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
181348182554
}
181349182555
fts5StorageInsert(&rc, pTab, apVal, pRowid);
181350182556
}else{
181351182557
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
181352182558
if( rc==SQLITE_OK ){
181353
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
182559
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
181354182560
}
181355182561
if( rc==SQLITE_OK ){
181356182562
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
181357182563
}
181358182564
}
181359182565
}else{
181360
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
182566
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
181361182567
fts5StorageInsert(&rc, pTab, apVal, pRowid);
181362182568
}
181363182569
}
181364182570
}
181365182571
@@ -181409,10 +182615,12 @@
181409182615
fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
181410182616
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
181411182617
return rc;
181412182618
}
181413182619
182620
+static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
182621
+
181414182622
static void *fts5ApiUserData(Fts5Context *pCtx){
181415182623
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181416182624
return pCsr->pAux->pUserData;
181417182625
}
181418182626
@@ -181458,21 +182666,76 @@
181458182666
static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
181459182667
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181460182668
return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
181461182669
}
181462182670
181463
-static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
181464
- int n;
181465
- if( pCsr->pSorter ){
182671
+static int fts5ApiColumnText(
182672
+ Fts5Context *pCtx,
182673
+ int iCol,
182674
+ const char **pz,
182675
+ int *pn
182676
+){
182677
+ int rc = SQLITE_OK;
182678
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
182679
+ if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
182680
+ *pz = 0;
182681
+ *pn = 0;
182682
+ }else{
182683
+ rc = fts5SeekCursor(pCsr, 0);
182684
+ if( rc==SQLITE_OK ){
182685
+ *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
182686
+ *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
182687
+ }
182688
+ }
182689
+ return rc;
182690
+}
182691
+
182692
+static int fts5CsrPoslist(
182693
+ Fts5Cursor *pCsr,
182694
+ int iPhrase,
182695
+ const u8 **pa,
182696
+ int *pn
182697
+){
182698
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
182699
+ int rc = SQLITE_OK;
182700
+ int bLive = (pCsr->pSorter==0);
182701
+
182702
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
182703
+
182704
+ if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
182705
+ Fts5PoslistPopulator *aPopulator;
182706
+ int i;
182707
+ aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
182708
+ if( aPopulator==0 ) rc = SQLITE_NOMEM;
182709
+ for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
182710
+ int n; const char *z;
182711
+ rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
182712
+ if( rc==SQLITE_OK ){
182713
+ rc = sqlite3Fts5ExprPopulatePoslists(
182714
+ pConfig, pCsr->pExpr, aPopulator, i, z, n
182715
+ );
182716
+ }
182717
+ }
182718
+ sqlite3_free(aPopulator);
182719
+
182720
+ if( pCsr->pSorter ){
182721
+ sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
182722
+ }
182723
+ }
182724
+ CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
182725
+ }
182726
+
182727
+ if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
181466182728
Fts5Sorter *pSorter = pCsr->pSorter;
181467182729
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
181468
- n = pSorter->aIdx[iPhrase] - i1;
182730
+ *pn = pSorter->aIdx[iPhrase] - i1;
181469182731
*pa = &pSorter->aPoslist[i1];
181470182732
}else{
181471
- n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
182733
+ *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
181472182734
}
181473
- return n;
182735
+
182736
+ return rc;
181474182737
}
181475182738
181476182739
/*
181477182740
** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
181478182741
** correctly for the current view. Return SQLITE_OK if successful, or an
@@ -181493,47 +182756,52 @@
181493182756
if( aIter ){
181494182757
int nInst = 0; /* Number instances seen so far */
181495182758
int i;
181496182759
181497182760
/* Initialize all iterators */
181498
- for(i=0; i<nIter; i++){
182761
+ for(i=0; i<nIter && rc==SQLITE_OK; i++){
181499182762
const u8 *a;
181500
- int n = fts5CsrPoslist(pCsr, i, &a);
181501
- sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
181502
- }
181503
-
181504
- while( 1 ){
181505
- int *aInst;
181506
- int iBest = -1;
181507
- for(i=0; i<nIter; i++){
181508
- if( (aIter[i].bEof==0)
181509
- && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
181510
- ){
181511
- iBest = i;
181512
- }
181513
- }
181514
- if( iBest<0 ) break;
181515
-
181516
- nInst++;
181517
- if( nInst>=pCsr->nInstAlloc ){
181518
- pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
181519
- aInst = (int*)sqlite3_realloc(
181520
- pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
181521
- );
181522
- if( aInst ){
181523
- pCsr->aInst = aInst;
181524
- }else{
181525
- rc = SQLITE_NOMEM;
181526
- break;
181527
- }
181528
- }
181529
-
181530
- aInst = &pCsr->aInst[3 * (nInst-1)];
181531
- aInst[0] = iBest;
181532
- aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
181533
- aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
181534
- sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
182763
+ int n;
182764
+ rc = fts5CsrPoslist(pCsr, i, &a, &n);
182765
+ if( rc==SQLITE_OK ){
182766
+ sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
182767
+ }
182768
+ }
182769
+
182770
+ if( rc==SQLITE_OK ){
182771
+ while( 1 ){
182772
+ int *aInst;
182773
+ int iBest = -1;
182774
+ for(i=0; i<nIter; i++){
182775
+ if( (aIter[i].bEof==0)
182776
+ && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
182777
+ ){
182778
+ iBest = i;
182779
+ }
182780
+ }
182781
+ if( iBest<0 ) break;
182782
+
182783
+ nInst++;
182784
+ if( nInst>=pCsr->nInstAlloc ){
182785
+ pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
182786
+ aInst = (int*)sqlite3_realloc(
182787
+ pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
182788
+ );
182789
+ if( aInst ){
182790
+ pCsr->aInst = aInst;
182791
+ }else{
182792
+ rc = SQLITE_NOMEM;
182793
+ break;
182794
+ }
182795
+ }
182796
+
182797
+ aInst = &pCsr->aInst[3 * (nInst-1)];
182798
+ aInst[0] = iBest;
182799
+ aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
182800
+ aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
182801
+ sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
182802
+ }
181535182803
}
181536182804
181537182805
pCsr->nInstCount = nInst;
181538182806
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
181539182807
}
@@ -181562,10 +182830,16 @@
181562182830
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
181563182831
|| SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
181564182832
){
181565182833
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
181566182834
rc = SQLITE_RANGE;
182835
+#if 0
182836
+ }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
182837
+ *piPhrase = pCsr->aInst[iIdx*3];
182838
+ *piCol = pCsr->aInst[iIdx*3 + 2];
182839
+ *piOff = -1;
182840
+#endif
181567182841
}else{
181568182842
*piPhrase = pCsr->aInst[iIdx*3];
181569182843
*piCol = pCsr->aInst[iIdx*3 + 1];
181570182844
*piOff = pCsr->aInst[iIdx*3 + 2];
181571182845
}
@@ -181575,31 +182849,10 @@
181575182849
181576182850
static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
181577182851
return fts5CursorRowid((Fts5Cursor*)pCtx);
181578182852
}
181579182853
181580
-static int fts5ApiColumnText(
181581
- Fts5Context *pCtx,
181582
- int iCol,
181583
- const char **pz,
181584
- int *pn
181585
-){
181586
- int rc = SQLITE_OK;
181587
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181588
- if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
181589
- *pz = 0;
181590
- *pn = 0;
181591
- }else{
181592
- rc = fts5SeekCursor(pCsr, 0);
181593
- if( rc==SQLITE_OK ){
181594
- *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
181595
- *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
181596
- }
181597
- }
181598
- return rc;
181599
-}
181600
-
181601182854
static int fts5ColumnSizeCb(
181602182855
void *pContext, /* Pointer to int */
181603182856
int tflags,
181604182857
const char *pToken, /* Buffer containing token */
181605182858
int nToken, /* Size of token in bytes */
@@ -181740,23 +182993,101 @@
181740182993
}
181741182994
*piOff += (iVal-2);
181742182995
}
181743182996
}
181744182997
181745
-static void fts5ApiPhraseFirst(
182998
+static int fts5ApiPhraseFirst(
181746182999
Fts5Context *pCtx,
181747183000
int iPhrase,
181748183001
Fts5PhraseIter *pIter,
181749183002
int *piCol, int *piOff
181750183003
){
181751183004
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181752
- int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
181753
- pIter->b = &pIter->a[n];
181754
- *piCol = 0;
181755
- *piOff = 0;
181756
- fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
183005
+ int n;
183006
+ int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
183007
+ if( rc==SQLITE_OK ){
183008
+ pIter->b = &pIter->a[n];
183009
+ *piCol = 0;
183010
+ *piOff = 0;
183011
+ fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
183012
+ }
183013
+ return rc;
181757183014
}
183015
+
183016
+static void fts5ApiPhraseNextColumn(
183017
+ Fts5Context *pCtx,
183018
+ Fts5PhraseIter *pIter,
183019
+ int *piCol
183020
+){
183021
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
183022
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
183023
+
183024
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
183025
+ if( pIter->a>=pIter->b ){
183026
+ *piCol = -1;
183027
+ }else{
183028
+ int iIncr;
183029
+ pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
183030
+ *piCol += (iIncr-2);
183031
+ }
183032
+ }else{
183033
+ while( 1 ){
183034
+ int dummy;
183035
+ if( pIter->a>=pIter->b ){
183036
+ *piCol = -1;
183037
+ return;
183038
+ }
183039
+ if( pIter->a[0]==0x01 ) break;
183040
+ pIter->a += fts5GetVarint32(pIter->a, dummy);
183041
+ }
183042
+ pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
183043
+ }
183044
+}
183045
+
183046
+static int fts5ApiPhraseFirstColumn(
183047
+ Fts5Context *pCtx,
183048
+ int iPhrase,
183049
+ Fts5PhraseIter *pIter,
183050
+ int *piCol
183051
+){
183052
+ int rc = SQLITE_OK;
183053
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
183054
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
183055
+
183056
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
183057
+ Fts5Sorter *pSorter = pCsr->pSorter;
183058
+ int n;
183059
+ if( pSorter ){
183060
+ int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
183061
+ n = pSorter->aIdx[iPhrase] - i1;
183062
+ pIter->a = &pSorter->aPoslist[i1];
183063
+ }else{
183064
+ rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
183065
+ }
183066
+ if( rc==SQLITE_OK ){
183067
+ pIter->b = &pIter->a[n];
183068
+ *piCol = 0;
183069
+ fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
183070
+ }
183071
+ }else{
183072
+ int n;
183073
+ rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
183074
+ if( rc==SQLITE_OK ){
183075
+ pIter->b = &pIter->a[n];
183076
+ if( n<=0 ){
183077
+ *piCol = -1;
183078
+ }else if( pIter->a[0]==0x01 ){
183079
+ pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
183080
+ }else{
183081
+ *piCol = 0;
183082
+ }
183083
+ }
183084
+ }
183085
+
183086
+ return rc;
183087
+}
183088
+
181758183089
181759183090
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
181760183091
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
181761183092
);
181762183093
@@ -181777,12 +183108,13 @@
181777183108
fts5ApiQueryPhrase,
181778183109
fts5ApiSetAuxdata,
181779183110
fts5ApiGetAuxdata,
181780183111
fts5ApiPhraseFirst,
181781183112
fts5ApiPhraseNext,
183113
+ fts5ApiPhraseFirstColumn,
183114
+ fts5ApiPhraseNextColumn,
181782183115
};
181783
-
181784183116
181785183117
/*
181786183118
** Implementation of API function xQueryPhrase().
181787183119
*/
181788183120
static int fts5ApiQueryPhrase(
@@ -181911,24 +183243,50 @@
181911183243
int rc = SQLITE_OK;
181912183244
int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
181913183245
Fts5Buffer val;
181914183246
181915183247
memset(&val, 0, sizeof(Fts5Buffer));
181916
-
181917
- /* Append the varints */
181918
- for(i=0; i<(nPhrase-1); i++){
181919
- const u8 *dummy;
181920
- int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
181921
- sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
181922
- }
181923
-
181924
- /* Append the position lists */
181925
- for(i=0; i<nPhrase; i++){
181926
- const u8 *pPoslist;
181927
- int nPoslist;
181928
- nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
181929
- sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
183248
+ switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
183249
+ case FTS5_DETAIL_FULL:
183250
+
183251
+ /* Append the varints */
183252
+ for(i=0; i<(nPhrase-1); i++){
183253
+ const u8 *dummy;
183254
+ int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
183255
+ sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
183256
+ }
183257
+
183258
+ /* Append the position lists */
183259
+ for(i=0; i<nPhrase; i++){
183260
+ const u8 *pPoslist;
183261
+ int nPoslist;
183262
+ nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
183263
+ sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
183264
+ }
183265
+ break;
183266
+
183267
+ case FTS5_DETAIL_COLUMNS:
183268
+
183269
+ /* Append the varints */
183270
+ for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
183271
+ const u8 *dummy;
183272
+ int nByte;
183273
+ rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
183274
+ sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
183275
+ }
183276
+
183277
+ /* Append the position lists */
183278
+ for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
183279
+ const u8 *pPoslist;
183280
+ int nPoslist;
183281
+ rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
183282
+ sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
183283
+ }
183284
+ break;
183285
+
183286
+ default:
183287
+ break;
181930183288
}
181931183289
181932183290
sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
181933183291
return rc;
181934183292
}
@@ -182247,11 +183605,11 @@
182247183605
sqlite3_context *pCtx, /* Function call context */
182248183606
int nArg, /* Number of args */
182249183607
sqlite3_value **apVal /* Function arguments */
182250183608
){
182251183609
assert( nArg==0 );
182252
- sqlite3_result_text(pCtx, "fts5: 2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566", -1, SQLITE_TRANSIENT);
183610
+ sqlite3_result_text(pCtx, "fts5: 2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1", -1, SQLITE_TRANSIENT);
182253183611
}
182254183612
182255183613
static int fts5Init(sqlite3 *db){
182256183614
static const sqlite3_module fts5Mod = {
182257183615
/* iVersion */ 2,
@@ -182732,43 +184090,56 @@
182732184090
/*
182733184091
** If a row with rowid iDel is present in the %_content table, add the
182734184092
** delete-markers to the FTS index necessary to delete it. Do not actually
182735184093
** remove the %_content row at this time though.
182736184094
*/
182737
-static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
184095
+static int fts5StorageDeleteFromIndex(
184096
+ Fts5Storage *p,
184097
+ i64 iDel,
184098
+ sqlite3_value **apVal
184099
+){
182738184100
Fts5Config *pConfig = p->pConfig;
182739
- sqlite3_stmt *pSeek; /* SELECT to read row iDel from %_data */
184101
+ sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
182740184102
int rc; /* Return code */
184103
+ int rc2; /* sqlite3_reset() return code */
184104
+ int iCol;
184105
+ Fts5InsertCtx ctx;
182741184106
182742
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
182743
- if( rc==SQLITE_OK ){
182744
- int rc2;
184107
+ if( apVal==0 ){
184108
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
184109
+ if( rc!=SQLITE_OK ) return rc;
182745184110
sqlite3_bind_int64(pSeek, 1, iDel);
182746
- if( sqlite3_step(pSeek)==SQLITE_ROW ){
182747
- int iCol;
182748
- Fts5InsertCtx ctx;
182749
- ctx.pStorage = p;
182750
- ctx.iCol = -1;
182751
- rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
182752
- for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
182753
- if( pConfig->abUnindexed[iCol-1] ) continue;
182754
- ctx.szCol = 0;
182755
- rc = sqlite3Fts5Tokenize(pConfig,
182756
- FTS5_TOKENIZE_DOCUMENT,
182757
- (const char*)sqlite3_column_text(pSeek, iCol),
182758
- sqlite3_column_bytes(pSeek, iCol),
182759
- (void*)&ctx,
182760
- fts5StorageInsertCallback
182761
- );
182762
- p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
182763
- }
182764
- p->nTotalRow--;
182765
- }
182766
- rc2 = sqlite3_reset(pSeek);
182767
- if( rc==SQLITE_OK ) rc = rc2;
182768
- }
182769
-
184111
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
184112
+ return sqlite3_reset(pSeek);
184113
+ }
184114
+ }
184115
+
184116
+ ctx.pStorage = p;
184117
+ ctx.iCol = -1;
184118
+ rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
184119
+ for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
184120
+ if( pConfig->abUnindexed[iCol-1]==0 ){
184121
+ const char *zText;
184122
+ int nText;
184123
+ if( pSeek ){
184124
+ zText = (const char*)sqlite3_column_text(pSeek, iCol);
184125
+ nText = sqlite3_column_bytes(pSeek, iCol);
184126
+ }else{
184127
+ zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
184128
+ nText = sqlite3_value_bytes(apVal[iCol-1]);
184129
+ }
184130
+ ctx.szCol = 0;
184131
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
184132
+ zText, nText, (void*)&ctx, fts5StorageInsertCallback
184133
+ );
184134
+ p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
184135
+ }
184136
+ }
184137
+ p->nTotalRow--;
184138
+
184139
+ rc2 = sqlite3_reset(pSeek);
184140
+ if( rc==SQLITE_OK ) rc = rc2;
182770184141
return rc;
182771184142
}
182772184143
182773184144
182774184145
/*
@@ -182844,20 +184215,21 @@
182844184215
}
182845184216
182846184217
/*
182847184218
** Remove a row from the FTS table.
182848184219
*/
182849
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
184220
+static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
182850184221
Fts5Config *pConfig = p->pConfig;
182851184222
int rc;
182852184223
sqlite3_stmt *pDel = 0;
182853184224
184225
+ assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
182854184226
rc = fts5StorageLoadTotals(p, 1);
182855184227
182856184228
/* Delete the index records */
182857184229
if( rc==SQLITE_OK ){
182858
- rc = fts5StorageDeleteFromIndex(p, iDel);
184230
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
182859184231
}
182860184232
182861184233
/* Delete the %_docsize record */
182862184234
if( rc==SQLITE_OK && pConfig->bColumnsize ){
182863184235
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
@@ -182871,65 +184243,10 @@
182871184243
/* Delete the %_content record */
182872184244
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
182873184245
if( rc==SQLITE_OK ){
182874184246
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
182875184247
}
182876
- if( rc==SQLITE_OK ){
182877
- sqlite3_bind_int64(pDel, 1, iDel);
182878
- sqlite3_step(pDel);
182879
- rc = sqlite3_reset(pDel);
182880
- }
182881
- }
182882
-
182883
- /* Write the averages record */
182884
- if( rc==SQLITE_OK ){
182885
- rc = fts5StorageSaveTotals(p);
182886
- }
182887
-
182888
- return rc;
182889
-}
182890
-
182891
-static int sqlite3Fts5StorageSpecialDelete(
182892
- Fts5Storage *p,
182893
- i64 iDel,
182894
- sqlite3_value **apVal
182895
-){
182896
- Fts5Config *pConfig = p->pConfig;
182897
- int rc;
182898
- sqlite3_stmt *pDel = 0;
182899
-
182900
- assert( pConfig->eContent!=FTS5_CONTENT_NORMAL );
182901
- rc = fts5StorageLoadTotals(p, 1);
182902
-
182903
- /* Delete the index records */
182904
- if( rc==SQLITE_OK ){
182905
- int iCol;
182906
- Fts5InsertCtx ctx;
182907
- ctx.pStorage = p;
182908
- ctx.iCol = -1;
182909
-
182910
- rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
182911
- for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
182912
- if( pConfig->abUnindexed[iCol] ) continue;
182913
- ctx.szCol = 0;
182914
- rc = sqlite3Fts5Tokenize(pConfig,
182915
- FTS5_TOKENIZE_DOCUMENT,
182916
- (const char*)sqlite3_value_text(apVal[iCol]),
182917
- sqlite3_value_bytes(apVal[iCol]),
182918
- (void*)&ctx,
182919
- fts5StorageInsertCallback
182920
- );
182921
- p->aTotalSize[iCol] -= (i64)ctx.szCol;
182922
- }
182923
- p->nTotalRow--;
182924
- }
182925
-
182926
- /* Delete the %_docsize record */
182927
- if( pConfig->bColumnsize ){
182928
- if( rc==SQLITE_OK ){
182929
- rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
182930
- }
182931184248
if( rc==SQLITE_OK ){
182932184249
sqlite3_bind_int64(pDel, 1, iDel);
182933184250
sqlite3_step(pDel);
182934184251
rc = sqlite3_reset(pDel);
182935184252
}
@@ -183179,32 +184496,77 @@
183179184496
struct Fts5IntegrityCtx {
183180184497
i64 iRowid;
183181184498
int iCol;
183182184499
int szCol;
183183184500
u64 cksum;
184501
+ Fts5Termset *pTermset;
183184184502
Fts5Config *pConfig;
183185184503
};
184504
+
183186184505
183187184506
/*
183188184507
** Tokenization callback used by integrity check.
183189184508
*/
183190184509
static int fts5StorageIntegrityCallback(
183191
- void *pContext, /* Pointer to Fts5InsertCtx object */
184510
+ void *pContext, /* Pointer to Fts5IntegrityCtx object */
183192184511
int tflags,
183193184512
const char *pToken, /* Buffer containing token */
183194184513
int nToken, /* Size of token in bytes */
183195184514
int iStart, /* Start offset of token */
183196184515
int iEnd /* End offset of token */
183197184516
){
183198184517
Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
184518
+ Fts5Termset *pTermset = pCtx->pTermset;
184519
+ int bPresent;
184520
+ int ii;
184521
+ int rc = SQLITE_OK;
184522
+ int iPos;
184523
+ int iCol;
184524
+
183199184525
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
183200184526
pCtx->szCol++;
183201184527
}
183202
- pCtx->cksum ^= sqlite3Fts5IndexCksum(
183203
- pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken
183204
- );
183205
- return SQLITE_OK;
184528
+
184529
+ switch( pCtx->pConfig->eDetail ){
184530
+ case FTS5_DETAIL_FULL:
184531
+ iPos = pCtx->szCol-1;
184532
+ iCol = pCtx->iCol;
184533
+ break;
184534
+
184535
+ case FTS5_DETAIL_COLUMNS:
184536
+ iPos = pCtx->iCol;
184537
+ iCol = 0;
184538
+ break;
184539
+
184540
+ default:
184541
+ assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE );
184542
+ iPos = 0;
184543
+ iCol = 0;
184544
+ break;
184545
+ }
184546
+
184547
+ rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent);
184548
+ if( rc==SQLITE_OK && bPresent==0 ){
184549
+ pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
184550
+ pCtx->iRowid, iCol, iPos, 0, pToken, nToken
184551
+ );
184552
+ }
184553
+
184554
+ for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){
184555
+ const int nChar = pCtx->pConfig->aPrefix[ii];
184556
+ int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
184557
+ if( nByte ){
184558
+ rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent);
184559
+ if( bPresent==0 ){
184560
+ pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
184561
+ pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte
184562
+ );
184563
+ }
184564
+ }
184565
+ }
184566
+
184567
+ return rc;
183206184568
}
183207184569
183208184570
/*
183209184571
** Check that the contents of the FTS index match that of the %_content
183210184572
** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return
@@ -183235,27 +184597,42 @@
183235184597
int i;
183236184598
ctx.iRowid = sqlite3_column_int64(pScan, 0);
183237184599
ctx.szCol = 0;
183238184600
if( pConfig->bColumnsize ){
183239184601
rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
184602
+ }
184603
+ if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
184604
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
183240184605
}
183241184606
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
183242184607
if( pConfig->abUnindexed[i] ) continue;
183243184608
ctx.iCol = i;
183244184609
ctx.szCol = 0;
183245
- rc = sqlite3Fts5Tokenize(pConfig,
183246
- FTS5_TOKENIZE_DOCUMENT,
183247
- (const char*)sqlite3_column_text(pScan, i+1),
183248
- sqlite3_column_bytes(pScan, i+1),
183249
- (void*)&ctx,
183250
- fts5StorageIntegrityCallback
183251
- );
183252
- if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
184610
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
184611
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
184612
+ }
184613
+ if( rc==SQLITE_OK ){
184614
+ rc = sqlite3Fts5Tokenize(pConfig,
184615
+ FTS5_TOKENIZE_DOCUMENT,
184616
+ (const char*)sqlite3_column_text(pScan, i+1),
184617
+ sqlite3_column_bytes(pScan, i+1),
184618
+ (void*)&ctx,
184619
+ fts5StorageIntegrityCallback
184620
+ );
184621
+ }
184622
+ if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
183253184623
rc = FTS5_CORRUPT;
183254184624
}
183255184625
aTotalSize[i] += ctx.szCol;
184626
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
184627
+ sqlite3Fts5TermsetFree(ctx.pTermset);
184628
+ ctx.pTermset = 0;
184629
+ }
183256184630
}
184631
+ sqlite3Fts5TermsetFree(ctx.pTermset);
184632
+ ctx.pTermset = 0;
184633
+
183257184634
if( rc!=SQLITE_OK ) break;
183258184635
}
183259184636
rc2 = sqlite3_reset(pScan);
183260184637
if( rc==SQLITE_OK ) rc = rc2;
183261184638
}
@@ -185777,11 +187154,11 @@
185777187154
185778187155
pCsr->rowid++;
185779187156
185780187157
if( pTab->eType==FTS5_VOCAB_COL ){
185781187158
for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
185782
- if( pCsr->aCnt[pCsr->iCol] ) break;
187159
+ if( pCsr->aDoc[pCsr->iCol] ) break;
185783187160
}
185784187161
}
185785187162
185786187163
if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
185787187164
if( sqlite3Fts5IterEof(pCsr->pIter) ){
@@ -185810,28 +187187,64 @@
185810187187
i64 dummy;
185811187188
const u8 *pPos; int nPos; /* Position list */
185812187189
i64 iPos = 0; /* 64-bit position read from poslist */
185813187190
int iOff = 0; /* Current offset within position list */
185814187191
185815
- rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
185816
- if( rc==SQLITE_OK ){
185817
- if( pTab->eType==FTS5_VOCAB_ROW ){
185818
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
185819
- pCsr->aCnt[0]++;
185820
- }
185821
- pCsr->aDoc[0]++;
185822
- }else{
185823
- int iCol = -1;
185824
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
185825
- int ii = FTS5_POS2COLUMN(iPos);
185826
- pCsr->aCnt[ii]++;
185827
- if( iCol!=ii ){
185828
- pCsr->aDoc[ii]++;
185829
- iCol = ii;
185830
- }
185831
- }
185832
- }
187192
+ switch( pCsr->pConfig->eDetail ){
187193
+ case FTS5_DETAIL_FULL:
187194
+ rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
187195
+ if( rc==SQLITE_OK ){
187196
+ if( pTab->eType==FTS5_VOCAB_ROW ){
187197
+ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
187198
+ pCsr->aCnt[0]++;
187199
+ }
187200
+ pCsr->aDoc[0]++;
187201
+ }else{
187202
+ int iCol = -1;
187203
+ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
187204
+ int ii = FTS5_POS2COLUMN(iPos);
187205
+ pCsr->aCnt[ii]++;
187206
+ if( iCol!=ii ){
187207
+ if( ii>=nCol ){
187208
+ rc = FTS5_CORRUPT;
187209
+ break;
187210
+ }
187211
+ pCsr->aDoc[ii]++;
187212
+ iCol = ii;
187213
+ }
187214
+ }
187215
+ }
187216
+ }
187217
+ break;
187218
+
187219
+ case FTS5_DETAIL_COLUMNS:
187220
+ if( pTab->eType==FTS5_VOCAB_ROW ){
187221
+ pCsr->aDoc[0]++;
187222
+ }else{
187223
+ Fts5Buffer buf = {0, 0, 0};
187224
+ rc = sqlite3Fts5IterPoslistBuffer(pCsr->pIter, &buf);
187225
+ if( rc==SQLITE_OK ){
187226
+ while( 0==sqlite3Fts5PoslistNext64(buf.p, buf.n, &iOff,&iPos) ){
187227
+ assert_nc( iPos>=0 && iPos<nCol );
187228
+ if( iPos>=nCol ){
187229
+ rc = FTS5_CORRUPT;
187230
+ break;
187231
+ }
187232
+ pCsr->aDoc[iPos]++;
187233
+ }
187234
+ }
187235
+ sqlite3Fts5BufferFree(&buf);
187236
+ }
187237
+ break;
187238
+
187239
+ default:
187240
+ assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
187241
+ pCsr->aDoc[0]++;
187242
+ break;
187243
+ }
187244
+
187245
+ if( rc==SQLITE_OK ){
185833187246
rc = sqlite3Fts5IterNextScan(pCsr->pIter);
185834187247
}
185835187248
185836187249
if( rc==SQLITE_OK ){
185837187250
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
@@ -185842,12 +187255,12 @@
185842187255
}
185843187256
}
185844187257
}
185845187258
}
185846187259
185847
- if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
185848
- while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
187260
+ if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
187261
+ while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
185849187262
assert( pCsr->iCol<pCsr->pConfig->nCol );
185850187263
}
185851187264
return rc;
185852187265
}
185853187266
@@ -185923,34 +187336,40 @@
185923187336
sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
185924187337
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
185925187338
int iCol /* Index of column to read value from */
185926187339
){
185927187340
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
187341
+ int eDetail = pCsr->pConfig->eDetail;
187342
+ int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
187343
+ i64 iVal = 0;
185928187344
185929187345
if( iCol==0 ){
185930187346
sqlite3_result_text(
185931187347
pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
185932187348
);
185933
- }
185934
- else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){
187349
+ }else if( eType==FTS5_VOCAB_COL ){
185935187350
assert( iCol==1 || iCol==2 || iCol==3 );
185936187351
if( iCol==1 ){
185937
- const char *z = pCsr->pConfig->azCol[pCsr->iCol];
185938
- sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
187352
+ if( eDetail!=FTS5_DETAIL_NONE ){
187353
+ const char *z = pCsr->pConfig->azCol[pCsr->iCol];
187354
+ sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
187355
+ }
185939187356
}else if( iCol==2 ){
185940
- sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]);
187357
+ iVal = pCsr->aDoc[pCsr->iCol];
185941187358
}else{
185942
- sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]);
187359
+ iVal = pCsr->aCnt[pCsr->iCol];
185943187360
}
185944187361
}else{
185945187362
assert( iCol==1 || iCol==2 );
185946187363
if( iCol==1 ){
185947
- sqlite3_result_int64(pCtx, pCsr->aDoc[0]);
187364
+ iVal = pCsr->aDoc[0];
185948187365
}else{
185949
- sqlite3_result_int64(pCtx, pCsr->aCnt[0]);
187366
+ iVal = pCsr->aCnt[0];
185950187367
}
185951187368
}
187369
+
187370
+ if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
185952187371
return SQLITE_OK;
185953187372
}
185954187373
185955187374
/*
185956187375
** This is the xRowid method. The SQLite core calls this routine to
185957187376
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.10.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.
@@ -119,10 +119,12 @@
119 #define SQLITE_ENABLE_LOCKING_STYLE 0
120 #define HAVE_UTIME 1
121 #else
122 /* This is not VxWorks. */
123 #define OS_VXWORKS 0
 
 
124 #endif /* defined(_WRS_KERNEL) */
125
126 /************** End of vxworks.h *********************************************/
127 /************** Continuing where we left off in sqliteInt.h ******************/
128
@@ -323,13 +325,13 @@
323 **
324 ** See also: [sqlite3_libversion()],
325 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
326 ** [sqlite_version()] and [sqlite_source_id()].
327 */
328 #define SQLITE_VERSION "3.10.0"
329 #define SQLITE_VERSION_NUMBER 3010000
330 #define SQLITE_SOURCE_ID "2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566"
331
332 /*
333 ** CAPI3REF: Run-Time Library Version Numbers
334 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
335 **
@@ -1006,12 +1008,17 @@
1006 ** improve performance on some systems.
1007 **
1008 ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
1009 ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
1010 ** to the [sqlite3_file] object associated with a particular database
1011 ** connection. See the [sqlite3_file_control()] documentation for
1012 ** additional information.
 
 
 
 
 
1013 **
1014 ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
1015 ** No longer in use.
1016 **
1017 ** <li>[[SQLITE_FCNTL_SYNC]]
@@ -1222,10 +1229,11 @@
1222 #define SQLITE_FCNTL_WIN32_SET_HANDLE 23
1223 #define SQLITE_FCNTL_WAL_BLOCK 24
1224 #define SQLITE_FCNTL_ZIPVFS 25
1225 #define SQLITE_FCNTL_RBU 26
1226 #define SQLITE_FCNTL_VFS_POINTER 27
 
1227
1228 /* deprecated names */
1229 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1230 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1231 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -8399,10 +8407,13 @@
8399 ** If parameter iCol is greater than or equal to the number of columns
8400 ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
8401 ** an OOM condition or IO error), an appropriate SQLite error code is
8402 ** returned.
8403 **
 
 
 
8404 ** xColumnText:
8405 ** This function attempts to retrieve the text of column iCol of the
8406 ** current document. If successful, (*pz) is set to point to a buffer
8407 ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
8408 ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -8419,18 +8430,32 @@
8419 ** xInstCount:
8420 ** Set *pnInst to the total number of occurrences of all phrases within
8421 ** the query within the current row. Return SQLITE_OK if successful, or
8422 ** an error code (i.e. SQLITE_NOMEM) if an error occurs.
8423 **
 
 
 
 
 
8424 ** xInst:
8425 ** Query for the details of phrase match iIdx within the current row.
8426 ** Phrase matches are numbered starting from zero, so the iIdx argument
8427 ** should be greater than or equal to zero and smaller than the value
8428 ** output by xInstCount().
 
 
 
 
 
 
8429 **
8430 ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
8431 ** if an error occurs.
 
 
 
8432 **
8433 ** xRowid:
8434 ** Returns the rowid of the current row.
8435 **
8436 ** xTokenize:
@@ -8511,25 +8536,63 @@
8511 ** through instances of phrase iPhrase, use the following code:
8512 **
8513 ** Fts5PhraseIter iter;
8514 ** int iCol, iOff;
8515 ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
8516 ** iOff>=0;
8517 ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
8518 ** ){
8519 ** // An instance of phrase iPhrase at offset iOff of column iCol
8520 ** }
8521 **
8522 ** The Fts5PhraseIter structure is defined above. Applications should not
8523 ** modify this structure directly - it should only be used as shown above
8524 ** with the xPhraseFirst() and xPhraseNext() API methods.
 
 
 
 
 
 
 
8525 **
8526 ** xPhraseNext()
8527 ** See xPhraseFirst above.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8528 */
8529 struct Fts5ExtensionApi {
8530 int iVersion; /* Currently always set to 1 */
8531
8532 void *(*xUserData)(Fts5Context*);
8533
8534 int (*xColumnCount)(Fts5Context*);
8535 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -8555,12 +8618,15 @@
8555 int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
8556 );
8557 int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
8558 void *(*xGetAuxdata)(Fts5Context*, int bClear);
8559
8560 void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
8561 void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
 
 
 
8562 };
8563
8564 /*
8565 ** CUSTOM AUXILIARY FUNCTIONS
8566 *************************************************************************/
@@ -9340,10 +9406,25 @@
9340 #else
9341 # define ALWAYS(X) (X)
9342 # define NEVER(X) (X)
9343 #endif
9344
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9345 /*
9346 ** Declarations used for tracing the operating system interfaces.
9347 */
9348 #if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \
9349 (defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
@@ -9976,14 +10057,10 @@
9976 /*
9977 ** Default maximum size of memory used by memory-mapped I/O in the VFS
9978 */
9979 #ifdef __APPLE__
9980 # include <TargetConditionals.h>
9981 # if TARGET_OS_IPHONE
9982 # undef SQLITE_MAX_MMAP_SIZE
9983 # define SQLITE_MAX_MMAP_SIZE 0
9984 # endif
9985 #endif
9986 #ifndef SQLITE_MAX_MMAP_SIZE
9987 # if defined(__linux__) \
9988 || defined(_WIN32) \
9989 || (defined(__APPLE__) && defined(__MACH__)) \
@@ -10479,19 +10556,21 @@
10479 ** Enter and Leave procedures no-ops.
10480 */
10481 #ifndef SQLITE_OMIT_SHARED_CACHE
10482 SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*);
10483 SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*);
 
 
10484 #else
10485 # define sqlite3BtreeEnter(X)
10486 # define sqlite3BtreeEnterAll(X)
 
 
10487 #endif
10488
10489 #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
10490 SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
10491 SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*);
10492 SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
10493 SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*);
10494 SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*);
10495 #ifndef NDEBUG
10496 /* These routines are used inside assert() statements only. */
10497 SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*);
@@ -10498,13 +10577,11 @@
10498 SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*);
10499 SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
10500 #endif
10501 #else
10502
10503 # define sqlite3BtreeSharable(X) 0
10504 # define sqlite3BtreeLeave(X)
10505 # define sqlite3BtreeEnterCursor(X)
10506 # define sqlite3BtreeLeaveCursor(X)
10507 # define sqlite3BtreeLeaveAll(X)
10508
10509 # define sqlite3BtreeHoldsMutex(X) 1
10510 # define sqlite3BtreeHoldsAllMutexes(X) 1
@@ -10899,19 +10976,24 @@
10899 SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
10900 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
10901 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
10902 SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
10903 SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
10904 SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
 
 
 
 
 
10905 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
10906 SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
10907 SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
10908 SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
10909 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
10910 SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
10911 SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
10912 SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
10913 SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
10914 SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
10915 SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
10916 SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
10917 SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
@@ -11215,10 +11297,11 @@
11215 #endif
11216 SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
11217 SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
11218 SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
11219 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
 
11220 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
11221 SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
11222 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
11223 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
11224 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
@@ -11309,10 +11392,12 @@
11309 #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before
11310 ** writing this page to the database */
11311 #define PGHDR_NEED_READ 0x010 /* Content is unread */
11312 #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
11313 #define PGHDR_MMAP 0x040 /* This is an mmap page object */
 
 
11314
11315 /* Initialize and shutdown the page cache subsystem */
11316 SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
11317 SQLITE_PRIVATE void sqlite3PcacheShutdown(void);
11318
@@ -12162,13 +12247,12 @@
12162 struct FuncDef {
12163 i16 nArg; /* Number of arguments. -1 means unlimited */
12164 u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
12165 void *pUserData; /* User data parameter */
12166 FuncDef *pNext; /* Next function with same name */
12167 void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
12168 void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
12169 void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */
12170 char *zName; /* SQL name of the function. */
12171 FuncDef *pHash; /* Next with a different name but the same hash */
12172 FuncDestructor *pDestructor; /* Reference counted destructor function */
12173 };
12174
@@ -12247,32 +12331,32 @@
12247 ** FuncDef.flags variable is set to the value passed as the flags
12248 ** parameter.
12249 */
12250 #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
12251 {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12252 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12253 #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
12254 {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12255 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12256 #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
12257 {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12258 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12259 #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
12260 {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
12261 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
12262 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
12263 {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12264 pArg, 0, xFunc, 0, 0, #zName, 0, 0}
12265 #define LIKEFUNC(zName, nArg, arg, flags) \
12266 {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
12267 (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
12268 #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
12269 {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
12270 SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
12271 #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
12272 {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
12273 SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
12274
12275 /*
12276 ** All current savepoints are stored in a linked list starting at
12277 ** sqlite3.pSavepoint. The first element in the list is the most recently
12278 ** opened savepoint. Savepoints are added to the list by the vdbe
@@ -13579,11 +13663,11 @@
13579 ** each recursion. The boundary between these two regions is determined
13580 ** using offsetof(Parse,nVar) so the nVar field must be the first field
13581 ** in the recursive region.
13582 ************************************************************************/
13583
13584 int nVar; /* Number of '?' variables seen in the SQL so far */
13585 int nzVar; /* Number of available slots in azVar[] */
13586 u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
13587 u8 explain; /* True if the EXPLAIN flag is found on the query */
13588 #ifndef SQLITE_OMIT_VIRTUALTABLE
13589 u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
@@ -13861,14 +13945,14 @@
13861
13862 /*
13863 ** Context pointer passed down through the tree-walk.
13864 */
13865 struct Walker {
 
13866 int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */
13867 int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
13868 void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
13869 Parse *pParse; /* Parser context. */
13870 int walkerDepth; /* Number of subqueries */
13871 u8 eCode; /* A small processing code */
13872 union { /* Extra data for callback */
13873 NameContext *pNC; /* Naming context */
13874 int n; /* A counter */
@@ -14135,11 +14219,10 @@
14135 SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
14136 SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
14137 SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
14138 SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
14139 SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
14140 SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int);
14141 SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
14142 SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
14143 SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
14144 SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
14145 SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
@@ -16066,15 +16149,19 @@
16066 SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
16067 SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
16068 SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
16069 SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
16070
16071 #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
16072 SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
16073 SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
16074 #else
16075 # define sqlite3VdbeEnter(X)
 
 
 
 
 
16076 # define sqlite3VdbeLeave(X)
16077 #endif
16078
16079 #ifdef SQLITE_DEBUG
16080 SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
@@ -16508,52 +16595,68 @@
16508 char tzSet; /* Timezone was set explicitly */
16509 };
16510
16511
16512 /*
16513 ** Convert zDate into one or more integers. Additional arguments
16514 ** come in groups of 5 as follows:
16515 **
16516 ** N number of digits in the integer
16517 ** min minimum allowed value of the integer
16518 ** max maximum allowed value of the integer
16519 ** nextC first character after the integer
16520 ** pVal where to write the integers value.
16521 **
16522 ** Conversions continue until one with nextC==0 is encountered.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16523 ** The function returns the number of successful conversions.
16524 */
16525 static int getDigits(const char *zDate, ...){
 
 
 
16526 va_list ap;
16527 int val;
16528 int N;
16529 int min;
16530 int max;
16531 int nextC;
16532 int *pVal;
16533 int cnt = 0;
16534 va_start(ap, zDate);
 
16535 do{
16536 N = va_arg(ap, int);
16537 min = va_arg(ap, int);
16538 max = va_arg(ap, int);
16539 nextC = va_arg(ap, int);
16540 pVal = va_arg(ap, int*);
 
 
 
16541 val = 0;
16542 while( N-- ){
16543 if( !sqlite3Isdigit(*zDate) ){
16544 goto end_getDigits;
16545 }
16546 val = val*10 + *zDate - '0';
16547 zDate++;
16548 }
16549 if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
16550 goto end_getDigits;
16551 }
16552 *pVal = val;
16553 zDate++;
16554 cnt++;
 
16555 }while( nextC );
16556 end_getDigits:
16557 va_end(ap);
16558 return cnt;
16559 }
@@ -16590,11 +16693,11 @@
16590 goto zulu_time;
16591 }else{
16592 return c!=0;
16593 }
16594 zDate++;
16595 if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
16596 return 1;
16597 }
16598 zDate += 5;
16599 p->tz = sgn*(nMn + nHr*60);
16600 zulu_time:
@@ -16611,17 +16714,17 @@
16611 ** Return 1 if there is a parsing error and 0 on success.
16612 */
16613 static int parseHhMmSs(const char *zDate, DateTime *p){
16614 int h, m, s;
16615 double ms = 0.0;
16616 if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
16617 return 1;
16618 }
16619 zDate += 5;
16620 if( *zDate==':' ){
16621 zDate++;
16622 if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
16623 return 1;
16624 }
16625 zDate += 2;
16626 if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){
16627 double rScale = 1.0;
@@ -16705,11 +16808,11 @@
16705 zDate++;
16706 neg = 1;
16707 }else{
16708 neg = 0;
16709 }
16710 if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
16711 return 1;
16712 }
16713 zDate += 10;
16714 while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; }
16715 if( parseHhMmSs(zDate, p)==0 ){
@@ -19758,10 +19861,11 @@
19758 /*
19759 ** Mutex to control access to the memory allocation subsystem.
19760 */
19761 sqlite3_mutex *mutex;
19762
 
19763 /*
19764 ** Performance statistics
19765 */
19766 u64 nAlloc; /* Total number of calls to malloc */
19767 u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
@@ -19769,10 +19873,11 @@
19769 u32 currentOut; /* Current checkout, including internal fragmentation */
19770 u32 currentCount; /* Current number of distinct checkouts */
19771 u32 maxOut; /* Maximum instantaneous currentOut */
19772 u32 maxCount; /* Maximum instantaneous currentCount */
19773 u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
 
19774
19775 /*
19776 ** Lists of free blocks. aiFreelist[0] is a list of free blocks of
19777 ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
19778 ** aiFreelist[2] holds free blocks of size szAtom*4. And so forth.
@@ -19880,18 +19985,21 @@
19880 int iLogsize; /* Log2 of iFullSz/POW2_MIN */
19881
19882 /* nByte must be a positive */
19883 assert( nByte>0 );
19884
 
 
 
 
19885 /* Keep track of the maximum allocation request. Even unfulfilled
19886 ** requests are counted */
19887 if( (u32)nByte>mem5.maxRequest ){
19888 /* Abort if the requested allocation size is larger than the largest
19889 ** power of two that we can represent using 32-bit signed integers. */
19890 if( nByte > 0x40000000 ) return 0;
19891 mem5.maxRequest = nByte;
19892 }
 
 
19893
19894 /* Round nByte up to the next valid power of two */
19895 for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){}
19896
19897 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
@@ -19914,18 +20022,20 @@
19914 mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
19915 memsys5Link(i+newSize, iBin);
19916 }
19917 mem5.aCtrl[i] = iLogsize;
19918
 
19919 /* Update allocator performance statistics. */
19920 mem5.nAlloc++;
19921 mem5.totalAlloc += iFullSz;
19922 mem5.totalExcess += iFullSz - nByte;
19923 mem5.currentCount++;
19924 mem5.currentOut += iFullSz;
19925 if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
19926 if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
 
19927
19928 #ifdef SQLITE_DEBUG
19929 /* Make sure the allocated memory does not assume that it is set to zero
19930 ** or retains a value from a previous allocation */
19931 memset(&mem5.zPool[i*mem5.szAtom], 0xAA, iFullSz);
@@ -19956,16 +20066,19 @@
19956 size = 1<<iLogsize;
19957 assert( iBlock+size-1<(u32)mem5.nBlock );
19958
19959 mem5.aCtrl[iBlock] |= CTRL_FREE;
19960 mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
 
 
19961 assert( mem5.currentCount>0 );
19962 assert( mem5.currentOut>=(size*mem5.szAtom) );
19963 mem5.currentCount--;
19964 mem5.currentOut -= size*mem5.szAtom;
19965 assert( mem5.currentOut>0 || mem5.currentCount==0 );
19966 assert( mem5.currentCount>0 || mem5.currentOut==0 );
 
19967
19968 mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
19969 while( ALWAYS(iLogsize<LOGMAX) ){
19970 int iBuddy;
19971 if( (iBlock>>iLogsize) & 1 ){
@@ -22281,12 +22394,13 @@
22281 }
22282 return p;
22283 }
22284
22285 /*
22286 ** Allocate and zero memory. If the allocation fails, make
22287 ** the mallocFailed flag in the connection pointer.
 
22288 **
22289 ** If db!=0 and db->mallocFailed is true (indicating a prior malloc
22290 ** failure on the same database connection) then always return 0.
22291 ** Hence for a particular database connection, once malloc starts
22292 ** failing, it fails consistently until mallocFailed is reset.
@@ -22298,12 +22412,12 @@
22298 ** if( b ) a[10] = 9;
22299 **
22300 ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
22301 ** that all prior mallocs (ex: "a") worked too.
22302 */
 
22303 SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
22304 void *p;
22305 assert( db==0 || sqlite3_mutex_held(db->mutex) );
22306 assert( db==0 || db->pnBytesFreed==0 );
22307 #ifndef SQLITE_OMIT_LOOKASIDE
22308 if( db ){
22309 LookasideSlot *pBuf;
@@ -22329,11 +22443,14 @@
22329 #else
22330 if( db && db->mallocFailed ){
22331 return 0;
22332 }
22333 #endif
22334 p = sqlite3Malloc(n);
 
 
 
22335 if( !p && db ){
22336 db->mallocFailed = 1;
22337 }
22338 sqlite3MemdebugSetType(p,
22339 (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
@@ -27479,37 +27596,55 @@
27479 #define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
27480
27481 { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
27482 #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
27483
 
27484 { "fchown", (sqlite3_syscall_ptr)fchown, 0 },
 
 
 
27485 #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
27486
27487 { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 },
27488 #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
27489
27490 #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
27491 { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
 
 
 
27492 #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
27493
 
27494 { "munmap", (sqlite3_syscall_ptr)munmap, 0 },
 
 
 
27495 #define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
27496
27497 #if HAVE_MREMAP
27498 { "mremap", (sqlite3_syscall_ptr)mremap, 0 },
27499 #else
27500 { "mremap", (sqlite3_syscall_ptr)0, 0 },
27501 #endif
27502 #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
27503
 
27504 { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
 
 
 
27505 #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
27506
 
27507 { "readlink", (sqlite3_syscall_ptr)readlink, 0 },
 
 
 
27508 #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
27509
27510 #endif
27511
27512 }; /* End of the overrideable system calls */
27513
27514
27515 /*
@@ -27516,14 +27651,14 @@
27516 ** On some systems, calls to fchown() will trigger a message in a security
27517 ** log if they come from non-root processes. So avoid calling fchown() if
27518 ** we are not running as root.
27519 */
27520 static int robustFchown(int fd, uid_t uid, gid_t gid){
27521 #if OS_VXWORKS
27522 return 0;
27523 #else
27524 return osGeteuid() ? 0 : osFchown(fd,uid,gid);
 
 
27525 #endif
27526 }
27527
27528 /*
27529 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -32986,10 +33121,11 @@
32986 SimulateIOError( return SQLITE_ERROR );
32987
32988 assert( pVfs->mxPathname==MAX_PATHNAME );
32989 UNUSED_PARAMETER(pVfs);
32990
 
32991 /* Attempt to resolve the path as if it were a symbolic link. If it is
32992 ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if
32993 ** the identified file is not a symbolic link or does not exist, then
32994 ** zPath is copied directly into zOut. Either way, nByte is left set to
32995 ** the size of the string copied into zOut[] in bytes. */
@@ -33001,10 +33137,11 @@
33001 sqlite3_snprintf(nOut, zOut, "%s", zPath);
33002 nByte = sqlite3Strlen30(zOut);
33003 }else{
33004 zOut[nByte] = '\0';
33005 }
 
33006
33007 /* If buffer zOut[] now contains an absolute path there is nothing more
33008 ** to do. If it contains a relative path, do the following:
33009 **
33010 ** * move the relative path string so that it is at the end of th
@@ -43327,10 +43464,11 @@
43327 # define sqlite3WalCallback(z) 0
43328 # define sqlite3WalExclusiveMode(y,z) 0
43329 # define sqlite3WalHeapMemory(z) 0
43330 # define sqlite3WalFramesize(z) 0
43331 # define sqlite3WalFindFrame(x,y,z) 0
 
43332 #else
43333
43334 #define WAL_SAVEPOINT_NDATA 4
43335
43336 /* Connection to a write-ahead log (WAL) file.
@@ -43421,10 +43559,13 @@
43421 ** stored in each frame (i.e. the db page-size when the WAL was created).
43422 */
43423 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
43424 #endif
43425
 
 
 
43426 #endif /* ifndef SQLITE_OMIT_WAL */
43427 #endif /* _WAL_H_ */
43428
43429 /************** End of wal.h *************************************************/
43430 /************** Continuing where we left off in pager.c **********************/
@@ -49032,11 +49173,11 @@
49032 if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
49033 rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
49034 if( rc!=SQLITE_OK ){
49035 return rc;
49036 }
49037 sqlite3WalExclusiveMode(pPager->pWal, 1);
49038 }
49039
49040 /* Grab the write lock on the log file. If successful, upgrade to
49041 ** PAGER_RESERVED state. Otherwise, return an error code to the caller.
49042 ** The busy-handler is not invoked if another connection already
@@ -50096,10 +50237,22 @@
50096 ** not yet been opened.
50097 */
50098 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
50099 return pPager->fd;
50100 }
 
 
 
 
 
 
 
 
 
 
 
 
50101
50102 /*
50103 ** Return the full pathname of the journal file.
50104 */
50105 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
@@ -51202,10 +51355,11 @@
51202 u8 truncateOnCommit; /* True to truncate WAL file on commit */
51203 u8 syncHeader; /* Fsync the WAL header if true */
51204 u8 padToSectorBoundary; /* Pad transactions out to the next sector */
51205 WalIndexHdr hdr; /* Wal-index header for current transaction */
51206 u32 minFrame; /* Ignore wal frames before this one */
 
51207 const char *zWalName; /* Name of WAL file */
51208 u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
51209 #ifdef SQLITE_DEBUG
51210 u8 lockError; /* True if a locking error has occurred */
51211 #endif
@@ -51455,18 +51609,22 @@
51455 int nativeCksum; /* True for native byte-order checksums */
51456 u32 *aCksum = pWal->hdr.aFrameCksum;
51457 assert( WAL_FRAME_HDRSIZE==24 );
51458 sqlite3Put4byte(&aFrame[0], iPage);
51459 sqlite3Put4byte(&aFrame[4], nTruncate);
51460 memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
51461
51462 nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
51463 walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
51464 walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
51465
51466 sqlite3Put4byte(&aFrame[16], aCksum[0]);
51467 sqlite3Put4byte(&aFrame[20], aCksum[1]);
 
 
 
 
51468 }
51469
51470 /*
51471 ** Check to see if the frame with header in aFrame[] and content
51472 ** in aData[] is valid. If it is a valid frame, fill *piPage and
@@ -53389,10 +53547,11 @@
53389 int rc;
53390
53391 /* Cannot start a write transaction without first holding a read
53392 ** transaction. */
53393 assert( pWal->readLock>=0 );
 
53394
53395 if( pWal->readOnly ){
53396 return SQLITE_READONLY;
53397 }
53398
@@ -53424,10 +53583,11 @@
53424 */
53425 SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
53426 if( pWal->writeLock ){
53427 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
53428 pWal->writeLock = 0;
 
53429 pWal->truncateOnCommit = 0;
53430 }
53431 return SQLITE_OK;
53432 }
53433
@@ -53641,10 +53801,63 @@
53641 if( rc ) return rc;
53642 /* Write the page data */
53643 rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
53644 return rc;
53645 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53646
53647 /*
53648 ** Write a set of frames to the log. The caller must hold the write-lock
53649 ** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
53650 */
@@ -53662,10 +53875,12 @@
53662 PgHdr *pLast = 0; /* Last frame in list */
53663 int nExtra = 0; /* Number of extra copies of last page */
53664 int szFrame; /* The size of a single frame */
53665 i64 iOffset; /* Next byte to write in WAL file */
53666 WalWriter w; /* The writer */
 
 
53667
53668 assert( pList );
53669 assert( pWal->writeLock );
53670
53671 /* If this frame set completes a transaction, then nTruncate>0. If
@@ -53676,10 +53891,15 @@
53676 { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
53677 WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
53678 pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
53679 }
53680 #endif
 
 
 
 
 
53681
53682 /* See if it is possible to write these frames into the start of the
53683 ** log file, instead of appending to it at pWal->hdr.mxFrame.
53684 */
53685 if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
@@ -53741,17 +53961,45 @@
53741 szFrame = szPage + WAL_FRAME_HDRSIZE;
53742
53743 /* Write all frames into the log file exactly once */
53744 for(p=pList; p; p=p->pDirty){
53745 int nDbSize; /* 0 normally. Positive == commit flag */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53746 iFrame++;
53747 assert( iOffset==walFrameOffset(iFrame, szPage) );
53748 nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
53749 rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
53750 if( rc ) return rc;
53751 pLast = p;
53752 iOffset += szFrame;
 
 
 
 
 
 
 
53753 }
53754
53755 /* If this is the end of a transaction, then we might need to pad
53756 ** the transaction and/or sync the WAL file.
53757 **
@@ -53799,10 +54047,11 @@
53799 ** guarantees that there are no other writers, and no data that may
53800 ** be in use by existing readers is being overwritten.
53801 */
53802 iFrame = pWal->hdr.mxFrame;
53803 for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
 
53804 iFrame++;
53805 rc = walIndexAppend(pWal, iFrame, p->pgno);
53806 }
53807 while( rc==SQLITE_OK && nExtra>0 ){
53808 iFrame++;
@@ -53911,10 +54160,11 @@
53911 }
53912 }
53913
53914 /* Copy data from the log to the database file. */
53915 if( rc==SQLITE_OK ){
 
53916 if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
53917 rc = SQLITE_CORRUPT_BKPT;
53918 }else{
53919 rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
53920 }
@@ -54066,10 +54316,16 @@
54066 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
54067 assert( pWal==0 || pWal->readLock>=0 );
54068 return (pWal ? pWal->szPage : 0);
54069 }
54070 #endif
 
 
 
 
 
 
54071
54072 #endif /* #ifndef SQLITE_OMIT_WAL */
54073
54074 /************** End of wal.c *************************************************/
54075 /************** Begin file btmutex.c *****************************************/
@@ -54368,11 +54624,10 @@
54368 struct MemPage {
54369 u8 isInit; /* True if previously initialized. MUST BE FIRST! */
54370 u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
54371 u8 intKey; /* True if table b-trees. False for index b-trees */
54372 u8 intKeyLeaf; /* True if the leaf of an intKey table */
54373 u8 noPayload; /* True if internal intKey page (thus w/o data) */
54374 u8 leaf; /* True if a leaf page */
54375 u8 hdrOffset; /* 100 for page 1. 0 otherwise */
54376 u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
54377 u8 max1bytePayload; /* min(maxLocal,127) */
54378 u8 bBusy; /* Prevent endless loops on corrupt database files */
@@ -54955,25 +55210,10 @@
54955
54956 return (p->sharable==0 || p->locked);
54957 }
54958 #endif
54959
54960
54961 #ifndef SQLITE_OMIT_INCRBLOB
54962 /*
54963 ** Enter and leave a mutex on a Btree given a cursor owned by that
54964 ** Btree. These entry points are used by incremental I/O and can be
54965 ** omitted if that module is not used.
54966 */
54967 SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
54968 sqlite3BtreeEnter(pCur->pBtree);
54969 }
54970 SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
54971 sqlite3BtreeLeave(pCur->pBtree);
54972 }
54973 #endif /* SQLITE_OMIT_INCRBLOB */
54974
54975
54976 /*
54977 ** Enter the mutex on every Btree associated with a database
54978 ** connection. This is needed (for example) prior to parsing
54979 ** a statement since we will be comparing table and column names
@@ -55004,18 +55244,10 @@
55004 p = db->aDb[i].pBt;
55005 if( p ) sqlite3BtreeLeave(p);
55006 }
55007 }
55008
55009 /*
55010 ** Return true if a particular Btree requires a lock. Return FALSE if
55011 ** no lock is ever required since it is not sharable.
55012 */
55013 SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
55014 return p->sharable;
55015 }
55016
55017 #ifndef NDEBUG
55018 /*
55019 ** Return true if the current thread holds the database connection
55020 ** mutex and all required BtShared mutexes.
55021 **
@@ -55085,10 +55317,29 @@
55085 p->pBt->db = p->db;
55086 }
55087 }
55088 }
55089 #endif /* if SQLITE_THREADSAFE */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55090 #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
55091
55092 /************** End of btmutex.c *********************************************/
55093 /************** Begin file btree.c *******************************************/
55094 /*
@@ -55541,10 +55792,14 @@
55541 */
55542 #ifdef SQLITE_DEBUG
55543 static int cursorHoldsMutex(BtCursor *p){
55544 return sqlite3_mutex_held(p->pBt->mutex);
55545 }
 
 
 
 
55546 #endif
55547
55548 /*
55549 ** Invalidate the overflow cache of the cursor passed as the first argument.
55550 ** on the shared btree structure pBt.
@@ -55877,11 +56132,11 @@
55877 ** saveCursorPosition().
55878 */
55879 static int btreeRestoreCursorPosition(BtCursor *pCur){
55880 int rc;
55881 int skipNext;
55882 assert( cursorHoldsMutex(pCur) );
55883 assert( pCur->eState>=CURSOR_REQUIRESEEK );
55884 if( pCur->eState==CURSOR_FAULT ){
55885 return pCur->skipNext;
55886 }
55887 pCur->eState = CURSOR_INVALID;
@@ -56166,11 +56421,10 @@
56166 u8 *pCell, /* Pointer to the cell text. */
56167 CellInfo *pInfo /* Fill in this structure */
56168 ){
56169 assert( sqlite3_mutex_held(pPage->pBt->mutex) );
56170 assert( pPage->leaf==0 );
56171 assert( pPage->noPayload );
56172 assert( pPage->childPtrSize==4 );
56173 #ifndef SQLITE_DEBUG
56174 UNUSED_PARAMETER(pPage);
56175 #endif
56176 pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
@@ -56188,12 +56442,10 @@
56188 u32 nPayload; /* Number of bytes of cell payload */
56189 u64 iKey; /* Extracted Key value */
56190
56191 assert( sqlite3_mutex_held(pPage->pBt->mutex) );
56192 assert( pPage->leaf==0 || pPage->leaf==1 );
56193 assert( pPage->intKeyLeaf || pPage->noPayload );
56194 assert( pPage->noPayload==0 );
56195 assert( pPage->intKeyLeaf );
56196 assert( pPage->childPtrSize==0 );
56197 pIter = pCell;
56198
56199 /* The next block of code is equivalent to:
@@ -56258,11 +56510,10 @@
56258 u32 nPayload; /* Number of bytes of cell payload */
56259
56260 assert( sqlite3_mutex_held(pPage->pBt->mutex) );
56261 assert( pPage->leaf==0 || pPage->leaf==1 );
56262 assert( pPage->intKeyLeaf==0 );
56263 assert( pPage->noPayload==0 );
56264 pIter = pCell + pPage->childPtrSize;
56265 nPayload = *pIter;
56266 if( nPayload>=0x80 ){
56267 u8 *pEnd = &pIter[8];
56268 nPayload &= 0x7f;
@@ -56319,11 +56570,10 @@
56319 ** this function verifies that this invariant is not violated. */
56320 CellInfo debuginfo;
56321 pPage->xParseCell(pPage, pCell, &debuginfo);
56322 #endif
56323
56324 assert( pPage->noPayload==0 );
56325 nSize = *pIter;
56326 if( nSize>=0x80 ){
56327 pEnd = &pIter[8];
56328 nSize &= 0x7f;
56329 do{
@@ -56777,15 +57027,13 @@
56777 ** table b-tree page. */
56778 assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
56779 pPage->intKey = 1;
56780 if( pPage->leaf ){
56781 pPage->intKeyLeaf = 1;
56782 pPage->noPayload = 0;
56783 pPage->xParseCell = btreeParseCellPtr;
56784 }else{
56785 pPage->intKeyLeaf = 0;
56786 pPage->noPayload = 1;
56787 pPage->xCellSize = cellSizePtrNoPayload;
56788 pPage->xParseCell = btreeParseCellPtrNoPayload;
56789 }
56790 pPage->maxLocal = pBt->maxLeaf;
56791 pPage->minLocal = pBt->minLeaf;
@@ -56796,11 +57044,10 @@
56796 /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
56797 ** index b-tree page. */
56798 assert( (PTF_ZERODATA|PTF_LEAF)==10 );
56799 pPage->intKey = 0;
56800 pPage->intKeyLeaf = 0;
56801 pPage->noPayload = 0;
56802 pPage->xParseCell = btreeParseCellPtrIndex;
56803 pPage->maxLocal = pBt->maxLocal;
56804 pPage->minLocal = pBt->minLocal;
56805 }else{
56806 /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
@@ -58217,11 +58464,10 @@
58217 ** no progress. By returning SQLITE_BUSY and not invoking the busy callback
58218 ** when A already has a read lock, we encourage A to give up and let B
58219 ** proceed.
58220 */
58221 SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
58222 sqlite3 *pBlock = 0;
58223 BtShared *pBt = p->pBt;
58224 int rc = SQLITE_OK;
58225
58226 sqlite3BtreeEnter(p);
58227 btreeIntegrity(p);
@@ -58240,31 +58486,34 @@
58240 rc = SQLITE_READONLY;
58241 goto trans_begun;
58242 }
58243
58244 #ifndef SQLITE_OMIT_SHARED_CACHE
58245 /* If another database handle has already opened a write transaction
58246 ** on this shared-btree structure and a second write transaction is
58247 ** requested, return SQLITE_LOCKED.
58248 */
58249 if( (wrflag && pBt->inTransaction==TRANS_WRITE)
58250 || (pBt->btsFlags & BTS_PENDING)!=0
58251 ){
58252 pBlock = pBt->pWriter->db;
58253 }else if( wrflag>1 ){
58254 BtLock *pIter;
58255 for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
58256 if( pIter->pBtree!=p ){
58257 pBlock = pIter->pBtree->db;
58258 break;
58259 }
58260 }
58261 }
58262 if( pBlock ){
58263 sqlite3ConnectionBlocked(p->db, pBlock);
58264 rc = SQLITE_LOCKED_SHAREDCACHE;
58265 goto trans_begun;
 
 
 
58266 }
58267 #endif
58268
58269 /* Any read-only or read-write transaction implies a read-lock on
58270 ** page 1. So if some other shared-cache client already has a write-lock
@@ -59377,11 +59626,11 @@
59377 ** Failure is not possible. This function always returns SQLITE_OK.
59378 ** It might just as well be a procedure (returning void) but we continue
59379 ** to return an integer result code for historical reasons.
59380 */
59381 SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
59382 assert( cursorHoldsMutex(pCur) );
59383 assert( pCur->eState==CURSOR_VALID );
59384 assert( pCur->iPage>=0 );
59385 assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
59386 assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
59387 getCellInfo(pCur);
@@ -59757,11 +60006,11 @@
59757 if ( pCur->eState==CURSOR_INVALID ){
59758 return SQLITE_ABORT;
59759 }
59760 #endif
59761
59762 assert( cursorHoldsMutex(pCur) );
59763 rc = restoreCursorPosition(pCur);
59764 if( rc==SQLITE_OK ){
59765 assert( pCur->eState==CURSOR_VALID );
59766 assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
59767 assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
@@ -59795,11 +60044,11 @@
59795 ){
59796 u32 amt;
59797 assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
59798 assert( pCur->eState==CURSOR_VALID );
59799 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
59800 assert( cursorHoldsMutex(pCur) );
59801 assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
59802 assert( pCur->info.nSize>0 );
59803 assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
59804 assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
59805 amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
@@ -59841,11 +60090,11 @@
59841 ** vice-versa).
59842 */
59843 static int moveToChild(BtCursor *pCur, u32 newPgno){
59844 BtShared *pBt = pCur->pBt;
59845
59846 assert( cursorHoldsMutex(pCur) );
59847 assert( pCur->eState==CURSOR_VALID );
59848 assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
59849 assert( pCur->iPage>=0 );
59850 if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
59851 return SQLITE_CORRUPT_BKPT;
@@ -59887,11 +60136,11 @@
59887 ** to the page we are coming from. If we are coming from the
59888 ** right-most child page then pCur->idx is set to one more than
59889 ** the largest cell index.
59890 */
59891 static void moveToParent(BtCursor *pCur){
59892 assert( cursorHoldsMutex(pCur) );
59893 assert( pCur->eState==CURSOR_VALID );
59894 assert( pCur->iPage>0 );
59895 assert( pCur->apPage[pCur->iPage] );
59896 assertParentIndex(
59897 pCur->apPage[pCur->iPage-1],
@@ -59927,11 +60176,11 @@
59927 */
59928 static int moveToRoot(BtCursor *pCur){
59929 MemPage *pRoot;
59930 int rc = SQLITE_OK;
59931
59932 assert( cursorHoldsMutex(pCur) );
59933 assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
59934 assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
59935 assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
59936 if( pCur->eState>=CURSOR_REQUIRESEEK ){
59937 if( pCur->eState==CURSOR_FAULT ){
@@ -60006,11 +60255,11 @@
60006 static int moveToLeftmost(BtCursor *pCur){
60007 Pgno pgno;
60008 int rc = SQLITE_OK;
60009 MemPage *pPage;
60010
60011 assert( cursorHoldsMutex(pCur) );
60012 assert( pCur->eState==CURSOR_VALID );
60013 while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
60014 assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
60015 pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
60016 rc = moveToChild(pCur, pgno);
@@ -60031,11 +60280,11 @@
60031 static int moveToRightmost(BtCursor *pCur){
60032 Pgno pgno;
60033 int rc = SQLITE_OK;
60034 MemPage *pPage = 0;
60035
60036 assert( cursorHoldsMutex(pCur) );
60037 assert( pCur->eState==CURSOR_VALID );
60038 while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
60039 pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
60040 pCur->aiIdx[pCur->iPage] = pPage->nCell;
60041 rc = moveToChild(pCur, pgno);
@@ -60052,11 +60301,11 @@
60052 ** or set *pRes to 1 if the table is empty.
60053 */
60054 SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
60055 int rc;
60056
60057 assert( cursorHoldsMutex(pCur) );
60058 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60059 rc = moveToRoot(pCur);
60060 if( rc==SQLITE_OK ){
60061 if( pCur->eState==CURSOR_INVALID ){
60062 assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
@@ -60075,11 +60324,11 @@
60075 ** or set *pRes to 1 if the table is empty.
60076 */
60077 SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
60078 int rc;
60079
60080 assert( cursorHoldsMutex(pCur) );
60081 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60082
60083 /* If the cursor already points to the last entry, this is a no-op. */
60084 if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
60085 #ifdef SQLITE_DEBUG
@@ -60153,11 +60402,11 @@
60153 int *pRes /* Write search results here */
60154 ){
60155 int rc;
60156 RecordCompare xRecordCompare;
60157
60158 assert( cursorHoldsMutex(pCur) );
60159 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60160 assert( pRes );
60161 assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
60162
60163 /* If the cursor is already positioned at the point we are trying
@@ -60401,11 +60650,11 @@
60401 static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
60402 int rc;
60403 int idx;
60404 MemPage *pPage;
60405
60406 assert( cursorHoldsMutex(pCur) );
60407 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60408 assert( *pRes==0 );
60409 if( pCur->eState!=CURSOR_VALID ){
60410 assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
60411 rc = restoreCursorPosition(pCur);
@@ -60465,11 +60714,11 @@
60465 return moveToLeftmost(pCur);
60466 }
60467 }
60468 SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
60469 MemPage *pPage;
60470 assert( cursorHoldsMutex(pCur) );
60471 assert( pRes!=0 );
60472 assert( *pRes==0 || *pRes==1 );
60473 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60474 pCur->info.nSize = 0;
60475 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
@@ -60510,11 +60759,11 @@
60510 */
60511 static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
60512 int rc;
60513 MemPage *pPage;
60514
60515 assert( cursorHoldsMutex(pCur) );
60516 assert( pRes!=0 );
60517 assert( *pRes==0 );
60518 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60519 assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
60520 assert( pCur->info.nSize==0 );
@@ -60566,11 +60815,11 @@
60566 }
60567 }
60568 return rc;
60569 }
60570 SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
60571 assert( cursorHoldsMutex(pCur) );
60572 assert( pRes!=0 );
60573 assert( *pRes==0 || *pRes==1 );
60574 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60575 *pRes = 0;
60576 pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
@@ -62279,13 +62528,12 @@
62279 ** This must be done in advance. Once the balance starts, the cell
62280 ** offset section of the btree page will be overwritten and we will no
62281 ** long be able to find the cells if a pointer to each cell is not saved
62282 ** first.
62283 */
62284 memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*limit);
62285 if( pOld->nOverflow>0 ){
62286 memset(&b.szCell[b.nCell+limit], 0, sizeof(b.szCell[0])*pOld->nOverflow);
62287 limit = pOld->aiOvfl[0];
62288 for(j=0; j<limit; j++){
62289 b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
62290 piCell += 2;
62291 b.nCell++;
@@ -63046,11 +63294,11 @@
63046 if( pCur->eState==CURSOR_FAULT ){
63047 assert( pCur->skipNext!=SQLITE_OK );
63048 return pCur->skipNext;
63049 }
63050
63051 assert( cursorHoldsMutex(pCur) );
63052 assert( (pCur->curFlags & BTCF_WriteFlag)!=0
63053 && pBt->inTransaction==TRANS_WRITE
63054 && (pBt->btsFlags & BTS_READ_ONLY)==0 );
63055 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
63056
@@ -63193,11 +63441,11 @@
63193 int iCellIdx; /* Index of cell to delete */
63194 int iCellDepth; /* Depth of node containing pCell */
63195 u16 szCell; /* Size of the cell being deleted */
63196 int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
63197
63198 assert( cursorHoldsMutex(pCur) );
63199 assert( pBt->inTransaction==TRANS_WRITE );
63200 assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
63201 assert( pCur->curFlags & BTCF_WriteFlag );
63202 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
63203 assert( !hasReadConflicts(p, pCur->pgnoRoot) );
@@ -63633,10 +63881,18 @@
63633 */
63634 if( NEVER(pBt->pCursor) ){
63635 sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
63636 return SQLITE_LOCKED_SHAREDCACHE;
63637 }
 
 
 
 
 
 
 
 
63638
63639 rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
63640 if( rc ) return rc;
63641 rc = sqlite3BtreeClearTable(p, iTable, 0);
63642 if( rc ){
@@ -63644,80 +63900,71 @@
63644 return rc;
63645 }
63646
63647 *piMoved = 0;
63648
63649 if( iTable>1 ){
63650 #ifdef SQLITE_OMIT_AUTOVACUUM
63651 freePage(pPage, &rc);
63652 releasePage(pPage);
63653 #else
63654 if( pBt->autoVacuum ){
63655 Pgno maxRootPgno;
63656 sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
63657
63658 if( iTable==maxRootPgno ){
63659 /* If the table being dropped is the table with the largest root-page
63660 ** number in the database, put the root page on the free list.
63661 */
63662 freePage(pPage, &rc);
63663 releasePage(pPage);
63664 if( rc!=SQLITE_OK ){
63665 return rc;
63666 }
63667 }else{
63668 /* The table being dropped does not have the largest root-page
63669 ** number in the database. So move the page that does into the
63670 ** gap left by the deleted root-page.
63671 */
63672 MemPage *pMove;
63673 releasePage(pPage);
63674 rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63675 if( rc!=SQLITE_OK ){
63676 return rc;
63677 }
63678 rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
63679 releasePage(pMove);
63680 if( rc!=SQLITE_OK ){
63681 return rc;
63682 }
63683 pMove = 0;
63684 rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63685 freePage(pMove, &rc);
63686 releasePage(pMove);
63687 if( rc!=SQLITE_OK ){
63688 return rc;
63689 }
63690 *piMoved = maxRootPgno;
63691 }
63692
63693 /* Set the new 'max-root-page' value in the database header. This
63694 ** is the old value less one, less one more if that happens to
63695 ** be a root-page number, less one again if that is the
63696 ** PENDING_BYTE_PAGE.
63697 */
63698 maxRootPgno--;
63699 while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
63700 || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
63701 maxRootPgno--;
63702 }
63703 assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
63704
63705 rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
63706 }else{
63707 freePage(pPage, &rc);
63708 releasePage(pPage);
63709 }
63710 #endif
63711 }else{
63712 /* If sqlite3BtreeDropTable was called on page 1.
63713 ** This really never should happen except in a corrupt
63714 ** database.
63715 */
63716 zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
63717 releasePage(pPage);
63718 }
63719 return rc;
63720 }
63721 SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
63722 int rc;
63723 sqlite3BtreeEnter(p);
@@ -64655,11 +64902,11 @@
64655 ** parameters that attempt to write past the end of the existing data,
64656 ** no modifications are made and SQLITE_CORRUPT is returned.
64657 */
64658 SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
64659 int rc;
64660 assert( cursorHoldsMutex(pCsr) );
64661 assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
64662 assert( pCsr->curFlags & BTCF_Incrblob );
64663
64664 rc = restoreCursorPosition(pCsr);
64665 if( rc!=SQLITE_OK ){
@@ -64762,10 +65009,19 @@
64762
64763 /*
64764 ** Return the size of the header added to each page by this module.
64765 */
64766 SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
 
 
 
 
 
 
 
 
 
64767
64768 /************** End of btree.c ***********************************************/
64769 /************** Begin file backup.c ******************************************/
64770 /*
64771 ** 2009 January 28
@@ -66791,11 +67047,11 @@
66791
66792 assert( pCtx->pParse->rc==SQLITE_OK );
66793 memset(&ctx, 0, sizeof(ctx));
66794 ctx.pOut = pVal;
66795 ctx.pFunc = pFunc;
66796 pFunc->xFunc(&ctx, nVal, apVal);
66797 if( ctx.isError ){
66798 rc = ctx.isError;
66799 sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
66800 }else{
66801 sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
@@ -67538,12 +67794,11 @@
67538 char c;
67539 va_start(ap, zTypes);
67540 for(i=0; (c = zTypes[i])!=0; i++){
67541 if( c=='s' ){
67542 const char *z = va_arg(ap, const char*);
67543 int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++);
67544 if( z ) sqlite3VdbeChangeP4(p, addr, z, 0);
67545 }else{
67546 assert( c=='i' );
67547 sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
67548 }
67549 }
@@ -67593,12 +67848,11 @@
67593 ** The zWhere string must have been obtained from sqlite3_malloc().
67594 ** This routine will take ownership of the allocated memory.
67595 */
67596 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
67597 int j;
67598 int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
67599 sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
67600 for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
67601 }
67602
67603 /*
67604 ** Add an opcode that includes the p4 value as an integer.
@@ -67895,10 +68149,24 @@
67895 SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
67896 assert( p->magic==VDBE_MAGIC_INIT );
67897 return p->nOp;
67898 }
67899
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67900 /*
67901 ** This function returns a pointer to the array of opcodes associated with
67902 ** the Vdbe passed as the first argument. It is the callers responsibility
67903 ** to arrange for the returned array to be eventually freed using the
67904 ** vdbeFreeOpArray() function.
@@ -67920,23 +68188,27 @@
67920 p->aOp = 0;
67921 return aOp;
67922 }
67923
67924 /*
67925 ** Add a whole list of operations to the operation stack. Return the
67926 ** address of the first operation added.
67927 */
67928 SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
67929 int addr, i;
67930 VdbeOp *pOut;
 
 
 
 
 
67931 assert( nOp>0 );
67932 assert( p->magic==VDBE_MAGIC_INIT );
67933 if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
67934 return 0;
67935 }
67936 addr = p->nOp;
67937 pOut = &p->aOp[addr];
67938 for(i=0; i<nOp; i++, aOp++, pOut++){
67939 pOut->opcode = aOp->opcode;
67940 pOut->p1 = aOp->p1;
67941 pOut->p2 = aOp->p2;
67942 assert( aOp->p2>=0 );
@@ -67952,16 +68224,16 @@
67952 #else
67953 (void)iLineno;
67954 #endif
67955 #ifdef SQLITE_DEBUG
67956 if( p->db->flags & SQLITE_VdbeAddopTrace ){
67957 sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
67958 }
67959 #endif
67960 }
67961 p->nOp += nOp;
67962 return addr;
67963 }
67964
67965 #if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
67966 /*
67967 ** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
@@ -68005,11 +68277,11 @@
68005 }
68006 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
68007 sqlite3VdbeGetOp(p,addr)->p3 = val;
68008 }
68009 SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
68010 sqlite3VdbeGetOp(p,-1)->p5 = p5;
68011 }
68012
68013 /*
68014 ** Change the P2 operand of instruction addr so that it points to
68015 ** the address of the next instruction to be coded.
@@ -68093,11 +68365,11 @@
68093 */
68094 static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
68095 if( aOp ){
68096 Op *pOp;
68097 for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
68098 freeP4(db, pOp->p4type, pOp->p4.p);
68099 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
68100 sqlite3DbFree(db, pOp->zComment);
68101 #endif
68102 }
68103 }
@@ -68115,28 +68387,29 @@
68115 }
68116
68117 /*
68118 ** Change the opcode at addr into OP_Noop
68119 */
68120 SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
68121 if( addr<p->nOp ){
68122 VdbeOp *pOp = &p->aOp[addr];
68123 sqlite3 *db = p->db;
68124 freeP4(db, pOp->p4type, pOp->p4.p);
68125 memset(pOp, 0, sizeof(pOp[0]));
68126 pOp->opcode = OP_Noop;
68127 }
 
 
68128 }
68129
68130 /*
68131 ** If the last opcode is "op" and it is not a jump destination,
68132 ** then remove it. Return true if and only if an opcode was removed.
68133 */
68134 SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
68135 if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
68136 sqlite3VdbeChangeToNoop(p, p->nOp-1);
68137 return 1;
68138 }else{
68139 return 0;
68140 }
68141 }
68142
@@ -68155,65 +68428,60 @@
68155 ** to a string or structure that is guaranteed to exist for the lifetime of
68156 ** the Vdbe. In these cases we can just copy the pointer.
68157 **
68158 ** If addr<0 then change P4 on the most recently inserted instruction.
68159 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68160 SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
68161 Op *pOp;
68162 sqlite3 *db;
68163 assert( p!=0 );
68164 db = p->db;
68165 assert( p->magic==VDBE_MAGIC_INIT );
68166 if( p->aOp==0 || db->mallocFailed ){
68167 if( n!=P4_VTAB ){
68168 freeP4(db, n, (void*)*(char**)&zP4);
68169 }
68170 return;
68171 }
68172 assert( p->nOp>0 );
68173 assert( addr<p->nOp );
68174 if( addr<0 ){
68175 addr = p->nOp - 1;
68176 }
68177 pOp = &p->aOp[addr];
68178 assert( pOp->p4type==P4_NOTUSED
68179 || pOp->p4type==P4_INT32
68180 || pOp->p4type==P4_KEYINFO );
68181 freeP4(db, pOp->p4type, pOp->p4.p);
68182 pOp->p4.p = 0;
68183 if( n==P4_INT32 ){
68184 /* Note: this cast is safe, because the origin data point was an int
68185 ** that was cast to a (const char *). */
68186 pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
68187 pOp->p4type = P4_INT32;
68188 }else if( zP4==0 ){
68189 pOp->p4.p = 0;
68190 pOp->p4type = P4_NOTUSED;
68191 }else if( n==P4_KEYINFO ){
68192 pOp->p4.p = (void*)zP4;
68193 pOp->p4type = P4_KEYINFO;
68194 #ifdef SQLITE_ENABLE_CURSOR_HINTS
68195 }else if( n==P4_EXPR ){
68196 /* Responsibility for deleting the Expr tree is handed over to the
68197 ** VDBE by this operation. The caller should have already invoked
68198 ** sqlite3ExprDup() or whatever other routine is needed to make a
68199 ** private copy of the tree. */
68200 pOp->p4.pExpr = (Expr*)zP4;
68201 pOp->p4type = P4_EXPR;
68202 #endif
68203 }else if( n==P4_VTAB ){
68204 pOp->p4.p = (void*)zP4;
68205 pOp->p4type = P4_VTAB;
68206 sqlite3VtabLock((VTable *)zP4);
68207 assert( ((VTable *)zP4)->db==p->db );
68208 }else if( n<0 ){
68209 pOp->p4.p = (void*)zP4;
68210 pOp->p4type = (signed char)n;
68211 }else{
68212 if( n==0 ) n = sqlite3Strlen30(zP4);
68213 pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
68214 pOp->p4type = P4_DYNAMIC;
68215 }
68216 }
68217
68218 /*
68219 ** Set the P4 on the most recently added opcode to the KeyInfo for the
@@ -68605,11 +68873,11 @@
68605 if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
68606 DbMaskSet(p->lockMask, i);
68607 }
68608 }
68609
68610 #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
68611 /*
68612 ** If SQLite is compiled to support shared-cache mode and to be threadsafe,
68613 ** this routine obtains the mutex associated with each BtShared structure
68614 ** that may be accessed by the VM passed as an argument. In doing so it also
68615 ** sets the BtShared.db member of each of the BtShared structures, ensuring
@@ -69174,11 +69442,10 @@
69174 do {
69175 nByte = 0;
69176 p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte);
69177 p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte);
69178 p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte);
69179 p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), zCsr, &nFree, &nByte);
69180 p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
69181 zCsr, &nFree, &nByte);
69182 p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte);
69183 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
69184 p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte);
@@ -69197,15 +69464,14 @@
69197 for(n=0; n<nVar; n++){
69198 p->aVar[n].flags = MEM_Null;
69199 p->aVar[n].db = db;
69200 }
69201 }
69202 if( p->azVar && pParse->nzVar>0 ){
69203 p->nzVar = pParse->nzVar;
69204 memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
69205 memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
69206 }
69207 if( p->aMem ){
69208 p->aMem--; /* aMem[] goes from 1..nMem */
69209 p->nMem = nMem; /* not from 0..nMem-1 */
69210 for(n=1; n<=nMem; n++){
69211 p->aMem[n].flags = MEM_Undefined;
@@ -70188,10 +70454,11 @@
70188 pNext = pSub->pNext;
70189 vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
70190 sqlite3DbFree(db, pSub);
70191 }
70192 for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
 
70193 vdbeFreeOpArray(db, p->aOp, p->nOp);
70194 sqlite3DbFree(db, p->aColName);
70195 sqlite3DbFree(db, p->zSql);
70196 sqlite3DbFree(db, p->pFree);
70197 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -70932,13 +71199,13 @@
70932 v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
70933 n1 = v1==0 ? 0 : c1.n;
70934 v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
70935 n2 = v2==0 ? 0 : c2.n;
70936 rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
 
70937 sqlite3VdbeMemRelease(&c1);
70938 sqlite3VdbeMemRelease(&c2);
70939 if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
70940 return rc;
70941 }
70942 }
70943
70944 /*
@@ -71722,15 +71989,17 @@
71722 ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
71723 ** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
71724 ** in memory obtained from sqlite3DbMalloc).
71725 */
71726 SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
71727 sqlite3 *db = p->db;
71728 sqlite3DbFree(db, p->zErrMsg);
71729 p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
71730 sqlite3_free(pVtab->zErrMsg);
71731 pVtab->zErrMsg = 0;
 
 
71732 }
71733 #endif /* SQLITE_OMIT_VIRTUALTABLE */
71734
71735 /************** End of vdbeaux.c *********************************************/
71736 /************** Begin file vdbeapi.c *****************************************/
@@ -72513,11 +72782,11 @@
72513 ** Allocate or return the aggregate context for a user function. A new
72514 ** context is allocated on the first call. Subsequent calls return the
72515 ** same context that was returned on prior calls.
72516 */
72517 SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
72518 assert( p && p->pFunc && p->pFunc->xStep );
72519 assert( sqlite3_mutex_held(p->pOut->db->mutex) );
72520 testcase( nByte<0 );
72521 if( (p->pMem->flags & MEM_Agg)==0 ){
72522 return createAggContext(p, nByte);
72523 }else{
@@ -72604,11 +72873,11 @@
72604 ** provide only to avoid breaking legacy code. New aggregate function
72605 ** implementations should keep their own counts within their aggregate
72606 ** context.
72607 */
72608 SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
72609 assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
72610 return p->pMem->n;
72611 }
72612 #endif
72613
72614 /*
@@ -75347,12 +75616,12 @@
75347 }
75348 #endif
75349 MemSetTypeFlag(pCtx->pOut, MEM_Null);
75350 pCtx->fErrorOrAux = 0;
75351 db->lastRowid = lastRowid;
75352 (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */
75353 lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */
75354
75355 /* If the function returned an error, throw an exception */
75356 if( pCtx->fErrorOrAux ){
75357 if( pCtx->isError ){
75358 sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
@@ -76059,11 +76328,10 @@
76059 const u8 *zEndHdr; /* Pointer to first byte after the header */
76060 u32 offset; /* Offset into the data */
76061 u64 offset64; /* 64-bit offset */
76062 u32 avail; /* Number of bytes of available data */
76063 u32 t; /* A type code from the record header */
76064 u16 fx; /* pDest->flags value */
76065 Mem *pReg; /* PseudoTable input register */
76066
76067 p2 = pOp->p2;
76068 assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
76069 pDest = &aMem[pOp->p3];
@@ -76237,14 +76505,35 @@
76237 assert( p2<pC->nHdrParsed );
76238 assert( rc==SQLITE_OK );
76239 assert( sqlite3VdbeCheckMemInvariants(pDest) );
76240 if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
76241 assert( t==pC->aType[p2] );
 
76242 if( pC->szRow>=aOffset[p2+1] ){
76243 /* This is the common case where the desired content fits on the original
76244 ** page - where the content is not on an overflow page */
76245 sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76246 }else{
76247 /* This branch happens only when content is on overflow pages */
76248 if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
76249 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
76250 || (len = sqlite3VdbeSerialTypeLen(t))==0
@@ -76252,42 +76541,24 @@
76252 /* Content is irrelevant for
76253 ** 1. the typeof() function,
76254 ** 2. the length(X) function if X is a blob, and
76255 ** 3. if the content length is zero.
76256 ** So we might as well use bogus content rather than reading
76257 ** content from disk. NULL will work for the value for strings
76258 ** and blobs and whatever is in the payloadSize64 variable
76259 ** will work for everything else. */
76260 sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
76261 }else{
76262 rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
76263 pDest);
76264 if( rc!=SQLITE_OK ){
76265 goto op_column_error;
76266 }
76267 sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
76268 pDest->flags &= ~MEM_Ephem;
76269 }
76270 }
76271 pDest->enc = encoding;
76272
76273 op_column_out:
76274 /* If the column value is an ephemeral string, go ahead and persist
76275 ** that string in case the cursor moves before the column value is
76276 ** used. The following code does the equivalent of Deephemeralize()
76277 ** but does it faster. */
76278 if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
76279 fx = pDest->flags & (MEM_Str|MEM_Blob);
76280 assert( fx!=0 );
76281 zData = (const u8*)pDest->z;
76282 len = pDest->n;
76283 if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
76284 memcpy(pDest->z, zData, len);
76285 pDest->z[len] = 0;
76286 pDest->z[len+1] = 0;
76287 pDest->flags = fx|MEM_Term;
76288 }
76289 op_column_error:
76290 UPDATE_MAX_BLOBSIZE(pDest);
76291 REGISTER_TRACE(pOp->p3, pDest);
76292 break;
76293 }
@@ -78782,10 +79053,11 @@
78782 case OP_Destroy: { /* out2 */
78783 int iMoved;
78784 int iDb;
78785
78786 assert( p->readOnly==0 );
 
78787 pOut = out2Prerelease(p, pOp);
78788 pOut->flags = MEM_Null;
78789 if( db->nVdbeRead > db->nVDestroy+1 ){
78790 rc = SQLITE_LOCKED;
78791 p->errorAction = OE_Abort;
@@ -79586,11 +79858,11 @@
79586 pMem->n++;
79587 sqlite3VdbeMemInit(&t, db, MEM_Null);
79588 pCtx->pOut = &t;
79589 pCtx->fErrorOrAux = 0;
79590 pCtx->skipFlag = 0;
79591 (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
79592 if( pCtx->fErrorOrAux ){
79593 if( pCtx->isError ){
79594 sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
79595 rc = pCtx->isError;
79596 }
@@ -80584,42 +80856,10 @@
80584 int flags, /* True -> read/write access, false -> read-only */
80585 sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
80586 ){
80587 int nAttempt = 0;
80588 int iCol; /* Index of zColumn in row-record */
80589
80590 /* This VDBE program seeks a btree cursor to the identified
80591 ** db/table/row entry. The reason for using a vdbe program instead
80592 ** of writing code to use the b-tree layer directly is that the
80593 ** vdbe program will take advantage of the various transaction,
80594 ** locking and error handling infrastructure built into the vdbe.
80595 **
80596 ** After seeking the cursor, the vdbe executes an OP_ResultRow.
80597 ** Code external to the Vdbe then "borrows" the b-tree cursor and
80598 ** uses it to implement the blob_read(), blob_write() and
80599 ** blob_bytes() functions.
80600 **
80601 ** The sqlite3_blob_close() function finalizes the vdbe program,
80602 ** which closes the b-tree cursor and (possibly) commits the
80603 ** transaction.
80604 */
80605 static const int iLn = VDBE_OFFSET_LINENO(4);
80606 static const VdbeOpList openBlob[] = {
80607 /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
80608 {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
80609 /* One of the following two instructions is replaced by an OP_Noop. */
80610 {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
80611 {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
80612 {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
80613 {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
80614 {OP_Column, 0, 0, 1}, /* 6 */
80615 {OP_ResultRow, 1, 0, 0}, /* 7 */
80616 {OP_Goto, 0, 4, 0}, /* 8 */
80617 {OP_Close, 0, 0, 0}, /* 9 */
80618 {OP_Halt, 0, 0, 0}, /* 10 */
80619 };
80620
80621 int rc = SQLITE_OK;
80622 char *zErr = 0;
80623 Table *pTab;
80624 Parse *pParse = 0;
80625 Incrblob *pBlob = 0;
@@ -80734,49 +80974,84 @@
80734 }
80735
80736 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
80737 assert( pBlob->pStmt || db->mallocFailed );
80738 if( pBlob->pStmt ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80739 Vdbe *v = (Vdbe *)pBlob->pStmt;
80740 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
80741
80742
80743 sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
80744 pTab->pSchema->schema_cookie,
80745 pTab->pSchema->iGeneration);
80746 sqlite3VdbeChangeP5(v, 1);
80747 sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
80748
80749 /* Make sure a mutex is held on the table to be accessed */
80750 sqlite3VdbeUsesBtree(v, iDb);
80751
80752 /* Configure the OP_TableLock instruction */
 
 
80753 #ifdef SQLITE_OMIT_SHARED_CACHE
80754 sqlite3VdbeChangeToNoop(v, 1);
80755 #else
80756 sqlite3VdbeChangeP1(v, 1, iDb);
80757 sqlite3VdbeChangeP2(v, 1, pTab->tnum);
80758 sqlite3VdbeChangeP3(v, 1, flags);
80759 sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
 
 
80760 #endif
80761
80762 /* Remove either the OP_OpenWrite or OpenRead. Set the P2
80763 ** parameter of the other to pTab->tnum. */
80764 sqlite3VdbeChangeToNoop(v, 3 - flags);
80765 sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
80766 sqlite3VdbeChangeP3(v, 2 + flags, iDb);
80767
80768 /* Configure the number of columns. Configure the cursor to
80769 ** think that the table has one more column than it really
80770 ** does. An OP_Column to retrieve this imaginary column will
80771 ** always return an SQL NULL. This is useful because it means
80772 ** we can invoke OP_Column to fill in the vdbe cursors type
80773 ** and offset cache without causing any IO.
80774 */
80775 sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
80776 sqlite3VdbeChangeP2(v, 6, pTab->nCol);
80777 if( !db->mallocFailed ){
 
80778 pParse->nVar = 1;
80779 pParse->nMem = 1;
80780 pParse->nTab = 1;
80781 sqlite3VdbeMakeReady(v, pParse);
80782 }
@@ -81685,11 +81960,11 @@
81685 assert( pReadr->aBuffer==0 );
81686 assert( pReadr->aMap==0 );
81687
81688 rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
81689 if( rc==SQLITE_OK ){
81690 u64 nByte; /* Size of PMA in bytes */
81691 rc = vdbePmaReadVarint(pReadr, &nByte);
81692 pReadr->iEof = pReadr->iReadOff + nByte;
81693 *pnByte += nByte;
81694 }
81695
@@ -84243,13 +84518,12 @@
84243 ** return the top-level walk call.
84244 **
84245 ** The return value from this routine is WRC_Abort to abandon the tree walk
84246 ** and WRC_Continue to continue.
84247 */
84248 SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
84249 int rc;
84250 if( pExpr==0 ) return WRC_Continue;
84251 testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
84252 testcase( ExprHasProperty(pExpr, EP_Reduced) );
84253 rc = pWalker->xExprCallback(pWalker, pExpr);
84254 if( rc==WRC_Continue
84255 && !ExprHasProperty(pExpr,EP_TokenOnly) ){
@@ -84260,10 +84534,13 @@
84260 }else{
84261 if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
84262 }
84263 }
84264 return rc & WRC_Abort;
 
 
 
84265 }
84266
84267 /*
84268 ** Call sqlite3WalkExpr() for every expression in list p or until
84269 ** an abort request is seen.
@@ -85034,11 +85311,11 @@
85034 no_such_func = 1;
85035 }else{
85036 wrong_num_args = 1;
85037 }
85038 }else{
85039 is_agg = pDef->xFunc==0;
85040 if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
85041 ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
85042 if( n==2 ){
85043 pExpr->iTable = exprProbability(pList->a[1].pExpr);
85044 if( pExpr->iTable<0 ){
@@ -85762,14 +86039,16 @@
85762 pParse->nHeight += pExpr->nHeight;
85763 }
85764 #endif
85765 savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
85766 pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
85767 memset(&w, 0, sizeof(w));
85768 w.xExprCallback = resolveExprStep;
85769 w.xSelectCallback = resolveSelectStep;
85770 w.pParse = pNC->pParse;
 
 
85771 w.u.pNC = pNC;
85772 sqlite3WalkExpr(&w, pExpr);
85773 #if SQLITE_MAX_EXPR_DEPTH>0
85774 pNC->pParse->nHeight -= pExpr->nHeight;
85775 #endif
@@ -86327,12 +86606,13 @@
86327 || sqlite3GetInt32(pToken->z, &iValue)==0 ){
86328 nExtra = pToken->n+1;
86329 assert( iValue>=0 );
86330 }
86331 }
86332 pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
86333 if( pNew ){
 
86334 pNew->op = (u8)op;
86335 pNew->iAgg = -1;
86336 if( pToken ){
86337 if( nExtra==0 ){
86338 pNew->flags |= EP_IntValue;
@@ -87000,14 +87280,15 @@
87000 ExprList *pList, /* List to which to append. Might be NULL */
87001 Expr *pExpr /* Expression to be appended. Might be NULL */
87002 ){
87003 sqlite3 *db = pParse->db;
87004 if( pList==0 ){
87005 pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
87006 if( pList==0 ){
87007 goto no_mem;
87008 }
 
87009 pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
87010 if( pList->a==0 ) goto no_mem;
87011 }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
87012 struct ExprList_item *a;
87013 assert( pList->nExpr>0 );
@@ -88761,11 +89042,11 @@
88761 nFarg = pFarg ? pFarg->nExpr : 0;
88762 assert( !ExprHasProperty(pExpr, EP_IntValue) );
88763 zId = pExpr->u.zToken;
88764 nId = sqlite3Strlen30(zId);
88765 pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
88766 if( pDef==0 || pDef->xFunc==0 ){
88767 sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
88768 break;
88769 }
88770
88771 /* Attempt a direct implementation of the built-in COALESCE() and
@@ -91433,12 +91714,11 @@
91433 static const FuncDef statInitFuncdef = {
91434 2+IsStat34, /* nArg */
91435 SQLITE_UTF8, /* funcFlags */
91436 0, /* pUserData */
91437 0, /* pNext */
91438 statInit, /* xFunc */
91439 0, /* xStep */
91440 0, /* xFinalize */
91441 "stat_init", /* zName */
91442 0, /* pHash */
91443 0 /* pDestructor */
91444 };
@@ -91734,12 +92014,11 @@
91734 static const FuncDef statPushFuncdef = {
91735 2+IsStat34, /* nArg */
91736 SQLITE_UTF8, /* funcFlags */
91737 0, /* pUserData */
91738 0, /* pNext */
91739 statPush, /* xFunc */
91740 0, /* xStep */
91741 0, /* xFinalize */
91742 "stat_push", /* zName */
91743 0, /* pHash */
91744 0 /* pDestructor */
91745 };
@@ -91881,12 +92160,11 @@
91881 static const FuncDef statGetFuncdef = {
91882 1+IsStat34, /* nArg */
91883 SQLITE_UTF8, /* funcFlags */
91884 0, /* pUserData */
91885 0, /* pNext */
91886 statGet, /* xFunc */
91887 0, /* xStep */
91888 0, /* xFinalize */
91889 "stat_get", /* zName */
91890 0, /* pHash */
91891 0 /* pDestructor */
91892 };
@@ -91898,12 +92176,12 @@
91898 #elif SQLITE_DEBUG
91899 assert( iParam==STAT_GET_STAT1 );
91900 #else
91901 UNUSED_PARAMETER( iParam );
91902 #endif
91903 sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut);
91904 sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
91905 sqlite3VdbeChangeP5(v, 1 + IsStat34);
91906 }
91907
91908 /*
91909 ** Generate code to do an analysis of all indices associated with
@@ -92053,12 +92331,12 @@
92053 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
92054 sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
92055 #endif
92056 sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
92057 sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
92058 sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4);
92059 sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
92060 sqlite3VdbeChangeP5(v, 2+IsStat34);
92061
92062 /* Implementation of the following:
92063 **
92064 ** Rewind csr
@@ -92150,12 +92428,12 @@
92150 sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
92151 sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
92152 }
92153 #endif
92154 assert( regChng==(regStat4+1) );
92155 sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp);
92156 sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
92157 sqlite3VdbeChangeP5(v, 2+IsStat34);
92158 sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
92159
92160 /* Add the entry to the stat1 table. */
92161 callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
@@ -93208,15 +93486,15 @@
93208 sqlite3ExprCode(pParse, pDbname, regArgs+1);
93209 sqlite3ExprCode(pParse, pKey, regArgs+2);
93210
93211 assert( v || db->mallocFailed );
93212 if( v ){
93213 sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3);
 
93214 assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
93215 sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
93216 sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
93217
93218 /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
93219 ** statement only). For DETACH, set it to false (expire all existing
93220 ** statements).
93221 */
93222 sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
@@ -93237,12 +93515,11 @@
93237 static const FuncDef detach_func = {
93238 1, /* nArg */
93239 SQLITE_UTF8, /* funcFlags */
93240 0, /* pUserData */
93241 0, /* pNext */
93242 detachFunc, /* xFunc */
93243 0, /* xStep */
93244 0, /* xFinalize */
93245 "sqlite_detach", /* zName */
93246 0, /* pHash */
93247 0 /* pDestructor */
93248 };
@@ -93258,12 +93535,11 @@
93258 static const FuncDef attach_func = {
93259 3, /* nArg */
93260 SQLITE_UTF8, /* funcFlags */
93261 0, /* pUserData */
93262 0, /* pNext */
93263 attachFunc, /* xFunc */
93264 0, /* xStep */
93265 0, /* xFinalize */
93266 "sqlite_attach", /* zName */
93267 0, /* pHash */
93268 0 /* pDestructor */
93269 };
@@ -93723,19 +93999,10 @@
93723 ** COMMIT
93724 ** ROLLBACK
93725 */
93726 /* #include "sqliteInt.h" */
93727
93728 /*
93729 ** This routine is called when a new SQL statement is beginning to
93730 ** be parsed. Initialize the pParse structure as needed.
93731 */
93732 SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){
93733 pParse->explain = (u8)explainFlag;
93734 pParse->nVar = 0;
93735 }
93736
93737 #ifndef SQLITE_OMIT_SHARED_CACHE
93738 /*
93739 ** The TableLock structure is only used by the sqlite3TableLock() and
93740 ** codeTableLocks() functions.
93741 */
@@ -93936,19 +94203,23 @@
93936 /* A minimum of one cursor is required if autoincrement is used
93937 * See ticket [a696379c1f08866] */
93938 if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
93939 sqlite3VdbeMakeReady(v, pParse);
93940 pParse->rc = SQLITE_DONE;
93941 pParse->colNamesSet = 0;
93942 }else{
93943 pParse->rc = SQLITE_ERROR;
93944 }
 
 
 
 
93945 pParse->nTab = 0;
93946 pParse->nMem = 0;
93947 pParse->nSet = 0;
93948 pParse->nVar = 0;
93949 DbMaskZero(pParse->cookieMask);
 
93950 }
93951
93952 /*
93953 ** Run the parser and code generator recursively in order to generate
93954 ** code for the SQL statement given onto the end of the pParse context
@@ -94203,11 +94474,10 @@
94203 if( j<i ){
94204 db->aDb[j] = db->aDb[i];
94205 }
94206 j++;
94207 }
94208 memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
94209 db->nDb = j;
94210 if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
94211 memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
94212 sqlite3DbFree(db, db->aDb);
94213 db->aDb = db->aDbStatic;
@@ -94466,11 +94736,12 @@
94466 Token **pUnqual /* Write the unqualified object name here */
94467 ){
94468 int iDb; /* Database holding the object */
94469 sqlite3 *db = pParse->db;
94470
94471 if( ALWAYS(pName2!=0) && pName2->n>0 ){
 
94472 if( db->init.busy ) {
94473 sqlite3ErrorMsg(pParse, "corrupt database");
94474 return -1;
94475 }
94476 *pUnqual = pName2;
@@ -94555,66 +94826,50 @@
94555 sqlite3 *db = pParse->db;
94556 Vdbe *v;
94557 int iDb; /* Database number to create the table in */
94558 Token *pName; /* Unqualified name of the table to create */
94559
94560 /* The table or view name to create is passed to this routine via tokens
94561 ** pName1 and pName2. If the table name was fully qualified, for example:
94562 **
94563 ** CREATE TABLE xxx.yyy (...);
94564 **
94565 ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
94566 ** the table name is not fully qualified, i.e.:
94567 **
94568 ** CREATE TABLE yyy(...);
94569 **
94570 ** Then pName1 is set to "yyy" and pName2 is "".
94571 **
94572 ** The call below sets the pName pointer to point at the token (pName1 or
94573 ** pName2) that stores the unqualified table name. The variable iDb is
94574 ** set to the index of the database that the table or view is to be
94575 ** created in.
94576 */
94577 iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
94578 if( iDb<0 ) return;
94579 if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
94580 /* If creating a temp table, the name may not be qualified. Unless
94581 ** the database name is "temp" anyway. */
94582 sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
94583 return;
94584 }
94585 if( !OMIT_TEMPDB && isTemp ) iDb = 1;
94586
94587 pParse->sNameToken = *pName;
94588 zName = sqlite3NameFromToken(db, pName);
94589 if( zName==0 ) return;
94590 if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
94591 goto begin_table_error;
94592 }
94593 if( db->init.iDb==1 ) isTemp = 1;
94594 #ifndef SQLITE_OMIT_AUTHORIZATION
94595 assert( (isTemp & 1)==isTemp );
 
94596 {
94597 int code;
 
 
 
 
 
94598 char *zDb = db->aDb[iDb].zName;
94599 if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
94600 goto begin_table_error;
94601 }
94602 if( isView ){
94603 if( !OMIT_TEMPDB && isTemp ){
94604 code = SQLITE_CREATE_TEMP_VIEW;
94605 }else{
94606 code = SQLITE_CREATE_VIEW;
94607 }
94608 }else{
94609 if( !OMIT_TEMPDB && isTemp ){
94610 code = SQLITE_CREATE_TEMP_TABLE;
94611 }else{
94612 code = SQLITE_CREATE_TABLE;
94613 }
94614 }
94615 if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
94616 goto begin_table_error;
94617 }
94618 }
94619 #endif
94620
@@ -95572,13 +95827,17 @@
95572 /* If the db->init.busy is 1 it means we are reading the SQL off the
95573 ** "sqlite_master" or "sqlite_temp_master" table on the disk.
95574 ** So do not write to the disk again. Extract the root page number
95575 ** for the table from the db->init.newTnum field. (The page number
95576 ** should have been put there by the sqliteOpenCb routine.)
 
 
 
95577 */
95578 if( db->init.busy ){
95579 p->tnum = db->init.newTnum;
 
95580 }
95581
95582 /* Special processing for WITHOUT ROWID Tables */
95583 if( tabOpts & TF_WithoutRowid ){
95584 if( (p->tabFlags & TF_Autoincrement) ){
@@ -96027,10 +96286,11 @@
96027 ** erasing iTable (this can happen with an auto-vacuum database).
96028 */
96029 static void destroyRootPage(Parse *pParse, int iTable, int iDb){
96030 Vdbe *v = sqlite3GetVdbe(pParse);
96031 int r1 = sqlite3GetTempReg(pParse);
 
96032 sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
96033 sqlite3MayAbort(pParse);
96034 #ifndef SQLITE_OMIT_AUTOVACUUM
96035 /* OP_Destroy stores an in integer r1. If this integer
96036 ** is non-zero, then it is the root page number of a table moved to
@@ -97425,13 +97685,14 @@
97425 Token *pDatabase /* Database of the table */
97426 ){
97427 struct SrcList_item *pItem;
97428 assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
97429 if( pList==0 ){
97430 pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
97431 if( pList==0 ) return 0;
97432 pList->nAlloc = 1;
 
97433 }
97434 pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
97435 if( db->mallocFailed ){
97436 sqlite3SrcListDelete(db, pList);
97437 return 0;
@@ -97830,11 +98091,11 @@
97830 assert( (errCode&0xff)==SQLITE_CONSTRAINT );
97831 if( onError==OE_Abort ){
97832 sqlite3MayAbort(pParse);
97833 }
97834 sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
97835 if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
97836 }
97837
97838 /*
97839 ** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation.
97840 */
@@ -98371,12 +98632,12 @@
98371 ** 3: encoding matches and function takes any number of arguments
98372 ** 4: UTF8/16 conversion required - argument count matches exactly
98373 ** 5: UTF16 byte order conversion required - argument count matches exactly
98374 ** 6: Perfect match: encoding and argument count match exactly.
98375 **
98376 ** If nArg==(-2) then any function with a non-null xStep or xFunc is
98377 ** a perfect match and any function with both xStep and xFunc NULL is
98378 ** a non-match.
98379 */
98380 #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
98381 static int matchQuality(
98382 FuncDef *p, /* The function we are evaluating for match quality */
@@ -98384,11 +98645,11 @@
98384 u8 enc /* Desired text encoding */
98385 ){
98386 int match;
98387
98388 /* nArg of -2 is a special case */
98389 if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
98390
98391 /* Wrong number of arguments means "no match" */
98392 if( p->nArg!=nArg && p->nArg>=0 ) return 0;
98393
98394 /* Give a better score to a function with a specific number of arguments
@@ -98462,11 +98723,11 @@
98462 ** If the createFlag argument is true, then a new (blank) FuncDef
98463 ** structure is created and liked into the "db" structure if a
98464 ** no matching function previously existed.
98465 **
98466 ** If nArg is -2, then the first valid function found is returned. A
98467 ** function is valid if either xFunc or xStep is non-zero. The nArg==(-2)
98468 ** case is used to see if zName is a valid function name for some number
98469 ** of arguments. If nArg is -2, then createFlag must be 0.
98470 **
98471 ** If createFlag is false, then a function with the required name and
98472 ** number of arguments may be returned even if the eTextRep flag does not
@@ -98539,11 +98800,11 @@
98539 memcpy(pBest->zName, zName, nName);
98540 pBest->zName[nName] = 0;
98541 sqlite3FuncDefInsert(&db->aFunc, pBest);
98542 }
98543
98544 if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
98545 return pBest;
98546 }
98547 return 0;
98548 }
98549
@@ -100072,14 +100333,14 @@
100072
100073 /*
100074 ** A structure defining how to do GLOB-style comparisons.
100075 */
100076 struct compareInfo {
100077 u8 matchAll;
100078 u8 matchOne;
100079 u8 matchSet;
100080 u8 noCase;
100081 };
100082
100083 /*
100084 ** For LIKE and GLOB matching on EBCDIC machines, assume that every
100085 ** character is exactly one byte in size. Also, provde the Utf8Read()
@@ -100138,26 +100399,18 @@
100138 */
100139 static int patternCompare(
100140 const u8 *zPattern, /* The glob pattern */
100141 const u8 *zString, /* The string to compare against the glob */
100142 const struct compareInfo *pInfo, /* Information about how to do the compare */
100143 u32 esc /* The escape character */
100144 ){
100145 u32 c, c2; /* Next pattern and input string chars */
100146 u32 matchOne = pInfo->matchOne; /* "?" or "_" */
100147 u32 matchAll = pInfo->matchAll; /* "*" or "%" */
100148 u32 matchOther; /* "[" or the escape character */
100149 u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
100150 const u8 *zEscaped = 0; /* One past the last escaped input char */
100151
100152 /* The GLOB operator does not have an ESCAPE clause. And LIKE does not
100153 ** have the matchSet operator. So we either have to look for one or
100154 ** the other, never both. Hence the single variable matchOther is used
100155 ** to store the one we have to look for.
100156 */
100157 matchOther = esc ? esc : pInfo->matchSet;
100158
100159 while( (c = Utf8Read(zPattern))!=0 ){
100160 if( c==matchAll ){ /* Match "*" */
100161 /* Skip over multiple "*" characters in the pattern. If there
100162 ** are also "?" characters, skip those as well, but consume a
100163 ** single character of the input string for each "?" skipped */
@@ -100167,19 +100420,19 @@
100167 }
100168 }
100169 if( c==0 ){
100170 return 1; /* "*" at the end of the pattern matches */
100171 }else if( c==matchOther ){
100172 if( esc ){
100173 c = sqlite3Utf8Read(&zPattern);
100174 if( c==0 ) return 0;
100175 }else{
100176 /* "[...]" immediately follows the "*". We have to do a slow
100177 ** recursive search in this case, but it is an unusual case. */
100178 assert( matchOther<0x80 ); /* '[' is a single-byte character */
100179 while( *zString
100180 && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
100181 SQLITE_SKIP_UTF8(zString);
100182 }
100183 return *zString!=0;
100184 }
100185 }
@@ -100201,22 +100454,22 @@
100201 }else{
100202 cx = c;
100203 }
100204 while( (c2 = *(zString++))!=0 ){
100205 if( c2!=c && c2!=cx ) continue;
100206 if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
100207 }
100208 }else{
100209 while( (c2 = Utf8Read(zString))!=0 ){
100210 if( c2!=c ) continue;
100211 if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
100212 }
100213 }
100214 return 0;
100215 }
100216 if( c==matchOther ){
100217 if( esc ){
100218 c = sqlite3Utf8Read(&zPattern);
100219 if( c==0 ) return 0;
100220 zEscaped = zPattern;
100221 }else{
100222 u32 prior_c = 0;
@@ -100252,11 +100505,11 @@
100252 continue;
100253 }
100254 }
100255 c2 = Utf8Read(zString);
100256 if( c==c2 ) continue;
100257 if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
100258 continue;
100259 }
100260 if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
100261 return 0;
100262 }
@@ -100265,11 +100518,11 @@
100265
100266 /*
100267 ** The sqlite3_strglob() interface.
100268 */
100269 SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
100270 return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
100271 }
100272
100273 /*
100274 ** The sqlite3_strlike() interface.
100275 */
@@ -100303,13 +100556,14 @@
100303 sqlite3_context *context,
100304 int argc,
100305 sqlite3_value **argv
100306 ){
100307 const unsigned char *zA, *zB;
100308 u32 escape = 0;
100309 int nPat;
100310 sqlite3 *db = sqlite3_context_db_handle(context);
 
100311
100312 #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
100313 if( sqlite3_value_type(argv[0])==SQLITE_BLOB
100314 || sqlite3_value_type(argv[1])==SQLITE_BLOB
100315 ){
@@ -100345,17 +100599,17 @@
100345 sqlite3_result_error(context,
100346 "ESCAPE expression must be a single character", -1);
100347 return;
100348 }
100349 escape = sqlite3Utf8Read(&zEsc);
 
 
100350 }
100351 if( zA && zB ){
100352 struct compareInfo *pInfo = sqlite3_user_data(context);
100353 #ifdef SQLITE_TEST
100354 sqlite3_like_count++;
100355 #endif
100356
100357 sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
100358 }
100359 }
100360
100361 /*
@@ -104328,11 +104582,11 @@
104328 if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
104329 if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
104330 assert( pParse->nested==0 );
104331 pik_flags |= OPFLAG_NCHANGE;
104332 }
104333 if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags);
104334 }
104335 if( !HasRowid(pTab) ) return;
104336 regData = regNewData + 1;
104337 regRec = sqlite3GetTempReg(pParse);
104338 sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
@@ -104744,13 +104998,13 @@
104744 }else{
104745 addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
104746 assert( (pDest->tabFlags & TF_Autoincrement)==0 );
104747 }
104748 sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
104749 sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
 
104750 sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
104751 sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
104752 sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
104753 sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
104754 sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
104755 }else{
104756 sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName);
@@ -107199,19 +107453,21 @@
107199 { OP_IfPos, 1, 8, 0},
107200 { OP_Integer, 0, 1, 0}, /* 6 */
107201 { OP_Noop, 0, 0, 0},
107202 { OP_ResultRow, 1, 1, 0},
107203 };
107204 int addr;
107205 sqlite3VdbeUsesBtree(v, iDb);
107206 if( !zRight ){
107207 setOneColumnName(v, "cache_size");
107208 pParse->nMem += 2;
107209 addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
107210 sqlite3VdbeChangeP1(v, addr, iDb);
107211 sqlite3VdbeChangeP1(v, addr+1, iDb);
107212 sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
 
 
107213 }else{
107214 int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
107215 sqlite3BeginWriteOperation(pParse, 0, iDb);
107216 sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
107217 sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
@@ -107453,17 +107709,20 @@
107453 { OP_If, 1, 0, 0}, /* 2 */
107454 { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
107455 { OP_Integer, 0, 1, 0}, /* 4 */
107456 { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
107457 };
107458 int iAddr;
107459 iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
107460 sqlite3VdbeChangeP1(v, iAddr, iDb);
107461 sqlite3VdbeChangeP1(v, iAddr+1, iDb);
107462 sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
107463 sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
107464 sqlite3VdbeChangeP1(v, iAddr+5, iDb);
 
 
 
107465 sqlite3VdbeUsesBtree(v, iDb);
107466 }
107467 }
107468 break;
107469 }
@@ -108165,22 +108424,10 @@
108165 ** without most of the overhead of a full integrity-check.
108166 */
108167 case PragTyp_INTEGRITY_CHECK: {
108168 int i, j, addr, mxErr;
108169
108170 /* Code that appears at the end of the integrity check. If no error
108171 ** messages have been generated, output OK. Otherwise output the
108172 ** error message
108173 */
108174 static const int iLn = VDBE_OFFSET_LINENO(2);
108175 static const VdbeOpList endCode[] = {
108176 { OP_AddImm, 1, 0, 0}, /* 0 */
108177 { OP_If, 1, 0, 0}, /* 1 */
108178 { OP_String8, 0, 3, 0}, /* 2 */
108179 { OP_ResultRow, 3, 1, 0},
108180 };
108181
108182 int isQuick = (sqlite3Tolower(zLeft[0])=='q');
108183
108184 /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
108185 ** then iDb is set to the index of the database identified by <db>.
108186 ** In this case, the integrity of database iDb only is verified by
@@ -108373,14 +108620,28 @@
108373 sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
108374 }
108375 #endif /* SQLITE_OMIT_BTREECOUNT */
108376 }
108377 }
108378 addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
108379 sqlite3VdbeChangeP2(v, addr, -mxErr);
108380 sqlite3VdbeJumpHere(v, addr+1);
108381 sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108382 }
108383 break;
108384 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
108385
108386 #ifndef SQLITE_OMIT_UTF16
@@ -108493,26 +108754,32 @@
108493 static const VdbeOpList setCookie[] = {
108494 { OP_Transaction, 0, 1, 0}, /* 0 */
108495 { OP_Integer, 0, 1, 0}, /* 1 */
108496 { OP_SetCookie, 0, 0, 1}, /* 2 */
108497 };
108498 int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
108499 sqlite3VdbeChangeP1(v, addr, iDb);
108500 sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
108501 sqlite3VdbeChangeP1(v, addr+2, iDb);
108502 sqlite3VdbeChangeP2(v, addr+2, iCookie);
 
 
 
108503 }else{
108504 /* Read the specified cookie value */
108505 static const VdbeOpList readCookie[] = {
108506 { OP_Transaction, 0, 0, 0}, /* 0 */
108507 { OP_ReadCookie, 0, 1, 0}, /* 1 */
108508 { OP_ResultRow, 1, 1, 0}
108509 };
108510 int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
108511 sqlite3VdbeChangeP1(v, addr, iDb);
108512 sqlite3VdbeChangeP1(v, addr+1, iDb);
108513 sqlite3VdbeChangeP3(v, addr+1, iCookie);
 
 
 
108514 sqlite3VdbeSetNumCols(v, 1);
108515 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
108516 }
108517 }
108518 break;
@@ -108875,65 +109142,31 @@
108875 int rc;
108876 int i;
108877 #ifndef SQLITE_OMIT_DEPRECATED
108878 int size;
108879 #endif
108880 Table *pTab;
108881 Db *pDb;
108882 char const *azArg[4];
108883 int meta[5];
108884 InitData initData;
108885 char const *zMasterSchema;
108886 char const *zMasterName;
108887 int openedTransaction = 0;
108888
108889 /*
108890 ** The master database table has a structure like this
108891 */
108892 static const char master_schema[] =
108893 "CREATE TABLE sqlite_master(\n"
108894 " type text,\n"
108895 " name text,\n"
108896 " tbl_name text,\n"
108897 " rootpage integer,\n"
108898 " sql text\n"
108899 ")"
108900 ;
108901 #ifndef SQLITE_OMIT_TEMPDB
108902 static const char temp_master_schema[] =
108903 "CREATE TEMP TABLE sqlite_temp_master(\n"
108904 " type text,\n"
108905 " name text,\n"
108906 " tbl_name text,\n"
108907 " rootpage integer,\n"
108908 " sql text\n"
108909 ")"
108910 ;
108911 #else
108912 #define temp_master_schema 0
108913 #endif
108914
108915 assert( iDb>=0 && iDb<db->nDb );
108916 assert( db->aDb[iDb].pSchema );
108917 assert( sqlite3_mutex_held(db->mutex) );
108918 assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
108919
108920 /* zMasterSchema and zInitScript are set to point at the master schema
108921 ** and initialisation script appropriate for the database being
108922 ** initialized. zMasterName is the name of the master table.
108923 */
108924 if( !OMIT_TEMPDB && iDb==1 ){
108925 zMasterSchema = temp_master_schema;
108926 }else{
108927 zMasterSchema = master_schema;
108928 }
108929 zMasterName = SCHEMA_TABLE(iDb);
108930
108931 /* Construct the schema tables. */
108932 azArg[0] = zMasterName;
108933 azArg[1] = "1";
108934 azArg[2] = zMasterSchema;
 
108935 azArg[3] = 0;
108936 initData.db = db;
108937 initData.iDb = iDb;
108938 initData.rc = SQLITE_OK;
108939 initData.pzErrMsg = pzErrMsg;
@@ -108940,14 +109173,10 @@
108940 sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
108941 if( initData.rc ){
108942 rc = initData.rc;
108943 goto error_out;
108944 }
108945 pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
108946 if( ALWAYS(pTab) ){
108947 pTab->tabFlags |= TF_Readonly;
108948 }
108949
108950 /* Create a cursor to hold the database open
108951 */
108952 pDb = &db->aDb[iDb];
108953 if( pDb->pBt==0 ){
@@ -109062,11 +109291,11 @@
109062 */
109063 assert( db->init.busy );
109064 {
109065 char *zSql;
109066 zSql = sqlite3MPrintf(db,
109067 "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
109068 db->aDb[iDb].zName, zMasterName);
109069 #ifndef SQLITE_OMIT_AUTHORIZATION
109070 {
109071 sqlite3_xauth xAuth;
109072 xAuth = db->xAuth;
@@ -109688,10 +109917,11 @@
109688 int nOBSat; /* Number of ORDER BY terms satisfied by indices */
109689 int iECursor; /* Cursor number for the sorter */
109690 int regReturn; /* Register holding block-output return address */
109691 int labelBkOut; /* Start label for the block-output subroutine */
109692 int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
 
109693 u8 sortFlags; /* Zero or more SORTFLAG_* bits */
109694 };
109695 #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
109696
109697 /*
@@ -109745,33 +109975,41 @@
109745 Expr *pOffset /* OFFSET value. NULL means no offset */
109746 ){
109747 Select *pNew;
109748 Select standin;
109749 sqlite3 *db = pParse->db;
109750 pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
109751 if( pNew==0 ){
109752 assert( db->mallocFailed );
109753 pNew = &standin;
109754 memset(pNew, 0, sizeof(*pNew));
109755 }
109756 if( pEList==0 ){
109757 pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
109758 }
109759 pNew->pEList = pEList;
 
 
 
 
 
 
 
 
 
 
109760 if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
109761 pNew->pSrc = pSrc;
109762 pNew->pWhere = pWhere;
109763 pNew->pGroupBy = pGroupBy;
109764 pNew->pHaving = pHaving;
109765 pNew->pOrderBy = pOrderBy;
109766 pNew->selFlags = selFlags;
109767 pNew->op = TK_SELECT;
109768 pNew->pLimit = pLimit;
109769 pNew->pOffset = pOffset;
 
109770 assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
109771 pNew->addrOpenEphm[0] = -1;
109772 pNew->addrOpenEphm[1] = -1;
109773 if( db->mallocFailed ) {
109774 clearSelect(db, pNew, pNew!=&standin);
109775 pNew = 0;
109776 }else{
109777 assert( pNew->pSrc!=0 || pParse->nErr>0 );
@@ -110142,10 +110380,11 @@
110142 int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
110143 int regBase; /* Regs for sorter record */
110144 int regRecord = ++pParse->nMem; /* Assembled sorter record */
110145 int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
110146 int op; /* Opcode to add sorter record to sorter */
 
110147
110148 assert( bSeq==0 || bSeq==1 );
110149 assert( nData==1 || regData==regOrigData );
110150 if( nPrefixReg ){
110151 assert( nPrefixReg==nExpr+bSeq );
@@ -110152,19 +110391,21 @@
110152 regBase = regData - nExpr - bSeq;
110153 }else{
110154 regBase = pParse->nMem + 1;
110155 pParse->nMem += nBase;
110156 }
 
 
 
110157 sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
110158 SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
110159 if( bSeq ){
110160 sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
110161 }
110162 if( nPrefixReg==0 ){
110163 sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
110164 }
110165
110166 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
110167 if( nOBSat>0 ){
110168 int regPrevKey; /* The first nOBSat columns of the previous row */
110169 int addrFirst; /* Address of the OP_IfNot opcode */
110170 int addrJmp; /* Address of the OP_Jump opcode */
@@ -110195,10 +110436,14 @@
110195 sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
110196 pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
110197 pSort->regReturn = ++pParse->nMem;
110198 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
110199 sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
 
 
 
 
110200 sqlite3VdbeJumpHere(v, addrFirst);
110201 sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
110202 sqlite3VdbeJumpHere(v, addrJmp);
110203 }
110204 if( pSort->sortFlags & SORTFLAG_UseSorter ){
@@ -110205,18 +110450,12 @@
110205 op = OP_SorterInsert;
110206 }else{
110207 op = OP_IdxInsert;
110208 }
110209 sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
110210 if( pSelect->iLimit ){
110211 int addr;
110212 int iLimit;
110213 if( pSelect->iOffset ){
110214 iLimit = pSelect->iOffset+1;
110215 }else{
110216 iLimit = pSelect->iLimit;
110217 }
110218 addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
110219 sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
110220 sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
110221 sqlite3VdbeJumpHere(v, addr);
110222 }
@@ -110629,19 +110868,20 @@
110629 /*
110630 ** Allocate a KeyInfo object sufficient for an index of N key columns and
110631 ** X extra columns.
110632 */
110633 SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
110634 KeyInfo *p = sqlite3DbMallocZero(0,
110635 sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
110636 if( p ){
110637 p->aSortOrder = (u8*)&p->aColl[N+X];
110638 p->nField = (u16)N;
110639 p->nXField = (u16)X;
110640 p->enc = ENC(db);
110641 p->db = db;
110642 p->nRef = 1;
 
110643 }else{
110644 db->mallocFailed = 1;
110645 }
110646 return p;
110647 }
@@ -110816,11 +111056,11 @@
110816 SortCtx *pSort, /* Information on the ORDER BY clause */
110817 int nColumn, /* Number of columns of data */
110818 SelectDest *pDest /* Write the sorted results here */
110819 ){
110820 Vdbe *v = pParse->pVdbe; /* The prepared statement */
110821 int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
110822 int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
110823 int addr;
110824 int addrOnce = 0;
110825 int iTab;
110826 ExprList *pOrderBy = pSort->pOrderBy;
@@ -110835,10 +111075,11 @@
110835 int bSeq; /* True if sorter record includes seq. no. */
110836 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
110837 struct ExprList_item *aOutEx = p->pEList->a;
110838 #endif
110839
 
110840 if( pSort->labelBkOut ){
110841 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
110842 sqlite3VdbeGoto(v, addrBreak);
110843 sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
110844 }
@@ -116425,12 +116666,12 @@
116425 /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
116426 ** is a pointer to the sub-vdbe containing the trigger program. */
116427 if( pPrg ){
116428 int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
116429
116430 sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
116431 sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
116432 VdbeComment(
116433 (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
116434
116435 /* Set the P5 operand of the OP_Program instruction to non-zero if
116436 ** recursive invocation of this trigger program is disallowed. Recursive
@@ -118780,11 +119021,11 @@
118780 Expr *pExpr /* First argument to the function */
118781 ){
118782 Table *pTab;
118783 sqlite3_vtab *pVtab;
118784 sqlite3_module *pMod;
118785 void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
118786 void *pArg = 0;
118787 FuncDef *pNew;
118788 int rc = 0;
118789 char *zLowerName;
118790 unsigned char *z;
@@ -118808,11 +119049,11 @@
118808 zLowerName = sqlite3DbStrDup(db, pDef->zName);
118809 if( zLowerName ){
118810 for(z=(unsigned char*)zLowerName; *z; z++){
118811 *z = sqlite3UpperToLower[*z];
118812 }
118813 rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
118814 sqlite3DbFree(db, zLowerName);
118815 }
118816 if( rc==0 ){
118817 return pDef;
118818 }
@@ -118825,11 +119066,11 @@
118825 return pDef;
118826 }
118827 *pNew = *pDef;
118828 pNew->zName = (char *)&pNew[1];
118829 memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
118830 pNew->xFunc = xFunc;
118831 pNew->pUserData = pArg;
118832 pNew->funcFlags |= SQLITE_FUNC_EPHEM;
118833 return pNew;
118834 }
118835
@@ -119845,12 +120086,11 @@
119845 n--;
119846 }
119847
119848 /* Code the OP_Affinity opcode if there is anything left to do. */
119849 if( n>0 ){
119850 sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
119851 sqlite3VdbeChangeP4(v, -1, zAff, n);
119852 sqlite3ExprCacheAffinityChange(pParse, base, n);
119853 }
119854 }
119855
119856
@@ -121398,10 +121638,11 @@
121398 int cnt; /* Number of non-wildcard prefix characters */
121399 char wc[3]; /* Wildcard characters */
121400 sqlite3 *db = pParse->db; /* Database connection */
121401 sqlite3_value *pVal = 0;
121402 int op; /* Opcode of pRight */
 
121403
121404 if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
121405 return 0;
121406 }
121407 #ifdef SQLITE_EBCDIC
@@ -121463,12 +121704,13 @@
121463 }else{
121464 z = 0;
121465 }
121466 }
121467
 
121468 sqlite3ValueFree(pVal);
121469 return (z!=0);
121470 }
121471 #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
121472
121473
121474 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -126875,12 +127117,11 @@
126875 testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
126876 if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){
126877 Bitmask b = pTabItem->colUsed;
126878 int n = 0;
126879 for(; b; b=b>>1, n++){}
126880 sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1,
126881 SQLITE_INT_TO_PTR(n), P4_INT32);
126882 assert( n<=pTab->nCol );
126883 }
126884 #ifdef SQLITE_ENABLE_CURSOR_HINTS
126885 if( pLoop->u.btree.pIndex!=0 ){
126886 sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
@@ -129343,18 +129584,15 @@
129343 ** { ... } // User supplied code
129344 ** #line <lineno> <thisfile>
129345 ** break;
129346 */
129347 /********** Begin reduce actions **********************************************/
129348 case 5: /* explain ::= */
129349 { sqlite3BeginParse(pParse, 0); }
129350 break;
129351 case 6: /* explain ::= EXPLAIN */
129352 { sqlite3BeginParse(pParse, 1); }
129353 break;
129354 case 7: /* explain ::= EXPLAIN QUERY PLAN */
129355 { sqlite3BeginParse(pParse, 2); }
129356 break;
129357 case 8: /* cmdx ::= cmd */
129358 { sqlite3FinishCoding(pParse); }
129359 break;
129360 case 9: /* cmd ::= BEGIN transtype trans_opt */
@@ -130525,10 +130763,11 @@
130525 /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
130526 /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
130527 /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
130528 /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
130529 /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
 
130530 /* (10) trans_opt ::= */ yytestcase(yyruleno==10);
130531 /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
130532 /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
130533 /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
130534 /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
@@ -133601,11 +133840,11 @@
133601 sqlite3 *db,
133602 const char *zFunctionName,
133603 int nArg,
133604 int enc,
133605 void *pUserData,
133606 void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
133607 void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133608 void (*xFinal)(sqlite3_context*),
133609 FuncDestructor *pDestructor
133610 ){
133611 FuncDef *p;
@@ -133612,13 +133851,13 @@
133612 int nName;
133613 int extraFlags;
133614
133615 assert( sqlite3_mutex_held(db->mutex) );
133616 if( zFunctionName==0 ||
133617 (xFunc && (xFinal || xStep)) ||
133618 (!xFunc && (xFinal && !xStep)) ||
133619 (!xFunc && (!xFinal && xStep)) ||
133620 (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
133621 (255<(nName = sqlite3Strlen30( zFunctionName))) ){
133622 return SQLITE_MISUSE_BKPT;
133623 }
133624
@@ -133637,14 +133876,14 @@
133637 if( enc==SQLITE_UTF16 ){
133638 enc = SQLITE_UTF16NATIVE;
133639 }else if( enc==SQLITE_ANY ){
133640 int rc;
133641 rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
133642 pUserData, xFunc, xStep, xFinal, pDestructor);
133643 if( rc==SQLITE_OK ){
133644 rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
133645 pUserData, xFunc, xStep, xFinal, pDestructor);
133646 }
133647 if( rc!=SQLITE_OK ){
133648 return rc;
133649 }
133650 enc = SQLITE_UTF16BE;
@@ -133684,12 +133923,11 @@
133684 pDestructor->nRef++;
133685 }
133686 p->pDestructor = pDestructor;
133687 p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
133688 testcase( p->funcFlags & SQLITE_DETERMINISTIC );
133689 p->xFunc = xFunc;
133690 p->xStep = xStep;
133691 p->xFinalize = xFinal;
133692 p->pUserData = pUserData;
133693 p->nArg = (u16)nArg;
133694 return SQLITE_OK;
133695 }
@@ -133701,25 +133939,25 @@
133701 sqlite3 *db,
133702 const char *zFunc,
133703 int nArg,
133704 int enc,
133705 void *p,
133706 void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
133707 void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133708 void (*xFinal)(sqlite3_context*)
133709 ){
133710 return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
133711 xFinal, 0);
133712 }
133713
133714 SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
133715 sqlite3 *db,
133716 const char *zFunc,
133717 int nArg,
133718 int enc,
133719 void *p,
133720 void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
133721 void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133722 void (*xFinal)(sqlite3_context*),
133723 void (*xDestroy)(void *)
133724 ){
133725 int rc = SQLITE_ERROR;
@@ -133738,11 +133976,11 @@
133738 goto out;
133739 }
133740 pArg->xDestroy = xDestroy;
133741 pArg->pUserData = p;
133742 }
133743 rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
133744 if( pArg && pArg->nRef==0 ){
133745 assert( rc!=SQLITE_OK );
133746 xDestroy(p);
133747 sqlite3DbFree(db, pArg);
133748 }
@@ -133758,11 +133996,11 @@
133758 sqlite3 *db,
133759 const void *zFunctionName,
133760 int nArg,
133761 int eTextRep,
133762 void *p,
133763 void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
133764 void (*xStep)(sqlite3_context*,int,sqlite3_value**),
133765 void (*xFinal)(sqlite3_context*)
133766 ){
133767 int rc;
133768 char *zFunc8;
@@ -133771,11 +134009,11 @@
133771 if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT;
133772 #endif
133773 sqlite3_mutex_enter(db->mutex);
133774 assert( !db->mallocFailed );
133775 zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
133776 rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
133777 sqlite3DbFree(db, zFunc8);
133778 rc = sqlite3ApiExit(db, rc);
133779 sqlite3_mutex_leave(db->mutex);
133780 return rc;
133781 }
@@ -134996,11 +135234,10 @@
134996 sqlite3GlobalConfig.nLookaside);
134997
134998 sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
134999
135000 opendb_out:
135001 sqlite3_free(zOpen);
135002 if( db ){
135003 assert( db->mutex!=0 || isThreadsafe==0
135004 || sqlite3GlobalConfig.bFullMutex==0 );
135005 sqlite3_mutex_leave(db->mutex);
135006 }
@@ -135033,10 +135270,11 @@
135033 }
135034 sqlite3_key_v2(db, 0, zKey, i/2);
135035 }
135036 }
135037 #endif
 
135038 return rc & 0xff;
135039 }
135040
135041 /*
135042 ** Open a new database handle.
@@ -135450,10 +135688,13 @@
135450 *(sqlite3_file**)pArg = fd;
135451 rc = SQLITE_OK;
135452 }else if( op==SQLITE_FCNTL_VFS_POINTER ){
135453 *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
135454 rc = SQLITE_OK;
 
 
 
135455 }else if( fd->pMethods ){
135456 rc = sqlite3OsFileControl(fd, op, pArg);
135457 }else{
135458 rc = SQLITE_NOTFOUND;
135459 }
@@ -161083,11 +161324,11 @@
161083 */
161084 static void *rbuMalloc(sqlite3rbu *p, int nByte){
161085 void *pRet = 0;
161086 if( p->rc==SQLITE_OK ){
161087 assert( nByte>0 );
161088 pRet = sqlite3_malloc(nByte);
161089 if( pRet==0 ){
161090 p->rc = SQLITE_NOMEM;
161091 }else{
161092 memset(pRet, 0, nByte);
161093 }
@@ -161129,12 +161370,12 @@
161129 static char *rbuStrndup(const char *zStr, int *pRc){
161130 char *zRet = 0;
161131
161132 assert( *pRc==SQLITE_OK );
161133 if( zStr ){
161134 int nCopy = strlen(zStr) + 1;
161135 zRet = (char*)sqlite3_malloc(nCopy);
161136 if( zRet ){
161137 memcpy(zRet, zStr, nCopy);
161138 }else{
161139 *pRc = SQLITE_NOMEM;
161140 }
@@ -162478,11 +162719,11 @@
162478
162479 pRbu->pgsz = iAmt;
162480 if( pRbu->nFrame==pRbu->nFrameAlloc ){
162481 int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
162482 RbuFrame *aNew;
162483 aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame));
162484 if( aNew==0 ) return SQLITE_NOMEM;
162485 pRbu->aFrame = aNew;
162486 pRbu->nFrameAlloc = nNew;
162487 }
162488
@@ -162543,11 +162784,11 @@
162543
162544 nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
162545 if( nChar==0 ){
162546 return 0;
162547 }
162548 zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
162549 if( zWideFilename==0 ){
162550 return 0;
162551 }
162552 memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
162553 nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
@@ -163177,15 +163418,16 @@
163177 const char *zTarget,
163178 const char *zRbu,
163179 const char *zState
163180 ){
163181 sqlite3rbu *p;
163182 int nTarget = strlen(zTarget);
163183 int nRbu = strlen(zRbu);
163184 int nState = zState ? strlen(zState) : 0;
 
163185
163186 p = (sqlite3rbu*)sqlite3_malloc(sizeof(sqlite3rbu)+nTarget+1+nRbu+1+nState+1);
163187 if( p ){
163188 RbuState *pState = 0;
163189
163190 /* Create the custom VFS. */
163191 memset(p, 0, sizeof(sqlite3rbu));
@@ -163318,11 +163560,11 @@
163318 ** the pattern "rbu_imp_[0-9]*".
163319 */
163320 static void rbuEditErrmsg(sqlite3rbu *p){
163321 if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
163322 int i;
163323 int nErrmsg = strlen(p->zErrmsg);
163324 for(i=0; i<(nErrmsg-8); i++){
163325 if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
163326 int nDel = 8;
163327 while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
163328 memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
@@ -163782,11 +164024,11 @@
163782 ** instead of a file on disk. */
163783 assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
163784 if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
163785 if( iRegion<=p->nShm ){
163786 int nByte = (iRegion+1) * sizeof(char*);
163787 char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
163788 if( apNew==0 ){
163789 rc = SQLITE_NOMEM;
163790 }else{
163791 memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
163792 p->apShm = apNew;
@@ -163793,11 +164035,11 @@
163793 p->nShm = iRegion+1;
163794 }
163795 }
163796
163797 if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
163798 char *pNew = (char*)sqlite3_malloc(szRegion);
163799 if( pNew==0 ){
163800 rc = SQLITE_NOMEM;
163801 }else{
163802 memset(pNew, 0, szRegion);
163803 p->apShm[iRegion] = pNew;
@@ -163903,11 +164145,11 @@
163903 /* A main database has just been opened. The following block sets
163904 ** (pFd->zWal) to point to a buffer owned by SQLite that contains
163905 ** the name of the *-wal file this db connection will use. SQLite
163906 ** happens to pass a pointer to this buffer when using xAccess()
163907 ** or xOpen() to operate on the *-wal file. */
163908 int n = strlen(zName);
163909 const char *z = &zName[n];
163910 if( flags & SQLITE_OPEN_URI ){
163911 int odd = 0;
163912 while( 1 ){
163913 if( z[0]==0 ){
@@ -163929,12 +164171,12 @@
163929 if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
163930 /* This call is to open a *-wal file. Intead, open the *-oal. This
163931 ** code ensures that the string passed to xOpen() is terminated by a
163932 ** pair of '\0' bytes in case the VFS attempts to extract a URI
163933 ** parameter from it. */
163934 int nCopy = strlen(zName);
163935 char *zCopy = sqlite3_malloc(nCopy+2);
163936 if( zCopy ){
163937 memcpy(zCopy, zName, nCopy);
163938 zCopy[nCopy-3] = 'o';
163939 zCopy[nCopy] = '\0';
163940 zCopy[nCopy+1] = '\0';
@@ -164159,17 +164401,17 @@
164159 0, /* xCurrentTimeInt64 (version 2) */
164160 0, 0, 0 /* Unimplemented version 3 methods */
164161 };
164162
164163 rbu_vfs *pNew = 0; /* Newly allocated VFS */
164164 int nName;
164165 int rc = SQLITE_OK;
 
 
164166
164167 int nByte;
164168 nName = strlen(zName);
164169 nByte = sizeof(rbu_vfs) + nName + 1;
164170 pNew = (rbu_vfs*)sqlite3_malloc(nByte);
164171 if( pNew==0 ){
164172 rc = SQLITE_NOMEM;
164173 }else{
164174 sqlite3_vfs *pParent; /* Parent VFS */
164175 memset(pNew, 0, nByte);
@@ -167174,10 +167416,13 @@
167174 ** If parameter iCol is greater than or equal to the number of columns
167175 ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
167176 ** an OOM condition or IO error), an appropriate SQLite error code is
167177 ** returned.
167178 **
 
 
 
167179 ** xColumnText:
167180 ** This function attempts to retrieve the text of column iCol of the
167181 ** current document. If successful, (*pz) is set to point to a buffer
167182 ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
167183 ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -167194,18 +167439,32 @@
167194 ** xInstCount:
167195 ** Set *pnInst to the total number of occurrences of all phrases within
167196 ** the query within the current row. Return SQLITE_OK if successful, or
167197 ** an error code (i.e. SQLITE_NOMEM) if an error occurs.
167198 **
 
 
 
 
 
167199 ** xInst:
167200 ** Query for the details of phrase match iIdx within the current row.
167201 ** Phrase matches are numbered starting from zero, so the iIdx argument
167202 ** should be greater than or equal to zero and smaller than the value
167203 ** output by xInstCount().
 
 
 
 
 
 
167204 **
167205 ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
167206 ** if an error occurs.
 
 
 
167207 **
167208 ** xRowid:
167209 ** Returns the rowid of the current row.
167210 **
167211 ** xTokenize:
@@ -167286,25 +167545,63 @@
167286 ** through instances of phrase iPhrase, use the following code:
167287 **
167288 ** Fts5PhraseIter iter;
167289 ** int iCol, iOff;
167290 ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
167291 ** iOff>=0;
167292 ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
167293 ** ){
167294 ** // An instance of phrase iPhrase at offset iOff of column iCol
167295 ** }
167296 **
167297 ** The Fts5PhraseIter structure is defined above. Applications should not
167298 ** modify this structure directly - it should only be used as shown above
167299 ** with the xPhraseFirst() and xPhraseNext() API methods.
 
 
 
 
 
 
 
167300 **
167301 ** xPhraseNext()
167302 ** See xPhraseFirst above.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167303 */
167304 struct Fts5ExtensionApi {
167305 int iVersion; /* Currently always set to 1 */
167306
167307 void *(*xUserData)(Fts5Context*);
167308
167309 int (*xColumnCount)(Fts5Context*);
167310 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -167330,12 +167627,15 @@
167330 int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
167331 );
167332 int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
167333 void *(*xGetAuxdata)(Fts5Context*, int bClear);
167334
167335 void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
167336 void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
 
 
 
167337 };
167338
167339 /*
167340 ** CUSTOM AUXILIARY FUNCTIONS
167341 *************************************************************************/
@@ -167762,10 +168062,11 @@
167762 int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
167763 int eContent; /* An FTS5_CONTENT value */
167764 char *zContent; /* content table */
167765 char *zContentRowid; /* "content_rowid=" option value */
167766 int bColumnsize; /* "columnsize=" option value (dflt==1) */
 
167767 char *zContentExprlist;
167768 Fts5Tokenizer *pTok;
167769 fts5_tokenizer *pTokApi;
167770
167771 /* Values loaded from the %_config table */
@@ -167790,10 +168091,13 @@
167790
167791 #define FTS5_CONTENT_NORMAL 0
167792 #define FTS5_CONTENT_NONE 1
167793 #define FTS5_CONTENT_EXTERNAL 2
167794
 
 
 
167795
167796
167797
167798 static int sqlite3Fts5ConfigParse(
167799 Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
@@ -167832,17 +168136,17 @@
167832 ** Buffer object for the incremental building of string data.
167833 */
167834 typedef struct Fts5Buffer Fts5Buffer;
167835 struct Fts5Buffer {
167836 u8 *p;
167837 int n;
167838 int nSpace;
167839 };
167840
167841 static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, int);
167842 static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
167843 static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*);
167844 static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
167845 static void sqlite3Fts5BufferFree(Fts5Buffer*);
167846 static void sqlite3Fts5BufferZero(Fts5Buffer*);
167847 static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
167848 static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
@@ -167903,10 +168207,17 @@
167903 static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
167904
167905 /* Character set tests (like isspace(), isalpha() etc.) */
167906 static int sqlite3Fts5IsBareword(char t);
167907
 
 
 
 
 
 
 
167908 /*
167909 ** End of interface to code in fts5_buffer.c.
167910 **************************************************************************/
167911
167912 /**************************************************************************
@@ -167938,10 +168249,33 @@
167938 ** sqlite3Fts5IterNext(pIter)
167939 ** ){
167940 ** i64 iRowid = sqlite3Fts5IterRowid(pIter);
167941 ** }
167942 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167943
167944 /*
167945 ** Open a new iterator to iterate though all rowids that match the
167946 ** specified token or token prefix.
167947 */
@@ -168024,11 +168358,10 @@
168024 static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
168025
168026 /*
168027 ** Functions called by the storage module as part of integrity-check.
168028 */
168029 static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int);
168030 static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
168031
168032 /*
168033 ** Called during virtual module initialization to register UDF
168034 ** fts5_decode() with SQLite
@@ -168046,10 +168379,12 @@
168046 static int sqlite3Fts5IndexReinit(Fts5Index *p);
168047 static int sqlite3Fts5IndexOptimize(Fts5Index *p);
168048 static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
168049
168050 static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
 
 
168051
168052 /*
168053 ** End of interface to code in fts5_index.c.
168054 **************************************************************************/
168055
@@ -168103,11 +168438,11 @@
168103 typedef struct Fts5Hash Fts5Hash;
168104
168105 /*
168106 ** Create a hash table, free a hash table.
168107 */
168108 static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize);
168109 static void sqlite3Fts5HashFree(Fts5Hash*);
168110
168111 static int sqlite3Fts5HashWrite(
168112 Fts5Hash*,
168113 i64 iRowid, /* Rowid for this entry */
@@ -168162,11 +168497,11 @@
168162 static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
168163
168164 static int sqlite3Fts5DropAll(Fts5Config*);
168165 static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
168166
168167 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64);
168168 static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
168169 static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
168170
168171 static int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
168172
@@ -168182,12 +168517,10 @@
168182
168183 static int sqlite3Fts5StorageConfigValue(
168184 Fts5Storage *p, const char*, sqlite3_value*, int
168185 );
168186
168187 static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**);
168188
168189 static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
168190 static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
168191 static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
168192 static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
168193
@@ -168239,12 +168572,22 @@
168239 static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
168240
168241 static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
168242 static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
168243 static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
 
 
 
 
 
 
 
 
168244
168245 static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
 
 
168246
168247 /*******************************************
168248 ** The fts5_expr.c API above this point is used by the other hand-written
168249 ** C code in this module. The interfaces below this point are called by
168250 ** the parser code in fts5parse.y. */
@@ -170120,12 +170463,12 @@
170120
170121
170122
170123 /* #include "fts5Int.h" */
170124
170125 static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, int nByte){
170126 int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
170127 u8 *pNew;
170128 while( nNew<nByte ){
170129 nNew = nNew * 2;
170130 }
170131 pNew = sqlite3_realloc(pBuf->p, nNew);
@@ -170166,14 +170509,14 @@
170166 ** is called, it is a no-op.
170167 */
170168 static void sqlite3Fts5BufferAppendBlob(
170169 int *pRc,
170170 Fts5Buffer *pBuf,
170171 int nData,
170172 const u8 *pData
170173 ){
170174 assert( *pRc || nData>=0 );
170175 if( fts5BufferGrow(pRc, pBuf, nData) ) return;
170176 memcpy(&pBuf->p[pBuf->n], pData, nData);
170177 pBuf->n += nData;
170178 }
170179
@@ -170397,10 +170740,96 @@
170397
170398 return (t & 0x80) || aBareword[(int)t];
170399 }
170400
170401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170402
170403 /*
170404 ** 2014 Jun 09
170405 **
170406 ** The author disclaims copyright to this source code. In place of
@@ -170412,11 +170841,10 @@
170412 **
170413 ******************************************************************************
170414 **
170415 ** This is an SQLite module implementing full-text search.
170416 */
170417
170418
170419
170420 /* #include "fts5Int.h" */
170421
170422 #define FTS5_DEFAULT_PAGE_SIZE 4050
@@ -170595,10 +171023,37 @@
170595 if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
170596 fts5Dequote(z);
170597 }
170598 }
170599
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170600 /*
170601 ** Parse a "special" CREATE VIRTUAL TABLE directive and update
170602 ** configuration object pConfig as appropriate.
170603 **
170604 ** If successful, object pConfig is updated and SQLITE_OK returned. If
@@ -170652,11 +171107,11 @@
170652 while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
170653 nPre = nPre*10 + (p[0] - '0');
170654 p++;
170655 }
170656
170657 if( rc==SQLITE_OK && (nPre<=0 || nPre>=1000) ){
170658 *pzErr = sqlite3_mprintf("prefix length out of range (max 999)");
170659 rc = SQLITE_ERROR;
170660 break;
170661 }
170662
@@ -170744,10 +171199,24 @@
170744 }else{
170745 pConfig->bColumnsize = (zArg[0]=='1');
170746 }
170747 return rc;
170748 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170749
170750 *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
170751 return SQLITE_ERROR;
170752 }
170753
@@ -170900,10 +171369,11 @@
170900 pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
170901 pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
170902 pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
170903 pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
170904 pRet->bColumnsize = 1;
 
170905 #ifdef SQLITE_DEBUG
170906 pRet->bPrefixIndex = 1;
170907 #endif
170908 if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
170909 *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
@@ -171346,10 +171816,11 @@
171346 #endif
171347
171348
171349 struct Fts5Expr {
171350 Fts5Index *pIndex;
 
171351 Fts5ExprNode *pRoot;
171352 int bDesc; /* Iterate in descending rowid order */
171353 int nPhrase; /* Number of phrases in expression */
171354 Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */
171355 };
@@ -171541,10 +172012,11 @@
171541 sParse.rc = SQLITE_NOMEM;
171542 sqlite3Fts5ParseNodeFree(sParse.pExpr);
171543 }else{
171544 pNew->pRoot = sParse.pExpr;
171545 pNew->pIndex = 0;
 
171546 pNew->apExprPhrase = sParse.apPhrase;
171547 pNew->nPhrase = sParse.nPhrase;
171548 sParse.apPhrase = 0;
171549 }
171550 }
@@ -171605,12 +172077,13 @@
171605 }
171606
171607 /*
171608 ** Argument pTerm must be a synonym iterator.
171609 */
171610 static int fts5ExprSynonymPoslist(
171611 Fts5ExprTerm *pTerm,
 
171612 Fts5Colset *pColset,
171613 i64 iRowid,
171614 int *pbDel, /* OUT: Caller should sqlite3_free(*pa) */
171615 u8 **pa, int *pn
171616 ){
@@ -171625,13 +172098,20 @@
171625 for(p=pTerm; p; p=p->pSynonym){
171626 Fts5IndexIter *pIter = p->pIter;
171627 if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){
171628 const u8 *a;
171629 int n;
171630 i64 dummy;
171631 rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
 
 
 
 
 
 
171632 if( rc!=SQLITE_OK ) goto synonym_poslist_out;
 
171633 if( nIter==nAlloc ){
171634 int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
171635 Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
171636 if( aNew==0 ){
171637 rc = SQLITE_NOMEM;
@@ -171728,12 +172208,12 @@
171728 i64 dummy;
171729 int n = 0;
171730 int bFlag = 0;
171731 const u8 *a = 0;
171732 if( pTerm->pSynonym ){
171733 rc = fts5ExprSynonymPoslist(
171734 pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
171735 );
171736 }else{
171737 rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
171738 }
171739 if( rc!=SQLITE_OK ) goto ismatch_out;
@@ -172063,34 +172543,55 @@
172063 Fts5Expr *pExpr, /* Expression that pNear is a part of */
172064 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */
172065 ){
172066 Fts5ExprNearset *pNear = pNode->pNear;
172067 int rc = *pRc;
172068 int i;
172069
172070 /* Check that each phrase in the nearset matches the current row.
172071 ** Populate the pPhrase->poslist buffers at the same time. If any
172072 ** phrase is not a match, break out of the loop early. */
172073 for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
172074 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
172075 if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
172076 int bMatch = 0;
172077 rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
172078 if( bMatch==0 ) break;
172079 }else{
172080 rc = sqlite3Fts5IterPoslistBuffer(
172081 pPhrase->aTerm[0].pIter, &pPhrase->poslist
172082 );
172083 }
172084 }
172085
172086 *pRc = rc;
172087 if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
172088 return 1;
172089 }
172090
172091 return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172092 }
172093
172094 static int fts5ExprTokenTest(
172095 Fts5Expr *pExpr, /* Expression that pNear is a part of */
172096 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */
@@ -172109,11 +172610,11 @@
172109 assert( pNode->eType==FTS5_TERM );
172110 assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
172111 assert( pPhrase->aTerm[0].pSynonym==0 );
172112
172113 rc = sqlite3Fts5IterPoslist(pIter, pColset,
172114 (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
172115 );
172116 pNode->bNomatch = (pPhrase->poslist.n==0);
172117 return rc;
172118 }
172119
@@ -172524,10 +173025,13 @@
172524 if( cmp || p2->bNomatch ) break;
172525 rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
172526 }
172527 pNode->bEof = p1->bEof;
172528 pNode->iRowid = p1->iRowid;
 
 
 
172529 break;
172530 }
172531 }
172532 }
172533 return rc;
@@ -172909,10 +173413,11 @@
172909 }
172910
172911 if( rc==SQLITE_OK ){
172912 /* All the allocations succeeded. Put the expression object together. */
172913 pNew->pIndex = pExpr->pIndex;
 
172914 pNew->nPhrase = 1;
172915 pNew->apExprPhrase[0] = sCtx.pPhrase;
172916 pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
172917 pNew->pRoot->pNear->nPhrase = 1;
172918 sCtx.pPhrase->pNode = pNew->pRoot;
@@ -173050,10 +173555,19 @@
173050 static void sqlite3Fts5ParseSetColset(
173051 Fts5Parse *pParse,
173052 Fts5ExprNearset *pNear,
173053 Fts5Colset *pColset
173054 ){
 
 
 
 
 
 
 
 
 
173055 if( pNear ){
173056 pNear->pColset = pColset;
173057 }else{
173058 sqlite3_free(pColset);
173059 }
@@ -173111,15 +173625,24 @@
173111 if( eType==FTS5_STRING ){
173112 int iPhrase;
173113 for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
173114 pNear->apPhrase[iPhrase]->pNode = pRet;
173115 }
173116 if( pNear->nPhrase==1
173117 && pNear->apPhrase[0]->nTerm==1
173118 && pNear->apPhrase[0]->aTerm[0].pSynonym==0
173119 ){
173120 pRet->eType = FTS5_TERM;
 
 
 
 
 
 
 
 
 
173121 }
173122 }else{
173123 fts5ExprAddChildren(pRet, pLeft);
173124 fts5ExprAddChildren(pRet, pRight);
173125 }
@@ -173229,10 +173752,13 @@
173229
173230 zRet = fts5PrintfAppend(zRet, " {");
173231 for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
173232 char *zTerm = pPhrase->aTerm[iTerm].zTerm;
173233 zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
 
 
 
173234 }
173235
173236 if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
173237 if( zRet==0 ) return 0;
173238 }
@@ -173541,10 +174067,232 @@
173541 *pa = 0;
173542 nRet = 0;
173543 }
173544 return nRet;
173545 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173546
173547 /*
173548 ** 2014 August 11
173549 **
173550 ** The author disclaims copyright to this source code. In place of
@@ -173570,10 +174318,11 @@
173570 ** segment.
173571 */
173572
173573
173574 struct Fts5Hash {
 
173575 int *pnByte; /* Pointer to bytes counter */
173576 int nEntry; /* Number of entries currently in hash */
173577 int nSlot; /* Size of aSlot[] array */
173578 Fts5HashEntry *pScan; /* Current ordered scan item */
173579 Fts5HashEntry **aSlot; /* Array of hash slots */
@@ -173606,10 +174355,11 @@
173606
173607 int nAlloc; /* Total size of allocation */
173608 int iSzPoslist; /* Offset of space for 4-byte poslist size */
173609 int nData; /* Total bytes of data (incl. structure) */
173610 u8 bDel; /* Set delete-flag @ iSzPoslist */
 
173611
173612 int iCol; /* Column of last value written */
173613 int iPos; /* Position of last value written */
173614 i64 iRowid; /* Rowid of last value written */
173615 char zKey[8]; /* Nul-terminated entry key */
@@ -173623,11 +174373,11 @@
173623
173624
173625 /*
173626 ** Allocate a new hash table.
173627 */
173628 static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
173629 int rc = SQLITE_OK;
173630 Fts5Hash *pNew;
173631
173632 *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
173633 if( pNew==0 ){
@@ -173634,10 +174384,11 @@
173634 rc = SQLITE_NOMEM;
173635 }else{
173636 int nByte;
173637 memset(pNew, 0, sizeof(Fts5Hash));
173638 pNew->pnByte = pnByte;
 
173639
173640 pNew->nSlot = 1024;
173641 nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
173642 pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
173643 if( pNew->aSlot==0 ){
@@ -173726,30 +174477,50 @@
173726 pHash->nSlot = nNew;
173727 pHash->aSlot = apNew;
173728 return SQLITE_OK;
173729 }
173730
173731 static void fts5HashAddPoslistSize(Fts5HashEntry *p){
173732 if( p->iSzPoslist ){
173733 u8 *pPtr = (u8*)p;
173734 int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
173735 int nPos = nSz*2 + p->bDel; /* Value of nPos field */
173736
173737 assert( p->bDel==0 || p->bDel==1 );
173738 if( nPos<=127 ){
173739 pPtr[p->iSzPoslist] = (u8)nPos;
173740 }else{
173741 int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
173742 memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
173743 sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
173744 p->nData += (nByte-1);
173745 }
173746 p->bDel = 0;
 
 
 
 
 
 
 
 
 
 
173747 p->iSzPoslist = 0;
 
 
173748 }
173749 }
173750
 
 
 
 
 
 
 
 
173751 static int sqlite3Fts5HashWrite(
173752 Fts5Hash *pHash,
173753 i64 iRowid, /* Rowid for this entry */
173754 int iCol, /* Column token appears in (-ve -> delete) */
173755 int iPos, /* Position of token within column */
@@ -173758,10 +174529,13 @@
173758 ){
173759 unsigned int iHash;
173760 Fts5HashEntry *p;
173761 u8 *pPtr;
173762 int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */
 
 
 
173763
173764 /* Attempt to locate an existing hash entry */
173765 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
173766 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
173767 if( p->zKey[0]==bByte
@@ -173772,92 +174546,120 @@
173772 }
173773 }
173774
173775 /* If an existing hash entry cannot be found, create a new one. */
173776 if( p==0 ){
 
173777 int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
173778 if( nByte<128 ) nByte = 128;
173779
 
173780 if( (pHash->nEntry*2)>=pHash->nSlot ){
173781 int rc = fts5HashResize(pHash);
173782 if( rc!=SQLITE_OK ) return rc;
173783 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
173784 }
173785
 
173786 p = (Fts5HashEntry*)sqlite3_malloc(nByte);
173787 if( !p ) return SQLITE_NOMEM;
173788 memset(p, 0, FTS5_HASHENTRYSIZE);
173789 p->nAlloc = nByte;
173790 p->zKey[0] = bByte;
173791 memcpy(&p->zKey[1], pToken, nToken);
173792 assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
173793 p->zKey[nToken+1] = '\0';
173794 p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
173795 p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
173796 p->iSzPoslist = p->nData;
173797 p->nData += 1;
173798 p->iRowid = iRowid;
173799 p->pHashNext = pHash->aSlot[iHash];
173800 pHash->aSlot[iHash] = p;
173801 pHash->nEntry++;
 
 
 
 
 
 
 
 
 
 
 
173802 nIncr += p->nData;
173803 }
173804
173805 /* Check there is enough space to append a new entry. Worst case scenario
173806 ** is:
173807 **
173808 ** + 9 bytes for a new rowid,
173809 ** + 4 byte reserved for the "poslist size" varint.
173810 ** + 1 byte for a "new column" byte,
173811 ** + 3 bytes for a new column number (16-bit max) as a varint,
173812 ** + 5 bytes for the new position offset (32-bit max).
173813 */
173814 if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
173815 int nNew = p->nAlloc * 2;
173816 Fts5HashEntry *pNew;
173817 Fts5HashEntry **pp;
173818 pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
173819 if( pNew==0 ) return SQLITE_NOMEM;
173820 pNew->nAlloc = nNew;
173821 for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
173822 *pp = pNew;
173823 p = pNew;
173824 }
173825 pPtr = (u8*)p;
173826 nIncr -= p->nData;
 
 
 
 
173827
173828 /* If this is a new rowid, append the 4-byte size field for the previous
173829 ** entry, and the new rowid for this entry. */
173830 if( iRowid!=p->iRowid ){
173831 fts5HashAddPoslistSize(p);
173832 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
 
 
173833 p->iSzPoslist = p->nData;
173834 p->nData += 1;
173835 p->iCol = 0;
173836 p->iPos = 0;
173837 p->iRowid = iRowid;
 
173838 }
173839
173840 if( iCol>=0 ){
173841 /* Append a new column value, if necessary */
173842 assert( iCol>=p->iCol );
173843 if( iCol!=p->iCol ){
173844 pPtr[p->nData++] = 0x01;
173845 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
173846 p->iCol = iCol;
173847 p->iPos = 0;
173848 }
173849
173850 /* Append the new position offset */
173851 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
173852 p->iPos = iPos;
 
 
 
 
 
 
 
 
 
 
 
173853 }else{
173854 /* This is a delete. Set the delete flag. */
173855 p->bDel = 1;
173856 }
 
173857 nIncr += p->nData;
173858
173859 *pHash->pnByte += nIncr;
173860 return SQLITE_OK;
173861 }
173862
173863
@@ -173967,11 +174769,11 @@
173967 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
173968 if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
173969 }
173970
173971 if( p ){
173972 fts5HashAddPoslistSize(p);
173973 *ppDoclist = (const u8*)&p->zKey[nTerm+1];
173974 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
173975 }else{
173976 *ppDoclist = 0;
173977 *pnDoclist = 0;
@@ -174003,11 +174805,11 @@
174003 int *pnDoclist /* OUT: size of doclist in bytes */
174004 ){
174005 Fts5HashEntry *p;
174006 if( (p = pHash->pScan) ){
174007 int nTerm = (int)strlen(p->zKey);
174008 fts5HashAddPoslistSize(p);
174009 *pzTerm = p->zKey;
174010 *ppDoclist = (const u8*)&p->zKey[nTerm+1];
174011 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
174012 }else{
174013 *pzTerm = 0;
@@ -174450,10 +175252,13 @@
174450 int iLeafPgno; /* Current leaf page number */
174451 Fts5Data *pLeaf; /* Current leaf data */
174452 Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
174453 int iLeafOffset; /* Byte offset within current leaf */
174454
 
 
 
174455 /* The page and offset from which the current term was read. The offset
174456 ** is the offset of the first rowid in the current doclist. */
174457 int iTermLeafPgno;
174458 int iTermLeafOffset;
174459
@@ -174469,11 +175274,11 @@
174469
174470 /* Variables populated based on current entry. */
174471 Fts5Buffer term; /* Current term */
174472 i64 iRowid; /* Current rowid */
174473 int nPos; /* Number of bytes in current position list */
174474 int bDel; /* True if the delete flag is set */
174475 };
174476
174477 /*
174478 ** Argument is a pointer to an Fts5Data structure that contains a
174479 ** leaf page.
@@ -174482,11 +175287,10 @@
174482 (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
174483 )
174484
174485 #define FTS5_SEGITER_ONETERM 0x01
174486 #define FTS5_SEGITER_REVERSE 0x02
174487
174488
174489 /*
174490 ** Argument is a pointer to an Fts5Data structure that contains a leaf
174491 ** page. This macro evaluates to true if the leaf contains no terms, or
174492 ** false if it contains at least one term.
@@ -175509,17 +176313,33 @@
175509 ** position list content (if any).
175510 */
175511 static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
175512 if( p->rc==SQLITE_OK ){
175513 int iOff = pIter->iLeafOffset; /* Offset to read at */
175514 int nSz;
175515 ASSERT_SZLEAF_OK(pIter->pLeaf);
175516 fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
175517 pIter->bDel = (nSz & 0x0001);
175518 pIter->nPos = nSz>>1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175519 pIter->iLeafOffset = iOff;
175520 assert_nc( pIter->nPos>=0 );
175521 }
175522 }
175523
175524 static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
175525 u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
@@ -175575,10 +176395,24 @@
175575 pIter->iEndofDoclist += nExtra;
175576 }
175577
175578 fts5SegIterLoadRowid(p, pIter);
175579 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175580
175581 /*
175582 ** Initialize the iterator object pIter to iterate through the entries in
175583 ** segment pSeg. The iterator is left pointing to the first entry when
175584 ** this function returns.
@@ -175601,10 +176435,11 @@
175601 return;
175602 }
175603
175604 if( p->rc==SQLITE_OK ){
175605 memset(pIter, 0, sizeof(*pIter));
 
175606 pIter->pSeg = pSeg;
175607 pIter->iLeafPgno = pSeg->pgnoFirst-1;
175608 fts5SegIterNextPage(p, pIter);
175609 }
175610
@@ -175632,10 +176467,11 @@
175632 ** aRowidOffset[] and iRowidOffset variables. At this point the iterator
175633 ** is in its regular state - Fts5SegIter.iLeafOffset points to the first
175634 ** byte of the position list content associated with said rowid.
175635 */
175636 static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
 
175637 int n = pIter->pLeaf->szLeaf;
175638 int i = pIter->iLeafOffset;
175639 u8 *a = pIter->pLeaf->p;
175640 int iRowidOffset = 0;
175641
@@ -175644,19 +176480,28 @@
175644 }
175645
175646 ASSERT_SZLEAF_OK(pIter->pLeaf);
175647 while( 1 ){
175648 i64 iDelta = 0;
175649 int nPos;
175650 int bDummy;
175651
175652 i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
175653 i += nPos;
 
 
 
 
 
 
 
 
 
 
175654 if( i>=n ) break;
175655 i += fts5GetVarint(&a[i], (u64*)&iDelta);
175656 pIter->iRowid += iDelta;
175657
 
175658 if( iRowidOffset>=pIter->nRowidOffset ){
175659 int nNew = pIter->nRowidOffset + 8;
175660 int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
175661 if( aNew==0 ){
175662 p->rc = SQLITE_NOMEM;
@@ -175730,10 +176575,112 @@
175730 */
175731 static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){
175732 Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
175733 return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
175734 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175735
175736 /*
175737 ** Advance iterator pIter to the next entry.
175738 **
175739 ** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
@@ -175743,144 +176690,135 @@
175743 static void fts5SegIterNext(
175744 Fts5Index *p, /* FTS5 backend object */
175745 Fts5SegIter *pIter, /* Iterator to advance */
175746 int *pbNewTerm /* OUT: Set for new term */
175747 ){
175748 assert( pbNewTerm==0 || *pbNewTerm==0 );
175749 if( p->rc==SQLITE_OK ){
175750 if( pIter->flags & FTS5_SEGITER_REVERSE ){
175751 assert( pIter->pNextLeaf==0 );
175752 if( pIter->iRowidOffset>0 ){
175753 u8 *a = pIter->pLeaf->p;
175754 int iOff;
175755 int nPos;
175756 int bDummy;
175757 i64 iDelta;
175758
175759 pIter->iRowidOffset--;
175760 pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset];
175761 iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
175762 iOff += nPos;
175763 fts5GetVarint(&a[iOff], (u64*)&iDelta);
175764 pIter->iRowid -= iDelta;
175765 fts5SegIterLoadNPos(p, pIter);
175766 }else{
175767 fts5SegIterReverseNewPage(p, pIter);
175768 }
175769 }else{
175770 Fts5Data *pLeaf = pIter->pLeaf;
175771 int iOff;
175772 int bNewTerm = 0;
175773 int nKeep = 0;
175774
175775 /* Search for the end of the position list within the current page. */
175776 u8 *a = pLeaf->p;
175777 int n = pLeaf->szLeaf;
175778
175779 ASSERT_SZLEAF_OK(pLeaf);
175780 iOff = pIter->iLeafOffset + pIter->nPos;
175781
175782 if( iOff<n ){
175783 /* The next entry is on the current page. */
175784 assert_nc( iOff<=pIter->iEndofDoclist );
175785 if( iOff>=pIter->iEndofDoclist ){
175786 bNewTerm = 1;
175787 if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
175788 iOff += fts5GetVarint32(&a[iOff], nKeep);
175789 }
175790 }else{
175791 u64 iDelta;
175792 iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
175793 pIter->iRowid += iDelta;
175794 assert_nc( iDelta>0 );
175795 }
175796 pIter->iLeafOffset = iOff;
175797
175798 }else if( pIter->pSeg==0 ){
175799 const u8 *pList = 0;
175800 const char *zTerm = 0;
175801 int nList = 0;
175802 assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
175803 if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
175804 sqlite3Fts5HashScanNext(p->pHash);
175805 sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
175806 }
175807 if( pList==0 ){
175808 fts5DataRelease(pIter->pLeaf);
175809 pIter->pLeaf = 0;
175810 }else{
175811 pIter->pLeaf->p = (u8*)pList;
175812 pIter->pLeaf->nn = nList;
175813 pIter->pLeaf->szLeaf = nList;
175814 pIter->iEndofDoclist = nList+1;
175815 sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
175816 (u8*)zTerm);
175817 pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
175818 *pbNewTerm = 1;
175819 }
175820 }else{
175821 iOff = 0;
175822 /* Next entry is not on the current page */
175823 while( iOff==0 ){
175824 fts5SegIterNextPage(p, pIter);
175825 pLeaf = pIter->pLeaf;
175826 if( pLeaf==0 ) break;
175827 ASSERT_SZLEAF_OK(pLeaf);
175828 if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
175829 iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
175830 pIter->iLeafOffset = iOff;
175831
175832 if( pLeaf->nn>pLeaf->szLeaf ){
175833 pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
175834 &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
175835 );
175836 }
175837
175838 }
175839 else if( pLeaf->nn>pLeaf->szLeaf ){
175840 pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
175841 &pLeaf->p[pLeaf->szLeaf], iOff
175842 );
175843 pIter->iLeafOffset = iOff;
175844 pIter->iEndofDoclist = iOff;
175845 bNewTerm = 1;
175846 }
175847 if( iOff>=pLeaf->szLeaf ){
175848 p->rc = FTS5_CORRUPT;
175849 return;
175850 }
175851 }
175852 }
175853
175854 /* Check if the iterator is now at EOF. If so, return early. */
175855 if( pIter->pLeaf ){
175856 if( bNewTerm ){
175857 if( pIter->flags & FTS5_SEGITER_ONETERM ){
175858 fts5DataRelease(pIter->pLeaf);
175859 pIter->pLeaf = 0;
175860 }else{
175861 fts5SegIterLoadTerm(p, pIter, nKeep);
175862 fts5SegIterLoadNPos(p, pIter);
175863 if( pbNewTerm ) *pbNewTerm = 1;
175864 }
175865 }else{
175866 /* The following could be done by calling fts5SegIterLoadNPos(). But
175867 ** this block is particularly performance critical, so equivalent
175868 ** code is inlined. */
175869 int nSz;
175870 assert( p->rc==SQLITE_OK );
175871 fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
175872 pIter->bDel = (nSz & 0x0001);
175873 pIter->nPos = nSz>>1;
175874 assert_nc( pIter->nPos>=0 );
175875 }
175876 }
175877 }
175878 }
175879 }
175880
175881 #define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
 
 
 
 
 
175882
175883 /*
175884 ** Iterator pIter currently points to the first rowid in a doclist. This
175885 ** function sets the iterator up so that iterates in reverse order through
175886 ** the doclist.
@@ -175898,11 +176836,21 @@
175898 Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
175899
175900 /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
175901 ** position-list content for the current rowid. Back it up so that it
175902 ** points to the start of the position-list size field. */
175903 pIter->iLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel);
 
 
 
 
 
 
 
 
 
 
175904
175905 /* If this condition is true then the largest rowid for the current
175906 ** term may not be stored on the current page. So search forward to
175907 ** see where said rowid really is. */
175908 if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
@@ -175982,15 +176930,10 @@
175982 }
175983
175984 pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
175985 }
175986
175987 #define fts5IndexSkipVarint(a, iOff) { \
175988 int iEnd = iOff+9; \
175989 while( (a[iOff++] & 0x80) && iOff<iEnd ); \
175990 }
175991
175992 /*
175993 ** The iterator object passed as the second argument currently contains
175994 ** no valid values except for the Fts5SegIter.pLeaf member variable. This
175995 ** function searches the leaf page for a term matching (pTerm/nTerm).
175996 **
@@ -176189,10 +177132,12 @@
176189 fts5SegIterReverse(p, pIter);
176190 }
176191 }
176192 }
176193
 
 
176194 /* Either:
176195 **
176196 ** 1) an error has occurred, or
176197 ** 2) the iterator points to EOF, or
176198 ** 3) the iterator points to an entry with term (pTerm/nTerm), or
@@ -176246,19 +177191,21 @@
176246 if( pLeaf==0 ) return;
176247 pLeaf->p = (u8*)pList;
176248 pLeaf->nn = pLeaf->szLeaf = nList;
176249 pIter->pLeaf = pLeaf;
176250 pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
176251 pIter->iEndofDoclist = pLeaf->nn+1;
176252
176253 if( flags & FTS5INDEX_QUERY_DESC ){
176254 pIter->flags |= FTS5_SEGITER_REVERSE;
176255 fts5SegIterReverseInitPage(p, pIter);
176256 }else{
176257 fts5SegIterLoadNPos(p, pIter);
176258 }
176259 }
 
 
176260 }
176261
176262 /*
176263 ** Zero the iterator passed as the only argument.
176264 */
@@ -176498,11 +177445,11 @@
176498 bMove = 0;
176499 }
176500 }
176501
176502 do{
176503 if( bMove ) fts5SegIterNext(p, pIter, 0);
176504 if( pIter->pLeaf==0 ) break;
176505 if( bRev==0 && pIter->iRowid>=iMatch ) break;
176506 if( bRev!=0 && pIter->iRowid<=iMatch ) break;
176507 bMove = 1;
176508 }while( p->rc==SQLITE_OK );
@@ -176532,11 +177479,13 @@
176532 ){
176533 int i;
176534 for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
176535 int iEq;
176536 if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
176537 fts5SegIterNext(p, &pIter->aSeg[iEq], 0);
 
 
176538 i = pIter->nSeg + iEq;
176539 }
176540 }
176541 }
176542
@@ -176619,11 +177568,11 @@
176619 Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
176620 assert( p->rc==SQLITE_OK );
176621 if( bUseFrom && pSeg->pDlidx ){
176622 fts5SegIterNextFrom(p, pSeg, iFrom);
176623 }else{
176624 fts5SegIterNext(p, pSeg, &bNewTerm);
176625 }
176626
176627 if( pSeg->pLeaf==0 || bNewTerm
176628 || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
176629 ){
@@ -176647,11 +177596,12 @@
176647 do {
176648 int iFirst = pIter->aFirst[1].iFirst;
176649 Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
176650 int bNewTerm = 0;
176651
176652 fts5SegIterNext(p, pSeg, &bNewTerm);
 
176653 if( pSeg->pLeaf==0 || bNewTerm
176654 || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
176655 ){
176656 fts5MultiIterAdvanced(p, pIter, iFirst, 1);
176657 fts5MultiIterSetEof(pIter);
@@ -176767,11 +177717,12 @@
176767 ** object and set the output variable to NULL. */
176768 if( p->rc==SQLITE_OK ){
176769 for(iIter=pNew->nSeg-1; iIter>0; iIter--){
176770 int iEq;
176771 if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
176772 fts5SegIterNext(p, &pNew->aSeg[iEq], 0);
 
176773 fts5MultiIterAdvanced(p, pNew, iEq, iIter);
176774 }
176775 }
176776 fts5MultiIterSetEof(pNew);
176777 fts5AssertMultiIterSetup(p, pNew);
@@ -176817,10 +177768,11 @@
176817 }
176818 pData = 0;
176819 }else{
176820 pNew->bEof = 1;
176821 }
 
176822
176823 *ppOut = pNew;
176824 }
176825
176826 fts5DataRelease(pData);
@@ -176885,10 +177837,13 @@
176885 Fts5Data *pData = 0;
176886 u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
176887 int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
176888 int pgno = pSeg->iLeafPgno;
176889 int pgnoSave = 0;
 
 
 
176890
176891 if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
176892 pgnoSave = pgno+1;
176893 }
176894
@@ -177309,12 +178264,11 @@
177309 ** Append a rowid and position-list size field to the writers output.
177310 */
177311 static void fts5WriteAppendRowid(
177312 Fts5Index *p,
177313 Fts5SegWriter *pWriter,
177314 i64 iRowid,
177315 int nPos
177316 ){
177317 if( p->rc==SQLITE_OK ){
177318 Fts5PageWriter *pPage = &pWriter->writer;
177319
177320 if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){
@@ -177337,12 +178291,10 @@
177337 fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
177338 }
177339 pWriter->iPrevRowid = iRowid;
177340 pWriter->bFirstRowidInDoclist = 0;
177341 pWriter->bFirstRowidInPage = 0;
177342
177343 fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos);
177344 }
177345 }
177346
177347 static void fts5WriteAppendPoslistData(
177348 Fts5Index *p,
@@ -177534,10 +178486,11 @@
177534 int nInput; /* Number of input segments */
177535 Fts5SegWriter writer; /* Writer object */
177536 Fts5StructureSegment *pSeg; /* Output segment */
177537 Fts5Buffer term;
177538 int bOldest; /* True if the output segment is the oldest */
 
177539
177540 assert( iLvl<pStruct->nLevel );
177541 assert( pLvl->nMerge<=pLvl->nSeg );
177542
177543 memset(&writer, 0, sizeof(Fts5SegWriter));
@@ -177603,15 +178556,25 @@
177603 fts5BufferSet(&p->rc, &term, nTerm, pTerm);
177604 }
177605
177606 /* Append the rowid to the output */
177607 /* WRITEPOSLISTSIZE */
177608 nPos = pSegIter->nPos*2 + pSegIter->bDel;
177609 fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos);
177610
177611 /* Append the position-list data to the output */
177612 fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
 
 
 
 
 
 
 
 
 
 
 
177613 }
177614
177615 /* Flush the last leaf page to disk. Set the output segment b-tree height
177616 ** and last leaf page number at the same time. */
177617 fts5WriteFinish(p, &writer, &pSeg->pgnoLast);
@@ -177795,11 +178758,11 @@
177795 pStruct = fts5StructureRead(p);
177796 iSegid = fts5AllocateSegid(p, pStruct);
177797
177798 if( iSegid ){
177799 const int pgsz = p->pConfig->pgsz;
177800
177801 Fts5StructureSegment *pSeg; /* New segment within pStruct */
177802 Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
177803 Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
177804
177805 Fts5SegWriter writer;
@@ -177838,16 +178801,11 @@
177838
177839 /* The entire doclist will not fit on this leaf. The following
177840 ** loop iterates through the poslists that make up the current
177841 ** doclist. */
177842 while( p->rc==SQLITE_OK && iOff<nDoclist ){
177843 int nPos;
177844 int nCopy;
177845 int bDummy;
177846 iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
177847 nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
177848 nCopy += nPos;
177849 iRowid += iDelta;
177850
177851 if( writer.bFirstRowidInPage ){
177852 fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
177853 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
@@ -177856,38 +178814,56 @@
177856 }else{
177857 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
177858 }
177859 assert( pBuf->n<=pBuf->nSpace );
177860
177861 if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
177862 /* The entire poslist will fit on the current leaf. So copy
177863 ** it in one go. */
177864 fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
177865 }else{
177866 /* The entire poslist will not fit on this leaf. So it needs
177867 ** to be broken into sections. The only qualification being
177868 ** that each varint must be stored contiguously. */
177869 const u8 *pPoslist = &pDoclist[iOff];
177870 int iPos = 0;
177871 while( p->rc==SQLITE_OK ){
177872 int nSpace = pgsz - pBuf->n - pPgidx->n;
177873 int n = 0;
177874 if( (nCopy - iPos)<=nSpace ){
177875 n = nCopy - iPos;
177876 }else{
177877 n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
177878 }
177879 assert( n>0 );
177880 fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
177881 iPos += n;
177882 if( (pBuf->n + pPgidx->n)>=pgsz ){
177883 fts5WriteFlushLeaf(p, &writer);
177884 }
177885 if( iPos>=nCopy ) break;
177886 }
177887 }
177888 iOff += nCopy;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177889 }
177890 }
177891
177892 /* TODO2: Doclist terminator written here. */
177893 /* pBuf->p[pBuf->n++] = '\0'; */
@@ -178018,10 +178994,18 @@
178018 Fts5Buffer *pBuf; /* Append to this buffer */
178019 Fts5Colset *pColset; /* Restrict matches to this column */
178020 int eState; /* See above */
178021 };
178022
 
 
 
 
 
 
 
 
178023 /*
178024 ** TODO: Make this more efficient!
178025 */
178026 static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
178027 int i;
@@ -178028,10 +179012,32 @@
178028 for(i=0; i<pColset->nCol; i++){
178029 if( pColset->aiCol[i]==iCol ) return 1;
178030 }
178031 return 0;
178032 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178033
178034 static void fts5PoslistFilterCallback(
178035 Fts5Index *p,
178036 void *pContext,
178037 const u8 *pChunk, int nChunk
@@ -178096,16 +179102,24 @@
178096 ){
178097 if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
178098 if( pColset==0 ){
178099 fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
178100 }else{
178101 PoslistCallbackCtx sCtx;
178102 sCtx.pBuf = pBuf;
178103 sCtx.pColset = pColset;
178104 sCtx.eState = fts5IndexColsetTest(pColset, 0);
178105 assert( sCtx.eState==0 || sCtx.eState==1 );
178106 fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
 
 
 
 
 
 
 
 
178107 }
178108 }
178109 }
178110
178111 /*
@@ -178144,10 +179158,20 @@
178144 prev = *p++;
178145 }
178146 return p - (*pa);
178147 }
178148
 
 
 
 
 
 
 
 
 
 
178149
178150 /*
178151 ** Iterator pMulti currently points to a valid entry (not EOF). This
178152 ** function appends the following to buffer pBuf:
178153 **
@@ -178171,12 +179195,12 @@
178171 if( p->rc==SQLITE_OK ){
178172 Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
178173 assert( fts5MultiIterEof(p, pMulti)==0 );
178174 assert( pSeg->nPos>0 );
178175 if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
178176
178177 if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
178178 && (pColset==0 || pColset->nCol==1)
178179 ){
178180 const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
178181 int nPos;
178182 if( pColset ){
@@ -178217,16 +179241,16 @@
178217 sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
178218 }
178219 }
178220 }
178221 }
178222
178223 }
178224 }
178225
178226 return 0;
178227 }
 
178228
178229 static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
178230 u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
178231
178232 assert( pIter->aPoslist );
@@ -178283,10 +179307,73 @@
178283 #define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
178284 assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
178285 fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
178286 (iLastRowid) = (iRowid); \
178287 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178288
178289 /*
178290 ** Buffers p1 and p2 contain doclists. This function merges the content
178291 ** of the two doclists together and sets buffer p1 to the result before
178292 ** returning.
@@ -178352,11 +179439,13 @@
178352 sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
178353 if( iPos1==iPos2 ){
178354 sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
178355 }
178356 }
178357 p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
 
 
178358 }
178359
178360 /* WRITEPOSLISTSIZE */
178361 fts5BufferSafeAppendVarint(&out, tmp.n * 2);
178362 fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
@@ -178369,16 +179458,10 @@
178369 fts5BufferFree(&tmp);
178370 fts5BufferFree(&out);
178371 }
178372 }
178373
178374 static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
178375 Fts5Buffer tmp = *p1;
178376 *p1 = *p2;
178377 *p2 = tmp;
178378 }
178379
178380 static void fts5SetupPrefixIter(
178381 Fts5Index *p, /* Index to read from */
178382 int bDesc, /* True for "ORDER BY rowid DESC" */
178383 const u8 *pToken, /* Buffer containing prefix to match */
178384 int nToken, /* Size of buffer pToken in bytes */
@@ -178386,10 +179469,20 @@
178386 Fts5IndexIter **ppIter /* OUT: New iterator */
178387 ){
178388 Fts5Structure *pStruct;
178389 Fts5Buffer *aBuf;
178390 const int nBuf = 32;
 
 
 
 
 
 
 
 
 
 
178391
178392 aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
178393 pStruct = fts5StructureRead(p);
178394
178395 if( aBuf && pStruct ){
@@ -178419,25 +179512,25 @@
178419 assert( i<nBuf );
178420 if( aBuf[i].n==0 ){
178421 fts5BufferSwap(&doclist, &aBuf[i]);
178422 fts5BufferZero(&doclist);
178423 }else{
178424 fts5MergePrefixLists(p, &doclist, &aBuf[i]);
178425 fts5BufferZero(&aBuf[i]);
178426 }
178427 }
178428 iLastRowid = 0;
178429 }
178430
178431 if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
178432 iLastRowid = iRowid;
178433 }
178434 }
178435
178436 for(i=0; i<nBuf; i++){
178437 if( p->rc==SQLITE_OK ){
178438 fts5MergePrefixLists(p, &doclist, &aBuf[i]);
178439 }
178440 fts5BufferFree(&aBuf[i]);
178441 }
178442 fts5MultiIterFree(p, p1);
178443
@@ -178463,11 +179556,11 @@
178463 static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
178464 assert( p->rc==SQLITE_OK );
178465
178466 /* Allocate the hash table if it has not already been allocated */
178467 if( p->pHash==0 ){
178468 p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData);
178469 }
178470
178471 /* Flush the hash table to disk if required */
178472 if( iRowid<p->iWriteRowid
178473 || (iRowid==p->iWriteRowid && p->bDelete==0)
@@ -178584,11 +179677,15 @@
178584 /*
178585 ** Argument p points to a buffer containing utf-8 text that is n bytes in
178586 ** size. Return the number of bytes in the nChar character prefix of the
178587 ** buffer, or 0 if there are less than nChar characters in total.
178588 */
178589 static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){
 
 
 
 
178590 int n = 0;
178591 int i;
178592 for(i=0; i<nChar; i++){
178593 if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
178594 if( (unsigned char)p[n++]>=0xc0 ){
@@ -178641,11 +179738,12 @@
178641 rc = sqlite3Fts5HashWrite(
178642 p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken
178643 );
178644
178645 for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
178646 int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]);
 
178647 if( nByte ){
178648 rc = sqlite3Fts5HashWrite(p->pHash,
178649 p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
178650 nByte
178651 );
@@ -178819,13 +179917,20 @@
178819 const u8 **pp, /* OUT: Pointer to position-list data */
178820 int *pn, /* OUT: Size of position-list in bytes */
178821 i64 *piRowid /* OUT: Current rowid */
178822 ){
178823 Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
 
 
178824 assert( pIter->pIndex->rc==SQLITE_OK );
178825 *piRowid = pSeg->iRowid;
178826 if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
 
 
 
 
 
178827 u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
178828 if( pColset==0 || pIter->bFiltered ){
178829 *pn = pSeg->nPos;
178830 *pp = pPos;
178831 }else if( pColset->nCol==1 ){
@@ -178838,15 +179943,28 @@
178838 *pn = pIter->poslist.n;
178839 }
178840 }else{
178841 fts5BufferZero(&pIter->poslist);
178842 fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
178843 *pp = pIter->poslist.p;
 
 
178844 *pn = pIter->poslist.n;
178845 }
178846 return fts5IndexReturn(pIter->pIndex);
178847 }
 
 
 
 
 
 
 
 
 
 
 
178848
178849 /*
178850 ** This function is similar to sqlite3Fts5IterPoslist(), except that it
178851 ** copies the position list into the buffer supplied as the second
178852 ** argument.
@@ -178957,11 +180075,11 @@
178957 */
178958
178959 /*
178960 ** Return a simple checksum value based on the arguments.
178961 */
178962 static u64 fts5IndexEntryCksum(
178963 i64 iRowid,
178964 int iCol,
178965 int iPos,
178966 int iIdx,
178967 const char *pTerm,
@@ -179027,34 +180145,41 @@
179027 const char *z, /* Index key to query for */
179028 int n, /* Size of index key in bytes */
179029 int flags, /* Flags for Fts5IndexQuery */
179030 u64 *pCksum /* IN/OUT: Checksum value */
179031 ){
 
179032 u64 cksum = *pCksum;
179033 Fts5IndexIter *pIdxIter = 0;
 
179034 int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
179035
179036 while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
179037 i64 dummy;
179038 const u8 *pPos;
179039 int nPos;
179040 i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
179041 rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179042 if( rc==SQLITE_OK ){
179043 Fts5PoslistReader sReader;
179044 for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
179045 sReader.bEof==0;
179046 sqlite3Fts5PoslistReaderNext(&sReader)
179047 ){
179048 int iCol = FTS5_POS2COLUMN(sReader.iPos);
179049 int iOff = FTS5_POS2OFFSET(sReader.iPos);
179050 cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
179051 }
179052 rc = sqlite3Fts5IterNext(pIdxIter);
179053 }
179054 }
179055 sqlite3Fts5IterClose(pIdxIter);
 
179056
179057 *pCksum = cksum;
179058 return rc;
179059 }
179060
@@ -179344,18 +180469,19 @@
179344
179345
179346 /*
179347 ** Run internal checks to ensure that the FTS index (a) is internally
179348 ** consistent and (b) contains entries for which the XOR of the checksums
179349 ** as calculated by fts5IndexEntryCksum() is cksum.
179350 **
179351 ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
179352 ** checksum does not match. Return SQLITE_OK if all checks pass without
179353 ** error, or some other SQLite error code if another error (e.g. OOM)
179354 ** occurs.
179355 */
179356 static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
 
179357 u64 cksum2 = 0; /* Checksum based on contents of indexes */
179358 Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
179359 Fts5IndexIter *pIter; /* Used to iterate through entire index */
179360 Fts5Structure *pStruct; /* Index structure */
179361
@@ -179403,16 +180529,22 @@
179403 char *z = (char*)fts5MultiIterTerm(pIter, &n);
179404
179405 /* If this is a new term, query for it. Update cksum3 with the results. */
179406 fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
179407
179408 poslist.n = 0;
179409 fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist);
179410 while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
179411 int iCol = FTS5_POS2COLUMN(iPos);
179412 int iTokOff = FTS5_POS2OFFSET(iPos);
179413 cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
 
 
 
 
 
 
179414 }
179415 }
179416 fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
179417
179418 fts5MultiIterFree(p, pIter);
@@ -179424,38 +180556,10 @@
179424 #endif
179425 fts5BufferFree(&poslist);
179426 return fts5IndexReturn(p);
179427 }
179428
179429
179430 /*
179431 ** Calculate and return a checksum that is the XOR of the index entry
179432 ** checksum of all entries that would be generated by the token specified
179433 ** by the final 5 arguments.
179434 */
179435 static u64 sqlite3Fts5IndexCksum(
179436 Fts5Config *pConfig, /* Configuration object */
179437 i64 iRowid, /* Document term appears in */
179438 int iCol, /* Column term appears in */
179439 int iPos, /* Position term appears in */
179440 const char *pTerm, int nTerm /* Term at iPos */
179441 ){
179442 u64 ret = 0; /* Return value */
179443 int iIdx; /* For iterating through indexes */
179444
179445 ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm);
179446
179447 for(iIdx=0; iIdx<pConfig->nPrefix; iIdx++){
179448 int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]);
179449 if( nByte ){
179450 ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte);
179451 }
179452 }
179453
179454 return ret;
179455 }
179456
179457 /*************************************************************************
179458 **************************************************************************
179459 ** Below this point is the implementation of the fts5_decode() scalar
179460 ** function only.
179461 */
@@ -179618,10 +180722,51 @@
179618 }
179619 }
179620
179621 return iOff;
179622 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179623
179624 /*
179625 ** The implementation of user-defined scalar function fts5_decode().
179626 */
179627 static void fts5DecodeFunction(
@@ -179634,10 +180779,11 @@
179634 const u8 *aBlob; int n; /* Record to decode */
179635 u8 *a = 0;
179636 Fts5Buffer s; /* Build up text to return here */
179637 int rc = SQLITE_OK; /* Return code */
179638 int nSpace = 0;
 
179639
179640 assert( nArg==2 );
179641 memset(&s, 0, sizeof(Fts5Buffer));
179642 iRowid = sqlite3_value_int64(apVal[0]);
179643
@@ -179675,10 +180821,58 @@
179675 if( iRowid==FTS5_AVERAGES_ROWID ){
179676 fts5DecodeAverages(&rc, &s, a, n);
179677 }else{
179678 fts5DecodeStructure(&rc, &s, a, n);
179679 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179680 }else{
179681 Fts5Buffer term; /* Current term read from page */
179682 int szLeaf; /* Offset of pgidx in a[] */
179683 int iPgidxOff;
179684 int iPgidxPrev = 0; /* Previous value read from pgidx */
@@ -179802,18 +180996,25 @@
179802 */
179803 static int sqlite3Fts5IndexInit(sqlite3 *db){
179804 int rc = sqlite3_create_function(
179805 db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
179806 );
 
 
 
 
 
 
 
 
179807 if( rc==SQLITE_OK ){
179808 rc = sqlite3_create_function(
179809 db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
179810 );
179811 }
179812 return rc;
179813 }
179814
179815
179816 /*
179817 ** 2014 Jun 09
179818 **
179819 ** The author disclaims copyright to this source code. In place of
@@ -180039,10 +181240,11 @@
180039 #define FTS5CSR_REQUIRE_DOCSIZE 0x02
180040 #define FTS5CSR_REQUIRE_INST 0x04
180041 #define FTS5CSR_EOF 0x08
180042 #define FTS5CSR_FREE_ZRANK 0x10
180043 #define FTS5CSR_REQUIRE_RESEEK 0x20
 
180044
180045 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
180046 #define BitFlagTest(x,y) (((x) & (y))!=0)
180047
180048
@@ -180452,10 +181654,11 @@
180452 static void fts5CsrNewrow(Fts5Cursor *pCsr){
180453 CsrFlagSet(pCsr,
180454 FTS5CSR_REQUIRE_CONTENT
180455 | FTS5CSR_REQUIRE_DOCSIZE
180456 | FTS5CSR_REQUIRE_INST
 
180457 );
180458 }
180459
180460 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
180461 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
@@ -180534,19 +181737,22 @@
180534
180535 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
180536 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
180537 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
180538
180539 for(i=0; i<(pSorter->nIdx-1); i++){
180540 int iVal;
180541 a += fts5GetVarint32(a, iVal);
180542 iOff += iVal;
180543 pSorter->aIdx[i] = iOff;
180544 }
180545 pSorter->aIdx[i] = &aBlob[nBlob] - a;
180546
180547 pSorter->aPoslist = a;
 
 
 
180548 fts5CsrNewrow(pCsr);
180549 }
180550
180551 return rc;
180552 }
@@ -180652,45 +181858,44 @@
180652
180653 return rc;
180654 }
180655
180656
180657 static sqlite3_stmt *fts5PrepareStatement(
180658 int *pRc,
180659 Fts5Config *pConfig,
180660 const char *zFmt,
180661 ...
180662 ){
180663 sqlite3_stmt *pRet = 0;
 
 
180664 va_list ap;
 
180665 va_start(ap, zFmt);
180666
180667 if( *pRc==SQLITE_OK ){
180668 int rc;
180669 char *zSql = sqlite3_vmprintf(zFmt, ap);
180670 if( zSql==0 ){
180671 rc = SQLITE_NOMEM;
180672 }else{
180673 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
180674 if( rc!=SQLITE_OK ){
180675 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
180676 }
180677 sqlite3_free(zSql);
180678 }
180679 *pRc = rc;
180680 }
180681
180682 va_end(ap);
180683 return pRet;
 
180684 }
180685
180686 static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
180687 Fts5Config *pConfig = pTab->pConfig;
180688 Fts5Sorter *pSorter;
180689 int nPhrase;
180690 int nByte;
180691 int rc = SQLITE_OK;
180692 const char *zRank = pCsr->zRank;
180693 const char *zRankArgs = pCsr->zRankArgs;
180694
180695 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
180696 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
@@ -180704,11 +181909,11 @@
180704 ** is not possible as SQLite reference counts the virtual table objects.
180705 ** And since the statement required here reads from this very virtual
180706 ** table, saving it creates a circular reference.
180707 **
180708 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
180709 pSorter->pStmt = fts5PrepareStatement(&rc, pConfig,
180710 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
180711 pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
180712 (zRankArgs ? ", " : ""),
180713 (zRankArgs ? zRankArgs : ""),
180714 bDesc ? "DESC" : "ASC"
@@ -180980,10 +182185,11 @@
180980 assert( pCsr->iLastRowid==LARGEST_INT64 );
180981 assert( pCsr->iFirstRowid==SMALLEST_INT64 );
180982 pCsr->ePlan = FTS5_PLAN_SOURCE;
180983 pCsr->pExpr = pTab->pSortCsr->pExpr;
180984 rc = fts5CursorFirst(pTab, pCsr, bDesc);
 
180985 }else if( pMatch ){
180986 const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
180987 if( zExpr==0 ) zExpr = "";
180988
180989 rc = fts5CursorParseRank(pConfig, pCsr, pRank);
@@ -181212,11 +182418,11 @@
181212 ){
181213 int rc = SQLITE_OK;
181214 int eType1 = sqlite3_value_type(apVal[1]);
181215 if( eType1==SQLITE_INTEGER ){
181216 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
181217 rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]);
181218 }
181219 return rc;
181220 }
181221
181222 static void fts5StorageInsert(
@@ -181319,21 +182525,21 @@
181319 }
181320
181321 /* Case 1: DELETE */
181322 else if( nArg==1 ){
181323 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
181324 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
181325 }
181326
181327 /* Case 2: INSERT */
181328 else if( eType0!=SQLITE_INTEGER ){
181329 /* If this is a REPLACE, first remove the current entry (if any) */
181330 if( eConflict==SQLITE_REPLACE
181331 && sqlite3_value_type(apVal[1])==SQLITE_INTEGER
181332 ){
181333 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
181334 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
181335 }
181336 fts5StorageInsert(&rc, pTab, apVal, pRowid);
181337 }
181338
181339 /* Case 2: UPDATE */
@@ -181340,26 +182546,26 @@
181340 else{
181341 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
181342 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
181343 if( iOld!=iNew ){
181344 if( eConflict==SQLITE_REPLACE ){
181345 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
181346 if( rc==SQLITE_OK ){
181347 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
181348 }
181349 fts5StorageInsert(&rc, pTab, apVal, pRowid);
181350 }else{
181351 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
181352 if( rc==SQLITE_OK ){
181353 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
181354 }
181355 if( rc==SQLITE_OK ){
181356 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
181357 }
181358 }
181359 }else{
181360 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
181361 fts5StorageInsert(&rc, pTab, apVal, pRowid);
181362 }
181363 }
181364 }
181365
@@ -181409,10 +182615,12 @@
181409 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
181410 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
181411 return rc;
181412 }
181413
 
 
181414 static void *fts5ApiUserData(Fts5Context *pCtx){
181415 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181416 return pCsr->pAux->pUserData;
181417 }
181418
@@ -181458,21 +182666,76 @@
181458 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
181459 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181460 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
181461 }
181462
181463 static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
181464 int n;
181465 if( pCsr->pSorter ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181466 Fts5Sorter *pSorter = pCsr->pSorter;
181467 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
181468 n = pSorter->aIdx[iPhrase] - i1;
181469 *pa = &pSorter->aPoslist[i1];
181470 }else{
181471 n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
181472 }
181473 return n;
 
181474 }
181475
181476 /*
181477 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
181478 ** correctly for the current view. Return SQLITE_OK if successful, or an
@@ -181493,47 +182756,52 @@
181493 if( aIter ){
181494 int nInst = 0; /* Number instances seen so far */
181495 int i;
181496
181497 /* Initialize all iterators */
181498 for(i=0; i<nIter; i++){
181499 const u8 *a;
181500 int n = fts5CsrPoslist(pCsr, i, &a);
181501 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
181502 }
181503
181504 while( 1 ){
181505 int *aInst;
181506 int iBest = -1;
181507 for(i=0; i<nIter; i++){
181508 if( (aIter[i].bEof==0)
181509 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
181510 ){
181511 iBest = i;
181512 }
181513 }
181514 if( iBest<0 ) break;
181515
181516 nInst++;
181517 if( nInst>=pCsr->nInstAlloc ){
181518 pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
181519 aInst = (int*)sqlite3_realloc(
181520 pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
181521 );
181522 if( aInst ){
181523 pCsr->aInst = aInst;
181524 }else{
181525 rc = SQLITE_NOMEM;
181526 break;
181527 }
181528 }
181529
181530 aInst = &pCsr->aInst[3 * (nInst-1)];
181531 aInst[0] = iBest;
181532 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
181533 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
181534 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
 
 
 
 
 
181535 }
181536
181537 pCsr->nInstCount = nInst;
181538 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
181539 }
@@ -181562,10 +182830,16 @@
181562 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
181563 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
181564 ){
181565 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
181566 rc = SQLITE_RANGE;
 
 
 
 
 
 
181567 }else{
181568 *piPhrase = pCsr->aInst[iIdx*3];
181569 *piCol = pCsr->aInst[iIdx*3 + 1];
181570 *piOff = pCsr->aInst[iIdx*3 + 2];
181571 }
@@ -181575,31 +182849,10 @@
181575
181576 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
181577 return fts5CursorRowid((Fts5Cursor*)pCtx);
181578 }
181579
181580 static int fts5ApiColumnText(
181581 Fts5Context *pCtx,
181582 int iCol,
181583 const char **pz,
181584 int *pn
181585 ){
181586 int rc = SQLITE_OK;
181587 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181588 if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
181589 *pz = 0;
181590 *pn = 0;
181591 }else{
181592 rc = fts5SeekCursor(pCsr, 0);
181593 if( rc==SQLITE_OK ){
181594 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
181595 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
181596 }
181597 }
181598 return rc;
181599 }
181600
181601 static int fts5ColumnSizeCb(
181602 void *pContext, /* Pointer to int */
181603 int tflags,
181604 const char *pToken, /* Buffer containing token */
181605 int nToken, /* Size of token in bytes */
@@ -181740,23 +182993,101 @@
181740 }
181741 *piOff += (iVal-2);
181742 }
181743 }
181744
181745 static void fts5ApiPhraseFirst(
181746 Fts5Context *pCtx,
181747 int iPhrase,
181748 Fts5PhraseIter *pIter,
181749 int *piCol, int *piOff
181750 ){
181751 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
181752 int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
181753 pIter->b = &pIter->a[n];
181754 *piCol = 0;
181755 *piOff = 0;
181756 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
 
 
 
 
181757 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181758
181759 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
181760 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
181761 );
181762
@@ -181777,12 +183108,13 @@
181777 fts5ApiQueryPhrase,
181778 fts5ApiSetAuxdata,
181779 fts5ApiGetAuxdata,
181780 fts5ApiPhraseFirst,
181781 fts5ApiPhraseNext,
 
 
181782 };
181783
181784
181785 /*
181786 ** Implementation of API function xQueryPhrase().
181787 */
181788 static int fts5ApiQueryPhrase(
@@ -181911,24 +183243,50 @@
181911 int rc = SQLITE_OK;
181912 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
181913 Fts5Buffer val;
181914
181915 memset(&val, 0, sizeof(Fts5Buffer));
181916
181917 /* Append the varints */
181918 for(i=0; i<(nPhrase-1); i++){
181919 const u8 *dummy;
181920 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
181921 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
181922 }
181923
181924 /* Append the position lists */
181925 for(i=0; i<nPhrase; i++){
181926 const u8 *pPoslist;
181927 int nPoslist;
181928 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
181929 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181930 }
181931
181932 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
181933 return rc;
181934 }
@@ -182247,11 +183605,11 @@
182247 sqlite3_context *pCtx, /* Function call context */
182248 int nArg, /* Number of args */
182249 sqlite3_value **apVal /* Function arguments */
182250 ){
182251 assert( nArg==0 );
182252 sqlite3_result_text(pCtx, "fts5: 2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566", -1, SQLITE_TRANSIENT);
182253 }
182254
182255 static int fts5Init(sqlite3 *db){
182256 static const sqlite3_module fts5Mod = {
182257 /* iVersion */ 2,
@@ -182732,43 +184090,56 @@
182732 /*
182733 ** If a row with rowid iDel is present in the %_content table, add the
182734 ** delete-markers to the FTS index necessary to delete it. Do not actually
182735 ** remove the %_content row at this time though.
182736 */
182737 static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
 
 
 
 
182738 Fts5Config *pConfig = p->pConfig;
182739 sqlite3_stmt *pSeek; /* SELECT to read row iDel from %_data */
182740 int rc; /* Return code */
 
 
 
182741
182742 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
182743 if( rc==SQLITE_OK ){
182744 int rc2;
182745 sqlite3_bind_int64(pSeek, 1, iDel);
182746 if( sqlite3_step(pSeek)==SQLITE_ROW ){
182747 int iCol;
182748 Fts5InsertCtx ctx;
182749 ctx.pStorage = p;
182750 ctx.iCol = -1;
182751 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
182752 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
182753 if( pConfig->abUnindexed[iCol-1] ) continue;
182754 ctx.szCol = 0;
182755 rc = sqlite3Fts5Tokenize(pConfig,
182756 FTS5_TOKENIZE_DOCUMENT,
182757 (const char*)sqlite3_column_text(pSeek, iCol),
182758 sqlite3_column_bytes(pSeek, iCol),
182759 (void*)&ctx,
182760 fts5StorageInsertCallback
182761 );
182762 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
182763 }
182764 p->nTotalRow--;
182765 }
182766 rc2 = sqlite3_reset(pSeek);
182767 if( rc==SQLITE_OK ) rc = rc2;
182768 }
182769
 
 
 
 
 
 
182770 return rc;
182771 }
182772
182773
182774 /*
@@ -182844,20 +184215,21 @@
182844 }
182845
182846 /*
182847 ** Remove a row from the FTS table.
182848 */
182849 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
182850 Fts5Config *pConfig = p->pConfig;
182851 int rc;
182852 sqlite3_stmt *pDel = 0;
182853
 
182854 rc = fts5StorageLoadTotals(p, 1);
182855
182856 /* Delete the index records */
182857 if( rc==SQLITE_OK ){
182858 rc = fts5StorageDeleteFromIndex(p, iDel);
182859 }
182860
182861 /* Delete the %_docsize record */
182862 if( rc==SQLITE_OK && pConfig->bColumnsize ){
182863 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
@@ -182871,65 +184243,10 @@
182871 /* Delete the %_content record */
182872 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
182873 if( rc==SQLITE_OK ){
182874 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
182875 }
182876 if( rc==SQLITE_OK ){
182877 sqlite3_bind_int64(pDel, 1, iDel);
182878 sqlite3_step(pDel);
182879 rc = sqlite3_reset(pDel);
182880 }
182881 }
182882
182883 /* Write the averages record */
182884 if( rc==SQLITE_OK ){
182885 rc = fts5StorageSaveTotals(p);
182886 }
182887
182888 return rc;
182889 }
182890
182891 static int sqlite3Fts5StorageSpecialDelete(
182892 Fts5Storage *p,
182893 i64 iDel,
182894 sqlite3_value **apVal
182895 ){
182896 Fts5Config *pConfig = p->pConfig;
182897 int rc;
182898 sqlite3_stmt *pDel = 0;
182899
182900 assert( pConfig->eContent!=FTS5_CONTENT_NORMAL );
182901 rc = fts5StorageLoadTotals(p, 1);
182902
182903 /* Delete the index records */
182904 if( rc==SQLITE_OK ){
182905 int iCol;
182906 Fts5InsertCtx ctx;
182907 ctx.pStorage = p;
182908 ctx.iCol = -1;
182909
182910 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
182911 for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
182912 if( pConfig->abUnindexed[iCol] ) continue;
182913 ctx.szCol = 0;
182914 rc = sqlite3Fts5Tokenize(pConfig,
182915 FTS5_TOKENIZE_DOCUMENT,
182916 (const char*)sqlite3_value_text(apVal[iCol]),
182917 sqlite3_value_bytes(apVal[iCol]),
182918 (void*)&ctx,
182919 fts5StorageInsertCallback
182920 );
182921 p->aTotalSize[iCol] -= (i64)ctx.szCol;
182922 }
182923 p->nTotalRow--;
182924 }
182925
182926 /* Delete the %_docsize record */
182927 if( pConfig->bColumnsize ){
182928 if( rc==SQLITE_OK ){
182929 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
182930 }
182931 if( rc==SQLITE_OK ){
182932 sqlite3_bind_int64(pDel, 1, iDel);
182933 sqlite3_step(pDel);
182934 rc = sqlite3_reset(pDel);
182935 }
@@ -183179,32 +184496,77 @@
183179 struct Fts5IntegrityCtx {
183180 i64 iRowid;
183181 int iCol;
183182 int szCol;
183183 u64 cksum;
 
183184 Fts5Config *pConfig;
183185 };
 
183186
183187 /*
183188 ** Tokenization callback used by integrity check.
183189 */
183190 static int fts5StorageIntegrityCallback(
183191 void *pContext, /* Pointer to Fts5InsertCtx object */
183192 int tflags,
183193 const char *pToken, /* Buffer containing token */
183194 int nToken, /* Size of token in bytes */
183195 int iStart, /* Start offset of token */
183196 int iEnd /* End offset of token */
183197 ){
183198 Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
 
 
 
 
 
 
 
183199 if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
183200 pCtx->szCol++;
183201 }
183202 pCtx->cksum ^= sqlite3Fts5IndexCksum(
183203 pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken
183204 );
183205 return SQLITE_OK;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183206 }
183207
183208 /*
183209 ** Check that the contents of the FTS index match that of the %_content
183210 ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return
@@ -183235,27 +184597,42 @@
183235 int i;
183236 ctx.iRowid = sqlite3_column_int64(pScan, 0);
183237 ctx.szCol = 0;
183238 if( pConfig->bColumnsize ){
183239 rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
 
 
 
183240 }
183241 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
183242 if( pConfig->abUnindexed[i] ) continue;
183243 ctx.iCol = i;
183244 ctx.szCol = 0;
183245 rc = sqlite3Fts5Tokenize(pConfig,
183246 FTS5_TOKENIZE_DOCUMENT,
183247 (const char*)sqlite3_column_text(pScan, i+1),
183248 sqlite3_column_bytes(pScan, i+1),
183249 (void*)&ctx,
183250 fts5StorageIntegrityCallback
183251 );
183252 if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
 
 
 
 
 
183253 rc = FTS5_CORRUPT;
183254 }
183255 aTotalSize[i] += ctx.szCol;
 
 
 
 
183256 }
 
 
 
183257 if( rc!=SQLITE_OK ) break;
183258 }
183259 rc2 = sqlite3_reset(pScan);
183260 if( rc==SQLITE_OK ) rc = rc2;
183261 }
@@ -185777,11 +187154,11 @@
185777
185778 pCsr->rowid++;
185779
185780 if( pTab->eType==FTS5_VOCAB_COL ){
185781 for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
185782 if( pCsr->aCnt[pCsr->iCol] ) break;
185783 }
185784 }
185785
185786 if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
185787 if( sqlite3Fts5IterEof(pCsr->pIter) ){
@@ -185810,28 +187187,64 @@
185810 i64 dummy;
185811 const u8 *pPos; int nPos; /* Position list */
185812 i64 iPos = 0; /* 64-bit position read from poslist */
185813 int iOff = 0; /* Current offset within position list */
185814
185815 rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
185816 if( rc==SQLITE_OK ){
185817 if( pTab->eType==FTS5_VOCAB_ROW ){
185818 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
185819 pCsr->aCnt[0]++;
185820 }
185821 pCsr->aDoc[0]++;
185822 }else{
185823 int iCol = -1;
185824 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
185825 int ii = FTS5_POS2COLUMN(iPos);
185826 pCsr->aCnt[ii]++;
185827 if( iCol!=ii ){
185828 pCsr->aDoc[ii]++;
185829 iCol = ii;
185830 }
185831 }
185832 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185833 rc = sqlite3Fts5IterNextScan(pCsr->pIter);
185834 }
185835
185836 if( rc==SQLITE_OK ){
185837 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
@@ -185842,12 +187255,12 @@
185842 }
185843 }
185844 }
185845 }
185846
185847 if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
185848 while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
185849 assert( pCsr->iCol<pCsr->pConfig->nCol );
185850 }
185851 return rc;
185852 }
185853
@@ -185923,34 +187336,40 @@
185923 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
185924 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
185925 int iCol /* Index of column to read value from */
185926 ){
185927 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
 
 
 
185928
185929 if( iCol==0 ){
185930 sqlite3_result_text(
185931 pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
185932 );
185933 }
185934 else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){
185935 assert( iCol==1 || iCol==2 || iCol==3 );
185936 if( iCol==1 ){
185937 const char *z = pCsr->pConfig->azCol[pCsr->iCol];
185938 sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
 
 
185939 }else if( iCol==2 ){
185940 sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]);
185941 }else{
185942 sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]);
185943 }
185944 }else{
185945 assert( iCol==1 || iCol==2 );
185946 if( iCol==1 ){
185947 sqlite3_result_int64(pCtx, pCsr->aDoc[0]);
185948 }else{
185949 sqlite3_result_int64(pCtx, pCsr->aCnt[0]);
185950 }
185951 }
 
 
185952 return SQLITE_OK;
185953 }
185954
185955 /*
185956 ** This is the xRowid method. The SQLite core calls this routine to
185957
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.11.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.
@@ -119,10 +119,12 @@
119 #define SQLITE_ENABLE_LOCKING_STYLE 0
120 #define HAVE_UTIME 1
121 #else
122 /* This is not VxWorks. */
123 #define OS_VXWORKS 0
124 #define HAVE_FCHOWN 1
125 #define HAVE_READLINK 1
126 #endif /* defined(_WRS_KERNEL) */
127
128 /************** End of vxworks.h *********************************************/
129 /************** Continuing where we left off in sqliteInt.h ******************/
130
@@ -323,13 +325,13 @@
325 **
326 ** See also: [sqlite3_libversion()],
327 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
328 ** [sqlite_version()] and [sqlite_source_id()].
329 */
330 #define SQLITE_VERSION "3.11.0"
331 #define SQLITE_VERSION_NUMBER 3011000
332 #define SQLITE_SOURCE_ID "2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1"
333
334 /*
335 ** CAPI3REF: Run-Time Library Version Numbers
336 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
337 **
@@ -1006,12 +1008,17 @@
1008 ** improve performance on some systems.
1009 **
1010 ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
1011 ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
1012 ** to the [sqlite3_file] object associated with a particular database
1013 ** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
1014 **
1015 ** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
1016 ** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
1017 ** to the [sqlite3_file] object associated with the journal file (either
1018 ** the [rollback journal] or the [write-ahead log]) for a particular database
1019 ** connection. See also [SQLITE_FCNTL_FILE_POINTER].
1020 **
1021 ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
1022 ** No longer in use.
1023 **
1024 ** <li>[[SQLITE_FCNTL_SYNC]]
@@ -1222,10 +1229,11 @@
1229 #define SQLITE_FCNTL_WIN32_SET_HANDLE 23
1230 #define SQLITE_FCNTL_WAL_BLOCK 24
1231 #define SQLITE_FCNTL_ZIPVFS 25
1232 #define SQLITE_FCNTL_RBU 26
1233 #define SQLITE_FCNTL_VFS_POINTER 27
1234 #define SQLITE_FCNTL_JOURNAL_POINTER 28
1235
1236 /* deprecated names */
1237 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1238 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1239 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -8399,10 +8407,13 @@
8407 ** If parameter iCol is greater than or equal to the number of columns
8408 ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
8409 ** an OOM condition or IO error), an appropriate SQLite error code is
8410 ** returned.
8411 **
8412 ** This function may be quite inefficient if used with an FTS5 table
8413 ** created with the "columnsize=0" option.
8414 **
8415 ** xColumnText:
8416 ** This function attempts to retrieve the text of column iCol of the
8417 ** current document. If successful, (*pz) is set to point to a buffer
8418 ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
8419 ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -8419,18 +8430,32 @@
8430 ** xInstCount:
8431 ** Set *pnInst to the total number of occurrences of all phrases within
8432 ** the query within the current row. Return SQLITE_OK if successful, or
8433 ** an error code (i.e. SQLITE_NOMEM) if an error occurs.
8434 **
8435 ** This API can be quite slow if used with an FTS5 table created with the
8436 ** "detail=none" or "detail=column" option. If the FTS5 table is created
8437 ** with either "detail=none" or "detail=column" and "content=" option
8438 ** (i.e. if it is a contentless table), then this API always returns 0.
8439 **
8440 ** xInst:
8441 ** Query for the details of phrase match iIdx within the current row.
8442 ** Phrase matches are numbered starting from zero, so the iIdx argument
8443 ** should be greater than or equal to zero and smaller than the value
8444 ** output by xInstCount().
8445 **
8446 ** Usually, output parameter *piPhrase is set to the phrase number, *piCol
8447 ** to the column in which it occurs and *piOff the token offset of the
8448 ** first token of the phrase. The exception is if the table was created
8449 ** with the offsets=0 option specified. In this case *piOff is always
8450 ** set to -1.
8451 **
8452 ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
8453 ** if an error occurs.
8454 **
8455 ** This API can be quite slow if used with an FTS5 table created with the
8456 ** "detail=none" or "detail=column" option.
8457 **
8458 ** xRowid:
8459 ** Returns the rowid of the current row.
8460 **
8461 ** xTokenize:
@@ -8511,25 +8536,63 @@
8536 ** through instances of phrase iPhrase, use the following code:
8537 **
8538 ** Fts5PhraseIter iter;
8539 ** int iCol, iOff;
8540 ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
8541 ** iCol>=0;
8542 ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
8543 ** ){
8544 ** // An instance of phrase iPhrase at offset iOff of column iCol
8545 ** }
8546 **
8547 ** The Fts5PhraseIter structure is defined above. Applications should not
8548 ** modify this structure directly - it should only be used as shown above
8549 ** with the xPhraseFirst() and xPhraseNext() API methods (and by
8550 ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
8551 **
8552 ** This API can be quite slow if used with an FTS5 table created with the
8553 ** "detail=none" or "detail=column" option. If the FTS5 table is created
8554 ** with either "detail=none" or "detail=column" and "content=" option
8555 ** (i.e. if it is a contentless table), then this API always iterates
8556 ** through an empty set (all calls to xPhraseFirst() set iCol to -1).
8557 **
8558 ** xPhraseNext()
8559 ** See xPhraseFirst above.
8560 **
8561 ** xPhraseFirstColumn()
8562 ** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
8563 ** and xPhraseNext() APIs described above. The difference is that instead
8564 ** of iterating through all instances of a phrase in the current row, these
8565 ** APIs are used to iterate through the set of columns in the current row
8566 ** that contain one or more instances of a specified phrase. For example:
8567 **
8568 ** Fts5PhraseIter iter;
8569 ** int iCol;
8570 ** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
8571 ** iCol>=0;
8572 ** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
8573 ** ){
8574 ** // Column iCol contains at least one instance of phrase iPhrase
8575 ** }
8576 **
8577 ** This API can be quite slow if used with an FTS5 table created with the
8578 ** "detail=none" option. If the FTS5 table is created with either
8579 ** "detail=none" "content=" option (i.e. if it is a contentless table),
8580 ** then this API always iterates through an empty set (all calls to
8581 ** xPhraseFirstColumn() set iCol to -1).
8582 **
8583 ** The information accessed using this API and its companion
8584 ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
8585 ** (or xInst/xInstCount). The chief advantage of this API is that it is
8586 ** significantly more efficient than those alternatives when used with
8587 ** "detail=column" tables.
8588 **
8589 ** xPhraseNextColumn()
8590 ** See xPhraseFirstColumn above.
8591 */
8592 struct Fts5ExtensionApi {
8593 int iVersion; /* Currently always set to 3 */
8594
8595 void *(*xUserData)(Fts5Context*);
8596
8597 int (*xColumnCount)(Fts5Context*);
8598 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -8555,12 +8618,15 @@
8618 int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
8619 );
8620 int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
8621 void *(*xGetAuxdata)(Fts5Context*, int bClear);
8622
8623 int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
8624 void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
8625
8626 int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
8627 void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
8628 };
8629
8630 /*
8631 ** CUSTOM AUXILIARY FUNCTIONS
8632 *************************************************************************/
@@ -9340,10 +9406,25 @@
9406 #else
9407 # define ALWAYS(X) (X)
9408 # define NEVER(X) (X)
9409 #endif
9410
9411 /*
9412 ** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
9413 ** defined. We need to defend against those failures when testing with
9414 ** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
9415 ** during a normal build. The following macro can be used to disable tests
9416 ** that are always false except when SQLITE_TEST_REALLOC_STRESS is set.
9417 */
9418 #if defined(SQLITE_TEST_REALLOC_STRESS)
9419 # define ONLY_IF_REALLOC_STRESS(X) (X)
9420 #elif !defined(NDEBUG)
9421 # define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0)
9422 #else
9423 # define ONLY_IF_REALLOC_STRESS(X) (0)
9424 #endif
9425
9426 /*
9427 ** Declarations used for tracing the operating system interfaces.
9428 */
9429 #if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \
9430 (defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
@@ -9976,14 +10057,10 @@
10057 /*
10058 ** Default maximum size of memory used by memory-mapped I/O in the VFS
10059 */
10060 #ifdef __APPLE__
10061 # include <TargetConditionals.h>
 
 
 
 
10062 #endif
10063 #ifndef SQLITE_MAX_MMAP_SIZE
10064 # if defined(__linux__) \
10065 || defined(_WIN32) \
10066 || (defined(__APPLE__) && defined(__MACH__)) \
@@ -10479,19 +10556,21 @@
10556 ** Enter and Leave procedures no-ops.
10557 */
10558 #ifndef SQLITE_OMIT_SHARED_CACHE
10559 SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*);
10560 SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*);
10561 SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
10562 SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
10563 #else
10564 # define sqlite3BtreeEnter(X)
10565 # define sqlite3BtreeEnterAll(X)
10566 # define sqlite3BtreeSharable(X) 0
10567 # define sqlite3BtreeEnterCursor(X)
10568 #endif
10569
10570 #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
 
10571 SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*);
 
10572 SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*);
10573 SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*);
10574 #ifndef NDEBUG
10575 /* These routines are used inside assert() statements only. */
10576 SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*);
@@ -10498,13 +10577,11 @@
10577 SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*);
10578 SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
10579 #endif
10580 #else
10581
 
10582 # define sqlite3BtreeLeave(X)
 
10583 # define sqlite3BtreeLeaveCursor(X)
10584 # define sqlite3BtreeLeaveAll(X)
10585
10586 # define sqlite3BtreeHoldsMutex(X) 1
10587 # define sqlite3BtreeHoldsAllMutexes(X) 1
@@ -10899,19 +10976,24 @@
10976 SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
10977 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
10978 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
10979 SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
10980 SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
10981 #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
10982 SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
10983 #else
10984 # define sqlite3VdbeVerifyNoMallocRequired(A,B)
10985 #endif
10986 SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
10987 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
10988 SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
10989 SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
10990 SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
10991 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
10992 SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
10993 SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
10994 SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
10995 SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
10996 SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
10997 SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
10998 SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
10999 SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
@@ -11215,10 +11297,11 @@
11297 #endif
11298 SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
11299 SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
11300 SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
11301 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
11302 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
11303 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
11304 SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
11305 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
11306 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
11307 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
@@ -11309,10 +11392,12 @@
11392 #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before
11393 ** writing this page to the database */
11394 #define PGHDR_NEED_READ 0x010 /* Content is unread */
11395 #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
11396 #define PGHDR_MMAP 0x040 /* This is an mmap page object */
11397
11398 #define PGHDR_WAL_APPEND 0x080 /* Appended to wal file */
11399
11400 /* Initialize and shutdown the page cache subsystem */
11401 SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
11402 SQLITE_PRIVATE void sqlite3PcacheShutdown(void);
11403
@@ -12162,13 +12247,12 @@
12247 struct FuncDef {
12248 i16 nArg; /* Number of arguments. -1 means unlimited */
12249 u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
12250 void *pUserData; /* User data parameter */
12251 FuncDef *pNext; /* Next function with same name */
12252 void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
12253 void (*xFinalize)(sqlite3_context*); /* Agg finalizer */
 
12254 char *zName; /* SQL name of the function. */
12255 FuncDef *pHash; /* Next with a different name but the same hash */
12256 FuncDestructor *pDestructor; /* Reference counted destructor function */
12257 };
12258
@@ -12247,32 +12331,32 @@
12331 ** FuncDef.flags variable is set to the value passed as the flags
12332 ** parameter.
12333 */
12334 #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
12335 {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12336 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
12337 #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
12338 {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12339 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
12340 #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
12341 {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12342 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
12343 #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
12344 {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
12345 SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
12346 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
12347 {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
12348 pArg, 0, xFunc, 0, #zName, 0, 0}
12349 #define LIKEFUNC(zName, nArg, arg, flags) \
12350 {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
12351 (void *)arg, 0, likeFunc, 0, #zName, 0, 0}
12352 #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
12353 {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
12354 SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
12355 #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
12356 {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
12357 SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
12358
12359 /*
12360 ** All current savepoints are stored in a linked list starting at
12361 ** sqlite3.pSavepoint. The first element in the list is the most recently
12362 ** opened savepoint. Savepoints are added to the list by the vdbe
@@ -13579,11 +13663,11 @@
13663 ** each recursion. The boundary between these two regions is determined
13664 ** using offsetof(Parse,nVar) so the nVar field must be the first field
13665 ** in the recursive region.
13666 ************************************************************************/
13667
13668 ynVar nVar; /* Number of '?' variables seen in the SQL so far */
13669 int nzVar; /* Number of available slots in azVar[] */
13670 u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
13671 u8 explain; /* True if the EXPLAIN flag is found on the query */
13672 #ifndef SQLITE_OMIT_VIRTUALTABLE
13673 u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
@@ -13861,14 +13945,14 @@
13945
13946 /*
13947 ** Context pointer passed down through the tree-walk.
13948 */
13949 struct Walker {
13950 Parse *pParse; /* Parser context. */
13951 int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */
13952 int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
13953 void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
 
13954 int walkerDepth; /* Number of subqueries */
13955 u8 eCode; /* A small processing code */
13956 union { /* Extra data for callback */
13957 NameContext *pNC; /* Naming context */
13958 int n; /* A counter */
@@ -14135,11 +14219,10 @@
14219 SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
14220 SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
14221 SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
14222 SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
14223 SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
 
14224 SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
14225 SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
14226 SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
14227 SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
14228 SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
@@ -16066,15 +16149,19 @@
16149 SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
16150 SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
16151 SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
16152 SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
16153
16154 #if !defined(SQLITE_OMIT_SHARED_CACHE)
16155 SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
 
16156 #else
16157 # define sqlite3VdbeEnter(X)
16158 #endif
16159
16160 #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
16161 SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
16162 #else
16163 # define sqlite3VdbeLeave(X)
16164 #endif
16165
16166 #ifdef SQLITE_DEBUG
16167 SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
@@ -16508,52 +16595,68 @@
16595 char tzSet; /* Timezone was set explicitly */
16596 };
16597
16598
16599 /*
16600 ** Convert zDate into one or more integers according to the conversion
16601 ** specifier zFormat.
16602 **
16603 ** zFormat[] contains 4 characters for each integer converted, except for
16604 ** the last integer which is specified by three characters. The meaning
16605 ** of a four-character format specifiers ABCD is:
16606 **
16607 ** A: number of digits to convert. Always "2" or "4".
16608 ** B: minimum value. Always "0" or "1".
16609 ** C: maximum value, decoded as:
16610 ** a: 12
16611 ** b: 14
16612 ** c: 24
16613 ** d: 31
16614 ** e: 59
16615 ** f: 9999
16616 ** D: the separator character, or \000 to indicate this is the
16617 ** last number to convert.
16618 **
16619 ** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would
16620 ** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-".
16621 ** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates
16622 ** the 2-digit day which is the last integer in the set.
16623 **
16624 ** The function returns the number of successful conversions.
16625 */
16626 static int getDigits(const char *zDate, const char *zFormat, ...){
16627 /* The aMx[] array translates the 3rd character of each format
16628 ** spec into a max size: a b c d e f */
16629 static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
16630 va_list ap;
 
 
 
 
 
 
16631 int cnt = 0;
16632 char nextC;
16633 va_start(ap, zFormat);
16634 do{
16635 char N = zFormat[0] - '0';
16636 char min = zFormat[1] - '0';
16637 int val = 0;
16638 u16 max;
16639
16640 assert( zFormat[2]>='a' && zFormat[2]<='f' );
16641 max = aMx[zFormat[2] - 'a'];
16642 nextC = zFormat[3];
16643 val = 0;
16644 while( N-- ){
16645 if( !sqlite3Isdigit(*zDate) ){
16646 goto end_getDigits;
16647 }
16648 val = val*10 + *zDate - '0';
16649 zDate++;
16650 }
16651 if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){
16652 goto end_getDigits;
16653 }
16654 *va_arg(ap,int*) = val;
16655 zDate++;
16656 cnt++;
16657 zFormat += 4;
16658 }while( nextC );
16659 end_getDigits:
16660 va_end(ap);
16661 return cnt;
16662 }
@@ -16590,11 +16693,11 @@
16693 goto zulu_time;
16694 }else{
16695 return c!=0;
16696 }
16697 zDate++;
16698 if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
16699 return 1;
16700 }
16701 zDate += 5;
16702 p->tz = sgn*(nMn + nHr*60);
16703 zulu_time:
@@ -16611,17 +16714,17 @@
16714 ** Return 1 if there is a parsing error and 0 on success.
16715 */
16716 static int parseHhMmSs(const char *zDate, DateTime *p){
16717 int h, m, s;
16718 double ms = 0.0;
16719 if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){
16720 return 1;
16721 }
16722 zDate += 5;
16723 if( *zDate==':' ){
16724 zDate++;
16725 if( getDigits(zDate, "20e", &s)!=1 ){
16726 return 1;
16727 }
16728 zDate += 2;
16729 if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){
16730 double rScale = 1.0;
@@ -16705,11 +16808,11 @@
16808 zDate++;
16809 neg = 1;
16810 }else{
16811 neg = 0;
16812 }
16813 if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){
16814 return 1;
16815 }
16816 zDate += 10;
16817 while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; }
16818 if( parseHhMmSs(zDate, p)==0 ){
@@ -19758,10 +19861,11 @@
19861 /*
19862 ** Mutex to control access to the memory allocation subsystem.
19863 */
19864 sqlite3_mutex *mutex;
19865
19866 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
19867 /*
19868 ** Performance statistics
19869 */
19870 u64 nAlloc; /* Total number of calls to malloc */
19871 u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
@@ -19769,10 +19873,11 @@
19873 u32 currentOut; /* Current checkout, including internal fragmentation */
19874 u32 currentCount; /* Current number of distinct checkouts */
19875 u32 maxOut; /* Maximum instantaneous currentOut */
19876 u32 maxCount; /* Maximum instantaneous currentCount */
19877 u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
19878 #endif
19879
19880 /*
19881 ** Lists of free blocks. aiFreelist[0] is a list of free blocks of
19882 ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
19883 ** aiFreelist[2] holds free blocks of size szAtom*4. And so forth.
@@ -19880,18 +19985,21 @@
19985 int iLogsize; /* Log2 of iFullSz/POW2_MIN */
19986
19987 /* nByte must be a positive */
19988 assert( nByte>0 );
19989
19990 /* No more than 1GiB per allocation */
19991 if( nByte > 0x40000000 ) return 0;
19992
19993 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
19994 /* Keep track of the maximum allocation request. Even unfulfilled
19995 ** requests are counted */
19996 if( (u32)nByte>mem5.maxRequest ){
 
 
 
19997 mem5.maxRequest = nByte;
19998 }
19999 #endif
20000
20001
20002 /* Round nByte up to the next valid power of two */
20003 for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){}
20004
20005 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
@@ -19914,18 +20022,20 @@
20022 mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
20023 memsys5Link(i+newSize, iBin);
20024 }
20025 mem5.aCtrl[i] = iLogsize;
20026
20027 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
20028 /* Update allocator performance statistics. */
20029 mem5.nAlloc++;
20030 mem5.totalAlloc += iFullSz;
20031 mem5.totalExcess += iFullSz - nByte;
20032 mem5.currentCount++;
20033 mem5.currentOut += iFullSz;
20034 if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
20035 if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
20036 #endif
20037
20038 #ifdef SQLITE_DEBUG
20039 /* Make sure the allocated memory does not assume that it is set to zero
20040 ** or retains a value from a previous allocation */
20041 memset(&mem5.zPool[i*mem5.szAtom], 0xAA, iFullSz);
@@ -19956,16 +20066,19 @@
20066 size = 1<<iLogsize;
20067 assert( iBlock+size-1<(u32)mem5.nBlock );
20068
20069 mem5.aCtrl[iBlock] |= CTRL_FREE;
20070 mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
20071
20072 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
20073 assert( mem5.currentCount>0 );
20074 assert( mem5.currentOut>=(size*mem5.szAtom) );
20075 mem5.currentCount--;
20076 mem5.currentOut -= size*mem5.szAtom;
20077 assert( mem5.currentOut>0 || mem5.currentCount==0 );
20078 assert( mem5.currentCount>0 || mem5.currentOut==0 );
20079 #endif
20080
20081 mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
20082 while( ALWAYS(iLogsize<LOGMAX) ){
20083 int iBuddy;
20084 if( (iBlock>>iLogsize) & 1 ){
@@ -22281,12 +22394,13 @@
22394 }
22395 return p;
22396 }
22397
22398 /*
22399 ** Allocate memory, either lookaside (if possible) or heap.
22400 ** If the allocation fails, set the mallocFailed flag in
22401 ** the connection pointer.
22402 **
22403 ** If db!=0 and db->mallocFailed is true (indicating a prior malloc
22404 ** failure on the same database connection) then always return 0.
22405 ** Hence for a particular database connection, once malloc starts
22406 ** failing, it fails consistently until mallocFailed is reset.
@@ -22298,12 +22412,12 @@
22412 ** if( b ) a[10] = 9;
22413 **
22414 ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
22415 ** that all prior mallocs (ex: "a") worked too.
22416 */
22417 static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n);
22418 SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
 
22419 assert( db==0 || sqlite3_mutex_held(db->mutex) );
22420 assert( db==0 || db->pnBytesFreed==0 );
22421 #ifndef SQLITE_OMIT_LOOKASIDE
22422 if( db ){
22423 LookasideSlot *pBuf;
@@ -22329,11 +22443,14 @@
22443 #else
22444 if( db && db->mallocFailed ){
22445 return 0;
22446 }
22447 #endif
22448 return dbMallocRawFinish(db, n);
22449 }
22450 static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
22451 void *p = sqlite3Malloc(n);
22452 if( !p && db ){
22453 db->mallocFailed = 1;
22454 }
22455 sqlite3MemdebugSetType(p,
22456 (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
@@ -27479,37 +27596,55 @@
27596 #define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
27597
27598 { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
27599 #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
27600
27601 #if defined(HAVE_FCHOWN)
27602 { "fchown", (sqlite3_syscall_ptr)fchown, 0 },
27603 #else
27604 { "fchown", (sqlite3_syscall_ptr)0, 0 },
27605 #endif
27606 #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
27607
27608 { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 },
27609 #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
27610
27611 #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
27612 { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
27613 #else
27614 { "mmap", (sqlite3_syscall_ptr)0, 0 },
27615 #endif
27616 #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
27617
27618 #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
27619 { "munmap", (sqlite3_syscall_ptr)munmap, 0 },
27620 #else
27621 { "munmap", (sqlite3_syscall_ptr)0, 0 },
27622 #endif
27623 #define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
27624
27625 #if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
27626 { "mremap", (sqlite3_syscall_ptr)mremap, 0 },
27627 #else
27628 { "mremap", (sqlite3_syscall_ptr)0, 0 },
27629 #endif
27630 #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
27631
27632 #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
27633 { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
27634 #else
27635 { "getpagesize", (sqlite3_syscall_ptr)0, 0 },
27636 #endif
27637 #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
27638
27639 #if defined(HAVE_READLINK)
27640 { "readlink", (sqlite3_syscall_ptr)readlink, 0 },
27641 #else
27642 { "readlink", (sqlite3_syscall_ptr)0, 0 },
27643 #endif
27644 #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
27645
 
27646
27647 }; /* End of the overrideable system calls */
27648
27649
27650 /*
@@ -27516,14 +27651,14 @@
27651 ** On some systems, calls to fchown() will trigger a message in a security
27652 ** log if they come from non-root processes. So avoid calling fchown() if
27653 ** we are not running as root.
27654 */
27655 static int robustFchown(int fd, uid_t uid, gid_t gid){
27656 #if defined(HAVE_FCHOWN)
 
 
27657 return osGeteuid() ? 0 : osFchown(fd,uid,gid);
27658 #else
27659 return 0;
27660 #endif
27661 }
27662
27663 /*
27664 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -32986,10 +33121,11 @@
33121 SimulateIOError( return SQLITE_ERROR );
33122
33123 assert( pVfs->mxPathname==MAX_PATHNAME );
33124 UNUSED_PARAMETER(pVfs);
33125
33126 #if defined(HAVE_READLINK)
33127 /* Attempt to resolve the path as if it were a symbolic link. If it is
33128 ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if
33129 ** the identified file is not a symbolic link or does not exist, then
33130 ** zPath is copied directly into zOut. Either way, nByte is left set to
33131 ** the size of the string copied into zOut[] in bytes. */
@@ -33001,10 +33137,11 @@
33137 sqlite3_snprintf(nOut, zOut, "%s", zPath);
33138 nByte = sqlite3Strlen30(zOut);
33139 }else{
33140 zOut[nByte] = '\0';
33141 }
33142 #endif
33143
33144 /* If buffer zOut[] now contains an absolute path there is nothing more
33145 ** to do. If it contains a relative path, do the following:
33146 **
33147 ** * move the relative path string so that it is at the end of th
@@ -43327,10 +43464,11 @@
43464 # define sqlite3WalCallback(z) 0
43465 # define sqlite3WalExclusiveMode(y,z) 0
43466 # define sqlite3WalHeapMemory(z) 0
43467 # define sqlite3WalFramesize(z) 0
43468 # define sqlite3WalFindFrame(x,y,z) 0
43469 # define sqlite3WalFile(x) 0
43470 #else
43471
43472 #define WAL_SAVEPOINT_NDATA 4
43473
43474 /* Connection to a write-ahead log (WAL) file.
@@ -43421,10 +43559,13 @@
43559 ** stored in each frame (i.e. the db page-size when the WAL was created).
43560 */
43561 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
43562 #endif
43563
43564 /* Return the sqlite3_file object for the WAL file */
43565 SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
43566
43567 #endif /* ifndef SQLITE_OMIT_WAL */
43568 #endif /* _WAL_H_ */
43569
43570 /************** End of wal.h *************************************************/
43571 /************** Continuing where we left off in pager.c **********************/
@@ -49032,11 +49173,11 @@
49173 if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
49174 rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
49175 if( rc!=SQLITE_OK ){
49176 return rc;
49177 }
49178 (void)sqlite3WalExclusiveMode(pPager->pWal, 1);
49179 }
49180
49181 /* Grab the write lock on the log file. If successful, upgrade to
49182 ** PAGER_RESERVED state. Otherwise, return an error code to the caller.
49183 ** The busy-handler is not invoked if another connection already
@@ -50096,10 +50237,22 @@
50237 ** not yet been opened.
50238 */
50239 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
50240 return pPager->fd;
50241 }
50242
50243 /*
50244 ** Return the file handle for the journal file (if it exists).
50245 ** This will be either the rollback journal or the WAL file.
50246 */
50247 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
50248 #if SQLITE_OMIT_WAL
50249 return pPager->jfd;
50250 #else
50251 return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
50252 #endif
50253 }
50254
50255 /*
50256 ** Return the full pathname of the journal file.
50257 */
50258 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
@@ -51202,10 +51355,11 @@
51355 u8 truncateOnCommit; /* True to truncate WAL file on commit */
51356 u8 syncHeader; /* Fsync the WAL header if true */
51357 u8 padToSectorBoundary; /* Pad transactions out to the next sector */
51358 WalIndexHdr hdr; /* Wal-index header for current transaction */
51359 u32 minFrame; /* Ignore wal frames before this one */
51360 u32 iReCksum; /* On commit, recalculate checksums from here */
51361 const char *zWalName; /* Name of WAL file */
51362 u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
51363 #ifdef SQLITE_DEBUG
51364 u8 lockError; /* True if a locking error has occurred */
51365 #endif
@@ -51455,18 +51609,22 @@
51609 int nativeCksum; /* True for native byte-order checksums */
51610 u32 *aCksum = pWal->hdr.aFrameCksum;
51611 assert( WAL_FRAME_HDRSIZE==24 );
51612 sqlite3Put4byte(&aFrame[0], iPage);
51613 sqlite3Put4byte(&aFrame[4], nTruncate);
51614 if( pWal->iReCksum==0 ){
51615 memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
51616
51617 nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
51618 walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
51619 walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
51620
51621 sqlite3Put4byte(&aFrame[16], aCksum[0]);
51622 sqlite3Put4byte(&aFrame[20], aCksum[1]);
51623 }else{
51624 memset(&aFrame[8], 0, 16);
51625 }
51626 }
51627
51628 /*
51629 ** Check to see if the frame with header in aFrame[] and content
51630 ** in aData[] is valid. If it is a valid frame, fill *piPage and
@@ -53389,10 +53547,11 @@
53547 int rc;
53548
53549 /* Cannot start a write transaction without first holding a read
53550 ** transaction. */
53551 assert( pWal->readLock>=0 );
53552 assert( pWal->writeLock==0 && pWal->iReCksum==0 );
53553
53554 if( pWal->readOnly ){
53555 return SQLITE_READONLY;
53556 }
53557
@@ -53424,10 +53583,11 @@
53583 */
53584 SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
53585 if( pWal->writeLock ){
53586 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
53587 pWal->writeLock = 0;
53588 pWal->iReCksum = 0;
53589 pWal->truncateOnCommit = 0;
53590 }
53591 return SQLITE_OK;
53592 }
53593
@@ -53641,10 +53801,63 @@
53801 if( rc ) return rc;
53802 /* Write the page data */
53803 rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
53804 return rc;
53805 }
53806
53807 /*
53808 ** This function is called as part of committing a transaction within which
53809 ** one or more frames have been overwritten. It updates the checksums for
53810 ** all frames written to the wal file by the current transaction starting
53811 ** with the earliest to have been overwritten.
53812 **
53813 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
53814 */
53815 static int walRewriteChecksums(Wal *pWal, u32 iLast){
53816 const int szPage = pWal->szPage;/* Database page size */
53817 int rc = SQLITE_OK; /* Return code */
53818 u8 *aBuf; /* Buffer to load data from wal file into */
53819 u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */
53820 u32 iRead; /* Next frame to read from wal file */
53821 i64 iCksumOff;
53822
53823 aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
53824 if( aBuf==0 ) return SQLITE_NOMEM;
53825
53826 /* Find the checksum values to use as input for the recalculating the
53827 ** first checksum. If the first frame is frame 1 (implying that the current
53828 ** transaction restarted the wal file), these values must be read from the
53829 ** wal-file header. Otherwise, read them from the frame header of the
53830 ** previous frame. */
53831 assert( pWal->iReCksum>0 );
53832 if( pWal->iReCksum==1 ){
53833 iCksumOff = 24;
53834 }else{
53835 iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16;
53836 }
53837 rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff);
53838 pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf);
53839 pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]);
53840
53841 iRead = pWal->iReCksum;
53842 pWal->iReCksum = 0;
53843 for(; rc==SQLITE_OK && iRead<=iLast; iRead++){
53844 i64 iOff = walFrameOffset(iRead, szPage);
53845 rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff);
53846 if( rc==SQLITE_OK ){
53847 u32 iPgno, nDbSize;
53848 iPgno = sqlite3Get4byte(aBuf);
53849 nDbSize = sqlite3Get4byte(&aBuf[4]);
53850
53851 walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame);
53852 rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff);
53853 }
53854 }
53855
53856 sqlite3_free(aBuf);
53857 return rc;
53858 }
53859
53860 /*
53861 ** Write a set of frames to the log. The caller must hold the write-lock
53862 ** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
53863 */
@@ -53662,10 +53875,12 @@
53875 PgHdr *pLast = 0; /* Last frame in list */
53876 int nExtra = 0; /* Number of extra copies of last page */
53877 int szFrame; /* The size of a single frame */
53878 i64 iOffset; /* Next byte to write in WAL file */
53879 WalWriter w; /* The writer */
53880 u32 iFirst = 0; /* First frame that may be overwritten */
53881 WalIndexHdr *pLive; /* Pointer to shared header */
53882
53883 assert( pList );
53884 assert( pWal->writeLock );
53885
53886 /* If this frame set completes a transaction, then nTruncate>0. If
@@ -53676,10 +53891,15 @@
53891 { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
53892 WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
53893 pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
53894 }
53895 #endif
53896
53897 pLive = (WalIndexHdr*)walIndexHdr(pWal);
53898 if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){
53899 iFirst = pLive->mxFrame+1;
53900 }
53901
53902 /* See if it is possible to write these frames into the start of the
53903 ** log file, instead of appending to it at pWal->hdr.mxFrame.
53904 */
53905 if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
@@ -53741,17 +53961,45 @@
53961 szFrame = szPage + WAL_FRAME_HDRSIZE;
53962
53963 /* Write all frames into the log file exactly once */
53964 for(p=pList; p; p=p->pDirty){
53965 int nDbSize; /* 0 normally. Positive == commit flag */
53966
53967 /* Check if this page has already been written into the wal file by
53968 ** the current transaction. If so, overwrite the existing frame and
53969 ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
53970 ** checksums must be recomputed when the transaction is committed. */
53971 if( iFirst && (p->pDirty || isCommit==0) ){
53972 u32 iWrite = 0;
53973 VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
53974 assert( rc==SQLITE_OK || iWrite==0 );
53975 if( iWrite>=iFirst ){
53976 i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
53977 if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
53978 pWal->iReCksum = iWrite;
53979 }
53980 rc = sqlite3OsWrite(pWal->pWalFd, p->pData, szPage, iOff);
53981 if( rc ) return rc;
53982 p->flags &= ~PGHDR_WAL_APPEND;
53983 continue;
53984 }
53985 }
53986
53987 iFrame++;
53988 assert( iOffset==walFrameOffset(iFrame, szPage) );
53989 nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
53990 rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
53991 if( rc ) return rc;
53992 pLast = p;
53993 iOffset += szFrame;
53994 p->flags |= PGHDR_WAL_APPEND;
53995 }
53996
53997 /* Recalculate checksums within the wal file if required. */
53998 if( isCommit && pWal->iReCksum ){
53999 rc = walRewriteChecksums(pWal, iFrame);
54000 if( rc ) return rc;
54001 }
54002
54003 /* If this is the end of a transaction, then we might need to pad
54004 ** the transaction and/or sync the WAL file.
54005 **
@@ -53799,10 +54047,11 @@
54047 ** guarantees that there are no other writers, and no data that may
54048 ** be in use by existing readers is being overwritten.
54049 */
54050 iFrame = pWal->hdr.mxFrame;
54051 for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
54052 if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue;
54053 iFrame++;
54054 rc = walIndexAppend(pWal, iFrame, p->pgno);
54055 }
54056 while( rc==SQLITE_OK && nExtra>0 ){
54057 iFrame++;
@@ -53911,10 +54160,11 @@
54160 }
54161 }
54162
54163 /* Copy data from the log to the database file. */
54164 if( rc==SQLITE_OK ){
54165
54166 if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
54167 rc = SQLITE_CORRUPT_BKPT;
54168 }else{
54169 rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
54170 }
@@ -54066,10 +54316,16 @@
54316 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
54317 assert( pWal==0 || pWal->readLock>=0 );
54318 return (pWal ? pWal->szPage : 0);
54319 }
54320 #endif
54321
54322 /* Return the sqlite3_file object for the WAL file
54323 */
54324 SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
54325 return pWal->pWalFd;
54326 }
54327
54328 #endif /* #ifndef SQLITE_OMIT_WAL */
54329
54330 /************** End of wal.c *************************************************/
54331 /************** Begin file btmutex.c *****************************************/
@@ -54368,11 +54624,10 @@
54624 struct MemPage {
54625 u8 isInit; /* True if previously initialized. MUST BE FIRST! */
54626 u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
54627 u8 intKey; /* True if table b-trees. False for index b-trees */
54628 u8 intKeyLeaf; /* True if the leaf of an intKey table */
 
54629 u8 leaf; /* True if a leaf page */
54630 u8 hdrOffset; /* 100 for page 1. 0 otherwise */
54631 u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
54632 u8 max1bytePayload; /* min(maxLocal,127) */
54633 u8 bBusy; /* Prevent endless loops on corrupt database files */
@@ -54955,25 +55210,10 @@
55210
55211 return (p->sharable==0 || p->locked);
55212 }
55213 #endif
55214
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55215
55216 /*
55217 ** Enter the mutex on every Btree associated with a database
55218 ** connection. This is needed (for example) prior to parsing
55219 ** a statement since we will be comparing table and column names
@@ -55004,18 +55244,10 @@
55244 p = db->aDb[i].pBt;
55245 if( p ) sqlite3BtreeLeave(p);
55246 }
55247 }
55248
 
 
 
 
 
 
 
 
55249 #ifndef NDEBUG
55250 /*
55251 ** Return true if the current thread holds the database connection
55252 ** mutex and all required BtShared mutexes.
55253 **
@@ -55085,10 +55317,29 @@
55317 p->pBt->db = p->db;
55318 }
55319 }
55320 }
55321 #endif /* if SQLITE_THREADSAFE */
55322
55323 #ifndef SQLITE_OMIT_INCRBLOB
55324 /*
55325 ** Enter a mutex on a Btree given a cursor owned by that Btree.
55326 **
55327 ** These entry points are used by incremental I/O only. Enter() is required
55328 ** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
55329 ** the build is threadsafe. Leave() is only required by threadsafe builds.
55330 */
55331 SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
55332 sqlite3BtreeEnter(pCur->pBtree);
55333 }
55334 # if SQLITE_THREADSAFE
55335 SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
55336 sqlite3BtreeLeave(pCur->pBtree);
55337 }
55338 # endif
55339 #endif /* ifndef SQLITE_OMIT_INCRBLOB */
55340
55341 #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
55342
55343 /************** End of btmutex.c *********************************************/
55344 /************** Begin file btree.c *******************************************/
55345 /*
@@ -55541,10 +55792,14 @@
55792 */
55793 #ifdef SQLITE_DEBUG
55794 static int cursorHoldsMutex(BtCursor *p){
55795 return sqlite3_mutex_held(p->pBt->mutex);
55796 }
55797 static int cursorOwnsBtShared(BtCursor *p){
55798 assert( cursorHoldsMutex(p) );
55799 return (p->pBtree->db==p->pBt->db);
55800 }
55801 #endif
55802
55803 /*
55804 ** Invalidate the overflow cache of the cursor passed as the first argument.
55805 ** on the shared btree structure pBt.
@@ -55877,11 +56132,11 @@
56132 ** saveCursorPosition().
56133 */
56134 static int btreeRestoreCursorPosition(BtCursor *pCur){
56135 int rc;
56136 int skipNext;
56137 assert( cursorOwnsBtShared(pCur) );
56138 assert( pCur->eState>=CURSOR_REQUIRESEEK );
56139 if( pCur->eState==CURSOR_FAULT ){
56140 return pCur->skipNext;
56141 }
56142 pCur->eState = CURSOR_INVALID;
@@ -56166,11 +56421,10 @@
56421 u8 *pCell, /* Pointer to the cell text. */
56422 CellInfo *pInfo /* Fill in this structure */
56423 ){
56424 assert( sqlite3_mutex_held(pPage->pBt->mutex) );
56425 assert( pPage->leaf==0 );
 
56426 assert( pPage->childPtrSize==4 );
56427 #ifndef SQLITE_DEBUG
56428 UNUSED_PARAMETER(pPage);
56429 #endif
56430 pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
@@ -56188,12 +56442,10 @@
56442 u32 nPayload; /* Number of bytes of cell payload */
56443 u64 iKey; /* Extracted Key value */
56444
56445 assert( sqlite3_mutex_held(pPage->pBt->mutex) );
56446 assert( pPage->leaf==0 || pPage->leaf==1 );
 
 
56447 assert( pPage->intKeyLeaf );
56448 assert( pPage->childPtrSize==0 );
56449 pIter = pCell;
56450
56451 /* The next block of code is equivalent to:
@@ -56258,11 +56510,10 @@
56510 u32 nPayload; /* Number of bytes of cell payload */
56511
56512 assert( sqlite3_mutex_held(pPage->pBt->mutex) );
56513 assert( pPage->leaf==0 || pPage->leaf==1 );
56514 assert( pPage->intKeyLeaf==0 );
 
56515 pIter = pCell + pPage->childPtrSize;
56516 nPayload = *pIter;
56517 if( nPayload>=0x80 ){
56518 u8 *pEnd = &pIter[8];
56519 nPayload &= 0x7f;
@@ -56319,11 +56570,10 @@
56570 ** this function verifies that this invariant is not violated. */
56571 CellInfo debuginfo;
56572 pPage->xParseCell(pPage, pCell, &debuginfo);
56573 #endif
56574
 
56575 nSize = *pIter;
56576 if( nSize>=0x80 ){
56577 pEnd = &pIter[8];
56578 nSize &= 0x7f;
56579 do{
@@ -56777,15 +57027,13 @@
57027 ** table b-tree page. */
57028 assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
57029 pPage->intKey = 1;
57030 if( pPage->leaf ){
57031 pPage->intKeyLeaf = 1;
 
57032 pPage->xParseCell = btreeParseCellPtr;
57033 }else{
57034 pPage->intKeyLeaf = 0;
 
57035 pPage->xCellSize = cellSizePtrNoPayload;
57036 pPage->xParseCell = btreeParseCellPtrNoPayload;
57037 }
57038 pPage->maxLocal = pBt->maxLeaf;
57039 pPage->minLocal = pBt->minLeaf;
@@ -56796,11 +57044,10 @@
57044 /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
57045 ** index b-tree page. */
57046 assert( (PTF_ZERODATA|PTF_LEAF)==10 );
57047 pPage->intKey = 0;
57048 pPage->intKeyLeaf = 0;
 
57049 pPage->xParseCell = btreeParseCellPtrIndex;
57050 pPage->maxLocal = pBt->maxLocal;
57051 pPage->minLocal = pBt->minLocal;
57052 }else{
57053 /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
@@ -58217,11 +58464,10 @@
58464 ** no progress. By returning SQLITE_BUSY and not invoking the busy callback
58465 ** when A already has a read lock, we encourage A to give up and let B
58466 ** proceed.
58467 */
58468 SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
 
58469 BtShared *pBt = p->pBt;
58470 int rc = SQLITE_OK;
58471
58472 sqlite3BtreeEnter(p);
58473 btreeIntegrity(p);
@@ -58240,31 +58486,34 @@
58486 rc = SQLITE_READONLY;
58487 goto trans_begun;
58488 }
58489
58490 #ifndef SQLITE_OMIT_SHARED_CACHE
58491 {
58492 sqlite3 *pBlock = 0;
58493 /* If another database handle has already opened a write transaction
58494 ** on this shared-btree structure and a second write transaction is
58495 ** requested, return SQLITE_LOCKED.
58496 */
58497 if( (wrflag && pBt->inTransaction==TRANS_WRITE)
58498 || (pBt->btsFlags & BTS_PENDING)!=0
58499 ){
58500 pBlock = pBt->pWriter->db;
58501 }else if( wrflag>1 ){
58502 BtLock *pIter;
58503 for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
58504 if( pIter->pBtree!=p ){
58505 pBlock = pIter->pBtree->db;
58506 break;
58507 }
58508 }
58509 }
58510 if( pBlock ){
58511 sqlite3ConnectionBlocked(p->db, pBlock);
58512 rc = SQLITE_LOCKED_SHAREDCACHE;
58513 goto trans_begun;
58514 }
58515 }
58516 #endif
58517
58518 /* Any read-only or read-write transaction implies a read-lock on
58519 ** page 1. So if some other shared-cache client already has a write-lock
@@ -59377,11 +59626,11 @@
59626 ** Failure is not possible. This function always returns SQLITE_OK.
59627 ** It might just as well be a procedure (returning void) but we continue
59628 ** to return an integer result code for historical reasons.
59629 */
59630 SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
59631 assert( cursorOwnsBtShared(pCur) );
59632 assert( pCur->eState==CURSOR_VALID );
59633 assert( pCur->iPage>=0 );
59634 assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
59635 assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
59636 getCellInfo(pCur);
@@ -59757,11 +60006,11 @@
60006 if ( pCur->eState==CURSOR_INVALID ){
60007 return SQLITE_ABORT;
60008 }
60009 #endif
60010
60011 assert( cursorOwnsBtShared(pCur) );
60012 rc = restoreCursorPosition(pCur);
60013 if( rc==SQLITE_OK ){
60014 assert( pCur->eState==CURSOR_VALID );
60015 assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
60016 assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
@@ -59795,11 +60044,11 @@
60044 ){
60045 u32 amt;
60046 assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
60047 assert( pCur->eState==CURSOR_VALID );
60048 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60049 assert( cursorOwnsBtShared(pCur) );
60050 assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
60051 assert( pCur->info.nSize>0 );
60052 assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
60053 assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
60054 amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
@@ -59841,11 +60090,11 @@
60090 ** vice-versa).
60091 */
60092 static int moveToChild(BtCursor *pCur, u32 newPgno){
60093 BtShared *pBt = pCur->pBt;
60094
60095 assert( cursorOwnsBtShared(pCur) );
60096 assert( pCur->eState==CURSOR_VALID );
60097 assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
60098 assert( pCur->iPage>=0 );
60099 if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
60100 return SQLITE_CORRUPT_BKPT;
@@ -59887,11 +60136,11 @@
60136 ** to the page we are coming from. If we are coming from the
60137 ** right-most child page then pCur->idx is set to one more than
60138 ** the largest cell index.
60139 */
60140 static void moveToParent(BtCursor *pCur){
60141 assert( cursorOwnsBtShared(pCur) );
60142 assert( pCur->eState==CURSOR_VALID );
60143 assert( pCur->iPage>0 );
60144 assert( pCur->apPage[pCur->iPage] );
60145 assertParentIndex(
60146 pCur->apPage[pCur->iPage-1],
@@ -59927,11 +60176,11 @@
60176 */
60177 static int moveToRoot(BtCursor *pCur){
60178 MemPage *pRoot;
60179 int rc = SQLITE_OK;
60180
60181 assert( cursorOwnsBtShared(pCur) );
60182 assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
60183 assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
60184 assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
60185 if( pCur->eState>=CURSOR_REQUIRESEEK ){
60186 if( pCur->eState==CURSOR_FAULT ){
@@ -60006,11 +60255,11 @@
60255 static int moveToLeftmost(BtCursor *pCur){
60256 Pgno pgno;
60257 int rc = SQLITE_OK;
60258 MemPage *pPage;
60259
60260 assert( cursorOwnsBtShared(pCur) );
60261 assert( pCur->eState==CURSOR_VALID );
60262 while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
60263 assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
60264 pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
60265 rc = moveToChild(pCur, pgno);
@@ -60031,11 +60280,11 @@
60280 static int moveToRightmost(BtCursor *pCur){
60281 Pgno pgno;
60282 int rc = SQLITE_OK;
60283 MemPage *pPage = 0;
60284
60285 assert( cursorOwnsBtShared(pCur) );
60286 assert( pCur->eState==CURSOR_VALID );
60287 while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
60288 pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
60289 pCur->aiIdx[pCur->iPage] = pPage->nCell;
60290 rc = moveToChild(pCur, pgno);
@@ -60052,11 +60301,11 @@
60301 ** or set *pRes to 1 if the table is empty.
60302 */
60303 SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
60304 int rc;
60305
60306 assert( cursorOwnsBtShared(pCur) );
60307 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60308 rc = moveToRoot(pCur);
60309 if( rc==SQLITE_OK ){
60310 if( pCur->eState==CURSOR_INVALID ){
60311 assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
@@ -60075,11 +60324,11 @@
60324 ** or set *pRes to 1 if the table is empty.
60325 */
60326 SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
60327 int rc;
60328
60329 assert( cursorOwnsBtShared(pCur) );
60330 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60331
60332 /* If the cursor already points to the last entry, this is a no-op. */
60333 if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
60334 #ifdef SQLITE_DEBUG
@@ -60153,11 +60402,11 @@
60402 int *pRes /* Write search results here */
60403 ){
60404 int rc;
60405 RecordCompare xRecordCompare;
60406
60407 assert( cursorOwnsBtShared(pCur) );
60408 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
60409 assert( pRes );
60410 assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
60411
60412 /* If the cursor is already positioned at the point we are trying
@@ -60401,11 +60650,11 @@
60650 static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
60651 int rc;
60652 int idx;
60653 MemPage *pPage;
60654
60655 assert( cursorOwnsBtShared(pCur) );
60656 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60657 assert( *pRes==0 );
60658 if( pCur->eState!=CURSOR_VALID ){
60659 assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
60660 rc = restoreCursorPosition(pCur);
@@ -60465,11 +60714,11 @@
60714 return moveToLeftmost(pCur);
60715 }
60716 }
60717 SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
60718 MemPage *pPage;
60719 assert( cursorOwnsBtShared(pCur) );
60720 assert( pRes!=0 );
60721 assert( *pRes==0 || *pRes==1 );
60722 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60723 pCur->info.nSize = 0;
60724 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
@@ -60510,11 +60759,11 @@
60759 */
60760 static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
60761 int rc;
60762 MemPage *pPage;
60763
60764 assert( cursorOwnsBtShared(pCur) );
60765 assert( pRes!=0 );
60766 assert( *pRes==0 );
60767 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60768 assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
60769 assert( pCur->info.nSize==0 );
@@ -60566,11 +60815,11 @@
60815 }
60816 }
60817 return rc;
60818 }
60819 SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
60820 assert( cursorOwnsBtShared(pCur) );
60821 assert( pRes!=0 );
60822 assert( *pRes==0 || *pRes==1 );
60823 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
60824 *pRes = 0;
60825 pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
@@ -62279,13 +62528,12 @@
62528 ** This must be done in advance. Once the balance starts, the cell
62529 ** offset section of the btree page will be overwritten and we will no
62530 ** long be able to find the cells if a pointer to each cell is not saved
62531 ** first.
62532 */
62533 memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
62534 if( pOld->nOverflow>0 ){
 
62535 limit = pOld->aiOvfl[0];
62536 for(j=0; j<limit; j++){
62537 b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
62538 piCell += 2;
62539 b.nCell++;
@@ -63046,11 +63294,11 @@
63294 if( pCur->eState==CURSOR_FAULT ){
63295 assert( pCur->skipNext!=SQLITE_OK );
63296 return pCur->skipNext;
63297 }
63298
63299 assert( cursorOwnsBtShared(pCur) );
63300 assert( (pCur->curFlags & BTCF_WriteFlag)!=0
63301 && pBt->inTransaction==TRANS_WRITE
63302 && (pBt->btsFlags & BTS_READ_ONLY)==0 );
63303 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
63304
@@ -63193,11 +63441,11 @@
63441 int iCellIdx; /* Index of cell to delete */
63442 int iCellDepth; /* Depth of node containing pCell */
63443 u16 szCell; /* Size of the cell being deleted */
63444 int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
63445
63446 assert( cursorOwnsBtShared(pCur) );
63447 assert( pBt->inTransaction==TRANS_WRITE );
63448 assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
63449 assert( pCur->curFlags & BTCF_WriteFlag );
63450 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
63451 assert( !hasReadConflicts(p, pCur->pgnoRoot) );
@@ -63633,10 +63881,18 @@
63881 */
63882 if( NEVER(pBt->pCursor) ){
63883 sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
63884 return SQLITE_LOCKED_SHAREDCACHE;
63885 }
63886
63887 /*
63888 ** It is illegal to drop the sqlite_master table on page 1. But again,
63889 ** this error is caught long before reaching this point.
63890 */
63891 if( NEVER(iTable<2) ){
63892 return SQLITE_CORRUPT_BKPT;
63893 }
63894
63895 rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
63896 if( rc ) return rc;
63897 rc = sqlite3BtreeClearTable(p, iTable, 0);
63898 if( rc ){
@@ -63644,80 +63900,71 @@
63900 return rc;
63901 }
63902
63903 *piMoved = 0;
63904
63905 #ifdef SQLITE_OMIT_AUTOVACUUM
63906 freePage(pPage, &rc);
63907 releasePage(pPage);
63908 #else
63909 if( pBt->autoVacuum ){
63910 Pgno maxRootPgno;
63911 sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
63912
63913 if( iTable==maxRootPgno ){
63914 /* If the table being dropped is the table with the largest root-page
63915 ** number in the database, put the root page on the free list.
63916 */
63917 freePage(pPage, &rc);
63918 releasePage(pPage);
63919 if( rc!=SQLITE_OK ){
63920 return rc;
63921 }
63922 }else{
63923 /* The table being dropped does not have the largest root-page
63924 ** number in the database. So move the page that does into the
63925 ** gap left by the deleted root-page.
63926 */
63927 MemPage *pMove;
63928 releasePage(pPage);
63929 rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63930 if( rc!=SQLITE_OK ){
63931 return rc;
63932 }
63933 rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
63934 releasePage(pMove);
63935 if( rc!=SQLITE_OK ){
63936 return rc;
63937 }
63938 pMove = 0;
63939 rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
63940 freePage(pMove, &rc);
63941 releasePage(pMove);
63942 if( rc!=SQLITE_OK ){
63943 return rc;
63944 }
63945 *piMoved = maxRootPgno;
63946 }
63947
63948 /* Set the new 'max-root-page' value in the database header. This
63949 ** is the old value less one, less one more if that happens to
63950 ** be a root-page number, less one again if that is the
63951 ** PENDING_BYTE_PAGE.
63952 */
63953 maxRootPgno--;
63954 while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
63955 || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
63956 maxRootPgno--;
63957 }
63958 assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
63959
63960 rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
63961 }else{
63962 freePage(pPage, &rc);
63963 releasePage(pPage);
63964 }
63965 #endif
 
 
 
 
 
 
 
 
 
63966 return rc;
63967 }
63968 SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
63969 int rc;
63970 sqlite3BtreeEnter(p);
@@ -64655,11 +64902,11 @@
64902 ** parameters that attempt to write past the end of the existing data,
64903 ** no modifications are made and SQLITE_CORRUPT is returned.
64904 */
64905 SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
64906 int rc;
64907 assert( cursorOwnsBtShared(pCsr) );
64908 assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
64909 assert( pCsr->curFlags & BTCF_Incrblob );
64910
64911 rc = restoreCursorPosition(pCsr);
64912 if( rc!=SQLITE_OK ){
@@ -64762,10 +65009,19 @@
65009
65010 /*
65011 ** Return the size of the header added to each page by this module.
65012 */
65013 SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
65014
65015 #if !defined(SQLITE_OMIT_SHARED_CACHE)
65016 /*
65017 ** Return true if the Btree passed as the only argument is sharable.
65018 */
65019 SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
65020 return p->sharable;
65021 }
65022 #endif
65023
65024 /************** End of btree.c ***********************************************/
65025 /************** Begin file backup.c ******************************************/
65026 /*
65027 ** 2009 January 28
@@ -66791,11 +67047,11 @@
67047
67048 assert( pCtx->pParse->rc==SQLITE_OK );
67049 memset(&ctx, 0, sizeof(ctx));
67050 ctx.pOut = pVal;
67051 ctx.pFunc = pFunc;
67052 pFunc->xSFunc(&ctx, nVal, apVal);
67053 if( ctx.isError ){
67054 rc = ctx.isError;
67055 sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
67056 }else{
67057 sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
@@ -67538,12 +67794,11 @@
67794 char c;
67795 va_start(ap, zTypes);
67796 for(i=0; (c = zTypes[i])!=0; i++){
67797 if( c=='s' ){
67798 const char *z = va_arg(ap, const char*);
67799 sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0);
 
67800 }else{
67801 assert( c=='i' );
67802 sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
67803 }
67804 }
@@ -67593,12 +67848,11 @@
67848 ** The zWhere string must have been obtained from sqlite3_malloc().
67849 ** This routine will take ownership of the allocated memory.
67850 */
67851 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
67852 int j;
67853 sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
 
67854 for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
67855 }
67856
67857 /*
67858 ** Add an opcode that includes the p4 value as an integer.
@@ -67895,10 +68149,24 @@
68149 SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
68150 assert( p->magic==VDBE_MAGIC_INIT );
68151 return p->nOp;
68152 }
68153
68154 /*
68155 ** Verify that at least N opcode slots are available in p without
68156 ** having to malloc for more space (except when compiled using
68157 ** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing
68158 ** to verify that certain calls to sqlite3VdbeAddOpList() can never
68159 ** fail due to a OOM fault and hence that the return value from
68160 ** sqlite3VdbeAddOpList() will always be non-NULL.
68161 */
68162 #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
68163 SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){
68164 assert( p->nOp + N <= p->pParse->nOpAlloc );
68165 }
68166 #endif
68167
68168 /*
68169 ** This function returns a pointer to the array of opcodes associated with
68170 ** the Vdbe passed as the first argument. It is the callers responsibility
68171 ** to arrange for the returned array to be eventually freed using the
68172 ** vdbeFreeOpArray() function.
@@ -67920,23 +68188,27 @@
68188 p->aOp = 0;
68189 return aOp;
68190 }
68191
68192 /*
68193 ** Add a whole list of operations to the operation stack. Return a
68194 ** pointer to the first operation inserted.
68195 */
68196 SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
68197 Vdbe *p, /* Add opcodes to the prepared statement */
68198 int nOp, /* Number of opcodes to add */
68199 VdbeOpList const *aOp, /* The opcodes to be added */
68200 int iLineno /* Source-file line number of first opcode */
68201 ){
68202 int i;
68203 VdbeOp *pOut, *pFirst;
68204 assert( nOp>0 );
68205 assert( p->magic==VDBE_MAGIC_INIT );
68206 if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
68207 return 0;
68208 }
68209 pFirst = pOut = &p->aOp[p->nOp];
 
68210 for(i=0; i<nOp; i++, aOp++, pOut++){
68211 pOut->opcode = aOp->opcode;
68212 pOut->p1 = aOp->p1;
68213 pOut->p2 = aOp->p2;
68214 assert( aOp->p2>=0 );
@@ -67952,16 +68224,16 @@
68224 #else
68225 (void)iLineno;
68226 #endif
68227 #ifdef SQLITE_DEBUG
68228 if( p->db->flags & SQLITE_VdbeAddopTrace ){
68229 sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]);
68230 }
68231 #endif
68232 }
68233 p->nOp += nOp;
68234 return pFirst;
68235 }
68236
68237 #if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
68238 /*
68239 ** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
@@ -68005,11 +68277,11 @@
68277 }
68278 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
68279 sqlite3VdbeGetOp(p,addr)->p3 = val;
68280 }
68281 SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
68282 if( !p->db->mallocFailed ) p->aOp[p->nOp-1].p5 = p5;
68283 }
68284
68285 /*
68286 ** Change the P2 operand of instruction addr so that it points to
68287 ** the address of the next instruction to be coded.
@@ -68093,11 +68365,11 @@
68365 */
68366 static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
68367 if( aOp ){
68368 Op *pOp;
68369 for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
68370 if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
68371 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
68372 sqlite3DbFree(db, pOp->zComment);
68373 #endif
68374 }
68375 }
@@ -68115,28 +68387,29 @@
68387 }
68388
68389 /*
68390 ** Change the opcode at addr into OP_Noop
68391 */
68392 SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
68393 VdbeOp *pOp;
68394 if( p->db->mallocFailed ) return 0;
68395 assert( addr>=0 && addr<p->nOp );
68396 pOp = &p->aOp[addr];
68397 freeP4(p->db, pOp->p4type, pOp->p4.p);
68398 pOp->p4type = P4_NOTUSED;
68399 pOp->p4.z = 0;
68400 pOp->opcode = OP_Noop;
68401 return 1;
68402 }
68403
68404 /*
68405 ** If the last opcode is "op" and it is not a jump destination,
68406 ** then remove it. Return true if and only if an opcode was removed.
68407 */
68408 SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
68409 if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
68410 return sqlite3VdbeChangeToNoop(p, p->nOp-1);
 
68411 }else{
68412 return 0;
68413 }
68414 }
68415
@@ -68155,65 +68428,60 @@
68428 ** to a string or structure that is guaranteed to exist for the lifetime of
68429 ** the Vdbe. In these cases we can just copy the pointer.
68430 **
68431 ** If addr<0 then change P4 on the most recently inserted instruction.
68432 */
68433 static void SQLITE_NOINLINE vdbeChangeP4Full(
68434 Vdbe *p,
68435 Op *pOp,
68436 const char *zP4,
68437 int n
68438 ){
68439 if( pOp->p4type ){
68440 freeP4(p->db, pOp->p4type, pOp->p4.p);
68441 pOp->p4type = 0;
68442 pOp->p4.p = 0;
68443 }
68444 if( n<0 ){
68445 sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n);
68446 }else{
68447 if( n==0 ) n = sqlite3Strlen30(zP4);
68448 pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
68449 pOp->p4type = P4_DYNAMIC;
68450 }
68451 }
68452 SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
68453 Op *pOp;
68454 sqlite3 *db;
68455 assert( p!=0 );
68456 db = p->db;
68457 assert( p->magic==VDBE_MAGIC_INIT );
68458 assert( p->aOp!=0 || db->mallocFailed );
68459 if( db->mallocFailed ){
68460 if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
 
68461 return;
68462 }
68463 assert( p->nOp>0 );
68464 assert( addr<p->nOp );
68465 if( addr<0 ){
68466 addr = p->nOp - 1;
68467 }
68468 pOp = &p->aOp[addr];
68469 if( n>=0 || pOp->p4type ){
68470 vdbeChangeP4Full(p, pOp, zP4, n);
68471 return;
68472 }
 
68473 if( n==P4_INT32 ){
68474 /* Note: this cast is safe, because the origin data point was an int
68475 ** that was cast to a (const char *). */
68476 pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
68477 pOp->p4type = P4_INT32;
68478 }else if( zP4!=0 ){
68479 assert( n<0 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68480 pOp->p4.p = (void*)zP4;
68481 pOp->p4type = (signed char)n;
68482 if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4);
 
 
 
68483 }
68484 }
68485
68486 /*
68487 ** Set the P4 on the most recently added opcode to the KeyInfo for the
@@ -68605,11 +68873,11 @@
68873 if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
68874 DbMaskSet(p->lockMask, i);
68875 }
68876 }
68877
68878 #if !defined(SQLITE_OMIT_SHARED_CACHE)
68879 /*
68880 ** If SQLite is compiled to support shared-cache mode and to be threadsafe,
68881 ** this routine obtains the mutex associated with each BtShared structure
68882 ** that may be accessed by the VM passed as an argument. In doing so it also
68883 ** sets the BtShared.db member of each of the BtShared structures, ensuring
@@ -69174,11 +69442,10 @@
69442 do {
69443 nByte = 0;
69444 p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte);
69445 p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte);
69446 p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte);
 
69447 p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
69448 zCsr, &nFree, &nByte);
69449 p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte);
69450 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
69451 p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte);
@@ -69197,15 +69464,14 @@
69464 for(n=0; n<nVar; n++){
69465 p->aVar[n].flags = MEM_Null;
69466 p->aVar[n].db = db;
69467 }
69468 }
69469 p->nzVar = pParse->nzVar;
69470 p->azVar = pParse->azVar;
69471 pParse->nzVar = 0;
69472 pParse->azVar = 0;
 
69473 if( p->aMem ){
69474 p->aMem--; /* aMem[] goes from 1..nMem */
69475 p->nMem = nMem; /* not from 0..nMem-1 */
69476 for(n=1; n<=nMem; n++){
69477 p->aMem[n].flags = MEM_Undefined;
@@ -70188,10 +70454,11 @@
70454 pNext = pSub->pNext;
70455 vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
70456 sqlite3DbFree(db, pSub);
70457 }
70458 for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
70459 sqlite3DbFree(db, p->azVar);
70460 vdbeFreeOpArray(db, p->aOp, p->nOp);
70461 sqlite3DbFree(db, p->aColName);
70462 sqlite3DbFree(db, p->zSql);
70463 sqlite3DbFree(db, p->pFree);
70464 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -70932,13 +71199,13 @@
71199 v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
71200 n1 = v1==0 ? 0 : c1.n;
71201 v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
71202 n2 = v2==0 ? 0 : c2.n;
71203 rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
71204 if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
71205 sqlite3VdbeMemRelease(&c1);
71206 sqlite3VdbeMemRelease(&c2);
 
71207 return rc;
71208 }
71209 }
71210
71211 /*
@@ -71722,15 +71989,17 @@
71989 ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
71990 ** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
71991 ** in memory obtained from sqlite3DbMalloc).
71992 */
71993 SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
71994 if( pVtab->zErrMsg ){
71995 sqlite3 *db = p->db;
71996 sqlite3DbFree(db, p->zErrMsg);
71997 p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
71998 sqlite3_free(pVtab->zErrMsg);
71999 pVtab->zErrMsg = 0;
72000 }
72001 }
72002 #endif /* SQLITE_OMIT_VIRTUALTABLE */
72003
72004 /************** End of vdbeaux.c *********************************************/
72005 /************** Begin file vdbeapi.c *****************************************/
@@ -72513,11 +72782,11 @@
72782 ** Allocate or return the aggregate context for a user function. A new
72783 ** context is allocated on the first call. Subsequent calls return the
72784 ** same context that was returned on prior calls.
72785 */
72786 SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
72787 assert( p && p->pFunc && p->pFunc->xFinalize );
72788 assert( sqlite3_mutex_held(p->pOut->db->mutex) );
72789 testcase( nByte<0 );
72790 if( (p->pMem->flags & MEM_Agg)==0 ){
72791 return createAggContext(p, nByte);
72792 }else{
@@ -72604,11 +72873,11 @@
72873 ** provide only to avoid breaking legacy code. New aggregate function
72874 ** implementations should keep their own counts within their aggregate
72875 ** context.
72876 */
72877 SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
72878 assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize );
72879 return p->pMem->n;
72880 }
72881 #endif
72882
72883 /*
@@ -75347,12 +75616,12 @@
75616 }
75617 #endif
75618 MemSetTypeFlag(pCtx->pOut, MEM_Null);
75619 pCtx->fErrorOrAux = 0;
75620 db->lastRowid = lastRowid;
75621 (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
75622 lastRowid = db->lastRowid; /* Remember rowid changes made by xSFunc */
75623
75624 /* If the function returned an error, throw an exception */
75625 if( pCtx->fErrorOrAux ){
75626 if( pCtx->isError ){
75627 sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
@@ -76059,11 +76328,10 @@
76328 const u8 *zEndHdr; /* Pointer to first byte after the header */
76329 u32 offset; /* Offset into the data */
76330 u64 offset64; /* 64-bit offset */
76331 u32 avail; /* Number of bytes of available data */
76332 u32 t; /* A type code from the record header */
 
76333 Mem *pReg; /* PseudoTable input register */
76334
76335 p2 = pOp->p2;
76336 assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
76337 pDest = &aMem[pOp->p3];
@@ -76237,14 +76505,35 @@
76505 assert( p2<pC->nHdrParsed );
76506 assert( rc==SQLITE_OK );
76507 assert( sqlite3VdbeCheckMemInvariants(pDest) );
76508 if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
76509 assert( t==pC->aType[p2] );
76510 pDest->enc = encoding;
76511 if( pC->szRow>=aOffset[p2+1] ){
76512 /* This is the common case where the desired content fits on the original
76513 ** page - where the content is not on an overflow page */
76514 zData = pC->aRow + aOffset[p2];
76515 if( t<12 ){
76516 sqlite3VdbeSerialGet(zData, t, pDest);
76517 }else{
76518 /* If the column value is a string, we need a persistent value, not
76519 ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent
76520 ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize().
76521 */
76522 static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term };
76523 pDest->n = len = (t-12)/2;
76524 if( pDest->szMalloc < len+2 ){
76525 pDest->flags = MEM_Null;
76526 if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
76527 }else{
76528 pDest->z = pDest->zMalloc;
76529 }
76530 memcpy(pDest->z, zData, len);
76531 pDest->z[len] = 0;
76532 pDest->z[len+1] = 0;
76533 pDest->flags = aFlag[t&1];
76534 }
76535 }else{
76536 /* This branch happens only when content is on overflow pages */
76537 if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
76538 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
76539 || (len = sqlite3VdbeSerialTypeLen(t))==0
@@ -76252,42 +76541,24 @@
76541 /* Content is irrelevant for
76542 ** 1. the typeof() function,
76543 ** 2. the length(X) function if X is a blob, and
76544 ** 3. if the content length is zero.
76545 ** So we might as well use bogus content rather than reading
76546 ** content from disk. */
76547 static u8 aZero[8]; /* This is the bogus content */
76548 sqlite3VdbeSerialGet(aZero, t, pDest);
 
76549 }else{
76550 rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
76551 pDest);
76552 if( rc==SQLITE_OK ){
76553 sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
76554 pDest->flags &= ~MEM_Ephem;
76555 }
76556 }
76557 }
76558
76559 op_column_out:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76560 op_column_error:
76561 UPDATE_MAX_BLOBSIZE(pDest);
76562 REGISTER_TRACE(pOp->p3, pDest);
76563 break;
76564 }
@@ -78782,10 +79053,11 @@
79053 case OP_Destroy: { /* out2 */
79054 int iMoved;
79055 int iDb;
79056
79057 assert( p->readOnly==0 );
79058 assert( pOp->p1>1 );
79059 pOut = out2Prerelease(p, pOp);
79060 pOut->flags = MEM_Null;
79061 if( db->nVdbeRead > db->nVDestroy+1 ){
79062 rc = SQLITE_LOCKED;
79063 p->errorAction = OE_Abort;
@@ -79586,11 +79858,11 @@
79858 pMem->n++;
79859 sqlite3VdbeMemInit(&t, db, MEM_Null);
79860 pCtx->pOut = &t;
79861 pCtx->fErrorOrAux = 0;
79862 pCtx->skipFlag = 0;
79863 (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
79864 if( pCtx->fErrorOrAux ){
79865 if( pCtx->isError ){
79866 sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
79867 rc = pCtx->isError;
79868 }
@@ -80584,42 +80856,10 @@
80856 int flags, /* True -> read/write access, false -> read-only */
80857 sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
80858 ){
80859 int nAttempt = 0;
80860 int iCol; /* Index of zColumn in row-record */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80861 int rc = SQLITE_OK;
80862 char *zErr = 0;
80863 Table *pTab;
80864 Parse *pParse = 0;
80865 Incrblob *pBlob = 0;
@@ -80734,49 +80974,84 @@
80974 }
80975
80976 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
80977 assert( pBlob->pStmt || db->mallocFailed );
80978 if( pBlob->pStmt ){
80979
80980 /* This VDBE program seeks a btree cursor to the identified
80981 ** db/table/row entry. The reason for using a vdbe program instead
80982 ** of writing code to use the b-tree layer directly is that the
80983 ** vdbe program will take advantage of the various transaction,
80984 ** locking and error handling infrastructure built into the vdbe.
80985 **
80986 ** After seeking the cursor, the vdbe executes an OP_ResultRow.
80987 ** Code external to the Vdbe then "borrows" the b-tree cursor and
80988 ** uses it to implement the blob_read(), blob_write() and
80989 ** blob_bytes() functions.
80990 **
80991 ** The sqlite3_blob_close() function finalizes the vdbe program,
80992 ** which closes the b-tree cursor and (possibly) commits the
80993 ** transaction.
80994 */
80995 static const int iLn = VDBE_OFFSET_LINENO(4);
80996 static const VdbeOpList openBlob[] = {
80997 /* addr/ofst */
80998 /* {OP_Transaction, 0, 0, 0}, // 0/ inserted separately */
80999 {OP_TableLock, 0, 0, 0}, /* 1/0: Acquire a read or write lock */
81000 {OP_OpenRead, 0, 0, 0}, /* 2/1: Open a cursor */
81001 {OP_Variable, 1, 1, 0}, /* 3/2: Move ?1 into reg[1] */
81002 {OP_NotExists, 0, 8, 1}, /* 4/3: Seek the cursor */
81003 {OP_Column, 0, 0, 1}, /* 5/4 */
81004 {OP_ResultRow, 1, 0, 0}, /* 6/5 */
81005 {OP_Goto, 0, 3, 0}, /* 7/6 */
81006 {OP_Close, 0, 0, 0}, /* 8/7 */
81007 {OP_Halt, 0, 0, 0}, /* 9/8 */
81008 };
81009 Vdbe *v = (Vdbe *)pBlob->pStmt;
81010 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
81011 VdbeOp *aOp;
81012
81013 sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
81014 pTab->pSchema->schema_cookie,
81015 pTab->pSchema->iGeneration);
81016 sqlite3VdbeChangeP5(v, 1);
81017 aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
81018
81019 /* Make sure a mutex is held on the table to be accessed */
81020 sqlite3VdbeUsesBtree(v, iDb);
81021
81022 if( db->mallocFailed==0 ){
81023 assert( aOp!=0 );
81024 /* Configure the OP_TableLock instruction */
81025 #ifdef SQLITE_OMIT_SHARED_CACHE
81026 aOp[0].opcode = OP_Noop;
81027 #else
81028 aOp[0].p1 = iDb;
81029 aOp[0].p2 = pTab->tnum;
81030 aOp[0].p3 = flags;
81031 sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
81032 }
81033 if( db->mallocFailed==0 ){
81034 #endif
81035
81036 /* Remove either the OP_OpenWrite or OpenRead. Set the P2
81037 ** parameter of the other to pTab->tnum. */
81038 if( flags ) aOp[1].opcode = OP_OpenWrite;
81039 aOp[1].p2 = pTab->tnum;
81040 aOp[1].p3 = iDb;
81041
81042 /* Configure the number of columns. Configure the cursor to
81043 ** think that the table has one more column than it really
81044 ** does. An OP_Column to retrieve this imaginary column will
81045 ** always return an SQL NULL. This is useful because it means
81046 ** we can invoke OP_Column to fill in the vdbe cursors type
81047 ** and offset cache without causing any IO.
81048 */
81049 aOp[1].p4type = P4_INT32;
81050 aOp[1].p4.i = pTab->nCol+1;
81051 aOp[4].p2 = pTab->nCol;
81052
81053 pParse->nVar = 1;
81054 pParse->nMem = 1;
81055 pParse->nTab = 1;
81056 sqlite3VdbeMakeReady(v, pParse);
81057 }
@@ -81685,11 +81960,11 @@
81960 assert( pReadr->aBuffer==0 );
81961 assert( pReadr->aMap==0 );
81962
81963 rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
81964 if( rc==SQLITE_OK ){
81965 u64 nByte = 0; /* Size of PMA in bytes */
81966 rc = vdbePmaReadVarint(pReadr, &nByte);
81967 pReadr->iEof = pReadr->iReadOff + nByte;
81968 *pnByte += nByte;
81969 }
81970
@@ -84243,13 +84518,12 @@
84518 ** return the top-level walk call.
84519 **
84520 ** The return value from this routine is WRC_Abort to abandon the tree walk
84521 ** and WRC_Continue to continue.
84522 */
84523 static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
84524 int rc;
 
84525 testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
84526 testcase( ExprHasProperty(pExpr, EP_Reduced) );
84527 rc = pWalker->xExprCallback(pWalker, pExpr);
84528 if( rc==WRC_Continue
84529 && !ExprHasProperty(pExpr,EP_TokenOnly) ){
@@ -84260,10 +84534,13 @@
84534 }else{
84535 if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
84536 }
84537 }
84538 return rc & WRC_Abort;
84539 }
84540 SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
84541 return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
84542 }
84543
84544 /*
84545 ** Call sqlite3WalkExpr() for every expression in list p or until
84546 ** an abort request is seen.
@@ -85034,11 +85311,11 @@
85311 no_such_func = 1;
85312 }else{
85313 wrong_num_args = 1;
85314 }
85315 }else{
85316 is_agg = pDef->xFinalize!=0;
85317 if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
85318 ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
85319 if( n==2 ){
85320 pExpr->iTable = exprProbability(pList->a[1].pExpr);
85321 if( pExpr->iTable<0 ){
@@ -85762,14 +86039,16 @@
86039 pParse->nHeight += pExpr->nHeight;
86040 }
86041 #endif
86042 savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
86043 pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
86044 w.pParse = pNC->pParse;
86045 w.xExprCallback = resolveExprStep;
86046 w.xSelectCallback = resolveSelectStep;
86047 w.xSelectCallback2 = 0;
86048 w.walkerDepth = 0;
86049 w.eCode = 0;
86050 w.u.pNC = pNC;
86051 sqlite3WalkExpr(&w, pExpr);
86052 #if SQLITE_MAX_EXPR_DEPTH>0
86053 pNC->pParse->nHeight -= pExpr->nHeight;
86054 #endif
@@ -86327,12 +86606,13 @@
86606 || sqlite3GetInt32(pToken->z, &iValue)==0 ){
86607 nExtra = pToken->n+1;
86608 assert( iValue>=0 );
86609 }
86610 }
86611 pNew = sqlite3DbMallocRaw(db, sizeof(Expr)+nExtra);
86612 if( pNew ){
86613 memset(pNew, 0, sizeof(Expr));
86614 pNew->op = (u8)op;
86615 pNew->iAgg = -1;
86616 if( pToken ){
86617 if( nExtra==0 ){
86618 pNew->flags |= EP_IntValue;
@@ -87000,14 +87280,15 @@
87280 ExprList *pList, /* List to which to append. Might be NULL */
87281 Expr *pExpr /* Expression to be appended. Might be NULL */
87282 ){
87283 sqlite3 *db = pParse->db;
87284 if( pList==0 ){
87285 pList = sqlite3DbMallocRaw(db, sizeof(ExprList) );
87286 if( pList==0 ){
87287 goto no_mem;
87288 }
87289 pList->nExpr = 0;
87290 pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
87291 if( pList->a==0 ) goto no_mem;
87292 }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
87293 struct ExprList_item *a;
87294 assert( pList->nExpr>0 );
@@ -88761,11 +89042,11 @@
89042 nFarg = pFarg ? pFarg->nExpr : 0;
89043 assert( !ExprHasProperty(pExpr, EP_IntValue) );
89044 zId = pExpr->u.zToken;
89045 nId = sqlite3Strlen30(zId);
89046 pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
89047 if( pDef==0 || pDef->xFinalize!=0 ){
89048 sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
89049 break;
89050 }
89051
89052 /* Attempt a direct implementation of the built-in COALESCE() and
@@ -91433,12 +91714,11 @@
91714 static const FuncDef statInitFuncdef = {
91715 2+IsStat34, /* nArg */
91716 SQLITE_UTF8, /* funcFlags */
91717 0, /* pUserData */
91718 0, /* pNext */
91719 statInit, /* xSFunc */
 
91720 0, /* xFinalize */
91721 "stat_init", /* zName */
91722 0, /* pHash */
91723 0 /* pDestructor */
91724 };
@@ -91734,12 +92014,11 @@
92014 static const FuncDef statPushFuncdef = {
92015 2+IsStat34, /* nArg */
92016 SQLITE_UTF8, /* funcFlags */
92017 0, /* pUserData */
92018 0, /* pNext */
92019 statPush, /* xSFunc */
 
92020 0, /* xFinalize */
92021 "stat_push", /* zName */
92022 0, /* pHash */
92023 0 /* pDestructor */
92024 };
@@ -91881,12 +92160,11 @@
92160 static const FuncDef statGetFuncdef = {
92161 1+IsStat34, /* nArg */
92162 SQLITE_UTF8, /* funcFlags */
92163 0, /* pUserData */
92164 0, /* pNext */
92165 statGet, /* xSFunc */
 
92166 0, /* xFinalize */
92167 "stat_get", /* zName */
92168 0, /* pHash */
92169 0 /* pDestructor */
92170 };
@@ -91898,12 +92176,12 @@
92176 #elif SQLITE_DEBUG
92177 assert( iParam==STAT_GET_STAT1 );
92178 #else
92179 UNUSED_PARAMETER( iParam );
92180 #endif
92181 sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
92182 (char*)&statGetFuncdef, P4_FUNCDEF);
92183 sqlite3VdbeChangeP5(v, 1 + IsStat34);
92184 }
92185
92186 /*
92187 ** Generate code to do an analysis of all indices associated with
@@ -92053,12 +92331,12 @@
92331 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
92332 sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
92333 #endif
92334 sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
92335 sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
92336 sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
92337 (char*)&statInitFuncdef, P4_FUNCDEF);
92338 sqlite3VdbeChangeP5(v, 2+IsStat34);
92339
92340 /* Implementation of the following:
92341 **
92342 ** Rewind csr
@@ -92150,12 +92428,12 @@
92428 sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
92429 sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
92430 }
92431 #endif
92432 assert( regChng==(regStat4+1) );
92433 sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
92434 (char*)&statPushFuncdef, P4_FUNCDEF);
92435 sqlite3VdbeChangeP5(v, 2+IsStat34);
92436 sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
92437
92438 /* Add the entry to the stat1 table. */
92439 callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
@@ -93208,15 +93486,15 @@
93486 sqlite3ExprCode(pParse, pDbname, regArgs+1);
93487 sqlite3ExprCode(pParse, pKey, regArgs+2);
93488
93489 assert( v || db->mallocFailed );
93490 if( v ){
93491 sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
93492 (char *)pFunc, P4_FUNCDEF);
93493 assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
93494 sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
93495
 
93496 /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
93497 ** statement only). For DETACH, set it to false (expire all existing
93498 ** statements).
93499 */
93500 sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
@@ -93237,12 +93515,11 @@
93515 static const FuncDef detach_func = {
93516 1, /* nArg */
93517 SQLITE_UTF8, /* funcFlags */
93518 0, /* pUserData */
93519 0, /* pNext */
93520 detachFunc, /* xSFunc */
 
93521 0, /* xFinalize */
93522 "sqlite_detach", /* zName */
93523 0, /* pHash */
93524 0 /* pDestructor */
93525 };
@@ -93258,12 +93535,11 @@
93535 static const FuncDef attach_func = {
93536 3, /* nArg */
93537 SQLITE_UTF8, /* funcFlags */
93538 0, /* pUserData */
93539 0, /* pNext */
93540 attachFunc, /* xSFunc */
 
93541 0, /* xFinalize */
93542 "sqlite_attach", /* zName */
93543 0, /* pHash */
93544 0 /* pDestructor */
93545 };
@@ -93723,19 +93999,10 @@
93999 ** COMMIT
94000 ** ROLLBACK
94001 */
94002 /* #include "sqliteInt.h" */
94003
 
 
 
 
 
 
 
 
 
94004 #ifndef SQLITE_OMIT_SHARED_CACHE
94005 /*
94006 ** The TableLock structure is only used by the sqlite3TableLock() and
94007 ** codeTableLocks() functions.
94008 */
@@ -93936,19 +94203,23 @@
94203 /* A minimum of one cursor is required if autoincrement is used
94204 * See ticket [a696379c1f08866] */
94205 if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
94206 sqlite3VdbeMakeReady(v, pParse);
94207 pParse->rc = SQLITE_DONE;
 
94208 }else{
94209 pParse->rc = SQLITE_ERROR;
94210 }
94211
94212 /* We are done with this Parse object. There is no need to de-initialize it */
94213 #if 0
94214 pParse->colNamesSet = 0;
94215 pParse->nTab = 0;
94216 pParse->nMem = 0;
94217 pParse->nSet = 0;
94218 pParse->nVar = 0;
94219 DbMaskZero(pParse->cookieMask);
94220 #endif
94221 }
94222
94223 /*
94224 ** Run the parser and code generator recursively in order to generate
94225 ** code for the SQL statement given onto the end of the pParse context
@@ -94203,11 +94474,10 @@
94474 if( j<i ){
94475 db->aDb[j] = db->aDb[i];
94476 }
94477 j++;
94478 }
 
94479 db->nDb = j;
94480 if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
94481 memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
94482 sqlite3DbFree(db, db->aDb);
94483 db->aDb = db->aDbStatic;
@@ -94466,11 +94736,12 @@
94736 Token **pUnqual /* Write the unqualified object name here */
94737 ){
94738 int iDb; /* Database holding the object */
94739 sqlite3 *db = pParse->db;
94740
94741 assert( pName2!=0 );
94742 if( pName2->n>0 ){
94743 if( db->init.busy ) {
94744 sqlite3ErrorMsg(pParse, "corrupt database");
94745 return -1;
94746 }
94747 *pUnqual = pName2;
@@ -94555,66 +94826,50 @@
94826 sqlite3 *db = pParse->db;
94827 Vdbe *v;
94828 int iDb; /* Database number to create the table in */
94829 Token *pName; /* Unqualified name of the table to create */
94830
94831 if( db->init.busy && db->init.newTnum==1 ){
94832 /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
94833 iDb = db->init.iDb;
94834 zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
94835 pName = pName1;
94836 }else{
94837 /* The common case */
94838 iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
94839 if( iDb<0 ) return;
94840 if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
94841 /* If creating a temp table, the name may not be qualified. Unless
94842 ** the database name is "temp" anyway. */
94843 sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
94844 return;
94845 }
94846 if( !OMIT_TEMPDB && isTemp ) iDb = 1;
94847 zName = sqlite3NameFromToken(db, pName);
94848 }
94849 pParse->sNameToken = *pName;
 
 
 
 
 
 
 
 
 
 
94850 if( zName==0 ) return;
94851 if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
94852 goto begin_table_error;
94853 }
94854 if( db->init.iDb==1 ) isTemp = 1;
94855 #ifndef SQLITE_OMIT_AUTHORIZATION
94856 assert( isTemp==0 || isTemp==1 );
94857 assert( isView==0 || isView==1 );
94858 {
94859 static const u8 aCode[] = {
94860 SQLITE_CREATE_TABLE,
94861 SQLITE_CREATE_TEMP_TABLE,
94862 SQLITE_CREATE_VIEW,
94863 SQLITE_CREATE_TEMP_VIEW
94864 };
94865 char *zDb = db->aDb[iDb].zName;
94866 if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
94867 goto begin_table_error;
94868 }
94869 if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView],
94870 zName, 0, zDb) ){
 
 
 
 
 
 
 
 
 
 
 
 
94871 goto begin_table_error;
94872 }
94873 }
94874 #endif
94875
@@ -95572,13 +95827,17 @@
95827 /* If the db->init.busy is 1 it means we are reading the SQL off the
95828 ** "sqlite_master" or "sqlite_temp_master" table on the disk.
95829 ** So do not write to the disk again. Extract the root page number
95830 ** for the table from the db->init.newTnum field. (The page number
95831 ** should have been put there by the sqliteOpenCb routine.)
95832 **
95833 ** If the root page number is 1, that means this is the sqlite_master
95834 ** table itself. So mark it read-only.
95835 */
95836 if( db->init.busy ){
95837 p->tnum = db->init.newTnum;
95838 if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
95839 }
95840
95841 /* Special processing for WITHOUT ROWID Tables */
95842 if( tabOpts & TF_WithoutRowid ){
95843 if( (p->tabFlags & TF_Autoincrement) ){
@@ -96027,10 +96286,11 @@
96286 ** erasing iTable (this can happen with an auto-vacuum database).
96287 */
96288 static void destroyRootPage(Parse *pParse, int iTable, int iDb){
96289 Vdbe *v = sqlite3GetVdbe(pParse);
96290 int r1 = sqlite3GetTempReg(pParse);
96291 assert( iTable>1 );
96292 sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
96293 sqlite3MayAbort(pParse);
96294 #ifndef SQLITE_OMIT_AUTOVACUUM
96295 /* OP_Destroy stores an in integer r1. If this integer
96296 ** is non-zero, then it is the root page number of a table moved to
@@ -97425,13 +97685,14 @@
97685 Token *pDatabase /* Database of the table */
97686 ){
97687 struct SrcList_item *pItem;
97688 assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
97689 if( pList==0 ){
97690 pList = sqlite3DbMallocRaw(db, sizeof(SrcList) );
97691 if( pList==0 ) return 0;
97692 pList->nAlloc = 1;
97693 pList->nSrc = 0;
97694 }
97695 pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
97696 if( db->mallocFailed ){
97697 sqlite3SrcListDelete(db, pList);
97698 return 0;
@@ -97830,11 +98091,11 @@
98091 assert( (errCode&0xff)==SQLITE_CONSTRAINT );
98092 if( onError==OE_Abort ){
98093 sqlite3MayAbort(pParse);
98094 }
98095 sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
98096 sqlite3VdbeChangeP5(v, p5Errmsg);
98097 }
98098
98099 /*
98100 ** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation.
98101 */
@@ -98371,12 +98632,12 @@
98632 ** 3: encoding matches and function takes any number of arguments
98633 ** 4: UTF8/16 conversion required - argument count matches exactly
98634 ** 5: UTF16 byte order conversion required - argument count matches exactly
98635 ** 6: Perfect match: encoding and argument count match exactly.
98636 **
98637 ** If nArg==(-2) then any function with a non-null xSFunc is
98638 ** a perfect match and any function with xSFunc NULL is
98639 ** a non-match.
98640 */
98641 #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
98642 static int matchQuality(
98643 FuncDef *p, /* The function we are evaluating for match quality */
@@ -98384,11 +98645,11 @@
98645 u8 enc /* Desired text encoding */
98646 ){
98647 int match;
98648
98649 /* nArg of -2 is a special case */
98650 if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
98651
98652 /* Wrong number of arguments means "no match" */
98653 if( p->nArg!=nArg && p->nArg>=0 ) return 0;
98654
98655 /* Give a better score to a function with a specific number of arguments
@@ -98462,11 +98723,11 @@
98723 ** If the createFlag argument is true, then a new (blank) FuncDef
98724 ** structure is created and liked into the "db" structure if a
98725 ** no matching function previously existed.
98726 **
98727 ** If nArg is -2, then the first valid function found is returned. A
98728 ** function is valid if xSFunc is non-zero. The nArg==(-2)
98729 ** case is used to see if zName is a valid function name for some number
98730 ** of arguments. If nArg is -2, then createFlag must be 0.
98731 **
98732 ** If createFlag is false, then a function with the required name and
98733 ** number of arguments may be returned even if the eTextRep flag does not
@@ -98539,11 +98800,11 @@
98800 memcpy(pBest->zName, zName, nName);
98801 pBest->zName[nName] = 0;
98802 sqlite3FuncDefInsert(&db->aFunc, pBest);
98803 }
98804
98805 if( pBest && (pBest->xSFunc || createFlag) ){
98806 return pBest;
98807 }
98808 return 0;
98809 }
98810
@@ -100072,14 +100333,14 @@
100333
100334 /*
100335 ** A structure defining how to do GLOB-style comparisons.
100336 */
100337 struct compareInfo {
100338 u8 matchAll; /* "*" or "%" */
100339 u8 matchOne; /* "?" or "_" */
100340 u8 matchSet; /* "[" or 0 */
100341 u8 noCase; /* true to ignore case differences */
100342 };
100343
100344 /*
100345 ** For LIKE and GLOB matching on EBCDIC machines, assume that every
100346 ** character is exactly one byte in size. Also, provde the Utf8Read()
@@ -100138,26 +100399,18 @@
100399 */
100400 static int patternCompare(
100401 const u8 *zPattern, /* The glob pattern */
100402 const u8 *zString, /* The string to compare against the glob */
100403 const struct compareInfo *pInfo, /* Information about how to do the compare */
100404 u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */
100405 ){
100406 u32 c, c2; /* Next pattern and input string chars */
100407 u32 matchOne = pInfo->matchOne; /* "?" or "_" */
100408 u32 matchAll = pInfo->matchAll; /* "*" or "%" */
 
100409 u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
100410 const u8 *zEscaped = 0; /* One past the last escaped input char */
100411
 
 
 
 
 
 
 
100412 while( (c = Utf8Read(zPattern))!=0 ){
100413 if( c==matchAll ){ /* Match "*" */
100414 /* Skip over multiple "*" characters in the pattern. If there
100415 ** are also "?" characters, skip those as well, but consume a
100416 ** single character of the input string for each "?" skipped */
@@ -100167,19 +100420,19 @@
100420 }
100421 }
100422 if( c==0 ){
100423 return 1; /* "*" at the end of the pattern matches */
100424 }else if( c==matchOther ){
100425 if( pInfo->matchSet==0 ){
100426 c = sqlite3Utf8Read(&zPattern);
100427 if( c==0 ) return 0;
100428 }else{
100429 /* "[...]" immediately follows the "*". We have to do a slow
100430 ** recursive search in this case, but it is an unusual case. */
100431 assert( matchOther<0x80 ); /* '[' is a single-byte character */
100432 while( *zString
100433 && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){
100434 SQLITE_SKIP_UTF8(zString);
100435 }
100436 return *zString!=0;
100437 }
100438 }
@@ -100201,22 +100454,22 @@
100454 }else{
100455 cx = c;
100456 }
100457 while( (c2 = *(zString++))!=0 ){
100458 if( c2!=c && c2!=cx ) continue;
100459 if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
100460 }
100461 }else{
100462 while( (c2 = Utf8Read(zString))!=0 ){
100463 if( c2!=c ) continue;
100464 if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
100465 }
100466 }
100467 return 0;
100468 }
100469 if( c==matchOther ){
100470 if( pInfo->matchSet==0 ){
100471 c = sqlite3Utf8Read(&zPattern);
100472 if( c==0 ) return 0;
100473 zEscaped = zPattern;
100474 }else{
100475 u32 prior_c = 0;
@@ -100252,11 +100505,11 @@
100505 continue;
100506 }
100507 }
100508 c2 = Utf8Read(zString);
100509 if( c==c2 ) continue;
100510 if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
100511 continue;
100512 }
100513 if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
100514 return 0;
100515 }
@@ -100265,11 +100518,11 @@
100518
100519 /*
100520 ** The sqlite3_strglob() interface.
100521 */
100522 SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
100523 return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0;
100524 }
100525
100526 /*
100527 ** The sqlite3_strlike() interface.
100528 */
@@ -100303,13 +100556,14 @@
100556 sqlite3_context *context,
100557 int argc,
100558 sqlite3_value **argv
100559 ){
100560 const unsigned char *zA, *zB;
100561 u32 escape;
100562 int nPat;
100563 sqlite3 *db = sqlite3_context_db_handle(context);
100564 struct compareInfo *pInfo = sqlite3_user_data(context);
100565
100566 #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
100567 if( sqlite3_value_type(argv[0])==SQLITE_BLOB
100568 || sqlite3_value_type(argv[1])==SQLITE_BLOB
100569 ){
@@ -100345,17 +100599,17 @@
100599 sqlite3_result_error(context,
100600 "ESCAPE expression must be a single character", -1);
100601 return;
100602 }
100603 escape = sqlite3Utf8Read(&zEsc);
100604 }else{
100605 escape = pInfo->matchSet;
100606 }
100607 if( zA && zB ){
 
100608 #ifdef SQLITE_TEST
100609 sqlite3_like_count++;
100610 #endif
 
100611 sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
100612 }
100613 }
100614
100615 /*
@@ -104328,11 +104582,11 @@
104582 if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
104583 if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
104584 assert( pParse->nested==0 );
104585 pik_flags |= OPFLAG_NCHANGE;
104586 }
104587 sqlite3VdbeChangeP5(v, pik_flags);
104588 }
104589 if( !HasRowid(pTab) ) return;
104590 regData = regNewData + 1;
104591 regRec = sqlite3GetTempReg(pParse);
104592 sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
@@ -104744,13 +104998,13 @@
104998 }else{
104999 addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
105000 assert( (pDest->tabFlags & TF_Autoincrement)==0 );
105001 }
105002 sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
105003 sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
105004 pDest->zName, 0);
105005 sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
 
105006 sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
105007 sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
105008 sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
105009 }else{
105010 sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName);
@@ -107199,19 +107453,21 @@
107453 { OP_IfPos, 1, 8, 0},
107454 { OP_Integer, 0, 1, 0}, /* 6 */
107455 { OP_Noop, 0, 0, 0},
107456 { OP_ResultRow, 1, 1, 0},
107457 };
107458 VdbeOp *aOp;
107459 sqlite3VdbeUsesBtree(v, iDb);
107460 if( !zRight ){
107461 setOneColumnName(v, "cache_size");
107462 pParse->nMem += 2;
107463 sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
107464 aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
107465 if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
107466 aOp[0].p1 = iDb;
107467 aOp[1].p1 = iDb;
107468 aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE;
107469 }else{
107470 int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
107471 sqlite3BeginWriteOperation(pParse, 0, iDb);
107472 sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
107473 sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
@@ -107453,17 +107709,20 @@
107709 { OP_If, 1, 0, 0}, /* 2 */
107710 { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
107711 { OP_Integer, 0, 1, 0}, /* 4 */
107712 { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
107713 };
107714 VdbeOp *aOp;
107715 int iAddr = sqlite3VdbeCurrentAddr(v);
107716 sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6));
107717 aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
107718 if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
107719 aOp[0].p1 = iDb;
107720 aOp[1].p1 = iDb;
107721 aOp[2].p2 = iAddr+4;
107722 aOp[4].p1 = eAuto - 1;
107723 aOp[5].p1 = iDb;
107724 sqlite3VdbeUsesBtree(v, iDb);
107725 }
107726 }
107727 break;
107728 }
@@ -108165,22 +108424,10 @@
108424 ** without most of the overhead of a full integrity-check.
108425 */
108426 case PragTyp_INTEGRITY_CHECK: {
108427 int i, j, addr, mxErr;
108428
 
 
 
 
 
 
 
 
 
 
 
 
108429 int isQuick = (sqlite3Tolower(zLeft[0])=='q');
108430
108431 /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
108432 ** then iDb is set to the index of the database identified by <db>.
108433 ** In this case, the integrity of database iDb only is verified by
@@ -108373,14 +108620,28 @@
108620 sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
108621 }
108622 #endif /* SQLITE_OMIT_BTREECOUNT */
108623 }
108624 }
108625 {
108626 static const int iLn = VDBE_OFFSET_LINENO(2);
108627 static const VdbeOpList endCode[] = {
108628 { OP_AddImm, 1, 0, 0}, /* 0 */
108629 { OP_If, 1, 0, 0}, /* 1 */
108630 { OP_String8, 0, 3, 0}, /* 2 */
108631 { OP_ResultRow, 3, 1, 0},
108632 };
108633 VdbeOp *aOp;
108634
108635 aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
108636 if( aOp ){
108637 aOp[0].p2 = -mxErr;
108638 aOp[1].p2 = sqlite3VdbeCurrentAddr(v);
108639 aOp[2].p4type = P4_STATIC;
108640 aOp[2].p4.z = "ok";
108641 }
108642 }
108643 }
108644 break;
108645 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
108646
108647 #ifndef SQLITE_OMIT_UTF16
@@ -108493,26 +108754,32 @@
108754 static const VdbeOpList setCookie[] = {
108755 { OP_Transaction, 0, 1, 0}, /* 0 */
108756 { OP_Integer, 0, 1, 0}, /* 1 */
108757 { OP_SetCookie, 0, 0, 1}, /* 2 */
108758 };
108759 VdbeOp *aOp;
108760 sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));
108761 aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
108762 if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
108763 aOp[0].p1 = iDb;
108764 aOp[1].p1 = sqlite3Atoi(zRight);
108765 aOp[2].p1 = iDb;
108766 aOp[2].p2 = iCookie;
108767 }else{
108768 /* Read the specified cookie value */
108769 static const VdbeOpList readCookie[] = {
108770 { OP_Transaction, 0, 0, 0}, /* 0 */
108771 { OP_ReadCookie, 0, 1, 0}, /* 1 */
108772 { OP_ResultRow, 1, 1, 0}
108773 };
108774 VdbeOp *aOp;
108775 sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie));
108776 aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0);
108777 if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
108778 aOp[0].p1 = iDb;
108779 aOp[1].p1 = iDb;
108780 aOp[1].p3 = iCookie;
108781 sqlite3VdbeSetNumCols(v, 1);
108782 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
108783 }
108784 }
108785 break;
@@ -108875,65 +109142,31 @@
109142 int rc;
109143 int i;
109144 #ifndef SQLITE_OMIT_DEPRECATED
109145 int size;
109146 #endif
 
109147 Db *pDb;
109148 char const *azArg[4];
109149 int meta[5];
109150 InitData initData;
109151 const char *zMasterName;
 
109152 int openedTransaction = 0;
109153
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109154 assert( iDb>=0 && iDb<db->nDb );
109155 assert( db->aDb[iDb].pSchema );
109156 assert( sqlite3_mutex_held(db->mutex) );
109157 assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
109158
109159 /* Construct the in-memory representation schema tables (sqlite_master or
109160 ** sqlite_temp_master) by invoking the parser directly. The appropriate
109161 ** table name will be inserted automatically by the parser so we can just
109162 ** use the abbreviation "x" here. The parser will also automatically tag
109163 ** the schema table as read-only. */
109164 azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
 
 
 
 
 
 
 
109165 azArg[1] = "1";
109166 azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
109167 "rootpage integer,sql text)";
109168 azArg[3] = 0;
109169 initData.db = db;
109170 initData.iDb = iDb;
109171 initData.rc = SQLITE_OK;
109172 initData.pzErrMsg = pzErrMsg;
@@ -108940,14 +109173,10 @@
109173 sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
109174 if( initData.rc ){
109175 rc = initData.rc;
109176 goto error_out;
109177 }
 
 
 
 
109178
109179 /* Create a cursor to hold the database open
109180 */
109181 pDb = &db->aDb[iDb];
109182 if( pDb->pBt==0 ){
@@ -109062,11 +109291,11 @@
109291 */
109292 assert( db->init.busy );
109293 {
109294 char *zSql;
109295 zSql = sqlite3MPrintf(db,
109296 "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
109297 db->aDb[iDb].zName, zMasterName);
109298 #ifndef SQLITE_OMIT_AUTHORIZATION
109299 {
109300 sqlite3_xauth xAuth;
109301 xAuth = db->xAuth;
@@ -109688,10 +109917,11 @@
109917 int nOBSat; /* Number of ORDER BY terms satisfied by indices */
109918 int iECursor; /* Cursor number for the sorter */
109919 int regReturn; /* Register holding block-output return address */
109920 int labelBkOut; /* Start label for the block-output subroutine */
109921 int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
109922 int labelDone; /* Jump here when done, ex: LIMIT reached */
109923 u8 sortFlags; /* Zero or more SORTFLAG_* bits */
109924 };
109925 #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
109926
109927 /*
@@ -109745,33 +109975,41 @@
109975 Expr *pOffset /* OFFSET value. NULL means no offset */
109976 ){
109977 Select *pNew;
109978 Select standin;
109979 sqlite3 *db = pParse->db;
109980 pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
109981 if( pNew==0 ){
109982 assert( db->mallocFailed );
109983 pNew = &standin;
 
109984 }
109985 if( pEList==0 ){
109986 pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
109987 }
109988 pNew->pEList = pEList;
109989 pNew->op = TK_SELECT;
109990 pNew->selFlags = selFlags;
109991 pNew->iLimit = 0;
109992 pNew->iOffset = 0;
109993 #if SELECTTRACE_ENABLED
109994 pNew->zSelName[0] = 0;
109995 #endif
109996 pNew->addrOpenEphm[0] = -1;
109997 pNew->addrOpenEphm[1] = -1;
109998 pNew->nSelectRow = 0;
109999 if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
110000 pNew->pSrc = pSrc;
110001 pNew->pWhere = pWhere;
110002 pNew->pGroupBy = pGroupBy;
110003 pNew->pHaving = pHaving;
110004 pNew->pOrderBy = pOrderBy;
110005 pNew->pPrior = 0;
110006 pNew->pNext = 0;
110007 pNew->pLimit = pLimit;
110008 pNew->pOffset = pOffset;
110009 pNew->pWith = 0;
110010 assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
 
 
110011 if( db->mallocFailed ) {
110012 clearSelect(db, pNew, pNew!=&standin);
110013 pNew = 0;
110014 }else{
110015 assert( pNew->pSrc!=0 || pParse->nErr>0 );
@@ -110142,10 +110380,11 @@
110380 int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
110381 int regBase; /* Regs for sorter record */
110382 int regRecord = ++pParse->nMem; /* Assembled sorter record */
110383 int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
110384 int op; /* Opcode to add sorter record to sorter */
110385 int iLimit; /* LIMIT counter */
110386
110387 assert( bSeq==0 || bSeq==1 );
110388 assert( nData==1 || regData==regOrigData );
110389 if( nPrefixReg ){
110390 assert( nPrefixReg==nExpr+bSeq );
@@ -110152,19 +110391,21 @@
110391 regBase = regData - nExpr - bSeq;
110392 }else{
110393 regBase = pParse->nMem + 1;
110394 pParse->nMem += nBase;
110395 }
110396 assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
110397 iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
110398 pSort->labelDone = sqlite3VdbeMakeLabel(v);
110399 sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
110400 SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
110401 if( bSeq ){
110402 sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
110403 }
110404 if( nPrefixReg==0 ){
110405 sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
110406 }
 
110407 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
110408 if( nOBSat>0 ){
110409 int regPrevKey; /* The first nOBSat columns of the previous row */
110410 int addrFirst; /* Address of the OP_IfNot opcode */
110411 int addrJmp; /* Address of the OP_Jump opcode */
@@ -110195,10 +110436,14 @@
110436 sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
110437 pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
110438 pSort->regReturn = ++pParse->nMem;
110439 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
110440 sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
110441 if( iLimit ){
110442 sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
110443 VdbeCoverage(v);
110444 }
110445 sqlite3VdbeJumpHere(v, addrFirst);
110446 sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
110447 sqlite3VdbeJumpHere(v, addrJmp);
110448 }
110449 if( pSort->sortFlags & SORTFLAG_UseSorter ){
@@ -110205,18 +110450,12 @@
110450 op = OP_SorterInsert;
110451 }else{
110452 op = OP_IdxInsert;
110453 }
110454 sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
110455 if( iLimit ){
110456 int addr;
 
 
 
 
 
 
110457 addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
110458 sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
110459 sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
110460 sqlite3VdbeJumpHere(v, addr);
110461 }
@@ -110629,19 +110868,20 @@
110868 /*
110869 ** Allocate a KeyInfo object sufficient for an index of N key columns and
110870 ** X extra columns.
110871 */
110872 SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
110873 int nExtra = (N+X)*(sizeof(CollSeq*)+1);
110874 KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra);
110875 if( p ){
110876 p->aSortOrder = (u8*)&p->aColl[N+X];
110877 p->nField = (u16)N;
110878 p->nXField = (u16)X;
110879 p->enc = ENC(db);
110880 p->db = db;
110881 p->nRef = 1;
110882 memset(&p[1], 0, nExtra);
110883 }else{
110884 db->mallocFailed = 1;
110885 }
110886 return p;
110887 }
@@ -110816,11 +111056,11 @@
111056 SortCtx *pSort, /* Information on the ORDER BY clause */
111057 int nColumn, /* Number of columns of data */
111058 SelectDest *pDest /* Write the sorted results here */
111059 ){
111060 Vdbe *v = pParse->pVdbe; /* The prepared statement */
111061 int addrBreak = pSort->labelDone; /* Jump here to exit loop */
111062 int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
111063 int addr;
111064 int addrOnce = 0;
111065 int iTab;
111066 ExprList *pOrderBy = pSort->pOrderBy;
@@ -110835,10 +111075,11 @@
111075 int bSeq; /* True if sorter record includes seq. no. */
111076 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
111077 struct ExprList_item *aOutEx = p->pEList->a;
111078 #endif
111079
111080 assert( addrBreak<0 );
111081 if( pSort->labelBkOut ){
111082 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
111083 sqlite3VdbeGoto(v, addrBreak);
111084 sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
111085 }
@@ -116425,12 +116666,12 @@
116666 /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
116667 ** is a pointer to the sub-vdbe containing the trigger program. */
116668 if( pPrg ){
116669 int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
116670
116671 sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem,
116672 (const char *)pPrg->pProgram, P4_SUBPROGRAM);
116673 VdbeComment(
116674 (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
116675
116676 /* Set the P5 operand of the OP_Program instruction to non-zero if
116677 ** recursive invocation of this trigger program is disallowed. Recursive
@@ -118780,11 +119021,11 @@
119021 Expr *pExpr /* First argument to the function */
119022 ){
119023 Table *pTab;
119024 sqlite3_vtab *pVtab;
119025 sqlite3_module *pMod;
119026 void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
119027 void *pArg = 0;
119028 FuncDef *pNew;
119029 int rc = 0;
119030 char *zLowerName;
119031 unsigned char *z;
@@ -118808,11 +119049,11 @@
119049 zLowerName = sqlite3DbStrDup(db, pDef->zName);
119050 if( zLowerName ){
119051 for(z=(unsigned char*)zLowerName; *z; z++){
119052 *z = sqlite3UpperToLower[*z];
119053 }
119054 rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
119055 sqlite3DbFree(db, zLowerName);
119056 }
119057 if( rc==0 ){
119058 return pDef;
119059 }
@@ -118825,11 +119066,11 @@
119066 return pDef;
119067 }
119068 *pNew = *pDef;
119069 pNew->zName = (char *)&pNew[1];
119070 memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
119071 pNew->xSFunc = xSFunc;
119072 pNew->pUserData = pArg;
119073 pNew->funcFlags |= SQLITE_FUNC_EPHEM;
119074 return pNew;
119075 }
119076
@@ -119845,12 +120086,11 @@
120086 n--;
120087 }
120088
120089 /* Code the OP_Affinity opcode if there is anything left to do. */
120090 if( n>0 ){
120091 sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
 
120092 sqlite3ExprCacheAffinityChange(pParse, base, n);
120093 }
120094 }
120095
120096
@@ -121398,10 +121638,11 @@
121638 int cnt; /* Number of non-wildcard prefix characters */
121639 char wc[3]; /* Wildcard characters */
121640 sqlite3 *db = pParse->db; /* Database connection */
121641 sqlite3_value *pVal = 0;
121642 int op; /* Opcode of pRight */
121643 int rc; /* Result code to return */
121644
121645 if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
121646 return 0;
121647 }
121648 #ifdef SQLITE_EBCDIC
@@ -121463,12 +121704,13 @@
121704 }else{
121705 z = 0;
121706 }
121707 }
121708
121709 rc = (z!=0);
121710 sqlite3ValueFree(pVal);
121711 return rc;
121712 }
121713 #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
121714
121715
121716 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -126875,12 +127117,11 @@
127117 testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
127118 if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){
127119 Bitmask b = pTabItem->colUsed;
127120 int n = 0;
127121 for(; b; b=b>>1, n++){}
127122 sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32);
 
127123 assert( n<=pTab->nCol );
127124 }
127125 #ifdef SQLITE_ENABLE_CURSOR_HINTS
127126 if( pLoop->u.btree.pIndex!=0 ){
127127 sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
@@ -129343,18 +129584,15 @@
129584 ** { ... } // User supplied code
129585 ** #line <lineno> <thisfile>
129586 ** break;
129587 */
129588 /********** Begin reduce actions **********************************************/
 
 
 
129589 case 6: /* explain ::= EXPLAIN */
129590 { pParse->explain = 1; }
129591 break;
129592 case 7: /* explain ::= EXPLAIN QUERY PLAN */
129593 { pParse->explain = 2; }
129594 break;
129595 case 8: /* cmdx ::= cmd */
129596 { sqlite3FinishCoding(pParse); }
129597 break;
129598 case 9: /* cmd ::= BEGIN transtype trans_opt */
@@ -130525,10 +130763,11 @@
130763 /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
130764 /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
130765 /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
130766 /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
130767 /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
130768 /* (5) explain ::= */ yytestcase(yyruleno==5);
130769 /* (10) trans_opt ::= */ yytestcase(yyruleno==10);
130770 /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
130771 /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
130772 /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
130773 /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
@@ -133601,11 +133840,11 @@
133840 sqlite3 *db,
133841 const char *zFunctionName,
133842 int nArg,
133843 int enc,
133844 void *pUserData,
133845 void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
133846 void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133847 void (*xFinal)(sqlite3_context*),
133848 FuncDestructor *pDestructor
133849 ){
133850 FuncDef *p;
@@ -133612,13 +133851,13 @@
133851 int nName;
133852 int extraFlags;
133853
133854 assert( sqlite3_mutex_held(db->mutex) );
133855 if( zFunctionName==0 ||
133856 (xSFunc && (xFinal || xStep)) ||
133857 (!xSFunc && (xFinal && !xStep)) ||
133858 (!xSFunc && (!xFinal && xStep)) ||
133859 (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
133860 (255<(nName = sqlite3Strlen30( zFunctionName))) ){
133861 return SQLITE_MISUSE_BKPT;
133862 }
133863
@@ -133637,14 +133876,14 @@
133876 if( enc==SQLITE_UTF16 ){
133877 enc = SQLITE_UTF16NATIVE;
133878 }else if( enc==SQLITE_ANY ){
133879 int rc;
133880 rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
133881 pUserData, xSFunc, xStep, xFinal, pDestructor);
133882 if( rc==SQLITE_OK ){
133883 rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
133884 pUserData, xSFunc, xStep, xFinal, pDestructor);
133885 }
133886 if( rc!=SQLITE_OK ){
133887 return rc;
133888 }
133889 enc = SQLITE_UTF16BE;
@@ -133684,12 +133923,11 @@
133923 pDestructor->nRef++;
133924 }
133925 p->pDestructor = pDestructor;
133926 p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
133927 testcase( p->funcFlags & SQLITE_DETERMINISTIC );
133928 p->xSFunc = xSFunc ? xSFunc : xStep;
 
133929 p->xFinalize = xFinal;
133930 p->pUserData = pUserData;
133931 p->nArg = (u16)nArg;
133932 return SQLITE_OK;
133933 }
@@ -133701,25 +133939,25 @@
133939 sqlite3 *db,
133940 const char *zFunc,
133941 int nArg,
133942 int enc,
133943 void *p,
133944 void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
133945 void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133946 void (*xFinal)(sqlite3_context*)
133947 ){
133948 return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
133949 xFinal, 0);
133950 }
133951
133952 SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
133953 sqlite3 *db,
133954 const char *zFunc,
133955 int nArg,
133956 int enc,
133957 void *p,
133958 void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
133959 void (*xStep)(sqlite3_context*,int,sqlite3_value **),
133960 void (*xFinal)(sqlite3_context*),
133961 void (*xDestroy)(void *)
133962 ){
133963 int rc = SQLITE_ERROR;
@@ -133738,11 +133976,11 @@
133976 goto out;
133977 }
133978 pArg->xDestroy = xDestroy;
133979 pArg->pUserData = p;
133980 }
133981 rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
133982 if( pArg && pArg->nRef==0 ){
133983 assert( rc!=SQLITE_OK );
133984 xDestroy(p);
133985 sqlite3DbFree(db, pArg);
133986 }
@@ -133758,11 +133996,11 @@
133996 sqlite3 *db,
133997 const void *zFunctionName,
133998 int nArg,
133999 int eTextRep,
134000 void *p,
134001 void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
134002 void (*xStep)(sqlite3_context*,int,sqlite3_value**),
134003 void (*xFinal)(sqlite3_context*)
134004 ){
134005 int rc;
134006 char *zFunc8;
@@ -133771,11 +134009,11 @@
134009 if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT;
134010 #endif
134011 sqlite3_mutex_enter(db->mutex);
134012 assert( !db->mallocFailed );
134013 zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
134014 rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
134015 sqlite3DbFree(db, zFunc8);
134016 rc = sqlite3ApiExit(db, rc);
134017 sqlite3_mutex_leave(db->mutex);
134018 return rc;
134019 }
@@ -134996,11 +135234,10 @@
135234 sqlite3GlobalConfig.nLookaside);
135235
135236 sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
135237
135238 opendb_out:
 
135239 if( db ){
135240 assert( db->mutex!=0 || isThreadsafe==0
135241 || sqlite3GlobalConfig.bFullMutex==0 );
135242 sqlite3_mutex_leave(db->mutex);
135243 }
@@ -135033,10 +135270,11 @@
135270 }
135271 sqlite3_key_v2(db, 0, zKey, i/2);
135272 }
135273 }
135274 #endif
135275 sqlite3_free(zOpen);
135276 return rc & 0xff;
135277 }
135278
135279 /*
135280 ** Open a new database handle.
@@ -135450,10 +135688,13 @@
135688 *(sqlite3_file**)pArg = fd;
135689 rc = SQLITE_OK;
135690 }else if( op==SQLITE_FCNTL_VFS_POINTER ){
135691 *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
135692 rc = SQLITE_OK;
135693 }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
135694 *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
135695 rc = SQLITE_OK;
135696 }else if( fd->pMethods ){
135697 rc = sqlite3OsFileControl(fd, op, pArg);
135698 }else{
135699 rc = SQLITE_NOTFOUND;
135700 }
@@ -161083,11 +161324,11 @@
161324 */
161325 static void *rbuMalloc(sqlite3rbu *p, int nByte){
161326 void *pRet = 0;
161327 if( p->rc==SQLITE_OK ){
161328 assert( nByte>0 );
161329 pRet = sqlite3_malloc64(nByte);
161330 if( pRet==0 ){
161331 p->rc = SQLITE_NOMEM;
161332 }else{
161333 memset(pRet, 0, nByte);
161334 }
@@ -161129,12 +161370,12 @@
161370 static char *rbuStrndup(const char *zStr, int *pRc){
161371 char *zRet = 0;
161372
161373 assert( *pRc==SQLITE_OK );
161374 if( zStr ){
161375 size_t nCopy = strlen(zStr) + 1;
161376 zRet = (char*)sqlite3_malloc64(nCopy);
161377 if( zRet ){
161378 memcpy(zRet, zStr, nCopy);
161379 }else{
161380 *pRc = SQLITE_NOMEM;
161381 }
@@ -162478,11 +162719,11 @@
162719
162720 pRbu->pgsz = iAmt;
162721 if( pRbu->nFrame==pRbu->nFrameAlloc ){
162722 int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
162723 RbuFrame *aNew;
162724 aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame));
162725 if( aNew==0 ) return SQLITE_NOMEM;
162726 pRbu->aFrame = aNew;
162727 pRbu->nFrameAlloc = nNew;
162728 }
162729
@@ -162543,11 +162784,11 @@
162784
162785 nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
162786 if( nChar==0 ){
162787 return 0;
162788 }
162789 zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
162790 if( zWideFilename==0 ){
162791 return 0;
162792 }
162793 memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
162794 nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
@@ -163177,15 +163418,16 @@
163418 const char *zTarget,
163419 const char *zRbu,
163420 const char *zState
163421 ){
163422 sqlite3rbu *p;
163423 size_t nTarget = strlen(zTarget);
163424 size_t nRbu = strlen(zRbu);
163425 size_t nState = zState ? strlen(zState) : 0;
163426 size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1;
163427
163428 p = (sqlite3rbu*)sqlite3_malloc64(nByte);
163429 if( p ){
163430 RbuState *pState = 0;
163431
163432 /* Create the custom VFS. */
163433 memset(p, 0, sizeof(sqlite3rbu));
@@ -163318,11 +163560,11 @@
163560 ** the pattern "rbu_imp_[0-9]*".
163561 */
163562 static void rbuEditErrmsg(sqlite3rbu *p){
163563 if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
163564 int i;
163565 size_t nErrmsg = strlen(p->zErrmsg);
163566 for(i=0; i<(nErrmsg-8); i++){
163567 if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
163568 int nDel = 8;
163569 while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
163570 memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
@@ -163782,11 +164024,11 @@
164024 ** instead of a file on disk. */
164025 assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
164026 if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
164027 if( iRegion<=p->nShm ){
164028 int nByte = (iRegion+1) * sizeof(char*);
164029 char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
164030 if( apNew==0 ){
164031 rc = SQLITE_NOMEM;
164032 }else{
164033 memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
164034 p->apShm = apNew;
@@ -163793,11 +164035,11 @@
164035 p->nShm = iRegion+1;
164036 }
164037 }
164038
164039 if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
164040 char *pNew = (char*)sqlite3_malloc64(szRegion);
164041 if( pNew==0 ){
164042 rc = SQLITE_NOMEM;
164043 }else{
164044 memset(pNew, 0, szRegion);
164045 p->apShm[iRegion] = pNew;
@@ -163903,11 +164145,11 @@
164145 /* A main database has just been opened. The following block sets
164146 ** (pFd->zWal) to point to a buffer owned by SQLite that contains
164147 ** the name of the *-wal file this db connection will use. SQLite
164148 ** happens to pass a pointer to this buffer when using xAccess()
164149 ** or xOpen() to operate on the *-wal file. */
164150 int n = (int)strlen(zName);
164151 const char *z = &zName[n];
164152 if( flags & SQLITE_OPEN_URI ){
164153 int odd = 0;
164154 while( 1 ){
164155 if( z[0]==0 ){
@@ -163929,12 +164171,12 @@
164171 if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
164172 /* This call is to open a *-wal file. Intead, open the *-oal. This
164173 ** code ensures that the string passed to xOpen() is terminated by a
164174 ** pair of '\0' bytes in case the VFS attempts to extract a URI
164175 ** parameter from it. */
164176 size_t nCopy = strlen(zName);
164177 char *zCopy = sqlite3_malloc64(nCopy+2);
164178 if( zCopy ){
164179 memcpy(zCopy, zName, nCopy);
164180 zCopy[nCopy-3] = 'o';
164181 zCopy[nCopy] = '\0';
164182 zCopy[nCopy+1] = '\0';
@@ -164159,17 +164401,17 @@
164401 0, /* xCurrentTimeInt64 (version 2) */
164402 0, 0, 0 /* Unimplemented version 3 methods */
164403 };
164404
164405 rbu_vfs *pNew = 0; /* Newly allocated VFS */
 
164406 int rc = SQLITE_OK;
164407 size_t nName;
164408 size_t nByte;
164409
 
164410 nName = strlen(zName);
164411 nByte = sizeof(rbu_vfs) + nName + 1;
164412 pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
164413 if( pNew==0 ){
164414 rc = SQLITE_NOMEM;
164415 }else{
164416 sqlite3_vfs *pParent; /* Parent VFS */
164417 memset(pNew, 0, nByte);
@@ -167174,10 +167416,13 @@
167416 ** If parameter iCol is greater than or equal to the number of columns
167417 ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
167418 ** an OOM condition or IO error), an appropriate SQLite error code is
167419 ** returned.
167420 **
167421 ** This function may be quite inefficient if used with an FTS5 table
167422 ** created with the "columnsize=0" option.
167423 **
167424 ** xColumnText:
167425 ** This function attempts to retrieve the text of column iCol of the
167426 ** current document. If successful, (*pz) is set to point to a buffer
167427 ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
167428 ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -167194,18 +167439,32 @@
167439 ** xInstCount:
167440 ** Set *pnInst to the total number of occurrences of all phrases within
167441 ** the query within the current row. Return SQLITE_OK if successful, or
167442 ** an error code (i.e. SQLITE_NOMEM) if an error occurs.
167443 **
167444 ** This API can be quite slow if used with an FTS5 table created with the
167445 ** "detail=none" or "detail=column" option. If the FTS5 table is created
167446 ** with either "detail=none" or "detail=column" and "content=" option
167447 ** (i.e. if it is a contentless table), then this API always returns 0.
167448 **
167449 ** xInst:
167450 ** Query for the details of phrase match iIdx within the current row.
167451 ** Phrase matches are numbered starting from zero, so the iIdx argument
167452 ** should be greater than or equal to zero and smaller than the value
167453 ** output by xInstCount().
167454 **
167455 ** Usually, output parameter *piPhrase is set to the phrase number, *piCol
167456 ** to the column in which it occurs and *piOff the token offset of the
167457 ** first token of the phrase. The exception is if the table was created
167458 ** with the offsets=0 option specified. In this case *piOff is always
167459 ** set to -1.
167460 **
167461 ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
167462 ** if an error occurs.
167463 **
167464 ** This API can be quite slow if used with an FTS5 table created with the
167465 ** "detail=none" or "detail=column" option.
167466 **
167467 ** xRowid:
167468 ** Returns the rowid of the current row.
167469 **
167470 ** xTokenize:
@@ -167286,25 +167545,63 @@
167545 ** through instances of phrase iPhrase, use the following code:
167546 **
167547 ** Fts5PhraseIter iter;
167548 ** int iCol, iOff;
167549 ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
167550 ** iCol>=0;
167551 ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
167552 ** ){
167553 ** // An instance of phrase iPhrase at offset iOff of column iCol
167554 ** }
167555 **
167556 ** The Fts5PhraseIter structure is defined above. Applications should not
167557 ** modify this structure directly - it should only be used as shown above
167558 ** with the xPhraseFirst() and xPhraseNext() API methods (and by
167559 ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
167560 **
167561 ** This API can be quite slow if used with an FTS5 table created with the
167562 ** "detail=none" or "detail=column" option. If the FTS5 table is created
167563 ** with either "detail=none" or "detail=column" and "content=" option
167564 ** (i.e. if it is a contentless table), then this API always iterates
167565 ** through an empty set (all calls to xPhraseFirst() set iCol to -1).
167566 **
167567 ** xPhraseNext()
167568 ** See xPhraseFirst above.
167569 **
167570 ** xPhraseFirstColumn()
167571 ** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
167572 ** and xPhraseNext() APIs described above. The difference is that instead
167573 ** of iterating through all instances of a phrase in the current row, these
167574 ** APIs are used to iterate through the set of columns in the current row
167575 ** that contain one or more instances of a specified phrase. For example:
167576 **
167577 ** Fts5PhraseIter iter;
167578 ** int iCol;
167579 ** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
167580 ** iCol>=0;
167581 ** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
167582 ** ){
167583 ** // Column iCol contains at least one instance of phrase iPhrase
167584 ** }
167585 **
167586 ** This API can be quite slow if used with an FTS5 table created with the
167587 ** "detail=none" option. If the FTS5 table is created with either
167588 ** "detail=none" "content=" option (i.e. if it is a contentless table),
167589 ** then this API always iterates through an empty set (all calls to
167590 ** xPhraseFirstColumn() set iCol to -1).
167591 **
167592 ** The information accessed using this API and its companion
167593 ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
167594 ** (or xInst/xInstCount). The chief advantage of this API is that it is
167595 ** significantly more efficient than those alternatives when used with
167596 ** "detail=column" tables.
167597 **
167598 ** xPhraseNextColumn()
167599 ** See xPhraseFirstColumn above.
167600 */
167601 struct Fts5ExtensionApi {
167602 int iVersion; /* Currently always set to 3 */
167603
167604 void *(*xUserData)(Fts5Context*);
167605
167606 int (*xColumnCount)(Fts5Context*);
167607 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -167330,12 +167627,15 @@
167627 int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
167628 );
167629 int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
167630 void *(*xGetAuxdata)(Fts5Context*, int bClear);
167631
167632 int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
167633 void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
167634
167635 int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
167636 void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
167637 };
167638
167639 /*
167640 ** CUSTOM AUXILIARY FUNCTIONS
167641 *************************************************************************/
@@ -167762,10 +168062,11 @@
168062 int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
168063 int eContent; /* An FTS5_CONTENT value */
168064 char *zContent; /* content table */
168065 char *zContentRowid; /* "content_rowid=" option value */
168066 int bColumnsize; /* "columnsize=" option value (dflt==1) */
168067 int eDetail; /* FTS5_DETAIL_XXX value */
168068 char *zContentExprlist;
168069 Fts5Tokenizer *pTok;
168070 fts5_tokenizer *pTokApi;
168071
168072 /* Values loaded from the %_config table */
@@ -167790,10 +168091,13 @@
168091
168092 #define FTS5_CONTENT_NORMAL 0
168093 #define FTS5_CONTENT_NONE 1
168094 #define FTS5_CONTENT_EXTERNAL 2
168095
168096 #define FTS5_DETAIL_FULL 0
168097 #define FTS5_DETAIL_NONE 1
168098 #define FTS5_DETAIL_COLUMNS 2
168099
168100
168101
168102 static int sqlite3Fts5ConfigParse(
168103 Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
@@ -167832,17 +168136,17 @@
168136 ** Buffer object for the incremental building of string data.
168137 */
168138 typedef struct Fts5Buffer Fts5Buffer;
168139 struct Fts5Buffer {
168140 u8 *p;
168141 u32 n;
168142 u32 nSpace;
168143 };
168144
168145 static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32);
168146 static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
168147 static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*);
168148 static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
168149 static void sqlite3Fts5BufferFree(Fts5Buffer*);
168150 static void sqlite3Fts5BufferZero(Fts5Buffer*);
168151 static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
168152 static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
@@ -167903,10 +168207,17 @@
168207 static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
168208
168209 /* Character set tests (like isspace(), isalpha() etc.) */
168210 static int sqlite3Fts5IsBareword(char t);
168211
168212
168213 /* Bucket of terms object used by the integrity-check in offsets=0 mode. */
168214 typedef struct Fts5Termset Fts5Termset;
168215 static int sqlite3Fts5TermsetNew(Fts5Termset**);
168216 static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent);
168217 static void sqlite3Fts5TermsetFree(Fts5Termset*);
168218
168219 /*
168220 ** End of interface to code in fts5_buffer.c.
168221 **************************************************************************/
168222
168223 /**************************************************************************
@@ -167938,10 +168249,33 @@
168249 ** sqlite3Fts5IterNext(pIter)
168250 ** ){
168251 ** i64 iRowid = sqlite3Fts5IterRowid(pIter);
168252 ** }
168253 */
168254
168255 /*
168256 ** Return a simple checksum value based on the arguments.
168257 */
168258 static u64 sqlite3Fts5IndexEntryCksum(
168259 i64 iRowid,
168260 int iCol,
168261 int iPos,
168262 int iIdx,
168263 const char *pTerm,
168264 int nTerm
168265 );
168266
168267 /*
168268 ** Argument p points to a buffer containing utf-8 text that is n bytes in
168269 ** size. Return the number of bytes in the nChar character prefix of the
168270 ** buffer, or 0 if there are less than nChar characters in total.
168271 */
168272 static int sqlite3Fts5IndexCharlenToBytelen(
168273 const char *p,
168274 int nByte,
168275 int nChar
168276 );
168277
168278 /*
168279 ** Open a new iterator to iterate though all rowids that match the
168280 ** specified token or token prefix.
168281 */
@@ -168024,11 +168358,10 @@
168358 static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
168359
168360 /*
168361 ** Functions called by the storage module as part of integrity-check.
168362 */
 
168363 static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
168364
168365 /*
168366 ** Called during virtual module initialization to register UDF
168367 ** fts5_decode() with SQLite
@@ -168046,10 +168379,12 @@
168379 static int sqlite3Fts5IndexReinit(Fts5Index *p);
168380 static int sqlite3Fts5IndexOptimize(Fts5Index *p);
168381 static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
168382
168383 static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
168384
168385 static int sqlite3Fts5IterCollist(Fts5IndexIter*, const u8 **, int*);
168386
168387 /*
168388 ** End of interface to code in fts5_index.c.
168389 **************************************************************************/
168390
@@ -168103,11 +168438,11 @@
168438 typedef struct Fts5Hash Fts5Hash;
168439
168440 /*
168441 ** Create a hash table, free a hash table.
168442 */
168443 static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize);
168444 static void sqlite3Fts5HashFree(Fts5Hash*);
168445
168446 static int sqlite3Fts5HashWrite(
168447 Fts5Hash*,
168448 i64 iRowid, /* Rowid for this entry */
@@ -168162,11 +168497,11 @@
168497 static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
168498
168499 static int sqlite3Fts5DropAll(Fts5Config*);
168500 static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
168501
168502 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
168503 static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
168504 static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
168505
168506 static int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
168507
@@ -168182,12 +168517,10 @@
168517
168518 static int sqlite3Fts5StorageConfigValue(
168519 Fts5Storage *p, const char*, sqlite3_value*, int
168520 );
168521
 
 
168522 static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
168523 static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
168524 static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
168525 static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
168526
@@ -168239,12 +168572,22 @@
168572 static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
168573
168574 static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
168575 static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
168576 static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
168577
168578 typedef struct Fts5PoslistPopulator Fts5PoslistPopulator;
168579 static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int);
168580 static int sqlite3Fts5ExprPopulatePoslists(
168581 Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
168582 );
168583 static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
168584 static void sqlite3Fts5ExprClearEof(Fts5Expr*);
168585
168586 static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
168587
168588 static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
168589
168590 /*******************************************
168591 ** The fts5_expr.c API above this point is used by the other hand-written
168592 ** C code in this module. The interfaces below this point are called by
168593 ** the parser code in fts5parse.y. */
@@ -170120,12 +170463,12 @@
170463
170464
170465
170466 /* #include "fts5Int.h" */
170467
170468 static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
170469 u32 nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
170470 u8 *pNew;
170471 while( nNew<nByte ){
170472 nNew = nNew * 2;
170473 }
170474 pNew = sqlite3_realloc(pBuf->p, nNew);
@@ -170166,14 +170509,14 @@
170509 ** is called, it is a no-op.
170510 */
170511 static void sqlite3Fts5BufferAppendBlob(
170512 int *pRc,
170513 Fts5Buffer *pBuf,
170514 u32 nData,
170515 const u8 *pData
170516 ){
170517 assert_nc( *pRc || nData>=0 );
170518 if( fts5BufferGrow(pRc, pBuf, nData) ) return;
170519 memcpy(&pBuf->p[pBuf->n], pData, nData);
170520 pBuf->n += nData;
170521 }
170522
@@ -170397,10 +170740,96 @@
170740
170741 return (t & 0x80) || aBareword[(int)t];
170742 }
170743
170744
170745 /*************************************************************************
170746 */
170747 typedef struct Fts5TermsetEntry Fts5TermsetEntry;
170748 struct Fts5TermsetEntry {
170749 char *pTerm;
170750 int nTerm;
170751 int iIdx; /* Index (main or aPrefix[] entry) */
170752 Fts5TermsetEntry *pNext;
170753 };
170754
170755 struct Fts5Termset {
170756 Fts5TermsetEntry *apHash[512];
170757 };
170758
170759 static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
170760 int rc = SQLITE_OK;
170761 *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset));
170762 return rc;
170763 }
170764
170765 static int sqlite3Fts5TermsetAdd(
170766 Fts5Termset *p,
170767 int iIdx,
170768 const char *pTerm, int nTerm,
170769 int *pbPresent
170770 ){
170771 int rc = SQLITE_OK;
170772 *pbPresent = 0;
170773 if( p ){
170774 int i;
170775 int hash = 13;
170776 Fts5TermsetEntry *pEntry;
170777
170778 /* Calculate a hash value for this term. This is the same hash checksum
170779 ** used by the fts5_hash.c module. This is not important for correct
170780 ** operation of the module, but is necessary to ensure that some tests
170781 ** designed to produce hash table collisions really do work. */
170782 for(i=nTerm-1; i>=0; i--){
170783 hash = (hash << 3) ^ hash ^ pTerm[i];
170784 }
170785 hash = (hash << 3) ^ hash ^ iIdx;
170786 hash = hash % ArraySize(p->apHash);
170787
170788 for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
170789 if( pEntry->iIdx==iIdx
170790 && pEntry->nTerm==nTerm
170791 && memcmp(pEntry->pTerm, pTerm, nTerm)==0
170792 ){
170793 *pbPresent = 1;
170794 break;
170795 }
170796 }
170797
170798 if( pEntry==0 ){
170799 pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm);
170800 if( pEntry ){
170801 pEntry->pTerm = (char*)&pEntry[1];
170802 pEntry->nTerm = nTerm;
170803 pEntry->iIdx = iIdx;
170804 memcpy(pEntry->pTerm, pTerm, nTerm);
170805 pEntry->pNext = p->apHash[hash];
170806 p->apHash[hash] = pEntry;
170807 }
170808 }
170809 }
170810
170811 return rc;
170812 }
170813
170814 static void sqlite3Fts5TermsetFree(Fts5Termset *p){
170815 if( p ){
170816 int i;
170817 for(i=0; i<ArraySize(p->apHash); i++){
170818 Fts5TermsetEntry *pEntry = p->apHash[i];
170819 while( pEntry ){
170820 Fts5TermsetEntry *pDel = pEntry;
170821 pEntry = pEntry->pNext;
170822 sqlite3_free(pDel);
170823 }
170824 }
170825 sqlite3_free(p);
170826 }
170827 }
170828
170829
170830
170831
170832 /*
170833 ** 2014 Jun 09
170834 **
170835 ** The author disclaims copyright to this source code. In place of
@@ -170412,11 +170841,10 @@
170841 **
170842 ******************************************************************************
170843 **
170844 ** This is an SQLite module implementing full-text search.
170845 */
 
170846
170847
170848 /* #include "fts5Int.h" */
170849
170850 #define FTS5_DEFAULT_PAGE_SIZE 4050
@@ -170595,10 +171023,37 @@
171023 if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
171024 fts5Dequote(z);
171025 }
171026 }
171027
171028
171029 struct Fts5Enum {
171030 const char *zName;
171031 int eVal;
171032 };
171033 typedef struct Fts5Enum Fts5Enum;
171034
171035 static int fts5ConfigSetEnum(
171036 const Fts5Enum *aEnum,
171037 const char *zEnum,
171038 int *peVal
171039 ){
171040 int nEnum = strlen(zEnum);
171041 int i;
171042 int iVal = -1;
171043
171044 for(i=0; aEnum[i].zName; i++){
171045 if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){
171046 if( iVal>=0 ) return SQLITE_ERROR;
171047 iVal = aEnum[i].eVal;
171048 }
171049 }
171050
171051 *peVal = iVal;
171052 return iVal<0 ? SQLITE_ERROR : SQLITE_OK;
171053 }
171054
171055 /*
171056 ** Parse a "special" CREATE VIRTUAL TABLE directive and update
171057 ** configuration object pConfig as appropriate.
171058 **
171059 ** If successful, object pConfig is updated and SQLITE_OK returned. If
@@ -170652,11 +171107,11 @@
171107 while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
171108 nPre = nPre*10 + (p[0] - '0');
171109 p++;
171110 }
171111
171112 if( nPre<=0 || nPre>=1000 ){
171113 *pzErr = sqlite3_mprintf("prefix length out of range (max 999)");
171114 rc = SQLITE_ERROR;
171115 break;
171116 }
171117
@@ -170744,10 +171199,24 @@
171199 }else{
171200 pConfig->bColumnsize = (zArg[0]=='1');
171201 }
171202 return rc;
171203 }
171204
171205 if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
171206 const Fts5Enum aDetail[] = {
171207 { "none", FTS5_DETAIL_NONE },
171208 { "full", FTS5_DETAIL_FULL },
171209 { "columns", FTS5_DETAIL_COLUMNS },
171210 { 0, 0 }
171211 };
171212
171213 if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){
171214 *pzErr = sqlite3_mprintf("malformed detail=... directive");
171215 }
171216 return rc;
171217 }
171218
171219 *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
171220 return SQLITE_ERROR;
171221 }
171222
@@ -170900,10 +171369,11 @@
171369 pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
171370 pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
171371 pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
171372 pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
171373 pRet->bColumnsize = 1;
171374 pRet->eDetail = FTS5_DETAIL_FULL;
171375 #ifdef SQLITE_DEBUG
171376 pRet->bPrefixIndex = 1;
171377 #endif
171378 if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
171379 *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
@@ -171346,10 +171816,11 @@
171816 #endif
171817
171818
171819 struct Fts5Expr {
171820 Fts5Index *pIndex;
171821 Fts5Config *pConfig;
171822 Fts5ExprNode *pRoot;
171823 int bDesc; /* Iterate in descending rowid order */
171824 int nPhrase; /* Number of phrases in expression */
171825 Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */
171826 };
@@ -171541,10 +172012,11 @@
172012 sParse.rc = SQLITE_NOMEM;
172013 sqlite3Fts5ParseNodeFree(sParse.pExpr);
172014 }else{
172015 pNew->pRoot = sParse.pExpr;
172016 pNew->pIndex = 0;
172017 pNew->pConfig = pConfig;
172018 pNew->apExprPhrase = sParse.apPhrase;
172019 pNew->nPhrase = sParse.nPhrase;
172020 sParse.apPhrase = 0;
172021 }
172022 }
@@ -171605,12 +172077,13 @@
172077 }
172078
172079 /*
172080 ** Argument pTerm must be a synonym iterator.
172081 */
172082 static int fts5ExprSynonymList(
172083 Fts5ExprTerm *pTerm,
172084 int bCollist,
172085 Fts5Colset *pColset,
172086 i64 iRowid,
172087 int *pbDel, /* OUT: Caller should sqlite3_free(*pa) */
172088 u8 **pa, int *pn
172089 ){
@@ -171625,13 +172098,20 @@
172098 for(p=pTerm; p; p=p->pSynonym){
172099 Fts5IndexIter *pIter = p->pIter;
172100 if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){
172101 const u8 *a;
172102 int n;
172103
172104 if( bCollist ){
172105 rc = sqlite3Fts5IterCollist(pIter, &a, &n);
172106 }else{
172107 i64 dummy;
172108 rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
172109 }
172110
172111 if( rc!=SQLITE_OK ) goto synonym_poslist_out;
172112 if( n==0 ) continue;
172113 if( nIter==nAlloc ){
172114 int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
172115 Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
172116 if( aNew==0 ){
172117 rc = SQLITE_NOMEM;
@@ -171728,12 +172208,12 @@
172208 i64 dummy;
172209 int n = 0;
172210 int bFlag = 0;
172211 const u8 *a = 0;
172212 if( pTerm->pSynonym ){
172213 rc = fts5ExprSynonymList(
172214 pTerm, 0, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
172215 );
172216 }else{
172217 rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
172218 }
172219 if( rc!=SQLITE_OK ) goto ismatch_out;
@@ -172063,34 +172543,55 @@
172543 Fts5Expr *pExpr, /* Expression that pNear is a part of */
172544 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */
172545 ){
172546 Fts5ExprNearset *pNear = pNode->pNear;
172547 int rc = *pRc;
172548
172549 if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){
172550 Fts5ExprTerm *pTerm;
172551 Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
172552 pPhrase->poslist.n = 0;
172553 for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
172554 Fts5IndexIter *pIter = pTerm->pIter;
172555 if( sqlite3Fts5IterEof(pIter)==0 ){
172556 int n;
172557 i64 iRowid;
172558 rc = sqlite3Fts5IterPoslist(pIter, pNear->pColset, 0, &n, &iRowid);
172559 if( rc!=SQLITE_OK ){
172560 *pRc = rc;
172561 return 0;
172562 }else if( iRowid==pNode->iRowid && n>0 ){
172563 pPhrase->poslist.n = 1;
172564 }
172565 }
172566 }
172567 return pPhrase->poslist.n;
172568 }else{
172569 int i;
172570
172571 /* Check that each phrase in the nearset matches the current row.
172572 ** Populate the pPhrase->poslist buffers at the same time. If any
172573 ** phrase is not a match, break out of the loop early. */
172574 for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
172575 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
172576 if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
172577 int bMatch = 0;
172578 rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
172579 if( bMatch==0 ) break;
172580 }else{
172581 rc = sqlite3Fts5IterPoslistBuffer(
172582 pPhrase->aTerm[0].pIter, &pPhrase->poslist
172583 );
172584 }
172585 }
172586
172587 *pRc = rc;
172588 if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
172589 return 1;
172590 }
172591 return 0;
172592 }
172593 }
172594
172595 static int fts5ExprTokenTest(
172596 Fts5Expr *pExpr, /* Expression that pNear is a part of */
172597 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */
@@ -172109,11 +172610,11 @@
172610 assert( pNode->eType==FTS5_TERM );
172611 assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
172612 assert( pPhrase->aTerm[0].pSynonym==0 );
172613
172614 rc = sqlite3Fts5IterPoslist(pIter, pColset,
172615 (const u8**)&pPhrase->poslist.p, (int*)&pPhrase->poslist.n, &pNode->iRowid
172616 );
172617 pNode->bNomatch = (pPhrase->poslist.n==0);
172618 return rc;
172619 }
172620
@@ -172524,10 +173025,13 @@
173025 if( cmp || p2->bNomatch ) break;
173026 rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
173027 }
173028 pNode->bEof = p1->bEof;
173029 pNode->iRowid = p1->iRowid;
173030 if( p1->bEof ){
173031 fts5ExprNodeZeroPoslist(p2);
173032 }
173033 break;
173034 }
173035 }
173036 }
173037 return rc;
@@ -172909,10 +173413,11 @@
173413 }
173414
173415 if( rc==SQLITE_OK ){
173416 /* All the allocations succeeded. Put the expression object together. */
173417 pNew->pIndex = pExpr->pIndex;
173418 pNew->pConfig = pExpr->pConfig;
173419 pNew->nPhrase = 1;
173420 pNew->apExprPhrase[0] = sCtx.pPhrase;
173421 pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
173422 pNew->pRoot->pNear->nPhrase = 1;
173423 sCtx.pPhrase->pNode = pNew->pRoot;
@@ -173050,10 +173555,19 @@
173555 static void sqlite3Fts5ParseSetColset(
173556 Fts5Parse *pParse,
173557 Fts5ExprNearset *pNear,
173558 Fts5Colset *pColset
173559 ){
173560 if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
173561 pParse->rc = SQLITE_ERROR;
173562 pParse->zErr = sqlite3_mprintf(
173563 "fts5: column queries are not supported (detail=none)"
173564 );
173565 sqlite3_free(pColset);
173566 return;
173567 }
173568
173569 if( pNear ){
173570 pNear->pColset = pColset;
173571 }else{
173572 sqlite3_free(pColset);
173573 }
@@ -173111,15 +173625,24 @@
173625 if( eType==FTS5_STRING ){
173626 int iPhrase;
173627 for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
173628 pNear->apPhrase[iPhrase]->pNode = pRet;
173629 }
173630 if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 ){
173631 if( pNear->apPhrase[0]->aTerm[0].pSynonym==0 ){
173632 pRet->eType = FTS5_TERM;
173633 }
173634 }else if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
173635 assert( pParse->rc==SQLITE_OK );
173636 pParse->rc = SQLITE_ERROR;
173637 assert( pParse->zErr==0 );
173638 pParse->zErr = sqlite3_mprintf(
173639 "fts5: %s queries are not supported (detail!=full)",
173640 pNear->nPhrase==1 ? "phrase": "NEAR"
173641 );
173642 sqlite3_free(pRet);
173643 pRet = 0;
173644 }
173645 }else{
173646 fts5ExprAddChildren(pRet, pLeft);
173647 fts5ExprAddChildren(pRet, pRight);
173648 }
@@ -173229,10 +173752,13 @@
173752
173753 zRet = fts5PrintfAppend(zRet, " {");
173754 for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
173755 char *zTerm = pPhrase->aTerm[iTerm].zTerm;
173756 zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
173757 if( pPhrase->aTerm[iTerm].bPrefix ){
173758 zRet = fts5PrintfAppend(zRet, "*");
173759 }
173760 }
173761
173762 if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
173763 if( zRet==0 ) return 0;
173764 }
@@ -173541,10 +174067,232 @@
174067 *pa = 0;
174068 nRet = 0;
174069 }
174070 return nRet;
174071 }
174072
174073 struct Fts5PoslistPopulator {
174074 Fts5PoslistWriter writer;
174075 int bOk; /* True if ok to populate */
174076 int bMiss;
174077 };
174078
174079 static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
174080 Fts5PoslistPopulator *pRet;
174081 pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
174082 if( pRet ){
174083 int i;
174084 memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
174085 for(i=0; i<pExpr->nPhrase; i++){
174086 Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
174087 Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
174088 assert( pExpr->apExprPhrase[i]->nTerm==1 );
174089 if( bLive &&
174090 (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
174091 ){
174092 pRet[i].bMiss = 1;
174093 }else{
174094 pBuf->n = 0;
174095 }
174096 }
174097 }
174098 return pRet;
174099 }
174100
174101 struct Fts5ExprCtx {
174102 Fts5Expr *pExpr;
174103 Fts5PoslistPopulator *aPopulator;
174104 i64 iOff;
174105 };
174106 typedef struct Fts5ExprCtx Fts5ExprCtx;
174107
174108 /*
174109 ** TODO: Make this more efficient!
174110 */
174111 static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
174112 int i;
174113 for(i=0; i<pColset->nCol; i++){
174114 if( pColset->aiCol[i]==iCol ) return 1;
174115 }
174116 return 0;
174117 }
174118
174119 static int fts5ExprPopulatePoslistsCb(
174120 void *pCtx, /* Copy of 2nd argument to xTokenize() */
174121 int tflags, /* Mask of FTS5_TOKEN_* flags */
174122 const char *pToken, /* Pointer to buffer containing token */
174123 int nToken, /* Size of token in bytes */
174124 int iStart, /* Byte offset of token within input text */
174125 int iEnd /* Byte offset of end of token within input text */
174126 ){
174127 Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
174128 Fts5Expr *pExpr = p->pExpr;
174129 int i;
174130
174131 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
174132 for(i=0; i<pExpr->nPhrase; i++){
174133 Fts5ExprTerm *pTerm;
174134 if( p->aPopulator[i].bOk==0 ) continue;
174135 for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
174136 int nTerm = strlen(pTerm->zTerm);
174137 if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
174138 && memcmp(pTerm->zTerm, pToken, nTerm)==0
174139 ){
174140 int rc = sqlite3Fts5PoslistWriterAppend(
174141 &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
174142 );
174143 if( rc ) return rc;
174144 break;
174145 }
174146 }
174147 }
174148 return SQLITE_OK;
174149 }
174150
174151 static int sqlite3Fts5ExprPopulatePoslists(
174152 Fts5Config *pConfig,
174153 Fts5Expr *pExpr,
174154 Fts5PoslistPopulator *aPopulator,
174155 int iCol,
174156 const char *z, int n
174157 ){
174158 int i;
174159 Fts5ExprCtx sCtx;
174160 sCtx.pExpr = pExpr;
174161 sCtx.aPopulator = aPopulator;
174162 sCtx.iOff = (((i64)iCol) << 32) - 1;
174163
174164 for(i=0; i<pExpr->nPhrase; i++){
174165 Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
174166 Fts5Colset *pColset = pNode->pNear->pColset;
174167 if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
174168 || aPopulator[i].bMiss
174169 ){
174170 aPopulator[i].bOk = 0;
174171 }else{
174172 aPopulator[i].bOk = 1;
174173 }
174174 }
174175
174176 return sqlite3Fts5Tokenize(pConfig,
174177 FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
174178 );
174179 }
174180
174181 static void fts5ExprClearPoslists(Fts5ExprNode *pNode){
174182 if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){
174183 pNode->pNear->apPhrase[0]->poslist.n = 0;
174184 }else{
174185 int i;
174186 for(i=0; i<pNode->nChild; i++){
174187 fts5ExprClearPoslists(pNode->apChild[i]);
174188 }
174189 }
174190 }
174191
174192 static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
174193 pNode->iRowid = iRowid;
174194 pNode->bEof = 0;
174195 switch( pNode->eType ){
174196 case FTS5_TERM:
174197 case FTS5_STRING:
174198 return (pNode->pNear->apPhrase[0]->poslist.n>0);
174199
174200 case FTS5_AND: {
174201 int i;
174202 for(i=0; i<pNode->nChild; i++){
174203 if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){
174204 fts5ExprClearPoslists(pNode);
174205 return 0;
174206 }
174207 }
174208 break;
174209 }
174210
174211 case FTS5_OR: {
174212 int i;
174213 int bRet = 0;
174214 for(i=0; i<pNode->nChild; i++){
174215 if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){
174216 bRet = 1;
174217 }
174218 }
174219 return bRet;
174220 }
174221
174222 default: {
174223 assert( pNode->eType==FTS5_NOT );
174224 if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid)
174225 || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid)
174226 ){
174227 fts5ExprClearPoslists(pNode);
174228 return 0;
174229 }
174230 break;
174231 }
174232 }
174233 return 1;
174234 }
174235
174236 static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
174237 fts5ExprCheckPoslists(pExpr->pRoot, iRowid);
174238 }
174239
174240 static void fts5ExprClearEof(Fts5ExprNode *pNode){
174241 int i;
174242 for(i=0; i<pNode->nChild; i++){
174243 fts5ExprClearEof(pNode->apChild[i]);
174244 }
174245 pNode->bEof = 0;
174246 }
174247 static void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){
174248 fts5ExprClearEof(pExpr->pRoot);
174249 }
174250
174251 /*
174252 ** This function is only called for detail=columns tables.
174253 */
174254 static int sqlite3Fts5ExprPhraseCollist(
174255 Fts5Expr *pExpr,
174256 int iPhrase,
174257 const u8 **ppCollist,
174258 int *pnCollist
174259 ){
174260 Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
174261 Fts5ExprNode *pNode = pPhrase->pNode;
174262 int rc = SQLITE_OK;
174263
174264 assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
174265 if( pNode->bEof==0
174266 && pNode->iRowid==pExpr->pRoot->iRowid
174267 && pPhrase->poslist.n>0
174268 ){
174269 Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
174270 if( pTerm->pSynonym ){
174271 int bDel = 0;
174272 u8 *a;
174273 rc = fts5ExprSynonymList(
174274 pTerm, 1, 0, pNode->iRowid, &bDel, &a, pnCollist
174275 );
174276 if( bDel ){
174277 sqlite3Fts5BufferSet(&rc, &pPhrase->poslist, *pnCollist, a);
174278 *ppCollist = pPhrase->poslist.p;
174279 sqlite3_free(a);
174280 }else{
174281 *ppCollist = a;
174282 }
174283 }else{
174284 sqlite3Fts5IterCollist(pPhrase->aTerm[0].pIter, ppCollist, pnCollist);
174285 }
174286 }else{
174287 *ppCollist = 0;
174288 *pnCollist = 0;
174289 }
174290
174291 return rc;
174292 }
174293
174294
174295 /*
174296 ** 2014 August 11
174297 **
174298 ** The author disclaims copyright to this source code. In place of
@@ -173570,10 +174318,11 @@
174318 ** segment.
174319 */
174320
174321
174322 struct Fts5Hash {
174323 int eDetail; /* Copy of Fts5Config.eDetail */
174324 int *pnByte; /* Pointer to bytes counter */
174325 int nEntry; /* Number of entries currently in hash */
174326 int nSlot; /* Size of aSlot[] array */
174327 Fts5HashEntry *pScan; /* Current ordered scan item */
174328 Fts5HashEntry **aSlot; /* Array of hash slots */
@@ -173606,10 +174355,11 @@
174355
174356 int nAlloc; /* Total size of allocation */
174357 int iSzPoslist; /* Offset of space for 4-byte poslist size */
174358 int nData; /* Total bytes of data (incl. structure) */
174359 u8 bDel; /* Set delete-flag @ iSzPoslist */
174360 u8 bContent; /* Set content-flag (detail=none mode) */
174361
174362 int iCol; /* Column of last value written */
174363 int iPos; /* Position of last value written */
174364 i64 iRowid; /* Rowid of last value written */
174365 char zKey[8]; /* Nul-terminated entry key */
@@ -173623,11 +174373,11 @@
174373
174374
174375 /*
174376 ** Allocate a new hash table.
174377 */
174378 static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
174379 int rc = SQLITE_OK;
174380 Fts5Hash *pNew;
174381
174382 *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
174383 if( pNew==0 ){
@@ -173634,10 +174384,11 @@
174384 rc = SQLITE_NOMEM;
174385 }else{
174386 int nByte;
174387 memset(pNew, 0, sizeof(Fts5Hash));
174388 pNew->pnByte = pnByte;
174389 pNew->eDetail = pConfig->eDetail;
174390
174391 pNew->nSlot = 1024;
174392 nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
174393 pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
174394 if( pNew->aSlot==0 ){
@@ -173726,30 +174477,50 @@
174477 pHash->nSlot = nNew;
174478 pHash->aSlot = apNew;
174479 return SQLITE_OK;
174480 }
174481
174482 static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
174483 if( p->iSzPoslist ){
174484 u8 *pPtr = (u8*)p;
174485 if( pHash->eDetail==FTS5_DETAIL_NONE ){
174486 assert( p->nData==p->iSzPoslist );
174487 if( p->bDel ){
174488 pPtr[p->nData++] = 0x00;
174489 if( p->bContent ){
174490 pPtr[p->nData++] = 0x00;
174491 }
174492 }
174493 }else{
174494 int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
174495 int nPos = nSz*2 + p->bDel; /* Value of nPos field */
174496
174497 assert( p->bDel==0 || p->bDel==1 );
174498 if( nPos<=127 ){
174499 pPtr[p->iSzPoslist] = (u8)nPos;
174500 }else{
174501 int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
174502 memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
174503 sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
174504 p->nData += (nByte-1);
174505 }
174506 }
174507
174508 p->iSzPoslist = 0;
174509 p->bDel = 0;
174510 p->bContent = 0;
174511 }
174512 }
174513
174514 /*
174515 ** Add an entry to the in-memory hash table. The key is the concatenation
174516 ** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos).
174517 **
174518 ** (bByte || pToken) -> (iRowid,iCol,iPos)
174519 **
174520 ** Or, if iCol is negative, then the value is a delete marker.
174521 */
174522 static int sqlite3Fts5HashWrite(
174523 Fts5Hash *pHash,
174524 i64 iRowid, /* Rowid for this entry */
174525 int iCol, /* Column token appears in (-ve -> delete) */
174526 int iPos, /* Position of token within column */
@@ -173758,10 +174529,13 @@
174529 ){
174530 unsigned int iHash;
174531 Fts5HashEntry *p;
174532 u8 *pPtr;
174533 int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */
174534 int bNew; /* If non-delete entry should be written */
174535
174536 bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
174537
174538 /* Attempt to locate an existing hash entry */
174539 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
174540 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
174541 if( p->zKey[0]==bByte
@@ -173772,92 +174546,120 @@
174546 }
174547 }
174548
174549 /* If an existing hash entry cannot be found, create a new one. */
174550 if( p==0 ){
174551 /* Figure out how much space to allocate */
174552 int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
174553 if( nByte<128 ) nByte = 128;
174554
174555 /* Grow the Fts5Hash.aSlot[] array if necessary. */
174556 if( (pHash->nEntry*2)>=pHash->nSlot ){
174557 int rc = fts5HashResize(pHash);
174558 if( rc!=SQLITE_OK ) return rc;
174559 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
174560 }
174561
174562 /* Allocate new Fts5HashEntry and add it to the hash table. */
174563 p = (Fts5HashEntry*)sqlite3_malloc(nByte);
174564 if( !p ) return SQLITE_NOMEM;
174565 memset(p, 0, FTS5_HASHENTRYSIZE);
174566 p->nAlloc = nByte;
174567 p->zKey[0] = bByte;
174568 memcpy(&p->zKey[1], pToken, nToken);
174569 assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
174570 p->zKey[nToken+1] = '\0';
174571 p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
 
 
 
 
174572 p->pHashNext = pHash->aSlot[iHash];
174573 pHash->aSlot[iHash] = p;
174574 pHash->nEntry++;
174575
174576 /* Add the first rowid field to the hash-entry */
174577 p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
174578 p->iRowid = iRowid;
174579
174580 p->iSzPoslist = p->nData;
174581 if( pHash->eDetail!=FTS5_DETAIL_NONE ){
174582 p->nData += 1;
174583 p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
174584 }
174585
174586 nIncr += p->nData;
174587 }else{
174588
174589 /* Appending to an existing hash-entry. Check that there is enough
174590 ** space to append the largest possible new entry. Worst case scenario
174591 ** is:
174592 **
174593 ** + 9 bytes for a new rowid,
174594 ** + 4 byte reserved for the "poslist size" varint.
174595 ** + 1 byte for a "new column" byte,
174596 ** + 3 bytes for a new column number (16-bit max) as a varint,
174597 ** + 5 bytes for the new position offset (32-bit max).
174598 */
174599 if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
174600 int nNew = p->nAlloc * 2;
174601 Fts5HashEntry *pNew;
174602 Fts5HashEntry **pp;
174603 pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
174604 if( pNew==0 ) return SQLITE_NOMEM;
174605 pNew->nAlloc = nNew;
174606 for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
174607 *pp = pNew;
174608 p = pNew;
174609 }
174610 nIncr -= p->nData;
174611 }
174612 assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) );
174613
174614 pPtr = (u8*)p;
174615
174616 /* If this is a new rowid, append the 4-byte size field for the previous
174617 ** entry, and the new rowid for this entry. */
174618 if( iRowid!=p->iRowid ){
174619 fts5HashAddPoslistSize(pHash, p);
174620 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
174621 p->iRowid = iRowid;
174622 bNew = 1;
174623 p->iSzPoslist = p->nData;
174624 if( pHash->eDetail!=FTS5_DETAIL_NONE ){
174625 p->nData += 1;
174626 p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
174627 p->iPos = 0;
174628 }
174629 }
174630
174631 if( iCol>=0 ){
174632 if( pHash->eDetail==FTS5_DETAIL_NONE ){
174633 p->bContent = 1;
174634 }else{
174635 /* Append a new column value, if necessary */
174636 assert( iCol>=p->iCol );
174637 if( iCol!=p->iCol ){
174638 if( pHash->eDetail==FTS5_DETAIL_FULL ){
174639 pPtr[p->nData++] = 0x01;
174640 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
174641 p->iCol = iCol;
174642 p->iPos = 0;
174643 }else{
174644 bNew = 1;
174645 p->iCol = iPos = iCol;
174646 }
174647 }
174648
174649 /* Append the new position offset, if necessary */
174650 if( bNew ){
174651 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
174652 p->iPos = iPos;
174653 }
174654 }
174655 }else{
174656 /* This is a delete. Set the delete flag. */
174657 p->bDel = 1;
174658 }
174659
174660 nIncr += p->nData;
 
174661 *pHash->pnByte += nIncr;
174662 return SQLITE_OK;
174663 }
174664
174665
@@ -173967,11 +174769,11 @@
174769 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
174770 if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
174771 }
174772
174773 if( p ){
174774 fts5HashAddPoslistSize(pHash, p);
174775 *ppDoclist = (const u8*)&p->zKey[nTerm+1];
174776 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
174777 }else{
174778 *ppDoclist = 0;
174779 *pnDoclist = 0;
@@ -174003,11 +174805,11 @@
174805 int *pnDoclist /* OUT: size of doclist in bytes */
174806 ){
174807 Fts5HashEntry *p;
174808 if( (p = pHash->pScan) ){
174809 int nTerm = (int)strlen(p->zKey);
174810 fts5HashAddPoslistSize(pHash, p);
174811 *pzTerm = p->zKey;
174812 *ppDoclist = (const u8*)&p->zKey[nTerm+1];
174813 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
174814 }else{
174815 *pzTerm = 0;
@@ -174450,10 +175252,13 @@
175252 int iLeafPgno; /* Current leaf page number */
175253 Fts5Data *pLeaf; /* Current leaf data */
175254 Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
175255 int iLeafOffset; /* Byte offset within current leaf */
175256
175257 /* Next method */
175258 void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
175259
175260 /* The page and offset from which the current term was read. The offset
175261 ** is the offset of the first rowid in the current doclist. */
175262 int iTermLeafPgno;
175263 int iTermLeafOffset;
175264
@@ -174469,11 +175274,11 @@
175274
175275 /* Variables populated based on current entry. */
175276 Fts5Buffer term; /* Current term */
175277 i64 iRowid; /* Current rowid */
175278 int nPos; /* Number of bytes in current position list */
175279 u8 bDel; /* True if the delete flag is set */
175280 };
175281
175282 /*
175283 ** Argument is a pointer to an Fts5Data structure that contains a
175284 ** leaf page.
@@ -174482,11 +175287,10 @@
175287 (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
175288 )
175289
175290 #define FTS5_SEGITER_ONETERM 0x01
175291 #define FTS5_SEGITER_REVERSE 0x02
 
175292
175293 /*
175294 ** Argument is a pointer to an Fts5Data structure that contains a leaf
175295 ** page. This macro evaluates to true if the leaf contains no terms, or
175296 ** false if it contains at least one term.
@@ -175509,17 +176313,33 @@
176313 ** position list content (if any).
176314 */
176315 static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
176316 if( p->rc==SQLITE_OK ){
176317 int iOff = pIter->iLeafOffset; /* Offset to read at */
 
176318 ASSERT_SZLEAF_OK(pIter->pLeaf);
176319 if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
176320 int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf);
176321 pIter->bDel = 0;
176322 pIter->nPos = 1;
176323 if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
176324 pIter->bDel = 1;
176325 iOff++;
176326 if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
176327 pIter->nPos = 1;
176328 iOff++;
176329 }else{
176330 pIter->nPos = 0;
176331 }
176332 }
176333 }else{
176334 int nSz;
176335 fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
176336 pIter->bDel = (nSz & 0x0001);
176337 pIter->nPos = nSz>>1;
176338 assert_nc( pIter->nPos>=0 );
176339 }
176340 pIter->iLeafOffset = iOff;
 
176341 }
176342 }
176343
176344 static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
176345 u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
@@ -175575,10 +176395,24 @@
176395 pIter->iEndofDoclist += nExtra;
176396 }
176397
176398 fts5SegIterLoadRowid(p, pIter);
176399 }
176400
176401 static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*);
176402 static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*);
176403 static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*);
176404
176405 static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
176406 if( pIter->flags & FTS5_SEGITER_REVERSE ){
176407 pIter->xNext = fts5SegIterNext_Reverse;
176408 }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
176409 pIter->xNext = fts5SegIterNext_None;
176410 }else{
176411 pIter->xNext = fts5SegIterNext;
176412 }
176413 }
176414
176415 /*
176416 ** Initialize the iterator object pIter to iterate through the entries in
176417 ** segment pSeg. The iterator is left pointing to the first entry when
176418 ** this function returns.
@@ -175601,10 +176435,11 @@
176435 return;
176436 }
176437
176438 if( p->rc==SQLITE_OK ){
176439 memset(pIter, 0, sizeof(*pIter));
176440 fts5SegIterSetNext(p, pIter);
176441 pIter->pSeg = pSeg;
176442 pIter->iLeafPgno = pSeg->pgnoFirst-1;
176443 fts5SegIterNextPage(p, pIter);
176444 }
176445
@@ -175632,10 +176467,11 @@
176467 ** aRowidOffset[] and iRowidOffset variables. At this point the iterator
176468 ** is in its regular state - Fts5SegIter.iLeafOffset points to the first
176469 ** byte of the position list content associated with said rowid.
176470 */
176471 static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
176472 int eDetail = p->pConfig->eDetail;
176473 int n = pIter->pLeaf->szLeaf;
176474 int i = pIter->iLeafOffset;
176475 u8 *a = pIter->pLeaf->p;
176476 int iRowidOffset = 0;
176477
@@ -175644,19 +176480,28 @@
176480 }
176481
176482 ASSERT_SZLEAF_OK(pIter->pLeaf);
176483 while( 1 ){
176484 i64 iDelta = 0;
 
 
176485
176486 if( eDetail==FTS5_DETAIL_NONE ){
176487 /* todo */
176488 if( i<n && a[i]==0 ){
176489 i++;
176490 if( i<n && a[i]==0 ) i++;
176491 }
176492 }else{
176493 int nPos;
176494 int bDummy;
176495 i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
176496 i += nPos;
176497 }
176498 if( i>=n ) break;
176499 i += fts5GetVarint(&a[i], (u64*)&iDelta);
176500 pIter->iRowid += iDelta;
176501
176502 /* If necessary, grow the pIter->aRowidOffset[] array. */
176503 if( iRowidOffset>=pIter->nRowidOffset ){
176504 int nNew = pIter->nRowidOffset + 8;
176505 int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
176506 if( aNew==0 ){
176507 p->rc = SQLITE_NOMEM;
@@ -175730,10 +176575,112 @@
176575 */
176576 static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){
176577 Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
176578 return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
176579 }
176580
176581 /*
176582 ** Advance iterator pIter to the next entry.
176583 **
176584 ** This version of fts5SegIterNext() is only used by reverse iterators.
176585 */
176586 static void fts5SegIterNext_Reverse(
176587 Fts5Index *p, /* FTS5 backend object */
176588 Fts5SegIter *pIter, /* Iterator to advance */
176589 int *pbNewTerm /* OUT: Set for new term */
176590 ){
176591 assert( pIter->flags & FTS5_SEGITER_REVERSE );
176592 assert( pIter->pNextLeaf==0 );
176593 if( pIter->iRowidOffset>0 ){
176594 u8 *a = pIter->pLeaf->p;
176595 int iOff;
176596 i64 iDelta;
176597
176598 pIter->iRowidOffset--;
176599 pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
176600 fts5SegIterLoadNPos(p, pIter);
176601 iOff = pIter->iLeafOffset;
176602 if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
176603 iOff += pIter->nPos;
176604 }
176605 fts5GetVarint(&a[iOff], (u64*)&iDelta);
176606 pIter->iRowid -= iDelta;
176607 }else{
176608 fts5SegIterReverseNewPage(p, pIter);
176609 }
176610 }
176611
176612 /*
176613 ** Advance iterator pIter to the next entry.
176614 **
176615 ** This version of fts5SegIterNext() is only used if detail=none and the
176616 ** iterator is not a reverse direction iterator.
176617 */
176618 static void fts5SegIterNext_None(
176619 Fts5Index *p, /* FTS5 backend object */
176620 Fts5SegIter *pIter, /* Iterator to advance */
176621 int *pbNewTerm /* OUT: Set for new term */
176622 ){
176623 int iOff;
176624
176625 assert( p->rc==SQLITE_OK );
176626 assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 );
176627 assert( p->pConfig->eDetail==FTS5_DETAIL_NONE );
176628
176629 ASSERT_SZLEAF_OK(pIter->pLeaf);
176630 iOff = pIter->iLeafOffset;
176631
176632 /* Next entry is on the next page */
176633 if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
176634 fts5SegIterNextPage(p, pIter);
176635 if( p->rc || pIter->pLeaf==0 ) return;
176636 pIter->iRowid = 0;
176637 iOff = 4;
176638 }
176639
176640 if( iOff<pIter->iEndofDoclist ){
176641 /* Next entry is on the current page */
176642 i64 iDelta;
176643 iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
176644 pIter->iLeafOffset = iOff;
176645 pIter->iRowid += iDelta;
176646 }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
176647 if( pIter->pSeg ){
176648 int nKeep = 0;
176649 if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){
176650 iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep);
176651 }
176652 pIter->iLeafOffset = iOff;
176653 fts5SegIterLoadTerm(p, pIter, nKeep);
176654 }else{
176655 const u8 *pList = 0;
176656 const char *zTerm = 0;
176657 int nList;
176658 sqlite3Fts5HashScanNext(p->pHash);
176659 sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
176660 if( pList==0 ) goto next_none_eof;
176661 pIter->pLeaf->p = (u8*)pList;
176662 pIter->pLeaf->nn = nList;
176663 pIter->pLeaf->szLeaf = nList;
176664 pIter->iEndofDoclist = nList;
176665 sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
176666 pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
176667 }
176668
176669 if( pbNewTerm ) *pbNewTerm = 1;
176670 }else{
176671 goto next_none_eof;
176672 }
176673
176674 fts5SegIterLoadNPos(p, pIter);
176675
176676 return;
176677 next_none_eof:
176678 fts5DataRelease(pIter->pLeaf);
176679 pIter->pLeaf = 0;
176680 }
176681
176682
176683 /*
176684 ** Advance iterator pIter to the next entry.
176685 **
176686 ** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
@@ -175743,144 +176690,135 @@
176690 static void fts5SegIterNext(
176691 Fts5Index *p, /* FTS5 backend object */
176692 Fts5SegIter *pIter, /* Iterator to advance */
176693 int *pbNewTerm /* OUT: Set for new term */
176694 ){
176695 Fts5Data *pLeaf = pIter->pLeaf;
176696 int iOff;
176697 int bNewTerm = 0;
176698 int nKeep = 0;
176699 u8 *a;
176700 int n;
176701
176702 assert( pbNewTerm==0 || *pbNewTerm==0 );
176703 assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
176704
176705 /* Search for the end of the position list within the current page. */
176706 a = pLeaf->p;
176707 n = pLeaf->szLeaf;
176708
176709 ASSERT_SZLEAF_OK(pLeaf);
176710 iOff = pIter->iLeafOffset + pIter->nPos;
176711
176712 if( iOff<n ){
176713 /* The next entry is on the current page. */
176714 assert_nc( iOff<=pIter->iEndofDoclist );
176715 if( iOff>=pIter->iEndofDoclist ){
176716 bNewTerm = 1;
176717 if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
176718 iOff += fts5GetVarint32(&a[iOff], nKeep);
176719 }
176720 }else{
176721 u64 iDelta;
176722 iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
176723 pIter->iRowid += iDelta;
176724 assert_nc( iDelta>0 );
176725 }
176726 pIter->iLeafOffset = iOff;
176727
176728 }else if( pIter->pSeg==0 ){
176729 const u8 *pList = 0;
176730 const char *zTerm = 0;
176731 int nList = 0;
176732 assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
176733 if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
176734 sqlite3Fts5HashScanNext(p->pHash);
176735 sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
176736 }
176737 if( pList==0 ){
176738 fts5DataRelease(pIter->pLeaf);
176739 pIter->pLeaf = 0;
176740 }else{
176741 pIter->pLeaf->p = (u8*)pList;
176742 pIter->pLeaf->nn = nList;
176743 pIter->pLeaf->szLeaf = nList;
176744 pIter->iEndofDoclist = nList+1;
176745 sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
176746 (u8*)zTerm);
176747 pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
176748 *pbNewTerm = 1;
176749 }
176750 }else{
176751 iOff = 0;
176752 /* Next entry is not on the current page */
176753 while( iOff==0 ){
176754 fts5SegIterNextPage(p, pIter);
176755 pLeaf = pIter->pLeaf;
176756 if( pLeaf==0 ) break;
176757 ASSERT_SZLEAF_OK(pLeaf);
176758 if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
176759 iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
176760 pIter->iLeafOffset = iOff;
176761
176762 if( pLeaf->nn>pLeaf->szLeaf ){
176763 pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
176764 &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
176765 );
176766 }
176767
176768 }
176769 else if( pLeaf->nn>pLeaf->szLeaf ){
176770 pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
176771 &pLeaf->p[pLeaf->szLeaf], iOff
176772 );
176773 pIter->iLeafOffset = iOff;
176774 pIter->iEndofDoclist = iOff;
176775 bNewTerm = 1;
176776 }
176777 assert_nc( iOff<pLeaf->szLeaf );
176778 if( iOff>pLeaf->szLeaf ){
176779 p->rc = FTS5_CORRUPT;
176780 return;
176781 }
176782 }
176783 }
176784
176785 /* Check if the iterator is now at EOF. If so, return early. */
176786 if( pIter->pLeaf ){
176787 if( bNewTerm ){
176788 if( pIter->flags & FTS5_SEGITER_ONETERM ){
176789 fts5DataRelease(pIter->pLeaf);
176790 pIter->pLeaf = 0;
176791 }else{
176792 fts5SegIterLoadTerm(p, pIter, nKeep);
176793 fts5SegIterLoadNPos(p, pIter);
176794 if( pbNewTerm ) *pbNewTerm = 1;
176795 }
176796 }else{
176797 /* The following could be done by calling fts5SegIterLoadNPos(). But
176798 ** this block is particularly performance critical, so equivalent
176799 ** code is inlined.
176800 **
176801 ** Later: Switched back to fts5SegIterLoadNPos() because it supports
176802 ** detail=none mode. Not ideal.
176803 */
176804 int nSz;
176805 assert( p->rc==SQLITE_OK );
176806 fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
176807 pIter->bDel = (nSz & 0x0001);
176808 pIter->nPos = nSz>>1;
176809 assert_nc( pIter->nPos>=0 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176810 }
176811 }
176812 }
176813
176814 #define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
176815
176816 #define fts5IndexSkipVarint(a, iOff) { \
176817 int iEnd = iOff+9; \
176818 while( (a[iOff++] & 0x80) && iOff<iEnd ); \
176819 }
176820
176821 /*
176822 ** Iterator pIter currently points to the first rowid in a doclist. This
176823 ** function sets the iterator up so that iterates in reverse order through
176824 ** the doclist.
@@ -175898,11 +176836,21 @@
176836 Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
176837
176838 /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
176839 ** position-list content for the current rowid. Back it up so that it
176840 ** points to the start of the position-list size field. */
176841 int iPoslist;
176842 if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
176843 iPoslist = pIter->iTermLeafOffset;
176844 }else{
176845 iPoslist = 4;
176846 }
176847 fts5IndexSkipVarint(pLeaf->p, iPoslist);
176848 assert( p->pConfig->eDetail==FTS5_DETAIL_NONE || iPoslist==(
176849 pIter->iLeafOffset - sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel)
176850 ));
176851 pIter->iLeafOffset = iPoslist;
176852
176853 /* If this condition is true then the largest rowid for the current
176854 ** term may not be stored on the current page. So search forward to
176855 ** see where said rowid really is. */
176856 if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
@@ -175982,15 +176930,10 @@
176930 }
176931
176932 pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
176933 }
176934
 
 
 
 
 
176935 /*
176936 ** The iterator object passed as the second argument currently contains
176937 ** no valid values except for the Fts5SegIter.pLeaf member variable. This
176938 ** function searches the leaf page for a term matching (pTerm/nTerm).
176939 **
@@ -176189,10 +177132,12 @@
177132 fts5SegIterReverse(p, pIter);
177133 }
177134 }
177135 }
177136
177137 fts5SegIterSetNext(p, pIter);
177138
177139 /* Either:
177140 **
177141 ** 1) an error has occurred, or
177142 ** 2) the iterator points to EOF, or
177143 ** 3) the iterator points to an entry with term (pTerm/nTerm), or
@@ -176246,19 +177191,21 @@
177191 if( pLeaf==0 ) return;
177192 pLeaf->p = (u8*)pList;
177193 pLeaf->nn = pLeaf->szLeaf = nList;
177194 pIter->pLeaf = pLeaf;
177195 pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
177196 pIter->iEndofDoclist = pLeaf->nn;
177197
177198 if( flags & FTS5INDEX_QUERY_DESC ){
177199 pIter->flags |= FTS5_SEGITER_REVERSE;
177200 fts5SegIterReverseInitPage(p, pIter);
177201 }else{
177202 fts5SegIterLoadNPos(p, pIter);
177203 }
177204 }
177205
177206 fts5SegIterSetNext(p, pIter);
177207 }
177208
177209 /*
177210 ** Zero the iterator passed as the only argument.
177211 */
@@ -176498,11 +177445,11 @@
177445 bMove = 0;
177446 }
177447 }
177448
177449 do{
177450 if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0);
177451 if( pIter->pLeaf==0 ) break;
177452 if( bRev==0 && pIter->iRowid>=iMatch ) break;
177453 if( bRev!=0 && pIter->iRowid<=iMatch ) break;
177454 bMove = 1;
177455 }while( p->rc==SQLITE_OK );
@@ -176532,11 +177479,13 @@
177479 ){
177480 int i;
177481 for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
177482 int iEq;
177483 if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
177484 Fts5SegIter *pSeg = &pIter->aSeg[iEq];
177485 assert( p->rc==SQLITE_OK );
177486 pSeg->xNext(p, pSeg, 0);
177487 i = pIter->nSeg + iEq;
177488 }
177489 }
177490 }
177491
@@ -176619,11 +177568,11 @@
177568 Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
177569 assert( p->rc==SQLITE_OK );
177570 if( bUseFrom && pSeg->pDlidx ){
177571 fts5SegIterNextFrom(p, pSeg, iFrom);
177572 }else{
177573 pSeg->xNext(p, pSeg, &bNewTerm);
177574 }
177575
177576 if( pSeg->pLeaf==0 || bNewTerm
177577 || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
177578 ){
@@ -176647,11 +177596,12 @@
177596 do {
177597 int iFirst = pIter->aFirst[1].iFirst;
177598 Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
177599 int bNewTerm = 0;
177600
177601 assert( p->rc==SQLITE_OK );
177602 pSeg->xNext(p, pSeg, &bNewTerm);
177603 if( pSeg->pLeaf==0 || bNewTerm
177604 || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
177605 ){
177606 fts5MultiIterAdvanced(p, pIter, iFirst, 1);
177607 fts5MultiIterSetEof(pIter);
@@ -176767,11 +177717,12 @@
177717 ** object and set the output variable to NULL. */
177718 if( p->rc==SQLITE_OK ){
177719 for(iIter=pNew->nSeg-1; iIter>0; iIter--){
177720 int iEq;
177721 if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
177722 Fts5SegIter *pSeg = &pNew->aSeg[iEq];
177723 if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
177724 fts5MultiIterAdvanced(p, pNew, iEq, iIter);
177725 }
177726 }
177727 fts5MultiIterSetEof(pNew);
177728 fts5AssertMultiIterSetup(p, pNew);
@@ -176817,10 +177768,11 @@
177768 }
177769 pData = 0;
177770 }else{
177771 pNew->bEof = 1;
177772 }
177773 fts5SegIterSetNext(p, pIter);
177774
177775 *ppOut = pNew;
177776 }
177777
177778 fts5DataRelease(pData);
@@ -176885,10 +177837,13 @@
177837 Fts5Data *pData = 0;
177838 u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
177839 int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
177840 int pgno = pSeg->iLeafPgno;
177841 int pgnoSave = 0;
177842
177843 /* This function does notmwork with detail=none databases. */
177844 assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
177845
177846 if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
177847 pgnoSave = pgno+1;
177848 }
177849
@@ -177309,12 +178264,11 @@
178264 ** Append a rowid and position-list size field to the writers output.
178265 */
178266 static void fts5WriteAppendRowid(
178267 Fts5Index *p,
178268 Fts5SegWriter *pWriter,
178269 i64 iRowid
 
178270 ){
178271 if( p->rc==SQLITE_OK ){
178272 Fts5PageWriter *pPage = &pWriter->writer;
178273
178274 if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){
@@ -177337,12 +178291,10 @@
178291 fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
178292 }
178293 pWriter->iPrevRowid = iRowid;
178294 pWriter->bFirstRowidInDoclist = 0;
178295 pWriter->bFirstRowidInPage = 0;
 
 
178296 }
178297 }
178298
178299 static void fts5WriteAppendPoslistData(
178300 Fts5Index *p,
@@ -177534,10 +178486,11 @@
178486 int nInput; /* Number of input segments */
178487 Fts5SegWriter writer; /* Writer object */
178488 Fts5StructureSegment *pSeg; /* Output segment */
178489 Fts5Buffer term;
178490 int bOldest; /* True if the output segment is the oldest */
178491 int eDetail = p->pConfig->eDetail;
178492
178493 assert( iLvl<pStruct->nLevel );
178494 assert( pLvl->nMerge<=pLvl->nSeg );
178495
178496 memset(&writer, 0, sizeof(Fts5SegWriter));
@@ -177603,15 +178556,25 @@
178556 fts5BufferSet(&p->rc, &term, nTerm, pTerm);
178557 }
178558
178559 /* Append the rowid to the output */
178560 /* WRITEPOSLISTSIZE */
178561 fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter));
 
178562
178563 if( eDetail==FTS5_DETAIL_NONE ){
178564 if( pSegIter->bDel ){
178565 fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
178566 if( pSegIter->nPos>0 ){
178567 fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
178568 }
178569 }
178570 }else{
178571 /* Append the position-list data to the output */
178572 nPos = pSegIter->nPos*2 + pSegIter->bDel;
178573 fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos);
178574 fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
178575 }
178576 }
178577
178578 /* Flush the last leaf page to disk. Set the output segment b-tree height
178579 ** and last leaf page number at the same time. */
178580 fts5WriteFinish(p, &writer, &pSeg->pgnoLast);
@@ -177795,11 +178758,11 @@
178758 pStruct = fts5StructureRead(p);
178759 iSegid = fts5AllocateSegid(p, pStruct);
178760
178761 if( iSegid ){
178762 const int pgsz = p->pConfig->pgsz;
178763 int eDetail = p->pConfig->eDetail;
178764 Fts5StructureSegment *pSeg; /* New segment within pStruct */
178765 Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
178766 Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
178767
178768 Fts5SegWriter writer;
@@ -177838,16 +178801,11 @@
178801
178802 /* The entire doclist will not fit on this leaf. The following
178803 ** loop iterates through the poslists that make up the current
178804 ** doclist. */
178805 while( p->rc==SQLITE_OK && iOff<nDoclist ){
 
 
 
178806 iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
 
 
178807 iRowid += iDelta;
178808
178809 if( writer.bFirstRowidInPage ){
178810 fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
178811 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
@@ -177856,38 +178814,56 @@
178814 }else{
178815 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
178816 }
178817 assert( pBuf->n<=pBuf->nSpace );
178818
178819 if( eDetail==FTS5_DETAIL_NONE ){
178820 if( iOff<nDoclist && pDoclist[iOff]==0 ){
178821 pBuf->p[pBuf->n++] = 0;
178822 iOff++;
178823 if( iOff<nDoclist && pDoclist[iOff]==0 ){
178824 pBuf->p[pBuf->n++] = 0;
178825 iOff++;
178826 }
178827 }
178828 if( (pBuf->n + pPgidx->n)>=pgsz ){
178829 fts5WriteFlushLeaf(p, &writer);
178830 }
178831 }else{
178832 int bDummy;
178833 int nPos;
178834 int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
178835 nCopy += nPos;
178836 if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
178837 /* The entire poslist will fit on the current leaf. So copy
178838 ** it in one go. */
178839 fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
178840 }else{
178841 /* The entire poslist will not fit on this leaf. So it needs
178842 ** to be broken into sections. The only qualification being
178843 ** that each varint must be stored contiguously. */
178844 const u8 *pPoslist = &pDoclist[iOff];
178845 int iPos = 0;
178846 while( p->rc==SQLITE_OK ){
178847 int nSpace = pgsz - pBuf->n - pPgidx->n;
178848 int n = 0;
178849 if( (nCopy - iPos)<=nSpace ){
178850 n = nCopy - iPos;
178851 }else{
178852 n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
178853 }
178854 assert( n>0 );
178855 fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
178856 iPos += n;
178857 if( (pBuf->n + pPgidx->n)>=pgsz ){
178858 fts5WriteFlushLeaf(p, &writer);
178859 }
178860 if( iPos>=nCopy ) break;
178861 }
178862 }
178863 iOff += nCopy;
178864 }
178865 }
178866 }
178867
178868 /* TODO2: Doclist terminator written here. */
178869 /* pBuf->p[pBuf->n++] = '\0'; */
@@ -178018,10 +178994,18 @@
178994 Fts5Buffer *pBuf; /* Append to this buffer */
178995 Fts5Colset *pColset; /* Restrict matches to this column */
178996 int eState; /* See above */
178997 };
178998
178999 typedef struct PoslistOffsetsCtx PoslistOffsetsCtx;
179000 struct PoslistOffsetsCtx {
179001 Fts5Buffer *pBuf; /* Append to this buffer */
179002 Fts5Colset *pColset; /* Restrict matches to this column */
179003 int iRead;
179004 int iWrite;
179005 };
179006
179007 /*
179008 ** TODO: Make this more efficient!
179009 */
179010 static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
179011 int i;
@@ -178028,10 +179012,32 @@
179012 for(i=0; i<pColset->nCol; i++){
179013 if( pColset->aiCol[i]==iCol ) return 1;
179014 }
179015 return 0;
179016 }
179017
179018 static void fts5PoslistOffsetsCallback(
179019 Fts5Index *p,
179020 void *pContext,
179021 const u8 *pChunk, int nChunk
179022 ){
179023 PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
179024 assert_nc( nChunk>=0 );
179025 if( nChunk>0 ){
179026 int i = 0;
179027 while( i<nChunk ){
179028 int iVal;
179029 i += fts5GetVarint32(&pChunk[i], iVal);
179030 iVal += pCtx->iRead - 2;
179031 pCtx->iRead = iVal;
179032 if( fts5IndexColsetTest(pCtx->pColset, iVal) ){
179033 fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite);
179034 pCtx->iWrite = iVal;
179035 }
179036 }
179037 }
179038 }
179039
179040 static void fts5PoslistFilterCallback(
179041 Fts5Index *p,
179042 void *pContext,
179043 const u8 *pChunk, int nChunk
@@ -178096,16 +179102,24 @@
179102 ){
179103 if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
179104 if( pColset==0 ){
179105 fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
179106 }else{
179107 if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
179108 PoslistCallbackCtx sCtx;
179109 sCtx.pBuf = pBuf;
179110 sCtx.pColset = pColset;
179111 sCtx.eState = fts5IndexColsetTest(pColset, 0);
179112 assert( sCtx.eState==0 || sCtx.eState==1 );
179113 fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
179114 }else{
179115 PoslistOffsetsCtx sCtx;
179116 memset(&sCtx, 0, sizeof(sCtx));
179117 sCtx.pBuf = pBuf;
179118 sCtx.pColset = pColset;
179119 fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback);
179120 }
179121 }
179122 }
179123 }
179124
179125 /*
@@ -178144,10 +179158,20 @@
179158 prev = *p++;
179159 }
179160 return p - (*pa);
179161 }
179162
179163 static int fts5AppendRowid(
179164 Fts5Index *p,
179165 i64 iDelta,
179166 Fts5IndexIter *pMulti,
179167 Fts5Colset *pColset,
179168 Fts5Buffer *pBuf
179169 ){
179170 fts5BufferAppendVarint(&p->rc, pBuf, iDelta);
179171 return 0;
179172 }
179173
179174 /*
179175 ** Iterator pMulti currently points to a valid entry (not EOF). This
179176 ** function appends the following to buffer pBuf:
179177 **
@@ -178171,12 +179195,12 @@
179195 if( p->rc==SQLITE_OK ){
179196 Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
179197 assert( fts5MultiIterEof(p, pMulti)==0 );
179198 assert( pSeg->nPos>0 );
179199 if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
179200 if( p->pConfig->eDetail==FTS5_DETAIL_FULL
179201 && pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
179202 && (pColset==0 || pColset->nCol==1)
179203 ){
179204 const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
179205 int nPos;
179206 if( pColset ){
@@ -178217,16 +179241,16 @@
179241 sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
179242 }
179243 }
179244 }
179245 }
 
179246 }
179247 }
179248
179249 return 0;
179250 }
179251
179252
179253 static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
179254 u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
179255
179256 assert( pIter->aPoslist );
@@ -178283,10 +179307,73 @@
179307 #define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
179308 assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
179309 fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
179310 (iLastRowid) = (iRowid); \
179311 }
179312
179313 /*
179314 ** Swap the contents of buffer *p1 with that of *p2.
179315 */
179316 static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
179317 Fts5Buffer tmp = *p1;
179318 *p1 = *p2;
179319 *p2 = tmp;
179320 }
179321
179322 static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
179323 int i = *piOff;
179324 if( i>=pBuf->n ){
179325 *piOff = -1;
179326 }else{
179327 u64 iVal;
179328 *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal);
179329 *piRowid += iVal;
179330 }
179331 }
179332
179333 /*
179334 ** This is the equivalent of fts5MergePrefixLists() for detail=none mode.
179335 ** In this case the buffers consist of a delta-encoded list of rowids only.
179336 */
179337 static void fts5MergeRowidLists(
179338 Fts5Index *p, /* FTS5 backend object */
179339 Fts5Buffer *p1, /* First list to merge */
179340 Fts5Buffer *p2 /* Second list to merge */
179341 ){
179342 int i1 = 0;
179343 int i2 = 0;
179344 i64 iRowid1 = 0;
179345 i64 iRowid2 = 0;
179346 i64 iOut = 0;
179347
179348 Fts5Buffer out;
179349 memset(&out, 0, sizeof(out));
179350 sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
179351 if( p->rc ) return;
179352
179353 fts5NextRowid(p1, &i1, &iRowid1);
179354 fts5NextRowid(p2, &i2, &iRowid2);
179355 while( i1>=0 || i2>=0 ){
179356 if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){
179357 assert( iOut==0 || iRowid1>iOut );
179358 fts5BufferSafeAppendVarint(&out, iRowid1 - iOut);
179359 iOut = iRowid1;
179360 fts5NextRowid(p1, &i1, &iRowid1);
179361 }else{
179362 assert( iOut==0 || iRowid2>iOut );
179363 fts5BufferSafeAppendVarint(&out, iRowid2 - iOut);
179364 iOut = iRowid2;
179365 if( i1>=0 && iRowid1==iRowid2 ){
179366 fts5NextRowid(p1, &i1, &iRowid1);
179367 }
179368 fts5NextRowid(p2, &i2, &iRowid2);
179369 }
179370 }
179371
179372 fts5BufferSwap(&out, p1);
179373 fts5BufferFree(&out);
179374 }
179375
179376 /*
179377 ** Buffers p1 and p2 contain doclists. This function merges the content
179378 ** of the two doclists together and sets buffer p1 to the result before
179379 ** returning.
@@ -178352,11 +179439,13 @@
179439 sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
179440 if( iPos1==iPos2 ){
179441 sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
179442 }
179443 }
179444 if( iNew!=writer.iPrev || tmp.n==0 ){
179445 p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
179446 }
179447 }
179448
179449 /* WRITEPOSLISTSIZE */
179450 fts5BufferSafeAppendVarint(&out, tmp.n * 2);
179451 fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
@@ -178369,16 +179458,10 @@
179458 fts5BufferFree(&tmp);
179459 fts5BufferFree(&out);
179460 }
179461 }
179462
 
 
 
 
 
 
179463 static void fts5SetupPrefixIter(
179464 Fts5Index *p, /* Index to read from */
179465 int bDesc, /* True for "ORDER BY rowid DESC" */
179466 const u8 *pToken, /* Buffer containing prefix to match */
179467 int nToken, /* Size of buffer pToken in bytes */
@@ -178386,10 +179469,20 @@
179469 Fts5IndexIter **ppIter /* OUT: New iterator */
179470 ){
179471 Fts5Structure *pStruct;
179472 Fts5Buffer *aBuf;
179473 const int nBuf = 32;
179474
179475 void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
179476 int (*xAppend)(Fts5Index*, i64, Fts5IndexIter*, Fts5Colset*, Fts5Buffer*);
179477 if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
179478 xMerge = fts5MergeRowidLists;
179479 xAppend = fts5AppendRowid;
179480 }else{
179481 xMerge = fts5MergePrefixLists;
179482 xAppend = fts5AppendPoslist;
179483 }
179484
179485 aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
179486 pStruct = fts5StructureRead(p);
179487
179488 if( aBuf && pStruct ){
@@ -178419,25 +179512,25 @@
179512 assert( i<nBuf );
179513 if( aBuf[i].n==0 ){
179514 fts5BufferSwap(&doclist, &aBuf[i]);
179515 fts5BufferZero(&doclist);
179516 }else{
179517 xMerge(p, &doclist, &aBuf[i]);
179518 fts5BufferZero(&aBuf[i]);
179519 }
179520 }
179521 iLastRowid = 0;
179522 }
179523
179524 if( !xAppend(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
179525 iLastRowid = iRowid;
179526 }
179527 }
179528
179529 for(i=0; i<nBuf; i++){
179530 if( p->rc==SQLITE_OK ){
179531 xMerge(p, &doclist, &aBuf[i]);
179532 }
179533 fts5BufferFree(&aBuf[i]);
179534 }
179535 fts5MultiIterFree(p, p1);
179536
@@ -178463,11 +179556,11 @@
179556 static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
179557 assert( p->rc==SQLITE_OK );
179558
179559 /* Allocate the hash table if it has not already been allocated */
179560 if( p->pHash==0 ){
179561 p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
179562 }
179563
179564 /* Flush the hash table to disk if required */
179565 if( iRowid<p->iWriteRowid
179566 || (iRowid==p->iWriteRowid && p->bDelete==0)
@@ -178584,11 +179677,15 @@
179677 /*
179678 ** Argument p points to a buffer containing utf-8 text that is n bytes in
179679 ** size. Return the number of bytes in the nChar character prefix of the
179680 ** buffer, or 0 if there are less than nChar characters in total.
179681 */
179682 static int sqlite3Fts5IndexCharlenToBytelen(
179683 const char *p,
179684 int nByte,
179685 int nChar
179686 ){
179687 int n = 0;
179688 int i;
179689 for(i=0; i<nChar; i++){
179690 if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
179691 if( (unsigned char)p[n++]>=0xc0 ){
@@ -178641,11 +179738,12 @@
179738 rc = sqlite3Fts5HashWrite(
179739 p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken
179740 );
179741
179742 for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
179743 const int nChar = pConfig->aPrefix[i];
179744 int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
179745 if( nByte ){
179746 rc = sqlite3Fts5HashWrite(p->pHash,
179747 p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
179748 nByte
179749 );
@@ -178819,13 +179917,20 @@
179917 const u8 **pp, /* OUT: Pointer to position-list data */
179918 int *pn, /* OUT: Size of position-list in bytes */
179919 i64 *piRowid /* OUT: Current rowid */
179920 ){
179921 Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
179922 int eDetail = pIter->pIndex->pConfig->eDetail;
179923
179924 assert( pIter->pIndex->rc==SQLITE_OK );
179925 *piRowid = pSeg->iRowid;
179926 if( eDetail==FTS5_DETAIL_NONE ){
179927 *pn = pSeg->nPos;
179928 }else
179929 if( eDetail==FTS5_DETAIL_FULL
179930 && pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
179931 ){
179932 u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
179933 if( pColset==0 || pIter->bFiltered ){
179934 *pn = pSeg->nPos;
179935 *pp = pPos;
179936 }else if( pColset->nCol==1 ){
@@ -178838,15 +179943,28 @@
179943 *pn = pIter->poslist.n;
179944 }
179945 }else{
179946 fts5BufferZero(&pIter->poslist);
179947 fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
179948 if( eDetail==FTS5_DETAIL_FULL ){
179949 *pp = pIter->poslist.p;
179950 }
179951 *pn = pIter->poslist.n;
179952 }
179953 return fts5IndexReturn(pIter->pIndex);
179954 }
179955
179956 static int sqlite3Fts5IterCollist(
179957 Fts5IndexIter *pIter,
179958 const u8 **pp, /* OUT: Pointer to position-list data */
179959 int *pn /* OUT: Size of position-list in bytes */
179960 ){
179961 assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
179962 *pp = pIter->poslist.p;
179963 *pn = pIter->poslist.n;
179964 return SQLITE_OK;
179965 }
179966
179967 /*
179968 ** This function is similar to sqlite3Fts5IterPoslist(), except that it
179969 ** copies the position list into the buffer supplied as the second
179970 ** argument.
@@ -178957,11 +180075,11 @@
180075 */
180076
180077 /*
180078 ** Return a simple checksum value based on the arguments.
180079 */
180080 static u64 sqlite3Fts5IndexEntryCksum(
180081 i64 iRowid,
180082 int iCol,
180083 int iPos,
180084 int iIdx,
180085 const char *pTerm,
@@ -179027,34 +180145,41 @@
180145 const char *z, /* Index key to query for */
180146 int n, /* Size of index key in bytes */
180147 int flags, /* Flags for Fts5IndexQuery */
180148 u64 *pCksum /* IN/OUT: Checksum value */
180149 ){
180150 int eDetail = p->pConfig->eDetail;
180151 u64 cksum = *pCksum;
180152 Fts5IndexIter *pIdxIter = 0;
180153 Fts5Buffer buf = {0, 0, 0};
180154 int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
180155
180156 while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
 
 
 
180157 i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
180158
180159 if( eDetail==FTS5_DETAIL_NONE ){
180160 cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
180161 }else{
180162 rc = sqlite3Fts5IterPoslistBuffer(pIdxIter, &buf);
180163 if( rc==SQLITE_OK ){
180164 Fts5PoslistReader sReader;
180165 for(sqlite3Fts5PoslistReaderInit(buf.p, buf.n, &sReader);
180166 sReader.bEof==0;
180167 sqlite3Fts5PoslistReaderNext(&sReader)
180168 ){
180169 int iCol = FTS5_POS2COLUMN(sReader.iPos);
180170 int iOff = FTS5_POS2OFFSET(sReader.iPos);
180171 cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
180172 }
180173 }
180174 }
180175 if( rc==SQLITE_OK ){
 
 
 
 
 
 
 
 
 
180176 rc = sqlite3Fts5IterNext(pIdxIter);
180177 }
180178 }
180179 sqlite3Fts5IterClose(pIdxIter);
180180 fts5BufferFree(&buf);
180181
180182 *pCksum = cksum;
180183 return rc;
180184 }
180185
@@ -179344,18 +180469,19 @@
180469
180470
180471 /*
180472 ** Run internal checks to ensure that the FTS index (a) is internally
180473 ** consistent and (b) contains entries for which the XOR of the checksums
180474 ** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
180475 **
180476 ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
180477 ** checksum does not match. Return SQLITE_OK if all checks pass without
180478 ** error, or some other SQLite error code if another error (e.g. OOM)
180479 ** occurs.
180480 */
180481 static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
180482 int eDetail = p->pConfig->eDetail;
180483 u64 cksum2 = 0; /* Checksum based on contents of indexes */
180484 Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
180485 Fts5IndexIter *pIter; /* Used to iterate through entire index */
180486 Fts5Structure *pStruct; /* Index structure */
180487
@@ -179403,16 +180529,22 @@
180529 char *z = (char*)fts5MultiIterTerm(pIter, &n);
180530
180531 /* If this is a new term, query for it. Update cksum3 with the results. */
180532 fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
180533
180534 if( eDetail==FTS5_DETAIL_NONE ){
180535 if( 0==fts5MultiIterIsEmpty(p, pIter) ){
180536 cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
180537 }
180538 }else{
180539 poslist.n = 0;
180540 fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
180541 while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
180542 int iCol = FTS5_POS2COLUMN(iPos);
180543 int iTokOff = FTS5_POS2OFFSET(iPos);
180544 cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
180545 }
180546 }
180547 }
180548 fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
180549
180550 fts5MultiIterFree(p, pIter);
@@ -179424,38 +180556,10 @@
180556 #endif
180557 fts5BufferFree(&poslist);
180558 return fts5IndexReturn(p);
180559 }
180560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180561 /*************************************************************************
180562 **************************************************************************
180563 ** Below this point is the implementation of the fts5_decode() scalar
180564 ** function only.
180565 */
@@ -179618,10 +180722,51 @@
180722 }
180723 }
180724
180725 return iOff;
180726 }
180727
180728 /*
180729 ** This function is part of the fts5_decode() debugging function. It is
180730 ** only ever used with detail=none tables.
180731 **
180732 ** Buffer (pData/nData) contains a doclist in the format used by detail=none
180733 ** tables. This function appends a human-readable version of that list to
180734 ** buffer pBuf.
180735 **
180736 ** If *pRc is other than SQLITE_OK when this function is called, it is a
180737 ** no-op. If an OOM or other error occurs within this function, *pRc is
180738 ** set to an SQLite error code before returning. The final state of buffer
180739 ** pBuf is undefined in this case.
180740 */
180741 static void fts5DecodeRowidList(
180742 int *pRc, /* IN/OUT: Error code */
180743 Fts5Buffer *pBuf, /* Buffer to append text to */
180744 const u8 *pData, int nData /* Data to decode list-of-rowids from */
180745 ){
180746 int i = 0;
180747 i64 iRowid = 0;
180748
180749 while( i<nData ){
180750 const char *zApp = "";
180751 u64 iVal;
180752 i += sqlite3Fts5GetVarint(&pData[i], &iVal);
180753 iRowid += iVal;
180754
180755 if( i<nData && pData[i]==0x00 ){
180756 i++;
180757 if( i<nData && pData[i]==0x00 ){
180758 i++;
180759 zApp = "+";
180760 }else{
180761 zApp = "*";
180762 }
180763 }
180764
180765 sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
180766 }
180767 }
180768
180769 /*
180770 ** The implementation of user-defined scalar function fts5_decode().
180771 */
180772 static void fts5DecodeFunction(
@@ -179634,10 +180779,11 @@
180779 const u8 *aBlob; int n; /* Record to decode */
180780 u8 *a = 0;
180781 Fts5Buffer s; /* Build up text to return here */
180782 int rc = SQLITE_OK; /* Return code */
180783 int nSpace = 0;
180784 int eDetailNone = (sqlite3_user_data(pCtx)!=0);
180785
180786 assert( nArg==2 );
180787 memset(&s, 0, sizeof(Fts5Buffer));
180788 iRowid = sqlite3_value_int64(apVal[0]);
180789
@@ -179675,10 +180821,58 @@
180821 if( iRowid==FTS5_AVERAGES_ROWID ){
180822 fts5DecodeAverages(&rc, &s, a, n);
180823 }else{
180824 fts5DecodeStructure(&rc, &s, a, n);
180825 }
180826 }else if( eDetailNone ){
180827 Fts5Buffer term; /* Current term read from page */
180828 int szLeaf;
180829 int iPgidxOff = szLeaf = fts5GetU16(&a[2]);
180830 int iTermOff;
180831 int nKeep = 0;
180832 int iOff;
180833
180834 memset(&term, 0, sizeof(Fts5Buffer));
180835
180836 /* Decode any entries that occur before the first term. */
180837 if( szLeaf<n ){
180838 iPgidxOff += fts5GetVarint32(&a[iPgidxOff], iTermOff);
180839 }else{
180840 iTermOff = szLeaf;
180841 }
180842 fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
180843
180844 iOff = iTermOff;
180845 while( iOff<szLeaf ){
180846 int nAppend;
180847
180848 /* Read the term data for the next term*/
180849 iOff += fts5GetVarint32(&a[iOff], nAppend);
180850 term.n = nKeep;
180851 fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
180852 sqlite3Fts5BufferAppendPrintf(
180853 &rc, &s, " term=%.*s", term.n, (const char*)term.p
180854 );
180855 iOff += nAppend;
180856
180857 /* Figure out where the doclist for this term ends */
180858 if( iPgidxOff<n ){
180859 int nIncr;
180860 iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr);
180861 iTermOff += nIncr;
180862 }else{
180863 iTermOff = szLeaf;
180864 }
180865
180866 fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
180867 iOff = iTermOff;
180868 if( iOff<szLeaf ){
180869 iOff += fts5GetVarint32(&a[iOff], nKeep);
180870 }
180871 }
180872
180873 fts5BufferFree(&term);
180874 }else{
180875 Fts5Buffer term; /* Current term read from page */
180876 int szLeaf; /* Offset of pgidx in a[] */
180877 int iPgidxOff;
180878 int iPgidxPrev = 0; /* Previous value read from pgidx */
@@ -179802,18 +180996,25 @@
180996 */
180997 static int sqlite3Fts5IndexInit(sqlite3 *db){
180998 int rc = sqlite3_create_function(
180999 db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
181000 );
181001
181002 if( rc==SQLITE_OK ){
181003 rc = sqlite3_create_function(
181004 db, "fts5_decode_none", 2,
181005 SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
181006 );
181007 }
181008
181009 if( rc==SQLITE_OK ){
181010 rc = sqlite3_create_function(
181011 db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
181012 );
181013 }
181014 return rc;
181015 }
 
181016
181017 /*
181018 ** 2014 Jun 09
181019 **
181020 ** The author disclaims copyright to this source code. In place of
@@ -180039,10 +181240,11 @@
181240 #define FTS5CSR_REQUIRE_DOCSIZE 0x02
181241 #define FTS5CSR_REQUIRE_INST 0x04
181242 #define FTS5CSR_EOF 0x08
181243 #define FTS5CSR_FREE_ZRANK 0x10
181244 #define FTS5CSR_REQUIRE_RESEEK 0x20
181245 #define FTS5CSR_REQUIRE_POSLIST 0x40
181246
181247 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
181248 #define BitFlagTest(x,y) (((x) & (y))!=0)
181249
181250
@@ -180452,10 +181654,11 @@
181654 static void fts5CsrNewrow(Fts5Cursor *pCsr){
181655 CsrFlagSet(pCsr,
181656 FTS5CSR_REQUIRE_CONTENT
181657 | FTS5CSR_REQUIRE_DOCSIZE
181658 | FTS5CSR_REQUIRE_INST
181659 | FTS5CSR_REQUIRE_POSLIST
181660 );
181661 }
181662
181663 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
181664 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
@@ -180534,19 +181737,22 @@
181737
181738 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
181739 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
181740 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
181741
181742 /* nBlob==0 in detail=none mode. */
181743 if( nBlob>0 ){
181744 for(i=0; i<(pSorter->nIdx-1); i++){
181745 int iVal;
181746 a += fts5GetVarint32(a, iVal);
181747 iOff += iVal;
181748 pSorter->aIdx[i] = iOff;
181749 }
181750 pSorter->aIdx[i] = &aBlob[nBlob] - a;
181751 pSorter->aPoslist = a;
181752 }
181753
181754 fts5CsrNewrow(pCsr);
181755 }
181756
181757 return rc;
181758 }
@@ -180652,45 +181858,44 @@
181858
181859 return rc;
181860 }
181861
181862
181863 static int fts5PrepareStatement(
181864 sqlite3_stmt **ppStmt,
181865 Fts5Config *pConfig,
181866 const char *zFmt,
181867 ...
181868 ){
181869 sqlite3_stmt *pRet = 0;
181870 int rc;
181871 char *zSql;
181872 va_list ap;
181873
181874 va_start(ap, zFmt);
181875 zSql = sqlite3_vmprintf(zFmt, ap);
181876 if( zSql==0 ){
181877 rc = SQLITE_NOMEM;
181878 }else{
181879 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
181880 if( rc!=SQLITE_OK ){
181881 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
181882 }
181883 sqlite3_free(zSql);
 
 
 
 
 
181884 }
181885
181886 va_end(ap);
181887 *ppStmt = pRet;
181888 return rc;
181889 }
181890
181891 static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
181892 Fts5Config *pConfig = pTab->pConfig;
181893 Fts5Sorter *pSorter;
181894 int nPhrase;
181895 int nByte;
181896 int rc;
181897 const char *zRank = pCsr->zRank;
181898 const char *zRankArgs = pCsr->zRankArgs;
181899
181900 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
181901 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
@@ -180704,11 +181909,11 @@
181909 ** is not possible as SQLite reference counts the virtual table objects.
181910 ** And since the statement required here reads from this very virtual
181911 ** table, saving it creates a circular reference.
181912 **
181913 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
181914 rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
181915 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
181916 pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
181917 (zRankArgs ? ", " : ""),
181918 (zRankArgs ? zRankArgs : ""),
181919 bDesc ? "DESC" : "ASC"
@@ -180980,10 +182185,11 @@
182185 assert( pCsr->iLastRowid==LARGEST_INT64 );
182186 assert( pCsr->iFirstRowid==SMALLEST_INT64 );
182187 pCsr->ePlan = FTS5_PLAN_SOURCE;
182188 pCsr->pExpr = pTab->pSortCsr->pExpr;
182189 rc = fts5CursorFirst(pTab, pCsr, bDesc);
182190 sqlite3Fts5ExprClearEof(pCsr->pExpr);
182191 }else if( pMatch ){
182192 const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
182193 if( zExpr==0 ) zExpr = "";
182194
182195 rc = fts5CursorParseRank(pConfig, pCsr, pRank);
@@ -181212,11 +182418,11 @@
182418 ){
182419 int rc = SQLITE_OK;
182420 int eType1 = sqlite3_value_type(apVal[1]);
182421 if( eType1==SQLITE_INTEGER ){
182422 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
182423 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
182424 }
182425 return rc;
182426 }
182427
182428 static void fts5StorageInsert(
@@ -181319,21 +182525,21 @@
182525 }
182526
182527 /* Case 1: DELETE */
182528 else if( nArg==1 ){
182529 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
182530 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
182531 }
182532
182533 /* Case 2: INSERT */
182534 else if( eType0!=SQLITE_INTEGER ){
182535 /* If this is a REPLACE, first remove the current entry (if any) */
182536 if( eConflict==SQLITE_REPLACE
182537 && sqlite3_value_type(apVal[1])==SQLITE_INTEGER
182538 ){
182539 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
182540 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
182541 }
182542 fts5StorageInsert(&rc, pTab, apVal, pRowid);
182543 }
182544
182545 /* Case 2: UPDATE */
@@ -181340,26 +182546,26 @@
182546 else{
182547 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
182548 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
182549 if( iOld!=iNew ){
182550 if( eConflict==SQLITE_REPLACE ){
182551 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
182552 if( rc==SQLITE_OK ){
182553 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
182554 }
182555 fts5StorageInsert(&rc, pTab, apVal, pRowid);
182556 }else{
182557 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
182558 if( rc==SQLITE_OK ){
182559 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
182560 }
182561 if( rc==SQLITE_OK ){
182562 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
182563 }
182564 }
182565 }else{
182566 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
182567 fts5StorageInsert(&rc, pTab, apVal, pRowid);
182568 }
182569 }
182570 }
182571
@@ -181409,10 +182615,12 @@
182615 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
182616 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
182617 return rc;
182618 }
182619
182620 static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
182621
182622 static void *fts5ApiUserData(Fts5Context *pCtx){
182623 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
182624 return pCsr->pAux->pUserData;
182625 }
182626
@@ -181458,21 +182666,76 @@
182666 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
182667 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
182668 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
182669 }
182670
182671 static int fts5ApiColumnText(
182672 Fts5Context *pCtx,
182673 int iCol,
182674 const char **pz,
182675 int *pn
182676 ){
182677 int rc = SQLITE_OK;
182678 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
182679 if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
182680 *pz = 0;
182681 *pn = 0;
182682 }else{
182683 rc = fts5SeekCursor(pCsr, 0);
182684 if( rc==SQLITE_OK ){
182685 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
182686 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
182687 }
182688 }
182689 return rc;
182690 }
182691
182692 static int fts5CsrPoslist(
182693 Fts5Cursor *pCsr,
182694 int iPhrase,
182695 const u8 **pa,
182696 int *pn
182697 ){
182698 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
182699 int rc = SQLITE_OK;
182700 int bLive = (pCsr->pSorter==0);
182701
182702 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
182703
182704 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
182705 Fts5PoslistPopulator *aPopulator;
182706 int i;
182707 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
182708 if( aPopulator==0 ) rc = SQLITE_NOMEM;
182709 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
182710 int n; const char *z;
182711 rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
182712 if( rc==SQLITE_OK ){
182713 rc = sqlite3Fts5ExprPopulatePoslists(
182714 pConfig, pCsr->pExpr, aPopulator, i, z, n
182715 );
182716 }
182717 }
182718 sqlite3_free(aPopulator);
182719
182720 if( pCsr->pSorter ){
182721 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
182722 }
182723 }
182724 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
182725 }
182726
182727 if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
182728 Fts5Sorter *pSorter = pCsr->pSorter;
182729 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
182730 *pn = pSorter->aIdx[iPhrase] - i1;
182731 *pa = &pSorter->aPoslist[i1];
182732 }else{
182733 *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
182734 }
182735
182736 return rc;
182737 }
182738
182739 /*
182740 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
182741 ** correctly for the current view. Return SQLITE_OK if successful, or an
@@ -181493,47 +182756,52 @@
182756 if( aIter ){
182757 int nInst = 0; /* Number instances seen so far */
182758 int i;
182759
182760 /* Initialize all iterators */
182761 for(i=0; i<nIter && rc==SQLITE_OK; i++){
182762 const u8 *a;
182763 int n;
182764 rc = fts5CsrPoslist(pCsr, i, &a, &n);
182765 if( rc==SQLITE_OK ){
182766 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
182767 }
182768 }
182769
182770 if( rc==SQLITE_OK ){
182771 while( 1 ){
182772 int *aInst;
182773 int iBest = -1;
182774 for(i=0; i<nIter; i++){
182775 if( (aIter[i].bEof==0)
182776 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
182777 ){
182778 iBest = i;
182779 }
182780 }
182781 if( iBest<0 ) break;
182782
182783 nInst++;
182784 if( nInst>=pCsr->nInstAlloc ){
182785 pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
182786 aInst = (int*)sqlite3_realloc(
182787 pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
182788 );
182789 if( aInst ){
182790 pCsr->aInst = aInst;
182791 }else{
182792 rc = SQLITE_NOMEM;
182793 break;
182794 }
182795 }
182796
182797 aInst = &pCsr->aInst[3 * (nInst-1)];
182798 aInst[0] = iBest;
182799 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
182800 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
182801 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
182802 }
182803 }
182804
182805 pCsr->nInstCount = nInst;
182806 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
182807 }
@@ -181562,10 +182830,16 @@
182830 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
182831 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
182832 ){
182833 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
182834 rc = SQLITE_RANGE;
182835 #if 0
182836 }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
182837 *piPhrase = pCsr->aInst[iIdx*3];
182838 *piCol = pCsr->aInst[iIdx*3 + 2];
182839 *piOff = -1;
182840 #endif
182841 }else{
182842 *piPhrase = pCsr->aInst[iIdx*3];
182843 *piCol = pCsr->aInst[iIdx*3 + 1];
182844 *piOff = pCsr->aInst[iIdx*3 + 2];
182845 }
@@ -181575,31 +182849,10 @@
182849
182850 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
182851 return fts5CursorRowid((Fts5Cursor*)pCtx);
182852 }
182853
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182854 static int fts5ColumnSizeCb(
182855 void *pContext, /* Pointer to int */
182856 int tflags,
182857 const char *pToken, /* Buffer containing token */
182858 int nToken, /* Size of token in bytes */
@@ -181740,23 +182993,101 @@
182993 }
182994 *piOff += (iVal-2);
182995 }
182996 }
182997
182998 static int fts5ApiPhraseFirst(
182999 Fts5Context *pCtx,
183000 int iPhrase,
183001 Fts5PhraseIter *pIter,
183002 int *piCol, int *piOff
183003 ){
183004 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
183005 int n;
183006 int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
183007 if( rc==SQLITE_OK ){
183008 pIter->b = &pIter->a[n];
183009 *piCol = 0;
183010 *piOff = 0;
183011 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
183012 }
183013 return rc;
183014 }
183015
183016 static void fts5ApiPhraseNextColumn(
183017 Fts5Context *pCtx,
183018 Fts5PhraseIter *pIter,
183019 int *piCol
183020 ){
183021 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
183022 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
183023
183024 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
183025 if( pIter->a>=pIter->b ){
183026 *piCol = -1;
183027 }else{
183028 int iIncr;
183029 pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
183030 *piCol += (iIncr-2);
183031 }
183032 }else{
183033 while( 1 ){
183034 int dummy;
183035 if( pIter->a>=pIter->b ){
183036 *piCol = -1;
183037 return;
183038 }
183039 if( pIter->a[0]==0x01 ) break;
183040 pIter->a += fts5GetVarint32(pIter->a, dummy);
183041 }
183042 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
183043 }
183044 }
183045
183046 static int fts5ApiPhraseFirstColumn(
183047 Fts5Context *pCtx,
183048 int iPhrase,
183049 Fts5PhraseIter *pIter,
183050 int *piCol
183051 ){
183052 int rc = SQLITE_OK;
183053 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
183054 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
183055
183056 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
183057 Fts5Sorter *pSorter = pCsr->pSorter;
183058 int n;
183059 if( pSorter ){
183060 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
183061 n = pSorter->aIdx[iPhrase] - i1;
183062 pIter->a = &pSorter->aPoslist[i1];
183063 }else{
183064 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
183065 }
183066 if( rc==SQLITE_OK ){
183067 pIter->b = &pIter->a[n];
183068 *piCol = 0;
183069 fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
183070 }
183071 }else{
183072 int n;
183073 rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
183074 if( rc==SQLITE_OK ){
183075 pIter->b = &pIter->a[n];
183076 if( n<=0 ){
183077 *piCol = -1;
183078 }else if( pIter->a[0]==0x01 ){
183079 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
183080 }else{
183081 *piCol = 0;
183082 }
183083 }
183084 }
183085
183086 return rc;
183087 }
183088
183089
183090 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
183091 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
183092 );
183093
@@ -181777,12 +183108,13 @@
183108 fts5ApiQueryPhrase,
183109 fts5ApiSetAuxdata,
183110 fts5ApiGetAuxdata,
183111 fts5ApiPhraseFirst,
183112 fts5ApiPhraseNext,
183113 fts5ApiPhraseFirstColumn,
183114 fts5ApiPhraseNextColumn,
183115 };
 
183116
183117 /*
183118 ** Implementation of API function xQueryPhrase().
183119 */
183120 static int fts5ApiQueryPhrase(
@@ -181911,24 +183243,50 @@
183243 int rc = SQLITE_OK;
183244 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
183245 Fts5Buffer val;
183246
183247 memset(&val, 0, sizeof(Fts5Buffer));
183248 switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
183249 case FTS5_DETAIL_FULL:
183250
183251 /* Append the varints */
183252 for(i=0; i<(nPhrase-1); i++){
183253 const u8 *dummy;
183254 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
183255 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
183256 }
183257
183258 /* Append the position lists */
183259 for(i=0; i<nPhrase; i++){
183260 const u8 *pPoslist;
183261 int nPoslist;
183262 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
183263 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
183264 }
183265 break;
183266
183267 case FTS5_DETAIL_COLUMNS:
183268
183269 /* Append the varints */
183270 for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
183271 const u8 *dummy;
183272 int nByte;
183273 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
183274 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
183275 }
183276
183277 /* Append the position lists */
183278 for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
183279 const u8 *pPoslist;
183280 int nPoslist;
183281 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
183282 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
183283 }
183284 break;
183285
183286 default:
183287 break;
183288 }
183289
183290 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
183291 return rc;
183292 }
@@ -182247,11 +183605,11 @@
183605 sqlite3_context *pCtx, /* Function call context */
183606 int nArg, /* Number of args */
183607 sqlite3_value **apVal /* Function arguments */
183608 ){
183609 assert( nArg==0 );
183610 sqlite3_result_text(pCtx, "fts5: 2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1", -1, SQLITE_TRANSIENT);
183611 }
183612
183613 static int fts5Init(sqlite3 *db){
183614 static const sqlite3_module fts5Mod = {
183615 /* iVersion */ 2,
@@ -182732,43 +184090,56 @@
184090 /*
184091 ** If a row with rowid iDel is present in the %_content table, add the
184092 ** delete-markers to the FTS index necessary to delete it. Do not actually
184093 ** remove the %_content row at this time though.
184094 */
184095 static int fts5StorageDeleteFromIndex(
184096 Fts5Storage *p,
184097 i64 iDel,
184098 sqlite3_value **apVal
184099 ){
184100 Fts5Config *pConfig = p->pConfig;
184101 sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
184102 int rc; /* Return code */
184103 int rc2; /* sqlite3_reset() return code */
184104 int iCol;
184105 Fts5InsertCtx ctx;
184106
184107 if( apVal==0 ){
184108 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
184109 if( rc!=SQLITE_OK ) return rc;
184110 sqlite3_bind_int64(pSeek, 1, iDel);
184111 if( sqlite3_step(pSeek)!=SQLITE_ROW ){
184112 return sqlite3_reset(pSeek);
184113 }
184114 }
184115
184116 ctx.pStorage = p;
184117 ctx.iCol = -1;
184118 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
184119 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
184120 if( pConfig->abUnindexed[iCol-1]==0 ){
184121 const char *zText;
184122 int nText;
184123 if( pSeek ){
184124 zText = (const char*)sqlite3_column_text(pSeek, iCol);
184125 nText = sqlite3_column_bytes(pSeek, iCol);
184126 }else{
184127 zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
184128 nText = sqlite3_value_bytes(apVal[iCol-1]);
184129 }
184130 ctx.szCol = 0;
184131 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
184132 zText, nText, (void*)&ctx, fts5StorageInsertCallback
184133 );
184134 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
184135 }
184136 }
184137 p->nTotalRow--;
184138
184139 rc2 = sqlite3_reset(pSeek);
184140 if( rc==SQLITE_OK ) rc = rc2;
184141 return rc;
184142 }
184143
184144
184145 /*
@@ -182844,20 +184215,21 @@
184215 }
184216
184217 /*
184218 ** Remove a row from the FTS table.
184219 */
184220 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
184221 Fts5Config *pConfig = p->pConfig;
184222 int rc;
184223 sqlite3_stmt *pDel = 0;
184224
184225 assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
184226 rc = fts5StorageLoadTotals(p, 1);
184227
184228 /* Delete the index records */
184229 if( rc==SQLITE_OK ){
184230 rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
184231 }
184232
184233 /* Delete the %_docsize record */
184234 if( rc==SQLITE_OK && pConfig->bColumnsize ){
184235 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
@@ -182871,65 +184243,10 @@
184243 /* Delete the %_content record */
184244 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
184245 if( rc==SQLITE_OK ){
184246 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
184247 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184248 if( rc==SQLITE_OK ){
184249 sqlite3_bind_int64(pDel, 1, iDel);
184250 sqlite3_step(pDel);
184251 rc = sqlite3_reset(pDel);
184252 }
@@ -183179,32 +184496,77 @@
184496 struct Fts5IntegrityCtx {
184497 i64 iRowid;
184498 int iCol;
184499 int szCol;
184500 u64 cksum;
184501 Fts5Termset *pTermset;
184502 Fts5Config *pConfig;
184503 };
184504
184505
184506 /*
184507 ** Tokenization callback used by integrity check.
184508 */
184509 static int fts5StorageIntegrityCallback(
184510 void *pContext, /* Pointer to Fts5IntegrityCtx object */
184511 int tflags,
184512 const char *pToken, /* Buffer containing token */
184513 int nToken, /* Size of token in bytes */
184514 int iStart, /* Start offset of token */
184515 int iEnd /* End offset of token */
184516 ){
184517 Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
184518 Fts5Termset *pTermset = pCtx->pTermset;
184519 int bPresent;
184520 int ii;
184521 int rc = SQLITE_OK;
184522 int iPos;
184523 int iCol;
184524
184525 if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
184526 pCtx->szCol++;
184527 }
184528
184529 switch( pCtx->pConfig->eDetail ){
184530 case FTS5_DETAIL_FULL:
184531 iPos = pCtx->szCol-1;
184532 iCol = pCtx->iCol;
184533 break;
184534
184535 case FTS5_DETAIL_COLUMNS:
184536 iPos = pCtx->iCol;
184537 iCol = 0;
184538 break;
184539
184540 default:
184541 assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE );
184542 iPos = 0;
184543 iCol = 0;
184544 break;
184545 }
184546
184547 rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent);
184548 if( rc==SQLITE_OK && bPresent==0 ){
184549 pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
184550 pCtx->iRowid, iCol, iPos, 0, pToken, nToken
184551 );
184552 }
184553
184554 for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){
184555 const int nChar = pCtx->pConfig->aPrefix[ii];
184556 int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
184557 if( nByte ){
184558 rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent);
184559 if( bPresent==0 ){
184560 pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
184561 pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte
184562 );
184563 }
184564 }
184565 }
184566
184567 return rc;
184568 }
184569
184570 /*
184571 ** Check that the contents of the FTS index match that of the %_content
184572 ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return
@@ -183235,27 +184597,42 @@
184597 int i;
184598 ctx.iRowid = sqlite3_column_int64(pScan, 0);
184599 ctx.szCol = 0;
184600 if( pConfig->bColumnsize ){
184601 rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
184602 }
184603 if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
184604 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
184605 }
184606 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
184607 if( pConfig->abUnindexed[i] ) continue;
184608 ctx.iCol = i;
184609 ctx.szCol = 0;
184610 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
184611 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
184612 }
184613 if( rc==SQLITE_OK ){
184614 rc = sqlite3Fts5Tokenize(pConfig,
184615 FTS5_TOKENIZE_DOCUMENT,
184616 (const char*)sqlite3_column_text(pScan, i+1),
184617 sqlite3_column_bytes(pScan, i+1),
184618 (void*)&ctx,
184619 fts5StorageIntegrityCallback
184620 );
184621 }
184622 if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
184623 rc = FTS5_CORRUPT;
184624 }
184625 aTotalSize[i] += ctx.szCol;
184626 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
184627 sqlite3Fts5TermsetFree(ctx.pTermset);
184628 ctx.pTermset = 0;
184629 }
184630 }
184631 sqlite3Fts5TermsetFree(ctx.pTermset);
184632 ctx.pTermset = 0;
184633
184634 if( rc!=SQLITE_OK ) break;
184635 }
184636 rc2 = sqlite3_reset(pScan);
184637 if( rc==SQLITE_OK ) rc = rc2;
184638 }
@@ -185777,11 +187154,11 @@
187154
187155 pCsr->rowid++;
187156
187157 if( pTab->eType==FTS5_VOCAB_COL ){
187158 for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
187159 if( pCsr->aDoc[pCsr->iCol] ) break;
187160 }
187161 }
187162
187163 if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
187164 if( sqlite3Fts5IterEof(pCsr->pIter) ){
@@ -185810,28 +187187,64 @@
187187 i64 dummy;
187188 const u8 *pPos; int nPos; /* Position list */
187189 i64 iPos = 0; /* 64-bit position read from poslist */
187190 int iOff = 0; /* Current offset within position list */
187191
187192 switch( pCsr->pConfig->eDetail ){
187193 case FTS5_DETAIL_FULL:
187194 rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
187195 if( rc==SQLITE_OK ){
187196 if( pTab->eType==FTS5_VOCAB_ROW ){
187197 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
187198 pCsr->aCnt[0]++;
187199 }
187200 pCsr->aDoc[0]++;
187201 }else{
187202 int iCol = -1;
187203 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
187204 int ii = FTS5_POS2COLUMN(iPos);
187205 pCsr->aCnt[ii]++;
187206 if( iCol!=ii ){
187207 if( ii>=nCol ){
187208 rc = FTS5_CORRUPT;
187209 break;
187210 }
187211 pCsr->aDoc[ii]++;
187212 iCol = ii;
187213 }
187214 }
187215 }
187216 }
187217 break;
187218
187219 case FTS5_DETAIL_COLUMNS:
187220 if( pTab->eType==FTS5_VOCAB_ROW ){
187221 pCsr->aDoc[0]++;
187222 }else{
187223 Fts5Buffer buf = {0, 0, 0};
187224 rc = sqlite3Fts5IterPoslistBuffer(pCsr->pIter, &buf);
187225 if( rc==SQLITE_OK ){
187226 while( 0==sqlite3Fts5PoslistNext64(buf.p, buf.n, &iOff,&iPos) ){
187227 assert_nc( iPos>=0 && iPos<nCol );
187228 if( iPos>=nCol ){
187229 rc = FTS5_CORRUPT;
187230 break;
187231 }
187232 pCsr->aDoc[iPos]++;
187233 }
187234 }
187235 sqlite3Fts5BufferFree(&buf);
187236 }
187237 break;
187238
187239 default:
187240 assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
187241 pCsr->aDoc[0]++;
187242 break;
187243 }
187244
187245 if( rc==SQLITE_OK ){
187246 rc = sqlite3Fts5IterNextScan(pCsr->pIter);
187247 }
187248
187249 if( rc==SQLITE_OK ){
187250 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
@@ -185842,12 +187255,12 @@
187255 }
187256 }
187257 }
187258 }
187259
187260 if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
187261 while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
187262 assert( pCsr->iCol<pCsr->pConfig->nCol );
187263 }
187264 return rc;
187265 }
187266
@@ -185923,34 +187336,40 @@
187336 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
187337 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
187338 int iCol /* Index of column to read value from */
187339 ){
187340 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
187341 int eDetail = pCsr->pConfig->eDetail;
187342 int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
187343 i64 iVal = 0;
187344
187345 if( iCol==0 ){
187346 sqlite3_result_text(
187347 pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
187348 );
187349 }else if( eType==FTS5_VOCAB_COL ){
 
187350 assert( iCol==1 || iCol==2 || iCol==3 );
187351 if( iCol==1 ){
187352 if( eDetail!=FTS5_DETAIL_NONE ){
187353 const char *z = pCsr->pConfig->azCol[pCsr->iCol];
187354 sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
187355 }
187356 }else if( iCol==2 ){
187357 iVal = pCsr->aDoc[pCsr->iCol];
187358 }else{
187359 iVal = pCsr->aCnt[pCsr->iCol];
187360 }
187361 }else{
187362 assert( iCol==1 || iCol==2 );
187363 if( iCol==1 ){
187364 iVal = pCsr->aDoc[0];
187365 }else{
187366 iVal = pCsr->aCnt[0];
187367 }
187368 }
187369
187370 if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
187371 return SQLITE_OK;
187372 }
187373
187374 /*
187375 ** This is the xRowid method. The SQLite core calls this routine to
187376
+73 -9
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -109,13 +109,13 @@
109109
**
110110
** See also: [sqlite3_libversion()],
111111
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112112
** [sqlite_version()] and [sqlite_source_id()].
113113
*/
114
-#define SQLITE_VERSION "3.10.0"
115
-#define SQLITE_VERSION_NUMBER 3010000
116
-#define SQLITE_SOURCE_ID "2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566"
114
+#define SQLITE_VERSION "3.11.0"
115
+#define SQLITE_VERSION_NUMBER 3011000
116
+#define SQLITE_SOURCE_ID "2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1"
117117
118118
/*
119119
** CAPI3REF: Run-Time Library Version Numbers
120120
** KEYWORDS: sqlite3_version, sqlite3_sourceid
121121
**
@@ -792,12 +792,17 @@
792792
** improve performance on some systems.
793793
**
794794
** <li>[[SQLITE_FCNTL_FILE_POINTER]]
795795
** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
796796
** to the [sqlite3_file] object associated with a particular database
797
-** connection. See the [sqlite3_file_control()] documentation for
798
-** additional information.
797
+** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
798
+**
799
+** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
800
+** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
801
+** to the [sqlite3_file] object associated with the journal file (either
802
+** the [rollback journal] or the [write-ahead log]) for a particular database
803
+** connection. See also [SQLITE_FCNTL_FILE_POINTER].
799804
**
800805
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
801806
** No longer in use.
802807
**
803808
** <li>[[SQLITE_FCNTL_SYNC]]
@@ -1008,10 +1013,11 @@
10081013
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
10091014
#define SQLITE_FCNTL_WAL_BLOCK 24
10101015
#define SQLITE_FCNTL_ZIPVFS 25
10111016
#define SQLITE_FCNTL_RBU 26
10121017
#define SQLITE_FCNTL_VFS_POINTER 27
1018
+#define SQLITE_FCNTL_JOURNAL_POINTER 28
10131019
10141020
/* deprecated names */
10151021
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
10161022
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
10171023
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -8185,10 +8191,13 @@
81858191
** If parameter iCol is greater than or equal to the number of columns
81868192
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
81878193
** an OOM condition or IO error), an appropriate SQLite error code is
81888194
** returned.
81898195
**
8196
+** This function may be quite inefficient if used with an FTS5 table
8197
+** created with the "columnsize=0" option.
8198
+**
81908199
** xColumnText:
81918200
** This function attempts to retrieve the text of column iCol of the
81928201
** current document. If successful, (*pz) is set to point to a buffer
81938202
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
81948203
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -8205,18 +8214,32 @@
82058214
** xInstCount:
82068215
** Set *pnInst to the total number of occurrences of all phrases within
82078216
** the query within the current row. Return SQLITE_OK if successful, or
82088217
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
82098218
**
8219
+** This API can be quite slow if used with an FTS5 table created with the
8220
+** "detail=none" or "detail=column" option. If the FTS5 table is created
8221
+** with either "detail=none" or "detail=column" and "content=" option
8222
+** (i.e. if it is a contentless table), then this API always returns 0.
8223
+**
82108224
** xInst:
82118225
** Query for the details of phrase match iIdx within the current row.
82128226
** Phrase matches are numbered starting from zero, so the iIdx argument
82138227
** should be greater than or equal to zero and smaller than the value
82148228
** output by xInstCount().
8229
+**
8230
+** Usually, output parameter *piPhrase is set to the phrase number, *piCol
8231
+** to the column in which it occurs and *piOff the token offset of the
8232
+** first token of the phrase. The exception is if the table was created
8233
+** with the offsets=0 option specified. In this case *piOff is always
8234
+** set to -1.
82158235
**
82168236
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
82178237
** if an error occurs.
8238
+**
8239
+** This API can be quite slow if used with an FTS5 table created with the
8240
+** "detail=none" or "detail=column" option.
82188241
**
82198242
** xRowid:
82208243
** Returns the rowid of the current row.
82218244
**
82228245
** xTokenize:
@@ -8297,25 +8320,63 @@
82978320
** through instances of phrase iPhrase, use the following code:
82988321
**
82998322
** Fts5PhraseIter iter;
83008323
** int iCol, iOff;
83018324
** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
8302
-** iOff>=0;
8325
+** iCol>=0;
83038326
** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
83048327
** ){
83058328
** // An instance of phrase iPhrase at offset iOff of column iCol
83068329
** }
83078330
**
83088331
** The Fts5PhraseIter structure is defined above. Applications should not
83098332
** modify this structure directly - it should only be used as shown above
8310
-** with the xPhraseFirst() and xPhraseNext() API methods.
8333
+** with the xPhraseFirst() and xPhraseNext() API methods (and by
8334
+** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
8335
+**
8336
+** This API can be quite slow if used with an FTS5 table created with the
8337
+** "detail=none" or "detail=column" option. If the FTS5 table is created
8338
+** with either "detail=none" or "detail=column" and "content=" option
8339
+** (i.e. if it is a contentless table), then this API always iterates
8340
+** through an empty set (all calls to xPhraseFirst() set iCol to -1).
83118341
**
83128342
** xPhraseNext()
83138343
** See xPhraseFirst above.
8344
+**
8345
+** xPhraseFirstColumn()
8346
+** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
8347
+** and xPhraseNext() APIs described above. The difference is that instead
8348
+** of iterating through all instances of a phrase in the current row, these
8349
+** APIs are used to iterate through the set of columns in the current row
8350
+** that contain one or more instances of a specified phrase. For example:
8351
+**
8352
+** Fts5PhraseIter iter;
8353
+** int iCol;
8354
+** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
8355
+** iCol>=0;
8356
+** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
8357
+** ){
8358
+** // Column iCol contains at least one instance of phrase iPhrase
8359
+** }
8360
+**
8361
+** This API can be quite slow if used with an FTS5 table created with the
8362
+** "detail=none" option. If the FTS5 table is created with either
8363
+** "detail=none" "content=" option (i.e. if it is a contentless table),
8364
+** then this API always iterates through an empty set (all calls to
8365
+** xPhraseFirstColumn() set iCol to -1).
8366
+**
8367
+** The information accessed using this API and its companion
8368
+** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
8369
+** (or xInst/xInstCount). The chief advantage of this API is that it is
8370
+** significantly more efficient than those alternatives when used with
8371
+** "detail=column" tables.
8372
+**
8373
+** xPhraseNextColumn()
8374
+** See xPhraseFirstColumn above.
83148375
*/
83158376
struct Fts5ExtensionApi {
8316
- int iVersion; /* Currently always set to 1 */
8377
+ int iVersion; /* Currently always set to 3 */
83178378
83188379
void *(*xUserData)(Fts5Context*);
83198380
83208381
int (*xColumnCount)(Fts5Context*);
83218382
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -8341,12 +8402,15 @@
83418402
int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
83428403
);
83438404
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
83448405
void *(*xGetAuxdata)(Fts5Context*, int bClear);
83458406
8346
- void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
8407
+ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
83478408
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
8409
+
8410
+ int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
8411
+ void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
83488412
};
83498413
83508414
/*
83518415
** CUSTOM AUXILIARY FUNCTIONS
83528416
*************************************************************************/
83538417
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -109,13 +109,13 @@
109 **
110 ** See also: [sqlite3_libversion()],
111 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112 ** [sqlite_version()] and [sqlite_source_id()].
113 */
114 #define SQLITE_VERSION "3.10.0"
115 #define SQLITE_VERSION_NUMBER 3010000
116 #define SQLITE_SOURCE_ID "2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566"
117
118 /*
119 ** CAPI3REF: Run-Time Library Version Numbers
120 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
121 **
@@ -792,12 +792,17 @@
792 ** improve performance on some systems.
793 **
794 ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
795 ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
796 ** to the [sqlite3_file] object associated with a particular database
797 ** connection. See the [sqlite3_file_control()] documentation for
798 ** additional information.
 
 
 
 
 
799 **
800 ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
801 ** No longer in use.
802 **
803 ** <li>[[SQLITE_FCNTL_SYNC]]
@@ -1008,10 +1013,11 @@
1008 #define SQLITE_FCNTL_WIN32_SET_HANDLE 23
1009 #define SQLITE_FCNTL_WAL_BLOCK 24
1010 #define SQLITE_FCNTL_ZIPVFS 25
1011 #define SQLITE_FCNTL_RBU 26
1012 #define SQLITE_FCNTL_VFS_POINTER 27
 
1013
1014 /* deprecated names */
1015 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1016 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1017 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -8185,10 +8191,13 @@
8185 ** If parameter iCol is greater than or equal to the number of columns
8186 ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
8187 ** an OOM condition or IO error), an appropriate SQLite error code is
8188 ** returned.
8189 **
 
 
 
8190 ** xColumnText:
8191 ** This function attempts to retrieve the text of column iCol of the
8192 ** current document. If successful, (*pz) is set to point to a buffer
8193 ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
8194 ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -8205,18 +8214,32 @@
8205 ** xInstCount:
8206 ** Set *pnInst to the total number of occurrences of all phrases within
8207 ** the query within the current row. Return SQLITE_OK if successful, or
8208 ** an error code (i.e. SQLITE_NOMEM) if an error occurs.
8209 **
 
 
 
 
 
8210 ** xInst:
8211 ** Query for the details of phrase match iIdx within the current row.
8212 ** Phrase matches are numbered starting from zero, so the iIdx argument
8213 ** should be greater than or equal to zero and smaller than the value
8214 ** output by xInstCount().
 
 
 
 
 
 
8215 **
8216 ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
8217 ** if an error occurs.
 
 
 
8218 **
8219 ** xRowid:
8220 ** Returns the rowid of the current row.
8221 **
8222 ** xTokenize:
@@ -8297,25 +8320,63 @@
8297 ** through instances of phrase iPhrase, use the following code:
8298 **
8299 ** Fts5PhraseIter iter;
8300 ** int iCol, iOff;
8301 ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
8302 ** iOff>=0;
8303 ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
8304 ** ){
8305 ** // An instance of phrase iPhrase at offset iOff of column iCol
8306 ** }
8307 **
8308 ** The Fts5PhraseIter structure is defined above. Applications should not
8309 ** modify this structure directly - it should only be used as shown above
8310 ** with the xPhraseFirst() and xPhraseNext() API methods.
 
 
 
 
 
 
 
8311 **
8312 ** xPhraseNext()
8313 ** See xPhraseFirst above.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8314 */
8315 struct Fts5ExtensionApi {
8316 int iVersion; /* Currently always set to 1 */
8317
8318 void *(*xUserData)(Fts5Context*);
8319
8320 int (*xColumnCount)(Fts5Context*);
8321 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -8341,12 +8402,15 @@
8341 int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
8342 );
8343 int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
8344 void *(*xGetAuxdata)(Fts5Context*, int bClear);
8345
8346 void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
8347 void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
 
 
 
8348 };
8349
8350 /*
8351 ** CUSTOM AUXILIARY FUNCTIONS
8352 *************************************************************************/
8353
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -109,13 +109,13 @@
109 **
110 ** See also: [sqlite3_libversion()],
111 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112 ** [sqlite_version()] and [sqlite_source_id()].
113 */
114 #define SQLITE_VERSION "3.11.0"
115 #define SQLITE_VERSION_NUMBER 3011000
116 #define SQLITE_SOURCE_ID "2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1"
117
118 /*
119 ** CAPI3REF: Run-Time Library Version Numbers
120 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
121 **
@@ -792,12 +792,17 @@
792 ** improve performance on some systems.
793 **
794 ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
795 ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
796 ** to the [sqlite3_file] object associated with a particular database
797 ** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
798 **
799 ** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
800 ** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
801 ** to the [sqlite3_file] object associated with the journal file (either
802 ** the [rollback journal] or the [write-ahead log]) for a particular database
803 ** connection. See also [SQLITE_FCNTL_FILE_POINTER].
804 **
805 ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
806 ** No longer in use.
807 **
808 ** <li>[[SQLITE_FCNTL_SYNC]]
@@ -1008,10 +1013,11 @@
1013 #define SQLITE_FCNTL_WIN32_SET_HANDLE 23
1014 #define SQLITE_FCNTL_WAL_BLOCK 24
1015 #define SQLITE_FCNTL_ZIPVFS 25
1016 #define SQLITE_FCNTL_RBU 26
1017 #define SQLITE_FCNTL_VFS_POINTER 27
1018 #define SQLITE_FCNTL_JOURNAL_POINTER 28
1019
1020 /* deprecated names */
1021 #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
1022 #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
1023 #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -8185,10 +8191,13 @@
8191 ** If parameter iCol is greater than or equal to the number of columns
8192 ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
8193 ** an OOM condition or IO error), an appropriate SQLite error code is
8194 ** returned.
8195 **
8196 ** This function may be quite inefficient if used with an FTS5 table
8197 ** created with the "columnsize=0" option.
8198 **
8199 ** xColumnText:
8200 ** This function attempts to retrieve the text of column iCol of the
8201 ** current document. If successful, (*pz) is set to point to a buffer
8202 ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
8203 ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
@@ -8205,18 +8214,32 @@
8214 ** xInstCount:
8215 ** Set *pnInst to the total number of occurrences of all phrases within
8216 ** the query within the current row. Return SQLITE_OK if successful, or
8217 ** an error code (i.e. SQLITE_NOMEM) if an error occurs.
8218 **
8219 ** This API can be quite slow if used with an FTS5 table created with the
8220 ** "detail=none" or "detail=column" option. If the FTS5 table is created
8221 ** with either "detail=none" or "detail=column" and "content=" option
8222 ** (i.e. if it is a contentless table), then this API always returns 0.
8223 **
8224 ** xInst:
8225 ** Query for the details of phrase match iIdx within the current row.
8226 ** Phrase matches are numbered starting from zero, so the iIdx argument
8227 ** should be greater than or equal to zero and smaller than the value
8228 ** output by xInstCount().
8229 **
8230 ** Usually, output parameter *piPhrase is set to the phrase number, *piCol
8231 ** to the column in which it occurs and *piOff the token offset of the
8232 ** first token of the phrase. The exception is if the table was created
8233 ** with the offsets=0 option specified. In this case *piOff is always
8234 ** set to -1.
8235 **
8236 ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
8237 ** if an error occurs.
8238 **
8239 ** This API can be quite slow if used with an FTS5 table created with the
8240 ** "detail=none" or "detail=column" option.
8241 **
8242 ** xRowid:
8243 ** Returns the rowid of the current row.
8244 **
8245 ** xTokenize:
@@ -8297,25 +8320,63 @@
8320 ** through instances of phrase iPhrase, use the following code:
8321 **
8322 ** Fts5PhraseIter iter;
8323 ** int iCol, iOff;
8324 ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
8325 ** iCol>=0;
8326 ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
8327 ** ){
8328 ** // An instance of phrase iPhrase at offset iOff of column iCol
8329 ** }
8330 **
8331 ** The Fts5PhraseIter structure is defined above. Applications should not
8332 ** modify this structure directly - it should only be used as shown above
8333 ** with the xPhraseFirst() and xPhraseNext() API methods (and by
8334 ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
8335 **
8336 ** This API can be quite slow if used with an FTS5 table created with the
8337 ** "detail=none" or "detail=column" option. If the FTS5 table is created
8338 ** with either "detail=none" or "detail=column" and "content=" option
8339 ** (i.e. if it is a contentless table), then this API always iterates
8340 ** through an empty set (all calls to xPhraseFirst() set iCol to -1).
8341 **
8342 ** xPhraseNext()
8343 ** See xPhraseFirst above.
8344 **
8345 ** xPhraseFirstColumn()
8346 ** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
8347 ** and xPhraseNext() APIs described above. The difference is that instead
8348 ** of iterating through all instances of a phrase in the current row, these
8349 ** APIs are used to iterate through the set of columns in the current row
8350 ** that contain one or more instances of a specified phrase. For example:
8351 **
8352 ** Fts5PhraseIter iter;
8353 ** int iCol;
8354 ** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
8355 ** iCol>=0;
8356 ** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
8357 ** ){
8358 ** // Column iCol contains at least one instance of phrase iPhrase
8359 ** }
8360 **
8361 ** This API can be quite slow if used with an FTS5 table created with the
8362 ** "detail=none" option. If the FTS5 table is created with either
8363 ** "detail=none" "content=" option (i.e. if it is a contentless table),
8364 ** then this API always iterates through an empty set (all calls to
8365 ** xPhraseFirstColumn() set iCol to -1).
8366 **
8367 ** The information accessed using this API and its companion
8368 ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
8369 ** (or xInst/xInstCount). The chief advantage of this API is that it is
8370 ** significantly more efficient than those alternatives when used with
8371 ** "detail=column" tables.
8372 **
8373 ** xPhraseNextColumn()
8374 ** See xPhraseFirstColumn above.
8375 */
8376 struct Fts5ExtensionApi {
8377 int iVersion; /* Currently always set to 3 */
8378
8379 void *(*xUserData)(Fts5Context*);
8380
8381 int (*xColumnCount)(Fts5Context*);
8382 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -8341,12 +8402,15 @@
8402 int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
8403 );
8404 int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
8405 void *(*xGetAuxdata)(Fts5Context*, int bClear);
8406
8407 int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
8408 void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
8409
8410 int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
8411 void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
8412 };
8413
8414 /*
8415 ** CUSTOM AUXILIARY FUNCTIONS
8416 *************************************************************************/
8417
+20 -17
--- src/statrep.c
+++ src/statrep.c
@@ -1,7 +1,7 @@
11
/*
2
-** Copyright (c) 2013 Stephen Beal
2
+** Copyright (c) 2013 Stephan Beal
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
77
@@ -241,10 +241,11 @@
241241
rowClass = ++nRowNumber % 2;
242242
@ <tr class='row%d(rowClass)'>
243243
@ <td></td>
244244
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
245245
@</tr>
246
+ showYearTotal = 0;
246247
}
247248
nEventsPerYear = 0;
248249
memcpy(zPrevYear,zTimeframe,4);
249250
rowClass = ++nRowNumber % 2;
250251
@ <tr class='row%d(rowClass)'>
@@ -334,12 +335,12 @@
334335
all rows. */
335336
stats_report_init_view();
336337
@ <h1>Timeline Events
337338
@ (%s(stats_report_label_for_type())) by User</h1>
338339
db_multi_exec(
339
- "CREATE TEMP TABLE piechart(amt,label);"
340
- "INSERT INTO piechart SELECT count(*), ifnull(euser,user) FROM v_reports"
340
+ "CREATE TEMP VIEW piechart(amt,label) AS"
341
+ " SELECT count(*), ifnull(euser,user) FROM v_reports"
341342
" GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
342343
);
343344
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
344345
@ <center><svg width=700 height=400>
345346
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@@ -482,24 +483,26 @@
482483
if( zUserName ){
483484
@ for user %h(zUserName)
484485
}
485486
@ </h1>
486487
db_multi_exec(
487
- "CREATE TEMP TABLE piechart(amt,label);"
488
- "INSERT INTO piechart"
489
- " SELECT count(*), cast(strftime('%%w', mtime) AS INT) FROM v_reports"
490
- " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
491
- " GROUP BY 2 ORDER BY 2;"
492
- "UPDATE piechart SET label = CASE label"
493
- " WHEN 0 THEN 'Sunday'"
494
- " WHEN 1 THEN 'Monday'"
495
- " WHEN 2 THEN 'Tuesday'"
496
- " WHEN 3 THEN 'Wednesday'"
497
- " WHEN 4 THEN 'Thursday'"
498
- " WHEN 5 THEN 'Friday'"
499
- " WHEN 6 THEN 'Saturday'"
500
- " ELSE 'ERROR' END;", zUserName
488
+ "CREATE TEMP VIEW piechart(amt,label) AS"
489
+ " SELECT count(*),"
490
+ " CASE cast(strftime('%%w', mtime) AS INT)"
491
+ " WHEN 0 THEN 'Sunday'"
492
+ " WHEN 1 THEN 'Monday'"
493
+ " WHEN 2 THEN 'Tuesday'"
494
+ " WHEN 3 THEN 'Wednesday'"
495
+ " WHEN 4 THEN 'Thursday'"
496
+ " WHEN 5 THEN 'Friday'"
497
+ " WHEN 6 THEN 'Saturday'"
498
+ " ELSE 'ERROR'"
499
+ " END"
500
+ " FROM v_reports"
501
+ " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
502
+ " GROUP BY 2 ORDER BY cast(strftime('%%w', mtime) AS INT);"
503
+ , zUserName
501504
);
502505
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
503506
@ <center><svg width=700 height=400>
504507
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
505508
@ </svg></centre><hr/>
506509
--- src/statrep.c
+++ src/statrep.c
@@ -1,7 +1,7 @@
1 /*
2 ** Copyright (c) 2013 Stephen Beal
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
@@ -241,10 +241,11 @@
241 rowClass = ++nRowNumber % 2;
242 @ <tr class='row%d(rowClass)'>
243 @ <td></td>
244 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
245 @</tr>
 
246 }
247 nEventsPerYear = 0;
248 memcpy(zPrevYear,zTimeframe,4);
249 rowClass = ++nRowNumber % 2;
250 @ <tr class='row%d(rowClass)'>
@@ -334,12 +335,12 @@
334 all rows. */
335 stats_report_init_view();
336 @ <h1>Timeline Events
337 @ (%s(stats_report_label_for_type())) by User</h1>
338 db_multi_exec(
339 "CREATE TEMP TABLE piechart(amt,label);"
340 "INSERT INTO piechart SELECT count(*), ifnull(euser,user) FROM v_reports"
341 " GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
342 );
343 if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
344 @ <center><svg width=700 height=400>
345 piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@@ -482,24 +483,26 @@
482 if( zUserName ){
483 @ for user %h(zUserName)
484 }
485 @ </h1>
486 db_multi_exec(
487 "CREATE TEMP TABLE piechart(amt,label);"
488 "INSERT INTO piechart"
489 " SELECT count(*), cast(strftime('%%w', mtime) AS INT) FROM v_reports"
490 " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
491 " GROUP BY 2 ORDER BY 2;"
492 "UPDATE piechart SET label = CASE label"
493 " WHEN 0 THEN 'Sunday'"
494 " WHEN 1 THEN 'Monday'"
495 " WHEN 2 THEN 'Tuesday'"
496 " WHEN 3 THEN 'Wednesday'"
497 " WHEN 4 THEN 'Thursday'"
498 " WHEN 5 THEN 'Friday'"
499 " WHEN 6 THEN 'Saturday'"
500 " ELSE 'ERROR' END;", zUserName
 
 
501 );
502 if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
503 @ <center><svg width=700 height=400>
504 piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
505 @ </svg></centre><hr/>
506
--- src/statrep.c
+++ src/statrep.c
@@ -1,7 +1,7 @@
1 /*
2 ** Copyright (c) 2013 Stephan Beal
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
@@ -241,10 +241,11 @@
241 rowClass = ++nRowNumber % 2;
242 @ <tr class='row%d(rowClass)'>
243 @ <td></td>
244 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
245 @</tr>
246 showYearTotal = 0;
247 }
248 nEventsPerYear = 0;
249 memcpy(zPrevYear,zTimeframe,4);
250 rowClass = ++nRowNumber % 2;
251 @ <tr class='row%d(rowClass)'>
@@ -334,12 +335,12 @@
335 all rows. */
336 stats_report_init_view();
337 @ <h1>Timeline Events
338 @ (%s(stats_report_label_for_type())) by User</h1>
339 db_multi_exec(
340 "CREATE TEMP VIEW piechart(amt,label) AS"
341 " SELECT count(*), ifnull(euser,user) FROM v_reports"
342 " GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
343 );
344 if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
345 @ <center><svg width=700 height=400>
346 piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@@ -482,24 +483,26 @@
483 if( zUserName ){
484 @ for user %h(zUserName)
485 }
486 @ </h1>
487 db_multi_exec(
488 "CREATE TEMP VIEW piechart(amt,label) AS"
489 " SELECT count(*),"
490 " CASE cast(strftime('%%w', mtime) AS INT)"
491 " WHEN 0 THEN 'Sunday'"
492 " WHEN 1 THEN 'Monday'"
493 " WHEN 2 THEN 'Tuesday'"
494 " WHEN 3 THEN 'Wednesday'"
495 " WHEN 4 THEN 'Thursday'"
496 " WHEN 5 THEN 'Friday'"
497 " WHEN 6 THEN 'Saturday'"
498 " ELSE 'ERROR'"
499 " END"
500 " FROM v_reports"
501 " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
502 " GROUP BY 2 ORDER BY cast(strftime('%%w', mtime) AS INT);"
503 , zUserName
504 );
505 if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
506 @ <center><svg width=700 height=400>
507 piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
508 @ </svg></centre><hr/>
509
+80 -2
--- src/th.c
+++ src/th.c
@@ -6,10 +6,30 @@
66
77
#include "config.h"
88
#include "th.h"
99
#include <string.h>
1010
#include <assert.h>
11
+
12
+/*
13
+** Values used for element values in the tcl_platform array.
14
+*/
15
+
16
+#if !defined(TH_ENGINE)
17
+# define TH_ENGINE "TH1"
18
+#endif
19
+
20
+#if !defined(TH_PLATFORM)
21
+# if defined(_WIN32) || defined(WIN32)
22
+# define TH_PLATFORM "windows"
23
+# else
24
+# define TH_PLATFORM "unix"
25
+# endif
26
+#endif
27
+
28
+/*
29
+** Forward declarations for structures defined below.
30
+*/
1131
1232
typedef struct Th_Command Th_Command;
1333
typedef struct Th_Frame Th_Frame;
1434
typedef struct Th_Variable Th_Variable;
1535
typedef struct Th_InterpAndList Th_InterpAndList;
@@ -1231,10 +1251,18 @@
12311251
*/
12321252
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
12331253
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
12341254
return pValue && (pValue->zData || pValue->pHash);
12351255
}
1256
+
1257
+/*
1258
+** Return true if array variable (zVar, nVar) exists.
1259
+*/
1260
+int Th_ExistsArrayVar(Th_Interp *interp, const char *zVar, int nVar){
1261
+ Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
1262
+ return pValue && !pValue->zData && pValue->pHash;
1263
+}
12361264
12371265
/*
12381266
** String (zVar, nVar) must contain the name of a scalar variable or
12391267
** array member. If the variable does not exist it is created. The
12401268
** variable is set to the value supplied in string (zValue, nValue).
@@ -1756,10 +1784,22 @@
17561784
*pzStr = zNew;
17571785
*pnStr = nNew;
17581786
17591787
return TH_OK;
17601788
}
1789
+
1790
+/*
1791
+** Initialize an interpreter.
1792
+*/
1793
+static int thInitialize(Th_Interp *interp){
1794
+ assert(interp->pFrame);
1795
+
1796
+ Th_SetVar(interp, (char *)"::tcl_platform(engine)", -1, TH_ENGINE, -1);
1797
+ Th_SetVar(interp, (char *)"::tcl_platform(platform)", -1, TH_PLATFORM, -1);
1798
+
1799
+ return TH_OK;
1800
+}
17611801
17621802
/*
17631803
** Delete an interpreter.
17641804
*/
17651805
void Th_DeleteInterp(Th_Interp *interp){
@@ -1790,10 +1830,11 @@
17901830
p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
17911831
memset(p, 0, sizeof(Th_Interp));
17921832
p->pVtab = pVtab;
17931833
p->paCmd = Th_HashNew(p);
17941834
thPushFrame(p, (Th_Frame *)&p[1]);
1835
+ thInitialize(p);
17951836
17961837
return p;
17971838
}
17981839
17991840
/*
@@ -2865,11 +2906,15 @@
28652906
/*
28662907
** Appends all currently registered command names to the specified list
28672908
** and returns TH_OK upon success. Any other return value indicates an
28682909
** error.
28692910
*/
2870
-int Th_ListAppendCommands(Th_Interp *interp, char **pzList, int *pnList){
2911
+int Th_ListAppendCommands(
2912
+ Th_Interp *interp, /* Interpreter context */
2913
+ char **pzList, /* OUT: List of command names */
2914
+ int *pnList /* OUT: Number of command names */
2915
+){
28712916
Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
28722917
interp, sizeof(Th_InterpAndList)
28732918
);
28742919
p->interp = interp;
28752920
p->pzList = pzList;
@@ -2882,11 +2927,15 @@
28822927
/*
28832928
** Appends all variable names for the current frame to the specified list
28842929
** and returns TH_OK upon success. Any other return value indicates an
28852930
** error. If the current frame cannot be obtained, TH_ERROR is returned.
28862931
*/
2887
-int Th_ListAppendVariables(Th_Interp *interp, char **pzList, int *pnList){
2932
+int Th_ListAppendVariables(
2933
+ Th_Interp *interp, /* Interpreter context */
2934
+ char **pzList, /* OUT: List of variable names */
2935
+ int *pnList /* OUT: Number of variable names */
2936
+){
28882937
Th_Frame *pFrame = getFrame(interp, 0);
28892938
if( pFrame ){
28902939
Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
28912940
interp, sizeof(Th_InterpAndList)
28922941
);
@@ -2898,5 +2947,34 @@
28982947
return TH_OK;
28992948
}else{
29002949
return TH_ERROR;
29012950
}
29022951
}
2952
+
2953
+/*
2954
+** Appends all array element names for the specified array variable to the
2955
+** specified list and returns TH_OK upon success. Any other return value
2956
+** indicates an error.
2957
+*/
2958
+int Th_ListAppendArray(
2959
+ Th_Interp *interp, /* Interpreter context */
2960
+ const char *zVar, /* Pointer to variable name */
2961
+ int nVar, /* Number of bytes at nVar */
2962
+ char **pzList, /* OUT: List of array element names */
2963
+ int *pnList /* OUT: Number of array element names */
2964
+){
2965
+ Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
2966
+ if( pValue && !pValue->zData && pValue->pHash ){
2967
+ Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
2968
+ interp, sizeof(Th_InterpAndList)
2969
+ );
2970
+ p->interp = interp;
2971
+ p->pzList = pzList;
2972
+ p->pnList = pnList;
2973
+ Th_HashIterate(interp, pValue->pHash, thListAppendHashKey, p);
2974
+ Th_Free(interp, p);
2975
+ }else{
2976
+ *pzList = 0;
2977
+ *pnList = 0;
2978
+ }
2979
+ return TH_OK;
2980
+}
29032981
--- src/th.c
+++ src/th.c
@@ -6,10 +6,30 @@
6
7 #include "config.h"
8 #include "th.h"
9 #include <string.h>
10 #include <assert.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
12 typedef struct Th_Command Th_Command;
13 typedef struct Th_Frame Th_Frame;
14 typedef struct Th_Variable Th_Variable;
15 typedef struct Th_InterpAndList Th_InterpAndList;
@@ -1231,10 +1251,18 @@
1231 */
1232 int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
1233 Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
1234 return pValue && (pValue->zData || pValue->pHash);
1235 }
 
 
 
 
 
 
 
 
1236
1237 /*
1238 ** String (zVar, nVar) must contain the name of a scalar variable or
1239 ** array member. If the variable does not exist it is created. The
1240 ** variable is set to the value supplied in string (zValue, nValue).
@@ -1756,10 +1784,22 @@
1756 *pzStr = zNew;
1757 *pnStr = nNew;
1758
1759 return TH_OK;
1760 }
 
 
 
 
 
 
 
 
 
 
 
 
1761
1762 /*
1763 ** Delete an interpreter.
1764 */
1765 void Th_DeleteInterp(Th_Interp *interp){
@@ -1790,10 +1830,11 @@
1790 p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
1791 memset(p, 0, sizeof(Th_Interp));
1792 p->pVtab = pVtab;
1793 p->paCmd = Th_HashNew(p);
1794 thPushFrame(p, (Th_Frame *)&p[1]);
 
1795
1796 return p;
1797 }
1798
1799 /*
@@ -2865,11 +2906,15 @@
2865 /*
2866 ** Appends all currently registered command names to the specified list
2867 ** and returns TH_OK upon success. Any other return value indicates an
2868 ** error.
2869 */
2870 int Th_ListAppendCommands(Th_Interp *interp, char **pzList, int *pnList){
 
 
 
 
2871 Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
2872 interp, sizeof(Th_InterpAndList)
2873 );
2874 p->interp = interp;
2875 p->pzList = pzList;
@@ -2882,11 +2927,15 @@
2882 /*
2883 ** Appends all variable names for the current frame to the specified list
2884 ** and returns TH_OK upon success. Any other return value indicates an
2885 ** error. If the current frame cannot be obtained, TH_ERROR is returned.
2886 */
2887 int Th_ListAppendVariables(Th_Interp *interp, char **pzList, int *pnList){
 
 
 
 
2888 Th_Frame *pFrame = getFrame(interp, 0);
2889 if( pFrame ){
2890 Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
2891 interp, sizeof(Th_InterpAndList)
2892 );
@@ -2898,5 +2947,34 @@
2898 return TH_OK;
2899 }else{
2900 return TH_ERROR;
2901 }
2902 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2903
--- src/th.c
+++ src/th.c
@@ -6,10 +6,30 @@
6
7 #include "config.h"
8 #include "th.h"
9 #include <string.h>
10 #include <assert.h>
11
12 /*
13 ** Values used for element values in the tcl_platform array.
14 */
15
16 #if !defined(TH_ENGINE)
17 # define TH_ENGINE "TH1"
18 #endif
19
20 #if !defined(TH_PLATFORM)
21 # if defined(_WIN32) || defined(WIN32)
22 # define TH_PLATFORM "windows"
23 # else
24 # define TH_PLATFORM "unix"
25 # endif
26 #endif
27
28 /*
29 ** Forward declarations for structures defined below.
30 */
31
32 typedef struct Th_Command Th_Command;
33 typedef struct Th_Frame Th_Frame;
34 typedef struct Th_Variable Th_Variable;
35 typedef struct Th_InterpAndList Th_InterpAndList;
@@ -1231,10 +1251,18 @@
1251 */
1252 int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
1253 Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
1254 return pValue && (pValue->zData || pValue->pHash);
1255 }
1256
1257 /*
1258 ** Return true if array variable (zVar, nVar) exists.
1259 */
1260 int Th_ExistsArrayVar(Th_Interp *interp, const char *zVar, int nVar){
1261 Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
1262 return pValue && !pValue->zData && pValue->pHash;
1263 }
1264
1265 /*
1266 ** String (zVar, nVar) must contain the name of a scalar variable or
1267 ** array member. If the variable does not exist it is created. The
1268 ** variable is set to the value supplied in string (zValue, nValue).
@@ -1756,10 +1784,22 @@
1784 *pzStr = zNew;
1785 *pnStr = nNew;
1786
1787 return TH_OK;
1788 }
1789
1790 /*
1791 ** Initialize an interpreter.
1792 */
1793 static int thInitialize(Th_Interp *interp){
1794 assert(interp->pFrame);
1795
1796 Th_SetVar(interp, (char *)"::tcl_platform(engine)", -1, TH_ENGINE, -1);
1797 Th_SetVar(interp, (char *)"::tcl_platform(platform)", -1, TH_PLATFORM, -1);
1798
1799 return TH_OK;
1800 }
1801
1802 /*
1803 ** Delete an interpreter.
1804 */
1805 void Th_DeleteInterp(Th_Interp *interp){
@@ -1790,10 +1830,11 @@
1830 p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
1831 memset(p, 0, sizeof(Th_Interp));
1832 p->pVtab = pVtab;
1833 p->paCmd = Th_HashNew(p);
1834 thPushFrame(p, (Th_Frame *)&p[1]);
1835 thInitialize(p);
1836
1837 return p;
1838 }
1839
1840 /*
@@ -2865,11 +2906,15 @@
2906 /*
2907 ** Appends all currently registered command names to the specified list
2908 ** and returns TH_OK upon success. Any other return value indicates an
2909 ** error.
2910 */
2911 int Th_ListAppendCommands(
2912 Th_Interp *interp, /* Interpreter context */
2913 char **pzList, /* OUT: List of command names */
2914 int *pnList /* OUT: Number of command names */
2915 ){
2916 Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
2917 interp, sizeof(Th_InterpAndList)
2918 );
2919 p->interp = interp;
2920 p->pzList = pzList;
@@ -2882,11 +2927,15 @@
2927 /*
2928 ** Appends all variable names for the current frame to the specified list
2929 ** and returns TH_OK upon success. Any other return value indicates an
2930 ** error. If the current frame cannot be obtained, TH_ERROR is returned.
2931 */
2932 int Th_ListAppendVariables(
2933 Th_Interp *interp, /* Interpreter context */
2934 char **pzList, /* OUT: List of variable names */
2935 int *pnList /* OUT: Number of variable names */
2936 ){
2937 Th_Frame *pFrame = getFrame(interp, 0);
2938 if( pFrame ){
2939 Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
2940 interp, sizeof(Th_InterpAndList)
2941 );
@@ -2898,5 +2947,34 @@
2947 return TH_OK;
2948 }else{
2949 return TH_ERROR;
2950 }
2951 }
2952
2953 /*
2954 ** Appends all array element names for the specified array variable to the
2955 ** specified list and returns TH_OK upon success. Any other return value
2956 ** indicates an error.
2957 */
2958 int Th_ListAppendArray(
2959 Th_Interp *interp, /* Interpreter context */
2960 const char *zVar, /* Pointer to variable name */
2961 int nVar, /* Number of bytes at nVar */
2962 char **pzList, /* OUT: List of array element names */
2963 int *pnList /* OUT: Number of array element names */
2964 ){
2965 Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
2966 if( pValue && !pValue->zData && pValue->pHash ){
2967 Th_InterpAndList *p = (Th_InterpAndList *)Th_Malloc(
2968 interp, sizeof(Th_InterpAndList)
2969 );
2970 p->interp = interp;
2971 p->pzList = pzList;
2972 p->pnList = pnList;
2973 Th_HashIterate(interp, pValue->pHash, thListAppendHashKey, p);
2974 Th_Free(interp, p);
2975 }else{
2976 *pzList = 0;
2977 *pnList = 0;
2978 }
2979 return TH_OK;
2980 }
2981
+2
--- src/th.h
+++ src/th.h
@@ -50,10 +50,11 @@
5050
/*
5151
** Access TH variables in the current stack frame. If the variable name
5252
** begins with "::", the lookup is in the top level (global) frame.
5353
*/
5454
int Th_ExistsVar(Th_Interp *, const char *, int);
55
+int Th_ExistsArrayVar(Th_Interp *, const char *, int);
5556
int Th_GetVar(Th_Interp *, const char *, int);
5657
int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
5758
int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
5859
int Th_UnsetVar(Th_Interp *, const char *, int);
5960
@@ -143,10 +144,11 @@
143144
/*
144145
** Functions for handling command and variable introspection.
145146
*/
146147
int Th_ListAppendCommands(Th_Interp *, char **, int *);
147148
int Th_ListAppendVariables(Th_Interp *, char **, int *);
149
+int Th_ListAppendArray(Th_Interp *, const char *, int, char **, int *);
148150
149151
/*
150152
** Drop in replacements for the corresponding standard library functions.
151153
*/
152154
int th_strlen(const char *);
153155
--- src/th.h
+++ src/th.h
@@ -50,10 +50,11 @@
50 /*
51 ** Access TH variables in the current stack frame. If the variable name
52 ** begins with "::", the lookup is in the top level (global) frame.
53 */
54 int Th_ExistsVar(Th_Interp *, const char *, int);
 
55 int Th_GetVar(Th_Interp *, const char *, int);
56 int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
57 int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
58 int Th_UnsetVar(Th_Interp *, const char *, int);
59
@@ -143,10 +144,11 @@
143 /*
144 ** Functions for handling command and variable introspection.
145 */
146 int Th_ListAppendCommands(Th_Interp *, char **, int *);
147 int Th_ListAppendVariables(Th_Interp *, char **, int *);
 
148
149 /*
150 ** Drop in replacements for the corresponding standard library functions.
151 */
152 int th_strlen(const char *);
153
--- src/th.h
+++ src/th.h
@@ -50,10 +50,11 @@
50 /*
51 ** Access TH variables in the current stack frame. If the variable name
52 ** begins with "::", the lookup is in the top level (global) frame.
53 */
54 int Th_ExistsVar(Th_Interp *, const char *, int);
55 int Th_ExistsArrayVar(Th_Interp *, const char *, int);
56 int Th_GetVar(Th_Interp *, const char *, int);
57 int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
58 int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
59 int Th_UnsetVar(Th_Interp *, const char *, int);
60
@@ -143,10 +144,11 @@
144 /*
145 ** Functions for handling command and variable introspection.
146 */
147 int Th_ListAppendCommands(Th_Interp *, char **, int *);
148 int Th_ListAppendVariables(Th_Interp *, char **, int *);
149 int Th_ListAppendArray(Th_Interp *, const char *, int, char **, int *);
150
151 /*
152 ** Drop in replacements for the corresponding standard library functions.
153 */
154 int th_strlen(const char *);
155
+65 -1
--- src/th_lang.c
+++ src/th_lang.c
@@ -972,11 +972,53 @@
972972
}
973973
974974
/*
975975
** TH Syntax:
976976
**
977
-** unset VAR
977
+** array exists VARNAME
978
+*/
979
+static int array_exists_command(
980
+ Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
981
+){
982
+ int rc;
983
+
984
+ if( argc!=3 ){
985
+ return Th_WrongNumArgs(interp, "array exists var");
986
+ }
987
+ rc = Th_ExistsArrayVar(interp, argv[2], argl[2]);
988
+ Th_SetResultInt(interp, rc);
989
+ return TH_OK;
990
+}
991
+
992
+/*
993
+** TH Syntax:
994
+**
995
+** array names VARNAME
996
+*/
997
+static int array_names_command(
998
+ Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
999
+){
1000
+ int rc;
1001
+ char *zElem = 0;
1002
+ int nElem = 0;
1003
+
1004
+ if( argc!=3 ){
1005
+ return Th_WrongNumArgs(interp, "array names varname");
1006
+ }
1007
+ rc = Th_ListAppendArray(interp, argv[2], argl[2], &zElem, &nElem);
1008
+ if( rc!=TH_OK ){
1009
+ return rc;
1010
+ }
1011
+ Th_SetResult(interp, zElem, nElem);
1012
+ if( zElem ) Th_Free(interp, zElem);
1013
+ return TH_OK;
1014
+}
1015
+
1016
+/*
1017
+** TH Syntax:
1018
+**
1019
+** unset VARNAME
9781020
*/
9791021
static int unset_command(
9801022
Th_Interp *interp,
9811023
void *ctx,
9821024
int argc,
@@ -1065,10 +1107,31 @@
10651107
static const Th_SubCommand aSub[] = {
10661108
{ "commands", info_commands_command },
10671109
{ "exists", info_exists_command },
10681110
{ "vars", info_vars_command },
10691111
{ 0, 0 }
1112
+ };
1113
+ return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1114
+}
1115
+
1116
+/*
1117
+** TH Syntax:
1118
+**
1119
+** array exists VARNAME
1120
+** array names VARNAME
1121
+*/
1122
+static int array_command(
1123
+ Th_Interp *interp,
1124
+ void *ctx,
1125
+ int argc,
1126
+ const char **argv,
1127
+ int *argl
1128
+){
1129
+ static const Th_SubCommand aSub[] = {
1130
+ { "exists", array_exists_command },
1131
+ { "names", array_names_command },
1132
+ { 0, 0 }
10701133
};
10711134
return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
10721135
}
10731136
10741137
/*
@@ -1182,10 +1245,11 @@
11821245
struct _Command {
11831246
const char *zName;
11841247
Th_CommandProc xProc;
11851248
void *pContext;
11861249
} aCommand[] = {
1250
+ {"array", array_command, 0},
11871251
{"catch", catch_command, 0},
11881252
{"expr", expr_command, 0},
11891253
{"for", for_command, 0},
11901254
{"if", if_command, 0},
11911255
{"info", info_command, 0},
11921256
--- src/th_lang.c
+++ src/th_lang.c
@@ -972,11 +972,53 @@
972 }
973
974 /*
975 ** TH Syntax:
976 **
977 ** unset VAR
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
978 */
979 static int unset_command(
980 Th_Interp *interp,
981 void *ctx,
982 int argc,
@@ -1065,10 +1107,31 @@
1065 static const Th_SubCommand aSub[] = {
1066 { "commands", info_commands_command },
1067 { "exists", info_exists_command },
1068 { "vars", info_vars_command },
1069 { 0, 0 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1070 };
1071 return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1072 }
1073
1074 /*
@@ -1182,10 +1245,11 @@
1182 struct _Command {
1183 const char *zName;
1184 Th_CommandProc xProc;
1185 void *pContext;
1186 } aCommand[] = {
 
1187 {"catch", catch_command, 0},
1188 {"expr", expr_command, 0},
1189 {"for", for_command, 0},
1190 {"if", if_command, 0},
1191 {"info", info_command, 0},
1192
--- src/th_lang.c
+++ src/th_lang.c
@@ -972,11 +972,53 @@
972 }
973
974 /*
975 ** TH Syntax:
976 **
977 ** array exists VARNAME
978 */
979 static int array_exists_command(
980 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
981 ){
982 int rc;
983
984 if( argc!=3 ){
985 return Th_WrongNumArgs(interp, "array exists var");
986 }
987 rc = Th_ExistsArrayVar(interp, argv[2], argl[2]);
988 Th_SetResultInt(interp, rc);
989 return TH_OK;
990 }
991
992 /*
993 ** TH Syntax:
994 **
995 ** array names VARNAME
996 */
997 static int array_names_command(
998 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
999 ){
1000 int rc;
1001 char *zElem = 0;
1002 int nElem = 0;
1003
1004 if( argc!=3 ){
1005 return Th_WrongNumArgs(interp, "array names varname");
1006 }
1007 rc = Th_ListAppendArray(interp, argv[2], argl[2], &zElem, &nElem);
1008 if( rc!=TH_OK ){
1009 return rc;
1010 }
1011 Th_SetResult(interp, zElem, nElem);
1012 if( zElem ) Th_Free(interp, zElem);
1013 return TH_OK;
1014 }
1015
1016 /*
1017 ** TH Syntax:
1018 **
1019 ** unset VARNAME
1020 */
1021 static int unset_command(
1022 Th_Interp *interp,
1023 void *ctx,
1024 int argc,
@@ -1065,10 +1107,31 @@
1107 static const Th_SubCommand aSub[] = {
1108 { "commands", info_commands_command },
1109 { "exists", info_exists_command },
1110 { "vars", info_vars_command },
1111 { 0, 0 }
1112 };
1113 return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1114 }
1115
1116 /*
1117 ** TH Syntax:
1118 **
1119 ** array exists VARNAME
1120 ** array names VARNAME
1121 */
1122 static int array_command(
1123 Th_Interp *interp,
1124 void *ctx,
1125 int argc,
1126 const char **argv,
1127 int *argl
1128 ){
1129 static const Th_SubCommand aSub[] = {
1130 { "exists", array_exists_command },
1131 { "names", array_names_command },
1132 { 0, 0 }
1133 };
1134 return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1135 }
1136
1137 /*
@@ -1182,10 +1245,11 @@
1245 struct _Command {
1246 const char *zName;
1247 Th_CommandProc xProc;
1248 void *pContext;
1249 } aCommand[] = {
1250 {"array", array_command, 0},
1251 {"catch", catch_command, 0},
1252 {"expr", expr_command, 0},
1253 {"for", for_command, 0},
1254 {"if", if_command, 0},
1255 {"info", info_command, 0},
1256
+115 -3
--- src/th_main.c
+++ src/th_main.c
@@ -430,10 +430,74 @@
430430
return Th_WrongNumArgs(interp, "puts STRING");
431431
}
432432
sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert);
433433
return TH_OK;
434434
}
435
+
436
+/*
437
+** TH1 command: redirect URL
438
+**
439
+** Issues an HTTP redirect (302) to the specified URL and then exits the
440
+** process.
441
+*/
442
+static int redirectCmd(
443
+ Th_Interp *interp,
444
+ void *p,
445
+ int argc,
446
+ const char **argv,
447
+ int *argl
448
+){
449
+ if( argc!=2 ){
450
+ return Th_WrongNumArgs(interp, "redirect URL");
451
+ }
452
+ cgi_redirect(argv[1]);
453
+ Th_SetResult(interp, argv[1], argl[1]); /* NOT REACHED */
454
+ return TH_OK;
455
+}
456
+
457
+/*
458
+** TH1 command: insertCsrf
459
+**
460
+** While rendering a form, call this command to add the Anti-CSRF token
461
+** as a hidden element of the form.
462
+*/
463
+static int insertCsrfCmd(
464
+ Th_Interp *interp,
465
+ void *p,
466
+ int argc,
467
+ const char **argv,
468
+ int *argl
469
+){
470
+ if( argc!=1 ){
471
+ return Th_WrongNumArgs(interp, "insertCsrf");
472
+ }
473
+ login_insert_csrf_secret();
474
+ return TH_OK;
475
+}
476
+
477
+/*
478
+** TH1 command: verifyCsrf
479
+**
480
+** Before using the results of a form, first call this command to verify
481
+** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
482
+** is missing or is incorrect, that indicates a cross-site scripting attack.
483
+** If the event of an attack is detected, an error message is generated and
484
+** all further processing is aborted.
485
+*/
486
+static int verifyCsrfCmd(
487
+ Th_Interp *interp,
488
+ void *p,
489
+ int argc,
490
+ const char **argv,
491
+ int *argl
492
+){
493
+ if( argc!=1 ){
494
+ return Th_WrongNumArgs(interp, "verifyCsrf");
495
+ }
496
+ login_verify_csrf_secret();
497
+ return TH_OK;
498
+}
435499
436500
/*
437501
** TH1 command: markdown STRING
438502
**
439503
** Renders the input string as markdown. The result is a two-element list.
@@ -1767,15 +1831,17 @@
17671831
{"hascap", hascapCmd, (void*)&zeroInt},
17681832
{"hasfeature", hasfeatureCmd, 0},
17691833
{"html", putsCmd, (void*)&aFlags[0]},
17701834
{"htmlize", htmlizeCmd, 0},
17711835
{"http", httpCmd, 0},
1836
+ {"insertCsrf", insertCsrfCmd, 0},
17721837
{"linecount", linecntCmd, 0},
17731838
{"markdown", markdownCmd, 0},
17741839
{"puts", putsCmd, (void*)&aFlags[1]},
17751840
{"query", queryCmd, 0},
17761841
{"randhex", randhexCmd, 0},
1842
+ {"redirect", redirectCmd, 0},
17771843
{"regexp", regexpCmd, 0},
17781844
{"reinitialize", reinitializeCmd, 0},
17791845
{"render", renderCmd, 0},
17801846
{"repository", repositoryCmd, 0},
17811847
{"searchable", searchableCmd, 0},
@@ -1785,10 +1851,11 @@
17851851
{"styleFooter", styleFooterCmd, 0},
17861852
{"tclReady", tclReadyCmd, 0},
17871853
{"trace", traceCmd, 0},
17881854
{"stime", stimeCmd, 0},
17891855
{"utime", utimeCmd, 0},
1856
+ {"verifyCsrf", verifyCsrfCmd, 0},
17901857
{"wiki", wikiCmd, (void*)&aFlags[0]},
17911858
{0, 0, 0}
17921859
};
17931860
if( g.thTrace ){
17941861
Th_Trace("th1-init 0x%x => 0x%x<br />\n", g.th1Flags, flags);
@@ -2291,11 +2358,11 @@
22912358
** --http Include an HTTP response header in the output
22922359
** --open-config Open the configuration database
22932360
** --th-trace Trace TH1 execution (for debugging purposes)
22942361
*/
22952362
void test_th_render(void){
2296
- int forceCgi = 0, fullHttpReply = 0;
2363
+ int forceCgi, fullHttpReply;
22972364
Blob in;
22982365
Th_InitTraceLog();
22992366
forceCgi = find_option("cgi", 0, 0)!=0;
23002367
fullHttpReply = find_option("http", 0, 0)!=0;
23012368
if( fullHttpReply ) forceCgi = 1;
@@ -2318,11 +2385,11 @@
23182385
** COMMAND: test-th-eval
23192386
**
23202387
** Usage: %fossil test-th-eval SCRIPT
23212388
**
23222389
** Evaluate SCRIPT as if it were a header or footer or ticket rendering
2323
-** script, evaluate it, and show the results on standard output.
2390
+** script and show the results on standard output.
23242391
**
23252392
** Options:
23262393
**
23272394
** --cgi Include a CGI response header in the output
23282395
** --http Include an HTTP response header in the output
@@ -2339,15 +2406,59 @@
23392406
if( fullHttpReply ) forceCgi = 1;
23402407
if( forceCgi ) Th_ForceCgi(fullHttpReply);
23412408
if( find_option("open-config", 0, 0)!=0 ){
23422409
Th_OpenConfig(1);
23432410
}
2411
+ verify_all_options();
23442412
if( g.argc!=3 ){
23452413
usage("script");
23462414
}
23472415
Th_FossilInit(TH_INIT_DEFAULT);
23482416
rc = Th_Eval(g.interp, 0, g.argv[2], -1);
2417
+ zRc = Th_ReturnCodeName(rc, 1);
2418
+ fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
2419
+ Th_PrintTraceLog();
2420
+ if( forceCgi ) cgi_reply();
2421
+}
2422
+
2423
+/*
2424
+** COMMAND: test-th-source
2425
+**
2426
+** Usage: %fossil test-th-source FILE
2427
+**
2428
+** Evaluate the contents of the file named "FILE" as if it were a header
2429
+** or footer or ticket rendering script and show the results on standard
2430
+** output.
2431
+**
2432
+** Options:
2433
+**
2434
+** --cgi Include a CGI response header in the output
2435
+** --http Include an HTTP response header in the output
2436
+** --open-config Open the configuration database
2437
+** --th-trace Trace TH1 execution (for debugging purposes)
2438
+*/
2439
+void test_th_source(void){
2440
+ int rc;
2441
+ const char *zRc;
2442
+ int forceCgi, fullHttpReply;
2443
+ Blob in;
2444
+ Th_InitTraceLog();
2445
+ forceCgi = find_option("cgi", 0, 0)!=0;
2446
+ fullHttpReply = find_option("http", 0, 0)!=0;
2447
+ if( fullHttpReply ) forceCgi = 1;
2448
+ if( forceCgi ) Th_ForceCgi(fullHttpReply);
2449
+ if( find_option("open-config", 0, 0)!=0 ){
2450
+ Th_OpenConfig(1);
2451
+ }
2452
+ verify_all_options();
2453
+ if( g.argc!=3 ){
2454
+ usage("file");
2455
+ }
2456
+ blob_zero(&in);
2457
+ blob_read_from_file(&in, g.argv[2]);
2458
+ Th_FossilInit(TH_INIT_DEFAULT);
2459
+ rc = Th_Eval(g.interp, 0, blob_str(&in), -1);
23492460
zRc = Th_ReturnCodeName(rc, 1);
23502461
fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
23512462
Th_PrintTraceLog();
23522463
if( forceCgi ) cgi_reply();
23532464
}
@@ -2356,11 +2467,11 @@
23562467
/*
23572468
** COMMAND: test-th-hook
23582469
**
23592470
** Usage: %fossil test-th-hook TYPE NAME FLAGS
23602471
**
2361
-** Executes the TH1 script configured for the pre-operation (i.e. a command
2472
+** Evaluates the TH1 script configured for the pre-operation (i.e. a command
23622473
** or web page) "hook" or post-operation "notification". The results of the
23632474
** script evaluation, if any, will be printed to the standard output channel.
23642475
** The NAME argument must be the name of a command or web page; however, it
23652476
** does not necessarily have to be a command or web page that is normally
23662477
** recognized by Fossil. The FLAGS argument will be used to set the value
@@ -2397,10 +2508,11 @@
23972508
Th_InitTraceLog();
23982509
forceCgi = find_option("cgi", 0, 0)!=0;
23992510
fullHttpReply = find_option("http", 0, 0)!=0;
24002511
if( fullHttpReply ) forceCgi = 1;
24012512
if( forceCgi ) Th_ForceCgi(fullHttpReply);
2513
+ verify_all_options();
24022514
if( g.argc<5 ){
24032515
usage("TYPE NAME FLAGS");
24042516
}
24052517
if( fossil_stricmp(g.argv[2], "cmdhook")==0 ){
24062518
rc = Th_CommandHook(g.argv[3], (char)atoi(g.argv[4]));
24072519
--- src/th_main.c
+++ src/th_main.c
@@ -430,10 +430,74 @@
430 return Th_WrongNumArgs(interp, "puts STRING");
431 }
432 sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert);
433 return TH_OK;
434 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
436 /*
437 ** TH1 command: markdown STRING
438 **
439 ** Renders the input string as markdown. The result is a two-element list.
@@ -1767,15 +1831,17 @@
1767 {"hascap", hascapCmd, (void*)&zeroInt},
1768 {"hasfeature", hasfeatureCmd, 0},
1769 {"html", putsCmd, (void*)&aFlags[0]},
1770 {"htmlize", htmlizeCmd, 0},
1771 {"http", httpCmd, 0},
 
1772 {"linecount", linecntCmd, 0},
1773 {"markdown", markdownCmd, 0},
1774 {"puts", putsCmd, (void*)&aFlags[1]},
1775 {"query", queryCmd, 0},
1776 {"randhex", randhexCmd, 0},
 
1777 {"regexp", regexpCmd, 0},
1778 {"reinitialize", reinitializeCmd, 0},
1779 {"render", renderCmd, 0},
1780 {"repository", repositoryCmd, 0},
1781 {"searchable", searchableCmd, 0},
@@ -1785,10 +1851,11 @@
1785 {"styleFooter", styleFooterCmd, 0},
1786 {"tclReady", tclReadyCmd, 0},
1787 {"trace", traceCmd, 0},
1788 {"stime", stimeCmd, 0},
1789 {"utime", utimeCmd, 0},
 
1790 {"wiki", wikiCmd, (void*)&aFlags[0]},
1791 {0, 0, 0}
1792 };
1793 if( g.thTrace ){
1794 Th_Trace("th1-init 0x%x => 0x%x<br />\n", g.th1Flags, flags);
@@ -2291,11 +2358,11 @@
2291 ** --http Include an HTTP response header in the output
2292 ** --open-config Open the configuration database
2293 ** --th-trace Trace TH1 execution (for debugging purposes)
2294 */
2295 void test_th_render(void){
2296 int forceCgi = 0, fullHttpReply = 0;
2297 Blob in;
2298 Th_InitTraceLog();
2299 forceCgi = find_option("cgi", 0, 0)!=0;
2300 fullHttpReply = find_option("http", 0, 0)!=0;
2301 if( fullHttpReply ) forceCgi = 1;
@@ -2318,11 +2385,11 @@
2318 ** COMMAND: test-th-eval
2319 **
2320 ** Usage: %fossil test-th-eval SCRIPT
2321 **
2322 ** Evaluate SCRIPT as if it were a header or footer or ticket rendering
2323 ** script, evaluate it, and show the results on standard output.
2324 **
2325 ** Options:
2326 **
2327 ** --cgi Include a CGI response header in the output
2328 ** --http Include an HTTP response header in the output
@@ -2339,15 +2406,59 @@
2339 if( fullHttpReply ) forceCgi = 1;
2340 if( forceCgi ) Th_ForceCgi(fullHttpReply);
2341 if( find_option("open-config", 0, 0)!=0 ){
2342 Th_OpenConfig(1);
2343 }
 
2344 if( g.argc!=3 ){
2345 usage("script");
2346 }
2347 Th_FossilInit(TH_INIT_DEFAULT);
2348 rc = Th_Eval(g.interp, 0, g.argv[2], -1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2349 zRc = Th_ReturnCodeName(rc, 1);
2350 fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
2351 Th_PrintTraceLog();
2352 if( forceCgi ) cgi_reply();
2353 }
@@ -2356,11 +2467,11 @@
2356 /*
2357 ** COMMAND: test-th-hook
2358 **
2359 ** Usage: %fossil test-th-hook TYPE NAME FLAGS
2360 **
2361 ** Executes the TH1 script configured for the pre-operation (i.e. a command
2362 ** or web page) "hook" or post-operation "notification". The results of the
2363 ** script evaluation, if any, will be printed to the standard output channel.
2364 ** The NAME argument must be the name of a command or web page; however, it
2365 ** does not necessarily have to be a command or web page that is normally
2366 ** recognized by Fossil. The FLAGS argument will be used to set the value
@@ -2397,10 +2508,11 @@
2397 Th_InitTraceLog();
2398 forceCgi = find_option("cgi", 0, 0)!=0;
2399 fullHttpReply = find_option("http", 0, 0)!=0;
2400 if( fullHttpReply ) forceCgi = 1;
2401 if( forceCgi ) Th_ForceCgi(fullHttpReply);
 
2402 if( g.argc<5 ){
2403 usage("TYPE NAME FLAGS");
2404 }
2405 if( fossil_stricmp(g.argv[2], "cmdhook")==0 ){
2406 rc = Th_CommandHook(g.argv[3], (char)atoi(g.argv[4]));
2407
--- src/th_main.c
+++ src/th_main.c
@@ -430,10 +430,74 @@
430 return Th_WrongNumArgs(interp, "puts STRING");
431 }
432 sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert);
433 return TH_OK;
434 }
435
436 /*
437 ** TH1 command: redirect URL
438 **
439 ** Issues an HTTP redirect (302) to the specified URL and then exits the
440 ** process.
441 */
442 static int redirectCmd(
443 Th_Interp *interp,
444 void *p,
445 int argc,
446 const char **argv,
447 int *argl
448 ){
449 if( argc!=2 ){
450 return Th_WrongNumArgs(interp, "redirect URL");
451 }
452 cgi_redirect(argv[1]);
453 Th_SetResult(interp, argv[1], argl[1]); /* NOT REACHED */
454 return TH_OK;
455 }
456
457 /*
458 ** TH1 command: insertCsrf
459 **
460 ** While rendering a form, call this command to add the Anti-CSRF token
461 ** as a hidden element of the form.
462 */
463 static int insertCsrfCmd(
464 Th_Interp *interp,
465 void *p,
466 int argc,
467 const char **argv,
468 int *argl
469 ){
470 if( argc!=1 ){
471 return Th_WrongNumArgs(interp, "insertCsrf");
472 }
473 login_insert_csrf_secret();
474 return TH_OK;
475 }
476
477 /*
478 ** TH1 command: verifyCsrf
479 **
480 ** Before using the results of a form, first call this command to verify
481 ** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
482 ** is missing or is incorrect, that indicates a cross-site scripting attack.
483 ** If the event of an attack is detected, an error message is generated and
484 ** all further processing is aborted.
485 */
486 static int verifyCsrfCmd(
487 Th_Interp *interp,
488 void *p,
489 int argc,
490 const char **argv,
491 int *argl
492 ){
493 if( argc!=1 ){
494 return Th_WrongNumArgs(interp, "verifyCsrf");
495 }
496 login_verify_csrf_secret();
497 return TH_OK;
498 }
499
500 /*
501 ** TH1 command: markdown STRING
502 **
503 ** Renders the input string as markdown. The result is a two-element list.
@@ -1767,15 +1831,17 @@
1831 {"hascap", hascapCmd, (void*)&zeroInt},
1832 {"hasfeature", hasfeatureCmd, 0},
1833 {"html", putsCmd, (void*)&aFlags[0]},
1834 {"htmlize", htmlizeCmd, 0},
1835 {"http", httpCmd, 0},
1836 {"insertCsrf", insertCsrfCmd, 0},
1837 {"linecount", linecntCmd, 0},
1838 {"markdown", markdownCmd, 0},
1839 {"puts", putsCmd, (void*)&aFlags[1]},
1840 {"query", queryCmd, 0},
1841 {"randhex", randhexCmd, 0},
1842 {"redirect", redirectCmd, 0},
1843 {"regexp", regexpCmd, 0},
1844 {"reinitialize", reinitializeCmd, 0},
1845 {"render", renderCmd, 0},
1846 {"repository", repositoryCmd, 0},
1847 {"searchable", searchableCmd, 0},
@@ -1785,10 +1851,11 @@
1851 {"styleFooter", styleFooterCmd, 0},
1852 {"tclReady", tclReadyCmd, 0},
1853 {"trace", traceCmd, 0},
1854 {"stime", stimeCmd, 0},
1855 {"utime", utimeCmd, 0},
1856 {"verifyCsrf", verifyCsrfCmd, 0},
1857 {"wiki", wikiCmd, (void*)&aFlags[0]},
1858 {0, 0, 0}
1859 };
1860 if( g.thTrace ){
1861 Th_Trace("th1-init 0x%x => 0x%x<br />\n", g.th1Flags, flags);
@@ -2291,11 +2358,11 @@
2358 ** --http Include an HTTP response header in the output
2359 ** --open-config Open the configuration database
2360 ** --th-trace Trace TH1 execution (for debugging purposes)
2361 */
2362 void test_th_render(void){
2363 int forceCgi, fullHttpReply;
2364 Blob in;
2365 Th_InitTraceLog();
2366 forceCgi = find_option("cgi", 0, 0)!=0;
2367 fullHttpReply = find_option("http", 0, 0)!=0;
2368 if( fullHttpReply ) forceCgi = 1;
@@ -2318,11 +2385,11 @@
2385 ** COMMAND: test-th-eval
2386 **
2387 ** Usage: %fossil test-th-eval SCRIPT
2388 **
2389 ** Evaluate SCRIPT as if it were a header or footer or ticket rendering
2390 ** script and show the results on standard output.
2391 **
2392 ** Options:
2393 **
2394 ** --cgi Include a CGI response header in the output
2395 ** --http Include an HTTP response header in the output
@@ -2339,15 +2406,59 @@
2406 if( fullHttpReply ) forceCgi = 1;
2407 if( forceCgi ) Th_ForceCgi(fullHttpReply);
2408 if( find_option("open-config", 0, 0)!=0 ){
2409 Th_OpenConfig(1);
2410 }
2411 verify_all_options();
2412 if( g.argc!=3 ){
2413 usage("script");
2414 }
2415 Th_FossilInit(TH_INIT_DEFAULT);
2416 rc = Th_Eval(g.interp, 0, g.argv[2], -1);
2417 zRc = Th_ReturnCodeName(rc, 1);
2418 fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
2419 Th_PrintTraceLog();
2420 if( forceCgi ) cgi_reply();
2421 }
2422
2423 /*
2424 ** COMMAND: test-th-source
2425 **
2426 ** Usage: %fossil test-th-source FILE
2427 **
2428 ** Evaluate the contents of the file named "FILE" as if it were a header
2429 ** or footer or ticket rendering script and show the results on standard
2430 ** output.
2431 **
2432 ** Options:
2433 **
2434 ** --cgi Include a CGI response header in the output
2435 ** --http Include an HTTP response header in the output
2436 ** --open-config Open the configuration database
2437 ** --th-trace Trace TH1 execution (for debugging purposes)
2438 */
2439 void test_th_source(void){
2440 int rc;
2441 const char *zRc;
2442 int forceCgi, fullHttpReply;
2443 Blob in;
2444 Th_InitTraceLog();
2445 forceCgi = find_option("cgi", 0, 0)!=0;
2446 fullHttpReply = find_option("http", 0, 0)!=0;
2447 if( fullHttpReply ) forceCgi = 1;
2448 if( forceCgi ) Th_ForceCgi(fullHttpReply);
2449 if( find_option("open-config", 0, 0)!=0 ){
2450 Th_OpenConfig(1);
2451 }
2452 verify_all_options();
2453 if( g.argc!=3 ){
2454 usage("file");
2455 }
2456 blob_zero(&in);
2457 blob_read_from_file(&in, g.argv[2]);
2458 Th_FossilInit(TH_INIT_DEFAULT);
2459 rc = Th_Eval(g.interp, 0, blob_str(&in), -1);
2460 zRc = Th_ReturnCodeName(rc, 1);
2461 fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
2462 Th_PrintTraceLog();
2463 if( forceCgi ) cgi_reply();
2464 }
@@ -2356,11 +2467,11 @@
2467 /*
2468 ** COMMAND: test-th-hook
2469 **
2470 ** Usage: %fossil test-th-hook TYPE NAME FLAGS
2471 **
2472 ** Evaluates the TH1 script configured for the pre-operation (i.e. a command
2473 ** or web page) "hook" or post-operation "notification". The results of the
2474 ** script evaluation, if any, will be printed to the standard output channel.
2475 ** The NAME argument must be the name of a command or web page; however, it
2476 ** does not necessarily have to be a command or web page that is normally
2477 ** recognized by Fossil. The FLAGS argument will be used to set the value
@@ -2397,10 +2508,11 @@
2508 Th_InitTraceLog();
2509 forceCgi = find_option("cgi", 0, 0)!=0;
2510 fullHttpReply = find_option("http", 0, 0)!=0;
2511 if( fullHttpReply ) forceCgi = 1;
2512 if( forceCgi ) Th_ForceCgi(fullHttpReply);
2513 verify_all_options();
2514 if( g.argc<5 ){
2515 usage("TYPE NAME FLAGS");
2516 }
2517 if( fossil_stricmp(g.argv[2], "cmdhook")==0 ){
2518 rc = Th_CommandHook(g.argv[3], (char)atoi(g.argv[4]));
2519
+1 -1
--- src/timeline.c
+++ src/timeline.c
@@ -2133,11 +2133,11 @@
21332133
fossil_fatal("cannot compute descendants or ancestors of a date");
21342134
}
21352135
if( mode==0 ){
21362136
if( isIsoDate(zOrigin) ) zShift = ",'+1 day'";
21372137
}
2138
- zDate = mprintf("(SELECT julianday(%Q%s, fromLocal())", zOrigin, zShift);
2138
+ zDate = mprintf("(SELECT julianday(%Q%s, fromLocal()))", zOrigin, zShift);
21392139
}
21402140
21412141
if( zFilePattern ){
21422142
if( zType==0 ){
21432143
/* When zFilePattern is specified and type is not specified, only show
21442144
--- src/timeline.c
+++ src/timeline.c
@@ -2133,11 +2133,11 @@
2133 fossil_fatal("cannot compute descendants or ancestors of a date");
2134 }
2135 if( mode==0 ){
2136 if( isIsoDate(zOrigin) ) zShift = ",'+1 day'";
2137 }
2138 zDate = mprintf("(SELECT julianday(%Q%s, fromLocal())", zOrigin, zShift);
2139 }
2140
2141 if( zFilePattern ){
2142 if( zType==0 ){
2143 /* When zFilePattern is specified and type is not specified, only show
2144
--- src/timeline.c
+++ src/timeline.c
@@ -2133,11 +2133,11 @@
2133 fossil_fatal("cannot compute descendants or ancestors of a date");
2134 }
2135 if( mode==0 ){
2136 if( isIsoDate(zOrigin) ) zShift = ",'+1 day'";
2137 }
2138 zDate = mprintf("(SELECT julianday(%Q%s, fromLocal()))", zOrigin, zShift);
2139 }
2140
2141 if( zFilePattern ){
2142 if( zType==0 ){
2143 /* When zFilePattern is specified and type is not specified, only show
2144
+3 -1
--- src/xfer.c
+++ src/xfer.c
@@ -191,11 +191,13 @@
191191
}else{
192192
pXfer->nFileRcvd++;
193193
}
194194
sha1sum_blob(&content, &hash);
195195
if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
196
- blob_appendf(&pXfer->err, "content does not match sha1 hash");
196
+ blob_appendf(&pXfer->err,
197
+ "wrong hash on received artifact: expected %s but got %s",
198
+ blob_str(&pXfer->aToken[1]), blob_str(&hash));
197199
}
198200
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
199201
Th_AppendToList(pzUuidList, pnUuidList, blob_str(&hash), blob_size(&hash));
200202
blob_reset(&hash);
201203
if( rid==0 ){
202204
--- src/xfer.c
+++ src/xfer.c
@@ -191,11 +191,13 @@
191 }else{
192 pXfer->nFileRcvd++;
193 }
194 sha1sum_blob(&content, &hash);
195 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
196 blob_appendf(&pXfer->err, "content does not match sha1 hash");
 
 
197 }
198 rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
199 Th_AppendToList(pzUuidList, pnUuidList, blob_str(&hash), blob_size(&hash));
200 blob_reset(&hash);
201 if( rid==0 ){
202
--- src/xfer.c
+++ src/xfer.c
@@ -191,11 +191,13 @@
191 }else{
192 pXfer->nFileRcvd++;
193 }
194 sha1sum_blob(&content, &hash);
195 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
196 blob_appendf(&pXfer->err,
197 "wrong hash on received artifact: expected %s but got %s",
198 blob_str(&pXfer->aToken[1]), blob_str(&hash));
199 }
200 rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
201 Th_AppendToList(pzUuidList, pnUuidList, blob_str(&hash), blob_size(&hash));
202 blob_reset(&hash);
203 if( rid==0 ){
204
+1 -1
--- src/zip.c
+++ src/zip.c
@@ -143,11 +143,11 @@
143143
144144
/* Fill in as much of the header as we know.
145145
*/
146146
nBlob = pFile ? blob_size(pFile) : 0;
147147
if( pFile ){ /* This is a file, possibly empty... */
148
- iMethod = 8;
148
+ iMethod = (nBlob>0) ? 8 : 0; /* Cannot compress zero bytes. */
149149
switch( mPerm ){
150150
case PERM_LNK: iMode = 0120755; break;
151151
case PERM_EXE: iMode = 0100755; break;
152152
default: iMode = 0100644; break;
153153
}
154154
--- src/zip.c
+++ src/zip.c
@@ -143,11 +143,11 @@
143
144 /* Fill in as much of the header as we know.
145 */
146 nBlob = pFile ? blob_size(pFile) : 0;
147 if( pFile ){ /* This is a file, possibly empty... */
148 iMethod = 8;
149 switch( mPerm ){
150 case PERM_LNK: iMode = 0120755; break;
151 case PERM_EXE: iMode = 0100755; break;
152 default: iMode = 0100644; break;
153 }
154
--- src/zip.c
+++ src/zip.c
@@ -143,11 +143,11 @@
143
144 /* Fill in as much of the header as we know.
145 */
146 nBlob = pFile ? blob_size(pFile) : 0;
147 if( pFile ){ /* This is a file, possibly empty... */
148 iMethod = (nBlob>0) ? 8 : 0; /* Cannot compress zero bytes. */
149 switch( mPerm ){
150 case PERM_LNK: iMode = 0120755; break;
151 case PERM_EXE: iMode = 0100755; break;
152 default: iMode = 0100644; break;
153 }
154
+1 -1
--- src/zip.c
+++ src/zip.c
@@ -143,11 +143,11 @@
143143
144144
/* Fill in as much of the header as we know.
145145
*/
146146
nBlob = pFile ? blob_size(pFile) : 0;
147147
if( pFile ){ /* This is a file, possibly empty... */
148
- iMethod = 8;
148
+ iMethod = (nBlob>0) ? 8 : 0; /* Cannot compress zero bytes. */
149149
switch( mPerm ){
150150
case PERM_LNK: iMode = 0120755; break;
151151
case PERM_EXE: iMode = 0100755; break;
152152
default: iMode = 0100644; break;
153153
}
154154
--- src/zip.c
+++ src/zip.c
@@ -143,11 +143,11 @@
143
144 /* Fill in as much of the header as we know.
145 */
146 nBlob = pFile ? blob_size(pFile) : 0;
147 if( pFile ){ /* This is a file, possibly empty... */
148 iMethod = 8;
149 switch( mPerm ){
150 case PERM_LNK: iMode = 0120755; break;
151 case PERM_EXE: iMode = 0100755; break;
152 default: iMode = 0100644; break;
153 }
154
--- src/zip.c
+++ src/zip.c
@@ -143,11 +143,11 @@
143
144 /* Fill in as much of the header as we know.
145 */
146 nBlob = pFile ? blob_size(pFile) : 0;
147 if( pFile ){ /* This is a file, possibly empty... */
148 iMethod = (nBlob>0) ? 8 : 0; /* Cannot compress zero bytes. */
149 switch( mPerm ){
150 case PERM_LNK: iMode = 0120755; break;
151 case PERM_EXE: iMode = 0100755; break;
152 default: iMode = 0100644; break;
153 }
154
+17 -2
--- test/amend.test
+++ test/amend.test
@@ -1,6 +1,22 @@
11
#
2
+# Copyright (c) 2015 D. Richard Hipp
3
+#
4
+# This program is free software; you can redistribute it and/or
5
+# modify it under the terms of the Simplified BSD License (also
6
+# known as the "2-Clause License" or "FreeBSD License".)
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but without any warranty; without even the implied warranty of
10
+# merchantability or fitness for a particular purpose.
11
+#
12
+# Author contact information:
13
+# [email protected]
14
+# http://www.hwaci.com/drh/
15
+#
16
+############################################################################
17
+#
218
# Tests for the "amend" command.
319
#
420
521
proc short_uuid {uuid {len 10}} {
622
string range $uuid 0 $len-1
@@ -374,17 +390,16 @@
374390
prep-test "final comment" "final content"
375391
if {[catch {exec which ed} result]} {
376392
if {$VERBOSE} { protOut "Install ed for interactive comment test: $result" }
377393
test-comment 5 $UUID "ed required for interactive edit"
378394
} else {
379
- set env(EDITOR) "ed -s"
395
+ fossil settings editor "ed -s"
380396
set comment "interactive edited comment"
381397
fossil_maybe_answer "a\n$comment\n.\nw\nq\n" amend $UUID --edit-comment
382
- unset env(EDITOR)
383398
test-comment 5 $UUID $comment
384399
}
385400
386401
########################################
387402
# Test: NULL UUID #
388403
########################################
389404
fossil amend {} -close
390405
test amend-null-uuid {$CODE && [string first "no such check-in" $RESULT] != -1}
391406
--- test/amend.test
+++ test/amend.test
@@ -1,6 +1,22 @@
1 #
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2 # Tests for the "amend" command.
3 #
4
5 proc short_uuid {uuid {len 10}} {
6 string range $uuid 0 $len-1
@@ -374,17 +390,16 @@
374 prep-test "final comment" "final content"
375 if {[catch {exec which ed} result]} {
376 if {$VERBOSE} { protOut "Install ed for interactive comment test: $result" }
377 test-comment 5 $UUID "ed required for interactive edit"
378 } else {
379 set env(EDITOR) "ed -s"
380 set comment "interactive edited comment"
381 fossil_maybe_answer "a\n$comment\n.\nw\nq\n" amend $UUID --edit-comment
382 unset env(EDITOR)
383 test-comment 5 $UUID $comment
384 }
385
386 ########################################
387 # Test: NULL UUID #
388 ########################################
389 fossil amend {} -close
390 test amend-null-uuid {$CODE && [string first "no such check-in" $RESULT] != -1}
391
--- test/amend.test
+++ test/amend.test
@@ -1,6 +1,22 @@
1 #
2 # Copyright (c) 2015 D. Richard Hipp
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the Simplified BSD License (also
6 # known as the "2-Clause License" or "FreeBSD License".)
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but without any warranty; without even the implied warranty of
10 # merchantability or fitness for a particular purpose.
11 #
12 # Author contact information:
13 # [email protected]
14 # http://www.hwaci.com/drh/
15 #
16 ############################################################################
17 #
18 # Tests for the "amend" command.
19 #
20
21 proc short_uuid {uuid {len 10}} {
22 string range $uuid 0 $len-1
@@ -374,17 +390,16 @@
390 prep-test "final comment" "final content"
391 if {[catch {exec which ed} result]} {
392 if {$VERBOSE} { protOut "Install ed for interactive comment test: $result" }
393 test-comment 5 $UUID "ed required for interactive edit"
394 } else {
395 fossil settings editor "ed -s"
396 set comment "interactive edited comment"
397 fossil_maybe_answer "a\n$comment\n.\nw\nq\n" amend $UUID --edit-comment
 
398 test-comment 5 $UUID $comment
399 }
400
401 ########################################
402 # Test: NULL UUID #
403 ########################################
404 fossil amend {} -close
405 test amend-null-uuid {$CODE && [string first "no such check-in" $RESULT] != -1}
406
--- test/file1.test
+++ test/file1.test
@@ -15,10 +15,12 @@
1515
#
1616
############################################################################
1717
#
1818
# File utilities
1919
#
20
+
21
+repo_init
2022
2123
proc simplify-name {testname args} {
2224
set i 1
2325
foreach {path result} $args {
2426
fossil test-simplify-name $path
@@ -65,10 +67,13 @@
6567
6668
if {$::tcl_platform(os)=="Windows NT"} {
6769
simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
6870
simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
6971
}
72
+
73
+# This is needed because we are now running outside of the Fossil checkout.
74
+file mkdir file1; set savedPwd [pwd]; cd file1
7075
7176
# Those directories are only needed for the testcase being able to "--chdir" to it.
7277
file mkdir test1
7378
file mkdir test1/test2
7479
@@ -89,5 +94,7 @@
8994
absolute-tree-name 102 test1 [pwd]/test $dirname/file1/test . [pwd]/file1 $dirname/file1/file1 . [pwd]/file1/file2 $dirname/file1/file1/file2
9095
absolute-tree-name 103 . [pwd] $dirname/file1
9196
9297
catch {file delete test1/test2}
9398
catch {file delete test1}
99
+
100
+if {[info exists savedPwd]} {cd $savedPwd; unset savedPwd}
94101
--- test/file1.test
+++ test/file1.test
@@ -15,10 +15,12 @@
15 #
16 ############################################################################
17 #
18 # File utilities
19 #
 
 
20
21 proc simplify-name {testname args} {
22 set i 1
23 foreach {path result} $args {
24 fossil test-simplify-name $path
@@ -65,10 +67,13 @@
65
66 if {$::tcl_platform(os)=="Windows NT"} {
67 simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
68 simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
69 }
 
 
 
70
71 # Those directories are only needed for the testcase being able to "--chdir" to it.
72 file mkdir test1
73 file mkdir test1/test2
74
@@ -89,5 +94,7 @@
89 absolute-tree-name 102 test1 [pwd]/test $dirname/file1/test . [pwd]/file1 $dirname/file1/file1 . [pwd]/file1/file2 $dirname/file1/file1/file2
90 absolute-tree-name 103 . [pwd] $dirname/file1
91
92 catch {file delete test1/test2}
93 catch {file delete test1}
 
 
94
--- test/file1.test
+++ test/file1.test
@@ -15,10 +15,12 @@
15 #
16 ############################################################################
17 #
18 # File utilities
19 #
20
21 repo_init
22
23 proc simplify-name {testname args} {
24 set i 1
25 foreach {path result} $args {
26 fossil test-simplify-name $path
@@ -65,10 +67,13 @@
67
68 if {$::tcl_platform(os)=="Windows NT"} {
69 simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
70 simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
71 }
72
73 # This is needed because we are now running outside of the Fossil checkout.
74 file mkdir file1; set savedPwd [pwd]; cd file1
75
76 # Those directories are only needed for the testcase being able to "--chdir" to it.
77 file mkdir test1
78 file mkdir test1/test2
79
@@ -89,5 +94,7 @@
94 absolute-tree-name 102 test1 [pwd]/test $dirname/file1/test . [pwd]/file1 $dirname/file1/file1 . [pwd]/file1/file2 $dirname/file1/file1/file2
95 absolute-tree-name 103 . [pwd] $dirname/file1
96
97 catch {file delete test1/test2}
98 catch {file delete test1}
99
100 if {[info exists savedPwd]} {cd $savedPwd; unset savedPwd}
101
--- test/merge5.test
+++ test/merge5.test
@@ -48,11 +48,11 @@
4848
# We need not to clutter the $HOME of the test caller.
4949
set env(HOME) [pwd]
5050
5151
# Construct a test repository
5252
#
53
-exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql
53
+exec $::fossilexe sqlite3 --no-repository m5.fossil <$testdir/${testfile}_repo.sql
5454
fossil rebuild m5.fossil
5555
fossil open m5.fossil
5656
fossil user default drh --user drh
5757
fossil update baseline
5858
checkout-test 10 {
5959
--- test/merge5.test
+++ test/merge5.test
@@ -48,11 +48,11 @@
48 # We need not to clutter the $HOME of the test caller.
49 set env(HOME) [pwd]
50
51 # Construct a test repository
52 #
53 exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql
54 fossil rebuild m5.fossil
55 fossil open m5.fossil
56 fossil user default drh --user drh
57 fossil update baseline
58 checkout-test 10 {
59
--- test/merge5.test
+++ test/merge5.test
@@ -48,11 +48,11 @@
48 # We need not to clutter the $HOME of the test caller.
49 set env(HOME) [pwd]
50
51 # Construct a test repository
52 #
53 exec $::fossilexe sqlite3 --no-repository m5.fossil <$testdir/${testfile}_repo.sql
54 fossil rebuild m5.fossil
55 fossil open m5.fossil
56 fossil user default drh --user drh
57 fossil update baseline
58 checkout-test 10 {
59
--- test/merge6.test
+++ test/merge6.test
@@ -62,6 +62,6 @@
6262
fossil ls
6363
6464
test merge_multi-4 {[normalize_result] eq {f1
6565
f2
6666
f3
67
-f4}}
67
+f4}} knownBug
6868
--- test/merge6.test
+++ test/merge6.test
@@ -62,6 +62,6 @@
62 fossil ls
63
64 test merge_multi-4 {[normalize_result] eq {f1
65 f2
66 f3
67 f4}}
68
--- test/merge6.test
+++ test/merge6.test
@@ -62,6 +62,6 @@
62 fossil ls
63
64 test merge_multi-4 {[normalize_result] eq {f1
65 f2
66 f3
67 f4}} knownBug
68
--- test/merge_renames.test
+++ test/merge_renames.test
@@ -156,13 +156,13 @@
156156
}
157157
158158
if {$deletes!=0} {
159159
# failed
160160
protOut "Error, the merge should not delete any file"
161
- test merge_renames-2 0
161
+ test merge_renames-3 0
162162
} else {
163
- test merge_renames-2 1
163
+ test merge_renames-3 1
164164
}
165165
166166
######################################
167167
# Test 4 #
168168
# Reported: Ticket [67176c3aa4] #
@@ -198,14 +198,14 @@
198198
199199
fossil ls
200200
201201
test merge_renames-5 {[normalize_result] eq {f1
202202
f2
203
-f3}}
203
+f3}} knownBug
204204
205205
######################################
206206
#
207207
# Tests for troubles not specifically linked with renames but that I'd like to
208208
# write:
209209
# [c26c63eb1b] - 'merge --backout' does not handle conflicts properly
210210
# [953031915f] - Lack of warning when overwriting extra files
211211
# [4df5f38f1e] - Troubles merging a file delete with a file change
212212
--- test/merge_renames.test
+++ test/merge_renames.test
@@ -156,13 +156,13 @@
156 }
157
158 if {$deletes!=0} {
159 # failed
160 protOut "Error, the merge should not delete any file"
161 test merge_renames-2 0
162 } else {
163 test merge_renames-2 1
164 }
165
166 ######################################
167 # Test 4 #
168 # Reported: Ticket [67176c3aa4] #
@@ -198,14 +198,14 @@
198
199 fossil ls
200
201 test merge_renames-5 {[normalize_result] eq {f1
202 f2
203 f3}}
204
205 ######################################
206 #
207 # Tests for troubles not specifically linked with renames but that I'd like to
208 # write:
209 # [c26c63eb1b] - 'merge --backout' does not handle conflicts properly
210 # [953031915f] - Lack of warning when overwriting extra files
211 # [4df5f38f1e] - Troubles merging a file delete with a file change
212
--- test/merge_renames.test
+++ test/merge_renames.test
@@ -156,13 +156,13 @@
156 }
157
158 if {$deletes!=0} {
159 # failed
160 protOut "Error, the merge should not delete any file"
161 test merge_renames-3 0
162 } else {
163 test merge_renames-3 1
164 }
165
166 ######################################
167 # Test 4 #
168 # Reported: Ticket [67176c3aa4] #
@@ -198,14 +198,14 @@
198
199 fossil ls
200
201 test merge_renames-5 {[normalize_result] eq {f1
202 f2
203 f3}} knownBug
204
205 ######################################
206 #
207 # Tests for troubles not specifically linked with renames but that I'd like to
208 # write:
209 # [c26c63eb1b] - 'merge --backout' does not handle conflicts properly
210 # [953031915f] - Lack of warning when overwriting extra files
211 # [4df5f38f1e] - Troubles merging a file delete with a file change
212
--- test/revert.test
+++ test/revert.test
@@ -1,5 +1,22 @@
1
+#
2
+# Copyright (c) 2013 D. Richard Hipp
3
+#
4
+# This program is free software; you can redistribute it and/or
5
+# modify it under the terms of the Simplified BSD License (also
6
+# known as the "2-Clause License" or "FreeBSD License".)
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but without any warranty; without even the implied warranty of
10
+# merchantability or fitness for a particular purpose.
11
+#
12
+# Author contact information:
13
+# [email protected]
14
+# http://www.hwaci.com/drh/
15
+#
16
+############################################################################
17
+#
118
#
219
# Tests for 'fossil revert'
320
#
421
#
522
623
--- test/revert.test
+++ test/revert.test
@@ -1,5 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1 #
2 # Tests for 'fossil revert'
3 #
4 #
5
6
--- test/revert.test
+++ test/revert.test
@@ -1,5 +1,22 @@
1 #
2 # Copyright (c) 2013 D. Richard Hipp
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the Simplified BSD License (also
6 # known as the "2-Clause License" or "FreeBSD License".)
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but without any warranty; without even the implied warranty of
10 # merchantability or fitness for a particular purpose.
11 #
12 # Author contact information:
13 # [email protected]
14 # http://www.hwaci.com/drh/
15 #
16 ############################################################################
17 #
18 #
19 # Tests for 'fossil revert'
20 #
21 #
22
23
+82 -13
--- test/tester.tcl
+++ test/tester.tcl
@@ -21,12 +21,13 @@
2121
#
2222
# Where ../test/tester.tcl is the name of this file and ../bld/fossil
2323
# is the name of the executable to be tested.
2424
#
2525
26
+set testfiledir [file normalize [file dirname [info script]]]
2627
set testrundir [pwd]
27
-set testdir [file normalize [file dir $argv0]]
28
+set testdir [file normalize [file dirname $argv0]]
2829
set fossilexe [file normalize [lindex $argv 0]]
2930
set argv [lrange $argv 1 end]
3031
3132
set i [lsearch $argv -halt]
3233
if {$i>=0} {
@@ -57,10 +58,18 @@
5758
set QUIET 1
5859
set argv [lreplace $argv $i $i]
5960
} else {
6061
set QUIET 0
6162
}
63
+
64
+set i [lsearch $argv -strict]
65
+if {$i>=0} {
66
+ set STRICT 1
67
+ set argv [lreplace $argv $i $i]
68
+} else {
69
+ set STRICT 0
70
+}
6271
6372
if {[llength $argv]==0} {
6473
foreach f [lsort [glob $testdir/*.test]] {
6574
set base [file root [file tail $f]]
6675
lappend argv $base
@@ -188,10 +197,51 @@
188197
exec $::fossilexe new $filename
189198
exec $::fossilexe open $filename
190199
exec $::fossilexe clean -f
191200
exec $::fossilexe set mtime-changes off
192201
}
202
+
203
+# This procedure only returns non-zero if the Tcl integration feature was
204
+# enabled at compile-time and is now enabled at runtime.
205
+proc is_tcl_usable_by_fossil {} {
206
+ fossil test-th-eval "hasfeature tcl"
207
+ if {$::RESULT ne "1"} {return 0}
208
+ fossil test-th-eval "setting tcl"
209
+ if {$::RESULT eq "1"} {return 1}
210
+ fossil test-th-eval --open-config "setting tcl"
211
+ if {$::RESULT eq "1"} {return 1}
212
+ return [info exists ::env(TH1_ENABLE_TCL)]
213
+}
214
+
215
+# This procedure only returns non-zero if the TH1 hooks feature was enabled
216
+# at compile-time and is now enabled at runtime.
217
+proc are_th1_hooks_usable_by_fossil {} {
218
+ fossil test-th-eval "hasfeature th1Hooks"
219
+ if {$::RESULT ne "1"} {return 0}
220
+ fossil test-th-eval "setting th1-hooks"
221
+ if {$::RESULT eq "1"} {return 1}
222
+ fossil test-th-eval --open-config "setting th1-hooks"
223
+ if {$::RESULT eq "1"} {return 1}
224
+ return [info exists ::env(TH1_ENABLE_HOOKS)]
225
+}
226
+
227
+# This (rarely used) procedure is designed to run a test within the Fossil
228
+# source checkout (e.g. one that does NOT modify any state), while saving
229
+# and restoring the current directory (e.g. one used when running a test
230
+# file outside of the Fossil source checkout). Please do NOT use this
231
+# procedure unless you are absolutely sure it does not modify the state of
232
+# the repository or source checkout in any way.
233
+#
234
+proc run_in_checkout { script {dir ""} } {
235
+ if {[string length $dir] == 0} {set dir $::testfiledir}
236
+ set savedPwd [pwd]; cd $dir
237
+ set code [catch {
238
+ uplevel 1 $script
239
+ } result]
240
+ cd $savedPwd; unset savedPwd
241
+ return -code $code $result
242
+}
193243
194244
# Normalize file status lists (like those returned by 'fossil changes')
195245
# so they can be compared using simple string comparison
196246
#
197247
proc normalize_status_list {list} {
@@ -231,12 +281,11 @@
231281
#
232282
# NOTE: This uses the "testdir" global variable provided by the
233283
# test suite; alternatively, the root of the source tree
234284
# could be obtained directly from Fossil.
235285
#
236
- return [file normalize [file join [file dirname $::testdir] \
237
- .fossil-settings th1-setup]]
286
+ return [file normalize [file join .fossil-settings th1-setup]]
238287
}
239288
240289
# Return the saved name of the versioned settings file containing
241290
# the TH1 setup script.
242291
#
@@ -249,11 +298,13 @@
249298
# preserve the existing TH1 setup script. Prior to completing the test,
250299
# the [restoreTh1SetupFile] procedure should be called to restore the
251300
# original TH1 setup script.
252301
#
253302
proc writeTh1SetupFile { data } {
254
- return [write_file [getTh1SetupFileName] $data]
303
+ set fileName [getTh1SetupFileName]
304
+ file mkdir [file dirname $fileName]
305
+ return [write_file $fileName $data]
255306
}
256307
257308
# Saves the TH1 setup script file by renaming it, based on the current
258309
# process ID.
259310
#
@@ -284,24 +335,35 @@
284335
}
285336
286337
# Perform a test
287338
#
288339
set test_count 0
289
-proc test {name expr} {
290
- global bad_test test_count RESULT
340
+proc test {name expr {constraints ""}} {
341
+ global bad_test ignored_test test_count RESULT
291342
incr test_count
343
+ set knownBug [expr {"knownBug" in $constraints}]
292344
set r [uplevel 1 [list expr $expr]]
293345
if {$r} {
294
- protOut "test $name OK"
346
+ if {$knownBug && !$::STRICT} {
347
+ protOut "test $name OK (knownBug)?"
348
+ } else {
349
+ protOut "test $name OK"
350
+ }
295351
} else {
296
- protOut "test $name FAILED!" 1
297
- if {$::QUIET} {protOut "RESULT: $RESULT" 1}
298
- lappend bad_test $name
299
- if {$::HALT} exit
352
+ if {$knownBug && !$::STRICT} {
353
+ protOut "test $name FAILED (knownBug)!" 1
354
+ lappend ignored_test $name
355
+ } else {
356
+ protOut "test $name FAILED!" 1
357
+ if {$::QUIET} {protOut "RESULT: $RESULT" 1}
358
+ lappend bad_test $name
359
+ if {$::HALT} exit
360
+ }
300361
}
301362
}
302363
set bad_test {}
364
+set ignored_test {}
303365
304366
# Return a random string N characters long.
305367
#
306368
set vocabulary 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
307369
append vocabulary " ()*^!.eeeeeeeeaaaaattiioo "
@@ -451,10 +513,17 @@
451513
protOut "***** End of $testfile: [llength $bad_test] errors so far ******"
452514
cd $origwd
453515
}
454516
set nErr [llength $bad_test]
455517
if {$nErr>0 || !$::QUIET} {
456
- protOut "***** Final result: $nErr errors out of $test_count tests" 1
518
+ protOut "***** Final results: $nErr errors out of $test_count tests" 1
519
+}
520
+if {$nErr>0} {
521
+ protOut "***** Considered failures: $bad_test" 1
522
+}
523
+set nErr [llength $ignored_test]
524
+if {$nErr>0 || !$::QUIET} {
525
+ protOut "***** Ignored results: $nErr ignored errors out of $test_count tests" 1
457526
}
458527
if {$nErr>0} {
459
- protOut "***** Failures: $bad_test" 1
528
+ protOut "***** Ignored failures: $ignored_test" 1
460529
}
461530
--- test/tester.tcl
+++ test/tester.tcl
@@ -21,12 +21,13 @@
21 #
22 # Where ../test/tester.tcl is the name of this file and ../bld/fossil
23 # is the name of the executable to be tested.
24 #
25
 
26 set testrundir [pwd]
27 set testdir [file normalize [file dir $argv0]]
28 set fossilexe [file normalize [lindex $argv 0]]
29 set argv [lrange $argv 1 end]
30
31 set i [lsearch $argv -halt]
32 if {$i>=0} {
@@ -57,10 +58,18 @@
57 set QUIET 1
58 set argv [lreplace $argv $i $i]
59 } else {
60 set QUIET 0
61 }
 
 
 
 
 
 
 
 
62
63 if {[llength $argv]==0} {
64 foreach f [lsort [glob $testdir/*.test]] {
65 set base [file root [file tail $f]]
66 lappend argv $base
@@ -188,10 +197,51 @@
188 exec $::fossilexe new $filename
189 exec $::fossilexe open $filename
190 exec $::fossilexe clean -f
191 exec $::fossilexe set mtime-changes off
192 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
194 # Normalize file status lists (like those returned by 'fossil changes')
195 # so they can be compared using simple string comparison
196 #
197 proc normalize_status_list {list} {
@@ -231,12 +281,11 @@
231 #
232 # NOTE: This uses the "testdir" global variable provided by the
233 # test suite; alternatively, the root of the source tree
234 # could be obtained directly from Fossil.
235 #
236 return [file normalize [file join [file dirname $::testdir] \
237 .fossil-settings th1-setup]]
238 }
239
240 # Return the saved name of the versioned settings file containing
241 # the TH1 setup script.
242 #
@@ -249,11 +298,13 @@
249 # preserve the existing TH1 setup script. Prior to completing the test,
250 # the [restoreTh1SetupFile] procedure should be called to restore the
251 # original TH1 setup script.
252 #
253 proc writeTh1SetupFile { data } {
254 return [write_file [getTh1SetupFileName] $data]
 
 
255 }
256
257 # Saves the TH1 setup script file by renaming it, based on the current
258 # process ID.
259 #
@@ -284,24 +335,35 @@
284 }
285
286 # Perform a test
287 #
288 set test_count 0
289 proc test {name expr} {
290 global bad_test test_count RESULT
291 incr test_count
 
292 set r [uplevel 1 [list expr $expr]]
293 if {$r} {
294 protOut "test $name OK"
 
 
 
 
295 } else {
296 protOut "test $name FAILED!" 1
297 if {$::QUIET} {protOut "RESULT: $RESULT" 1}
298 lappend bad_test $name
299 if {$::HALT} exit
 
 
 
 
 
300 }
301 }
302 set bad_test {}
 
303
304 # Return a random string N characters long.
305 #
306 set vocabulary 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
307 append vocabulary " ()*^!.eeeeeeeeaaaaattiioo "
@@ -451,10 +513,17 @@
451 protOut "***** End of $testfile: [llength $bad_test] errors so far ******"
452 cd $origwd
453 }
454 set nErr [llength $bad_test]
455 if {$nErr>0 || !$::QUIET} {
456 protOut "***** Final result: $nErr errors out of $test_count tests" 1
 
 
 
 
 
 
 
457 }
458 if {$nErr>0} {
459 protOut "***** Failures: $bad_test" 1
460 }
461
--- test/tester.tcl
+++ test/tester.tcl
@@ -21,12 +21,13 @@
21 #
22 # Where ../test/tester.tcl is the name of this file and ../bld/fossil
23 # is the name of the executable to be tested.
24 #
25
26 set testfiledir [file normalize [file dirname [info script]]]
27 set testrundir [pwd]
28 set testdir [file normalize [file dirname $argv0]]
29 set fossilexe [file normalize [lindex $argv 0]]
30 set argv [lrange $argv 1 end]
31
32 set i [lsearch $argv -halt]
33 if {$i>=0} {
@@ -57,10 +58,18 @@
58 set QUIET 1
59 set argv [lreplace $argv $i $i]
60 } else {
61 set QUIET 0
62 }
63
64 set i [lsearch $argv -strict]
65 if {$i>=0} {
66 set STRICT 1
67 set argv [lreplace $argv $i $i]
68 } else {
69 set STRICT 0
70 }
71
72 if {[llength $argv]==0} {
73 foreach f [lsort [glob $testdir/*.test]] {
74 set base [file root [file tail $f]]
75 lappend argv $base
@@ -188,10 +197,51 @@
197 exec $::fossilexe new $filename
198 exec $::fossilexe open $filename
199 exec $::fossilexe clean -f
200 exec $::fossilexe set mtime-changes off
201 }
202
203 # This procedure only returns non-zero if the Tcl integration feature was
204 # enabled at compile-time and is now enabled at runtime.
205 proc is_tcl_usable_by_fossil {} {
206 fossil test-th-eval "hasfeature tcl"
207 if {$::RESULT ne "1"} {return 0}
208 fossil test-th-eval "setting tcl"
209 if {$::RESULT eq "1"} {return 1}
210 fossil test-th-eval --open-config "setting tcl"
211 if {$::RESULT eq "1"} {return 1}
212 return [info exists ::env(TH1_ENABLE_TCL)]
213 }
214
215 # This procedure only returns non-zero if the TH1 hooks feature was enabled
216 # at compile-time and is now enabled at runtime.
217 proc are_th1_hooks_usable_by_fossil {} {
218 fossil test-th-eval "hasfeature th1Hooks"
219 if {$::RESULT ne "1"} {return 0}
220 fossil test-th-eval "setting th1-hooks"
221 if {$::RESULT eq "1"} {return 1}
222 fossil test-th-eval --open-config "setting th1-hooks"
223 if {$::RESULT eq "1"} {return 1}
224 return [info exists ::env(TH1_ENABLE_HOOKS)]
225 }
226
227 # This (rarely used) procedure is designed to run a test within the Fossil
228 # source checkout (e.g. one that does NOT modify any state), while saving
229 # and restoring the current directory (e.g. one used when running a test
230 # file outside of the Fossil source checkout). Please do NOT use this
231 # procedure unless you are absolutely sure it does not modify the state of
232 # the repository or source checkout in any way.
233 #
234 proc run_in_checkout { script {dir ""} } {
235 if {[string length $dir] == 0} {set dir $::testfiledir}
236 set savedPwd [pwd]; cd $dir
237 set code [catch {
238 uplevel 1 $script
239 } result]
240 cd $savedPwd; unset savedPwd
241 return -code $code $result
242 }
243
244 # Normalize file status lists (like those returned by 'fossil changes')
245 # so they can be compared using simple string comparison
246 #
247 proc normalize_status_list {list} {
@@ -231,12 +281,11 @@
281 #
282 # NOTE: This uses the "testdir" global variable provided by the
283 # test suite; alternatively, the root of the source tree
284 # could be obtained directly from Fossil.
285 #
286 return [file normalize [file join .fossil-settings th1-setup]]
 
287 }
288
289 # Return the saved name of the versioned settings file containing
290 # the TH1 setup script.
291 #
@@ -249,11 +298,13 @@
298 # preserve the existing TH1 setup script. Prior to completing the test,
299 # the [restoreTh1SetupFile] procedure should be called to restore the
300 # original TH1 setup script.
301 #
302 proc writeTh1SetupFile { data } {
303 set fileName [getTh1SetupFileName]
304 file mkdir [file dirname $fileName]
305 return [write_file $fileName $data]
306 }
307
308 # Saves the TH1 setup script file by renaming it, based on the current
309 # process ID.
310 #
@@ -284,24 +335,35 @@
335 }
336
337 # Perform a test
338 #
339 set test_count 0
340 proc test {name expr {constraints ""}} {
341 global bad_test ignored_test test_count RESULT
342 incr test_count
343 set knownBug [expr {"knownBug" in $constraints}]
344 set r [uplevel 1 [list expr $expr]]
345 if {$r} {
346 if {$knownBug && !$::STRICT} {
347 protOut "test $name OK (knownBug)?"
348 } else {
349 protOut "test $name OK"
350 }
351 } else {
352 if {$knownBug && !$::STRICT} {
353 protOut "test $name FAILED (knownBug)!" 1
354 lappend ignored_test $name
355 } else {
356 protOut "test $name FAILED!" 1
357 if {$::QUIET} {protOut "RESULT: $RESULT" 1}
358 lappend bad_test $name
359 if {$::HALT} exit
360 }
361 }
362 }
363 set bad_test {}
364 set ignored_test {}
365
366 # Return a random string N characters long.
367 #
368 set vocabulary 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
369 append vocabulary " ()*^!.eeeeeeeeaaaaattiioo "
@@ -451,10 +513,17 @@
513 protOut "***** End of $testfile: [llength $bad_test] errors so far ******"
514 cd $origwd
515 }
516 set nErr [llength $bad_test]
517 if {$nErr>0 || !$::QUIET} {
518 protOut "***** Final results: $nErr errors out of $test_count tests" 1
519 }
520 if {$nErr>0} {
521 protOut "***** Considered failures: $bad_test" 1
522 }
523 set nErr [llength $ignored_test]
524 if {$nErr>0 || !$::QUIET} {
525 protOut "***** Ignored results: $nErr ignored errors out of $test_count tests" 1
526 }
527 if {$nErr>0} {
528 protOut "***** Ignored failures: $ignored_test" 1
529 }
530
--- test/th1-docs.test
+++ test/th1-docs.test
@@ -35,11 +35,14 @@
3535
set env(TH1_ENABLE_DOCS) 1; # TH1 docs must be enabled for this test.
3636
set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
3737
3838
###############################################################################
3939
40
-set data [fossil info]
40
+run_in_checkout {
41
+ set data [fossil info]
42
+}
43
+
4144
regexp -line -- {^repository: (.*)$} $data dummy repository
4245
4346
if {[string length $repository] == 0 || ![file exists $repository]} then {
4447
error "unable to locate repository"
4548
}
@@ -46,11 +49,13 @@
4649
4750
set dataFileName [file join $::testdir th1-docs-input.txt]
4851
4952
###############################################################################
5053
51
-set RESULT [test_fossil_http \
52
- $repository $dataFileName /doc/trunk/test/fileStat.th1]
54
+run_in_checkout {
55
+ set RESULT [test_fossil_http \
56
+ $repository $dataFileName /doc/trunk/test/fileStat.th1]
57
+}
5358
5459
test th1-docs-1a {[regexp {<title>Fossil: test/fileStat.th1</title>} $RESULT]}
5560
test th1-docs-1b {[regexp {>\[[0-9a-f]{40}\]<} $RESULT]}
5661
test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]}
5762
--- test/th1-docs.test
+++ test/th1-docs.test
@@ -35,11 +35,14 @@
35 set env(TH1_ENABLE_DOCS) 1; # TH1 docs must be enabled for this test.
36 set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
37
38 ###############################################################################
39
40 set data [fossil info]
 
 
 
41 regexp -line -- {^repository: (.*)$} $data dummy repository
42
43 if {[string length $repository] == 0 || ![file exists $repository]} then {
44 error "unable to locate repository"
45 }
@@ -46,11 +49,13 @@
46
47 set dataFileName [file join $::testdir th1-docs-input.txt]
48
49 ###############################################################################
50
51 set RESULT [test_fossil_http \
52 $repository $dataFileName /doc/trunk/test/fileStat.th1]
 
 
53
54 test th1-docs-1a {[regexp {<title>Fossil: test/fileStat.th1</title>} $RESULT]}
55 test th1-docs-1b {[regexp {>\[[0-9a-f]{40}\]<} $RESULT]}
56 test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]}
57
--- test/th1-docs.test
+++ test/th1-docs.test
@@ -35,11 +35,14 @@
35 set env(TH1_ENABLE_DOCS) 1; # TH1 docs must be enabled for this test.
36 set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
37
38 ###############################################################################
39
40 run_in_checkout {
41 set data [fossil info]
42 }
43
44 regexp -line -- {^repository: (.*)$} $data dummy repository
45
46 if {[string length $repository] == 0 || ![file exists $repository]} then {
47 error "unable to locate repository"
48 }
@@ -46,11 +49,13 @@
49
50 set dataFileName [file join $::testdir th1-docs-input.txt]
51
52 ###############################################################################
53
54 run_in_checkout {
55 set RESULT [test_fossil_http \
56 $repository $dataFileName /doc/trunk/test/fileStat.th1]
57 }
58
59 test th1-docs-1a {[regexp {<title>Fossil: test/fileStat.th1</title>} $RESULT]}
60 test th1-docs-1b {[regexp {>\[[0-9a-f]{40}\]<} $RESULT]}
61 test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]}
62
--- test/th1-hooks.test
+++ test/th1-hooks.test
@@ -24,10 +24,15 @@
2424
puts "Fossil was not compiled with TH1 hooks support."; return
2525
}
2626
2727
###############################################################################
2828
29
+repo_init
30
+write_file f1 "f1"; fossil add f1; fossil commit -m "c1"
31
+
32
+###############################################################################
33
+
2934
set env(TH1_ENABLE_HOOKS) 1; # TH1 hooks must be enabled for this test.
3035
3136
###############################################################################
3237
3338
set testTh1Setup {
@@ -130,11 +135,11 @@
130135
131136
test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}}
132137
133138
###############################################################################
134139
135
-fossil timeline now
140
+fossil timeline -n -1 now
136141
test th1-cmd-hooks-3a {[first_data_line] eq \
137142
{<h1><b>command_hook timeline</b></h1>}}
138143
139144
test th1-cmd-hooks-3b \
140145
{[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [second_data_line]]}
@@ -171,11 +176,13 @@
171176
{<h1><b>command_hook test4</b></h1>}}
172177
173178
###############################################################################
174179
175180
set RESULT [test_fossil_http $repository $dataFileName /timeline]
176
-test th1-web-hooks-1a {[regexp {<title>Fossil: Timeline</title>} $RESULT]}
181
+
182
+test th1-web-hooks-1a {[regexp \
183
+ {<title>Unnamed Fossil Project: Timeline</title>} $RESULT]}
177184
178185
test th1-web-hooks-1b {[regexp [appendArgs \
179186
{<h1><b>command_hook http webpage_hook timeline} " " \
180187
{webpage_notify timeline</b></h1>}] $RESULT]}
181188
182189
--- test/th1-hooks.test
+++ test/th1-hooks.test
@@ -24,10 +24,15 @@
24 puts "Fossil was not compiled with TH1 hooks support."; return
25 }
26
27 ###############################################################################
28
 
 
 
 
 
29 set env(TH1_ENABLE_HOOKS) 1; # TH1 hooks must be enabled for this test.
30
31 ###############################################################################
32
33 set testTh1Setup {
@@ -130,11 +135,11 @@
130
131 test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}}
132
133 ###############################################################################
134
135 fossil timeline now
136 test th1-cmd-hooks-3a {[first_data_line] eq \
137 {<h1><b>command_hook timeline</b></h1>}}
138
139 test th1-cmd-hooks-3b \
140 {[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [second_data_line]]}
@@ -171,11 +176,13 @@
171 {<h1><b>command_hook test4</b></h1>}}
172
173 ###############################################################################
174
175 set RESULT [test_fossil_http $repository $dataFileName /timeline]
176 test th1-web-hooks-1a {[regexp {<title>Fossil: Timeline</title>} $RESULT]}
 
 
177
178 test th1-web-hooks-1b {[regexp [appendArgs \
179 {<h1><b>command_hook http webpage_hook timeline} " " \
180 {webpage_notify timeline</b></h1>}] $RESULT]}
181
182
--- test/th1-hooks.test
+++ test/th1-hooks.test
@@ -24,10 +24,15 @@
24 puts "Fossil was not compiled with TH1 hooks support."; return
25 }
26
27 ###############################################################################
28
29 repo_init
30 write_file f1 "f1"; fossil add f1; fossil commit -m "c1"
31
32 ###############################################################################
33
34 set env(TH1_ENABLE_HOOKS) 1; # TH1 hooks must be enabled for this test.
35
36 ###############################################################################
37
38 set testTh1Setup {
@@ -130,11 +135,11 @@
135
136 test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}}
137
138 ###############################################################################
139
140 fossil timeline -n -1 now
141 test th1-cmd-hooks-3a {[first_data_line] eq \
142 {<h1><b>command_hook timeline</b></h1>}}
143
144 test th1-cmd-hooks-3b \
145 {[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [second_data_line]]}
@@ -171,11 +176,13 @@
176 {<h1><b>command_hook test4</b></h1>}}
177
178 ###############################################################################
179
180 set RESULT [test_fossil_http $repository $dataFileName /timeline]
181
182 test th1-web-hooks-1a {[regexp \
183 {<title>Unnamed Fossil Project: Timeline</title>} $RESULT]}
184
185 test th1-web-hooks-1b {[regexp [appendArgs \
186 {<h1><b>command_hook http webpage_hook timeline} " " \
187 {webpage_notify timeline</b></h1>}] $RESULT]}
188
189
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -20,10 +20,14 @@
2020
2121
set dir [file dirname [info script]]
2222
2323
###############################################################################
2424
25
+repo_init
26
+
27
+###############################################################################
28
+
2529
fossil test-th-eval "hasfeature tcl"
2630
2731
if {$::RESULT ne "1"} then {
2832
puts "Fossil was not compiled with Tcl support."; return
2933
}
@@ -58,14 +62,18 @@
5862
one_word
5963
three words now$} [normalize_result]]}
6064
6165
###############################################################################
6266
63
-fossil test-th-render --open-config \
64
- [file nativename [file join $dir th1-tcl2.txt]]
67
+if {[catch {package require sqlite3}] == 0} {
68
+ fossil test-th-render --open-config \
69
+ [file nativename [file join $dir th1-tcl2.txt]]
6570
66
-test th1-tcl-2 {[regexp -- {^\d+$} [normalize_result]]}
71
+ test th1-tcl-2 {[regexp -- {^\d+$} [normalize_result]]}
72
+} else {
73
+ puts stderr "Skipping 'th1-tcl-2', SQLite package for Tcl not available"
74
+}
6775
6876
###############################################################################
6977
7078
fossil test-th-render --open-config \
7179
[file nativename [file join $dir th1-tcl3.txt]]
7280
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -20,10 +20,14 @@
20
21 set dir [file dirname [info script]]
22
23 ###############################################################################
24
 
 
 
 
25 fossil test-th-eval "hasfeature tcl"
26
27 if {$::RESULT ne "1"} then {
28 puts "Fossil was not compiled with Tcl support."; return
29 }
@@ -58,14 +62,18 @@
58 one_word
59 three words now$} [normalize_result]]}
60
61 ###############################################################################
62
63 fossil test-th-render --open-config \
64 [file nativename [file join $dir th1-tcl2.txt]]
 
65
66 test th1-tcl-2 {[regexp -- {^\d+$} [normalize_result]]}
 
 
 
67
68 ###############################################################################
69
70 fossil test-th-render --open-config \
71 [file nativename [file join $dir th1-tcl3.txt]]
72
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -20,10 +20,14 @@
20
21 set dir [file dirname [info script]]
22
23 ###############################################################################
24
25 repo_init
26
27 ###############################################################################
28
29 fossil test-th-eval "hasfeature tcl"
30
31 if {$::RESULT ne "1"} then {
32 puts "Fossil was not compiled with Tcl support."; return
33 }
@@ -58,14 +62,18 @@
62 one_word
63 three words now$} [normalize_result]]}
64
65 ###############################################################################
66
67 if {[catch {package require sqlite3}] == 0} {
68 fossil test-th-render --open-config \
69 [file nativename [file join $dir th1-tcl2.txt]]
70
71 test th1-tcl-2 {[regexp -- {^\d+$} [normalize_result]]}
72 } else {
73 puts stderr "Skipping 'th1-tcl-2', SQLite package for Tcl not available"
74 }
75
76 ###############################################################################
77
78 fossil test-th-render --open-config \
79 [file nativename [file join $dir th1-tcl3.txt]]
80
+217 -29
--- test/th1.test
+++ test/th1.test
@@ -16,16 +16,16 @@
1616
############################################################################
1717
#
1818
# TH1 Commands
1919
#
2020
21
-set dir [file dirname [info script]]
21
+set dir [file dirname [info script]]; repo_init
2222
2323
###############################################################################
2424
25
-fossil test-th-eval --open-config "setting th1-hooks"
26
-set th1Hooks [expr {$RESULT eq "1"}]
25
+set th1Tcl [is_tcl_usable_by_fossil]
26
+set th1Hooks [are_th1_hooks_usable_by_fossil]
2727
2828
###############################################################################
2929
3030
fossil test-th-eval --open-config "setting abc"
3131
test th1-setting-1 {$RESULT eq ""}
@@ -554,16 +554,28 @@
554554
fossil test-th-eval "lindex list -0x"
555555
test th1-expr-49 {$RESULT eq {TH_ERROR: expected integer, got: "-0x"}}
556556
557557
###############################################################################
558558
559
-fossil test-th-eval "checkout 1"; # NOTE: Assumes running "in tree".
559
+run_in_checkout {
560
+ # NOTE: The "1" here forces the checkout to be opened.
561
+ fossil test-th-eval "checkout 1"
562
+}
563
+
560564
test th1-checkout-1 {[string length $RESULT] > 0}
561565
562566
###############################################################################
563567
564
-fossil test-th-eval "checkout"; # NOTE: Assumes running "in tree".
568
+run_in_checkout {
569
+ if {$th1Hooks} {
570
+ fossil test-th-eval "checkout"
571
+ } else {
572
+ # NOTE: No TH1 hooks, force checkout to be populated.
573
+ fossil test-th-eval --open-config "checkout"
574
+ }
575
+}
576
+
565577
test th1-checkout-2 {[string length $RESULT] > 0}
566578
567579
###############################################################################
568580
569581
set savedPwd [pwd]; cd /
@@ -639,11 +651,14 @@
639651
fossil test-th-eval "styleHeader {Page Title Here}"
640652
test th1-header-1 {$RESULT eq {TH_ERROR: repository unavailable}}
641653
642654
###############################################################################
643655
644
-fossil test-th-eval --open-config "styleHeader {Page Title Here}"
656
+run_in_checkout {
657
+ fossil test-th-eval --open-config "styleHeader {Page Title Here}"
658
+}
659
+
645660
test th1-header-2 {[regexp -- {<title>Fossil: Page Title Here</title>} $RESULT]}
646661
647662
###############################################################################
648663
649664
fossil test-th-eval "styleFooter"
@@ -722,11 +737,14 @@
722737
fossil test-th-eval "artifact tip"
723738
test th1-artifact-2 {$RESULT eq {TH_ERROR: repository unavailable}}
724739
725740
###############################################################################
726741
727
-fossil test-th-eval --open-config "artifact tip"
742
+run_in_checkout {
743
+ fossil test-th-eval --open-config "artifact tip"
744
+}
745
+
728746
test th1-artifact-3 {[regexp -- {F test/th1\.test [0-9a-f]{40}} $RESULT]}
729747
730748
###############################################################################
731749
732750
fossil test-th-eval "artifact 0000000000"
@@ -742,11 +760,14 @@
742760
fossil test-th-eval "artifact tip test/th1.test"
743761
test th1-artifact-6 {$RESULT eq {TH_ERROR: repository unavailable}}
744762
745763
###############################################################################
746764
747
-fossil test-th-eval --open-config "artifact tip test/th1.test"
765
+run_in_checkout {
766
+ fossil test-th-eval --open-config "artifact tip test/th1.test"
767
+}
768
+
748769
test th1-artifact-7 {[regexp -- {th1-artifact-7} $RESULT]}
749770
750771
###############################################################################
751772
752773
fossil test-th-eval "artifact 0000000000 test/th1.test"
@@ -757,17 +778,35 @@
757778
fossil test-th-eval --open-config "artifact 0000000000 test/th1.test"
758779
test th1-artifact-9 {$RESULT eq {TH_ERROR: manifest not found}}
759780
760781
###############################################################################
761782
762
-fossil test-th-eval "globalState checkout"
783
+run_in_checkout {
784
+ if {$th1Hooks} {
785
+ fossil test-th-eval "globalState checkout"
786
+ } else {
787
+ # NOTE: No TH1 hooks, force checkout to be populated.
788
+ fossil test-th-eval --open-config "globalState checkout"
789
+ }
790
+}
791
+
763792
test th1-globalState-1 {[string length $RESULT] > 0}
764793
765794
###############################################################################
766795
767
-fossil test-th-eval "globalState checkout"
768
-test th1-globalState-2 {$RESULT eq [fossil test-th-eval checkout]}
796
+run_in_checkout {
797
+ if {$th1Hooks} {
798
+ fossil test-th-eval "globalState checkout"
799
+ test th1-globalState-2 {$RESULT eq [fossil test-th-eval checkout]}
800
+ } else {
801
+ # NOTE: No TH1 hooks, force checkout to be populated.
802
+ fossil test-th-eval --open-config "globalState checkout"
803
+
804
+ test th1-globalState-2 {$RESULT eq \
805
+ [fossil test-th-eval --open-config checkout]}
806
+ }
807
+}
769808
770809
###############################################################################
771810
772811
fossil test-th-eval "globalState configuration"
773812
test th1-globalState-3 {[string length $RESULT] == 0}
@@ -792,17 +831,35 @@
792831
fossil test-th-eval --errorlog foserrors.log "globalState log"
793832
test th1-globalState-7 {$RESULT eq "foserrors.log"}
794833
795834
###############################################################################
796835
797
-fossil test-th-eval "globalState repository"
836
+run_in_checkout {
837
+ if {$th1Hooks} {
838
+ fossil test-th-eval "globalState repository"
839
+ } else {
840
+ # NOTE: No TH1 hooks, force repository to be populated.
841
+ fossil test-th-eval --open-config "globalState repository"
842
+ }
843
+}
844
+
798845
test th1-globalState-8 {[string length $RESULT] > 0}
799846
800847
###############################################################################
801848
802
-fossil test-th-eval "globalState repository"
803
-test th1-globalState-9 {$RESULT eq [fossil test-th-eval repository]}
849
+run_in_checkout {
850
+ if {$th1Hooks} {
851
+ fossil test-th-eval "globalState repository"
852
+ test th1-globalState-9 {$RESULT eq [fossil test-th-eval repository]}
853
+ } else {
854
+ # NOTE: No TH1 hooks, force repository to be populated.
855
+ fossil test-th-eval --open-config "globalState repository"
856
+
857
+ test th1-globalState-9 {$RESULT eq \
858
+ [fossil test-th-eval --open-config repository]}
859
+ }
860
+}
804861
805862
###############################################################################
806863
807864
fossil test-th-eval "globalState top"
808865
test th1-globalState-10 {[string length $RESULT] == 0}
@@ -856,46 +913,138 @@
856913
test th1-reinitialize-2 {$RESULT ne ""}
857914
858915
###############################################################################
859916
860917
#
861
-# NOTE: This test may fail if the command names do not always come
862
-# out in a deterministic order from TH1.
918
+# NOTE: This test may fail if the command names do not always come out in a
919
+# deterministic order from TH1.
863920
#
864921
fossil test-th-eval "info commands"
865
-test th1-info-commands-1 {$RESULT eq {linecount htmlize date stime\
866
-enable_output uplevel dir http expr glob_match utime styleFooter encode64\
867
-catch if tclReady searchable reinitialize combobox lindex query html anoncap\
868
-randhex llength for set break regexp markdown styleHeader puts return checkout\
869
-decorate artifact trace wiki proc hascap globalState continue getParameter\
870
-hasfeature setting lsearch breakpoint upvar render repository string unset\
871
-setParameter list error info rename anycap httpize}}
922
+
923
+if {$th1Tcl} {
924
+ test th1-info-commands-1 {$RESULT eq {linecount htmlize date stime\
925
+ enable_output uplevel dir http expr glob_match utime styleFooter encode64\
926
+ catch if tclReady searchable reinitialize combobox lindex tclIsSafe query\
927
+ html anoncap randhex llength for set break regexp markdown styleHeader\
928
+ puts return checkout decorate artifact trace wiki proc tclInvoke hascap\
929
+ globalState continue getParameter hasfeature setting lsearch breakpoint\
930
+ upvar render repository string unset setParameter list error info rename\
931
+ tclExpr array anycap tclEval httpize tclMakeSafe}}
932
+} else {
933
+ test th1-info-commands-1 {$RESULT eq {linecount htmlize date stime\
934
+ enable_output uplevel dir http expr glob_match utime styleFooter encode64\
935
+ catch if tclReady searchable reinitialize combobox lindex query html\
936
+ anoncap randhex llength for set break regexp markdown styleHeader puts\
937
+ return checkout decorate artifact trace wiki proc hascap globalState\
938
+ continue getParameter hasfeature setting lsearch breakpoint upvar render\
939
+ repository string unset setParameter list error info rename array anycap\
940
+ httpize}}
941
+}
872942
873943
###############################################################################
874944
875945
fossil test-th-eval "info vars"
876
-test th1-info-vars-1 {$RESULT eq ""}
946
+
947
+if {$th1Hooks} {
948
+ test th1-info-vars-1 {$RESULT eq \
949
+ "th_stack_trace cmd_flags tcl_platform cmd_name cmd_args"}
950
+} else {
951
+ test th1-info-vars-1 {$RESULT eq "tcl_platform"}
952
+}
877953
878954
###############################################################################
879955
880956
fossil test-th-eval "set x 1; info vars"
881
-test th1-info-vars-2 {$RESULT eq "x"}
957
+
958
+if {$th1Hooks} {
959
+ test th1-info-vars-2 {$RESULT eq \
960
+ "x th_stack_trace cmd_flags tcl_platform cmd_name cmd_args"}
961
+} else {
962
+ test th1-info-vars-2 {$RESULT eq "x tcl_platform"}
963
+}
882964
883965
###############################################################################
884966
885967
fossil test-th-eval "set x 1; unset x; info vars"
886
-test th1-info-vars-3 {$RESULT eq ""}
968
+
969
+if {$th1Hooks} {
970
+ test th1-info-vars-3 {$RESULT eq \
971
+ "th_stack_trace cmd_flags tcl_platform cmd_name cmd_args"}
972
+} else {
973
+ test th1-info-vars-3 {$RESULT eq "tcl_platform"}
974
+}
887975
888976
###############################################################################
889977
890978
fossil test-th-eval "proc foo {} {set x 1; info vars}; foo"
891979
test th1-info-vars-4 {$RESULT eq "x"}
892980
893981
###############################################################################
894982
895983
fossil test-th-eval "set y 1; proc foo {} {set x 1; uplevel 1 {info vars}}; foo"
896
-test th1-info-vars-5 {$RESULT eq "y"}
984
+
985
+if {$th1Hooks} {
986
+ test th1-info-vars-5 {$RESULT eq \
987
+ "th_stack_trace y cmd_flags tcl_platform cmd_name cmd_args"}
988
+} else {
989
+ test th1-info-vars-5 {$RESULT eq "y tcl_platform"}
990
+}
991
+
992
+###############################################################################
993
+
994
+fossil test-th-eval "array exists foo"
995
+test th1-array-exists-1 {$RESULT eq "0"}
996
+
997
+###############################################################################
998
+
999
+fossil test-th-eval "set foo(x) 1; array exists foo"
1000
+test th1-array-exists-2 {$RESULT eq "1"}
1001
+
1002
+###############################################################################
1003
+
1004
+fossil test-th-eval "set foo(x) 1; unset foo(x); array exists foo"
1005
+test th1-array-exists-3 {$RESULT eq "1"}
1006
+
1007
+###############################################################################
1008
+
1009
+fossil test-th-eval "set foo(x) 1; unset foo; array exists foo"
1010
+test th1-array-exists-4 {$RESULT eq "0"}
1011
+
1012
+###############################################################################
1013
+
1014
+fossil test-th-eval "set foo 1; array exists foo"
1015
+test th1-array-exists-5 {$RESULT eq "0"}
1016
+
1017
+###############################################################################
1018
+
1019
+fossil test-th-eval "array names foo"
1020
+test th1-array-names-1 {$RESULT eq ""}
1021
+
1022
+###############################################################################
1023
+
1024
+fossil test-th-eval "set foo 2; array names foo"
1025
+test th1-array-names-2 {$RESULT eq ""}
1026
+
1027
+###############################################################################
1028
+
1029
+fossil test-th-eval "set foo 2; unset foo; set foo(x) 2; array names foo"
1030
+test th1-array-names-3 {$RESULT eq "x"}
1031
+
1032
+###############################################################################
1033
+
1034
+fossil test-th-eval "set foo(x) 2; array names foo"
1035
+test th1-array-names-4 {$RESULT eq "x"}
1036
+
1037
+###############################################################################
1038
+
1039
+fossil test-th-eval "set foo(x) 2; set foo(y) 2; array names foo"
1040
+test th1-array-names-5 {$RESULT eq "x y"}
1041
+
1042
+###############################################################################
1043
+
1044
+fossil test-th-eval "set foo(x) 2; unset foo(x); array names foo"
1045
+test th1-array-names-6 {$RESULT eq ""}
8971046
8981047
###############################################################################
8991048
9001049
fossil test-th-eval "lsearch"
9011050
test th1-lsearch-1 {$RESULT eq \
@@ -1260,10 +1409,49 @@
12601409
12611410
#
12621411
# TODO: Modify the result of this test if the source file (i.e.
12631412
# "ajax/cgi-bin/fossil-json.cgi.example") changes.
12641413
#
1265
-fossil test-th-eval --open-config \
1266
- {encode64 [artifact trunk ajax/cgi-bin/fossil-json.cgi.example]}
1414
+run_in_checkout {
1415
+ fossil test-th-eval --open-config \
1416
+ {encode64 [artifact trunk ajax/cgi-bin/fossil-json.cgi.example]}
1417
+}
12671418
12681419
test th1-encode64-3 {$RESULT eq \
12691420
"IyEvcGF0aC90by9mb3NzaWwvYmluYXJ5CnJlcG9zaXRvcnk6IC9wYXRoL3RvL3JlcG8uZnNsCg=="}
1421
+
1422
+###############################################################################
1423
+
1424
+fossil test-th-eval {array exists tcl_platform}
1425
+test th1-platform-1 {$RESULT eq "1"}
1426
+
1427
+###############################################################################
1428
+
1429
+fossil test-th-eval {array names tcl_platform}
1430
+test th1-platform-2 {$RESULT eq "engine platform"}
1431
+
1432
+###############################################################################
1433
+
1434
+fossil test-th-eval {set tcl_platform(engine)}
1435
+test th1-platform-3 {$RESULT eq "TH1"}
1436
+
1437
+###############################################################################
1438
+
1439
+fossil test-th-eval {set tcl_platform(platform)}
1440
+test th1-platform-4 {$RESULT eq "windows" || $RESULT eq "unix"}
1441
+
1442
+###############################################################################
1443
+
1444
+set th1FileName [file join $::tempPath th1-[pid].th1]
1445
+
1446
+write_file $th1FileName {
1447
+ set x ""
1448
+ for {set i 0} {$i < 10} {set i [expr {$i + 1}]} {
1449
+ set x "$x $i"
1450
+ }
1451
+ return [string trim $x]
1452
+ set y; # NOTE: Never hit.
1453
+}
1454
+
1455
+fossil test-th-source $th1FileName
1456
+test th1-source-1 {$RESULT eq {TH_RETURN: 0 1 2 3 4 5 6 7 8 9}}
1457
+file delete $th1FileName
12701458
--- test/th1.test
+++ test/th1.test
@@ -16,16 +16,16 @@
16 ############################################################################
17 #
18 # TH1 Commands
19 #
20
21 set dir [file dirname [info script]]
22
23 ###############################################################################
24
25 fossil test-th-eval --open-config "setting th1-hooks"
26 set th1Hooks [expr {$RESULT eq "1"}]
27
28 ###############################################################################
29
30 fossil test-th-eval --open-config "setting abc"
31 test th1-setting-1 {$RESULT eq ""}
@@ -554,16 +554,28 @@
554 fossil test-th-eval "lindex list -0x"
555 test th1-expr-49 {$RESULT eq {TH_ERROR: expected integer, got: "-0x"}}
556
557 ###############################################################################
558
559 fossil test-th-eval "checkout 1"; # NOTE: Assumes running "in tree".
 
 
 
 
560 test th1-checkout-1 {[string length $RESULT] > 0}
561
562 ###############################################################################
563
564 fossil test-th-eval "checkout"; # NOTE: Assumes running "in tree".
 
 
 
 
 
 
 
 
565 test th1-checkout-2 {[string length $RESULT] > 0}
566
567 ###############################################################################
568
569 set savedPwd [pwd]; cd /
@@ -639,11 +651,14 @@
639 fossil test-th-eval "styleHeader {Page Title Here}"
640 test th1-header-1 {$RESULT eq {TH_ERROR: repository unavailable}}
641
642 ###############################################################################
643
644 fossil test-th-eval --open-config "styleHeader {Page Title Here}"
 
 
 
645 test th1-header-2 {[regexp -- {<title>Fossil: Page Title Here</title>} $RESULT]}
646
647 ###############################################################################
648
649 fossil test-th-eval "styleFooter"
@@ -722,11 +737,14 @@
722 fossil test-th-eval "artifact tip"
723 test th1-artifact-2 {$RESULT eq {TH_ERROR: repository unavailable}}
724
725 ###############################################################################
726
727 fossil test-th-eval --open-config "artifact tip"
 
 
 
728 test th1-artifact-3 {[regexp -- {F test/th1\.test [0-9a-f]{40}} $RESULT]}
729
730 ###############################################################################
731
732 fossil test-th-eval "artifact 0000000000"
@@ -742,11 +760,14 @@
742 fossil test-th-eval "artifact tip test/th1.test"
743 test th1-artifact-6 {$RESULT eq {TH_ERROR: repository unavailable}}
744
745 ###############################################################################
746
747 fossil test-th-eval --open-config "artifact tip test/th1.test"
 
 
 
748 test th1-artifact-7 {[regexp -- {th1-artifact-7} $RESULT]}
749
750 ###############################################################################
751
752 fossil test-th-eval "artifact 0000000000 test/th1.test"
@@ -757,17 +778,35 @@
757 fossil test-th-eval --open-config "artifact 0000000000 test/th1.test"
758 test th1-artifact-9 {$RESULT eq {TH_ERROR: manifest not found}}
759
760 ###############################################################################
761
762 fossil test-th-eval "globalState checkout"
 
 
 
 
 
 
 
 
763 test th1-globalState-1 {[string length $RESULT] > 0}
764
765 ###############################################################################
766
767 fossil test-th-eval "globalState checkout"
768 test th1-globalState-2 {$RESULT eq [fossil test-th-eval checkout]}
 
 
 
 
 
 
 
 
 
 
769
770 ###############################################################################
771
772 fossil test-th-eval "globalState configuration"
773 test th1-globalState-3 {[string length $RESULT] == 0}
@@ -792,17 +831,35 @@
792 fossil test-th-eval --errorlog foserrors.log "globalState log"
793 test th1-globalState-7 {$RESULT eq "foserrors.log"}
794
795 ###############################################################################
796
797 fossil test-th-eval "globalState repository"
 
 
 
 
 
 
 
 
798 test th1-globalState-8 {[string length $RESULT] > 0}
799
800 ###############################################################################
801
802 fossil test-th-eval "globalState repository"
803 test th1-globalState-9 {$RESULT eq [fossil test-th-eval repository]}
 
 
 
 
 
 
 
 
 
 
804
805 ###############################################################################
806
807 fossil test-th-eval "globalState top"
808 test th1-globalState-10 {[string length $RESULT] == 0}
@@ -856,46 +913,138 @@
856 test th1-reinitialize-2 {$RESULT ne ""}
857
858 ###############################################################################
859
860 #
861 # NOTE: This test may fail if the command names do not always come
862 # out in a deterministic order from TH1.
863 #
864 fossil test-th-eval "info commands"
865 test th1-info-commands-1 {$RESULT eq {linecount htmlize date stime\
866 enable_output uplevel dir http expr glob_match utime styleFooter encode64\
867 catch if tclReady searchable reinitialize combobox lindex query html anoncap\
868 randhex llength for set break regexp markdown styleHeader puts return checkout\
869 decorate artifact trace wiki proc hascap globalState continue getParameter\
870 hasfeature setting lsearch breakpoint upvar render repository string unset\
871 setParameter list error info rename anycap httpize}}
 
 
 
 
 
 
 
 
 
 
 
 
 
872
873 ###############################################################################
874
875 fossil test-th-eval "info vars"
876 test th1-info-vars-1 {$RESULT eq ""}
 
 
 
 
 
 
877
878 ###############################################################################
879
880 fossil test-th-eval "set x 1; info vars"
881 test th1-info-vars-2 {$RESULT eq "x"}
 
 
 
 
 
 
882
883 ###############################################################################
884
885 fossil test-th-eval "set x 1; unset x; info vars"
886 test th1-info-vars-3 {$RESULT eq ""}
 
 
 
 
 
 
887
888 ###############################################################################
889
890 fossil test-th-eval "proc foo {} {set x 1; info vars}; foo"
891 test th1-info-vars-4 {$RESULT eq "x"}
892
893 ###############################################################################
894
895 fossil test-th-eval "set y 1; proc foo {} {set x 1; uplevel 1 {info vars}}; foo"
896 test th1-info-vars-5 {$RESULT eq "y"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
897
898 ###############################################################################
899
900 fossil test-th-eval "lsearch"
901 test th1-lsearch-1 {$RESULT eq \
@@ -1260,10 +1409,49 @@
1260
1261 #
1262 # TODO: Modify the result of this test if the source file (i.e.
1263 # "ajax/cgi-bin/fossil-json.cgi.example") changes.
1264 #
1265 fossil test-th-eval --open-config \
1266 {encode64 [artifact trunk ajax/cgi-bin/fossil-json.cgi.example]}
 
 
1267
1268 test th1-encode64-3 {$RESULT eq \
1269 "IyEvcGF0aC90by9mb3NzaWwvYmluYXJ5CnJlcG9zaXRvcnk6IC9wYXRoL3RvL3JlcG8uZnNsCg=="}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1270
--- test/th1.test
+++ test/th1.test
@@ -16,16 +16,16 @@
16 ############################################################################
17 #
18 # TH1 Commands
19 #
20
21 set dir [file dirname [info script]]; repo_init
22
23 ###############################################################################
24
25 set th1Tcl [is_tcl_usable_by_fossil]
26 set th1Hooks [are_th1_hooks_usable_by_fossil]
27
28 ###############################################################################
29
30 fossil test-th-eval --open-config "setting abc"
31 test th1-setting-1 {$RESULT eq ""}
@@ -554,16 +554,28 @@
554 fossil test-th-eval "lindex list -0x"
555 test th1-expr-49 {$RESULT eq {TH_ERROR: expected integer, got: "-0x"}}
556
557 ###############################################################################
558
559 run_in_checkout {
560 # NOTE: The "1" here forces the checkout to be opened.
561 fossil test-th-eval "checkout 1"
562 }
563
564 test th1-checkout-1 {[string length $RESULT] > 0}
565
566 ###############################################################################
567
568 run_in_checkout {
569 if {$th1Hooks} {
570 fossil test-th-eval "checkout"
571 } else {
572 # NOTE: No TH1 hooks, force checkout to be populated.
573 fossil test-th-eval --open-config "checkout"
574 }
575 }
576
577 test th1-checkout-2 {[string length $RESULT] > 0}
578
579 ###############################################################################
580
581 set savedPwd [pwd]; cd /
@@ -639,11 +651,14 @@
651 fossil test-th-eval "styleHeader {Page Title Here}"
652 test th1-header-1 {$RESULT eq {TH_ERROR: repository unavailable}}
653
654 ###############################################################################
655
656 run_in_checkout {
657 fossil test-th-eval --open-config "styleHeader {Page Title Here}"
658 }
659
660 test th1-header-2 {[regexp -- {<title>Fossil: Page Title Here</title>} $RESULT]}
661
662 ###############################################################################
663
664 fossil test-th-eval "styleFooter"
@@ -722,11 +737,14 @@
737 fossil test-th-eval "artifact tip"
738 test th1-artifact-2 {$RESULT eq {TH_ERROR: repository unavailable}}
739
740 ###############################################################################
741
742 run_in_checkout {
743 fossil test-th-eval --open-config "artifact tip"
744 }
745
746 test th1-artifact-3 {[regexp -- {F test/th1\.test [0-9a-f]{40}} $RESULT]}
747
748 ###############################################################################
749
750 fossil test-th-eval "artifact 0000000000"
@@ -742,11 +760,14 @@
760 fossil test-th-eval "artifact tip test/th1.test"
761 test th1-artifact-6 {$RESULT eq {TH_ERROR: repository unavailable}}
762
763 ###############################################################################
764
765 run_in_checkout {
766 fossil test-th-eval --open-config "artifact tip test/th1.test"
767 }
768
769 test th1-artifact-7 {[regexp -- {th1-artifact-7} $RESULT]}
770
771 ###############################################################################
772
773 fossil test-th-eval "artifact 0000000000 test/th1.test"
@@ -757,17 +778,35 @@
778 fossil test-th-eval --open-config "artifact 0000000000 test/th1.test"
779 test th1-artifact-9 {$RESULT eq {TH_ERROR: manifest not found}}
780
781 ###############################################################################
782
783 run_in_checkout {
784 if {$th1Hooks} {
785 fossil test-th-eval "globalState checkout"
786 } else {
787 # NOTE: No TH1 hooks, force checkout to be populated.
788 fossil test-th-eval --open-config "globalState checkout"
789 }
790 }
791
792 test th1-globalState-1 {[string length $RESULT] > 0}
793
794 ###############################################################################
795
796 run_in_checkout {
797 if {$th1Hooks} {
798 fossil test-th-eval "globalState checkout"
799 test th1-globalState-2 {$RESULT eq [fossil test-th-eval checkout]}
800 } else {
801 # NOTE: No TH1 hooks, force checkout to be populated.
802 fossil test-th-eval --open-config "globalState checkout"
803
804 test th1-globalState-2 {$RESULT eq \
805 [fossil test-th-eval --open-config checkout]}
806 }
807 }
808
809 ###############################################################################
810
811 fossil test-th-eval "globalState configuration"
812 test th1-globalState-3 {[string length $RESULT] == 0}
@@ -792,17 +831,35 @@
831 fossil test-th-eval --errorlog foserrors.log "globalState log"
832 test th1-globalState-7 {$RESULT eq "foserrors.log"}
833
834 ###############################################################################
835
836 run_in_checkout {
837 if {$th1Hooks} {
838 fossil test-th-eval "globalState repository"
839 } else {
840 # NOTE: No TH1 hooks, force repository to be populated.
841 fossil test-th-eval --open-config "globalState repository"
842 }
843 }
844
845 test th1-globalState-8 {[string length $RESULT] > 0}
846
847 ###############################################################################
848
849 run_in_checkout {
850 if {$th1Hooks} {
851 fossil test-th-eval "globalState repository"
852 test th1-globalState-9 {$RESULT eq [fossil test-th-eval repository]}
853 } else {
854 # NOTE: No TH1 hooks, force repository to be populated.
855 fossil test-th-eval --open-config "globalState repository"
856
857 test th1-globalState-9 {$RESULT eq \
858 [fossil test-th-eval --open-config repository]}
859 }
860 }
861
862 ###############################################################################
863
864 fossil test-th-eval "globalState top"
865 test th1-globalState-10 {[string length $RESULT] == 0}
@@ -856,46 +913,138 @@
913 test th1-reinitialize-2 {$RESULT ne ""}
914
915 ###############################################################################
916
917 #
918 # NOTE: This test may fail if the command names do not always come out in a
919 # deterministic order from TH1.
920 #
921 fossil test-th-eval "info commands"
922
923 if {$th1Tcl} {
924 test th1-info-commands-1 {$RESULT eq {linecount htmlize date stime\
925 enable_output uplevel dir http expr glob_match utime styleFooter encode64\
926 catch if tclReady searchable reinitialize combobox lindex tclIsSafe query\
927 html anoncap randhex llength for set break regexp markdown styleHeader\
928 puts return checkout decorate artifact trace wiki proc tclInvoke hascap\
929 globalState continue getParameter hasfeature setting lsearch breakpoint\
930 upvar render repository string unset setParameter list error info rename\
931 tclExpr array anycap tclEval httpize tclMakeSafe}}
932 } else {
933 test th1-info-commands-1 {$RESULT eq {linecount htmlize date stime\
934 enable_output uplevel dir http expr glob_match utime styleFooter encode64\
935 catch if tclReady searchable reinitialize combobox lindex query html\
936 anoncap randhex llength for set break regexp markdown styleHeader puts\
937 return checkout decorate artifact trace wiki proc hascap globalState\
938 continue getParameter hasfeature setting lsearch breakpoint upvar render\
939 repository string unset setParameter list error info rename array anycap\
940 httpize}}
941 }
942
943 ###############################################################################
944
945 fossil test-th-eval "info vars"
946
947 if {$th1Hooks} {
948 test th1-info-vars-1 {$RESULT eq \
949 "th_stack_trace cmd_flags tcl_platform cmd_name cmd_args"}
950 } else {
951 test th1-info-vars-1 {$RESULT eq "tcl_platform"}
952 }
953
954 ###############################################################################
955
956 fossil test-th-eval "set x 1; info vars"
957
958 if {$th1Hooks} {
959 test th1-info-vars-2 {$RESULT eq \
960 "x th_stack_trace cmd_flags tcl_platform cmd_name cmd_args"}
961 } else {
962 test th1-info-vars-2 {$RESULT eq "x tcl_platform"}
963 }
964
965 ###############################################################################
966
967 fossil test-th-eval "set x 1; unset x; info vars"
968
969 if {$th1Hooks} {
970 test th1-info-vars-3 {$RESULT eq \
971 "th_stack_trace cmd_flags tcl_platform cmd_name cmd_args"}
972 } else {
973 test th1-info-vars-3 {$RESULT eq "tcl_platform"}
974 }
975
976 ###############################################################################
977
978 fossil test-th-eval "proc foo {} {set x 1; info vars}; foo"
979 test th1-info-vars-4 {$RESULT eq "x"}
980
981 ###############################################################################
982
983 fossil test-th-eval "set y 1; proc foo {} {set x 1; uplevel 1 {info vars}}; foo"
984
985 if {$th1Hooks} {
986 test th1-info-vars-5 {$RESULT eq \
987 "th_stack_trace y cmd_flags tcl_platform cmd_name cmd_args"}
988 } else {
989 test th1-info-vars-5 {$RESULT eq "y tcl_platform"}
990 }
991
992 ###############################################################################
993
994 fossil test-th-eval "array exists foo"
995 test th1-array-exists-1 {$RESULT eq "0"}
996
997 ###############################################################################
998
999 fossil test-th-eval "set foo(x) 1; array exists foo"
1000 test th1-array-exists-2 {$RESULT eq "1"}
1001
1002 ###############################################################################
1003
1004 fossil test-th-eval "set foo(x) 1; unset foo(x); array exists foo"
1005 test th1-array-exists-3 {$RESULT eq "1"}
1006
1007 ###############################################################################
1008
1009 fossil test-th-eval "set foo(x) 1; unset foo; array exists foo"
1010 test th1-array-exists-4 {$RESULT eq "0"}
1011
1012 ###############################################################################
1013
1014 fossil test-th-eval "set foo 1; array exists foo"
1015 test th1-array-exists-5 {$RESULT eq "0"}
1016
1017 ###############################################################################
1018
1019 fossil test-th-eval "array names foo"
1020 test th1-array-names-1 {$RESULT eq ""}
1021
1022 ###############################################################################
1023
1024 fossil test-th-eval "set foo 2; array names foo"
1025 test th1-array-names-2 {$RESULT eq ""}
1026
1027 ###############################################################################
1028
1029 fossil test-th-eval "set foo 2; unset foo; set foo(x) 2; array names foo"
1030 test th1-array-names-3 {$RESULT eq "x"}
1031
1032 ###############################################################################
1033
1034 fossil test-th-eval "set foo(x) 2; array names foo"
1035 test th1-array-names-4 {$RESULT eq "x"}
1036
1037 ###############################################################################
1038
1039 fossil test-th-eval "set foo(x) 2; set foo(y) 2; array names foo"
1040 test th1-array-names-5 {$RESULT eq "x y"}
1041
1042 ###############################################################################
1043
1044 fossil test-th-eval "set foo(x) 2; unset foo(x); array names foo"
1045 test th1-array-names-6 {$RESULT eq ""}
1046
1047 ###############################################################################
1048
1049 fossil test-th-eval "lsearch"
1050 test th1-lsearch-1 {$RESULT eq \
@@ -1260,10 +1409,49 @@
1409
1410 #
1411 # TODO: Modify the result of this test if the source file (i.e.
1412 # "ajax/cgi-bin/fossil-json.cgi.example") changes.
1413 #
1414 run_in_checkout {
1415 fossil test-th-eval --open-config \
1416 {encode64 [artifact trunk ajax/cgi-bin/fossil-json.cgi.example]}
1417 }
1418
1419 test th1-encode64-3 {$RESULT eq \
1420 "IyEvcGF0aC90by9mb3NzaWwvYmluYXJ5CnJlcG9zaXRvcnk6IC9wYXRoL3RvL3JlcG8uZnNsCg=="}
1421
1422 ###############################################################################
1423
1424 fossil test-th-eval {array exists tcl_platform}
1425 test th1-platform-1 {$RESULT eq "1"}
1426
1427 ###############################################################################
1428
1429 fossil test-th-eval {array names tcl_platform}
1430 test th1-platform-2 {$RESULT eq "engine platform"}
1431
1432 ###############################################################################
1433
1434 fossil test-th-eval {set tcl_platform(engine)}
1435 test th1-platform-3 {$RESULT eq "TH1"}
1436
1437 ###############################################################################
1438
1439 fossil test-th-eval {set tcl_platform(platform)}
1440 test th1-platform-4 {$RESULT eq "windows" || $RESULT eq "unix"}
1441
1442 ###############################################################################
1443
1444 set th1FileName [file join $::tempPath th1-[pid].th1]
1445
1446 write_file $th1FileName {
1447 set x ""
1448 for {set i 0} {$i < 10} {set i [expr {$i + 1}]} {
1449 set x "$x $i"
1450 }
1451 return [string trim $x]
1452 set y; # NOTE: Never hit.
1453 }
1454
1455 fossil test-th-source $th1FileName
1456 test th1-source-1 {$RESULT eq {TH_RETURN: 0 1 2 3 4 5 6 7 8 9}}
1457 file delete $th1FileName
1458
--- test/utf.test
+++ test/utf.test
@@ -39,26 +39,29 @@
3939
test utf-check-$testname.$i {$::RESULT eq $result}
4040
incr i
4141
}
4242
}
4343
44
+unset -nocomplain enc
4445
array set enc [list \
4546
0 binary \
4647
1 binary \
4748
2 unicode \
4849
3 unicode-reverse \
4950
]
5051
52
+unset -nocomplain bom
5153
array set bom [list \
5254
0 "" \
5355
1 \xEF\xBB\xBF \
5456
2 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
5557
"\xFF\xFE" : "\xFE\xFF"}] \
5658
3 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
5759
"\xFE\xFF" : "\xFF\xFE"}] \
5860
]
5961
62
+unset -nocomplain data
6063
array set data [list \
6164
0 "" \
6265
1 \r \
6366
2 \n \
6467
3 \r\n \
@@ -239,10 +242,11 @@
239242
178 \xF4\x90\x80\x80\r \
240243
179 \xF4\x90\x80\x80\n \
241244
180 \xF4\x90\x80\x80\r\n \
242245
]
243246
247
+unset -nocomplain extraData
244248
array set extraData [list \
245249
0 "" \
246250
1 Z \
247251
]
248252
249253
--- test/utf.test
+++ test/utf.test
@@ -39,26 +39,29 @@
39 test utf-check-$testname.$i {$::RESULT eq $result}
40 incr i
41 }
42 }
43
 
44 array set enc [list \
45 0 binary \
46 1 binary \
47 2 unicode \
48 3 unicode-reverse \
49 ]
50
 
51 array set bom [list \
52 0 "" \
53 1 \xEF\xBB\xBF \
54 2 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
55 "\xFF\xFE" : "\xFE\xFF"}] \
56 3 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
57 "\xFE\xFF" : "\xFF\xFE"}] \
58 ]
59
 
60 array set data [list \
61 0 "" \
62 1 \r \
63 2 \n \
64 3 \r\n \
@@ -239,10 +242,11 @@
239 178 \xF4\x90\x80\x80\r \
240 179 \xF4\x90\x80\x80\n \
241 180 \xF4\x90\x80\x80\r\n \
242 ]
243
 
244 array set extraData [list \
245 0 "" \
246 1 Z \
247 ]
248
249
--- test/utf.test
+++ test/utf.test
@@ -39,26 +39,29 @@
39 test utf-check-$testname.$i {$::RESULT eq $result}
40 incr i
41 }
42 }
43
44 unset -nocomplain enc
45 array set enc [list \
46 0 binary \
47 1 binary \
48 2 unicode \
49 3 unicode-reverse \
50 ]
51
52 unset -nocomplain bom
53 array set bom [list \
54 0 "" \
55 1 \xEF\xBB\xBF \
56 2 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
57 "\xFF\xFE" : "\xFE\xFF"}] \
58 3 [expr {$tcl_platform(byteOrder) eq "littleEndian" ? \
59 "\xFE\xFF" : "\xFF\xFE"}] \
60 ]
61
62 unset -nocomplain data
63 array set data [list \
64 0 "" \
65 1 \r \
66 2 \n \
67 3 \r\n \
@@ -239,10 +242,11 @@
242 178 \xF4\x90\x80\x80\r \
243 179 \xF4\x90\x80\x80\n \
244 180 \xF4\x90\x80\x80\r\n \
245 ]
246
247 unset -nocomplain extraData
248 array set extraData [list \
249 0 "" \
250 1 Z \
251 ]
252
253
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -158,11 +158,11 @@
158158
#### The directories where the OpenSSL include and library files are located.
159159
# The recommended usage here is to use the Sysinternals junction tool
160160
# to create a hard link between an "openssl-1.x" sub-directory of the
161161
# Fossil source code directory and the target OpenSSL source directory.
162162
#
163
-OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2e
163
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2f
164164
OPENSSLINCDIR = $(OPENSSLDIR)/include
165165
OPENSSLLIBDIR = $(OPENSSLDIR)
166166
167167
#### Either the directory where the Tcl library is installed or the Tcl
168168
# source code directory resides (depending on the value of the macro
@@ -972,11 +972,11 @@
972972
APPTARGETS += openssl
973973
endif
974974
975975
$(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
976976
$(CODECHECK1) $(TRANS_SRC)
977
- $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
977
+ $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB)
978978
979979
# This rule prevents make from using its default rules to try build
980980
# an executable named "manifest" out of the file named "manifest.c"
981981
#
982982
$(SRCDIR)/../manifest:
983983
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -158,11 +158,11 @@
158 #### The directories where the OpenSSL include and library files are located.
159 # The recommended usage here is to use the Sysinternals junction tool
160 # to create a hard link between an "openssl-1.x" sub-directory of the
161 # Fossil source code directory and the target OpenSSL source directory.
162 #
163 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2e
164 OPENSSLINCDIR = $(OPENSSLDIR)/include
165 OPENSSLLIBDIR = $(OPENSSLDIR)
166
167 #### Either the directory where the Tcl library is installed or the Tcl
168 # source code directory resides (depending on the value of the macro
@@ -972,11 +972,11 @@
972 APPTARGETS += openssl
973 endif
974
975 $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
976 $(CODECHECK1) $(TRANS_SRC)
977 $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
978
979 # This rule prevents make from using its default rules to try build
980 # an executable named "manifest" out of the file named "manifest.c"
981 #
982 $(SRCDIR)/../manifest:
983
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -158,11 +158,11 @@
158 #### The directories where the OpenSSL include and library files are located.
159 # The recommended usage here is to use the Sysinternals junction tool
160 # to create a hard link between an "openssl-1.x" sub-directory of the
161 # Fossil source code directory and the target OpenSSL source directory.
162 #
163 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2f
164 OPENSSLINCDIR = $(OPENSSLDIR)/include
165 OPENSSLLIBDIR = $(OPENSSLDIR)
166
167 #### Either the directory where the Tcl library is installed or the Tcl
168 # source code directory resides (depending on the value of the macro
@@ -972,11 +972,11 @@
972 APPTARGETS += openssl
973 endif
974
975 $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
976 $(CODECHECK1) $(TRANS_SRC)
977 $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB)
978
979 # This rule prevents make from using its default rules to try build
980 # an executable named "manifest" out of the file named "manifest.c"
981 #
982 $(SRCDIR)/../manifest:
983
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -158,11 +158,11 @@
158158
#### The directories where the OpenSSL include and library files are located.
159159
# The recommended usage here is to use the Sysinternals junction tool
160160
# to create a hard link between an "openssl-1.x" sub-directory of the
161161
# Fossil source code directory and the target OpenSSL source directory.
162162
#
163
-OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2e
163
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2f
164164
OPENSSLINCDIR = $(OPENSSLDIR)/include
165165
OPENSSLLIBDIR = $(OPENSSLDIR)
166166
167167
#### Either the directory where the Tcl library is installed or the Tcl
168168
# source code directory resides (depending on the value of the macro
@@ -972,11 +972,11 @@
972972
APPTARGETS += openssl
973973
endif
974974
975975
$(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
976976
$(CODECHECK1) $(TRANS_SRC)
977
- $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
977
+ $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB)
978978
979979
# This rule prevents make from using its default rules to try build
980980
# an executable named "manifest" out of the file named "manifest.c"
981981
#
982982
$(SRCDIR)/../manifest:
983983
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -158,11 +158,11 @@
158 #### The directories where the OpenSSL include and library files are located.
159 # The recommended usage here is to use the Sysinternals junction tool
160 # to create a hard link between an "openssl-1.x" sub-directory of the
161 # Fossil source code directory and the target OpenSSL source directory.
162 #
163 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2e
164 OPENSSLINCDIR = $(OPENSSLDIR)/include
165 OPENSSLLIBDIR = $(OPENSSLDIR)
166
167 #### Either the directory where the Tcl library is installed or the Tcl
168 # source code directory resides (depending on the value of the macro
@@ -972,11 +972,11 @@
972 APPTARGETS += openssl
973 endif
974
975 $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
976 $(CODECHECK1) $(TRANS_SRC)
977 $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
978
979 # This rule prevents make from using its default rules to try build
980 # an executable named "manifest" out of the file named "manifest.c"
981 #
982 $(SRCDIR)/../manifest:
983
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -158,11 +158,11 @@
158 #### The directories where the OpenSSL include and library files are located.
159 # The recommended usage here is to use the Sysinternals junction tool
160 # to create a hard link between an "openssl-1.x" sub-directory of the
161 # Fossil source code directory and the target OpenSSL source directory.
162 #
163 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2f
164 OPENSSLINCDIR = $(OPENSSLDIR)/include
165 OPENSSLLIBDIR = $(OPENSSLDIR)
166
167 #### Either the directory where the Tcl library is installed or the Tcl
168 # source code directory resides (depending on the value of the macro
@@ -972,11 +972,11 @@
972 APPTARGETS += openssl
973 endif
974
975 $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o
976 $(CODECHECK1) $(TRANS_SRC)
977 $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB)
978
979 # This rule prevents make from using its default rules to try build
980 # an executable named "manifest" out of the file named "manifest.c"
981 #
982 $(SRCDIR)/../manifest:
983
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -93,11 +93,11 @@
9393
!ifndef FOSSIL_ENABLE_WINXP
9494
FOSSIL_ENABLE_WINXP = 0
9595
!endif
9696
9797
!if $(FOSSIL_ENABLE_SSL)!=0
98
-SSLDIR = $(B)\compat\openssl-1.0.2e
98
+SSLDIR = $(B)\compat\openssl-1.0.2f
9999
SSLINCDIR = $(SSLDIR)\inc32
100100
!if $(FOSSIL_DYNAMIC_BUILD)!=0
101101
SSLLIBDIR = $(SSLDIR)\out32dll
102102
!else
103103
SSLLIBDIR = $(SSLDIR)\out32
104104
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -93,11 +93,11 @@
93 !ifndef FOSSIL_ENABLE_WINXP
94 FOSSIL_ENABLE_WINXP = 0
95 !endif
96
97 !if $(FOSSIL_ENABLE_SSL)!=0
98 SSLDIR = $(B)\compat\openssl-1.0.2e
99 SSLINCDIR = $(SSLDIR)\inc32
100 !if $(FOSSIL_DYNAMIC_BUILD)!=0
101 SSLLIBDIR = $(SSLDIR)\out32dll
102 !else
103 SSLLIBDIR = $(SSLDIR)\out32
104
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -93,11 +93,11 @@
93 !ifndef FOSSIL_ENABLE_WINXP
94 FOSSIL_ENABLE_WINXP = 0
95 !endif
96
97 !if $(FOSSIL_ENABLE_SSL)!=0
98 SSLDIR = $(B)\compat\openssl-1.0.2f
99 SSLINCDIR = $(SSLDIR)\inc32
100 !if $(FOSSIL_DYNAMIC_BUILD)!=0
101 SSLLIBDIR = $(SSLDIR)\out32dll
102 !else
103 SSLLIBDIR = $(SSLDIR)\out32
104
--- win/buildmsvc.bat
+++ win/buildmsvc.bat
@@ -259,12 +259,14 @@
259259
CALL :fn_UnsetVariable PFILES_SDK71A
260260
SET NMAKE_ARGS=%NMAKE_ARGS% FOSSIL_ENABLE_WINXP=1
261261
GOTO :EOF
262262
263263
:fn_UnsetVariable
264
- IF NOT "%1" == "" (
265
- SET %1=
264
+ SET VALUE=%1
265
+ IF DEFINED VALUE (
266
+ SET %VALUE%=
267
+ SET VALUE=
266268
CALL :fn_ResetErrorLevel
267269
)
268270
GOTO :EOF
269271
270272
:fn_ResetErrorLevel
271273
--- win/buildmsvc.bat
+++ win/buildmsvc.bat
@@ -259,12 +259,14 @@
259 CALL :fn_UnsetVariable PFILES_SDK71A
260 SET NMAKE_ARGS=%NMAKE_ARGS% FOSSIL_ENABLE_WINXP=1
261 GOTO :EOF
262
263 :fn_UnsetVariable
264 IF NOT "%1" == "" (
265 SET %1=
 
 
266 CALL :fn_ResetErrorLevel
267 )
268 GOTO :EOF
269
270 :fn_ResetErrorLevel
271
--- win/buildmsvc.bat
+++ win/buildmsvc.bat
@@ -259,12 +259,14 @@
259 CALL :fn_UnsetVariable PFILES_SDK71A
260 SET NMAKE_ARGS=%NMAKE_ARGS% FOSSIL_ENABLE_WINXP=1
261 GOTO :EOF
262
263 :fn_UnsetVariable
264 SET VALUE=%1
265 IF DEFINED VALUE (
266 SET %VALUE%=
267 SET VALUE=
268 CALL :fn_ResetErrorLevel
269 )
270 GOTO :EOF
271
272 :fn_ResetErrorLevel
273
+14 -8
--- www/build.wiki
+++ www/build.wiki
@@ -111,23 +111,29 @@
111111
<li><p><i>Unix without running "configure"</i> → if you prefer to avoid
112112
running configure, you can also use: <b>make -f Makefile.classic</b>. You may
113113
want to make minor edits to Makefile.classic to configure the build for your
114114
system.
115115
116
-<li><p><i>MinGW3.x (not 4.0)/MinGW-w64</i> → Use the mingw makefile:
117
-"<b>make -f win/Makefile.mingw</b>". On a Windows box you will
118
-need either Cygwin or Msys as build environment. On Cygwin, Linux
119
-or Darwin you may want to make minor edits to win/Makefile.mingw
120
-to configure the cross-compile environment.
116
+<li><p><i>MinGW 3.x (<u>not</u> 4.x) / MinGW-w64</i> → Use the MinGW makefile:
117
+"<b>make -f win/Makefile.mingw</b>". On a Windows box you will need either
118
+Cygwin or Msys as build environment. On Cygwin, Linux or Darwin you may want
119
+to make minor edits to win/Makefile.mingw to configure the cross-compile
120
+environment.
121121
122122
To enable the native [./th1.md#tclEval | Tcl integration feature], use a
123123
command line like the following (all on one line):
124124
125125
<b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>
126126
127
-Hint: don't use MinGW-4.0, it will compile but fossil won't work correctly, see
128
-<a href="https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c">https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c</a>.
127
+Alternatively, <b>./configure</b> may now be used to create a Makefile
128
+suitable for use with MinGW; however, options passed to configure that are
129
+not applicable on Windows may cause the configuration or compilation to fail
130
+(e.g. fusefs, internal-sqlite, etc).
131
+
132
+<i>HINT</i>: Do <u>not</u> use MinGW-4.x, it may compile but the Fossil binary
133
+will not work correctly, see
134
+[https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c | ticket].
129135
130136
<li><p><i>MSVC</i> → Use the MSVC makefile. First
131137
change to the "win/" subdirectory ("<b>cd win</b>") then run
132138
"<b>nmake /f Makefile.msc</b>".<br><br>Alternatively, the batch
133139
file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
@@ -135,11 +141,11 @@
135141
the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
136142
first <a href="https://www.openssl.org/source/">download the official
137143
source code for OpenSSL</a> and extract it to an appropriately named
138144
"<b>openssl-X.Y.ZA</b>" subdirectory within the local
139145
[/tree?ci=trunk&name=compat | compat] directory (e.g.
140
-"<b>compat/openssl-1.0.2e</b>"), then make sure that some recent
146
+"<b>compat/openssl-1.0.2f</b>"), then make sure that some recent
141147
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
142148
and finally run one of the following commands:
143149
<blockquote><pre>
144150
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
145151
</pre></blockquote>
146152
--- www/build.wiki
+++ www/build.wiki
@@ -111,23 +111,29 @@
111 <li><p><i>Unix without running "configure"</i> → if you prefer to avoid
112 running configure, you can also use: <b>make -f Makefile.classic</b>. You may
113 want to make minor edits to Makefile.classic to configure the build for your
114 system.
115
116 <li><p><i>MinGW3.x (not 4.0)/MinGW-w64</i> → Use the mingw makefile:
117 "<b>make -f win/Makefile.mingw</b>". On a Windows box you will
118 need either Cygwin or Msys as build environment. On Cygwin, Linux
119 or Darwin you may want to make minor edits to win/Makefile.mingw
120 to configure the cross-compile environment.
121
122 To enable the native [./th1.md#tclEval | Tcl integration feature], use a
123 command line like the following (all on one line):
124
125 <b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>
126
127 Hint: don't use MinGW-4.0, it will compile but fossil won't work correctly, see
128 <a href="https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c">https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c</a>.
 
 
 
 
 
 
129
130 <li><p><i>MSVC</i> → Use the MSVC makefile. First
131 change to the "win/" subdirectory ("<b>cd win</b>") then run
132 "<b>nmake /f Makefile.msc</b>".<br><br>Alternatively, the batch
133 file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
@@ -135,11 +141,11 @@
135 the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
136 first <a href="https://www.openssl.org/source/">download the official
137 source code for OpenSSL</a> and extract it to an appropriately named
138 "<b>openssl-X.Y.ZA</b>" subdirectory within the local
139 [/tree?ci=trunk&name=compat | compat] directory (e.g.
140 "<b>compat/openssl-1.0.2e</b>"), then make sure that some recent
141 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
142 and finally run one of the following commands:
143 <blockquote><pre>
144 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
145 </pre></blockquote>
146
--- www/build.wiki
+++ www/build.wiki
@@ -111,23 +111,29 @@
111 <li><p><i>Unix without running "configure"</i> → if you prefer to avoid
112 running configure, you can also use: <b>make -f Makefile.classic</b>. You may
113 want to make minor edits to Makefile.classic to configure the build for your
114 system.
115
116 <li><p><i>MinGW 3.x (<u>not</u> 4.x) / MinGW-w64</i> → Use the MinGW makefile:
117 "<b>make -f win/Makefile.mingw</b>". On a Windows box you will need either
118 Cygwin or Msys as build environment. On Cygwin, Linux or Darwin you may want
119 to make minor edits to win/Makefile.mingw to configure the cross-compile
120 environment.
121
122 To enable the native [./th1.md#tclEval | Tcl integration feature], use a
123 command line like the following (all on one line):
124
125 <b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>
126
127 Alternatively, <b>./configure</b> may now be used to create a Makefile
128 suitable for use with MinGW; however, options passed to configure that are
129 not applicable on Windows may cause the configuration or compilation to fail
130 (e.g. fusefs, internal-sqlite, etc).
131
132 <i>HINT</i>: Do <u>not</u> use MinGW-4.x, it may compile but the Fossil binary
133 will not work correctly, see
134 [https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c | ticket].
135
136 <li><p><i>MSVC</i> → Use the MSVC makefile. First
137 change to the "win/" subdirectory ("<b>cd win</b>") then run
138 "<b>nmake /f Makefile.msc</b>".<br><br>Alternatively, the batch
139 file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
@@ -135,11 +141,11 @@
141 the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
142 first <a href="https://www.openssl.org/source/">download the official
143 source code for OpenSSL</a> and extract it to an appropriately named
144 "<b>openssl-X.Y.ZA</b>" subdirectory within the local
145 [/tree?ci=trunk&name=compat | compat] directory (e.g.
146 "<b>compat/openssl-1.0.2f</b>"), then make sure that some recent
147 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
148 and finally run one of the following commands:
149 <blockquote><pre>
150 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
151 </pre></blockquote>
152
+11 -1
--- www/changes.wiki
+++ www/changes.wiki
@@ -14,15 +14,25 @@
1414
the ancestors of a particular file version, it only shows direct
1515
ancestors and omits changes on branches, thus making it show the same set
1616
of ancestors that are used for [/help?cmd=/blame|/blame].
1717
* Added the --page option to the [/help?cmd=ui|fossil ui] command
1818
* Added the [/help?cmd=bisect|fossil bisect ui] command
19
- * Enhanced the [/help?cmd=diff|fossil diff] command so that it accepts
19
+ * Enhanced the [/help?cmd=diff|fossil diff] command so that it accepts
2020
directory names as arguments and computes diffs on all files contained
2121
within those directories.
2222
* Fix the [/help?cmd=add|fossil add] command so that it shows "SKIP" for
2323
files added that were already under management.
24
+ * TH1 enhancements:
25
+ <ul><li>Add <nowiki>[array exists]</nowiki> command.</li>
26
+ <li>Add minimal <nowiki>[array names]</nowiki> command.</li>
27
+ <li>Add tcl_platform(engine) and tcl_platform(platform) array
28
+ elements.</li>
29
+ </ul>
30
+ * Get autosetup working with MinGW.
31
+ * Fix autosetup detection of zlib in the source tree.
32
+ * Added autosetup detection of OpenSSL when it may be present under the
33
+ "compat" subdirectory of the source tree.
2434
2535
<h2>Changes for Version 1.34 (2015-11-02)</h2>
2636
2737
* Make the [/help?cmd=clean|fossil clean] command undoable for files less
2838
than 10MiB.
2939
--- www/changes.wiki
+++ www/changes.wiki
@@ -14,15 +14,25 @@
14 the ancestors of a particular file version, it only shows direct
15 ancestors and omits changes on branches, thus making it show the same set
16 of ancestors that are used for [/help?cmd=/blame|/blame].
17 * Added the --page option to the [/help?cmd=ui|fossil ui] command
18 * Added the [/help?cmd=bisect|fossil bisect ui] command
19 * Enhanced the [/help?cmd=diff|fossil diff] command so that it accepts
20 directory names as arguments and computes diffs on all files contained
21 within those directories.
22 * Fix the [/help?cmd=add|fossil add] command so that it shows "SKIP" for
23 files added that were already under management.
 
 
 
 
 
 
 
 
 
 
24
25 <h2>Changes for Version 1.34 (2015-11-02)</h2>
26
27 * Make the [/help?cmd=clean|fossil clean] command undoable for files less
28 than 10MiB.
29
--- www/changes.wiki
+++ www/changes.wiki
@@ -14,15 +14,25 @@
14 the ancestors of a particular file version, it only shows direct
15 ancestors and omits changes on branches, thus making it show the same set
16 of ancestors that are used for [/help?cmd=/blame|/blame].
17 * Added the --page option to the [/help?cmd=ui|fossil ui] command
18 * Added the [/help?cmd=bisect|fossil bisect ui] command
19 * Enhanced the [/help?cmd=diff|fossil diff] command so that it accepts
20 directory names as arguments and computes diffs on all files contained
21 within those directories.
22 * Fix the [/help?cmd=add|fossil add] command so that it shows "SKIP" for
23 files added that were already under management.
24 * TH1 enhancements:
25 <ul><li>Add <nowiki>[array exists]</nowiki> command.</li>
26 <li>Add minimal <nowiki>[array names]</nowiki> command.</li>
27 <li>Add tcl_platform(engine) and tcl_platform(platform) array
28 elements.</li>
29 </ul>
30 * Get autosetup working with MinGW.
31 * Fix autosetup detection of zlib in the source tree.
32 * Added autosetup detection of OpenSSL when it may be present under the
33 "compat" subdirectory of the source tree.
34
35 <h2>Changes for Version 1.34 (2015-11-02)</h2>
36
37 * Make the [/help?cmd=clean|fossil clean] command undoable for files less
38 than 10MiB.
39
+47 -6
--- www/th1.md
+++ www/th1.md
@@ -83,10 +83,12 @@
8383
The original Tcl language after when TH1 is modeled has a very rich
8484
repertoire of commands. TH1, as it is designed to be minimalist and
8585
embedded has a greatly reduced command set. The following bullets
8686
summarize the commands available in TH1:
8787
88
+ * array exists VARNAME
89
+ * array names VARNAME
8890
* break
8991
* catch SCRIPT ?VARIABLE?
9092
* continue
9193
* error ?STRING?
9294
* expr EXPR
@@ -116,10 +118,17 @@
116118
117119
All of the above commands work as in the original Tcl. Refer to the
118120
<a href="https://www.tcl-lang.org/man/tcl/contents.htm">Tcl documentation</a>
119121
for details.
120122
123
+Summary of Core TH1 Variables
124
+-----------------------------
125
+
126
+ * tcl\_platform(engine) -- _This will always have the value "TH1"._
127
+ * tcl\_platform(platform) -- _This will have the value "windows" or "unix"._
128
+ * th\_stack\_trace -- _This will contain error stack information._
129
+
121130
TH1 Extended Commands
122131
---------------------
123132
124133
There are many new commands added to TH1 and used to access the special
125134
features of Fossil. The following is a summary of the extended commands:
@@ -130,26 +139,28 @@
130139
* checkout
131140
* combobox
132141
* date
133142
* decorate
134143
* dir
135
- * enable_output
144
+ * enable\_output
136145
* encode64
137146
* getParameter
138
- * glob_match
147
+ * glob\_match
139148
* globalState
140149
* hascap
141150
* hasfeature
142151
* html
143152
* htmlize
144153
* http
145154
* httpize
155
+ * insertCsrf
146156
* linecount
147157
* markdown
148158
* puts
149159
* query
150160
* randhex
161
+ * redirect
151162
* regexp
152163
* reinitialize
153164
* render
154165
* repository
155166
* searchable
@@ -164,10 +175,11 @@
164175
* tclMakeSafe
165176
* tclReady
166177
* trace
167178
* stime
168179
* utime
180
+ * verifyCsrf
169181
* wiki
170182
171183
Each of the commands above is documented by a block comment above their
172184
implementation in the th\_main.c or th\_tcl.c source files.
173185
@@ -248,14 +260,14 @@
248260
If DETAILS is non-zero, the result will be a list-of-lists, with each
249261
element containing at least three elements: the file name, the file
250262
size (in bytes), and the file last modification time (relative to the
251263
time zone configured for the repository).
252264
253
-<a name="enable_output"></a>TH1 enable_output Command
------------------------------------------------------
265
+<a name="enable_output"></a>TH1 enable\_output Command
266
+------------------------------------------------------
254267
255
- * enable_output BOOLEAN
268
+ * enable\_output BOOLEAN
256269
257270
Enable or disable sending output when the combobox, puts, or wiki
258271
commands are used.
259272
260273
<a name="encode64"></a>TH1 encode64 Command
@@ -271,14 +283,14 @@
271283
* getParameter NAME ?DEFAULT?
272284
273285
Returns the value of the specified query parameter or the specified
274286
default value when there is no matching query parameter.
275287
276
-<a name="glob_match"></a>TH1 glob_match Command
------------------------------------------------
288
+<a name="glob_match"></a>TH1 glob\_match Command
289
+------------------------------------------------
277290
278
- * glob_match ?-one? ?--? patternList string
291
+ * glob\_match ?-one? ?--? patternList string
279292
280293
Checks the string against the specified glob pattern -OR- list of glob
281294
patterns and returns non-zero if there is a match.
282295
283296
<a name="globalState"></a>TH1 globalState Command
@@ -369,10 +381,18 @@
369381
370382
* httpize STRING
371383
372384
Escape all characters of STRING which have special meaning in URI
373385
components. Returns the escaped string.
386
+
387
+<a name="insertCsrf"></a>TH1 insertCsrf Command
388
+-----------------------------------------------
389
+
390
+ * insertCsrf
391
+
392
+While rendering a form, call this command to add the Anti-CSRF token
393
+as a hidden element of the form.
374394
375395
<a name="linecount"></a>TH1 linecount Command
376396
---------------------------------------------
377397
378398
* linecount STRING MAX MIN
@@ -413,10 +433,18 @@
413433
414434
* randhex N
415435
416436
Returns a string of N*2 random hexadecimal digits with N<50. If N is
417437
omitted, use a value of 10.
438
+
439
+<a name="redirect"></a>TH1 redirect Command
440
+-------------------------------------------
441
+
442
+ * redirect URL
443
+
444
+Issues an HTTP redirect (302) to the specified URL and then exits the
445
+process.
418446
419447
<a name="regexp"></a>TH1 regexp Command
420448
---------------------------------------
421449
422450
* regexp ?-nocase? ?--? exp string
@@ -589,10 +617,21 @@
589617
590618
* utime
591619
592620
Returns the number of microseconds of CPU time consumed by the current
593621
process in user space.
622
+
623
+<a name="verifyCsrf"></a>TH1 verifyCsrf Command
624
+-----------------------------------------------
625
+
626
+ * verifyCsrf
627
+
628
+Before using the results of a form, first call this command to verify
629
+that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
630
+is missing or is incorrect, that indicates a cross-site scripting attack.
631
+If the event of an attack is detected, an error message is generated and
632
+all further processing is aborted.
594633
595634
<a name="wiki"></a>TH1 wiki Command
596635
-----------------------------------
597636
598637
* wiki STRING
599638
--- www/th1.md
+++ www/th1.md
@@ -83,10 +83,12 @@
83 The original Tcl language after when TH1 is modeled has a very rich
84 repertoire of commands. TH1, as it is designed to be minimalist and
85 embedded has a greatly reduced command set. The following bullets
86 summarize the commands available in TH1:
87
 
 
88 * break
89 * catch SCRIPT ?VARIABLE?
90 * continue
91 * error ?STRING?
92 * expr EXPR
@@ -116,10 +118,17 @@
116
117 All of the above commands work as in the original Tcl. Refer to the
118 <a href="https://www.tcl-lang.org/man/tcl/contents.htm">Tcl documentation</a>
119 for details.
120
 
 
 
 
 
 
 
121 TH1 Extended Commands
122 ---------------------
123
124 There are many new commands added to TH1 and used to access the special
125 features of Fossil. The following is a summary of the extended commands:
@@ -130,26 +139,28 @@
130 * checkout
131 * combobox
132 * date
133 * decorate
134 * dir
135 * enable_output
136 * encode64
137 * getParameter
138 * glob_match
139 * globalState
140 * hascap
141 * hasfeature
142 * html
143 * htmlize
144 * http
145 * httpize
 
146 * linecount
147 * markdown
148 * puts
149 * query
150 * randhex
 
151 * regexp
152 * reinitialize
153 * render
154 * repository
155 * searchable
@@ -164,10 +175,11 @@
164 * tclMakeSafe
165 * tclReady
166 * trace
167 * stime
168 * utime
 
169 * wiki
170
171 Each of the commands above is documented by a block comment above their
172 implementation in the th\_main.c or th\_tcl.c source files.
173
@@ -248,14 +260,14 @@
248 If DETAILS is non-zero, the result will be a list-of-lists, with each
249 element containing at least three elements: the file name, the file
250 size (in bytes), and the file last modification time (relative to the
251 time zone configured for the repository).
252
253 <a name="enable_output"></a>TH1 enable_output Command
------------------------------------------------------
 
 
254
255 * enable_output BOOLEAN
256
257 Enable or disable sending output when the combobox, puts, or wiki
258 commands are used.
259
260 <a name="encode64"></a>TH1 encode64 Command
@@ -271,14 +283,14 @@
271 * getParameter NAME ?DEFAULT?
272
273 Returns the value of the specified query parameter or the specified
274 default value when there is no matching query parameter.
275
276 <a name="glob_match"></a>TH1 glob_match Command
------------------------------------------------
 
 
277
278 * glob_match ?-one? ?--? patternList string
279
280 Checks the string against the specified glob pattern -OR- list of glob
281 patterns and returns non-zero if there is a match.
282
283 <a name="globalState"></a>TH1 globalState Command
@@ -369,10 +381,18 @@
369
370 * httpize STRING
371
372 Escape all characters of STRING which have special meaning in URI
373 components. Returns the escaped string.
 
 
 
 
 
 
 
 
374
375 <a name="linecount"></a>TH1 linecount Command
376 ---------------------------------------------
377
378 * linecount STRING MAX MIN
@@ -413,10 +433,18 @@
413
414 * randhex N
415
416 Returns a string of N*2 random hexadecimal digits with N<50. If N is
417 omitted, use a value of 10.
 
 
 
 
 
 
 
 
418
419 <a name="regexp"></a>TH1 regexp Command
420 ---------------------------------------
421
422 * regexp ?-nocase? ?--? exp string
@@ -589,10 +617,21 @@
589
590 * utime
591
592 Returns the number of microseconds of CPU time consumed by the current
593 process in user space.
 
 
 
 
 
 
 
 
 
 
 
594
595 <a name="wiki"></a>TH1 wiki Command
596 -----------------------------------
597
598 * wiki STRING
599
--- www/th1.md
+++ www/th1.md
@@ -83,10 +83,12 @@
83 The original Tcl language after when TH1 is modeled has a very rich
84 repertoire of commands. TH1, as it is designed to be minimalist and
85 embedded has a greatly reduced command set. The following bullets
86 summarize the commands available in TH1:
87
88 * array exists VARNAME
89 * array names VARNAME
90 * break
91 * catch SCRIPT ?VARIABLE?
92 * continue
93 * error ?STRING?
94 * expr EXPR
@@ -116,10 +118,17 @@
118
119 All of the above commands work as in the original Tcl. Refer to the
120 <a href="https://www.tcl-lang.org/man/tcl/contents.htm">Tcl documentation</a>
121 for details.
122
123 Summary of Core TH1 Variables
124 -----------------------------
125
126 * tcl\_platform(engine) -- _This will always have the value "TH1"._
127 * tcl\_platform(platform) -- _This will have the value "windows" or "unix"._
128 * th\_stack\_trace -- _This will contain error stack information._
129
130 TH1 Extended Commands
131 ---------------------
132
133 There are many new commands added to TH1 and used to access the special
134 features of Fossil. The following is a summary of the extended commands:
@@ -130,26 +139,28 @@
139 * checkout
140 * combobox
141 * date
142 * decorate
143 * dir
144 * enable\_output
145 * encode64
146 * getParameter
147 * glob\_match
148 * globalState
149 * hascap
150 * hasfeature
151 * html
152 * htmlize
153 * http
154 * httpize
155 * insertCsrf
156 * linecount
157 * markdown
158 * puts
159 * query
160 * randhex
161 * redirect
162 * regexp
163 * reinitialize
164 * render
165 * repository
166 * searchable
@@ -164,10 +175,11 @@
175 * tclMakeSafe
176 * tclReady
177 * trace
178 * stime
179 * utime
180 * verifyCsrf
181 * wiki
182
183 Each of the commands above is documented by a block comment above their
184 implementation in the th\_main.c or th\_tcl.c source files.
185
@@ -248,14 +260,14 @@
260 If DETAILS is non-zero, the result will be a list-of-lists, with each
261 element containing at least three elements: the file name, the file
262 size (in bytes), and the file last modification time (relative to the
263 time zone configured for the repository).
264
 
------------------------------------------------------
265 <a name="enable_output"></a>TH1 enable\_output Command
266 ------------------------------------------------------
267
268 * enable\_output BOOLEAN
269
270 Enable or disable sending output when the combobox, puts, or wiki
271 commands are used.
272
273 <a name="encode64"></a>TH1 encode64 Command
@@ -271,14 +283,14 @@
283 * getParameter NAME ?DEFAULT?
284
285 Returns the value of the specified query parameter or the specified
286 default value when there is no matching query parameter.
287
 
------------------------------------------------
288 <a name="glob_match"></a>TH1 glob\_match Command
289 ------------------------------------------------
290
291 * glob\_match ?-one? ?--? patternList string
292
293 Checks the string against the specified glob pattern -OR- list of glob
294 patterns and returns non-zero if there is a match.
295
296 <a name="globalState"></a>TH1 globalState Command
@@ -369,10 +381,18 @@
381
382 * httpize STRING
383
384 Escape all characters of STRING which have special meaning in URI
385 components. Returns the escaped string.
386
387 <a name="insertCsrf"></a>TH1 insertCsrf Command
388 -----------------------------------------------
389
390 * insertCsrf
391
392 While rendering a form, call this command to add the Anti-CSRF token
393 as a hidden element of the form.
394
395 <a name="linecount"></a>TH1 linecount Command
396 ---------------------------------------------
397
398 * linecount STRING MAX MIN
@@ -413,10 +433,18 @@
433
434 * randhex N
435
436 Returns a string of N*2 random hexadecimal digits with N<50. If N is
437 omitted, use a value of 10.
438
439 <a name="redirect"></a>TH1 redirect Command
440 -------------------------------------------
441
442 * redirect URL
443
444 Issues an HTTP redirect (302) to the specified URL and then exits the
445 process.
446
447 <a name="regexp"></a>TH1 regexp Command
448 ---------------------------------------
449
450 * regexp ?-nocase? ?--? exp string
@@ -589,10 +617,21 @@
617
618 * utime
619
620 Returns the number of microseconds of CPU time consumed by the current
621 process in user space.
622
623 <a name="verifyCsrf"></a>TH1 verifyCsrf Command
624 -----------------------------------------------
625
626 * verifyCsrf
627
628 Before using the results of a form, first call this command to verify
629 that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
630 is missing or is incorrect, that indicates a cross-site scripting attack.
631 If the event of an attack is detected, an error message is generated and
632 all further processing is aborted.
633
634 <a name="wiki"></a>TH1 wiki Command
635 -----------------------------------
636
637 * wiki STRING
638

Keyboard Shortcuts

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