Fossil SCM

merge trunk

jan.nijtmans 2014-04-24 08:12 cleanX merge
Commit 9d969db8a4a60c3bde48b009365e54f022082b00
--- Makefile.Cygwin.in
+++ Makefile.Cygwin.in
@@ -36,16 +36,13 @@
3636
# care about testing the end result, this can be blank.
3737
#
3838
TCLSH = tclsh
3939
4040
LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
41
-TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -DFOSSIL_OMIT_LOAD_AVERAGE
41
+TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
4242
INSTALLDIR =$(DESTDIR)@prefix@/bin
4343
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
44
-FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
45
-FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@
46
-FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@
4744
SQLITE_CFLAGS += -DSQLITE_WIN32_NO_ANSI
4845
SQLITE_CFLAGS += -DSQLITE_WIN32_MAX_PATH_BYTES=4096
4946
SQLITE_CFLAGS += -DSQLITE_MAX_MMAP_SIZE=0x7fff0000
5047
5148
include $(SRCDIR)/main.mk
5249
--- Makefile.Cygwin.in
+++ Makefile.Cygwin.in
@@ -36,16 +36,13 @@
36 # care about testing the end result, this can be blank.
37 #
38 TCLSH = tclsh
39
40 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
41 TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -DFOSSIL_OMIT_LOAD_AVERAGE
42 INSTALLDIR =$(DESTDIR)@prefix@/bin
43 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
44 FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
45 FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@
46 FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@
47 SQLITE_CFLAGS += -DSQLITE_WIN32_NO_ANSI
48 SQLITE_CFLAGS += -DSQLITE_WIN32_MAX_PATH_BYTES=4096
49 SQLITE_CFLAGS += -DSQLITE_MAX_MMAP_SIZE=0x7fff0000
50
51 include $(SRCDIR)/main.mk
52
--- Makefile.Cygwin.in
+++ Makefile.Cygwin.in
@@ -36,16 +36,13 @@
36 # care about testing the end result, this can be blank.
37 #
38 TCLSH = tclsh
39
40 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
41 TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
42 INSTALLDIR =$(DESTDIR)@prefix@/bin
43 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
 
 
 
44 SQLITE_CFLAGS += -DSQLITE_WIN32_NO_ANSI
45 SQLITE_CFLAGS += -DSQLITE_WIN32_MAX_PATH_BYTES=4096
46 SQLITE_CFLAGS += -DSQLITE_MAX_MMAP_SIZE=0x7fff0000
47
48 include $(SRCDIR)/main.mk
49
--- Makefile.in
+++ Makefile.in
@@ -40,13 +40,10 @@
4040
4141
LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
4242
TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
4343
INSTALLDIR = $(DESTDIR)@prefix@/bin
4444
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
45
-FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
46
-FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@
47
-FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@
4845
4946
include $(SRCDIR)/main.mk
5047
5148
distclean: clean
5249
rm -f autoconfig.h config.log Makefile
5350
--- Makefile.in
+++ Makefile.in
@@ -40,13 +40,10 @@
40
41 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
42 TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
43 INSTALLDIR = $(DESTDIR)@prefix@/bin
44 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
45 FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
46 FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@
47 FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@
48
49 include $(SRCDIR)/main.mk
50
51 distclean: clean
52 rm -f autoconfig.h config.log Makefile
53
--- Makefile.in
+++ Makefile.in
@@ -40,13 +40,10 @@
40
41 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
42 TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
43 INSTALLDIR = $(DESTDIR)@prefix@/bin
44 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
 
 
 
45
46 include $(SRCDIR)/main.mk
47
48 distclean: clean
49 rm -f autoconfig.h config.log Makefile
50
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-1.28
1
+1.29
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.28
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.29
2
+5
--- auto.def
+++ auto.def
@@ -248,10 +248,15 @@
248248
if {[string match *mingw* [get-define host]]} {
249249
define-append LIBS -lwsock32
250250
}
251251
}
252252
cc-check-function-in-lib iconv iconv
253
+
254
+# Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
255
+if {![cc-check-functions getloadavg]} {
256
+ define FOSSIL_OMIT_LOAD_AVERAGE 1
257
+}
253258
254259
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
255260
if {![cc-check-functions getpassphrase]} {
256261
# Haiku needs this
257262
cc-check-function-in-lib getpass bsd
258263
--- auto.def
+++ auto.def
@@ -248,10 +248,15 @@
248 if {[string match *mingw* [get-define host]]} {
249 define-append LIBS -lwsock32
250 }
251 }
252 cc-check-function-in-lib iconv iconv
 
 
 
 
 
253
254 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
255 if {![cc-check-functions getpassphrase]} {
256 # Haiku needs this
257 cc-check-function-in-lib getpass bsd
258
--- auto.def
+++ auto.def
@@ -248,10 +248,15 @@
248 if {[string match *mingw* [get-define host]]} {
249 define-append LIBS -lwsock32
250 }
251 }
252 cc-check-function-in-lib iconv iconv
253
254 # Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
255 if {![cc-check-functions getloadavg]} {
256 define FOSSIL_OMIT_LOAD_AVERAGE 1
257 }
258
259 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
260 if {![cc-check-functions getpassphrase]} {
261 # Haiku needs this
262 cc-check-function-in-lib getpass bsd
263
+2 -2
--- src/add.c
+++ src/add.c
@@ -25,11 +25,11 @@
2525
#include "cygsup.h"
2626
2727
/*
2828
** This routine returns the names of files in a working checkout that
2929
** are created by Fossil itself, and hence should not be added, deleted,
30
-** or merge, and should be omitted from "clean" and "extra" lists.
30
+** or merge, and should be omitted from "clean" and "extras" lists.
3131
**
3232
** Return the N-th name. The first name has N==0. When all names have
3333
** been used, return 0.
3434
*/
3535
const char *fossil_reserved_name(int N, int omitRepo){
@@ -461,11 +461,11 @@
461461
**
462462
** Do all necessary "add" and "rm" commands to synchronize the repository
463463
** with the content of the working checkout:
464464
**
465465
** * All files in the checkout but not in the repository (that is,
466
-** all files displayed using the "extra" command) are added as
466
+** all files displayed using the "extras" command) are added as
467467
** if by the "add" command.
468468
**
469469
** * All files in the repository but missing from the checkout (that is,
470470
** all files that show as MISSING with the "status" command) are
471471
** removed as if by the "rm" command.
472472
--- src/add.c
+++ src/add.c
@@ -25,11 +25,11 @@
25 #include "cygsup.h"
26
27 /*
28 ** This routine returns the names of files in a working checkout that
29 ** are created by Fossil itself, and hence should not be added, deleted,
30 ** or merge, and should be omitted from "clean" and "extra" lists.
31 **
32 ** Return the N-th name. The first name has N==0. When all names have
33 ** been used, return 0.
34 */
35 const char *fossil_reserved_name(int N, int omitRepo){
@@ -461,11 +461,11 @@
461 **
462 ** Do all necessary "add" and "rm" commands to synchronize the repository
463 ** with the content of the working checkout:
464 **
465 ** * All files in the checkout but not in the repository (that is,
466 ** all files displayed using the "extra" command) are added as
467 ** if by the "add" command.
468 **
469 ** * All files in the repository but missing from the checkout (that is,
470 ** all files that show as MISSING with the "status" command) are
471 ** removed as if by the "rm" command.
472
--- src/add.c
+++ src/add.c
@@ -25,11 +25,11 @@
25 #include "cygsup.h"
26
27 /*
28 ** This routine returns the names of files in a working checkout that
29 ** are created by Fossil itself, and hence should not be added, deleted,
30 ** or merge, and should be omitted from "clean" and "extras" lists.
31 **
32 ** Return the N-th name. The first name has N==0. When all names have
33 ** been used, return 0.
34 */
35 const char *fossil_reserved_name(int N, int omitRepo){
@@ -461,11 +461,11 @@
461 **
462 ** Do all necessary "add" and "rm" commands to synchronize the repository
463 ** with the content of the working checkout:
464 **
465 ** * All files in the checkout but not in the repository (that is,
466 ** all files displayed using the "extras" command) are added as
467 ** if by the "add" command.
468 **
469 ** * All files in the repository but missing from the checkout (that is,
470 ** all files that show as MISSING with the "status" command) are
471 ** removed as if by the "rm" command.
472
+16 -7
--- src/allrepo.c
+++ src/allrepo.c
@@ -76,11 +76,11 @@
7676
7777
7878
/*
7979
** COMMAND: all
8080
**
81
-** Usage: %fossil all (changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync)
81
+** Usage: %fossil all (changes|clean|extras|ignore|list|ls|pull|push|rebuild|sync)
8282
**
8383
** The ~/.fossil file records the location of all repositories for a
8484
** user. This command performs certain operations on all repositories
8585
** that can be useful before or after a period of disconnected operation.
8686
**
@@ -99,16 +99,16 @@
9999
** and the --whatif option to carefully review the files to
100100
** be deleted beforehand is highly recommended. The command
101101
** line options supported by the clean command itself, if any
102102
** are present, are passed along verbatim.
103103
**
104
-** extra Shows extra files from all local checkouts. The command
104
+** extras Shows "extra" files from all local checkouts. The command
105105
** line options supported by the extra command itself, if any
106106
** are present, are passed along verbatim.
107107
**
108108
** ignore Arguments are repositories that should be ignored by
109
-** subsequent clean, extra, list, pull, push, rebuild, and
109
+** subsequent clean, extras, list, pull, push, rebuild, and
110110
** sync operations. The -c|--ckout option causes the listed
111111
** local checkouts to be ignored instead.
112112
**
113113
** list | ls Display the location of all repositories. The -c|--ckout
114114
** option causes all local checkouts to be listed instead.
@@ -136,10 +136,11 @@
136136
** when one of the following commands are run against the repository:
137137
** clone, info, pull, push, or sync. Even previously ignored repositories
138138
** are added back to the list of repositories by these commands.
139139
**
140140
** Options:
141
+** --showfile Show the repository or checkout being operated upon.
141142
** --dontstop Continue with other repositories even after an error.
142143
** --dry-run If given, display instead of run actions.
143144
*/
144145
void all_cmd(void){
145146
int n;
@@ -150,10 +151,11 @@
150151
char *zQFilename;
151152
Blob extra;
152153
int useCheckouts = 0;
153154
int quiet = 0;
154155
int dryRunFlag = 0;
156
+ int showFile = find_option("showfile",0,0)!=0;
155157
int stopOnError = find_option("dontstop",0,0)==0;
156158
int rc;
157159
int nToDel = 0;
158160
159161
dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -160,11 +162,11 @@
160162
if( !dryRunFlag ){
161163
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
162164
}
163165
164166
if( g.argc<3 ){
165
- usage("changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync");
167
+ usage("changes|clean|extras|ignore|list|ls|pull|push|rebuild|sync");
166168
}
167169
n = strlen(g.argv[2]);
168170
db_open_config(1);
169171
blob_zero(&extra);
170172
zCmd = g.argv[2];
@@ -185,12 +187,16 @@
185187
collect_argument_value(&extra, "keep");
186188
collect_argument(&extra, "temp",0);
187189
collect_argument(&extra, "verbose","v");
188190
collect_argument(&extra, "whatif",0);
189191
useCheckouts = 1;
190
- }else if( strncmp(zCmd, "extra", n)==0 ){
191
- zCmd = "extra --chdir";
192
+ }else if( strncmp(zCmd, "extras", n)==0 ){
193
+ if( showFile ){
194
+ zCmd = "extras --chdir";
195
+ }else{
196
+ zCmd = "extras --header --chdir";
197
+ }
192198
collect_argument(&extra, "abs-paths",0);
193199
collect_argument_value(&extra, "case-sensitive");
194200
collect_argument(&extra, "dotfiles",0);
195201
collect_argument_value(&extra, "ignore");
196202
collect_argument(&extra, "rel-paths",0);
@@ -254,11 +260,11 @@
254260
}
255261
db_end_transaction(0);
256262
return;
257263
}else{
258264
fossil_fatal("\"all\" subcommand should be one of: "
259
- "changes clean extra ignore list ls push pull rebuild sync");
265
+ "changes clean extras ignore list ls push pull rebuild sync");
260266
}
261267
verify_all_options();
262268
zFossil = quoteFilename(g.nameOfExe);
263269
if( useCheckouts ){
264270
db_prepare(&q,
@@ -287,10 +293,13 @@
287293
continue;
288294
}
289295
if( zCmd[0]=='l' ){
290296
fossil_print("%s\n", zFilename);
291297
continue;
298
+ }else if( showFile ){
299
+ fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository",
300
+ zFilename);
292301
}
293302
zQFilename = quoteFilename(zFilename);
294303
zSyscmd = mprintf("%s %s %s%s",
295304
zFossil, zCmd, zQFilename, blob_str(&extra));
296305
if( !quiet || dryRunFlag ){
297306
--- src/allrepo.c
+++ src/allrepo.c
@@ -76,11 +76,11 @@
76
77
78 /*
79 ** COMMAND: all
80 **
81 ** Usage: %fossil all (changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync)
82 **
83 ** The ~/.fossil file records the location of all repositories for a
84 ** user. This command performs certain operations on all repositories
85 ** that can be useful before or after a period of disconnected operation.
86 **
@@ -99,16 +99,16 @@
99 ** and the --whatif option to carefully review the files to
100 ** be deleted beforehand is highly recommended. The command
101 ** line options supported by the clean command itself, if any
102 ** are present, are passed along verbatim.
103 **
104 ** extra Shows extra files from all local checkouts. The command
105 ** line options supported by the extra command itself, if any
106 ** are present, are passed along verbatim.
107 **
108 ** ignore Arguments are repositories that should be ignored by
109 ** subsequent clean, extra, list, pull, push, rebuild, and
110 ** sync operations. The -c|--ckout option causes the listed
111 ** local checkouts to be ignored instead.
112 **
113 ** list | ls Display the location of all repositories. The -c|--ckout
114 ** option causes all local checkouts to be listed instead.
@@ -136,10 +136,11 @@
136 ** when one of the following commands are run against the repository:
137 ** clone, info, pull, push, or sync. Even previously ignored repositories
138 ** are added back to the list of repositories by these commands.
139 **
140 ** Options:
 
141 ** --dontstop Continue with other repositories even after an error.
142 ** --dry-run If given, display instead of run actions.
143 */
144 void all_cmd(void){
145 int n;
@@ -150,10 +151,11 @@
150 char *zQFilename;
151 Blob extra;
152 int useCheckouts = 0;
153 int quiet = 0;
154 int dryRunFlag = 0;
 
155 int stopOnError = find_option("dontstop",0,0)==0;
156 int rc;
157 int nToDel = 0;
158
159 dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -160,11 +162,11 @@
160 if( !dryRunFlag ){
161 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
162 }
163
164 if( g.argc<3 ){
165 usage("changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync");
166 }
167 n = strlen(g.argv[2]);
168 db_open_config(1);
169 blob_zero(&extra);
170 zCmd = g.argv[2];
@@ -185,12 +187,16 @@
185 collect_argument_value(&extra, "keep");
186 collect_argument(&extra, "temp",0);
187 collect_argument(&extra, "verbose","v");
188 collect_argument(&extra, "whatif",0);
189 useCheckouts = 1;
190 }else if( strncmp(zCmd, "extra", n)==0 ){
191 zCmd = "extra --chdir";
 
 
 
 
192 collect_argument(&extra, "abs-paths",0);
193 collect_argument_value(&extra, "case-sensitive");
194 collect_argument(&extra, "dotfiles",0);
195 collect_argument_value(&extra, "ignore");
196 collect_argument(&extra, "rel-paths",0);
@@ -254,11 +260,11 @@
254 }
255 db_end_transaction(0);
256 return;
257 }else{
258 fossil_fatal("\"all\" subcommand should be one of: "
259 "changes clean extra ignore list ls push pull rebuild sync");
260 }
261 verify_all_options();
262 zFossil = quoteFilename(g.nameOfExe);
263 if( useCheckouts ){
264 db_prepare(&q,
@@ -287,10 +293,13 @@
287 continue;
288 }
289 if( zCmd[0]=='l' ){
290 fossil_print("%s\n", zFilename);
291 continue;
 
 
 
292 }
293 zQFilename = quoteFilename(zFilename);
294 zSyscmd = mprintf("%s %s %s%s",
295 zFossil, zCmd, zQFilename, blob_str(&extra));
296 if( !quiet || dryRunFlag ){
297
--- src/allrepo.c
+++ src/allrepo.c
@@ -76,11 +76,11 @@
76
77
78 /*
79 ** COMMAND: all
80 **
81 ** Usage: %fossil all (changes|clean|extras|ignore|list|ls|pull|push|rebuild|sync)
82 **
83 ** The ~/.fossil file records the location of all repositories for a
84 ** user. This command performs certain operations on all repositories
85 ** that can be useful before or after a period of disconnected operation.
86 **
@@ -99,16 +99,16 @@
99 ** and the --whatif option to carefully review the files to
100 ** be deleted beforehand is highly recommended. The command
101 ** line options supported by the clean command itself, if any
102 ** are present, are passed along verbatim.
103 **
104 ** extras Shows "extra" files from all local checkouts. The command
105 ** line options supported by the extra command itself, if any
106 ** are present, are passed along verbatim.
107 **
108 ** ignore Arguments are repositories that should be ignored by
109 ** subsequent clean, extras, list, pull, push, rebuild, and
110 ** sync operations. The -c|--ckout option causes the listed
111 ** local checkouts to be ignored instead.
112 **
113 ** list | ls Display the location of all repositories. The -c|--ckout
114 ** option causes all local checkouts to be listed instead.
@@ -136,10 +136,11 @@
136 ** when one of the following commands are run against the repository:
137 ** clone, info, pull, push, or sync. Even previously ignored repositories
138 ** are added back to the list of repositories by these commands.
139 **
140 ** Options:
141 ** --showfile Show the repository or checkout being operated upon.
142 ** --dontstop Continue with other repositories even after an error.
143 ** --dry-run If given, display instead of run actions.
144 */
145 void all_cmd(void){
146 int n;
@@ -150,10 +151,11 @@
151 char *zQFilename;
152 Blob extra;
153 int useCheckouts = 0;
154 int quiet = 0;
155 int dryRunFlag = 0;
156 int showFile = find_option("showfile",0,0)!=0;
157 int stopOnError = find_option("dontstop",0,0)==0;
158 int rc;
159 int nToDel = 0;
160
161 dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -160,11 +162,11 @@
162 if( !dryRunFlag ){
163 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
164 }
165
166 if( g.argc<3 ){
167 usage("changes|clean|extras|ignore|list|ls|pull|push|rebuild|sync");
168 }
169 n = strlen(g.argv[2]);
170 db_open_config(1);
171 blob_zero(&extra);
172 zCmd = g.argv[2];
@@ -185,12 +187,16 @@
187 collect_argument_value(&extra, "keep");
188 collect_argument(&extra, "temp",0);
189 collect_argument(&extra, "verbose","v");
190 collect_argument(&extra, "whatif",0);
191 useCheckouts = 1;
192 }else if( strncmp(zCmd, "extras", n)==0 ){
193 if( showFile ){
194 zCmd = "extras --chdir";
195 }else{
196 zCmd = "extras --header --chdir";
197 }
198 collect_argument(&extra, "abs-paths",0);
199 collect_argument_value(&extra, "case-sensitive");
200 collect_argument(&extra, "dotfiles",0);
201 collect_argument_value(&extra, "ignore");
202 collect_argument(&extra, "rel-paths",0);
@@ -254,11 +260,11 @@
260 }
261 db_end_transaction(0);
262 return;
263 }else{
264 fossil_fatal("\"all\" subcommand should be one of: "
265 "changes clean extras ignore list ls push pull rebuild sync");
266 }
267 verify_all_options();
268 zFossil = quoteFilename(g.nameOfExe);
269 if( useCheckouts ){
270 db_prepare(&q,
@@ -287,10 +293,13 @@
293 continue;
294 }
295 if( zCmd[0]=='l' ){
296 fossil_print("%s\n", zFilename);
297 continue;
298 }else if( showFile ){
299 fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository",
300 zFilename);
301 }
302 zQFilename = quoteFilename(zFilename);
303 zSyscmd = mprintf("%s %s %s%s",
304 zFossil, zCmd, zQFilename, blob_str(&extra));
305 if( !quiet || dryRunFlag ){
306
+4 -4
--- src/attach.c
+++ src/attach.c
@@ -258,11 +258,11 @@
258258
zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag"
259259
" WHERE tagname GLOB 'tkt-%q*'", zTkt);
260260
if( zTkt==0 ) fossil_redirect_home();
261261
}
262262
zTarget = zTkt;
263
- zTargetType = mprintf("Ticket <a href=\"%s/tktview/%S\">%S</a>",
263
+ zTargetType = mprintf("Ticket <a href=\"%s/tktview/%s\">%S</a>",
264264
g.zTop, zTkt, zTkt);
265265
}
266266
if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
267267
if( P("cancel") ){
268268
cgi_redirect(zFrom);
@@ -463,11 +463,11 @@
463463
if( strcmp(zModAction,"approve")==0 ){
464464
moderation_approve(rid);
465465
}
466466
}
467467
style_header("Attachment Details");
468
- style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
468
+ style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid);
469469
470470
@ <div class="section">Overview</div>
471471
@ <p><table class="label-value">
472472
@ <tr><th>Artifact&nbsp;ID:</th>
473473
@ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
@@ -531,12 +531,12 @@
531531
@ <pre>
532532
@ %h(z)
533533
@ </pre>
534534
}
535535
}else if( strncmp(zMime, "image/", 6)==0 ){
536
- @ <img src="%R/raw/%S(zSrc)?m=%s(zMime)"></img>
537
- style_submenu_element("Image", "Image", "%R/raw/%S?m=%s", zSrc, zMime);
536
+ @ <img src="%R/raw/%s(zSrc)?m=%s(zMime)"></img>
537
+ style_submenu_element("Image", "Image", "%R/raw/%s?m=%s", zSrc, zMime);
538538
}else{
539539
int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
540540
@ <i>(file is %d(sz) bytes of binary data)</i>
541541
}
542542
@ </blockquote>
543543
--- src/attach.c
+++ src/attach.c
@@ -258,11 +258,11 @@
258 zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag"
259 " WHERE tagname GLOB 'tkt-%q*'", zTkt);
260 if( zTkt==0 ) fossil_redirect_home();
261 }
262 zTarget = zTkt;
263 zTargetType = mprintf("Ticket <a href=\"%s/tktview/%S\">%S</a>",
264 g.zTop, zTkt, zTkt);
265 }
266 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
267 if( P("cancel") ){
268 cgi_redirect(zFrom);
@@ -463,11 +463,11 @@
463 if( strcmp(zModAction,"approve")==0 ){
464 moderation_approve(rid);
465 }
466 }
467 style_header("Attachment Details");
468 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
469
470 @ <div class="section">Overview</div>
471 @ <p><table class="label-value">
472 @ <tr><th>Artifact&nbsp;ID:</th>
473 @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
@@ -531,12 +531,12 @@
531 @ <pre>
532 @ %h(z)
533 @ </pre>
534 }
535 }else if( strncmp(zMime, "image/", 6)==0 ){
536 @ <img src="%R/raw/%S(zSrc)?m=%s(zMime)"></img>
537 style_submenu_element("Image", "Image", "%R/raw/%S?m=%s", zSrc, zMime);
538 }else{
539 int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
540 @ <i>(file is %d(sz) bytes of binary data)</i>
541 }
542 @ </blockquote>
543
--- src/attach.c
+++ src/attach.c
@@ -258,11 +258,11 @@
258 zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag"
259 " WHERE tagname GLOB 'tkt-%q*'", zTkt);
260 if( zTkt==0 ) fossil_redirect_home();
261 }
262 zTarget = zTkt;
263 zTargetType = mprintf("Ticket <a href=\"%s/tktview/%s\">%S</a>",
264 g.zTop, zTkt, zTkt);
265 }
266 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
267 if( P("cancel") ){
268 cgi_redirect(zFrom);
@@ -463,11 +463,11 @@
463 if( strcmp(zModAction,"approve")==0 ){
464 moderation_approve(rid);
465 }
466 }
467 style_header("Attachment Details");
468 style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid);
469
470 @ <div class="section">Overview</div>
471 @ <p><table class="label-value">
472 @ <tr><th>Artifact&nbsp;ID:</th>
473 @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
@@ -531,12 +531,12 @@
531 @ <pre>
532 @ %h(z)
533 @ </pre>
534 }
535 }else if( strncmp(zMime, "image/", 6)==0 ){
536 @ <img src="%R/raw/%s(zSrc)?m=%s(zMime)"></img>
537 style_submenu_element("Image", "Image", "%R/raw/%s?m=%s", zSrc, zMime);
538 }else{
539 int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
540 @ <i>(file is %d(sz) bytes of binary data)</i>
541 }
542 @ </blockquote>
543
+8 -11
--- src/browse.c
+++ src/browse.c
@@ -85,11 +85,11 @@
8585
8686
for(i=0; zPath[i]; i=j){
8787
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
8888
if( zPath[j] && g.perm.Hyperlink ){
8989
if( zCI ){
90
- char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx);
90
+ char *zLink = href("%R/%s?name=%#T%s&ci=%s", zURI, j, zPath, zREx, zCI);
9191
blob_appendf(pOut, "%s%z%#h</a>",
9292
zSep, zLink, j-i, &zPath[i]);
9393
}else{
9494
char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
9595
blob_appendf(pOut, "%s%z%#h</a>",
@@ -179,18 +179,15 @@
179179
if( linkTip ){
180180
style_submenu_element("Tip", "Tip", "%s",
181181
url_render(&sURI, "ci", "tip", 0, 0));
182182
}
183183
if( zCI ){
184
- char zShort[20];
185
- memcpy(zShort, zUuid, 10);
186
- zShort[10] = 0;
187
- @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>]
184
+ @ <h2>Files of check-in [%z(href("vinfo?name=%s",zUuid))%.10s(zUuid)</a>]
188185
@ %s(blob_str(&dirname))</h2>
189
- zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
186
+ zSubdirLink = mprintf("%R/dir?ci=%s&name=%T", zUuid, zPrefix);
190187
if( nD==0 ){
191
- style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
188
+ style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s",
192189
zUuid);
193190
}
194191
}else{
195192
@ <h2>The union of all files from all check-ins
196193
@ %s(blob_str(&dirname))</h2>
@@ -490,11 +487,11 @@
490487
}
491488
if( zCI ){
492489
style_submenu_element("All", "All", "%s",
493490
url_render(&sURI, "ci", 0, 0, 0));
494491
if( nD==0 && !showDirOnly ){
495
- style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
492
+ style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s",
496493
zUuid);
497494
}
498495
}
499496
if( linkTrunk ){
500497
style_submenu_element("Trunk", "Trunk", "%s",
@@ -574,11 +571,11 @@
574571
if( zCI ){
575572
@ <h2>%d(nFile) %s(zObjType) of check-in
576573
if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
577574
@ "%h(zCI)"
578575
}
579
- @ [%z(href("vinfo?name=%T",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2>
576
+ @ [%z(href("vinfo?name=%s",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2>
580577
}else{
581578
int n = db_int(0, "SELECT count(*) FROM plink");
582579
@ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins
583580
@ %s(blob_str(&dirname))</h2>
584581
}
@@ -617,11 +614,11 @@
617614
nDir++;
618615
}else if( !showDirOnly ){
619616
const char *zFileClass = fileext_class(p->zName);
620617
char *zLink;
621618
if( zCI ){
622
- zLink = href("%R/artifact/%S",p->zUuid);
619
+ zLink = href("%R/artifact/%s",p->zUuid);
623620
}else{
624621
zLink = href("%R/finfo?name=%T",p->zFullName);
625622
}
626623
@ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
627624
}
@@ -875,14 +872,14 @@
875872
zAge[0] = 0;
876873
}
877874
@ <tr>
878875
@ <td>%s(zAge)
879876
@ <td width="25">
880
- @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a>
877
+ @ <td>%z(href("%R/artifact/%s?ln", zFUuid))%h(db_column_text(&q, 3))</a>
881878
@ </tr>
882879
@
883880
}
884881
@ <tr><td colspan=3><hr></tr>
885882
@ </table>
886883
db_finalize(&q);
887884
style_footer();
888885
}
889886
--- src/browse.c
+++ src/browse.c
@@ -85,11 +85,11 @@
85
86 for(i=0; zPath[i]; i=j){
87 for(j=i; zPath[j] && zPath[j]!='/'; j++){}
88 if( zPath[j] && g.perm.Hyperlink ){
89 if( zCI ){
90 char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx);
91 blob_appendf(pOut, "%s%z%#h</a>",
92 zSep, zLink, j-i, &zPath[i]);
93 }else{
94 char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
95 blob_appendf(pOut, "%s%z%#h</a>",
@@ -179,18 +179,15 @@
179 if( linkTip ){
180 style_submenu_element("Tip", "Tip", "%s",
181 url_render(&sURI, "ci", "tip", 0, 0));
182 }
183 if( zCI ){
184 char zShort[20];
185 memcpy(zShort, zUuid, 10);
186 zShort[10] = 0;
187 @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>]
188 @ %s(blob_str(&dirname))</h2>
189 zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
190 if( nD==0 ){
191 style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
192 zUuid);
193 }
194 }else{
195 @ <h2>The union of all files from all check-ins
196 @ %s(blob_str(&dirname))</h2>
@@ -490,11 +487,11 @@
490 }
491 if( zCI ){
492 style_submenu_element("All", "All", "%s",
493 url_render(&sURI, "ci", 0, 0, 0));
494 if( nD==0 && !showDirOnly ){
495 style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
496 zUuid);
497 }
498 }
499 if( linkTrunk ){
500 style_submenu_element("Trunk", "Trunk", "%s",
@@ -574,11 +571,11 @@
574 if( zCI ){
575 @ <h2>%d(nFile) %s(zObjType) of check-in
576 if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
577 @ "%h(zCI)"
578 }
579 @ [%z(href("vinfo?name=%T",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2>
580 }else{
581 int n = db_int(0, "SELECT count(*) FROM plink");
582 @ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins
583 @ %s(blob_str(&dirname))</h2>
584 }
@@ -617,11 +614,11 @@
617 nDir++;
618 }else if( !showDirOnly ){
619 const char *zFileClass = fileext_class(p->zName);
620 char *zLink;
621 if( zCI ){
622 zLink = href("%R/artifact/%S",p->zUuid);
623 }else{
624 zLink = href("%R/finfo?name=%T",p->zFullName);
625 }
626 @ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
627 }
@@ -875,14 +872,14 @@
875 zAge[0] = 0;
876 }
877 @ <tr>
878 @ <td>%s(zAge)
879 @ <td width="25">
880 @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a>
881 @ </tr>
882 @
883 }
884 @ <tr><td colspan=3><hr></tr>
885 @ </table>
886 db_finalize(&q);
887 style_footer();
888 }
889
--- src/browse.c
+++ src/browse.c
@@ -85,11 +85,11 @@
85
86 for(i=0; zPath[i]; i=j){
87 for(j=i; zPath[j] && zPath[j]!='/'; j++){}
88 if( zPath[j] && g.perm.Hyperlink ){
89 if( zCI ){
90 char *zLink = href("%R/%s?name=%#T%s&ci=%s", zURI, j, zPath, zREx, zCI);
91 blob_appendf(pOut, "%s%z%#h</a>",
92 zSep, zLink, j-i, &zPath[i]);
93 }else{
94 char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
95 blob_appendf(pOut, "%s%z%#h</a>",
@@ -179,18 +179,15 @@
179 if( linkTip ){
180 style_submenu_element("Tip", "Tip", "%s",
181 url_render(&sURI, "ci", "tip", 0, 0));
182 }
183 if( zCI ){
184 @ <h2>Files of check-in [%z(href("vinfo?name=%s",zUuid))%.10s(zUuid)</a>]
 
 
 
185 @ %s(blob_str(&dirname))</h2>
186 zSubdirLink = mprintf("%R/dir?ci=%s&name=%T", zUuid, zPrefix);
187 if( nD==0 ){
188 style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s",
189 zUuid);
190 }
191 }else{
192 @ <h2>The union of all files from all check-ins
193 @ %s(blob_str(&dirname))</h2>
@@ -490,11 +487,11 @@
487 }
488 if( zCI ){
489 style_submenu_element("All", "All", "%s",
490 url_render(&sURI, "ci", 0, 0, 0));
491 if( nD==0 && !showDirOnly ){
492 style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s",
493 zUuid);
494 }
495 }
496 if( linkTrunk ){
497 style_submenu_element("Trunk", "Trunk", "%s",
@@ -574,11 +571,11 @@
571 if( zCI ){
572 @ <h2>%d(nFile) %s(zObjType) of check-in
573 if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
574 @ "%h(zCI)"
575 }
576 @ [%z(href("vinfo?name=%s",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2>
577 }else{
578 int n = db_int(0, "SELECT count(*) FROM plink");
579 @ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins
580 @ %s(blob_str(&dirname))</h2>
581 }
@@ -617,11 +614,11 @@
614 nDir++;
615 }else if( !showDirOnly ){
616 const char *zFileClass = fileext_class(p->zName);
617 char *zLink;
618 if( zCI ){
619 zLink = href("%R/artifact/%s",p->zUuid);
620 }else{
621 zLink = href("%R/finfo?name=%T",p->zFullName);
622 }
623 @ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
624 }
@@ -875,14 +872,14 @@
872 zAge[0] = 0;
873 }
874 @ <tr>
875 @ <td>%s(zAge)
876 @ <td width="25">
877 @ <td>%z(href("%R/artifact/%s?ln", zFUuid))%h(db_column_text(&q, 3))</a>
878 @ </tr>
879 @
880 }
881 @ <tr><td colspan=3><hr></tr>
882 @ </table>
883 db_finalize(&q);
884 style_footer();
885 }
886
+50 -21
--- src/checkin.c
+++ src/checkin.c
@@ -179,11 +179,11 @@
179179
** --sha1sum Verify file status using SHA1 hashing rather
180180
** than relying on file mtimes.
181181
** --header Identify the repository if there are changes
182182
** -v|--verbose Say "(none)" if there are no changes
183183
**
184
-** See also: extra, ls, status
184
+** See also: extras, ls, status
185185
*/
186186
void changes_cmd(void){
187187
Blob report;
188188
int vid;
189189
int useSha1sum = find_option("sha1sum", 0, 0)!=0;
@@ -223,11 +223,11 @@
223223
** --rel-paths Display pathnames relative to the current working
224224
** directory.
225225
** --sha1sum Verify file status using SHA1 hashing rather
226226
** than relying on file mtimes.
227227
**
228
-** See also: changes, extra, ls
228
+** See also: changes, extras, ls
229229
*/
230230
void status_cmd(void){
231231
int vid;
232232
db_must_be_within_tree();
233233
/* 012345678901234 */
@@ -255,11 +255,11 @@
255255
**
256256
** Options:
257257
** --age Show when each file was committed
258258
** -v|--verbose Provide extra information about each file.
259259
**
260
-** See also: changes, extra, status
260
+** See also: changes, extras, status
261261
*/
262262
void ls_cmd(void){
263263
int vid;
264264
Stmt q;
265265
int verboseFlag;
@@ -433,20 +433,22 @@
433433
**
434434
** Options:
435435
** --abs-paths Display absolute pathnames.
436436
** --case-sensitive <BOOL> override case-sensitive setting
437437
** --dotfiles include files beginning with a dot (".")
438
+** --header Identify the repository if there are extras
438439
** --ignore <CSG> ignore files matching patterns from the argument
439440
** --rel-paths Display pathnames relative to the current working
440441
** directory.
441442
**
442443
** See also: changes, clean, status
443444
*/
444
-void extra_cmd(void){
445
+void extras_cmd(void){
445446
Stmt q;
446447
const char *zIgnoreFlag = find_option("ignore",0,1);
447448
unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
449
+ int showHdr = find_option("header",0,0)!=0;
448450
int cwdRelative = 0;
449451
Glob *pIgnore;
450452
Blob rewrittenPathname;
451453
const char *zPathname, *zDisplayName;
452454
@@ -477,10 +479,15 @@
477479
zDisplayName = blob_str(&rewrittenPathname);
478480
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
479481
zDisplayName += 2; /* no unnecessary ./ prefix */
480482
}
481483
}
484
+ if( showHdr ){
485
+ showHdr = 0;
486
+ fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
487
+ g.zLocalRoot);
488
+ }
482489
fossil_print("%s\n", zDisplayName);
483490
}
484491
blob_reset(&rewrittenPathname);
485492
db_finalize(&q);
486493
}
@@ -547,11 +554,11 @@
547554
** checkout, except the ones matching --keep.
548555
** Files not matching any of --clean/--ignore/-keep,
549556
** will be prompted for.
550557
** Compatibile with "git clean -x".
551558
**
552
-** See also: addremove, extra, status
559
+** See also: addremove, extras, status
553560
*/
554561
void clean_cmd(void){
555562
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
556563
int emptyDirsFlag, dirsOnlyFlag;
557564
unsigned scanFlags = 0;
@@ -614,11 +621,11 @@
614621
nRoot = (int)strlen(g.zLocalRoot);
615622
if( !dirsOnlyFlag ){
616623
Stmt q;
617624
Blob repo;
618625
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags,
619
- extremeFlag ? 0 : pIgnore, pKeep);
626
+ extremeFlag ? 0 : pIgnore, 0);
620627
db_prepare(&q,
621628
"SELECT %Q || x FROM sfile"
622629
" WHERE x NOT IN (%s)"
623630
" ORDER BY 1",
624631
g.zLocalRoot, fossil_all_reserved_names(0)
@@ -627,10 +634,17 @@
627634
db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
628635
}
629636
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
630637
while( db_step(&q)==SQLITE_ROW ){
631638
const char *zName = db_column_text(&q, 0);
639
+ if( glob_match(pKeep, zName+nRoot) ){
640
+ if( verboseFlag ){
641
+ fossil_print("KEPT file \"%s\" not removed (due to --keep"
642
+ " or \"keep-glob\")\n", zName+nRoot);
643
+ }
644
+ continue;
645
+ }
632646
if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
633647
&& !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
634648
Blob ans;
635649
char cReply;
636650
int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -662,21 +676,28 @@
662676
Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
663677
Stmt q;
664678
Blob root;
665679
blob_init(&root, g.zLocalRoot, nRoot - 1);
666680
vfile_dir_scan(&root, blob_size(&root), scanFlags,
667
- extremeFlag ? 0 : pIgnore, pKeep,
668
- extremeFlag ? 0 : pEmptyDirs);
681
+ extremeFlag ? 0 : pIgnore,
682
+ extremeFlag ? 0 : pEmptyDirs, 0);
669683
blob_reset(&root);
670684
db_prepare(&q,
671685
"SELECT %Q || x FROM dscan_temp"
672686
" WHERE x NOT IN (%s) AND y = 0"
673687
" ORDER BY 1 DESC",
674688
g.zLocalRoot, fossil_all_reserved_names(0)
675689
);
676690
while( db_step(&q)==SQLITE_ROW ){
677691
const char *zName = db_column_text(&q, 0);
692
+ if( glob_match(pKeep, zName+nRoot) ){
693
+ if( verboseFlag ){
694
+ fossil_print("KEPT directory \"%s\" not removed (due to --keep"
695
+ " or \"keep-glob\")\n", zName+nRoot);
696
+ }
697
+ continue;
698
+ }
678699
if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
679700
&& !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
680701
Blob ans;
681702
char cReply;
682703
int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -842,11 +863,11 @@
842863
#else
843864
blob_init(&prompt, zInit, -1);
844865
#endif
845866
blob_append(&prompt,
846867
"\n"
847
- "# Enter commit message for this check-in. Lines beginning with # are ignored.\n"
868
+ "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
848869
"#\n", -1
849870
);
850871
blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
851872
if( p->zBranch && p->zBranch[0] ){
852873
blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
@@ -1345,21 +1366,25 @@
13451366
char *zOrig = file_newname(zFilename, "original", 1);
13461367
FILE *f;
13471368
blob_write_to_file(p, zOrig);
13481369
fossil_free(zOrig);
13491370
f = fossil_fopen(zFilename, "wb");
1350
- if( fUnicode ) {
1351
- int bomSize;
1352
- const unsigned char *bom = get_utf8_bom(&bomSize);
1353
- fwrite(bom, 1, bomSize, f);
1354
- blob_to_utf8_no_bom(p, 0);
1355
- }
1356
- if( fHasAnyCr ){
1357
- blob_to_lf_only(p);
1358
- }
1359
- fwrite(blob_buffer(p), 1, blob_size(p), f);
1360
- fclose(f);
1371
+ if( f==0 ){
1372
+ fossil_warning("cannot open %s for writing", zFilename);
1373
+ }else{
1374
+ if( fUnicode ) {
1375
+ int bomSize;
1376
+ const unsigned char *bom = get_utf8_bom(&bomSize);
1377
+ fwrite(bom, 1, bomSize, f);
1378
+ blob_to_utf8_no_bom(p, 0);
1379
+ }
1380
+ if( fHasAnyCr ){
1381
+ blob_to_lf_only(p);
1382
+ }
1383
+ fwrite(blob_buffer(p), 1, blob_size(p), f);
1384
+ fclose(f);
1385
+ }
13611386
return 1;
13621387
}else if( cReply!='y' && cReply!='Y' ){
13631388
fossil_fatal("Abandoning commit due to %s in %s",
13641389
zWarning, blob_str(&fname));
13651390
}
@@ -1421,10 +1446,14 @@
14211446
** unless the interactive user chooses to proceed. If there is no
14221447
** interactive user or these warnings should be skipped for some other
14231448
** reason, the --no-warnings option may be used. A check-in is not
14241449
** allowed against a closed leaf.
14251450
**
1451
+** If a commit message is blank, you will be prompted:
1452
+** ("continue (y/N)?") to confirm you really want to commit with a
1453
+** blank commit message. The default value is "N", do not commit.
1454
+**
14261455
** The --private option creates a private check-in that is never synced.
14271456
** Children of private check-ins are automatically private.
14281457
**
14291458
** The --tag option applies the symbolic tag name to the check-in.
14301459
**
@@ -1452,11 +1481,11 @@
14521481
** --private do not sync changes and their descendants
14531482
** --sha1sum verify file status using SHA1 hashing rather
14541483
** than relying on file mtimes
14551484
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
14561485
**
1457
-** See also: branch, changes, checkout, extra, sync
1486
+** See also: branch, changes, checkout, extras, sync
14581487
*/
14591488
void commit_cmd(void){
14601489
int hasChanges; /* True if unsaved changes exist */
14611490
int vid; /* blob-id of parent version */
14621491
int nrid; /* blob-id of a modified file */
14631492
--- src/checkin.c
+++ src/checkin.c
@@ -179,11 +179,11 @@
179 ** --sha1sum Verify file status using SHA1 hashing rather
180 ** than relying on file mtimes.
181 ** --header Identify the repository if there are changes
182 ** -v|--verbose Say "(none)" if there are no changes
183 **
184 ** See also: extra, ls, status
185 */
186 void changes_cmd(void){
187 Blob report;
188 int vid;
189 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
@@ -223,11 +223,11 @@
223 ** --rel-paths Display pathnames relative to the current working
224 ** directory.
225 ** --sha1sum Verify file status using SHA1 hashing rather
226 ** than relying on file mtimes.
227 **
228 ** See also: changes, extra, ls
229 */
230 void status_cmd(void){
231 int vid;
232 db_must_be_within_tree();
233 /* 012345678901234 */
@@ -255,11 +255,11 @@
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
259 **
260 ** See also: changes, extra, status
261 */
262 void ls_cmd(void){
263 int vid;
264 Stmt q;
265 int verboseFlag;
@@ -433,20 +433,22 @@
433 **
434 ** Options:
435 ** --abs-paths Display absolute pathnames.
436 ** --case-sensitive <BOOL> override case-sensitive setting
437 ** --dotfiles include files beginning with a dot (".")
 
438 ** --ignore <CSG> ignore files matching patterns from the argument
439 ** --rel-paths Display pathnames relative to the current working
440 ** directory.
441 **
442 ** See also: changes, clean, status
443 */
444 void extra_cmd(void){
445 Stmt q;
446 const char *zIgnoreFlag = find_option("ignore",0,1);
447 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
 
448 int cwdRelative = 0;
449 Glob *pIgnore;
450 Blob rewrittenPathname;
451 const char *zPathname, *zDisplayName;
452
@@ -477,10 +479,15 @@
477 zDisplayName = blob_str(&rewrittenPathname);
478 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
479 zDisplayName += 2; /* no unnecessary ./ prefix */
480 }
481 }
 
 
 
 
 
482 fossil_print("%s\n", zDisplayName);
483 }
484 blob_reset(&rewrittenPathname);
485 db_finalize(&q);
486 }
@@ -547,11 +554,11 @@
547 ** checkout, except the ones matching --keep.
548 ** Files not matching any of --clean/--ignore/-keep,
549 ** will be prompted for.
550 ** Compatibile with "git clean -x".
551 **
552 ** See also: addremove, extra, status
553 */
554 void clean_cmd(void){
555 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
556 int emptyDirsFlag, dirsOnlyFlag;
557 unsigned scanFlags = 0;
@@ -614,11 +621,11 @@
614 nRoot = (int)strlen(g.zLocalRoot);
615 if( !dirsOnlyFlag ){
616 Stmt q;
617 Blob repo;
618 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags,
619 extremeFlag ? 0 : pIgnore, pKeep);
620 db_prepare(&q,
621 "SELECT %Q || x FROM sfile"
622 " WHERE x NOT IN (%s)"
623 " ORDER BY 1",
624 g.zLocalRoot, fossil_all_reserved_names(0)
@@ -627,10 +634,17 @@
627 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
628 }
629 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
630 while( db_step(&q)==SQLITE_ROW ){
631 const char *zName = db_column_text(&q, 0);
 
 
 
 
 
 
 
632 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
633 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
634 Blob ans;
635 char cReply;
636 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -662,21 +676,28 @@
662 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
663 Stmt q;
664 Blob root;
665 blob_init(&root, g.zLocalRoot, nRoot - 1);
666 vfile_dir_scan(&root, blob_size(&root), scanFlags,
667 extremeFlag ? 0 : pIgnore, pKeep,
668 extremeFlag ? 0 : pEmptyDirs);
669 blob_reset(&root);
670 db_prepare(&q,
671 "SELECT %Q || x FROM dscan_temp"
672 " WHERE x NOT IN (%s) AND y = 0"
673 " ORDER BY 1 DESC",
674 g.zLocalRoot, fossil_all_reserved_names(0)
675 );
676 while( db_step(&q)==SQLITE_ROW ){
677 const char *zName = db_column_text(&q, 0);
 
 
 
 
 
 
 
678 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
679 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
680 Blob ans;
681 char cReply;
682 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -842,11 +863,11 @@
842 #else
843 blob_init(&prompt, zInit, -1);
844 #endif
845 blob_append(&prompt,
846 "\n"
847 "# Enter commit message for this check-in. Lines beginning with # are ignored.\n"
848 "#\n", -1
849 );
850 blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
851 if( p->zBranch && p->zBranch[0] ){
852 blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
@@ -1345,21 +1366,25 @@
1345 char *zOrig = file_newname(zFilename, "original", 1);
1346 FILE *f;
1347 blob_write_to_file(p, zOrig);
1348 fossil_free(zOrig);
1349 f = fossil_fopen(zFilename, "wb");
1350 if( fUnicode ) {
1351 int bomSize;
1352 const unsigned char *bom = get_utf8_bom(&bomSize);
1353 fwrite(bom, 1, bomSize, f);
1354 blob_to_utf8_no_bom(p, 0);
1355 }
1356 if( fHasAnyCr ){
1357 blob_to_lf_only(p);
1358 }
1359 fwrite(blob_buffer(p), 1, blob_size(p), f);
1360 fclose(f);
 
 
 
 
1361 return 1;
1362 }else if( cReply!='y' && cReply!='Y' ){
1363 fossil_fatal("Abandoning commit due to %s in %s",
1364 zWarning, blob_str(&fname));
1365 }
@@ -1421,10 +1446,14 @@
1421 ** unless the interactive user chooses to proceed. If there is no
1422 ** interactive user or these warnings should be skipped for some other
1423 ** reason, the --no-warnings option may be used. A check-in is not
1424 ** allowed against a closed leaf.
1425 **
 
 
 
 
1426 ** The --private option creates a private check-in that is never synced.
1427 ** Children of private check-ins are automatically private.
1428 **
1429 ** The --tag option applies the symbolic tag name to the check-in.
1430 **
@@ -1452,11 +1481,11 @@
1452 ** --private do not sync changes and their descendants
1453 ** --sha1sum verify file status using SHA1 hashing rather
1454 ** than relying on file mtimes
1455 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1456 **
1457 ** See also: branch, changes, checkout, extra, sync
1458 */
1459 void commit_cmd(void){
1460 int hasChanges; /* True if unsaved changes exist */
1461 int vid; /* blob-id of parent version */
1462 int nrid; /* blob-id of a modified file */
1463
--- src/checkin.c
+++ src/checkin.c
@@ -179,11 +179,11 @@
179 ** --sha1sum Verify file status using SHA1 hashing rather
180 ** than relying on file mtimes.
181 ** --header Identify the repository if there are changes
182 ** -v|--verbose Say "(none)" if there are no changes
183 **
184 ** See also: extras, ls, status
185 */
186 void changes_cmd(void){
187 Blob report;
188 int vid;
189 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
@@ -223,11 +223,11 @@
223 ** --rel-paths Display pathnames relative to the current working
224 ** directory.
225 ** --sha1sum Verify file status using SHA1 hashing rather
226 ** than relying on file mtimes.
227 **
228 ** See also: changes, extras, ls
229 */
230 void status_cmd(void){
231 int vid;
232 db_must_be_within_tree();
233 /* 012345678901234 */
@@ -255,11 +255,11 @@
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
259 **
260 ** See also: changes, extras, status
261 */
262 void ls_cmd(void){
263 int vid;
264 Stmt q;
265 int verboseFlag;
@@ -433,20 +433,22 @@
433 **
434 ** Options:
435 ** --abs-paths Display absolute pathnames.
436 ** --case-sensitive <BOOL> override case-sensitive setting
437 ** --dotfiles include files beginning with a dot (".")
438 ** --header Identify the repository if there are extras
439 ** --ignore <CSG> ignore files matching patterns from the argument
440 ** --rel-paths Display pathnames relative to the current working
441 ** directory.
442 **
443 ** See also: changes, clean, status
444 */
445 void extras_cmd(void){
446 Stmt q;
447 const char *zIgnoreFlag = find_option("ignore",0,1);
448 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
449 int showHdr = find_option("header",0,0)!=0;
450 int cwdRelative = 0;
451 Glob *pIgnore;
452 Blob rewrittenPathname;
453 const char *zPathname, *zDisplayName;
454
@@ -477,10 +479,15 @@
479 zDisplayName = blob_str(&rewrittenPathname);
480 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
481 zDisplayName += 2; /* no unnecessary ./ prefix */
482 }
483 }
484 if( showHdr ){
485 showHdr = 0;
486 fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
487 g.zLocalRoot);
488 }
489 fossil_print("%s\n", zDisplayName);
490 }
491 blob_reset(&rewrittenPathname);
492 db_finalize(&q);
493 }
@@ -547,11 +554,11 @@
554 ** checkout, except the ones matching --keep.
555 ** Files not matching any of --clean/--ignore/-keep,
556 ** will be prompted for.
557 ** Compatibile with "git clean -x".
558 **
559 ** See also: addremove, extras, status
560 */
561 void clean_cmd(void){
562 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
563 int emptyDirsFlag, dirsOnlyFlag;
564 unsigned scanFlags = 0;
@@ -614,11 +621,11 @@
621 nRoot = (int)strlen(g.zLocalRoot);
622 if( !dirsOnlyFlag ){
623 Stmt q;
624 Blob repo;
625 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags,
626 extremeFlag ? 0 : pIgnore, 0);
627 db_prepare(&q,
628 "SELECT %Q || x FROM sfile"
629 " WHERE x NOT IN (%s)"
630 " ORDER BY 1",
631 g.zLocalRoot, fossil_all_reserved_names(0)
@@ -627,10 +634,17 @@
634 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
635 }
636 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
637 while( db_step(&q)==SQLITE_ROW ){
638 const char *zName = db_column_text(&q, 0);
639 if( glob_match(pKeep, zName+nRoot) ){
640 if( verboseFlag ){
641 fossil_print("KEPT file \"%s\" not removed (due to --keep"
642 " or \"keep-glob\")\n", zName+nRoot);
643 }
644 continue;
645 }
646 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
647 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
648 Blob ans;
649 char cReply;
650 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -662,21 +676,28 @@
676 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
677 Stmt q;
678 Blob root;
679 blob_init(&root, g.zLocalRoot, nRoot - 1);
680 vfile_dir_scan(&root, blob_size(&root), scanFlags,
681 extremeFlag ? 0 : pIgnore,
682 extremeFlag ? 0 : pEmptyDirs, 0);
683 blob_reset(&root);
684 db_prepare(&q,
685 "SELECT %Q || x FROM dscan_temp"
686 " WHERE x NOT IN (%s) AND y = 0"
687 " ORDER BY 1 DESC",
688 g.zLocalRoot, fossil_all_reserved_names(0)
689 );
690 while( db_step(&q)==SQLITE_ROW ){
691 const char *zName = db_column_text(&q, 0);
692 if( glob_match(pKeep, zName+nRoot) ){
693 if( verboseFlag ){
694 fossil_print("KEPT directory \"%s\" not removed (due to --keep"
695 " or \"keep-glob\")\n", zName+nRoot);
696 }
697 continue;
698 }
699 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
700 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
701 Blob ans;
702 char cReply;
703 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -842,11 +863,11 @@
863 #else
864 blob_init(&prompt, zInit, -1);
865 #endif
866 blob_append(&prompt,
867 "\n"
868 "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
869 "#\n", -1
870 );
871 blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
872 if( p->zBranch && p->zBranch[0] ){
873 blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
@@ -1345,21 +1366,25 @@
1366 char *zOrig = file_newname(zFilename, "original", 1);
1367 FILE *f;
1368 blob_write_to_file(p, zOrig);
1369 fossil_free(zOrig);
1370 f = fossil_fopen(zFilename, "wb");
1371 if( f==0 ){
1372 fossil_warning("cannot open %s for writing", zFilename);
1373 }else{
1374 if( fUnicode ) {
1375 int bomSize;
1376 const unsigned char *bom = get_utf8_bom(&bomSize);
1377 fwrite(bom, 1, bomSize, f);
1378 blob_to_utf8_no_bom(p, 0);
1379 }
1380 if( fHasAnyCr ){
1381 blob_to_lf_only(p);
1382 }
1383 fwrite(blob_buffer(p), 1, blob_size(p), f);
1384 fclose(f);
1385 }
1386 return 1;
1387 }else if( cReply!='y' && cReply!='Y' ){
1388 fossil_fatal("Abandoning commit due to %s in %s",
1389 zWarning, blob_str(&fname));
1390 }
@@ -1421,10 +1446,14 @@
1446 ** unless the interactive user chooses to proceed. If there is no
1447 ** interactive user or these warnings should be skipped for some other
1448 ** reason, the --no-warnings option may be used. A check-in is not
1449 ** allowed against a closed leaf.
1450 **
1451 ** If a commit message is blank, you will be prompted:
1452 ** ("continue (y/N)?") to confirm you really want to commit with a
1453 ** blank commit message. The default value is "N", do not commit.
1454 **
1455 ** The --private option creates a private check-in that is never synced.
1456 ** Children of private check-ins are automatically private.
1457 **
1458 ** The --tag option applies the symbolic tag name to the check-in.
1459 **
@@ -1452,11 +1481,11 @@
1481 ** --private do not sync changes and their descendants
1482 ** --sha1sum verify file status using SHA1 hashing rather
1483 ** than relying on file mtimes
1484 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1485 **
1486 ** See also: branch, changes, checkout, extras, sync
1487 */
1488 void commit_cmd(void){
1489 int hasChanges; /* True if unsaved changes exist */
1490 int vid; /* blob-id of parent version */
1491 int nrid; /* blob-id of a modified file */
1492
+50 -21
--- src/checkin.c
+++ src/checkin.c
@@ -179,11 +179,11 @@
179179
** --sha1sum Verify file status using SHA1 hashing rather
180180
** than relying on file mtimes.
181181
** --header Identify the repository if there are changes
182182
** -v|--verbose Say "(none)" if there are no changes
183183
**
184
-** See also: extra, ls, status
184
+** See also: extras, ls, status
185185
*/
186186
void changes_cmd(void){
187187
Blob report;
188188
int vid;
189189
int useSha1sum = find_option("sha1sum", 0, 0)!=0;
@@ -223,11 +223,11 @@
223223
** --rel-paths Display pathnames relative to the current working
224224
** directory.
225225
** --sha1sum Verify file status using SHA1 hashing rather
226226
** than relying on file mtimes.
227227
**
228
-** See also: changes, extra, ls
228
+** See also: changes, extras, ls
229229
*/
230230
void status_cmd(void){
231231
int vid;
232232
db_must_be_within_tree();
233233
/* 012345678901234 */
@@ -255,11 +255,11 @@
255255
**
256256
** Options:
257257
** --age Show when each file was committed
258258
** -v|--verbose Provide extra information about each file.
259259
**
260
-** See also: changes, extra, status
260
+** See also: changes, extras, status
261261
*/
262262
void ls_cmd(void){
263263
int vid;
264264
Stmt q;
265265
int verboseFlag;
@@ -433,20 +433,22 @@
433433
**
434434
** Options:
435435
** --abs-paths Display absolute pathnames.
436436
** --case-sensitive <BOOL> override case-sensitive setting
437437
** --dotfiles include files beginning with a dot (".")
438
+** --header Identify the repository if there are extras
438439
** --ignore <CSG> ignore files matching patterns from the argument
439440
** --rel-paths Display pathnames relative to the current working
440441
** directory.
441442
**
442443
** See also: changes, clean, status
443444
*/
444
-void extra_cmd(void){
445
+void extras_cmd(void){
445446
Stmt q;
446447
const char *zIgnoreFlag = find_option("ignore",0,1);
447448
unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
449
+ int showHdr = find_option("header",0,0)!=0;
448450
int cwdRelative = 0;
449451
Glob *pIgnore;
450452
Blob rewrittenPathname;
451453
const char *zPathname, *zDisplayName;
452454
@@ -477,10 +479,15 @@
477479
zDisplayName = blob_str(&rewrittenPathname);
478480
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
479481
zDisplayName += 2; /* no unnecessary ./ prefix */
480482
}
481483
}
484
+ if( showHdr ){
485
+ showHdr = 0;
486
+ fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
487
+ g.zLocalRoot);
488
+ }
482489
fossil_print("%s\n", zDisplayName);
483490
}
484491
blob_reset(&rewrittenPathname);
485492
db_finalize(&q);
486493
}
@@ -547,11 +554,11 @@
547554
** checkout, except the ones matching --keep.
548555
** Files not matching any of --clean/--ignore/-keep,
549556
** will be prompted for.
550557
** Compatibile with "git clean -x".
551558
**
552
-** See also: addremove, extra, status
559
+** See also: addremove, extras, status
553560
*/
554561
void clean_cmd(void){
555562
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
556563
int emptyDirsFlag, dirsOnlyFlag;
557564
unsigned scanFlags = 0;
@@ -614,11 +621,11 @@
614621
nRoot = (int)strlen(g.zLocalRoot);
615622
if( !dirsOnlyFlag ){
616623
Stmt q;
617624
Blob repo;
618625
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags,
619
- extremeFlag ? 0 : pIgnore, pKeep);
626
+ extremeFlag ? 0 : pIgnore, 0);
620627
db_prepare(&q,
621628
"SELECT %Q || x FROM sfile"
622629
" WHERE x NOT IN (%s)"
623630
" ORDER BY 1",
624631
g.zLocalRoot, fossil_all_reserved_names(0)
@@ -627,10 +634,17 @@
627634
db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
628635
}
629636
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
630637
while( db_step(&q)==SQLITE_ROW ){
631638
const char *zName = db_column_text(&q, 0);
639
+ if( glob_match(pKeep, zName+nRoot) ){
640
+ if( verboseFlag ){
641
+ fossil_print("KEPT file \"%s\" not removed (due to --keep"
642
+ " or \"keep-glob\")\n", zName+nRoot);
643
+ }
644
+ continue;
645
+ }
632646
if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
633647
&& !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
634648
Blob ans;
635649
char cReply;
636650
int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -662,21 +676,28 @@
662676
Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
663677
Stmt q;
664678
Blob root;
665679
blob_init(&root, g.zLocalRoot, nRoot - 1);
666680
vfile_dir_scan(&root, blob_size(&root), scanFlags,
667
- extremeFlag ? 0 : pIgnore, pKeep,
668
- extremeFlag ? 0 : pEmptyDirs);
681
+ extremeFlag ? 0 : pIgnore,
682
+ extremeFlag ? 0 : pEmptyDirs, 0);
669683
blob_reset(&root);
670684
db_prepare(&q,
671685
"SELECT %Q || x FROM dscan_temp"
672686
" WHERE x NOT IN (%s) AND y = 0"
673687
" ORDER BY 1 DESC",
674688
g.zLocalRoot, fossil_all_reserved_names(0)
675689
);
676690
while( db_step(&q)==SQLITE_ROW ){
677691
const char *zName = db_column_text(&q, 0);
692
+ if( glob_match(pKeep, zName+nRoot) ){
693
+ if( verboseFlag ){
694
+ fossil_print("KEPT directory \"%s\" not removed (due to --keep"
695
+ " or \"keep-glob\")\n", zName+nRoot);
696
+ }
697
+ continue;
698
+ }
678699
if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
679700
&& !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
680701
Blob ans;
681702
char cReply;
682703
int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -842,11 +863,11 @@
842863
#else
843864
blob_init(&prompt, zInit, -1);
844865
#endif
845866
blob_append(&prompt,
846867
"\n"
847
- "# Enter commit message for this check-in. Lines beginning with # are ignored.\n"
868
+ "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
848869
"#\n", -1
849870
);
850871
blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
851872
if( p->zBranch && p->zBranch[0] ){
852873
blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
@@ -1345,21 +1366,25 @@
13451366
char *zOrig = file_newname(zFilename, "original", 1);
13461367
FILE *f;
13471368
blob_write_to_file(p, zOrig);
13481369
fossil_free(zOrig);
13491370
f = fossil_fopen(zFilename, "wb");
1350
- if( fUnicode ) {
1351
- int bomSize;
1352
- const unsigned char *bom = get_utf8_bom(&bomSize);
1353
- fwrite(bom, 1, bomSize, f);
1354
- blob_to_utf8_no_bom(p, 0);
1355
- }
1356
- if( fHasAnyCr ){
1357
- blob_to_lf_only(p);
1358
- }
1359
- fwrite(blob_buffer(p), 1, blob_size(p), f);
1360
- fclose(f);
1371
+ if( f==0 ){
1372
+ fossil_warning("cannot open %s for writing", zFilename);
1373
+ }else{
1374
+ if( fUnicode ) {
1375
+ int bomSize;
1376
+ const unsigned char *bom = get_utf8_bom(&bomSize);
1377
+ fwrite(bom, 1, bomSize, f);
1378
+ blob_to_utf8_no_bom(p, 0);
1379
+ }
1380
+ if( fHasAnyCr ){
1381
+ blob_to_lf_only(p);
1382
+ }
1383
+ fwrite(blob_buffer(p), 1, blob_size(p), f);
1384
+ fclose(f);
1385
+ }
13611386
return 1;
13621387
}else if( cReply!='y' && cReply!='Y' ){
13631388
fossil_fatal("Abandoning commit due to %s in %s",
13641389
zWarning, blob_str(&fname));
13651390
}
@@ -1421,10 +1446,14 @@
14211446
** unless the interactive user chooses to proceed. If there is no
14221447
** interactive user or these warnings should be skipped for some other
14231448
** reason, the --no-warnings option may be used. A check-in is not
14241449
** allowed against a closed leaf.
14251450
**
1451
+** If a commit message is blank, you will be prompted:
1452
+** ("continue (y/N)?") to confirm you really want to commit with a
1453
+** blank commit message. The default value is "N", do not commit.
1454
+**
14261455
** The --private option creates a private check-in that is never synced.
14271456
** Children of private check-ins are automatically private.
14281457
**
14291458
** The --tag option applies the symbolic tag name to the check-in.
14301459
**
@@ -1452,11 +1481,11 @@
14521481
** --private do not sync changes and their descendants
14531482
** --sha1sum verify file status using SHA1 hashing rather
14541483
** than relying on file mtimes
14551484
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
14561485
**
1457
-** See also: branch, changes, checkout, extra, sync
1486
+** See also: branch, changes, checkout, extras, sync
14581487
*/
14591488
void commit_cmd(void){
14601489
int hasChanges; /* True if unsaved changes exist */
14611490
int vid; /* blob-id of parent version */
14621491
int nrid; /* blob-id of a modified file */
14631492
--- src/checkin.c
+++ src/checkin.c
@@ -179,11 +179,11 @@
179 ** --sha1sum Verify file status using SHA1 hashing rather
180 ** than relying on file mtimes.
181 ** --header Identify the repository if there are changes
182 ** -v|--verbose Say "(none)" if there are no changes
183 **
184 ** See also: extra, ls, status
185 */
186 void changes_cmd(void){
187 Blob report;
188 int vid;
189 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
@@ -223,11 +223,11 @@
223 ** --rel-paths Display pathnames relative to the current working
224 ** directory.
225 ** --sha1sum Verify file status using SHA1 hashing rather
226 ** than relying on file mtimes.
227 **
228 ** See also: changes, extra, ls
229 */
230 void status_cmd(void){
231 int vid;
232 db_must_be_within_tree();
233 /* 012345678901234 */
@@ -255,11 +255,11 @@
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
259 **
260 ** See also: changes, extra, status
261 */
262 void ls_cmd(void){
263 int vid;
264 Stmt q;
265 int verboseFlag;
@@ -433,20 +433,22 @@
433 **
434 ** Options:
435 ** --abs-paths Display absolute pathnames.
436 ** --case-sensitive <BOOL> override case-sensitive setting
437 ** --dotfiles include files beginning with a dot (".")
 
438 ** --ignore <CSG> ignore files matching patterns from the argument
439 ** --rel-paths Display pathnames relative to the current working
440 ** directory.
441 **
442 ** See also: changes, clean, status
443 */
444 void extra_cmd(void){
445 Stmt q;
446 const char *zIgnoreFlag = find_option("ignore",0,1);
447 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
 
448 int cwdRelative = 0;
449 Glob *pIgnore;
450 Blob rewrittenPathname;
451 const char *zPathname, *zDisplayName;
452
@@ -477,10 +479,15 @@
477 zDisplayName = blob_str(&rewrittenPathname);
478 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
479 zDisplayName += 2; /* no unnecessary ./ prefix */
480 }
481 }
 
 
 
 
 
482 fossil_print("%s\n", zDisplayName);
483 }
484 blob_reset(&rewrittenPathname);
485 db_finalize(&q);
486 }
@@ -547,11 +554,11 @@
547 ** checkout, except the ones matching --keep.
548 ** Files not matching any of --clean/--ignore/-keep,
549 ** will be prompted for.
550 ** Compatibile with "git clean -x".
551 **
552 ** See also: addremove, extra, status
553 */
554 void clean_cmd(void){
555 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
556 int emptyDirsFlag, dirsOnlyFlag;
557 unsigned scanFlags = 0;
@@ -614,11 +621,11 @@
614 nRoot = (int)strlen(g.zLocalRoot);
615 if( !dirsOnlyFlag ){
616 Stmt q;
617 Blob repo;
618 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags,
619 extremeFlag ? 0 : pIgnore, pKeep);
620 db_prepare(&q,
621 "SELECT %Q || x FROM sfile"
622 " WHERE x NOT IN (%s)"
623 " ORDER BY 1",
624 g.zLocalRoot, fossil_all_reserved_names(0)
@@ -627,10 +634,17 @@
627 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
628 }
629 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
630 while( db_step(&q)==SQLITE_ROW ){
631 const char *zName = db_column_text(&q, 0);
 
 
 
 
 
 
 
632 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
633 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
634 Blob ans;
635 char cReply;
636 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -662,21 +676,28 @@
662 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
663 Stmt q;
664 Blob root;
665 blob_init(&root, g.zLocalRoot, nRoot - 1);
666 vfile_dir_scan(&root, blob_size(&root), scanFlags,
667 extremeFlag ? 0 : pIgnore, pKeep,
668 extremeFlag ? 0 : pEmptyDirs);
669 blob_reset(&root);
670 db_prepare(&q,
671 "SELECT %Q || x FROM dscan_temp"
672 " WHERE x NOT IN (%s) AND y = 0"
673 " ORDER BY 1 DESC",
674 g.zLocalRoot, fossil_all_reserved_names(0)
675 );
676 while( db_step(&q)==SQLITE_ROW ){
677 const char *zName = db_column_text(&q, 0);
 
 
 
 
 
 
 
678 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
679 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
680 Blob ans;
681 char cReply;
682 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -842,11 +863,11 @@
842 #else
843 blob_init(&prompt, zInit, -1);
844 #endif
845 blob_append(&prompt,
846 "\n"
847 "# Enter commit message for this check-in. Lines beginning with # are ignored.\n"
848 "#\n", -1
849 );
850 blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
851 if( p->zBranch && p->zBranch[0] ){
852 blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
@@ -1345,21 +1366,25 @@
1345 char *zOrig = file_newname(zFilename, "original", 1);
1346 FILE *f;
1347 blob_write_to_file(p, zOrig);
1348 fossil_free(zOrig);
1349 f = fossil_fopen(zFilename, "wb");
1350 if( fUnicode ) {
1351 int bomSize;
1352 const unsigned char *bom = get_utf8_bom(&bomSize);
1353 fwrite(bom, 1, bomSize, f);
1354 blob_to_utf8_no_bom(p, 0);
1355 }
1356 if( fHasAnyCr ){
1357 blob_to_lf_only(p);
1358 }
1359 fwrite(blob_buffer(p), 1, blob_size(p), f);
1360 fclose(f);
 
 
 
 
1361 return 1;
1362 }else if( cReply!='y' && cReply!='Y' ){
1363 fossil_fatal("Abandoning commit due to %s in %s",
1364 zWarning, blob_str(&fname));
1365 }
@@ -1421,10 +1446,14 @@
1421 ** unless the interactive user chooses to proceed. If there is no
1422 ** interactive user or these warnings should be skipped for some other
1423 ** reason, the --no-warnings option may be used. A check-in is not
1424 ** allowed against a closed leaf.
1425 **
 
 
 
 
1426 ** The --private option creates a private check-in that is never synced.
1427 ** Children of private check-ins are automatically private.
1428 **
1429 ** The --tag option applies the symbolic tag name to the check-in.
1430 **
@@ -1452,11 +1481,11 @@
1452 ** --private do not sync changes and their descendants
1453 ** --sha1sum verify file status using SHA1 hashing rather
1454 ** than relying on file mtimes
1455 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1456 **
1457 ** See also: branch, changes, checkout, extra, sync
1458 */
1459 void commit_cmd(void){
1460 int hasChanges; /* True if unsaved changes exist */
1461 int vid; /* blob-id of parent version */
1462 int nrid; /* blob-id of a modified file */
1463
--- src/checkin.c
+++ src/checkin.c
@@ -179,11 +179,11 @@
179 ** --sha1sum Verify file status using SHA1 hashing rather
180 ** than relying on file mtimes.
181 ** --header Identify the repository if there are changes
182 ** -v|--verbose Say "(none)" if there are no changes
183 **
184 ** See also: extras, ls, status
185 */
186 void changes_cmd(void){
187 Blob report;
188 int vid;
189 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
@@ -223,11 +223,11 @@
223 ** --rel-paths Display pathnames relative to the current working
224 ** directory.
225 ** --sha1sum Verify file status using SHA1 hashing rather
226 ** than relying on file mtimes.
227 **
228 ** See also: changes, extras, ls
229 */
230 void status_cmd(void){
231 int vid;
232 db_must_be_within_tree();
233 /* 012345678901234 */
@@ -255,11 +255,11 @@
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
259 **
260 ** See also: changes, extras, status
261 */
262 void ls_cmd(void){
263 int vid;
264 Stmt q;
265 int verboseFlag;
@@ -433,20 +433,22 @@
433 **
434 ** Options:
435 ** --abs-paths Display absolute pathnames.
436 ** --case-sensitive <BOOL> override case-sensitive setting
437 ** --dotfiles include files beginning with a dot (".")
438 ** --header Identify the repository if there are extras
439 ** --ignore <CSG> ignore files matching patterns from the argument
440 ** --rel-paths Display pathnames relative to the current working
441 ** directory.
442 **
443 ** See also: changes, clean, status
444 */
445 void extras_cmd(void){
446 Stmt q;
447 const char *zIgnoreFlag = find_option("ignore",0,1);
448 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
449 int showHdr = find_option("header",0,0)!=0;
450 int cwdRelative = 0;
451 Glob *pIgnore;
452 Blob rewrittenPathname;
453 const char *zPathname, *zDisplayName;
454
@@ -477,10 +479,15 @@
479 zDisplayName = blob_str(&rewrittenPathname);
480 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
481 zDisplayName += 2; /* no unnecessary ./ prefix */
482 }
483 }
484 if( showHdr ){
485 showHdr = 0;
486 fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
487 g.zLocalRoot);
488 }
489 fossil_print("%s\n", zDisplayName);
490 }
491 blob_reset(&rewrittenPathname);
492 db_finalize(&q);
493 }
@@ -547,11 +554,11 @@
554 ** checkout, except the ones matching --keep.
555 ** Files not matching any of --clean/--ignore/-keep,
556 ** will be prompted for.
557 ** Compatibile with "git clean -x".
558 **
559 ** See also: addremove, extras, status
560 */
561 void clean_cmd(void){
562 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
563 int emptyDirsFlag, dirsOnlyFlag;
564 unsigned scanFlags = 0;
@@ -614,11 +621,11 @@
621 nRoot = (int)strlen(g.zLocalRoot);
622 if( !dirsOnlyFlag ){
623 Stmt q;
624 Blob repo;
625 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags,
626 extremeFlag ? 0 : pIgnore, 0);
627 db_prepare(&q,
628 "SELECT %Q || x FROM sfile"
629 " WHERE x NOT IN (%s)"
630 " ORDER BY 1",
631 g.zLocalRoot, fossil_all_reserved_names(0)
@@ -627,10 +634,17 @@
634 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
635 }
636 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
637 while( db_step(&q)==SQLITE_ROW ){
638 const char *zName = db_column_text(&q, 0);
639 if( glob_match(pKeep, zName+nRoot) ){
640 if( verboseFlag ){
641 fossil_print("KEPT file \"%s\" not removed (due to --keep"
642 " or \"keep-glob\")\n", zName+nRoot);
643 }
644 continue;
645 }
646 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
647 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
648 Blob ans;
649 char cReply;
650 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -662,21 +676,28 @@
676 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
677 Stmt q;
678 Blob root;
679 blob_init(&root, g.zLocalRoot, nRoot - 1);
680 vfile_dir_scan(&root, blob_size(&root), scanFlags,
681 extremeFlag ? 0 : pIgnore,
682 extremeFlag ? 0 : pEmptyDirs, 0);
683 blob_reset(&root);
684 db_prepare(&q,
685 "SELECT %Q || x FROM dscan_temp"
686 " WHERE x NOT IN (%s) AND y = 0"
687 " ORDER BY 1 DESC",
688 g.zLocalRoot, fossil_all_reserved_names(0)
689 );
690 while( db_step(&q)==SQLITE_ROW ){
691 const char *zName = db_column_text(&q, 0);
692 if( glob_match(pKeep, zName+nRoot) ){
693 if( verboseFlag ){
694 fossil_print("KEPT directory \"%s\" not removed (due to --keep"
695 " or \"keep-glob\")\n", zName+nRoot);
696 }
697 continue;
698 }
699 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot)
700 && !(extremeFlag && glob_match(pIgnore, zName+nRoot)) ){
701 Blob ans;
702 char cReply;
703 int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
@@ -842,11 +863,11 @@
863 #else
864 blob_init(&prompt, zInit, -1);
865 #endif
866 blob_append(&prompt,
867 "\n"
868 "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
869 "#\n", -1
870 );
871 blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
872 if( p->zBranch && p->zBranch[0] ){
873 blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
@@ -1345,21 +1366,25 @@
1366 char *zOrig = file_newname(zFilename, "original", 1);
1367 FILE *f;
1368 blob_write_to_file(p, zOrig);
1369 fossil_free(zOrig);
1370 f = fossil_fopen(zFilename, "wb");
1371 if( f==0 ){
1372 fossil_warning("cannot open %s for writing", zFilename);
1373 }else{
1374 if( fUnicode ) {
1375 int bomSize;
1376 const unsigned char *bom = get_utf8_bom(&bomSize);
1377 fwrite(bom, 1, bomSize, f);
1378 blob_to_utf8_no_bom(p, 0);
1379 }
1380 if( fHasAnyCr ){
1381 blob_to_lf_only(p);
1382 }
1383 fwrite(blob_buffer(p), 1, blob_size(p), f);
1384 fclose(f);
1385 }
1386 return 1;
1387 }else if( cReply!='y' && cReply!='Y' ){
1388 fossil_fatal("Abandoning commit due to %s in %s",
1389 zWarning, blob_str(&fname));
1390 }
@@ -1421,10 +1446,14 @@
1446 ** unless the interactive user chooses to proceed. If there is no
1447 ** interactive user or these warnings should be skipped for some other
1448 ** reason, the --no-warnings option may be used. A check-in is not
1449 ** allowed against a closed leaf.
1450 **
1451 ** If a commit message is blank, you will be prompted:
1452 ** ("continue (y/N)?") to confirm you really want to commit with a
1453 ** blank commit message. The default value is "N", do not commit.
1454 **
1455 ** The --private option creates a private check-in that is never synced.
1456 ** Children of private check-ins are automatically private.
1457 **
1458 ** The --tag option applies the symbolic tag name to the check-in.
1459 **
@@ -1452,11 +1481,11 @@
1481 ** --private do not sync changes and their descendants
1482 ** --sha1sum verify file status using SHA1 hashing rather
1483 ** than relying on file mtimes
1484 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1485 **
1486 ** See also: branch, changes, checkout, extras, sync
1487 */
1488 void commit_cmd(void){
1489 int hasChanges; /* True if unsaved changes exist */
1490 int vid; /* blob-id of parent version */
1491 int nrid; /* blob-id of a modified file */
1492
+6 -6
--- src/clone.c
+++ src/clone.c
@@ -136,13 +136,13 @@
136136
if( file_size(g.argv[3])>0 ){
137137
fossil_fatal("file already exists: %s", g.argv[3]);
138138
}
139139
140140
url_parse(g.argv[2], urlFlags);
141
- if( zDefaultUser==0 && g.urlUser!=0 ) zDefaultUser = g.urlUser;
142
- if( g.urlIsFile ){
143
- file_copy(g.urlName, g.argv[3]);
141
+ if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
142
+ if( g.url.isFile ){
143
+ file_copy(g.url.name, g.argv[3]);
144144
db_close(1);
145145
db_open_repository(g.argv[3]);
146146
db_record_repository_filename(g.argv[3]);
147147
url_remember();
148148
if( !bPrivate ) delete_private_content();
@@ -211,11 +211,11 @@
211211
void remember_or_get_http_auth(
212212
const char *zHttpAuth, /* Credentials in the form "user:password" */
213213
int fRemember, /* True to remember credentials for later reuse */
214214
const char *zUrl /* URL for which these credentials apply */
215215
){
216
- char *zKey = mprintf("http-auth:%s", g.urlCanonical);
216
+ char *zKey = mprintf("http-auth:%s", g.url.canonical);
217217
if( zHttpAuth && zHttpAuth[0] ){
218218
g.zHttpAuth = mprintf("%s", zHttpAuth);
219219
}
220220
if( fRemember ){
221221
if( g.zHttpAuth && g.zHttpAuth[0] ){
@@ -233,20 +233,20 @@
233233
234234
/*
235235
** Get the HTTP Authorization preference from db.
236236
*/
237237
char *get_httpauth(void){
238
- char *zKey = mprintf("http-auth:%s", g.urlCanonical);
238
+ char *zKey = mprintf("http-auth:%s", g.url.canonical);
239239
return unobscure(db_get(zKey, 0));
240240
free(zKey);
241241
}
242242
243243
/*
244244
** Set the HTTP Authorization preference in db.
245245
*/
246246
void set_httpauth(const char *zHttpAuth){
247
- char *zKey = mprintf("http-auth:%s", g.urlCanonical);
247
+ char *zKey = mprintf("http-auth:%s", g.url.canonical);
248248
db_set(zKey, obscure(zHttpAuth), 0);
249249
free(zKey);
250250
}
251251
252252
/*
253253
--- src/clone.c
+++ src/clone.c
@@ -136,13 +136,13 @@
136 if( file_size(g.argv[3])>0 ){
137 fossil_fatal("file already exists: %s", g.argv[3]);
138 }
139
140 url_parse(g.argv[2], urlFlags);
141 if( zDefaultUser==0 && g.urlUser!=0 ) zDefaultUser = g.urlUser;
142 if( g.urlIsFile ){
143 file_copy(g.urlName, g.argv[3]);
144 db_close(1);
145 db_open_repository(g.argv[3]);
146 db_record_repository_filename(g.argv[3]);
147 url_remember();
148 if( !bPrivate ) delete_private_content();
@@ -211,11 +211,11 @@
211 void remember_or_get_http_auth(
212 const char *zHttpAuth, /* Credentials in the form "user:password" */
213 int fRemember, /* True to remember credentials for later reuse */
214 const char *zUrl /* URL for which these credentials apply */
215 ){
216 char *zKey = mprintf("http-auth:%s", g.urlCanonical);
217 if( zHttpAuth && zHttpAuth[0] ){
218 g.zHttpAuth = mprintf("%s", zHttpAuth);
219 }
220 if( fRemember ){
221 if( g.zHttpAuth && g.zHttpAuth[0] ){
@@ -233,20 +233,20 @@
233
234 /*
235 ** Get the HTTP Authorization preference from db.
236 */
237 char *get_httpauth(void){
238 char *zKey = mprintf("http-auth:%s", g.urlCanonical);
239 return unobscure(db_get(zKey, 0));
240 free(zKey);
241 }
242
243 /*
244 ** Set the HTTP Authorization preference in db.
245 */
246 void set_httpauth(const char *zHttpAuth){
247 char *zKey = mprintf("http-auth:%s", g.urlCanonical);
248 db_set(zKey, obscure(zHttpAuth), 0);
249 free(zKey);
250 }
251
252 /*
253
--- src/clone.c
+++ src/clone.c
@@ -136,13 +136,13 @@
136 if( file_size(g.argv[3])>0 ){
137 fossil_fatal("file already exists: %s", g.argv[3]);
138 }
139
140 url_parse(g.argv[2], urlFlags);
141 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
142 if( g.url.isFile ){
143 file_copy(g.url.name, g.argv[3]);
144 db_close(1);
145 db_open_repository(g.argv[3]);
146 db_record_repository_filename(g.argv[3]);
147 url_remember();
148 if( !bPrivate ) delete_private_content();
@@ -211,11 +211,11 @@
211 void remember_or_get_http_auth(
212 const char *zHttpAuth, /* Credentials in the form "user:password" */
213 int fRemember, /* True to remember credentials for later reuse */
214 const char *zUrl /* URL for which these credentials apply */
215 ){
216 char *zKey = mprintf("http-auth:%s", g.url.canonical);
217 if( zHttpAuth && zHttpAuth[0] ){
218 g.zHttpAuth = mprintf("%s", zHttpAuth);
219 }
220 if( fRemember ){
221 if( g.zHttpAuth && g.zHttpAuth[0] ){
@@ -233,20 +233,20 @@
233
234 /*
235 ** Get the HTTP Authorization preference from db.
236 */
237 char *get_httpauth(void){
238 char *zKey = mprintf("http-auth:%s", g.url.canonical);
239 return unobscure(db_get(zKey, 0));
240 free(zKey);
241 }
242
243 /*
244 ** Set the HTTP Authorization preference in db.
245 */
246 void set_httpauth(const char *zHttpAuth){
247 char *zKey = mprintf("http-auth:%s", g.url.canonical);
248 db_set(zKey, obscure(zHttpAuth), 0);
249 free(zKey);
250 }
251
252 /*
253
+1 -1
--- src/configure.c
+++ src/configure.c
@@ -924,11 +924,11 @@
924924
mask = configure_name_to_mask(g.argv[3], 1);
925925
if( g.argc==5 ){
926926
zServer = g.argv[4];
927927
}
928928
url_parse(zServer, URL_PROMPT_PW);
929
- if( g.urlProtocol==0 ) fossil_fatal("no server URL specified");
929
+ if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
930930
user_select();
931931
url_enable_proxy("via proxy: ");
932932
if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
933933
if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
934934
if( strncmp(zMethod, "push", n)==0 ){
935935
--- src/configure.c
+++ src/configure.c
@@ -924,11 +924,11 @@
924 mask = configure_name_to_mask(g.argv[3], 1);
925 if( g.argc==5 ){
926 zServer = g.argv[4];
927 }
928 url_parse(zServer, URL_PROMPT_PW);
929 if( g.urlProtocol==0 ) fossil_fatal("no server URL specified");
930 user_select();
931 url_enable_proxy("via proxy: ");
932 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
933 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
934 if( strncmp(zMethod, "push", n)==0 ){
935
--- src/configure.c
+++ src/configure.c
@@ -924,11 +924,11 @@
924 mask = configure_name_to_mask(g.argv[3], 1);
925 if( g.argc==5 ){
926 zServer = g.argv[4];
927 }
928 url_parse(zServer, URL_PROMPT_PW);
929 if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
930 user_select();
931 url_enable_proxy("via proxy: ");
932 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
933 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
934 if( strncmp(zMethod, "push", n)==0 ){
935
+5 -5
--- src/db.c
+++ src/db.c
@@ -729,16 +729,16 @@
729729
if( rc!=SQLITE_OK ){
730730
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
731731
}
732732
sqlite3_busy_timeout(db, 5000);
733733
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
734
- sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
735
- sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
734
+ sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0);
735
+ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
736736
db_checkin_mtime_function, 0, 0);
737
- sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
738
- sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
739
- sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
737
+ sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
738
+ sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
739
+ sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
740740
sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
741741
sqlite3_create_function(
742742
db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
743743
);
744744
sqlite3_create_function(
745745
--- src/db.c
+++ src/db.c
@@ -729,16 +729,16 @@
729 if( rc!=SQLITE_OK ){
730 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
731 }
732 sqlite3_busy_timeout(db, 5000);
733 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
734 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
735 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
736 db_checkin_mtime_function, 0, 0);
737 sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
738 sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
739 sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
740 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
741 sqlite3_create_function(
742 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
743 );
744 sqlite3_create_function(
745
--- src/db.c
+++ src/db.c
@@ -729,16 +729,16 @@
729 if( rc!=SQLITE_OK ){
730 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
731 }
732 sqlite3_busy_timeout(db, 5000);
733 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
734 sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0);
735 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
736 db_checkin_mtime_function, 0, 0);
737 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
738 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
739 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
740 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
741 sqlite3_create_function(
742 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
743 );
744 sqlite3_create_function(
745
+1 -1
--- src/delta.c
+++ src/delta.c
@@ -467,11 +467,11 @@
467467
zDelta += lenOut-base;
468468
}
469469
/* Output the final checksum record. */
470470
putInt(checksum(zOut, lenOut), &zDelta);
471471
*(zDelta++) = ';';
472
- free(collide);
472
+ fossil_free(collide);
473473
return zDelta - zOrigDelta;
474474
}
475475
476476
/*
477477
** Return the size (in bytes) of the output from applying
478478
--- src/delta.c
+++ src/delta.c
@@ -467,11 +467,11 @@
467 zDelta += lenOut-base;
468 }
469 /* Output the final checksum record. */
470 putInt(checksum(zOut, lenOut), &zDelta);
471 *(zDelta++) = ';';
472 free(collide);
473 return zDelta - zOrigDelta;
474 }
475
476 /*
477 ** Return the size (in bytes) of the output from applying
478
--- src/delta.c
+++ src/delta.c
@@ -467,11 +467,11 @@
467 zDelta += lenOut-base;
468 }
469 /* Output the final checksum record. */
470 putInt(checksum(zOut, lenOut), &zDelta);
471 *(zDelta++) = ';';
472 fossil_free(collide);
473 return zDelta - zOrigDelta;
474 }
475
476 /*
477 ** Return the size (in bytes) of the output from applying
478
--- src/descendants.c
+++ src/descendants.c
@@ -329,14 +329,16 @@
329329
**
330330
** The --recompute flag causes the content of the "leaf" table in the
331331
** repository database to be recomputed.
332332
**
333333
** Options:
334
-** -a|--all show ALL leaves
335
-** -c|--closed show only closed leaves
336
-** --bybranch order output by branch name
337
-** --recompute recompute the "leaf" table in the repository DB
334
+** -a|--all show ALL leaves
335
+** -c|--closed show only closed leaves
336
+** --bybranch order output by branch name
337
+** --recompute recompute the "leaf" table in the repository DB
338
+** -W|--width <num> With of lines (default 79). Must be >39 or 0
339
+** (= no limit, resulting in a single line per entry).
338340
**
339341
** See also: descendants, finfo, info, branch
340342
*/
341343
void leaves_cmd(void){
342344
Stmt q;
@@ -343,14 +345,23 @@
343345
Blob sql;
344346
int showAll = find_option("all", "a", 0)!=0;
345347
int showClosed = find_option("closed", "c", 0)!=0;
346348
int recomputeFlag = find_option("recompute",0,0)!=0;
347349
int byBranch = find_option("bybranch",0,0)!=0;
350
+ const char *zWidth = find_option("width","W",1);
348351
char *zLastBr = 0;
349
- int n;
352
+ int n, width;
350353
char zLineNo[10];
351354
355
+ if( zWidth ){
356
+ width = atoi(zWidth);
357
+ if( (width!=0) && (width<=39) ){
358
+ fossil_fatal("-W|--width value must be >39 or 0");
359
+ }
360
+ }else{
361
+ width = 79;
362
+ }
352363
db_find_and_open_repository(0,0);
353364
if( recomputeFlag ) leaf_rebuild();
354365
blob_zero(&sql);
355366
blob_append(&sql, timeline_query_for_tty(), -1);
356367
blob_appendf(&sql, " AND blob.rid IN leaf");
@@ -382,11 +393,11 @@
382393
}
383394
n++;
384395
sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
385396
fossil_print("%6s ", zLineNo);
386397
z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
387
- comment_print(z, 7, 79);
398
+ comment_print(z, 7, width);
388399
fossil_free(z);
389400
}
390401
fossil_free(zLastBr);
391402
db_finalize(&q);
392403
}
393404
--- src/descendants.c
+++ src/descendants.c
@@ -329,14 +329,16 @@
329 **
330 ** The --recompute flag causes the content of the "leaf" table in the
331 ** repository database to be recomputed.
332 **
333 ** Options:
334 ** -a|--all show ALL leaves
335 ** -c|--closed show only closed leaves
336 ** --bybranch order output by branch name
337 ** --recompute recompute the "leaf" table in the repository DB
 
 
338 **
339 ** See also: descendants, finfo, info, branch
340 */
341 void leaves_cmd(void){
342 Stmt q;
@@ -343,14 +345,23 @@
343 Blob sql;
344 int showAll = find_option("all", "a", 0)!=0;
345 int showClosed = find_option("closed", "c", 0)!=0;
346 int recomputeFlag = find_option("recompute",0,0)!=0;
347 int byBranch = find_option("bybranch",0,0)!=0;
 
348 char *zLastBr = 0;
349 int n;
350 char zLineNo[10];
351
 
 
 
 
 
 
 
 
352 db_find_and_open_repository(0,0);
353 if( recomputeFlag ) leaf_rebuild();
354 blob_zero(&sql);
355 blob_append(&sql, timeline_query_for_tty(), -1);
356 blob_appendf(&sql, " AND blob.rid IN leaf");
@@ -382,11 +393,11 @@
382 }
383 n++;
384 sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
385 fossil_print("%6s ", zLineNo);
386 z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
387 comment_print(z, 7, 79);
388 fossil_free(z);
389 }
390 fossil_free(zLastBr);
391 db_finalize(&q);
392 }
393
--- src/descendants.c
+++ src/descendants.c
@@ -329,14 +329,16 @@
329 **
330 ** The --recompute flag causes the content of the "leaf" table in the
331 ** repository database to be recomputed.
332 **
333 ** Options:
334 ** -a|--all show ALL leaves
335 ** -c|--closed show only closed leaves
336 ** --bybranch order output by branch name
337 ** --recompute recompute the "leaf" table in the repository DB
338 ** -W|--width <num> With of lines (default 79). Must be >39 or 0
339 ** (= no limit, resulting in a single line per entry).
340 **
341 ** See also: descendants, finfo, info, branch
342 */
343 void leaves_cmd(void){
344 Stmt q;
@@ -343,14 +345,23 @@
345 Blob sql;
346 int showAll = find_option("all", "a", 0)!=0;
347 int showClosed = find_option("closed", "c", 0)!=0;
348 int recomputeFlag = find_option("recompute",0,0)!=0;
349 int byBranch = find_option("bybranch",0,0)!=0;
350 const char *zWidth = find_option("width","W",1);
351 char *zLastBr = 0;
352 int n, width;
353 char zLineNo[10];
354
355 if( zWidth ){
356 width = atoi(zWidth);
357 if( (width!=0) && (width<=39) ){
358 fossil_fatal("-W|--width value must be >39 or 0");
359 }
360 }else{
361 width = 79;
362 }
363 db_find_and_open_repository(0,0);
364 if( recomputeFlag ) leaf_rebuild();
365 blob_zero(&sql);
366 blob_append(&sql, timeline_query_for_tty(), -1);
367 blob_appendf(&sql, " AND blob.rid IN leaf");
@@ -382,11 +393,11 @@
393 }
394 n++;
395 sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
396 fossil_print("%6s ", zLineNo);
397 z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
398 comment_print(z, 7, width);
399 fossil_free(z);
400 }
401 fossil_free(zLastBr);
402 db_finalize(&q);
403 }
404
+14 -14
--- src/diff.c
+++ src/diff.c
@@ -225,11 +225,11 @@
225225
while( a<pA->n && b<pB->n ){
226226
if( pA->z[a++] != pB->z[b++] ) return 0;
227227
while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
228228
while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
229229
}
230
- return pA->n-a == b<pB->n-b;
230
+ return pA->n-a == pB->n-b;
231231
}
232232
return 0;
233233
}
234234
235235
/*
@@ -766,13 +766,13 @@
766766
int aLCS[4]; /* Bounds of common middle segment */
767767
static const char zClassRm[] = "<span class=\"diffrm\">";
768768
static const char zClassAdd[] = "<span class=\"diffadd\">";
769769
static const char zClassChng[] = "<span class=\"diffchng\">";
770770
771
- nLeft = pLeft->h & LENGTH_MASK;
771
+ nLeft = pLeft->n;
772772
zLeft = pLeft->z;
773
- nRight = pRight->h & LENGTH_MASK;
773
+ nRight = pRight->n;
774774
zRight = pRight->z;
775775
nShort = nLeft<nRight ? nLeft : nRight;
776776
777777
nPrefix = 0;
778778
while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
@@ -914,12 +914,12 @@
914914
unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
915915
unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
916916
917917
zA = pA->z;
918918
zB = pB->z;
919
- nA = pA->h & LENGTH_MASK;
920
- nB = pB->h & LENGTH_MASK;
919
+ nA = pA->n;
920
+ nB = pB->n;
921921
while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
922922
while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
923923
while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
924924
while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
925925
if( nA>250 ) nA = 250;
@@ -2307,17 +2307,17 @@
23072307
clr = gradient_color(clr1, clr2, ann.nVers-1, i);
23082308
ann.aVers[i].zBgColor = mprintf("#%06x", clr);
23092309
}
23102310
23112311
if( showLog ){
2312
- char *zLink = href("%R/finfo?name=%t&ci=%S",zFilename,zCI);
2312
+ char *zLink = href("%R/finfo?name=%t&ci=%s",zFilename,zCI);
23132313
@ <h2>Ancestors of %z(zLink)%h(zFilename)</a> analyzed:</h2>
23142314
@ <ol>
23152315
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
23162316
@ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
2317
- @ check-in %z(href("%R/info/%S",p->zMUuid))%.10s(p->zMUuid)</a>
2318
- @ artifact %z(href("%R/artifact/%S",p->zFUuid))%.10s(p->zFUuid)</a>
2317
+ @ check-in %z(href("%R/info/%s",p->zMUuid))%.10s(p->zMUuid)</a>
2318
+ @ artifact %z(href("%R/artifact/%s",p->zFUuid))%.10s(p->zFUuid)</a>
23192319
@ </span>
23202320
#if 0
23212321
if( i>0 ){
23222322
char *zLink = xhref("target='infowindow'",
23232323
"%R/fdiff?v1=%S&v2=%S&sbs=1",
@@ -2335,17 +2335,17 @@
23352335
@ </ol>
23362336
@ <hr>
23372337
}
23382338
if( !ann.bLimit ){
23392339
@ <h2>Origin for each line in
2340
- @ %z(href("%R/finfo?name=%h&ci=%S", zFilename, zCI))%h(zFilename)</a>
2341
- @ from check-in %z(href("%R/info/%S",zCI))%S(zCI)</a>:</h2>
2340
+ @ %z(href("%R/finfo?name=%h&ci=%s", zFilename, zCI))%h(zFilename)</a>
2341
+ @ from check-in %z(href("%R/info/%s",zCI))%S(zCI)</a>:</h2>
23422342
iLimit = ann.nVers+10;
23432343
}else{
23442344
@ <h2>Lines added by the %d(iLimit) most recent ancestors of
2345
- @ %z(href("%R/finfo?name=%h&ci=%S", zFilename, zCI))%h(zFilename)</a>
2346
- @ from check-in %z(href("%R/info/%S",zCI))%S(zCI)</a>:</h2>
2345
+ @ %z(href("%R/finfo?name=%h&ci=%s", zFilename, zCI))%h(zFilename)</a>
2346
+ @ from check-in %z(href("%R/info/%s",zCI))%S(zCI)</a>:</h2>
23472347
}
23482348
@ <pre>
23492349
for(i=0; i<ann.nOrig; i++){
23502350
int iVers = ann.aOrig[i].iVers;
23512351
char *z = (char*)ann.aOrig[i].z;
@@ -2355,11 +2355,11 @@
23552355
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
23562356
23572357
if( bBlame ){
23582358
if( iVers>=0 ){
23592359
struct AnnVers *p = ann.aVers+iVers;
2360
- char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid);
2360
+ char *zLink = xhref("target='infowindow'", "%R/info/%s", p->zMUuid);
23612361
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
23622362
"<span style='background-color:%s'>"
23632363
"%s%.10s</a> %s</span> %13.13s:",
23642364
p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
23652365
fossil_free(zLink);
@@ -2367,11 +2367,11 @@
23672367
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
23682368
}
23692369
}else{
23702370
if( iVers>=0 ){
23712371
struct AnnVers *p = ann.aVers+iVers;
2372
- char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid);
2372
+ char *zLink = xhref("target='infowindow'", "%R/info/%s", p->zMUuid);
23732373
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
23742374
"<span style='background-color:%s'>"
23752375
"%s%.10s</a> %s</span> %4d:",
23762376
p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
23772377
fossil_free(zLink);
23782378
--- src/diff.c
+++ src/diff.c
@@ -225,11 +225,11 @@
225 while( a<pA->n && b<pB->n ){
226 if( pA->z[a++] != pB->z[b++] ) return 0;
227 while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
228 while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
229 }
230 return pA->n-a == b<pB->n-b;
231 }
232 return 0;
233 }
234
235 /*
@@ -766,13 +766,13 @@
766 int aLCS[4]; /* Bounds of common middle segment */
767 static const char zClassRm[] = "<span class=\"diffrm\">";
768 static const char zClassAdd[] = "<span class=\"diffadd\">";
769 static const char zClassChng[] = "<span class=\"diffchng\">";
770
771 nLeft = pLeft->h & LENGTH_MASK;
772 zLeft = pLeft->z;
773 nRight = pRight->h & LENGTH_MASK;
774 zRight = pRight->z;
775 nShort = nLeft<nRight ? nLeft : nRight;
776
777 nPrefix = 0;
778 while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
@@ -914,12 +914,12 @@
914 unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
915 unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
916
917 zA = pA->z;
918 zB = pB->z;
919 nA = pA->h & LENGTH_MASK;
920 nB = pB->h & LENGTH_MASK;
921 while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
922 while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
923 while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
924 while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
925 if( nA>250 ) nA = 250;
@@ -2307,17 +2307,17 @@
2307 clr = gradient_color(clr1, clr2, ann.nVers-1, i);
2308 ann.aVers[i].zBgColor = mprintf("#%06x", clr);
2309 }
2310
2311 if( showLog ){
2312 char *zLink = href("%R/finfo?name=%t&ci=%S",zFilename,zCI);
2313 @ <h2>Ancestors of %z(zLink)%h(zFilename)</a> analyzed:</h2>
2314 @ <ol>
2315 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2316 @ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
2317 @ check-in %z(href("%R/info/%S",p->zMUuid))%.10s(p->zMUuid)</a>
2318 @ artifact %z(href("%R/artifact/%S",p->zFUuid))%.10s(p->zFUuid)</a>
2319 @ </span>
2320 #if 0
2321 if( i>0 ){
2322 char *zLink = xhref("target='infowindow'",
2323 "%R/fdiff?v1=%S&v2=%S&sbs=1",
@@ -2335,17 +2335,17 @@
2335 @ </ol>
2336 @ <hr>
2337 }
2338 if( !ann.bLimit ){
2339 @ <h2>Origin for each line in
2340 @ %z(href("%R/finfo?name=%h&ci=%S", zFilename, zCI))%h(zFilename)</a>
2341 @ from check-in %z(href("%R/info/%S",zCI))%S(zCI)</a>:</h2>
2342 iLimit = ann.nVers+10;
2343 }else{
2344 @ <h2>Lines added by the %d(iLimit) most recent ancestors of
2345 @ %z(href("%R/finfo?name=%h&ci=%S", zFilename, zCI))%h(zFilename)</a>
2346 @ from check-in %z(href("%R/info/%S",zCI))%S(zCI)</a>:</h2>
2347 }
2348 @ <pre>
2349 for(i=0; i<ann.nOrig; i++){
2350 int iVers = ann.aOrig[i].iVers;
2351 char *z = (char*)ann.aOrig[i].z;
@@ -2355,11 +2355,11 @@
2355 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2356
2357 if( bBlame ){
2358 if( iVers>=0 ){
2359 struct AnnVers *p = ann.aVers+iVers;
2360 char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid);
2361 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2362 "<span style='background-color:%s'>"
2363 "%s%.10s</a> %s</span> %13.13s:",
2364 p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
2365 fossil_free(zLink);
@@ -2367,11 +2367,11 @@
2367 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
2368 }
2369 }else{
2370 if( iVers>=0 ){
2371 struct AnnVers *p = ann.aVers+iVers;
2372 char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid);
2373 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2374 "<span style='background-color:%s'>"
2375 "%s%.10s</a> %s</span> %4d:",
2376 p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
2377 fossil_free(zLink);
2378
--- src/diff.c
+++ src/diff.c
@@ -225,11 +225,11 @@
225 while( a<pA->n && b<pB->n ){
226 if( pA->z[a++] != pB->z[b++] ) return 0;
227 while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
228 while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
229 }
230 return pA->n-a == pB->n-b;
231 }
232 return 0;
233 }
234
235 /*
@@ -766,13 +766,13 @@
766 int aLCS[4]; /* Bounds of common middle segment */
767 static const char zClassRm[] = "<span class=\"diffrm\">";
768 static const char zClassAdd[] = "<span class=\"diffadd\">";
769 static const char zClassChng[] = "<span class=\"diffchng\">";
770
771 nLeft = pLeft->n;
772 zLeft = pLeft->z;
773 nRight = pRight->n;
774 zRight = pRight->z;
775 nShort = nLeft<nRight ? nLeft : nRight;
776
777 nPrefix = 0;
778 while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
@@ -914,12 +914,12 @@
914 unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
915 unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
916
917 zA = pA->z;
918 zB = pB->z;
919 nA = pA->n;
920 nB = pB->n;
921 while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
922 while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
923 while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
924 while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
925 if( nA>250 ) nA = 250;
@@ -2307,17 +2307,17 @@
2307 clr = gradient_color(clr1, clr2, ann.nVers-1, i);
2308 ann.aVers[i].zBgColor = mprintf("#%06x", clr);
2309 }
2310
2311 if( showLog ){
2312 char *zLink = href("%R/finfo?name=%t&ci=%s",zFilename,zCI);
2313 @ <h2>Ancestors of %z(zLink)%h(zFilename)</a> analyzed:</h2>
2314 @ <ol>
2315 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2316 @ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
2317 @ check-in %z(href("%R/info/%s",p->zMUuid))%.10s(p->zMUuid)</a>
2318 @ artifact %z(href("%R/artifact/%s",p->zFUuid))%.10s(p->zFUuid)</a>
2319 @ </span>
2320 #if 0
2321 if( i>0 ){
2322 char *zLink = xhref("target='infowindow'",
2323 "%R/fdiff?v1=%S&v2=%S&sbs=1",
@@ -2335,17 +2335,17 @@
2335 @ </ol>
2336 @ <hr>
2337 }
2338 if( !ann.bLimit ){
2339 @ <h2>Origin for each line in
2340 @ %z(href("%R/finfo?name=%h&ci=%s", zFilename, zCI))%h(zFilename)</a>
2341 @ from check-in %z(href("%R/info/%s",zCI))%S(zCI)</a>:</h2>
2342 iLimit = ann.nVers+10;
2343 }else{
2344 @ <h2>Lines added by the %d(iLimit) most recent ancestors of
2345 @ %z(href("%R/finfo?name=%h&ci=%s", zFilename, zCI))%h(zFilename)</a>
2346 @ from check-in %z(href("%R/info/%s",zCI))%S(zCI)</a>:</h2>
2347 }
2348 @ <pre>
2349 for(i=0; i<ann.nOrig; i++){
2350 int iVers = ann.aOrig[i].iVers;
2351 char *z = (char*)ann.aOrig[i].z;
@@ -2355,11 +2355,11 @@
2355 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2356
2357 if( bBlame ){
2358 if( iVers>=0 ){
2359 struct AnnVers *p = ann.aVers+iVers;
2360 char *zLink = xhref("target='infowindow'", "%R/info/%s", p->zMUuid);
2361 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2362 "<span style='background-color:%s'>"
2363 "%s%.10s</a> %s</span> %13.13s:",
2364 p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
2365 fossil_free(zLink);
@@ -2367,11 +2367,11 @@
2367 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
2368 }
2369 }else{
2370 if( iVers>=0 ){
2371 struct AnnVers *p = ann.aVers+iVers;
2372 char *zLink = xhref("target='infowindow'", "%R/info/%s", p->zMUuid);
2373 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2374 "<span style='background-color:%s'>"
2375 "%s%.10s</a> %s</span> %4d:",
2376 p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
2377 fossil_free(zLink);
2378
+35 -3
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -932,10 +932,11 @@
932932
@ }
933933
@ update idletasks
934934
@
935935
@ proc saveDiff {} {
936936
@ set fn [tk_getSaveFile]
937
+@ if {$fn==""} return
937938
@ set out [open $fn wb]
938939
@ puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'"
939940
@ puts $out "# to see the graphical diff.\n#"
940941
@ puts $out "set fossilcmd {}"
941942
@ puts $out "set prog [list $::prog]"
@@ -943,13 +944,39 @@
943944
@ foreach e $::difftxt {puts $out [list $e]}
944945
@ puts $out "\175"
945946
@ puts $out "eval \$prog"
946947
@ close $out
947948
@ }
949
+@ proc invertDiff {} {
950
+@ global CFG
951
+@ array set x [grid info .txtA]
952
+@ if {$x(-column)==1} {
953
+@ grid config .lnB -column 0
954
+@ grid config .txtB -column 1
955
+@ .txtB tag config add -background $CFG(RM_BG)
956
+@ grid config .lnA -column 3
957
+@ grid config .txtA -column 4
958
+@ .txtA tag config rm -background $CFG(ADD_BG)
959
+@ } else {
960
+@ grid config .lnA -column 0
961
+@ grid config .txtA -column 1
962
+@ .txtA tag config rm -background $CFG(RM_BG)
963
+@ grid config .lnB -column 3
964
+@ grid config .txtB -column 4
965
+@ .txtB tag config add -background $CFG(ADD_BG)
966
+@ }
967
+@ .mkr config -state normal
968
+@ set clt [.mkr search -all < 1.0 end]
969
+@ set cgt [.mkr search -all > 1.0 end]
970
+@ foreach c $clt {.mkr replace $c "$c +1 chars" >}
971
+@ foreach c $cgt {.mkr replace $c "$c +1 chars" <}
972
+@ .mkr config -state disabled
973
+@ }
948974
@ ::ttk::button .bb.quit -text {Quit} -command exit
975
+@ ::ttk::button .bb.invert -text {Invert} -command invertDiff
949976
@ ::ttk::button .bb.save -text {Save As...} -command saveDiff
950
-@ pack .bb.quit -side left
977
+@ pack .bb.quit .bb.invert -side left
951978
@ if {$fossilcmd!=""} {pack .bb.save -side left}
952979
@ pack .bb.files -side left
953980
@ grid rowconfigure . 1 -weight 1
954981
@ grid columnconfigure . 1 -weight 1
955982
@ grid columnconfigure . 4 -weight 1
@@ -998,12 +1025,17 @@
9981025
i++;
9991026
zTempFile = g.argv[i];
10001027
continue;
10011028
}
10021029
}
1003
- blob_append(&script, " ", 1);
1004
- shell_escape(&script, z);
1030
+ if( sqlite3_strglob("*}*",z) ){
1031
+ blob_appendf(&script, " {%/}", z);
1032
+ }else{
1033
+ int j;
1034
+ blob_append(&script, " ", 1);
1035
+ for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
1036
+ }
10051037
}
10061038
blob_appendf(&script, "}\n%s", zDiffScript);
10071039
if( zTempFile ){
10081040
blob_write_to_file(&script, zTempFile);
10091041
fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
10101042
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -932,10 +932,11 @@
932 @ }
933 @ update idletasks
934 @
935 @ proc saveDiff {} {
936 @ set fn [tk_getSaveFile]
 
937 @ set out [open $fn wb]
938 @ puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'"
939 @ puts $out "# to see the graphical diff.\n#"
940 @ puts $out "set fossilcmd {}"
941 @ puts $out "set prog [list $::prog]"
@@ -943,13 +944,39 @@
943 @ foreach e $::difftxt {puts $out [list $e]}
944 @ puts $out "\175"
945 @ puts $out "eval \$prog"
946 @ close $out
947 @ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
948 @ ::ttk::button .bb.quit -text {Quit} -command exit
 
949 @ ::ttk::button .bb.save -text {Save As...} -command saveDiff
950 @ pack .bb.quit -side left
951 @ if {$fossilcmd!=""} {pack .bb.save -side left}
952 @ pack .bb.files -side left
953 @ grid rowconfigure . 1 -weight 1
954 @ grid columnconfigure . 1 -weight 1
955 @ grid columnconfigure . 4 -weight 1
@@ -998,12 +1025,17 @@
998 i++;
999 zTempFile = g.argv[i];
1000 continue;
1001 }
1002 }
1003 blob_append(&script, " ", 1);
1004 shell_escape(&script, z);
 
 
 
 
 
1005 }
1006 blob_appendf(&script, "}\n%s", zDiffScript);
1007 if( zTempFile ){
1008 blob_write_to_file(&script, zTempFile);
1009 fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
1010
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -932,10 +932,11 @@
932 @ }
933 @ update idletasks
934 @
935 @ proc saveDiff {} {
936 @ set fn [tk_getSaveFile]
937 @ if {$fn==""} return
938 @ set out [open $fn wb]
939 @ puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'"
940 @ puts $out "# to see the graphical diff.\n#"
941 @ puts $out "set fossilcmd {}"
942 @ puts $out "set prog [list $::prog]"
@@ -943,13 +944,39 @@
944 @ foreach e $::difftxt {puts $out [list $e]}
945 @ puts $out "\175"
946 @ puts $out "eval \$prog"
947 @ close $out
948 @ }
949 @ proc invertDiff {} {
950 @ global CFG
951 @ array set x [grid info .txtA]
952 @ if {$x(-column)==1} {
953 @ grid config .lnB -column 0
954 @ grid config .txtB -column 1
955 @ .txtB tag config add -background $CFG(RM_BG)
956 @ grid config .lnA -column 3
957 @ grid config .txtA -column 4
958 @ .txtA tag config rm -background $CFG(ADD_BG)
959 @ } else {
960 @ grid config .lnA -column 0
961 @ grid config .txtA -column 1
962 @ .txtA tag config rm -background $CFG(RM_BG)
963 @ grid config .lnB -column 3
964 @ grid config .txtB -column 4
965 @ .txtB tag config add -background $CFG(ADD_BG)
966 @ }
967 @ .mkr config -state normal
968 @ set clt [.mkr search -all < 1.0 end]
969 @ set cgt [.mkr search -all > 1.0 end]
970 @ foreach c $clt {.mkr replace $c "$c +1 chars" >}
971 @ foreach c $cgt {.mkr replace $c "$c +1 chars" <}
972 @ .mkr config -state disabled
973 @ }
974 @ ::ttk::button .bb.quit -text {Quit} -command exit
975 @ ::ttk::button .bb.invert -text {Invert} -command invertDiff
976 @ ::ttk::button .bb.save -text {Save As...} -command saveDiff
977 @ pack .bb.quit .bb.invert -side left
978 @ if {$fossilcmd!=""} {pack .bb.save -side left}
979 @ pack .bb.files -side left
980 @ grid rowconfigure . 1 -weight 1
981 @ grid columnconfigure . 1 -weight 1
982 @ grid columnconfigure . 4 -weight 1
@@ -998,12 +1025,17 @@
1025 i++;
1026 zTempFile = g.argv[i];
1027 continue;
1028 }
1029 }
1030 if( sqlite3_strglob("*}*",z) ){
1031 blob_appendf(&script, " {%/}", z);
1032 }else{
1033 int j;
1034 blob_append(&script, " ", 1);
1035 for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
1036 }
1037 }
1038 blob_appendf(&script, "}\n%s", zDiffScript);
1039 if( zTempFile ){
1040 blob_write_to_file(&script, zTempFile);
1041 fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
1042
+7 -1
--- src/file.c
+++ src/file.c
@@ -977,10 +977,12 @@
977977
for(j=i+1; zPwd[j]; j++){
978978
if( zPwd[j]=='/' ){
979979
blob_append(pOut, "/..", 3);
980980
}
981981
}
982
+ while( i>0 && (zPwd[i]!='/')) --i;
983
+ blob_append(pOut, zPath+i, j-i);
982984
}
983985
if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
984986
blob_append(pOut, "/", 1);
985987
}
986988
blob_reset(&tmp);
@@ -1044,11 +1046,14 @@
10441046
int nFull;
10451047
char *zFull;
10461048
int (*xCmp)(const char*,const char*,int);
10471049
10481050
blob_zero(pOut);
1049
- db_must_be_within_tree();
1051
+ if( !g.localOpen ){
1052
+ blob_appendf(pOut, "%s", zOrigName);
1053
+ return 1;
1054
+ }
10501055
file_canonical_name(g.zLocalRoot, &localRoot, 1);
10511056
nLocalRoot = blob_size(&localRoot);
10521057
zLocalRoot = blob_buffer(&localRoot);
10531058
assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
10541059
file_canonical_name(zOrigName, &full, 0);
@@ -1093,10 +1098,11 @@
10931098
** a boolean: "yes", "no", "true", "false", etc.
10941099
*/
10951100
void cmd_test_tree_name(void){
10961101
int i;
10971102
Blob x;
1103
+ db_find_and_open_repository(0,0);
10981104
blob_zero(&x);
10991105
capture_case_sensitive_option();
11001106
for(i=2; i<g.argc; i++){
11011107
if( file_tree_name(g.argv[i], &x, 1) ){
11021108
fossil_print("%s\n", blob_buffer(&x));
11031109
--- src/file.c
+++ src/file.c
@@ -977,10 +977,12 @@
977 for(j=i+1; zPwd[j]; j++){
978 if( zPwd[j]=='/' ){
979 blob_append(pOut, "/..", 3);
980 }
981 }
 
 
982 }
983 if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
984 blob_append(pOut, "/", 1);
985 }
986 blob_reset(&tmp);
@@ -1044,11 +1046,14 @@
1044 int nFull;
1045 char *zFull;
1046 int (*xCmp)(const char*,const char*,int);
1047
1048 blob_zero(pOut);
1049 db_must_be_within_tree();
 
 
 
1050 file_canonical_name(g.zLocalRoot, &localRoot, 1);
1051 nLocalRoot = blob_size(&localRoot);
1052 zLocalRoot = blob_buffer(&localRoot);
1053 assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
1054 file_canonical_name(zOrigName, &full, 0);
@@ -1093,10 +1098,11 @@
1093 ** a boolean: "yes", "no", "true", "false", etc.
1094 */
1095 void cmd_test_tree_name(void){
1096 int i;
1097 Blob x;
 
1098 blob_zero(&x);
1099 capture_case_sensitive_option();
1100 for(i=2; i<g.argc; i++){
1101 if( file_tree_name(g.argv[i], &x, 1) ){
1102 fossil_print("%s\n", blob_buffer(&x));
1103
--- src/file.c
+++ src/file.c
@@ -977,10 +977,12 @@
977 for(j=i+1; zPwd[j]; j++){
978 if( zPwd[j]=='/' ){
979 blob_append(pOut, "/..", 3);
980 }
981 }
982 while( i>0 && (zPwd[i]!='/')) --i;
983 blob_append(pOut, zPath+i, j-i);
984 }
985 if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
986 blob_append(pOut, "/", 1);
987 }
988 blob_reset(&tmp);
@@ -1044,11 +1046,14 @@
1046 int nFull;
1047 char *zFull;
1048 int (*xCmp)(const char*,const char*,int);
1049
1050 blob_zero(pOut);
1051 if( !g.localOpen ){
1052 blob_appendf(pOut, "%s", zOrigName);
1053 return 1;
1054 }
1055 file_canonical_name(g.zLocalRoot, &localRoot, 1);
1056 nLocalRoot = blob_size(&localRoot);
1057 zLocalRoot = blob_buffer(&localRoot);
1058 assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
1059 file_canonical_name(zOrigName, &full, 0);
@@ -1093,10 +1098,11 @@
1098 ** a boolean: "yes", "no", "true", "false", etc.
1099 */
1100 void cmd_test_tree_name(void){
1101 int i;
1102 Blob x;
1103 db_find_and_open_repository(0,0);
1104 blob_zero(&x);
1105 capture_case_sensitive_option();
1106 for(i=2; i<g.argc; i++){
1107 if( file_tree_name(g.argv[i], &x, 1) ){
1108 fossil_print("%s\n", blob_buffer(&x));
1109
+7 -11
--- src/finfo.c
+++ src/finfo.c
@@ -151,11 +151,11 @@
151151
iWidth = zWidth ? atoi(zWidth) : 79;
152152
zOffset = find_option("offset",0,1);
153153
iOffset = zOffset ? atoi(zOffset) : 0;
154154
iBrief = (find_option("brief","b",0) == 0);
155155
if( (iWidth!=0) && (iWidth<=22) ){
156
- fossil_fatal("--width|-W value must be >22 or 0");
156
+ fossil_fatal("-W|--width value must be >22 or 0");
157157
}
158158
if( g.argc!=3 ){
159159
usage("?-l|--log? ?-b|--brief? FILENAME");
160160
}
161161
file_tree_name(g.argv[2], &fname, 1);
@@ -374,11 +374,11 @@
374374
}
375375
blob_reset(&sql);
376376
blob_zero(&title);
377377
if( baseCheckin ){
378378
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
379
- char *zLink = href("%R/info/%S", zUuid);
379
+ char *zLink = href("%R/info/%s", zUuid);
380380
blob_appendf(&title, "Ancestors of file ");
381381
hyperlinked_path(zFilename, &title, zUuid, "tree", "");
382382
blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid);
383383
fossil_free(zUuid);
384384
}else{
@@ -404,12 +404,10 @@
404404
const char *zBr = db_column_text(&q, 9);
405405
int fmid = db_column_int(&q, 10);
406406
int pfnid = db_column_int(&q, 11);
407407
int gidx;
408408
char zTime[10];
409
- char zShort[20];
410
- char zShortCkin[20];
411409
if( zBr==0 ) zBr = "trunk";
412410
if( uBg ){
413411
zBgClr = hash_color(zUser);
414412
}else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
415413
zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
@@ -430,12 +428,10 @@
430428
if( zBgClr && zBgClr[0] ){
431429
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
432430
}else{
433431
@ <td class="timelineTableCell">
434432
}
435
- sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
436
- sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
437433
if( zUuid ){
438434
if( fpid==0 ){
439435
@ <b>Added</b>
440436
}else if( pfnid ){
441437
char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
@@ -458,23 +454,23 @@
458454
fossil_free(zNewName);
459455
}else{
460456
@ <b>Deleted</b> by check-in
461457
}
462458
}
463
- hyperlink_to_uuid(zShortCkin);
459
+ hyperlink_to_uuid(zCkin);
464460
@ %w(zCom) (user:
465461
hyperlink_to_user(zUser, zDate, "");
466462
@ branch: %h(zBr))
467463
if( g.perm.Hyperlink && zUuid ){
468464
const char *z = zFilename;
469
- @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z))
465
+ @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
470466
@ [annotate]</a>
471
- @ %z(href("%R/blame?checkin=%S&filename=%h",zCkin,z))
467
+ @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
472468
@ [blame]</a>
473
- @ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins&nbsp;using]</a>
469
+ @ %z(href("%R/timeline?n=200&uf=%s",zUuid))[checkins&nbsp;using]</a>
474470
if( fpid ){
475
- @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zPUuid,zUuid))[diff]</a>
471
+ @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
476472
}
477473
}
478474
if( fDebug & FINFO_DEBUG_MLINK ){
479475
int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
480476
int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
481477
--- src/finfo.c
+++ src/finfo.c
@@ -151,11 +151,11 @@
151 iWidth = zWidth ? atoi(zWidth) : 79;
152 zOffset = find_option("offset",0,1);
153 iOffset = zOffset ? atoi(zOffset) : 0;
154 iBrief = (find_option("brief","b",0) == 0);
155 if( (iWidth!=0) && (iWidth<=22) ){
156 fossil_fatal("--width|-W value must be >22 or 0");
157 }
158 if( g.argc!=3 ){
159 usage("?-l|--log? ?-b|--brief? FILENAME");
160 }
161 file_tree_name(g.argv[2], &fname, 1);
@@ -374,11 +374,11 @@
374 }
375 blob_reset(&sql);
376 blob_zero(&title);
377 if( baseCheckin ){
378 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
379 char *zLink = href("%R/info/%S", zUuid);
380 blob_appendf(&title, "Ancestors of file ");
381 hyperlinked_path(zFilename, &title, zUuid, "tree", "");
382 blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid);
383 fossil_free(zUuid);
384 }else{
@@ -404,12 +404,10 @@
404 const char *zBr = db_column_text(&q, 9);
405 int fmid = db_column_int(&q, 10);
406 int pfnid = db_column_int(&q, 11);
407 int gidx;
408 char zTime[10];
409 char zShort[20];
410 char zShortCkin[20];
411 if( zBr==0 ) zBr = "trunk";
412 if( uBg ){
413 zBgClr = hash_color(zUser);
414 }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
415 zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
@@ -430,12 +428,10 @@
430 if( zBgClr && zBgClr[0] ){
431 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
432 }else{
433 @ <td class="timelineTableCell">
434 }
435 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
436 sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
437 if( zUuid ){
438 if( fpid==0 ){
439 @ <b>Added</b>
440 }else if( pfnid ){
441 char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
@@ -458,23 +454,23 @@
458 fossil_free(zNewName);
459 }else{
460 @ <b>Deleted</b> by check-in
461 }
462 }
463 hyperlink_to_uuid(zShortCkin);
464 @ %w(zCom) (user:
465 hyperlink_to_user(zUser, zDate, "");
466 @ branch: %h(zBr))
467 if( g.perm.Hyperlink && zUuid ){
468 const char *z = zFilename;
469 @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z))
470 @ [annotate]</a>
471 @ %z(href("%R/blame?checkin=%S&filename=%h",zCkin,z))
472 @ [blame]</a>
473 @ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins&nbsp;using]</a>
474 if( fpid ){
475 @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zPUuid,zUuid))[diff]</a>
476 }
477 }
478 if( fDebug & FINFO_DEBUG_MLINK ){
479 int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
480 int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
481
--- src/finfo.c
+++ src/finfo.c
@@ -151,11 +151,11 @@
151 iWidth = zWidth ? atoi(zWidth) : 79;
152 zOffset = find_option("offset",0,1);
153 iOffset = zOffset ? atoi(zOffset) : 0;
154 iBrief = (find_option("brief","b",0) == 0);
155 if( (iWidth!=0) && (iWidth<=22) ){
156 fossil_fatal("-W|--width value must be >22 or 0");
157 }
158 if( g.argc!=3 ){
159 usage("?-l|--log? ?-b|--brief? FILENAME");
160 }
161 file_tree_name(g.argv[2], &fname, 1);
@@ -374,11 +374,11 @@
374 }
375 blob_reset(&sql);
376 blob_zero(&title);
377 if( baseCheckin ){
378 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
379 char *zLink = href("%R/info/%s", zUuid);
380 blob_appendf(&title, "Ancestors of file ");
381 hyperlinked_path(zFilename, &title, zUuid, "tree", "");
382 blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid);
383 fossil_free(zUuid);
384 }else{
@@ -404,12 +404,10 @@
404 const char *zBr = db_column_text(&q, 9);
405 int fmid = db_column_int(&q, 10);
406 int pfnid = db_column_int(&q, 11);
407 int gidx;
408 char zTime[10];
 
 
409 if( zBr==0 ) zBr = "trunk";
410 if( uBg ){
411 zBgClr = hash_color(zUser);
412 }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
413 zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
@@ -430,12 +428,10 @@
428 if( zBgClr && zBgClr[0] ){
429 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
430 }else{
431 @ <td class="timelineTableCell">
432 }
 
 
433 if( zUuid ){
434 if( fpid==0 ){
435 @ <b>Added</b>
436 }else if( pfnid ){
437 char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
@@ -458,23 +454,23 @@
454 fossil_free(zNewName);
455 }else{
456 @ <b>Deleted</b> by check-in
457 }
458 }
459 hyperlink_to_uuid(zCkin);
460 @ %w(zCom) (user:
461 hyperlink_to_user(zUser, zDate, "");
462 @ branch: %h(zBr))
463 if( g.perm.Hyperlink && zUuid ){
464 const char *z = zFilename;
465 @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
466 @ [annotate]</a>
467 @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
468 @ [blame]</a>
469 @ %z(href("%R/timeline?n=200&uf=%s",zUuid))[checkins&nbsp;using]</a>
470 if( fpid ){
471 @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
472 }
473 }
474 if( fDebug & FINFO_DEBUG_MLINK ){
475 int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
476 int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
477
+31 -31
--- src/http.c
+++ src/http.c
@@ -55,31 +55,31 @@
5555
const char *zPw; /* The user password */
5656
Blob pw; /* The nonce with user password appended */
5757
Blob sig; /* The signature field */
5858
5959
blob_zero(pLogin);
60
- if( g.urlUser==0 || fossil_strcmp(g.urlUser, "anonymous")==0 ){
60
+ if( g.url.user==0 || fossil_strcmp(g.url.user, "anonymous")==0 ){
6161
return; /* If no login card for users "nobody" and "anonymous" */
6262
}
63
- if( g.urlIsSsh ){
63
+ if( g.url.isSsh ){
6464
return; /* If no login card for SSH: */
6565
}
6666
blob_zero(&nonce);
6767
blob_zero(&pw);
6868
sha1sum_blob(pPayload, &nonce);
6969
blob_copy(&pw, &nonce);
70
- zLogin = g.urlUser;
71
- if( g.urlPasswd ){
72
- zPw = g.urlPasswd;
70
+ zLogin = g.url.user;
71
+ if( g.url.passwd ){
72
+ zPw = g.url.passwd;
7373
}else if( g.cgiOutput ){
7474
/* Password failure while doing a sync from the web interface */
7575
cgi_printf("*** incorrect or missing password for user %h\n", zLogin);
7676
zPw = 0;
7777
}else{
7878
/* Password failure while doing a sync from the command-line interface */
7979
url_prompt_for_password();
80
- zPw = g.urlPasswd;
80
+ zPw = g.url.passwd;
8181
}
8282
8383
/* The login card wants the SHA1 hash of the password, so convert the
8484
** password to its SHA1 hash it it isn't already a SHA1 hash.
8585
*/
@@ -102,29 +102,29 @@
102102
static void http_build_header(Blob *pPayload, Blob *pHdr){
103103
int i;
104104
const char *zSep;
105105
106106
blob_zero(pHdr);
107
- i = strlen(g.urlPath);
108
- if( i>0 && g.urlPath[i-1]=='/' ){
107
+ i = strlen(g.url.path);
108
+ if( i>0 && g.url.path[i-1]=='/' ){
109109
zSep = "";
110110
}else{
111111
zSep = "/";
112112
}
113
- blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep);
114
- if( g.urlProxyAuth ){
115
- blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
113
+ blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.url.path, zSep);
114
+ if( g.url.proxyAuth ){
115
+ blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
116116
}
117117
if( g.zHttpAuth && g.zHttpAuth[0] ){
118118
const char *zCredentials = g.zHttpAuth;
119119
char *zEncoded = encode64(zCredentials, -1);
120120
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
121121
fossil_free(zEncoded);
122122
}
123
- blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
123
+ blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
124124
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
125
- if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
125
+ if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
126126
if( g.fHttpTrace ){
127127
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
128128
}else{
129129
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
130130
}
@@ -147,11 +147,11 @@
147147
** Prompt to save HTTP Basic Authorization information
148148
*/
149149
static int save_httpauth_prompt(void){
150150
Blob x;
151151
char c;
152
- if( (g.urlFlags & URL_REMEMBER)==0 ) return 0;
152
+ if( (g.url.flags & URL_REMEMBER)==0 ) return 0;
153153
prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
154154
c = blob_str(&x)[0];
155155
blob_reset(&x);
156156
return ( c!='n' && c!='N' );
157157
}
@@ -166,15 +166,15 @@
166166
char *zPw;
167167
char *zPrompt;
168168
char *zHttpAuth = 0;
169169
if( !isatty(fileno(stdin)) ) return 0;
170170
zPrompt = mprintf("\n%s authorization required by\n%s\n",
171
- g.urlIsHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.urlCanonical);
171
+ g.url.isHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.url.canonical);
172172
fossil_print(zPrompt);
173173
free(zPrompt);
174
- if ( g.urlUser && g.urlPasswd && use_fossil_creds_for_httpauth_prompt() ){
175
- zHttpAuth = mprintf("%s:%s", g.urlUser, g.urlPasswd);
174
+ if ( g.url.user && g.url.passwd && use_fossil_creds_for_httpauth_prompt() ){
175
+ zHttpAuth = mprintf("%s:%s", g.url.user, g.url.passwd);
176176
}else{
177177
prompt_user("Basic Authorization user: ", &x);
178178
zUser = mprintf("%b", &x);
179179
zPrompt = mprintf("HTTP password for %b: ", &x);
180180
blob_reset(&x);
@@ -213,12 +213,12 @@
213213
char *zLine; /* A single line of the reply header */
214214
int i; /* Loop counter */
215215
int isError = 0; /* True if the reply is an error message */
216216
int isCompressed = 1; /* True if the reply is compressed */
217217
218
- if( transport_open(GLOBAL_URL()) ){
219
- fossil_warning(transport_errmsg(GLOBAL_URL()));
218
+ if( transport_open(&g.url) ){
219
+ fossil_warning(transport_errmsg(&g.url));
220220
return 1;
221221
}
222222
223223
/* Construct the login card and prepare the complete payload */
224224
blob_zero(&login);
@@ -260,32 +260,32 @@
260260
}
261261
262262
/*
263263
** Send the request to the server.
264264
*/
265
- transport_send(GLOBAL_URL(), &hdr);
266
- transport_send(GLOBAL_URL(), &payload);
265
+ transport_send(&g.url, &hdr);
266
+ transport_send(&g.url, &payload);
267267
blob_reset(&hdr);
268268
blob_reset(&payload);
269
- transport_flip(GLOBAL_URL());
269
+ transport_flip(&g.url);
270270
271271
/*
272272
** Read and interpret the server reply
273273
*/
274274
closeConnection = 1;
275275
iLength = -1;
276
- while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
276
+ while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
277277
/* printf("[%s]\n", zLine); fflush(stdout); */
278278
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
279279
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
280280
if( rc==401 ){
281281
if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
282282
if( g.zHttpAuth ){
283283
if( g.zHttpAuth ) free(g.zHttpAuth);
284284
}
285285
g.zHttpAuth = prompt_for_httpauth_creds();
286
- transport_close(GLOBAL_URL());
286
+ transport_close(&g.url);
287287
return http_exchange(pSend, pReply, useLogin, maxRedirect);
288288
}
289289
}
290290
if( rc!=200 && rc!=302 ){
291291
int ii;
@@ -297,11 +297,11 @@
297297
if( iHttpVersion==0 ){
298298
closeConnection = 1;
299299
}else{
300300
closeConnection = 0;
301301
}
302
- }else if( g.urlIsSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
302
+ }else if( g.url.isSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
303303
if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
304304
if( rc!=200 && rc!=302 ){
305305
int ii;
306306
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
307307
while( zLine[ii]==' ' ) ii++;
@@ -337,11 +337,11 @@
337337
fossil_print("redirect to %s\n", &zLine[i]);
338338
url_parse(&zLine[i], 0);
339339
fSeenHttpAuth = 0;
340340
if( g.zHttpAuth ) free(g.zHttpAuth);
341341
g.zHttpAuth = get_httpauth();
342
- transport_close(GLOBAL_URL());
342
+ transport_close(&g.url);
343343
return http_exchange(pSend, pReply, useLogin, maxRedirect);
344344
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
345345
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
346346
isCompressed = 0;
347347
}else if( fossil_strnicmp(&zLine[14],
@@ -364,11 +364,11 @@
364364
/*
365365
** Extract the reply payload that follows the header
366366
*/
367367
blob_zero(pReply);
368368
blob_resize(pReply, iLength);
369
- iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
369
+ iLength = transport_receive(&g.url, blob_buffer(pReply), iLength);
370370
blob_resize(pReply, iLength);
371371
if( isError ){
372372
char *z;
373373
int i, j;
374374
z = blob_str(pReply);
@@ -391,20 +391,20 @@
391391
** connection from remaining open. The easiest fix for now is to
392392
** simply close and restart the connection for each round-trip.
393393
**
394394
** For SSH we will leave the connection open.
395395
*/
396
- if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
396
+ if( ! g.url.isSsh ) closeConnection = 1; /* FIX ME */
397397
if( closeConnection ){
398
- transport_close(GLOBAL_URL());
398
+ transport_close(&g.url);
399399
}else{
400
- transport_rewind(GLOBAL_URL());
400
+ transport_rewind(&g.url);
401401
}
402402
return 0;
403403
404404
/*
405405
** Jump to here if an error is seen.
406406
*/
407407
write_err:
408
- transport_close(GLOBAL_URL());
408
+ transport_close(&g.url);
409409
return 1;
410410
}
411411
--- src/http.c
+++ src/http.c
@@ -55,31 +55,31 @@
55 const char *zPw; /* The user password */
56 Blob pw; /* The nonce with user password appended */
57 Blob sig; /* The signature field */
58
59 blob_zero(pLogin);
60 if( g.urlUser==0 || fossil_strcmp(g.urlUser, "anonymous")==0 ){
61 return; /* If no login card for users "nobody" and "anonymous" */
62 }
63 if( g.urlIsSsh ){
64 return; /* If no login card for SSH: */
65 }
66 blob_zero(&nonce);
67 blob_zero(&pw);
68 sha1sum_blob(pPayload, &nonce);
69 blob_copy(&pw, &nonce);
70 zLogin = g.urlUser;
71 if( g.urlPasswd ){
72 zPw = g.urlPasswd;
73 }else if( g.cgiOutput ){
74 /* Password failure while doing a sync from the web interface */
75 cgi_printf("*** incorrect or missing password for user %h\n", zLogin);
76 zPw = 0;
77 }else{
78 /* Password failure while doing a sync from the command-line interface */
79 url_prompt_for_password();
80 zPw = g.urlPasswd;
81 }
82
83 /* The login card wants the SHA1 hash of the password, so convert the
84 ** password to its SHA1 hash it it isn't already a SHA1 hash.
85 */
@@ -102,29 +102,29 @@
102 static void http_build_header(Blob *pPayload, Blob *pHdr){
103 int i;
104 const char *zSep;
105
106 blob_zero(pHdr);
107 i = strlen(g.urlPath);
108 if( i>0 && g.urlPath[i-1]=='/' ){
109 zSep = "";
110 }else{
111 zSep = "/";
112 }
113 blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep);
114 if( g.urlProxyAuth ){
115 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
116 }
117 if( g.zHttpAuth && g.zHttpAuth[0] ){
118 const char *zCredentials = g.zHttpAuth;
119 char *zEncoded = encode64(zCredentials, -1);
120 blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
121 fossil_free(zEncoded);
122 }
123 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
124 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
125 if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
126 if( g.fHttpTrace ){
127 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
128 }else{
129 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
130 }
@@ -147,11 +147,11 @@
147 ** Prompt to save HTTP Basic Authorization information
148 */
149 static int save_httpauth_prompt(void){
150 Blob x;
151 char c;
152 if( (g.urlFlags & URL_REMEMBER)==0 ) return 0;
153 prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
154 c = blob_str(&x)[0];
155 blob_reset(&x);
156 return ( c!='n' && c!='N' );
157 }
@@ -166,15 +166,15 @@
166 char *zPw;
167 char *zPrompt;
168 char *zHttpAuth = 0;
169 if( !isatty(fileno(stdin)) ) return 0;
170 zPrompt = mprintf("\n%s authorization required by\n%s\n",
171 g.urlIsHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.urlCanonical);
172 fossil_print(zPrompt);
173 free(zPrompt);
174 if ( g.urlUser && g.urlPasswd && use_fossil_creds_for_httpauth_prompt() ){
175 zHttpAuth = mprintf("%s:%s", g.urlUser, g.urlPasswd);
176 }else{
177 prompt_user("Basic Authorization user: ", &x);
178 zUser = mprintf("%b", &x);
179 zPrompt = mprintf("HTTP password for %b: ", &x);
180 blob_reset(&x);
@@ -213,12 +213,12 @@
213 char *zLine; /* A single line of the reply header */
214 int i; /* Loop counter */
215 int isError = 0; /* True if the reply is an error message */
216 int isCompressed = 1; /* True if the reply is compressed */
217
218 if( transport_open(GLOBAL_URL()) ){
219 fossil_warning(transport_errmsg(GLOBAL_URL()));
220 return 1;
221 }
222
223 /* Construct the login card and prepare the complete payload */
224 blob_zero(&login);
@@ -260,32 +260,32 @@
260 }
261
262 /*
263 ** Send the request to the server.
264 */
265 transport_send(GLOBAL_URL(), &hdr);
266 transport_send(GLOBAL_URL(), &payload);
267 blob_reset(&hdr);
268 blob_reset(&payload);
269 transport_flip(GLOBAL_URL());
270
271 /*
272 ** Read and interpret the server reply
273 */
274 closeConnection = 1;
275 iLength = -1;
276 while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
277 /* printf("[%s]\n", zLine); fflush(stdout); */
278 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
279 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
280 if( rc==401 ){
281 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
282 if( g.zHttpAuth ){
283 if( g.zHttpAuth ) free(g.zHttpAuth);
284 }
285 g.zHttpAuth = prompt_for_httpauth_creds();
286 transport_close(GLOBAL_URL());
287 return http_exchange(pSend, pReply, useLogin, maxRedirect);
288 }
289 }
290 if( rc!=200 && rc!=302 ){
291 int ii;
@@ -297,11 +297,11 @@
297 if( iHttpVersion==0 ){
298 closeConnection = 1;
299 }else{
300 closeConnection = 0;
301 }
302 }else if( g.urlIsSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
303 if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
304 if( rc!=200 && rc!=302 ){
305 int ii;
306 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
307 while( zLine[ii]==' ' ) ii++;
@@ -337,11 +337,11 @@
337 fossil_print("redirect to %s\n", &zLine[i]);
338 url_parse(&zLine[i], 0);
339 fSeenHttpAuth = 0;
340 if( g.zHttpAuth ) free(g.zHttpAuth);
341 g.zHttpAuth = get_httpauth();
342 transport_close(GLOBAL_URL());
343 return http_exchange(pSend, pReply, useLogin, maxRedirect);
344 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
345 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
346 isCompressed = 0;
347 }else if( fossil_strnicmp(&zLine[14],
@@ -364,11 +364,11 @@
364 /*
365 ** Extract the reply payload that follows the header
366 */
367 blob_zero(pReply);
368 blob_resize(pReply, iLength);
369 iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
370 blob_resize(pReply, iLength);
371 if( isError ){
372 char *z;
373 int i, j;
374 z = blob_str(pReply);
@@ -391,20 +391,20 @@
391 ** connection from remaining open. The easiest fix for now is to
392 ** simply close and restart the connection for each round-trip.
393 **
394 ** For SSH we will leave the connection open.
395 */
396 if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
397 if( closeConnection ){
398 transport_close(GLOBAL_URL());
399 }else{
400 transport_rewind(GLOBAL_URL());
401 }
402 return 0;
403
404 /*
405 ** Jump to here if an error is seen.
406 */
407 write_err:
408 transport_close(GLOBAL_URL());
409 return 1;
410 }
411
--- src/http.c
+++ src/http.c
@@ -55,31 +55,31 @@
55 const char *zPw; /* The user password */
56 Blob pw; /* The nonce with user password appended */
57 Blob sig; /* The signature field */
58
59 blob_zero(pLogin);
60 if( g.url.user==0 || fossil_strcmp(g.url.user, "anonymous")==0 ){
61 return; /* If no login card for users "nobody" and "anonymous" */
62 }
63 if( g.url.isSsh ){
64 return; /* If no login card for SSH: */
65 }
66 blob_zero(&nonce);
67 blob_zero(&pw);
68 sha1sum_blob(pPayload, &nonce);
69 blob_copy(&pw, &nonce);
70 zLogin = g.url.user;
71 if( g.url.passwd ){
72 zPw = g.url.passwd;
73 }else if( g.cgiOutput ){
74 /* Password failure while doing a sync from the web interface */
75 cgi_printf("*** incorrect or missing password for user %h\n", zLogin);
76 zPw = 0;
77 }else{
78 /* Password failure while doing a sync from the command-line interface */
79 url_prompt_for_password();
80 zPw = g.url.passwd;
81 }
82
83 /* The login card wants the SHA1 hash of the password, so convert the
84 ** password to its SHA1 hash it it isn't already a SHA1 hash.
85 */
@@ -102,29 +102,29 @@
102 static void http_build_header(Blob *pPayload, Blob *pHdr){
103 int i;
104 const char *zSep;
105
106 blob_zero(pHdr);
107 i = strlen(g.url.path);
108 if( i>0 && g.url.path[i-1]=='/' ){
109 zSep = "";
110 }else{
111 zSep = "/";
112 }
113 blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.url.path, zSep);
114 if( g.url.proxyAuth ){
115 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
116 }
117 if( g.zHttpAuth && g.zHttpAuth[0] ){
118 const char *zCredentials = g.zHttpAuth;
119 char *zEncoded = encode64(zCredentials, -1);
120 blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
121 fossil_free(zEncoded);
122 }
123 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
124 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
125 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
126 if( g.fHttpTrace ){
127 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
128 }else{
129 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
130 }
@@ -147,11 +147,11 @@
147 ** Prompt to save HTTP Basic Authorization information
148 */
149 static int save_httpauth_prompt(void){
150 Blob x;
151 char c;
152 if( (g.url.flags & URL_REMEMBER)==0 ) return 0;
153 prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
154 c = blob_str(&x)[0];
155 blob_reset(&x);
156 return ( c!='n' && c!='N' );
157 }
@@ -166,15 +166,15 @@
166 char *zPw;
167 char *zPrompt;
168 char *zHttpAuth = 0;
169 if( !isatty(fileno(stdin)) ) return 0;
170 zPrompt = mprintf("\n%s authorization required by\n%s\n",
171 g.url.isHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.url.canonical);
172 fossil_print(zPrompt);
173 free(zPrompt);
174 if ( g.url.user && g.url.passwd && use_fossil_creds_for_httpauth_prompt() ){
175 zHttpAuth = mprintf("%s:%s", g.url.user, g.url.passwd);
176 }else{
177 prompt_user("Basic Authorization user: ", &x);
178 zUser = mprintf("%b", &x);
179 zPrompt = mprintf("HTTP password for %b: ", &x);
180 blob_reset(&x);
@@ -213,12 +213,12 @@
213 char *zLine; /* A single line of the reply header */
214 int i; /* Loop counter */
215 int isError = 0; /* True if the reply is an error message */
216 int isCompressed = 1; /* True if the reply is compressed */
217
218 if( transport_open(&g.url) ){
219 fossil_warning(transport_errmsg(&g.url));
220 return 1;
221 }
222
223 /* Construct the login card and prepare the complete payload */
224 blob_zero(&login);
@@ -260,32 +260,32 @@
260 }
261
262 /*
263 ** Send the request to the server.
264 */
265 transport_send(&g.url, &hdr);
266 transport_send(&g.url, &payload);
267 blob_reset(&hdr);
268 blob_reset(&payload);
269 transport_flip(&g.url);
270
271 /*
272 ** Read and interpret the server reply
273 */
274 closeConnection = 1;
275 iLength = -1;
276 while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
277 /* printf("[%s]\n", zLine); fflush(stdout); */
278 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
279 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
280 if( rc==401 ){
281 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
282 if( g.zHttpAuth ){
283 if( g.zHttpAuth ) free(g.zHttpAuth);
284 }
285 g.zHttpAuth = prompt_for_httpauth_creds();
286 transport_close(&g.url);
287 return http_exchange(pSend, pReply, useLogin, maxRedirect);
288 }
289 }
290 if( rc!=200 && rc!=302 ){
291 int ii;
@@ -297,11 +297,11 @@
297 if( iHttpVersion==0 ){
298 closeConnection = 1;
299 }else{
300 closeConnection = 0;
301 }
302 }else if( g.url.isSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
303 if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
304 if( rc!=200 && rc!=302 ){
305 int ii;
306 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
307 while( zLine[ii]==' ' ) ii++;
@@ -337,11 +337,11 @@
337 fossil_print("redirect to %s\n", &zLine[i]);
338 url_parse(&zLine[i], 0);
339 fSeenHttpAuth = 0;
340 if( g.zHttpAuth ) free(g.zHttpAuth);
341 g.zHttpAuth = get_httpauth();
342 transport_close(&g.url);
343 return http_exchange(pSend, pReply, useLogin, maxRedirect);
344 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
345 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
346 isCompressed = 0;
347 }else if( fossil_strnicmp(&zLine[14],
@@ -364,11 +364,11 @@
364 /*
365 ** Extract the reply payload that follows the header
366 */
367 blob_zero(pReply);
368 blob_resize(pReply, iLength);
369 iLength = transport_receive(&g.url, blob_buffer(pReply), iLength);
370 blob_resize(pReply, iLength);
371 if( isError ){
372 char *z;
373 int i, j;
374 z = blob_str(pReply);
@@ -391,20 +391,20 @@
391 ** connection from remaining open. The easiest fix for now is to
392 ** simply close and restart the connection for each round-trip.
393 **
394 ** For SSH we will leave the connection open.
395 */
396 if( ! g.url.isSsh ) closeConnection = 1; /* FIX ME */
397 if( closeConnection ){
398 transport_close(&g.url);
399 }else{
400 transport_rewind(&g.url);
401 }
402 return 0;
403
404 /*
405 ** Jump to here if an error is seen.
406 */
407 write_err:
408 transport_close(&g.url);
409 return 1;
410 }
411
--- src/http_socket.c
+++ src/http_socket.c
@@ -124,14 +124,14 @@
124124
}
125125
}
126126
127127
/*
128128
** Open a socket connection. The identify of the server is determined
129
-** by global variables that are set using url_parse():
129
+** by pUrlData
130130
**
131
-** g.urlName Name of the server. Ex: www.fossil-scm.org
132
-** g.urlPort TCP/IP port to use. Ex: 80
131
+** pUrlDAta->name Name of the server. Ex: www.fossil-scm.org
132
+** pUrlDAta->port TCP/IP port to use. Ex: 80
133133
**
134134
** Return the number of errors.
135135
*/
136136
int socket_open(UrlData *pUrlData){
137137
static struct sockaddr_in addr; /* The server address */
@@ -212,13 +212,14 @@
212212
}
213213
return total;
214214
}
215215
216216
/*
217
-** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
218
-** populated. For hostnames with more than one IP (or if overridden in
219
-** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
217
+** Attempt to resolve pUrlData->name to an IP address and setup g.zIpAddr
218
+** so rcvfrom gets populated. For hostnames with more than one IP (or
219
+** if overridden in ~/.ssh/config) the rcvfrom may not match the host
220
+** to which we connect.
220221
*/
221222
void socket_ssh_resolve_addr(UrlData *pUrlData){
222223
struct hostent *pHost; /* Used to make best effort for rcvfrom */
223224
struct sockaddr_in addr;
224225
225226
--- src/http_socket.c
+++ src/http_socket.c
@@ -124,14 +124,14 @@
124 }
125 }
126
127 /*
128 ** Open a socket connection. The identify of the server is determined
129 ** by global variables that are set using url_parse():
130 **
131 ** g.urlName Name of the server. Ex: www.fossil-scm.org
132 ** g.urlPort TCP/IP port to use. Ex: 80
133 **
134 ** Return the number of errors.
135 */
136 int socket_open(UrlData *pUrlData){
137 static struct sockaddr_in addr; /* The server address */
@@ -212,13 +212,14 @@
212 }
213 return total;
214 }
215
216 /*
217 ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
218 ** populated. For hostnames with more than one IP (or if overridden in
219 ** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
 
220 */
221 void socket_ssh_resolve_addr(UrlData *pUrlData){
222 struct hostent *pHost; /* Used to make best effort for rcvfrom */
223 struct sockaddr_in addr;
224
225
--- src/http_socket.c
+++ src/http_socket.c
@@ -124,14 +124,14 @@
124 }
125 }
126
127 /*
128 ** Open a socket connection. The identify of the server is determined
129 ** by pUrlData
130 **
131 ** pUrlDAta->name Name of the server. Ex: www.fossil-scm.org
132 ** pUrlDAta->port TCP/IP port to use. Ex: 80
133 **
134 ** Return the number of errors.
135 */
136 int socket_open(UrlData *pUrlData){
137 static struct sockaddr_in addr; /* The server address */
@@ -212,13 +212,14 @@
212 }
213 return total;
214 }
215
216 /*
217 ** Attempt to resolve pUrlData->name to an IP address and setup g.zIpAddr
218 ** so rcvfrom gets populated. For hostnames with more than one IP (or
219 ** if overridden in ~/.ssh/config) the rcvfrom may not match the host
220 ** to which we connect.
221 */
222 void socket_ssh_resolve_addr(UrlData *pUrlData){
223 struct hostent *pHost; /* Used to make best effort for rcvfrom */
224 struct sockaddr_in addr;
225
226
+8 -6
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -224,13 +224,13 @@
224224
return rc;
225225
}
226226
227227
/*
228228
** Open an SSL connection. The identify of the server is determined
229
-** by variables that are set using url_parse():
229
+** as follows:
230230
**
231
-** pUrlData->name Name of the server. Ex: www.fossil-scm.org
231
+** g.url.name Name of the server. Ex: www.fossil-scm.org
232232
** pUrlData->port TCP/IP port to use. Ex: 80
233233
**
234234
** Return the number of errors.
235235
*/
236236
int ssl_open(UrlData *pUrlData){
@@ -253,11 +253,11 @@
253253
254254
if( pUrlData->useProxy ){
255255
int rc;
256256
BIO *sBio;
257257
char *connStr;
258
- connStr = mprintf("%s:%d", g.urlName, pUrlData->port);
258
+ connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
259259
sBio = BIO_new_connect(connStr);
260260
free(connStr);
261261
if( BIO_do_connect(sBio)<=0 ){
262262
ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
263263
pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
@@ -417,26 +417,28 @@
417417
free(zHost);
418418
BIO_free(mem);
419419
}
420420
421421
/*
422
-** Get certificate for g.urlName from global config.
422
+** Get certificate for pUrlData->urlName from global config.
423423
** Return NULL if no certificate found.
424424
*/
425425
X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
426426
char *zHost, *zCert;
427427
BIO *mem;
428428
X509 *cert;
429429
430
- zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
430
+ zHost = mprintf("cert:%s",
431
+ pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
431432
zCert = db_get(zHost, NULL);
432433
free(zHost);
433434
if ( zCert==NULL )
434435
return NULL;
435436
436437
if ( pTrusted!=0 ){
437
- zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
438
+ zHost = mprintf("trusted:%s",
439
+ pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
438440
*pTrusted = db_get_int(zHost, 0);
439441
free(zHost);
440442
}
441443
442444
mem = BIO_new(BIO_s_mem());
443445
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -224,13 +224,13 @@
224 return rc;
225 }
226
227 /*
228 ** Open an SSL connection. The identify of the server is determined
229 ** by variables that are set using url_parse():
230 **
231 ** pUrlData->name Name of the server. Ex: www.fossil-scm.org
232 ** pUrlData->port TCP/IP port to use. Ex: 80
233 **
234 ** Return the number of errors.
235 */
236 int ssl_open(UrlData *pUrlData){
@@ -253,11 +253,11 @@
253
254 if( pUrlData->useProxy ){
255 int rc;
256 BIO *sBio;
257 char *connStr;
258 connStr = mprintf("%s:%d", g.urlName, pUrlData->port);
259 sBio = BIO_new_connect(connStr);
260 free(connStr);
261 if( BIO_do_connect(sBio)<=0 ){
262 ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
263 pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
@@ -417,26 +417,28 @@
417 free(zHost);
418 BIO_free(mem);
419 }
420
421 /*
422 ** Get certificate for g.urlName from global config.
423 ** Return NULL if no certificate found.
424 */
425 X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
426 char *zHost, *zCert;
427 BIO *mem;
428 X509 *cert;
429
430 zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
 
431 zCert = db_get(zHost, NULL);
432 free(zHost);
433 if ( zCert==NULL )
434 return NULL;
435
436 if ( pTrusted!=0 ){
437 zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
 
438 *pTrusted = db_get_int(zHost, 0);
439 free(zHost);
440 }
441
442 mem = BIO_new(BIO_s_mem());
443
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -224,13 +224,13 @@
224 return rc;
225 }
226
227 /*
228 ** Open an SSL connection. The identify of the server is determined
229 ** as follows:
230 **
231 ** g.url.name Name of the server. Ex: www.fossil-scm.org
232 ** pUrlData->port TCP/IP port to use. Ex: 80
233 **
234 ** Return the number of errors.
235 */
236 int ssl_open(UrlData *pUrlData){
@@ -253,11 +253,11 @@
253
254 if( pUrlData->useProxy ){
255 int rc;
256 BIO *sBio;
257 char *connStr;
258 connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
259 sBio = BIO_new_connect(connStr);
260 free(connStr);
261 if( BIO_do_connect(sBio)<=0 ){
262 ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
263 pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
@@ -417,26 +417,28 @@
417 free(zHost);
418 BIO_free(mem);
419 }
420
421 /*
422 ** Get certificate for pUrlData->urlName from global config.
423 ** Return NULL if no certificate found.
424 */
425 X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
426 char *zHost, *zCert;
427 BIO *mem;
428 X509 *cert;
429
430 zHost = mprintf("cert:%s",
431 pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
432 zCert = db_get(zHost, NULL);
433 free(zHost);
434 if ( zCert==NULL )
435 return NULL;
436
437 if ( pTrusted!=0 ){
438 zHost = mprintf("trusted:%s",
439 pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
440 *pTrusted = db_get_int(zHost, 0);
441 free(zHost);
442 }
443
444 mem = BIO_new(BIO_s_mem());
445
--- src/http_transport.c
+++ src/http_transport.c
@@ -138,15 +138,15 @@
138138
return sshPid==0;
139139
}
140140
141141
/*
142142
** Open a connection to the server. The server is defined by the following
143
-** global variables:
143
+** variables:
144144
**
145
-** g.urlName Name of the server. Ex: www.fossil-scm.org
146
-** g.urlPort TCP/IP port. Ex: 80
147
-** g.urlIsHttps Use TLS for the connection
145
+** pUrlData->name Name of the server. Ex: www.fossil-scm.org
146
+** pUrlData->port TCP/IP port. Ex: 80
147
+** pUrlData->isHttps Use TLS for the connection
148148
**
149149
** Return the number of errors.
150150
*/
151151
int transport_open(UrlData *pUrlData){
152152
int rc = 0;
153153
--- src/http_transport.c
+++ src/http_transport.c
@@ -138,15 +138,15 @@
138 return sshPid==0;
139 }
140
141 /*
142 ** Open a connection to the server. The server is defined by the following
143 ** global variables:
144 **
145 ** g.urlName Name of the server. Ex: www.fossil-scm.org
146 ** g.urlPort TCP/IP port. Ex: 80
147 ** g.urlIsHttps Use TLS for the connection
148 **
149 ** Return the number of errors.
150 */
151 int transport_open(UrlData *pUrlData){
152 int rc = 0;
153
--- src/http_transport.c
+++ src/http_transport.c
@@ -138,15 +138,15 @@
138 return sshPid==0;
139 }
140
141 /*
142 ** Open a connection to the server. The server is defined by the following
143 ** variables:
144 **
145 ** pUrlData->name Name of the server. Ex: www.fossil-scm.org
146 ** pUrlData->port TCP/IP port. Ex: 80
147 ** pUrlData->isHttps Use TLS for the connection
148 **
149 ** Return the number of errors.
150 */
151 int transport_open(UrlData *pUrlData){
152 int rc = 0;
153
+50 -38
--- src/info.c
+++ src/info.c
@@ -399,11 +399,11 @@
399399
}
400400
if( diffFlags ){
401401
append_diff(zOld, zNew, diffFlags, pRe);
402402
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
403403
@ &nbsp;&nbsp;
404
- @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
404
+ @ %z(href("%R/fdiff?v1=%s&v2=%s&sbs=1",zOld,zNew))[diff]</a>
405405
}
406406
}
407407
}
408408
409409
/*
@@ -612,19 +612,19 @@
612612
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
613613
zPJ[jj] = '_';
614614
}
615615
}
616616
@ <tr><th>Timelines:</th><td>
617
- @ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a>
617
+ @ %z(href("%R/timeline?f=%s&unhide",zUuid))family</a>
618618
if( zParent ){
619
- @ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a>
619
+ @ | %z(href("%R/timeline?p=%s&unhide",zUuid))ancestors</a>
620620
}
621621
if( !isLeaf ){
622
- @ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a>
622
+ @ | %z(href("%R/timeline?d=%s&unhide",zUuid))descendants</a>
623623
}
624624
if( zParent && !isLeaf ){
625
- @ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a>
625
+ @ | %z(href("%R/timeline?dp=%s&unhide",zUuid))both</a>
626626
}
627627
db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
628628
" WHERE rid=%d AND tagtype>0 "
629629
" AND tag.tagid=tagxref.tagid "
630630
" AND +tag.tagname GLOB 'sym-*'", rid);
@@ -647,16 +647,16 @@
647647
fossil_free(zUrl);
648648
}
649649
@ </td></tr>
650650
@ <tr><th>Other&nbsp;Links:</th>
651651
@ <td>
652
- @ %z(href("%R/tree?ci=%S",zUuid))files</a>
653
- @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a>
654
- @ | %z(href("%R/tree?ci=%S&nofiles",zUuid))folders</a>
655
- @ | %z(href("%R/artifact/%S",zUuid))manifest</a>
652
+ @ %z(href("%R/tree?ci=%s",zUuid))files</a>
653
+ @ | %z(href("%R/fileage?name=%s",zUuid))file ages</a>
654
+ @ | %z(href("%R/tree?ci=%s&nofiles",zUuid))folders</a>
655
+ @ | %z(href("%R/artifact/%s",zUuid))manifest</a>
656656
if( g.perm.Write ){
657
- @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
657
+ @ | %z(href("%R/ci_edit?r=%s",zUuid))edit</a>
658658
}
659659
@ </td>
660660
@ </tr>
661661
blob_reset(&projName);
662662
}
@@ -699,11 +699,11 @@
699699
@ Show&nbsp;Unified&nbsp;Diffs</a>
700700
@ %z(xhref("class='button'","%R/%s/%T?sbs=1",zPage,zName))
701701
@ Show&nbsp;Side-by-Side&nbsp;Diffs</a>
702702
}
703703
if( zParent ){
704
- @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid))
704
+ @ %z(xhref("class='button'","%R/vpatch?from=%s&to=%s",zParent,zUuid))
705705
@ Patch</a>
706706
}
707707
@</div>
708708
if( pRe ){
709709
@ <p><b>Only differences that match regular expression "%h(zRe)"
@@ -770,11 +770,11 @@
770770
}
771771
}
772772
style_header("Update of \"%h\"", pWiki->zWikiTitle);
773773
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
774774
zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
775
- style_submenu_element("Raw", "Raw", "artifact/%S", zUuid);
775
+ style_submenu_element("Raw", "Raw", "artifact/%s", zUuid);
776776
style_submenu_element("History", "History", "whistory?name=%t",
777777
pWiki->zWikiTitle);
778778
style_submenu_element("Page", "Page", "wiki?name=%t",
779779
pWiki->zWikiTitle);
780780
login_anonymous_available();
@@ -798,11 +798,11 @@
798798
if( pWiki->nParent>0 ){
799799
int i;
800800
@ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
801801
for(i=0; i<pWiki->nParent; i++){
802802
char *zParent = pWiki->azParent[i];
803
- @ %z(href("info/%S",zParent))%s(zParent)</a>
803
+ @ %z(href("info/%s",zParent))%s(zParent)</a>
804804
}
805805
@ </td></tr>
806806
}
807807
@ </table>
808808
@@ -1188,14 +1188,14 @@
11881188
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
11891189
}
11901190
@ - %!w(zCom) (user:
11911191
hyperlink_to_user(zUser,zDate,")");
11921192
if( g.perm.Hyperlink ){
1193
- @ %z(href("%R/finfo?name=%T&ci=%S",zName,zVers))[ancestry]</a>
1194
- @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
1193
+ @ %z(href("%R/finfo?name=%T&ci=%s",zName,zVers))[ancestry]</a>
1194
+ @ %z(href("%R/annotate?filename=%T&checkin=%s",zName,zVers))
11951195
@ [annotate]</a>
1196
- @ %z(href("%R/blame?checkin=%S&filename=%T",zVers,zName))
1196
+ @ %z(href("%R/blame?filename=%T&checkin=%s",zName,zVers))
11971197
@ [blame]</a>
11981198
}
11991199
cnt++;
12001200
if( pDownloadName && blob_size(pDownloadName)==0 ){
12011201
blob_append(pDownloadName, zName, -1);
@@ -1302,11 +1302,11 @@
13021302
@ Attachment "%h(zFilename)" to
13031303
}
13041304
objType |= OBJTYPE_ATTACHMENT;
13051305
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
13061306
if( g.perm.Hyperlink && g.perm.RdTkt ){
1307
- @ ticket [%z(href("%R/tktview?name=%S",zTarget))%S(zTarget)</a>]
1307
+ @ ticket [%z(href("%R/tktview?name=%s",zTarget))%S(zTarget)</a>]
13081308
}else{
13091309
@ ticket [%S(zTarget)]
13101310
}
13111311
}else{
13121312
if( g.perm.Hyperlink && g.perm.RdWiki ){
@@ -1328,11 +1328,11 @@
13281328
@ Control artifact.
13291329
if( pDownloadName && blob_size(pDownloadName)==0 ){
13301330
blob_appendf(pDownloadName, "%.10s.txt", zUuid);
13311331
}
13321332
}else if( linkToView && g.perm.Hyperlink ){
1333
- @ %z(href("%R/artifact/%S",zUuid))[view]</a>
1333
+ @ %z(href("%R/artifact/%s",zUuid))[view]</a>
13341334
}
13351335
return objType;
13361336
}
13371337
13381338
@@ -1404,17 +1404,17 @@
14041404
g.zTop, P("v1"), P("v2"), zW);
14051405
}
14061406
14071407
if( P("smhdr")!=0 ){
14081408
@ <h2>Differences From Artifact
1409
- @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1410
- @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1409
+ @ %z(href("%R/artifact/%s",zV1))[%S(zV1)]</a> To
1410
+ @ %z(href("%R/artifact/%s",zV2))[%S(zV2)]</a>.</h2>
14111411
}else{
14121412
@ <h2>Differences From
1413
- @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1413
+ @ Artifact %z(href("%R/artifact/%s",zV1))[%S(zV1)]</a>:</h2>
14141414
object_description(v1, 0, 0);
1415
- @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
1415
+ @ <h2>To Artifact %z(href("%R/artifact/%s",zV2))[%S(zV2)]</a>:</h2>
14161416
object_description(v2, 0, 0);
14171417
}
14181418
if( pRe ){
14191419
@ <b>Only differences that match regular expression "%h(zRe)"
14201420
@ are shown.</b>
@@ -1761,13 +1761,13 @@
17611761
@ <pre>
17621762
@ %h(z)
17631763
@ </pre>
17641764
}
17651765
}else if( strncmp(zMime, "image/", 6)==0 ){
1766
- @ <img src="%R/raw/%S(zUuid)?m=%s(zMime)" />
1766
+ @ <img src="%R/raw/%s(zUuid)?m=%s(zMime)" />
17671767
style_submenu_element("Image", "Image",
1768
- "%R/raw/%S?m=%s", zUuid, zMime);
1768
+ "%R/raw/%s?m=%s", zUuid, zMime);
17691769
}else{
17701770
@ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
17711771
}
17721772
@ </blockquote>
17731773
}
@@ -1819,19 +1819,19 @@
18191819
}
18201820
zTktTitle = db_table_has_column( "ticket", "title" )
18211821
? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
18221822
: 0;
18231823
style_header("Ticket Change Details");
1824
- style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1824
+ style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid);
18251825
style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
18261826
style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
18271827
style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
18281828
if( P("plaintext") ){
1829
- style_submenu_element("Formatted", "Formatted", "%R/info/%S", zUuid);
1829
+ style_submenu_element("Formatted", "Formatted", "%R/info/%s", zUuid);
18301830
}else{
18311831
style_submenu_element("Plaintext", "Plaintext",
1832
- "%R/info/%S?plaintext", zUuid);
1832
+ "%R/info/%s?plaintext", zUuid);
18331833
}
18341834
18351835
@ <div class="section">Overview</div>
18361836
@ <p><table class="label-value">
18371837
@ <tr><th>Artifact&nbsp;ID:</th>
@@ -1890,28 +1890,40 @@
18901890
void info_page(void){
18911891
const char *zName;
18921892
Blob uuid;
18931893
int rid;
18941894
int rc;
1895
+ int nLen;
18951896
18961897
zName = P("name");
18971898
if( zName==0 ) fossil_redirect_home();
1898
- if( validate16(zName, strlen(zName)) ){
1899
- if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
1900
- tktview_page();
1901
- return;
1902
- }
1903
- if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){
1904
- event_page();
1905
- return;
1906
- }
1907
- }
1899
+ nLen = strlen(zName);
19081900
blob_set(&uuid, zName);
1901
+ if( name_collisions(zName) ){
1902
+ cgi_set_parameter("src","info");
1903
+ ambiguous_page();
1904
+ return;
1905
+ }
19091906
rc = name_to_uuid(&uuid, -1, "*");
19101907
if( rc==1 ){
1908
+ if( validate16(zName, nLen) ){
1909
+ if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
1910
+ tktview_page();
1911
+ return;
1912
+ }
1913
+ if( db_exists("SELECT 1 FROM tag"
1914
+ " WHERE tagname GLOB 'event-%q*'", zName) ){
1915
+ event_page();
1916
+ return;
1917
+ }
1918
+ }
19111919
style_header("No Such Object");
19121920
@ <p>No such object: %h(zName)</p>
1921
+ if( nLen<4 ){
1922
+ @ <p>Object name should be no less than 4 characters. Ten or more
1923
+ @ characters are recommended.</p>
1924
+ }
19131925
style_footer();
19141926
return;
19151927
}else if( rc==2 ){
19161928
cgi_set_parameter("src","info");
19171929
ambiguous_page();
@@ -2341,11 +2353,11 @@
23412353
}
23422354
@ <p>Make changes to attributes of check-in
23432355
@ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
23442356
form_begin(0, "%R/ci_edit");
23452357
login_insert_csrf_secret();
2346
- @ <div><input type="hidden" name="r" value="%S(zUuid)" />
2358
+ @ <div><input type="hidden" name="r" value="%s(zUuid)" />
23472359
@ <table border="0" cellspacing="10">
23482360
23492361
@ <tr><th align="right" valign="top">User:</th>
23502362
@ <td valign="top">
23512363
@ <input type="text" name="u" size="20" value="%h(zNewUser)" />
23522364
--- src/info.c
+++ src/info.c
@@ -399,11 +399,11 @@
399 }
400 if( diffFlags ){
401 append_diff(zOld, zNew, diffFlags, pRe);
402 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
403 @ &nbsp;&nbsp;
404 @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
405 }
406 }
407 }
408
409 /*
@@ -612,19 +612,19 @@
612 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
613 zPJ[jj] = '_';
614 }
615 }
616 @ <tr><th>Timelines:</th><td>
617 @ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a>
618 if( zParent ){
619 @ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a>
620 }
621 if( !isLeaf ){
622 @ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a>
623 }
624 if( zParent && !isLeaf ){
625 @ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a>
626 }
627 db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
628 " WHERE rid=%d AND tagtype>0 "
629 " AND tag.tagid=tagxref.tagid "
630 " AND +tag.tagname GLOB 'sym-*'", rid);
@@ -647,16 +647,16 @@
647 fossil_free(zUrl);
648 }
649 @ </td></tr>
650 @ <tr><th>Other&nbsp;Links:</th>
651 @ <td>
652 @ %z(href("%R/tree?ci=%S",zUuid))files</a>
653 @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a>
654 @ | %z(href("%R/tree?ci=%S&nofiles",zUuid))folders</a>
655 @ | %z(href("%R/artifact/%S",zUuid))manifest</a>
656 if( g.perm.Write ){
657 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
658 }
659 @ </td>
660 @ </tr>
661 blob_reset(&projName);
662 }
@@ -699,11 +699,11 @@
699 @ Show&nbsp;Unified&nbsp;Diffs</a>
700 @ %z(xhref("class='button'","%R/%s/%T?sbs=1",zPage,zName))
701 @ Show&nbsp;Side-by-Side&nbsp;Diffs</a>
702 }
703 if( zParent ){
704 @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid))
705 @ Patch</a>
706 }
707 @</div>
708 if( pRe ){
709 @ <p><b>Only differences that match regular expression "%h(zRe)"
@@ -770,11 +770,11 @@
770 }
771 }
772 style_header("Update of \"%h\"", pWiki->zWikiTitle);
773 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
774 zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
775 style_submenu_element("Raw", "Raw", "artifact/%S", zUuid);
776 style_submenu_element("History", "History", "whistory?name=%t",
777 pWiki->zWikiTitle);
778 style_submenu_element("Page", "Page", "wiki?name=%t",
779 pWiki->zWikiTitle);
780 login_anonymous_available();
@@ -798,11 +798,11 @@
798 if( pWiki->nParent>0 ){
799 int i;
800 @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
801 for(i=0; i<pWiki->nParent; i++){
802 char *zParent = pWiki->azParent[i];
803 @ %z(href("info/%S",zParent))%s(zParent)</a>
804 }
805 @ </td></tr>
806 }
807 @ </table>
808
@@ -1188,14 +1188,14 @@
1188 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
1189 }
1190 @ - %!w(zCom) (user:
1191 hyperlink_to_user(zUser,zDate,")");
1192 if( g.perm.Hyperlink ){
1193 @ %z(href("%R/finfo?name=%T&ci=%S",zName,zVers))[ancestry]</a>
1194 @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
1195 @ [annotate]</a>
1196 @ %z(href("%R/blame?checkin=%S&filename=%T",zVers,zName))
1197 @ [blame]</a>
1198 }
1199 cnt++;
1200 if( pDownloadName && blob_size(pDownloadName)==0 ){
1201 blob_append(pDownloadName, zName, -1);
@@ -1302,11 +1302,11 @@
1302 @ Attachment "%h(zFilename)" to
1303 }
1304 objType |= OBJTYPE_ATTACHMENT;
1305 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1306 if( g.perm.Hyperlink && g.perm.RdTkt ){
1307 @ ticket [%z(href("%R/tktview?name=%S",zTarget))%S(zTarget)</a>]
1308 }else{
1309 @ ticket [%S(zTarget)]
1310 }
1311 }else{
1312 if( g.perm.Hyperlink && g.perm.RdWiki ){
@@ -1328,11 +1328,11 @@
1328 @ Control artifact.
1329 if( pDownloadName && blob_size(pDownloadName)==0 ){
1330 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1331 }
1332 }else if( linkToView && g.perm.Hyperlink ){
1333 @ %z(href("%R/artifact/%S",zUuid))[view]</a>
1334 }
1335 return objType;
1336 }
1337
1338
@@ -1404,17 +1404,17 @@
1404 g.zTop, P("v1"), P("v2"), zW);
1405 }
1406
1407 if( P("smhdr")!=0 ){
1408 @ <h2>Differences From Artifact
1409 @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1410 @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1411 }else{
1412 @ <h2>Differences From
1413 @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1414 object_description(v1, 0, 0);
1415 @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
1416 object_description(v2, 0, 0);
1417 }
1418 if( pRe ){
1419 @ <b>Only differences that match regular expression "%h(zRe)"
1420 @ are shown.</b>
@@ -1761,13 +1761,13 @@
1761 @ <pre>
1762 @ %h(z)
1763 @ </pre>
1764 }
1765 }else if( strncmp(zMime, "image/", 6)==0 ){
1766 @ <img src="%R/raw/%S(zUuid)?m=%s(zMime)" />
1767 style_submenu_element("Image", "Image",
1768 "%R/raw/%S?m=%s", zUuid, zMime);
1769 }else{
1770 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
1771 }
1772 @ </blockquote>
1773 }
@@ -1819,19 +1819,19 @@
1819 }
1820 zTktTitle = db_table_has_column( "ticket", "title" )
1821 ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1822 : 0;
1823 style_header("Ticket Change Details");
1824 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1825 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1826 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1827 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
1828 if( P("plaintext") ){
1829 style_submenu_element("Formatted", "Formatted", "%R/info/%S", zUuid);
1830 }else{
1831 style_submenu_element("Plaintext", "Plaintext",
1832 "%R/info/%S?plaintext", zUuid);
1833 }
1834
1835 @ <div class="section">Overview</div>
1836 @ <p><table class="label-value">
1837 @ <tr><th>Artifact&nbsp;ID:</th>
@@ -1890,28 +1890,40 @@
1890 void info_page(void){
1891 const char *zName;
1892 Blob uuid;
1893 int rid;
1894 int rc;
 
1895
1896 zName = P("name");
1897 if( zName==0 ) fossil_redirect_home();
1898 if( validate16(zName, strlen(zName)) ){
1899 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
1900 tktview_page();
1901 return;
1902 }
1903 if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){
1904 event_page();
1905 return;
1906 }
1907 }
1908 blob_set(&uuid, zName);
 
 
 
 
 
1909 rc = name_to_uuid(&uuid, -1, "*");
1910 if( rc==1 ){
 
 
 
 
 
 
 
 
 
 
 
1911 style_header("No Such Object");
1912 @ <p>No such object: %h(zName)</p>
 
 
 
 
1913 style_footer();
1914 return;
1915 }else if( rc==2 ){
1916 cgi_set_parameter("src","info");
1917 ambiguous_page();
@@ -2341,11 +2353,11 @@
2341 }
2342 @ <p>Make changes to attributes of check-in
2343 @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
2344 form_begin(0, "%R/ci_edit");
2345 login_insert_csrf_secret();
2346 @ <div><input type="hidden" name="r" value="%S(zUuid)" />
2347 @ <table border="0" cellspacing="10">
2348
2349 @ <tr><th align="right" valign="top">User:</th>
2350 @ <td valign="top">
2351 @ <input type="text" name="u" size="20" value="%h(zNewUser)" />
2352
--- src/info.c
+++ src/info.c
@@ -399,11 +399,11 @@
399 }
400 if( diffFlags ){
401 append_diff(zOld, zNew, diffFlags, pRe);
402 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
403 @ &nbsp;&nbsp;
404 @ %z(href("%R/fdiff?v1=%s&v2=%s&sbs=1",zOld,zNew))[diff]</a>
405 }
406 }
407 }
408
409 /*
@@ -612,19 +612,19 @@
612 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
613 zPJ[jj] = '_';
614 }
615 }
616 @ <tr><th>Timelines:</th><td>
617 @ %z(href("%R/timeline?f=%s&unhide",zUuid))family</a>
618 if( zParent ){
619 @ | %z(href("%R/timeline?p=%s&unhide",zUuid))ancestors</a>
620 }
621 if( !isLeaf ){
622 @ | %z(href("%R/timeline?d=%s&unhide",zUuid))descendants</a>
623 }
624 if( zParent && !isLeaf ){
625 @ | %z(href("%R/timeline?dp=%s&unhide",zUuid))both</a>
626 }
627 db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
628 " WHERE rid=%d AND tagtype>0 "
629 " AND tag.tagid=tagxref.tagid "
630 " AND +tag.tagname GLOB 'sym-*'", rid);
@@ -647,16 +647,16 @@
647 fossil_free(zUrl);
648 }
649 @ </td></tr>
650 @ <tr><th>Other&nbsp;Links:</th>
651 @ <td>
652 @ %z(href("%R/tree?ci=%s",zUuid))files</a>
653 @ | %z(href("%R/fileage?name=%s",zUuid))file ages</a>
654 @ | %z(href("%R/tree?ci=%s&nofiles",zUuid))folders</a>
655 @ | %z(href("%R/artifact/%s",zUuid))manifest</a>
656 if( g.perm.Write ){
657 @ | %z(href("%R/ci_edit?r=%s",zUuid))edit</a>
658 }
659 @ </td>
660 @ </tr>
661 blob_reset(&projName);
662 }
@@ -699,11 +699,11 @@
699 @ Show&nbsp;Unified&nbsp;Diffs</a>
700 @ %z(xhref("class='button'","%R/%s/%T?sbs=1",zPage,zName))
701 @ Show&nbsp;Side-by-Side&nbsp;Diffs</a>
702 }
703 if( zParent ){
704 @ %z(xhref("class='button'","%R/vpatch?from=%s&to=%s",zParent,zUuid))
705 @ Patch</a>
706 }
707 @</div>
708 if( pRe ){
709 @ <p><b>Only differences that match regular expression "%h(zRe)"
@@ -770,11 +770,11 @@
770 }
771 }
772 style_header("Update of \"%h\"", pWiki->zWikiTitle);
773 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
774 zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
775 style_submenu_element("Raw", "Raw", "artifact/%s", zUuid);
776 style_submenu_element("History", "History", "whistory?name=%t",
777 pWiki->zWikiTitle);
778 style_submenu_element("Page", "Page", "wiki?name=%t",
779 pWiki->zWikiTitle);
780 login_anonymous_available();
@@ -798,11 +798,11 @@
798 if( pWiki->nParent>0 ){
799 int i;
800 @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
801 for(i=0; i<pWiki->nParent; i++){
802 char *zParent = pWiki->azParent[i];
803 @ %z(href("info/%s",zParent))%s(zParent)</a>
804 }
805 @ </td></tr>
806 }
807 @ </table>
808
@@ -1188,14 +1188,14 @@
1188 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
1189 }
1190 @ - %!w(zCom) (user:
1191 hyperlink_to_user(zUser,zDate,")");
1192 if( g.perm.Hyperlink ){
1193 @ %z(href("%R/finfo?name=%T&ci=%s",zName,zVers))[ancestry]</a>
1194 @ %z(href("%R/annotate?filename=%T&checkin=%s",zName,zVers))
1195 @ [annotate]</a>
1196 @ %z(href("%R/blame?filename=%T&checkin=%s",zName,zVers))
1197 @ [blame]</a>
1198 }
1199 cnt++;
1200 if( pDownloadName && blob_size(pDownloadName)==0 ){
1201 blob_append(pDownloadName, zName, -1);
@@ -1302,11 +1302,11 @@
1302 @ Attachment "%h(zFilename)" to
1303 }
1304 objType |= OBJTYPE_ATTACHMENT;
1305 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1306 if( g.perm.Hyperlink && g.perm.RdTkt ){
1307 @ ticket [%z(href("%R/tktview?name=%s",zTarget))%S(zTarget)</a>]
1308 }else{
1309 @ ticket [%S(zTarget)]
1310 }
1311 }else{
1312 if( g.perm.Hyperlink && g.perm.RdWiki ){
@@ -1328,11 +1328,11 @@
1328 @ Control artifact.
1329 if( pDownloadName && blob_size(pDownloadName)==0 ){
1330 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1331 }
1332 }else if( linkToView && g.perm.Hyperlink ){
1333 @ %z(href("%R/artifact/%s",zUuid))[view]</a>
1334 }
1335 return objType;
1336 }
1337
1338
@@ -1404,17 +1404,17 @@
1404 g.zTop, P("v1"), P("v2"), zW);
1405 }
1406
1407 if( P("smhdr")!=0 ){
1408 @ <h2>Differences From Artifact
1409 @ %z(href("%R/artifact/%s",zV1))[%S(zV1)]</a> To
1410 @ %z(href("%R/artifact/%s",zV2))[%S(zV2)]</a>.</h2>
1411 }else{
1412 @ <h2>Differences From
1413 @ Artifact %z(href("%R/artifact/%s",zV1))[%S(zV1)]</a>:</h2>
1414 object_description(v1, 0, 0);
1415 @ <h2>To Artifact %z(href("%R/artifact/%s",zV2))[%S(zV2)]</a>:</h2>
1416 object_description(v2, 0, 0);
1417 }
1418 if( pRe ){
1419 @ <b>Only differences that match regular expression "%h(zRe)"
1420 @ are shown.</b>
@@ -1761,13 +1761,13 @@
1761 @ <pre>
1762 @ %h(z)
1763 @ </pre>
1764 }
1765 }else if( strncmp(zMime, "image/", 6)==0 ){
1766 @ <img src="%R/raw/%s(zUuid)?m=%s(zMime)" />
1767 style_submenu_element("Image", "Image",
1768 "%R/raw/%s?m=%s", zUuid, zMime);
1769 }else{
1770 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
1771 }
1772 @ </blockquote>
1773 }
@@ -1819,19 +1819,19 @@
1819 }
1820 zTktTitle = db_table_has_column( "ticket", "title" )
1821 ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1822 : 0;
1823 style_header("Ticket Change Details");
1824 style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid);
1825 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1826 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1827 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
1828 if( P("plaintext") ){
1829 style_submenu_element("Formatted", "Formatted", "%R/info/%s", zUuid);
1830 }else{
1831 style_submenu_element("Plaintext", "Plaintext",
1832 "%R/info/%s?plaintext", zUuid);
1833 }
1834
1835 @ <div class="section">Overview</div>
1836 @ <p><table class="label-value">
1837 @ <tr><th>Artifact&nbsp;ID:</th>
@@ -1890,28 +1890,40 @@
1890 void info_page(void){
1891 const char *zName;
1892 Blob uuid;
1893 int rid;
1894 int rc;
1895 int nLen;
1896
1897 zName = P("name");
1898 if( zName==0 ) fossil_redirect_home();
1899 nLen = strlen(zName);
 
 
 
 
 
 
 
 
 
1900 blob_set(&uuid, zName);
1901 if( name_collisions(zName) ){
1902 cgi_set_parameter("src","info");
1903 ambiguous_page();
1904 return;
1905 }
1906 rc = name_to_uuid(&uuid, -1, "*");
1907 if( rc==1 ){
1908 if( validate16(zName, nLen) ){
1909 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
1910 tktview_page();
1911 return;
1912 }
1913 if( db_exists("SELECT 1 FROM tag"
1914 " WHERE tagname GLOB 'event-%q*'", zName) ){
1915 event_page();
1916 return;
1917 }
1918 }
1919 style_header("No Such Object");
1920 @ <p>No such object: %h(zName)</p>
1921 if( nLen<4 ){
1922 @ <p>Object name should be no less than 4 characters. Ten or more
1923 @ characters are recommended.</p>
1924 }
1925 style_footer();
1926 return;
1927 }else if( rc==2 ){
1928 cgi_set_parameter("src","info");
1929 ambiguous_page();
@@ -2341,11 +2353,11 @@
2353 }
2354 @ <p>Make changes to attributes of check-in
2355 @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
2356 form_begin(0, "%R/ci_edit");
2357 login_insert_csrf_secret();
2358 @ <div><input type="hidden" name="r" value="%s(zUuid)" />
2359 @ <table border="0" cellspacing="10">
2360
2361 @ <tr><th align="right" valign="top">User:</th>
2362 @ <td valign="top">
2363 @ <input type="text" name="u" size="20" value="%h(zNewUser)" />
2364
+14 -14
--- src/json.c
+++ src/json.c
@@ -1275,15 +1275,15 @@
12751275
INT(g, xlinkClusterOnly);
12761276
INT(g, fTimeFormat);
12771277
INT(g, markPrivate);
12781278
INT(g, clockSkewSeen);
12791279
INT(g, isHTTP);
1280
- INT(g, urlIsFile);
1281
- INT(g, urlIsHttps);
1282
- INT(g, urlIsSsh);
1283
- INT(g, urlPort);
1284
- INT(g, urlDfltPort);
1280
+ INT(g.url, isFile);
1281
+ INT(g.url, isHttps);
1282
+ INT(g.url, isSsh);
1283
+ INT(g.url, port);
1284
+ INT(g.url, dfltPort);
12851285
INT(g, useLocalauth);
12861286
INT(g, noPswd);
12871287
INT(g, userUid);
12881288
INT(g, rcvid);
12891289
INT(g, okCsrf);
@@ -1299,19 +1299,19 @@
12991299
CSTR(g, zExtra);
13001300
CSTR(g, zBaseURL);
13011301
CSTR(g, zTop);
13021302
CSTR(g, zContentType);
13031303
CSTR(g, zErrMsg);
1304
- CSTR(g, urlName);
1305
- CSTR(g, urlHostname);
1306
- CSTR(g, urlProtocol);
1307
- CSTR(g, urlPath);
1308
- CSTR(g, urlUser);
1309
- CSTR(g, urlPasswd);
1310
- CSTR(g, urlCanonical);
1311
- CSTR(g, urlProxyAuth);
1312
- CSTR(g, urlFossil);
1304
+ CSTR(g.url, name);
1305
+ CSTR(g.url, hostname);
1306
+ CSTR(g.url, protocol);
1307
+ CSTR(g.url, path);
1308
+ CSTR(g.url, user);
1309
+ CSTR(g.url, passwd);
1310
+ CSTR(g.url, canonical);
1311
+ CSTR(g.url, proxyAuth);
1312
+ CSTR(g.url, fossil);
13131313
CSTR(g, zLogin);
13141314
CSTR(g, zSSLIdentity);
13151315
CSTR(g, zIpAddr);
13161316
CSTR(g, zNonce);
13171317
CSTR(g, zCsrfToken);
13181318
--- src/json.c
+++ src/json.c
@@ -1275,15 +1275,15 @@
1275 INT(g, xlinkClusterOnly);
1276 INT(g, fTimeFormat);
1277 INT(g, markPrivate);
1278 INT(g, clockSkewSeen);
1279 INT(g, isHTTP);
1280 INT(g, urlIsFile);
1281 INT(g, urlIsHttps);
1282 INT(g, urlIsSsh);
1283 INT(g, urlPort);
1284 INT(g, urlDfltPort);
1285 INT(g, useLocalauth);
1286 INT(g, noPswd);
1287 INT(g, userUid);
1288 INT(g, rcvid);
1289 INT(g, okCsrf);
@@ -1299,19 +1299,19 @@
1299 CSTR(g, zExtra);
1300 CSTR(g, zBaseURL);
1301 CSTR(g, zTop);
1302 CSTR(g, zContentType);
1303 CSTR(g, zErrMsg);
1304 CSTR(g, urlName);
1305 CSTR(g, urlHostname);
1306 CSTR(g, urlProtocol);
1307 CSTR(g, urlPath);
1308 CSTR(g, urlUser);
1309 CSTR(g, urlPasswd);
1310 CSTR(g, urlCanonical);
1311 CSTR(g, urlProxyAuth);
1312 CSTR(g, urlFossil);
1313 CSTR(g, zLogin);
1314 CSTR(g, zSSLIdentity);
1315 CSTR(g, zIpAddr);
1316 CSTR(g, zNonce);
1317 CSTR(g, zCsrfToken);
1318
--- src/json.c
+++ src/json.c
@@ -1275,15 +1275,15 @@
1275 INT(g, xlinkClusterOnly);
1276 INT(g, fTimeFormat);
1277 INT(g, markPrivate);
1278 INT(g, clockSkewSeen);
1279 INT(g, isHTTP);
1280 INT(g.url, isFile);
1281 INT(g.url, isHttps);
1282 INT(g.url, isSsh);
1283 INT(g.url, port);
1284 INT(g.url, dfltPort);
1285 INT(g, useLocalauth);
1286 INT(g, noPswd);
1287 INT(g, userUid);
1288 INT(g, rcvid);
1289 INT(g, okCsrf);
@@ -1299,19 +1299,19 @@
1299 CSTR(g, zExtra);
1300 CSTR(g, zBaseURL);
1301 CSTR(g, zTop);
1302 CSTR(g, zContentType);
1303 CSTR(g, zErrMsg);
1304 CSTR(g.url, name);
1305 CSTR(g.url, hostname);
1306 CSTR(g.url, protocol);
1307 CSTR(g.url, path);
1308 CSTR(g.url, user);
1309 CSTR(g.url, passwd);
1310 CSTR(g.url, canonical);
1311 CSTR(g.url, proxyAuth);
1312 CSTR(g.url, fossil);
1313 CSTR(g, zLogin);
1314 CSTR(g, zSSLIdentity);
1315 CSTR(g, zIpAddr);
1316 CSTR(g, zNonce);
1317 CSTR(g, zCsrfToken);
1318
+14 -6
--- src/login.c
+++ src/login.c
@@ -706,11 +706,11 @@
706706
zOtherRepo, &pOther,
707707
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
708708
g.zVfsName
709709
);
710710
if( rc==SQLITE_OK ){
711
- sqlite3_create_function(pOther,"now",0,SQLITE_ANY,0,db_now_function,0,0);
711
+ sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
712712
sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
713713
constant_time_cmp_function, 0, 0);
714714
sqlite3_busy_timeout(pOther, 5000);
715715
zSQL = mprintf(
716716
"SELECT cexpire FROM user"
@@ -737,10 +737,21 @@
737737
}
738738
sqlite3_close(pOther);
739739
fossil_free(zOtherRepo);
740740
return nXfer;
741741
}
742
+
743
+/*
744
+** Return TRUE if zLogin is one of the special usernames
745
+*/
746
+int login_is_special(const char *zLogin){
747
+ if( fossil_strcmp(zLogin, "anonymous")==0 ) return 1;
748
+ if( fossil_strcmp(zLogin, "nobody")==0 ) return 1;
749
+ if( fossil_strcmp(zLogin, "developer")==0 ) return 1;
750
+ if( fossil_strcmp(zLogin, "reader")==0 ) return 1;
751
+ return 0;
752
+}
742753
743754
/*
744755
** Lookup the uid for a non-built-in user with zLogin and zCookie and
745756
** zRemoteAddr. Return 0 if not found.
746757
**
@@ -752,14 +763,11 @@
752763
const char *zLogin, /* User name */
753764
const char *zCookie, /* Login cookie value */
754765
const char *zRemoteAddr /* Abbreviated IP address for valid login */
755766
){
756767
int uid;
757
- if( fossil_strcmp(zLogin, "anonymous")==0 ) return 0;
758
- if( fossil_strcmp(zLogin, "nobody")==0 ) return 0;
759
- if( fossil_strcmp(zLogin, "developer")==0 ) return 0;
760
- if( fossil_strcmp(zLogin, "reader")==0 ) return 0;
768
+ if( login_is_special(zLogin) ) return 0;
761769
uid = db_int(0,
762770
"SELECT uid FROM user"
763771
" WHERE login=%Q"
764772
" AND ipaddr=%Q"
765773
" AND cexpire>julianday('now')"
@@ -1409,11 +1417,11 @@
14091417
sqlite3_close(pPeer);
14101418
continue;
14111419
}
14121420
sqlite3_create_function(pPeer, "shared_secret", 3, SQLITE_UTF8,
14131421
0, sha1_shared_secret_sql_function, 0, 0);
1414
- sqlite3_create_function(pPeer, "now", 0,SQLITE_ANY,0,db_now_function,0,0);
1422
+ sqlite3_create_function(pPeer, "now", 0,SQLITE_UTF8,0,db_now_function,0,0);
14151423
sqlite3_busy_timeout(pPeer, 5000);
14161424
zErr = 0;
14171425
rc = sqlite3_exec(pPeer, zSql, 0, 0, &zErr);
14181426
if( zErr ){
14191427
blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName, zErr, zSuffix);
14201428
--- src/login.c
+++ src/login.c
@@ -706,11 +706,11 @@
706 zOtherRepo, &pOther,
707 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
708 g.zVfsName
709 );
710 if( rc==SQLITE_OK ){
711 sqlite3_create_function(pOther,"now",0,SQLITE_ANY,0,db_now_function,0,0);
712 sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
713 constant_time_cmp_function, 0, 0);
714 sqlite3_busy_timeout(pOther, 5000);
715 zSQL = mprintf(
716 "SELECT cexpire FROM user"
@@ -737,10 +737,21 @@
737 }
738 sqlite3_close(pOther);
739 fossil_free(zOtherRepo);
740 return nXfer;
741 }
 
 
 
 
 
 
 
 
 
 
 
742
743 /*
744 ** Lookup the uid for a non-built-in user with zLogin and zCookie and
745 ** zRemoteAddr. Return 0 if not found.
746 **
@@ -752,14 +763,11 @@
752 const char *zLogin, /* User name */
753 const char *zCookie, /* Login cookie value */
754 const char *zRemoteAddr /* Abbreviated IP address for valid login */
755 ){
756 int uid;
757 if( fossil_strcmp(zLogin, "anonymous")==0 ) return 0;
758 if( fossil_strcmp(zLogin, "nobody")==0 ) return 0;
759 if( fossil_strcmp(zLogin, "developer")==0 ) return 0;
760 if( fossil_strcmp(zLogin, "reader")==0 ) return 0;
761 uid = db_int(0,
762 "SELECT uid FROM user"
763 " WHERE login=%Q"
764 " AND ipaddr=%Q"
765 " AND cexpire>julianday('now')"
@@ -1409,11 +1417,11 @@
1409 sqlite3_close(pPeer);
1410 continue;
1411 }
1412 sqlite3_create_function(pPeer, "shared_secret", 3, SQLITE_UTF8,
1413 0, sha1_shared_secret_sql_function, 0, 0);
1414 sqlite3_create_function(pPeer, "now", 0,SQLITE_ANY,0,db_now_function,0,0);
1415 sqlite3_busy_timeout(pPeer, 5000);
1416 zErr = 0;
1417 rc = sqlite3_exec(pPeer, zSql, 0, 0, &zErr);
1418 if( zErr ){
1419 blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName, zErr, zSuffix);
1420
--- src/login.c
+++ src/login.c
@@ -706,11 +706,11 @@
706 zOtherRepo, &pOther,
707 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
708 g.zVfsName
709 );
710 if( rc==SQLITE_OK ){
711 sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
712 sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
713 constant_time_cmp_function, 0, 0);
714 sqlite3_busy_timeout(pOther, 5000);
715 zSQL = mprintf(
716 "SELECT cexpire FROM user"
@@ -737,10 +737,21 @@
737 }
738 sqlite3_close(pOther);
739 fossil_free(zOtherRepo);
740 return nXfer;
741 }
742
743 /*
744 ** Return TRUE if zLogin is one of the special usernames
745 */
746 int login_is_special(const char *zLogin){
747 if( fossil_strcmp(zLogin, "anonymous")==0 ) return 1;
748 if( fossil_strcmp(zLogin, "nobody")==0 ) return 1;
749 if( fossil_strcmp(zLogin, "developer")==0 ) return 1;
750 if( fossil_strcmp(zLogin, "reader")==0 ) return 1;
751 return 0;
752 }
753
754 /*
755 ** Lookup the uid for a non-built-in user with zLogin and zCookie and
756 ** zRemoteAddr. Return 0 if not found.
757 **
@@ -752,14 +763,11 @@
763 const char *zLogin, /* User name */
764 const char *zCookie, /* Login cookie value */
765 const char *zRemoteAddr /* Abbreviated IP address for valid login */
766 ){
767 int uid;
768 if( login_is_special(zLogin) ) return 0;
 
 
 
769 uid = db_int(0,
770 "SELECT uid FROM user"
771 " WHERE login=%Q"
772 " AND ipaddr=%Q"
773 " AND cexpire>julianday('now')"
@@ -1409,11 +1417,11 @@
1417 sqlite3_close(pPeer);
1418 continue;
1419 }
1420 sqlite3_create_function(pPeer, "shared_secret", 3, SQLITE_UTF8,
1421 0, sha1_shared_secret_sql_function, 0, 0);
1422 sqlite3_create_function(pPeer, "now", 0,SQLITE_UTF8,0,db_now_function,0,0);
1423 sqlite3_busy_timeout(pPeer, 5000);
1424 zErr = 0;
1425 rc = sqlite3_exec(pPeer, zSql, 0, 0, &zErr);
1426 if( zErr ){
1427 blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName, zErr, zSuffix);
1428
+5 -6
--- src/main.c
+++ src/main.c
@@ -112,15 +112,10 @@
112112
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
113113
void *pPostContext; /* Optional, provided to xPostEval(). */
114114
};
115115
#endif
116116
117
-/*
118
-** All global variables are in this structure.
119
-*/
120
-#define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
121
-
122117
struct Global {
123118
int argc; char **argv; /* Command-line arguments to the program */
124119
char *nameOfExe; /* Full path of executable. */
125120
const char *zErrlog; /* Log errors to this file, if not NULL */
126121
int isConst; /* True if the output is unchanging & cacheable */
@@ -171,11 +166,12 @@
171166
int clockSkewSeen; /* True if clocks on client and server out of sync */
172167
int wikiFlags; /* Wiki conversion flags applied to %w and %W */
173168
char isHTTP; /* True if server/CGI modes, else assume CLI. */
174169
char javascriptHyperlink; /* If true, set href= using script, not HTML */
175170
Blob httpHeader; /* Complete text of the HTTP request header */
176
-
171
+ UrlData url; /* Information about current URL */
172
+#if 0
177173
/*
178174
** NOTE: These members MUST be kept in sync with those in the "UrlData"
179175
** structure defined in "url.c".
180176
*/
181177
int urlIsFile; /* True if a "file:" url */
@@ -194,10 +190,12 @@
194190
char *urlFossil; /* The fossil query parameter on ssh: */
195191
unsigned urlFlags; /* Boolean flags controlling URL processing */
196192
int useProxy; /* Used to remember that a proxy is in use */
197193
char *proxyUrlPath;
198194
int proxyOrigPort; /* Tunneled port number for https through proxy */
195
+#endif
196
+
199197
const char *zLogin; /* Login name. NULL or "" if not logged in. */
200198
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
201199
** SSL client identity */
202200
int useLocalauth; /* No login required if from 127.0.0.1 */
203201
int noPswd; /* Logged in without password (on 127.0.0.1) */
@@ -1844,10 +1842,11 @@
18441842
18451843
/*
18461844
** Process all requests in a single SSH connection if possible.
18471845
*/
18481846
void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
1847
+ blob_zero(&g.cgiIn);
18491848
do{
18501849
cgi_handle_ssh_http_request(zIpAddr);
18511850
process_one_web_page(0, FileGlob);
18521851
blob_reset(&g.cgiIn);
18531852
} while ( g.fSshClient & CGI_SSH_FOSSIL ||
18541853
--- src/main.c
+++ src/main.c
@@ -112,15 +112,10 @@
112 void *xPostEval; /* Optional, called after Tcl_Eval*(). */
113 void *pPostContext; /* Optional, provided to xPostEval(). */
114 };
115 #endif
116
117 /*
118 ** All global variables are in this structure.
119 */
120 #define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
121
122 struct Global {
123 int argc; char **argv; /* Command-line arguments to the program */
124 char *nameOfExe; /* Full path of executable. */
125 const char *zErrlog; /* Log errors to this file, if not NULL */
126 int isConst; /* True if the output is unchanging & cacheable */
@@ -171,11 +166,12 @@
171 int clockSkewSeen; /* True if clocks on client and server out of sync */
172 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
173 char isHTTP; /* True if server/CGI modes, else assume CLI. */
174 char javascriptHyperlink; /* If true, set href= using script, not HTML */
175 Blob httpHeader; /* Complete text of the HTTP request header */
176
 
177 /*
178 ** NOTE: These members MUST be kept in sync with those in the "UrlData"
179 ** structure defined in "url.c".
180 */
181 int urlIsFile; /* True if a "file:" url */
@@ -194,10 +190,12 @@
194 char *urlFossil; /* The fossil query parameter on ssh: */
195 unsigned urlFlags; /* Boolean flags controlling URL processing */
196 int useProxy; /* Used to remember that a proxy is in use */
197 char *proxyUrlPath;
198 int proxyOrigPort; /* Tunneled port number for https through proxy */
 
 
199 const char *zLogin; /* Login name. NULL or "" if not logged in. */
200 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
201 ** SSL client identity */
202 int useLocalauth; /* No login required if from 127.0.0.1 */
203 int noPswd; /* Logged in without password (on 127.0.0.1) */
@@ -1844,10 +1842,11 @@
1844
1845 /*
1846 ** Process all requests in a single SSH connection if possible.
1847 */
1848 void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
 
1849 do{
1850 cgi_handle_ssh_http_request(zIpAddr);
1851 process_one_web_page(0, FileGlob);
1852 blob_reset(&g.cgiIn);
1853 } while ( g.fSshClient & CGI_SSH_FOSSIL ||
1854
--- src/main.c
+++ src/main.c
@@ -112,15 +112,10 @@
112 void *xPostEval; /* Optional, called after Tcl_Eval*(). */
113 void *pPostContext; /* Optional, provided to xPostEval(). */
114 };
115 #endif
116
 
 
 
 
 
117 struct Global {
118 int argc; char **argv; /* Command-line arguments to the program */
119 char *nameOfExe; /* Full path of executable. */
120 const char *zErrlog; /* Log errors to this file, if not NULL */
121 int isConst; /* True if the output is unchanging & cacheable */
@@ -171,11 +166,12 @@
166 int clockSkewSeen; /* True if clocks on client and server out of sync */
167 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
168 char isHTTP; /* True if server/CGI modes, else assume CLI. */
169 char javascriptHyperlink; /* If true, set href= using script, not HTML */
170 Blob httpHeader; /* Complete text of the HTTP request header */
171 UrlData url; /* Information about current URL */
172 #if 0
173 /*
174 ** NOTE: These members MUST be kept in sync with those in the "UrlData"
175 ** structure defined in "url.c".
176 */
177 int urlIsFile; /* True if a "file:" url */
@@ -194,10 +190,12 @@
190 char *urlFossil; /* The fossil query parameter on ssh: */
191 unsigned urlFlags; /* Boolean flags controlling URL processing */
192 int useProxy; /* Used to remember that a proxy is in use */
193 char *proxyUrlPath;
194 int proxyOrigPort; /* Tunneled port number for https through proxy */
195 #endif
196
197 const char *zLogin; /* Login name. NULL or "" if not logged in. */
198 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
199 ** SSL client identity */
200 int useLocalauth; /* No login required if from 127.0.0.1 */
201 int noPswd; /* Logged in without password (on 127.0.0.1) */
@@ -1844,10 +1842,11 @@
1842
1843 /*
1844 ** Process all requests in a single SSH connection if possible.
1845 */
1846 void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
1847 blob_zero(&g.cgiIn);
1848 do{
1849 cgi_handle_ssh_http_request(zIpAddr);
1850 process_one_web_page(0, FileGlob);
1851 blob_reset(&g.cgiIn);
1852 } while ( g.fSshClient & CGI_SSH_FOSSIL ||
1853
+1 -8
--- src/main.mk
+++ src/main.mk
@@ -400,18 +400,11 @@
400400
# using -lsqlite3.
401401
SQLITE3_OBJ.1 =
402402
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
403403
SQLITE3_OBJ. = $(SQLITE3_OBJ.0)
404404
405
-# The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
406
-# If it is set to 1, then we need to build the Tcl integration code and
407
-# link to the Tcl library.
408
-TCL_OBJ.0 =
409
-TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
410
-TCL_OBJ. = $(TCL_OBJ.0)
411
-
412
-EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o
405
+EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o
413406
414407
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
415408
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
416409
417410
# This rule prevents make from using its default rules to try build
418411
--- src/main.mk
+++ src/main.mk
@@ -400,18 +400,11 @@
400 # using -lsqlite3.
401 SQLITE3_OBJ.1 =
402 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
403 SQLITE3_OBJ. = $(SQLITE3_OBJ.0)
404
405 # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
406 # If it is set to 1, then we need to build the Tcl integration code and
407 # link to the Tcl library.
408 TCL_OBJ.0 =
409 TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
410 TCL_OBJ. = $(TCL_OBJ.0)
411
412 EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o
413
414 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
415 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
416
417 # This rule prevents make from using its default rules to try build
418
--- src/main.mk
+++ src/main.mk
@@ -400,18 +400,11 @@
400 # using -lsqlite3.
401 SQLITE3_OBJ.1 =
402 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
403 SQLITE3_OBJ. = $(SQLITE3_OBJ.0)
404
405 EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o
 
 
 
 
 
 
 
406
407 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
408 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
409
410 # This rule prevents make from using its default rules to try build
411
+9 -29
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -268,23 +268,16 @@
268268
# using -lsqlite3.
269269
SQLITE3_OBJ.1 =
270270
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
271271
SQLITE3_OBJ. = $(SQLITE3_OBJ.0)
272272
273
-# The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
274
-# If it is set to 1, then we need to build the Tcl integration code and
275
-# link to the Tcl library.
276
-TCL_OBJ.0 =
277
-TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
278
-TCL_OBJ. = $(TCL_OBJ.0)
279
-
280273
EXTRAOBJ = \
281274
$(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
282275
$(OBJDIR)/shell.o \
283276
$(OBJDIR)/th.o \
284277
$(OBJDIR)/th_lang.o \
285
- $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \
278
+ $(OBJDIR)/th_tcl.o \
286279
$(OBJDIR)/cson_amalgamation.o
287280
288281
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
289282
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
290283
@@ -451,12 +444,12 @@
451444
#### The directories where the OpenSSL include and library files are located.
452445
# The recommended usage here is to use the Sysinternals junction tool
453446
# to create a hard link between an "openssl-1.x" sub-directory of the
454447
# Fossil source code directory and the target OpenSSL source directory.
455448
#
456
-OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include
457
-OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f
449
+OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include
450
+OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g
458451
459452
#### Either the directory where the Tcl library is installed or the Tcl
460453
# source code directory resides (depending on the value of the macro
461454
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
462455
# this directory must have "include" and "lib" sub-directories. If
@@ -724,16 +717,13 @@
724717
EXTRAOBJ = \
725718
$(OBJDIR)/sqlite3.o \
726719
$(OBJDIR)/shell.o \
727720
$(OBJDIR)/th.o \
728721
$(OBJDIR)/th_lang.o \
722
+ $(OBJDIR)/th_tcl.o \
729723
$(OBJDIR)/cson_amalgamation.o
730724
731
-ifdef FOSSIL_ENABLE_TCL
732
-EXTRAOBJ += $(OBJDIR)/th_tcl.o
733
-endif
734
-
735725
zlib:
736726
$(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
737727
738728
clean-zlib:
739729
$(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean
@@ -824,14 +814,12 @@
824814
writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
825815
826816
writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
827817
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
828818
829
-writeln {ifdef FOSSIL_ENABLE_TCL
830
-$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
831
- $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
832
-endif}
819
+writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
820
+writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
833821
834822
close $output_file
835823
#
836824
# End of the win/Makefile.mingw output
837825
##############################################################################
@@ -1024,12 +1012,12 @@
10241012
10251013
# Uncomment to enable Tcl support
10261014
# FOSSIL_ENABLE_TCL = 1
10271015
10281016
!ifdef FOSSIL_ENABLE_SSL
1029
-SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
1030
-SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
1017
+SSLINCDIR = $(B)\compat\openssl-1.0.1g\include
1018
+SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32
10311019
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
10321020
!endif
10331021
10341022
!ifdef FOSSIL_ENABLE_TCL
10351023
TCLDIR = $(B)\compat\tcl-8.6
@@ -1107,11 +1095,11 @@
11071095
writeln -nonewline " "
11081096
}
11091097
writeln -nonewline "${s}_.c"; incr i
11101098
}
11111099
writeln "\n"
1112
-set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation]
1100
+set AdditionalObj [list shell sqlite3 th th_lang th_tcl cson_amalgamation]
11131101
writeln -nonewline "OBJ = "
11141102
set i 0
11151103
foreach s [lsort [concat $src $AdditionalObj]] {
11161104
if {$i > 0} {
11171105
writeln " \\"
@@ -1119,13 +1107,10 @@
11191107
}
11201108
writeln -nonewline "\$(OX)\\$s\$O"; incr i
11211109
}
11221110
writeln " \\"
11231111
writeln -nonewline " \$(OX)\\fossil.res\n\n"
1124
-writeln "!ifdef FOSSIL_ENABLE_TCL"
1125
-writeln "OBJ = \$(OBJ) \$(OX)\\th_tcl\$O"
1126
-writeln "!endif"
11271112
writeln {
11281113
APPNAME = $(OX)\fossil$(E)
11291114
PDBNAME = $(OX)\fossil$(P)
11301115
11311116
all: $(OX) $(APPNAME)
@@ -1142,14 +1127,11 @@
11421127
set redir {>}
11431128
foreach s [lsort [concat $src $AdditionalObj]] {
11441129
writeln "\techo \$(OX)\\$s.obj $redir \$@"
11451130
set redir {>>}
11461131
}
1147
-writeln "!ifdef FOSSIL_ENABLE_TCL"
1148
-writeln "\techo \$(OX)\\th_tcl.obj $redir \$@"
11491132
set redir {>>}
1150
-writeln "!endif"
11511133
writeln "\techo \$(LIBS) $redir \$@"
11521134
writeln {
11531135
$(OX):
11541136
@-mkdir $@
11551137
@@ -1175,14 +1157,12 @@
11751157
$(TCC) /Fo$@ -c $**
11761158
11771159
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
11781160
$(TCC) /Fo$@ -c $**
11791161
1180
-!ifdef FOSSIL_ENABLE_TCL
11811162
$(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
11821163
$(TCC) /Fo$@ -c $**
1183
-!endif
11841164
11851165
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
11861166
$** > $@
11871167
$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
11881168
$(TCC) /Fo$@ /c $**
11891169
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -268,23 +268,16 @@
268 # using -lsqlite3.
269 SQLITE3_OBJ.1 =
270 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
271 SQLITE3_OBJ. = $(SQLITE3_OBJ.0)
272
273 # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
274 # If it is set to 1, then we need to build the Tcl integration code and
275 # link to the Tcl library.
276 TCL_OBJ.0 =
277 TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
278 TCL_OBJ. = $(TCL_OBJ.0)
279
280 EXTRAOBJ = \
281 $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
282 $(OBJDIR)/shell.o \
283 $(OBJDIR)/th.o \
284 $(OBJDIR)/th_lang.o \
285 $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \
286 $(OBJDIR)/cson_amalgamation.o
287
288 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
289 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
290
@@ -451,12 +444,12 @@
451 #### The directories where the OpenSSL include and library files are located.
452 # The recommended usage here is to use the Sysinternals junction tool
453 # to create a hard link between an "openssl-1.x" sub-directory of the
454 # Fossil source code directory and the target OpenSSL source directory.
455 #
456 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include
457 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f
458
459 #### Either the directory where the Tcl library is installed or the Tcl
460 # source code directory resides (depending on the value of the macro
461 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
462 # this directory must have "include" and "lib" sub-directories. If
@@ -724,16 +717,13 @@
724 EXTRAOBJ = \
725 $(OBJDIR)/sqlite3.o \
726 $(OBJDIR)/shell.o \
727 $(OBJDIR)/th.o \
728 $(OBJDIR)/th_lang.o \
 
729 $(OBJDIR)/cson_amalgamation.o
730
731 ifdef FOSSIL_ENABLE_TCL
732 EXTRAOBJ += $(OBJDIR)/th_tcl.o
733 endif
734
735 zlib:
736 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
737
738 clean-zlib:
739 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean
@@ -824,14 +814,12 @@
824 writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
825
826 writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
827 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
828
829 writeln {ifdef FOSSIL_ENABLE_TCL
830 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
831 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
832 endif}
833
834 close $output_file
835 #
836 # End of the win/Makefile.mingw output
837 ##############################################################################
@@ -1024,12 +1012,12 @@
1024
1025 # Uncomment to enable Tcl support
1026 # FOSSIL_ENABLE_TCL = 1
1027
1028 !ifdef FOSSIL_ENABLE_SSL
1029 SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
1030 SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
1031 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
1032 !endif
1033
1034 !ifdef FOSSIL_ENABLE_TCL
1035 TCLDIR = $(B)\compat\tcl-8.6
@@ -1107,11 +1095,11 @@
1107 writeln -nonewline " "
1108 }
1109 writeln -nonewline "${s}_.c"; incr i
1110 }
1111 writeln "\n"
1112 set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation]
1113 writeln -nonewline "OBJ = "
1114 set i 0
1115 foreach s [lsort [concat $src $AdditionalObj]] {
1116 if {$i > 0} {
1117 writeln " \\"
@@ -1119,13 +1107,10 @@
1119 }
1120 writeln -nonewline "\$(OX)\\$s\$O"; incr i
1121 }
1122 writeln " \\"
1123 writeln -nonewline " \$(OX)\\fossil.res\n\n"
1124 writeln "!ifdef FOSSIL_ENABLE_TCL"
1125 writeln "OBJ = \$(OBJ) \$(OX)\\th_tcl\$O"
1126 writeln "!endif"
1127 writeln {
1128 APPNAME = $(OX)\fossil$(E)
1129 PDBNAME = $(OX)\fossil$(P)
1130
1131 all: $(OX) $(APPNAME)
@@ -1142,14 +1127,11 @@
1142 set redir {>}
1143 foreach s [lsort [concat $src $AdditionalObj]] {
1144 writeln "\techo \$(OX)\\$s.obj $redir \$@"
1145 set redir {>>}
1146 }
1147 writeln "!ifdef FOSSIL_ENABLE_TCL"
1148 writeln "\techo \$(OX)\\th_tcl.obj $redir \$@"
1149 set redir {>>}
1150 writeln "!endif"
1151 writeln "\techo \$(LIBS) $redir \$@"
1152 writeln {
1153 $(OX):
1154 @-mkdir $@
1155
@@ -1175,14 +1157,12 @@
1175 $(TCC) /Fo$@ -c $**
1176
1177 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
1178 $(TCC) /Fo$@ -c $**
1179
1180 !ifdef FOSSIL_ENABLE_TCL
1181 $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
1182 $(TCC) /Fo$@ -c $**
1183 !endif
1184
1185 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
1186 $** > $@
1187 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
1188 $(TCC) /Fo$@ /c $**
1189
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -268,23 +268,16 @@
268 # using -lsqlite3.
269 SQLITE3_OBJ.1 =
270 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
271 SQLITE3_OBJ. = $(SQLITE3_OBJ.0)
272
 
 
 
 
 
 
 
273 EXTRAOBJ = \
274 $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
275 $(OBJDIR)/shell.o \
276 $(OBJDIR)/th.o \
277 $(OBJDIR)/th_lang.o \
278 $(OBJDIR)/th_tcl.o \
279 $(OBJDIR)/cson_amalgamation.o
280
281 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
282 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
283
@@ -451,12 +444,12 @@
444 #### The directories where the OpenSSL include and library files are located.
445 # The recommended usage here is to use the Sysinternals junction tool
446 # to create a hard link between an "openssl-1.x" sub-directory of the
447 # Fossil source code directory and the target OpenSSL source directory.
448 #
449 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include
450 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g
451
452 #### Either the directory where the Tcl library is installed or the Tcl
453 # source code directory resides (depending on the value of the macro
454 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
455 # this directory must have "include" and "lib" sub-directories. If
@@ -724,16 +717,13 @@
717 EXTRAOBJ = \
718 $(OBJDIR)/sqlite3.o \
719 $(OBJDIR)/shell.o \
720 $(OBJDIR)/th.o \
721 $(OBJDIR)/th_lang.o \
722 $(OBJDIR)/th_tcl.o \
723 $(OBJDIR)/cson_amalgamation.o
724
 
 
 
 
725 zlib:
726 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
727
728 clean-zlib:
729 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean
@@ -824,14 +814,12 @@
814 writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
815
816 writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
817 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
818
819 writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
820 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
 
 
821
822 close $output_file
823 #
824 # End of the win/Makefile.mingw output
825 ##############################################################################
@@ -1024,12 +1012,12 @@
1012
1013 # Uncomment to enable Tcl support
1014 # FOSSIL_ENABLE_TCL = 1
1015
1016 !ifdef FOSSIL_ENABLE_SSL
1017 SSLINCDIR = $(B)\compat\openssl-1.0.1g\include
1018 SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32
1019 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
1020 !endif
1021
1022 !ifdef FOSSIL_ENABLE_TCL
1023 TCLDIR = $(B)\compat\tcl-8.6
@@ -1107,11 +1095,11 @@
1095 writeln -nonewline " "
1096 }
1097 writeln -nonewline "${s}_.c"; incr i
1098 }
1099 writeln "\n"
1100 set AdditionalObj [list shell sqlite3 th th_lang th_tcl cson_amalgamation]
1101 writeln -nonewline "OBJ = "
1102 set i 0
1103 foreach s [lsort [concat $src $AdditionalObj]] {
1104 if {$i > 0} {
1105 writeln " \\"
@@ -1119,13 +1107,10 @@
1107 }
1108 writeln -nonewline "\$(OX)\\$s\$O"; incr i
1109 }
1110 writeln " \\"
1111 writeln -nonewline " \$(OX)\\fossil.res\n\n"
 
 
 
1112 writeln {
1113 APPNAME = $(OX)\fossil$(E)
1114 PDBNAME = $(OX)\fossil$(P)
1115
1116 all: $(OX) $(APPNAME)
@@ -1142,14 +1127,11 @@
1127 set redir {>}
1128 foreach s [lsort [concat $src $AdditionalObj]] {
1129 writeln "\techo \$(OX)\\$s.obj $redir \$@"
1130 set redir {>>}
1131 }
 
 
1132 set redir {>>}
 
1133 writeln "\techo \$(LIBS) $redir \$@"
1134 writeln {
1135 $(OX):
1136 @-mkdir $@
1137
@@ -1175,14 +1157,12 @@
1157 $(TCC) /Fo$@ -c $**
1158
1159 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
1160 $(TCC) /Fo$@ -c $**
1161
 
1162 $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
1163 $(TCC) /Fo$@ -c $**
 
1164
1165 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
1166 $** > $@
1167 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
1168 $(TCC) /Fo$@ /c $**
1169
+30 -36
--- src/manifest.c
+++ src/manifest.c
@@ -135,16 +135,16 @@
135135
** Clear the memory allocated in a manifest object
136136
*/
137137
void manifest_destroy(Manifest *p){
138138
if( p ){
139139
blob_reset(&p->content);
140
- free(p->aFile);
141
- free(p->azParent);
142
- free(p->azCChild);
143
- free(p->aTag);
144
- free(p->aField);
145
- free(p->aCherrypick);
140
+ fossil_free(p->aFile);
141
+ fossil_free(p->azParent);
142
+ fossil_free(p->azCChild);
143
+ fossil_free(p->aTag);
144
+ fossil_free(p->aField);
145
+ fossil_free(p->aCherrypick);
146146
if( p->pBaseline ) manifest_destroy(p->pBaseline);
147147
memset(p, 0, sizeof(*p));
148148
fossil_free(p);
149149
}
150150
}
@@ -1608,11 +1608,11 @@
16081608
blob_appendf(&comment, "Ticket [%s|%.10s] <i>%h</i> status still %h with "
16091609
"%d other change%s",
16101610
pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle, zNewStatus,
16111611
pManifest->nField, pManifest->nField==1 ? "" : "s"
16121612
);
1613
- free(zNewStatus);
1613
+ fossil_free(zNewStatus);
16141614
blob_appendf(&brief, "Ticket [%s|%.10s]: %d change%s",
16151615
pManifest->zTicketUuid, pManifest->zTicketUuid, pManifest->nField,
16161616
pManifest->nField==1 ? "" : "s"
16171617
);
16181618
}
@@ -1621,11 +1621,11 @@
16211621
pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
16221622
);
16231623
blob_appendf(&brief, "New ticket [%s|%.10s].", pManifest->zTicketUuid,
16241624
pManifest->zTicketUuid);
16251625
}
1626
- free(zTitle);
1626
+ fossil_free(zTitle);
16271627
db_multi_exec(
16281628
"REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)"
16291629
"VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
16301630
tktTagId, pManifest->rDate, rid, pManifest->zUser,
16311631
blob_str(&comment), blob_str(&brief)
@@ -1753,11 +1753,11 @@
17531753
TAG_COMMENT, rid, p->rDate
17541754
);
17551755
zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
17561756
" WHERE rowid=last_insert_rowid()");
17571757
wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
1758
- free(zCom);
1758
+ fossil_free(zCom);
17591759
17601760
/* If this is a delta-manifest, record the fact that this repository
17611761
** contains delta manifests, to free the "commit" logic to generate
17621762
** new delta manifests.
17631763
*/
@@ -1822,11 +1822,11 @@
18221822
char zLength[40];
18231823
while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
18241824
nWiki = strlen(p->zWiki);
18251825
sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
18261826
tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
1827
- free(zTag);
1827
+ fossil_free(zTag);
18281828
prior = db_int(0,
18291829
"SELECT rid FROM tagxref"
18301830
" WHERE tagid=%d AND mtime<%.17g"
18311831
" ORDER BY mtime DESC",
18321832
tagid, p->rDate
@@ -1850,11 +1850,11 @@
18501850
TAG_BGCOLOR, rid,
18511851
TAG_BGCOLOR, rid,
18521852
TAG_USER, rid,
18531853
TAG_COMMENT, rid
18541854
);
1855
- free(zComment);
1855
+ fossil_free(zComment);
18561856
}
18571857
if( p->type==CFTYPE_EVENT ){
18581858
char *zTag = mprintf("event-%s", p->zEventId);
18591859
int tagid = tag_findid(zTag, 1);
18601860
int prior, subsequent;
@@ -1862,11 +1862,11 @@
18621862
char zLength[40];
18631863
while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
18641864
nWiki = strlen(p->zWiki);
18651865
sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
18661866
tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
1867
- free(zTag);
1867
+ fossil_free(zTag);
18681868
prior = db_int(0,
18691869
"SELECT rid FROM tagxref"
18701870
" WHERE tagid=%d AND mtime<%.17g AND rid!=%d"
18711871
" ORDER BY mtime DESC",
18721872
tagid, p->rDate, rid
@@ -1901,22 +1901,26 @@
19011901
);
19021902
}
19031903
}
19041904
if( p->type==CFTYPE_TICKET ){
19051905
char *zTag;
1906
-
19071906
assert( manifest_crosslink_busy==1 );
19081907
zTag = mprintf("tkt-%s", p->zTicketUuid);
19091908
tag_insert(zTag, 1, 0, rid, p->rDate, rid);
1910
- free(zTag);
1909
+ fossil_free(zTag);
19111910
db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
19121911
p->zTicketUuid);
19131912
}
19141913
if( p->type==CFTYPE_ATTACHMENT ){
1914
+ char *zComment = 0;
1915
+ char const isAdd = (p->zAttachSrc && p->zAttachSrc[0]) ? 1 : 0;
1916
+ char const attachToType = fossil_is_uuid(p->zAttachTarget)
1917
+ ? 't' /* attach to ticket */
1918
+ : 'w' /* attach to wiki page */;
19151919
db_multi_exec(
19161920
"INSERT INTO attachment(attachid, mtime, src, target,"
1917
- "filename, comment, user)"
1921
+ "filename, comment, user)"
19181922
"VALUES(%d,%.17g,%Q,%Q,%Q,%Q,%Q);",
19191923
rid, p->rDate, p->zAttachSrc, p->zAttachTarget, p->zAttachName,
19201924
(p->zComment ? p->zComment : ""), p->zUser
19211925
);
19221926
db_multi_exec(
@@ -1925,45 +1929,35 @@
19251929
" WHERE target=%Q AND filename=%Q))"
19261930
" WHERE target=%Q AND filename=%Q",
19271931
p->zAttachTarget, p->zAttachName,
19281932
p->zAttachTarget, p->zAttachName
19291933
);
1930
- if( strlen(p->zAttachTarget)!=UUID_SIZE
1931
- || !validate16(p->zAttachTarget, UUID_SIZE)
1932
- ){
1933
- char *zComment;
1934
- if( p->zAttachSrc && p->zAttachSrc[0] ){
1934
+ if( 'w' == attachToType ){
1935
+ if( isAdd ){
19351936
zComment = mprintf(
1936
- "Add attachment [/artifact/%S|%h] to wiki page [%h]",
1937
+ "Add attachment [/artifact/%s|%h] to wiki page [%h]",
19371938
p->zAttachSrc, p->zAttachName, p->zAttachTarget);
19381939
}else{
19391940
zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]",
19401941
p->zAttachName, p->zAttachTarget);
19411942
}
1942
- db_multi_exec(
1943
- "REPLACE INTO event(type,mtime,objid,user,comment)"
1944
- "VALUES('w',%.17g,%d,%Q,%Q)",
1945
- p->rDate, rid, p->zUser, zComment
1946
- );
1947
- free(zComment);
19481943
}else{
1949
- char *zComment;
1950
- if( p->zAttachSrc && p->zAttachSrc[0] ){
1944
+ if( isAdd ){
19511945
zComment = mprintf(
1952
- "Add attachment [/artifact/%S|%h] to ticket [%s|%.10s]",
1946
+ "Add attachment [/artifact/%s|%h] to ticket [%s|%.10s]",
19531947
p->zAttachSrc, p->zAttachName, p->zAttachTarget, p->zAttachTarget);
19541948
}else{
19551949
zComment = mprintf("Delete attachment \"%h\" from ticket [%s|%.10s]",
19561950
p->zAttachName, p->zAttachTarget, p->zAttachTarget);
19571951
}
1958
- db_multi_exec(
1952
+ }
1953
+ db_multi_exec(
19591954
"REPLACE INTO event(type,mtime,objid,user,comment)"
1960
- "VALUES('t',%.17g,%d,%Q,%Q)",
1961
- p->rDate, rid, p->zUser, zComment
1962
- );
1963
- free(zComment);
1964
- }
1955
+ "VALUES('%c',%.17g,%d,%Q,%Q)",
1956
+ attachToType, p->rDate, rid, p->zUser, zComment
1957
+ );
1958
+ fossil_free(zComment);
19651959
}
19661960
if( p->type==CFTYPE_CONTROL ){
19671961
Blob comment;
19681962
int i;
19691963
const char *zName;
19701964
--- src/manifest.c
+++ src/manifest.c
@@ -135,16 +135,16 @@
135 ** Clear the memory allocated in a manifest object
136 */
137 void manifest_destroy(Manifest *p){
138 if( p ){
139 blob_reset(&p->content);
140 free(p->aFile);
141 free(p->azParent);
142 free(p->azCChild);
143 free(p->aTag);
144 free(p->aField);
145 free(p->aCherrypick);
146 if( p->pBaseline ) manifest_destroy(p->pBaseline);
147 memset(p, 0, sizeof(*p));
148 fossil_free(p);
149 }
150 }
@@ -1608,11 +1608,11 @@
1608 blob_appendf(&comment, "Ticket [%s|%.10s] <i>%h</i> status still %h with "
1609 "%d other change%s",
1610 pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle, zNewStatus,
1611 pManifest->nField, pManifest->nField==1 ? "" : "s"
1612 );
1613 free(zNewStatus);
1614 blob_appendf(&brief, "Ticket [%s|%.10s]: %d change%s",
1615 pManifest->zTicketUuid, pManifest->zTicketUuid, pManifest->nField,
1616 pManifest->nField==1 ? "" : "s"
1617 );
1618 }
@@ -1621,11 +1621,11 @@
1621 pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
1622 );
1623 blob_appendf(&brief, "New ticket [%s|%.10s].", pManifest->zTicketUuid,
1624 pManifest->zTicketUuid);
1625 }
1626 free(zTitle);
1627 db_multi_exec(
1628 "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)"
1629 "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
1630 tktTagId, pManifest->rDate, rid, pManifest->zUser,
1631 blob_str(&comment), blob_str(&brief)
@@ -1753,11 +1753,11 @@
1753 TAG_COMMENT, rid, p->rDate
1754 );
1755 zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
1756 " WHERE rowid=last_insert_rowid()");
1757 wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
1758 free(zCom);
1759
1760 /* If this is a delta-manifest, record the fact that this repository
1761 ** contains delta manifests, to free the "commit" logic to generate
1762 ** new delta manifests.
1763 */
@@ -1822,11 +1822,11 @@
1822 char zLength[40];
1823 while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
1824 nWiki = strlen(p->zWiki);
1825 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
1826 tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
1827 free(zTag);
1828 prior = db_int(0,
1829 "SELECT rid FROM tagxref"
1830 " WHERE tagid=%d AND mtime<%.17g"
1831 " ORDER BY mtime DESC",
1832 tagid, p->rDate
@@ -1850,11 +1850,11 @@
1850 TAG_BGCOLOR, rid,
1851 TAG_BGCOLOR, rid,
1852 TAG_USER, rid,
1853 TAG_COMMENT, rid
1854 );
1855 free(zComment);
1856 }
1857 if( p->type==CFTYPE_EVENT ){
1858 char *zTag = mprintf("event-%s", p->zEventId);
1859 int tagid = tag_findid(zTag, 1);
1860 int prior, subsequent;
@@ -1862,11 +1862,11 @@
1862 char zLength[40];
1863 while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
1864 nWiki = strlen(p->zWiki);
1865 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
1866 tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
1867 free(zTag);
1868 prior = db_int(0,
1869 "SELECT rid FROM tagxref"
1870 " WHERE tagid=%d AND mtime<%.17g AND rid!=%d"
1871 " ORDER BY mtime DESC",
1872 tagid, p->rDate, rid
@@ -1901,22 +1901,26 @@
1901 );
1902 }
1903 }
1904 if( p->type==CFTYPE_TICKET ){
1905 char *zTag;
1906
1907 assert( manifest_crosslink_busy==1 );
1908 zTag = mprintf("tkt-%s", p->zTicketUuid);
1909 tag_insert(zTag, 1, 0, rid, p->rDate, rid);
1910 free(zTag);
1911 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
1912 p->zTicketUuid);
1913 }
1914 if( p->type==CFTYPE_ATTACHMENT ){
 
 
 
 
 
1915 db_multi_exec(
1916 "INSERT INTO attachment(attachid, mtime, src, target,"
1917 "filename, comment, user)"
1918 "VALUES(%d,%.17g,%Q,%Q,%Q,%Q,%Q);",
1919 rid, p->rDate, p->zAttachSrc, p->zAttachTarget, p->zAttachName,
1920 (p->zComment ? p->zComment : ""), p->zUser
1921 );
1922 db_multi_exec(
@@ -1925,45 +1929,35 @@
1925 " WHERE target=%Q AND filename=%Q))"
1926 " WHERE target=%Q AND filename=%Q",
1927 p->zAttachTarget, p->zAttachName,
1928 p->zAttachTarget, p->zAttachName
1929 );
1930 if( strlen(p->zAttachTarget)!=UUID_SIZE
1931 || !validate16(p->zAttachTarget, UUID_SIZE)
1932 ){
1933 char *zComment;
1934 if( p->zAttachSrc && p->zAttachSrc[0] ){
1935 zComment = mprintf(
1936 "Add attachment [/artifact/%S|%h] to wiki page [%h]",
1937 p->zAttachSrc, p->zAttachName, p->zAttachTarget);
1938 }else{
1939 zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]",
1940 p->zAttachName, p->zAttachTarget);
1941 }
1942 db_multi_exec(
1943 "REPLACE INTO event(type,mtime,objid,user,comment)"
1944 "VALUES('w',%.17g,%d,%Q,%Q)",
1945 p->rDate, rid, p->zUser, zComment
1946 );
1947 free(zComment);
1948 }else{
1949 char *zComment;
1950 if( p->zAttachSrc && p->zAttachSrc[0] ){
1951 zComment = mprintf(
1952 "Add attachment [/artifact/%S|%h] to ticket [%s|%.10s]",
1953 p->zAttachSrc, p->zAttachName, p->zAttachTarget, p->zAttachTarget);
1954 }else{
1955 zComment = mprintf("Delete attachment \"%h\" from ticket [%s|%.10s]",
1956 p->zAttachName, p->zAttachTarget, p->zAttachTarget);
1957 }
1958 db_multi_exec(
 
1959 "REPLACE INTO event(type,mtime,objid,user,comment)"
1960 "VALUES('t',%.17g,%d,%Q,%Q)",
1961 p->rDate, rid, p->zUser, zComment
1962 );
1963 free(zComment);
1964 }
1965 }
1966 if( p->type==CFTYPE_CONTROL ){
1967 Blob comment;
1968 int i;
1969 const char *zName;
1970
--- src/manifest.c
+++ src/manifest.c
@@ -135,16 +135,16 @@
135 ** Clear the memory allocated in a manifest object
136 */
137 void manifest_destroy(Manifest *p){
138 if( p ){
139 blob_reset(&p->content);
140 fossil_free(p->aFile);
141 fossil_free(p->azParent);
142 fossil_free(p->azCChild);
143 fossil_free(p->aTag);
144 fossil_free(p->aField);
145 fossil_free(p->aCherrypick);
146 if( p->pBaseline ) manifest_destroy(p->pBaseline);
147 memset(p, 0, sizeof(*p));
148 fossil_free(p);
149 }
150 }
@@ -1608,11 +1608,11 @@
1608 blob_appendf(&comment, "Ticket [%s|%.10s] <i>%h</i> status still %h with "
1609 "%d other change%s",
1610 pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle, zNewStatus,
1611 pManifest->nField, pManifest->nField==1 ? "" : "s"
1612 );
1613 fossil_free(zNewStatus);
1614 blob_appendf(&brief, "Ticket [%s|%.10s]: %d change%s",
1615 pManifest->zTicketUuid, pManifest->zTicketUuid, pManifest->nField,
1616 pManifest->nField==1 ? "" : "s"
1617 );
1618 }
@@ -1621,11 +1621,11 @@
1621 pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
1622 );
1623 blob_appendf(&brief, "New ticket [%s|%.10s].", pManifest->zTicketUuid,
1624 pManifest->zTicketUuid);
1625 }
1626 fossil_free(zTitle);
1627 db_multi_exec(
1628 "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)"
1629 "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
1630 tktTagId, pManifest->rDate, rid, pManifest->zUser,
1631 blob_str(&comment), blob_str(&brief)
@@ -1753,11 +1753,11 @@
1753 TAG_COMMENT, rid, p->rDate
1754 );
1755 zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
1756 " WHERE rowid=last_insert_rowid()");
1757 wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
1758 fossil_free(zCom);
1759
1760 /* If this is a delta-manifest, record the fact that this repository
1761 ** contains delta manifests, to free the "commit" logic to generate
1762 ** new delta manifests.
1763 */
@@ -1822,11 +1822,11 @@
1822 char zLength[40];
1823 while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
1824 nWiki = strlen(p->zWiki);
1825 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
1826 tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
1827 fossil_free(zTag);
1828 prior = db_int(0,
1829 "SELECT rid FROM tagxref"
1830 " WHERE tagid=%d AND mtime<%.17g"
1831 " ORDER BY mtime DESC",
1832 tagid, p->rDate
@@ -1850,11 +1850,11 @@
1850 TAG_BGCOLOR, rid,
1851 TAG_BGCOLOR, rid,
1852 TAG_USER, rid,
1853 TAG_COMMENT, rid
1854 );
1855 fossil_free(zComment);
1856 }
1857 if( p->type==CFTYPE_EVENT ){
1858 char *zTag = mprintf("event-%s", p->zEventId);
1859 int tagid = tag_findid(zTag, 1);
1860 int prior, subsequent;
@@ -1862,11 +1862,11 @@
1862 char zLength[40];
1863 while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
1864 nWiki = strlen(p->zWiki);
1865 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
1866 tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
1867 fossil_free(zTag);
1868 prior = db_int(0,
1869 "SELECT rid FROM tagxref"
1870 " WHERE tagid=%d AND mtime<%.17g AND rid!=%d"
1871 " ORDER BY mtime DESC",
1872 tagid, p->rDate, rid
@@ -1901,22 +1901,26 @@
1901 );
1902 }
1903 }
1904 if( p->type==CFTYPE_TICKET ){
1905 char *zTag;
 
1906 assert( manifest_crosslink_busy==1 );
1907 zTag = mprintf("tkt-%s", p->zTicketUuid);
1908 tag_insert(zTag, 1, 0, rid, p->rDate, rid);
1909 fossil_free(zTag);
1910 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
1911 p->zTicketUuid);
1912 }
1913 if( p->type==CFTYPE_ATTACHMENT ){
1914 char *zComment = 0;
1915 char const isAdd = (p->zAttachSrc && p->zAttachSrc[0]) ? 1 : 0;
1916 char const attachToType = fossil_is_uuid(p->zAttachTarget)
1917 ? 't' /* attach to ticket */
1918 : 'w' /* attach to wiki page */;
1919 db_multi_exec(
1920 "INSERT INTO attachment(attachid, mtime, src, target,"
1921 "filename, comment, user)"
1922 "VALUES(%d,%.17g,%Q,%Q,%Q,%Q,%Q);",
1923 rid, p->rDate, p->zAttachSrc, p->zAttachTarget, p->zAttachName,
1924 (p->zComment ? p->zComment : ""), p->zUser
1925 );
1926 db_multi_exec(
@@ -1925,45 +1929,35 @@
1929 " WHERE target=%Q AND filename=%Q))"
1930 " WHERE target=%Q AND filename=%Q",
1931 p->zAttachTarget, p->zAttachName,
1932 p->zAttachTarget, p->zAttachName
1933 );
1934 if( 'w' == attachToType ){
1935 if( isAdd ){
 
 
 
1936 zComment = mprintf(
1937 "Add attachment [/artifact/%s|%h] to wiki page [%h]",
1938 p->zAttachSrc, p->zAttachName, p->zAttachTarget);
1939 }else{
1940 zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]",
1941 p->zAttachName, p->zAttachTarget);
1942 }
 
 
 
 
 
 
1943 }else{
1944 if( isAdd ){
 
1945 zComment = mprintf(
1946 "Add attachment [/artifact/%s|%h] to ticket [%s|%.10s]",
1947 p->zAttachSrc, p->zAttachName, p->zAttachTarget, p->zAttachTarget);
1948 }else{
1949 zComment = mprintf("Delete attachment \"%h\" from ticket [%s|%.10s]",
1950 p->zAttachName, p->zAttachTarget, p->zAttachTarget);
1951 }
1952 }
1953 db_multi_exec(
1954 "REPLACE INTO event(type,mtime,objid,user,comment)"
1955 "VALUES('%c',%.17g,%d,%Q,%Q)",
1956 attachToType, p->rDate, rid, p->zUser, zComment
1957 );
1958 fossil_free(zComment);
 
1959 }
1960 if( p->type==CFTYPE_CONTROL ){
1961 Blob comment;
1962 int i;
1963 const char *zName;
1964
+120 -3
--- src/name.c
+++ src/name.c
@@ -266,11 +266,10 @@
266266
}
267267
}
268268
return rid;
269269
}
270270
271
-
272271
/*
273272
** This routine takes a user-entered UUID which might be in mixed
274273
** case and might only be a prefix of the full UUID and converts it
275274
** into the full-length UUID in canonical form.
276275
**
@@ -319,10 +318,39 @@
319318
}
320319
return rid;
321320
}
322321
323322
323
+/*
324
+** name_collisions searches through events, blobs, and tickets for
325
+** collisions of a given UUID based on its length on UUIDs no shorter
326
+** than 4 characters in length.
327
+*/
328
+int name_collisions(const char *zName){
329
+ Stmt q;
330
+ int c = 0; /* count of collisions for zName */
331
+ int nLen; /* length of zName */
332
+ nLen = strlen(zName);
333
+ if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){
334
+ db_prepare(&q,
335
+ "SELECT count(uuid) FROM"
336
+ " (SELECT substr(tkt_uuid, 1, %d) AS uuid FROM ticket"
337
+ " UNION ALL SELECT * FROM"
338
+ " (SELECT substr(tagname, 7, %d) FROM"
339
+ " tag WHERE tagname GLOB 'event-*')"
340
+ " UNION ALL SELECT * FROM"
341
+ " (SELECT substr(uuid, 1, %d) FROM blob))"
342
+ " WHERE uuid GLOB '%q*'"
343
+ " GROUP BY uuid HAVING count(uuid) > 1;",
344
+ nLen, nLen, nLen, zName);
345
+ if( db_step(&q)==SQLITE_ROW ){
346
+ c = db_column_int(&q, 0);
347
+ }
348
+ db_finalize(&q);
349
+ }
350
+ return c;
351
+}
324352
325353
/*
326354
** COMMAND: test-name-to-id
327355
**
328356
** Convert a name to a full artifact ID.
@@ -402,16 +430,56 @@
402430
canonical16(z, strlen(z));
403431
db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
404432
while( db_step(&q)==SQLITE_ROW ){
405433
const char *zUuid = db_column_text(&q, 0);
406434
int rid = db_column_int(&q, 1);
407
- @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%S(zUuid)">
408
- @ %S(zUuid)</a> -
435
+ @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
436
+ @ %s(zUuid)</a> -
437
+ object_description(rid, 0, 0);
438
+ @ </p></li>
439
+ }
440
+ db_finalize(&q);
441
+ db_prepare(&q,
442
+ " SELECT tkt_rid, tkt_uuid, title"
443
+ " FROM ticket, ticketchng"
444
+ " WHERE ticket.tkt_id = ticketchng.tkt_id"
445
+ " AND tkt_uuid GLOB '%q*'"
446
+ " GROUP BY tkt_uuid"
447
+ " ORDER BY tkt_ctime DESC", z);
448
+ while( db_step(&q)==SQLITE_ROW ){
449
+ int rid = db_column_int(&q, 0);
450
+ const char *zUuid = db_column_text(&q, 1);
451
+ const char *zTitle = db_column_text(&q, 2);
452
+ @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
453
+ @ %s(zUuid)</a> -
454
+ @ <ul></ul>
455
+ @ Ticket
456
+ hyperlink_to_uuid(zUuid);
457
+ @ - %s(zTitle).
458
+ @ <ul><li>
459
+ object_description(rid, 0, 0);
460
+ @ </li></ul>
461
+ @ </p></li>
462
+ }
463
+ db_finalize(&q);
464
+ db_prepare(&q,
465
+ "SELECT rid, uuid FROM"
466
+ " (SELECT tagxref.rid AS rid, substr(tagname, 7) AS uuid"
467
+ " FROM tagxref, tag WHERE tagxref.tagid = tag.tagid"
468
+ " AND tagname GLOB 'event-%q*') GROUP BY uuid", z);
469
+ while( db_step(&q)==SQLITE_ROW ){
470
+ int rid = db_column_int(&q, 0);
471
+ const char* zUuid = db_column_text(&q, 1);
472
+ @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
473
+ @ %s(zUuid)</a> -
474
+ @ <ul><li>
409475
object_description(rid, 0, 0);
476
+ @ </li></ul>
410477
@ </p></li>
411478
}
412479
@ </ol>
480
+ db_finalize(&q);
413481
style_footer();
414482
}
415483
416484
/*
417485
** Convert the name in CGI parameter zParamName into a rid and return that
@@ -630,5 +698,54 @@
630698
if( cnt++ ) fossil_print("%.79c\n", '-');
631699
whatis_rid(db_column_int(&q,0), 1);
632700
}
633701
db_finalize(&q);
634702
}
703
+
704
+
705
+/*
706
+** COMMAND: test-ambiguous
707
+** Usage: %fossil test-ambiguous [--minsize N]
708
+**
709
+** Show a list of ambiguous SHA1-hash abbreviations of N characters or
710
+** more where N defaults to 4. Change N to a different value using
711
+** the "--minsize N" command-line option.
712
+*/
713
+void test_ambiguous_cmd(void){
714
+ Stmt q, ins;
715
+ int i;
716
+ int minSize = 4;
717
+ const char *zMinsize;
718
+ char zPrev[100];
719
+ db_find_and_open_repository(0,0);
720
+ zMinsize = find_option("minsize",0,1);
721
+ if( zMinsize && atoi(zMinsize)>0 ) minSize = atoi(zMinsize);
722
+ db_multi_exec("CREATE TEMP TABLE dups(uuid, cnt)");
723
+ db_prepare(&ins,"INSERT INTO dups(uuid) VALUES(substr(:uuid,1,:cnt))");
724
+ db_prepare(&q,
725
+ "SELECT uuid FROM blob "
726
+ "UNION "
727
+ "SELECT substr(tagname,7) FROM tag WHERE tagname GLOB 'event-*' "
728
+ "UNION "
729
+ "SELECT tkt_uuid FROM ticket "
730
+ "ORDER BY 1"
731
+ );
732
+ zPrev[0] = 0;
733
+ while( db_step(&q)==SQLITE_ROW ){
734
+ const char *zUuid = db_column_text(&q, 0);
735
+ for(i=0; zUuid[i]==zPrev[i] && zUuid[i]!=0; i++){}
736
+ if( i>=minSize ){
737
+ db_bind_int(&ins, ":cnt", i);
738
+ db_bind_text(&ins, ":uuid", zUuid);
739
+ db_step(&ins);
740
+ db_reset(&ins);
741
+ }
742
+ sqlite3_snprintf(sizeof(zPrev), zPrev, "%s", zUuid);
743
+ }
744
+ db_finalize(&ins);
745
+ db_finalize(&q);
746
+ db_prepare(&q, "SELECT uuid FROM dups ORDER BY length(uuid) DESC, uuid");
747
+ while( db_step(&q)==SQLITE_ROW ){
748
+ fossil_print("%s\n", db_column_text(&q, 0));
749
+ }
750
+ db_finalize(&q);
751
+}
635752
--- src/name.c
+++ src/name.c
@@ -266,11 +266,10 @@
266 }
267 }
268 return rid;
269 }
270
271
272 /*
273 ** This routine takes a user-entered UUID which might be in mixed
274 ** case and might only be a prefix of the full UUID and converts it
275 ** into the full-length UUID in canonical form.
276 **
@@ -319,10 +318,39 @@
319 }
320 return rid;
321 }
322
323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
325 /*
326 ** COMMAND: test-name-to-id
327 **
328 ** Convert a name to a full artifact ID.
@@ -402,16 +430,56 @@
402 canonical16(z, strlen(z));
403 db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
404 while( db_step(&q)==SQLITE_ROW ){
405 const char *zUuid = db_column_text(&q, 0);
406 int rid = db_column_int(&q, 1);
407 @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%S(zUuid)">
408 @ %S(zUuid)</a> -
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409 object_description(rid, 0, 0);
 
410 @ </p></li>
411 }
412 @ </ol>
 
413 style_footer();
414 }
415
416 /*
417 ** Convert the name in CGI parameter zParamName into a rid and return that
@@ -630,5 +698,54 @@
630 if( cnt++ ) fossil_print("%.79c\n", '-');
631 whatis_rid(db_column_int(&q,0), 1);
632 }
633 db_finalize(&q);
634 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
635
--- src/name.c
+++ src/name.c
@@ -266,11 +266,10 @@
266 }
267 }
268 return rid;
269 }
270
 
271 /*
272 ** This routine takes a user-entered UUID which might be in mixed
273 ** case and might only be a prefix of the full UUID and converts it
274 ** into the full-length UUID in canonical form.
275 **
@@ -319,10 +318,39 @@
318 }
319 return rid;
320 }
321
322
323 /*
324 ** name_collisions searches through events, blobs, and tickets for
325 ** collisions of a given UUID based on its length on UUIDs no shorter
326 ** than 4 characters in length.
327 */
328 int name_collisions(const char *zName){
329 Stmt q;
330 int c = 0; /* count of collisions for zName */
331 int nLen; /* length of zName */
332 nLen = strlen(zName);
333 if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){
334 db_prepare(&q,
335 "SELECT count(uuid) FROM"
336 " (SELECT substr(tkt_uuid, 1, %d) AS uuid FROM ticket"
337 " UNION ALL SELECT * FROM"
338 " (SELECT substr(tagname, 7, %d) FROM"
339 " tag WHERE tagname GLOB 'event-*')"
340 " UNION ALL SELECT * FROM"
341 " (SELECT substr(uuid, 1, %d) FROM blob))"
342 " WHERE uuid GLOB '%q*'"
343 " GROUP BY uuid HAVING count(uuid) > 1;",
344 nLen, nLen, nLen, zName);
345 if( db_step(&q)==SQLITE_ROW ){
346 c = db_column_int(&q, 0);
347 }
348 db_finalize(&q);
349 }
350 return c;
351 }
352
353 /*
354 ** COMMAND: test-name-to-id
355 **
356 ** Convert a name to a full artifact ID.
@@ -402,16 +430,56 @@
430 canonical16(z, strlen(z));
431 db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
432 while( db_step(&q)==SQLITE_ROW ){
433 const char *zUuid = db_column_text(&q, 0);
434 int rid = db_column_int(&q, 1);
435 @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
436 @ %s(zUuid)</a> -
437 object_description(rid, 0, 0);
438 @ </p></li>
439 }
440 db_finalize(&q);
441 db_prepare(&q,
442 " SELECT tkt_rid, tkt_uuid, title"
443 " FROM ticket, ticketchng"
444 " WHERE ticket.tkt_id = ticketchng.tkt_id"
445 " AND tkt_uuid GLOB '%q*'"
446 " GROUP BY tkt_uuid"
447 " ORDER BY tkt_ctime DESC", z);
448 while( db_step(&q)==SQLITE_ROW ){
449 int rid = db_column_int(&q, 0);
450 const char *zUuid = db_column_text(&q, 1);
451 const char *zTitle = db_column_text(&q, 2);
452 @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
453 @ %s(zUuid)</a> -
454 @ <ul></ul>
455 @ Ticket
456 hyperlink_to_uuid(zUuid);
457 @ - %s(zTitle).
458 @ <ul><li>
459 object_description(rid, 0, 0);
460 @ </li></ul>
461 @ </p></li>
462 }
463 db_finalize(&q);
464 db_prepare(&q,
465 "SELECT rid, uuid FROM"
466 " (SELECT tagxref.rid AS rid, substr(tagname, 7) AS uuid"
467 " FROM tagxref, tag WHERE tagxref.tagid = tag.tagid"
468 " AND tagname GLOB 'event-%q*') GROUP BY uuid", z);
469 while( db_step(&q)==SQLITE_ROW ){
470 int rid = db_column_int(&q, 0);
471 const char* zUuid = db_column_text(&q, 1);
472 @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
473 @ %s(zUuid)</a> -
474 @ <ul><li>
475 object_description(rid, 0, 0);
476 @ </li></ul>
477 @ </p></li>
478 }
479 @ </ol>
480 db_finalize(&q);
481 style_footer();
482 }
483
484 /*
485 ** Convert the name in CGI parameter zParamName into a rid and return that
@@ -630,5 +698,54 @@
698 if( cnt++ ) fossil_print("%.79c\n", '-');
699 whatis_rid(db_column_int(&q,0), 1);
700 }
701 db_finalize(&q);
702 }
703
704
705 /*
706 ** COMMAND: test-ambiguous
707 ** Usage: %fossil test-ambiguous [--minsize N]
708 **
709 ** Show a list of ambiguous SHA1-hash abbreviations of N characters or
710 ** more where N defaults to 4. Change N to a different value using
711 ** the "--minsize N" command-line option.
712 */
713 void test_ambiguous_cmd(void){
714 Stmt q, ins;
715 int i;
716 int minSize = 4;
717 const char *zMinsize;
718 char zPrev[100];
719 db_find_and_open_repository(0,0);
720 zMinsize = find_option("minsize",0,1);
721 if( zMinsize && atoi(zMinsize)>0 ) minSize = atoi(zMinsize);
722 db_multi_exec("CREATE TEMP TABLE dups(uuid, cnt)");
723 db_prepare(&ins,"INSERT INTO dups(uuid) VALUES(substr(:uuid,1,:cnt))");
724 db_prepare(&q,
725 "SELECT uuid FROM blob "
726 "UNION "
727 "SELECT substr(tagname,7) FROM tag WHERE tagname GLOB 'event-*' "
728 "UNION "
729 "SELECT tkt_uuid FROM ticket "
730 "ORDER BY 1"
731 );
732 zPrev[0] = 0;
733 while( db_step(&q)==SQLITE_ROW ){
734 const char *zUuid = db_column_text(&q, 0);
735 for(i=0; zUuid[i]==zPrev[i] && zUuid[i]!=0; i++){}
736 if( i>=minSize ){
737 db_bind_int(&ins, ":cnt", i);
738 db_bind_text(&ins, ":uuid", zUuid);
739 db_step(&ins);
740 db_reset(&ins);
741 }
742 sqlite3_snprintf(sizeof(zPrev), zPrev, "%s", zUuid);
743 }
744 db_finalize(&ins);
745 db_finalize(&q);
746 db_prepare(&q, "SELECT uuid FROM dups ORDER BY length(uuid) DESC, uuid");
747 while( db_step(&q)==SQLITE_ROW ){
748 fossil_print("%s\n", db_column_text(&q, 0));
749 }
750 db_finalize(&q);
751 }
752
--- src/report.c
+++ src/report.c
@@ -302,10 +302,11 @@
302302
"FROM reportfmt WHERE rn=%d",rn);
303303
style_header("SQL For Report Format Number %d", rn);
304304
if( db_step(&q)!=SQLITE_ROW ){
305305
@ <p>Unknown report number: %d(rn)</p>
306306
style_footer();
307
+ db_finalize(&q);
307308
return;
308309
}
309310
zTitle = db_column_text(&q, 0);
310311
zSQL = db_column_text(&q, 1);
311312
zOwner = db_column_text(&q, 2);
@@ -323,10 +324,11 @@
323324
output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
324325
@ </td>
325326
@ </tr></table>
326327
report_format_hints();
327328
style_footer();
329
+ db_finalize(&q);
328330
}
329331
330332
/*
331333
** WEBPAGE: /rptnew
332334
** WEBPAGE: /rptedit
@@ -1026,10 +1028,11 @@
10261028
/* view_add_functions(tabs); */
10271029
db_prepare(&q,
10281030
"SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn);
10291031
if( db_step(&q)!=SQLITE_ROW ){
10301032
cgi_redirect("reportlist");
1033
+ db_finalize(&q);
10311034
return;
10321035
}
10331036
zTitle = db_column_malloc(&q, 0);
10341037
zSql = db_column_malloc(&q, 1);
10351038
zOwner = db_column_malloc(&q, 2);
10361039
--- src/report.c
+++ src/report.c
@@ -302,10 +302,11 @@
302 "FROM reportfmt WHERE rn=%d",rn);
303 style_header("SQL For Report Format Number %d", rn);
304 if( db_step(&q)!=SQLITE_ROW ){
305 @ <p>Unknown report number: %d(rn)</p>
306 style_footer();
 
307 return;
308 }
309 zTitle = db_column_text(&q, 0);
310 zSQL = db_column_text(&q, 1);
311 zOwner = db_column_text(&q, 2);
@@ -323,10 +324,11 @@
323 output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
324 @ </td>
325 @ </tr></table>
326 report_format_hints();
327 style_footer();
 
328 }
329
330 /*
331 ** WEBPAGE: /rptnew
332 ** WEBPAGE: /rptedit
@@ -1026,10 +1028,11 @@
1026 /* view_add_functions(tabs); */
1027 db_prepare(&q,
1028 "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn);
1029 if( db_step(&q)!=SQLITE_ROW ){
1030 cgi_redirect("reportlist");
 
1031 return;
1032 }
1033 zTitle = db_column_malloc(&q, 0);
1034 zSql = db_column_malloc(&q, 1);
1035 zOwner = db_column_malloc(&q, 2);
1036
--- src/report.c
+++ src/report.c
@@ -302,10 +302,11 @@
302 "FROM reportfmt WHERE rn=%d",rn);
303 style_header("SQL For Report Format Number %d", rn);
304 if( db_step(&q)!=SQLITE_ROW ){
305 @ <p>Unknown report number: %d(rn)</p>
306 style_footer();
307 db_finalize(&q);
308 return;
309 }
310 zTitle = db_column_text(&q, 0);
311 zSQL = db_column_text(&q, 1);
312 zOwner = db_column_text(&q, 2);
@@ -323,10 +324,11 @@
324 output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
325 @ </td>
326 @ </tr></table>
327 report_format_hints();
328 style_footer();
329 db_finalize(&q);
330 }
331
332 /*
333 ** WEBPAGE: /rptnew
334 ** WEBPAGE: /rptedit
@@ -1026,10 +1028,11 @@
1028 /* view_add_functions(tabs); */
1029 db_prepare(&q,
1030 "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn);
1031 if( db_step(&q)!=SQLITE_ROW ){
1032 cgi_redirect("reportlist");
1033 db_finalize(&q);
1034 return;
1035 }
1036 zTitle = db_column_malloc(&q, 0);
1037 zSql = db_column_malloc(&q, 1);
1038 zOwner = db_column_malloc(&q, 2);
1039
+1 -1
--- src/search.c
+++ src/search.c
@@ -199,11 +199,11 @@
199199
lines/entries to list */
200200
int width;
201201
if( zWidth ){
202202
width = atoi(zWidth);
203203
if( (width!=0) && (width<=20) ){
204
- fossil_fatal("--width|-W value must be >20 or 0");
204
+ fossil_fatal("-W|--width value must be >20 or 0");
205205
}
206206
}else{
207207
width = 79;
208208
}
209209
210210
--- src/search.c
+++ src/search.c
@@ -199,11 +199,11 @@
199 lines/entries to list */
200 int width;
201 if( zWidth ){
202 width = atoi(zWidth);
203 if( (width!=0) && (width<=20) ){
204 fossil_fatal("--width|-W value must be >20 or 0");
205 }
206 }else{
207 width = 79;
208 }
209
210
--- src/search.c
+++ src/search.c
@@ -199,11 +199,11 @@
199 lines/entries to list */
200 int width;
201 if( zWidth ){
202 width = atoi(zWidth);
203 if( (width!=0) && (width<=20) ){
204 fossil_fatal("-W|--width value must be >20 or 0");
205 }
206 }else{
207 width = 79;
208 }
209
210
+29 -19
--- src/setup.c
+++ src/setup.c
@@ -277,10 +277,11 @@
277277
@ </p></li>
278278
@
279279
@ </ol>
280280
@ </td></tr></table>
281281
style_footer();
282
+ db_finalize(&s);
282283
}
283284
284285
/*
285286
** Return true if zPw is a valid password string. A valid
286287
** password string is:
@@ -325,11 +326,11 @@
325326
zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
326327
higherUser = zOldCaps && strchr(zOldCaps,'s');
327328
}
328329
329330
if( P("can") ){
330
- cgi_redirect("setup_ulist");
331
+ cgi_redirect("setup_ulist"); /* User pressed the Cancel button */
331332
return;
332333
}
333334
334335
/* If we have all the necessary information, write the new or
335336
** modified user record. After writing the user record, redirect
@@ -362,13 +363,11 @@
362363
zPw = sha1_shared_secret(zPw, zLogin, 0);
363364
}else{
364365
zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
365366
}
366367
zOldLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid);
367
- if( uid>0 &&
368
- db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
369
- ){
368
+ if( db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid) ){
370369
style_header("User Creation Error");
371370
@ <span class="loginError">Login "%h(zLogin)" is already used by
372371
@ a different user.</span>
373372
@
374373
@ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
@@ -485,10 +484,15 @@
485484
style_header("Add A New User");
486485
}
487486
@ <div class="ueditCapBox">
488487
@ <form action="%s(g.zPath)" method="post"><div>
489488
login_insert_csrf_secret();
489
+ if( login_is_special(zLogin) ){
490
+ @ <input type="hidden" name="login" value="%s(zLogin)">
491
+ @ <input type="hidden" name="info" value="">
492
+ @ <input type="hidden" name="pw" value="*">
493
+ }
490494
@ <table>
491495
@ <tr>
492496
@ <td class="usetupEditLabel">User ID:</td>
493497
if( uid ){
494498
@ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td>
@@ -496,15 +500,19 @@
496500
@ <td>(new user)<input type="hidden" name="id" value="0" /></td>
497501
}
498502
@ </tr>
499503
@ <tr>
500504
@ <td class="usetupEditLabel">Login:</td>
501
- @ <td><input type="text" name="login" value="%h(zLogin)" /></td>
502
- @ </tr>
503
- @ <tr>
504
- @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
505
- @ <td><input type="text" name="info" size="40" value="%h(zInfo)" /></td>
505
+ if( login_is_special(zLogin) ){
506
+ @ <td><b>%h(zLogin)</b></td>
507
+ }else{
508
+ @ <td><input type="text" name="login" value="%h(zLogin)" /></td>
509
+ @ </tr>
510
+ @ <tr>
511
+ @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
512
+ @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
513
+ }
506514
@ </tr>
507515
@ <tr>
508516
@ <td class="usetupEditLabel">Capabilities:</td>
509517
@ <td>
510518
#define B(x) inherit[x]
@@ -564,20 +572,22 @@
564572
@ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
565573
@ Zip </label>
566574
@ </td></tr></table>
567575
@ </td>
568576
@ </tr>
569
- @ <tr>
570
- @ <td align="right">Password:</td>
571
- if( zPw[0] ){
572
- /* Obscure the password for all users */
573
- @ <td><input type="password" name="pw" value="**********" /></td>
574
- }else{
575
- /* Show an empty password as an empty input field */
576
- @ <td><input type="password" name="pw" value="" /></td>
577
- }
578
- @ </tr>
577
+ if( !login_is_special(zLogin) ){
578
+ @ <tr>
579
+ @ <td align="right">Password:</td>
580
+ if( zPw[0] ){
581
+ /* Obscure the password for all users */
582
+ @ <td><input type="password" name="pw" value="**********" /></td>
583
+ }else{
584
+ /* Show an empty password as an empty input field */
585
+ @ <td><input type="password" name="pw" value="" /></td>
586
+ }
587
+ @ </tr>
588
+ }
579589
zGroup = login_group_name();
580590
if( zGroup ){
581591
@ <tr>
582592
@ <td valign="top" align="right">Scope:</td>
583593
@ <td valign="top">
584594
--- src/setup.c
+++ src/setup.c
@@ -277,10 +277,11 @@
277 @ </p></li>
278 @
279 @ </ol>
280 @ </td></tr></table>
281 style_footer();
 
282 }
283
284 /*
285 ** Return true if zPw is a valid password string. A valid
286 ** password string is:
@@ -325,11 +326,11 @@
325 zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
326 higherUser = zOldCaps && strchr(zOldCaps,'s');
327 }
328
329 if( P("can") ){
330 cgi_redirect("setup_ulist");
331 return;
332 }
333
334 /* If we have all the necessary information, write the new or
335 ** modified user record. After writing the user record, redirect
@@ -362,13 +363,11 @@
362 zPw = sha1_shared_secret(zPw, zLogin, 0);
363 }else{
364 zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
365 }
366 zOldLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid);
367 if( uid>0 &&
368 db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
369 ){
370 style_header("User Creation Error");
371 @ <span class="loginError">Login "%h(zLogin)" is already used by
372 @ a different user.</span>
373 @
374 @ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
@@ -485,10 +484,15 @@
485 style_header("Add A New User");
486 }
487 @ <div class="ueditCapBox">
488 @ <form action="%s(g.zPath)" method="post"><div>
489 login_insert_csrf_secret();
 
 
 
 
 
490 @ <table>
491 @ <tr>
492 @ <td class="usetupEditLabel">User ID:</td>
493 if( uid ){
494 @ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td>
@@ -496,15 +500,19 @@
496 @ <td>(new user)<input type="hidden" name="id" value="0" /></td>
497 }
498 @ </tr>
499 @ <tr>
500 @ <td class="usetupEditLabel">Login:</td>
501 @ <td><input type="text" name="login" value="%h(zLogin)" /></td>
502 @ </tr>
503 @ <tr>
504 @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
505 @ <td><input type="text" name="info" size="40" value="%h(zInfo)" /></td>
 
 
 
 
506 @ </tr>
507 @ <tr>
508 @ <td class="usetupEditLabel">Capabilities:</td>
509 @ <td>
510 #define B(x) inherit[x]
@@ -564,20 +572,22 @@
564 @ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
565 @ Zip </label>
566 @ </td></tr></table>
567 @ </td>
568 @ </tr>
569 @ <tr>
570 @ <td align="right">Password:</td>
571 if( zPw[0] ){
572 /* Obscure the password for all users */
573 @ <td><input type="password" name="pw" value="**********" /></td>
574 }else{
575 /* Show an empty password as an empty input field */
576 @ <td><input type="password" name="pw" value="" /></td>
577 }
578 @ </tr>
 
 
579 zGroup = login_group_name();
580 if( zGroup ){
581 @ <tr>
582 @ <td valign="top" align="right">Scope:</td>
583 @ <td valign="top">
584
--- src/setup.c
+++ src/setup.c
@@ -277,10 +277,11 @@
277 @ </p></li>
278 @
279 @ </ol>
280 @ </td></tr></table>
281 style_footer();
282 db_finalize(&s);
283 }
284
285 /*
286 ** Return true if zPw is a valid password string. A valid
287 ** password string is:
@@ -325,11 +326,11 @@
326 zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
327 higherUser = zOldCaps && strchr(zOldCaps,'s');
328 }
329
330 if( P("can") ){
331 cgi_redirect("setup_ulist"); /* User pressed the Cancel button */
332 return;
333 }
334
335 /* If we have all the necessary information, write the new or
336 ** modified user record. After writing the user record, redirect
@@ -362,13 +363,11 @@
363 zPw = sha1_shared_secret(zPw, zLogin, 0);
364 }else{
365 zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
366 }
367 zOldLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid);
368 if( db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid) ){
 
 
369 style_header("User Creation Error");
370 @ <span class="loginError">Login "%h(zLogin)" is already used by
371 @ a different user.</span>
372 @
373 @ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
@@ -485,10 +484,15 @@
484 style_header("Add A New User");
485 }
486 @ <div class="ueditCapBox">
487 @ <form action="%s(g.zPath)" method="post"><div>
488 login_insert_csrf_secret();
489 if( login_is_special(zLogin) ){
490 @ <input type="hidden" name="login" value="%s(zLogin)">
491 @ <input type="hidden" name="info" value="">
492 @ <input type="hidden" name="pw" value="*">
493 }
494 @ <table>
495 @ <tr>
496 @ <td class="usetupEditLabel">User ID:</td>
497 if( uid ){
498 @ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td>
@@ -496,15 +500,19 @@
500 @ <td>(new user)<input type="hidden" name="id" value="0" /></td>
501 }
502 @ </tr>
503 @ <tr>
504 @ <td class="usetupEditLabel">Login:</td>
505 if( login_is_special(zLogin) ){
506 @ <td><b>%h(zLogin)</b></td>
507 }else{
508 @ <td><input type="text" name="login" value="%h(zLogin)" /></td>
509 @ </tr>
510 @ <tr>
511 @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
512 @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
513 }
514 @ </tr>
515 @ <tr>
516 @ <td class="usetupEditLabel">Capabilities:</td>
517 @ <td>
518 #define B(x) inherit[x]
@@ -564,20 +572,22 @@
572 @ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
573 @ Zip </label>
574 @ </td></tr></table>
575 @ </td>
576 @ </tr>
577 if( !login_is_special(zLogin) ){
578 @ <tr>
579 @ <td align="right">Password:</td>
580 if( zPw[0] ){
581 /* Obscure the password for all users */
582 @ <td><input type="password" name="pw" value="**********" /></td>
583 }else{
584 /* Show an empty password as an empty input field */
585 @ <td><input type="password" name="pw" value="" /></td>
586 }
587 @ </tr>
588 }
589 zGroup = login_group_name();
590 if( zGroup ){
591 @ <tr>
592 @ <td valign="top" align="right">Scope:</td>
593 @ <td valign="top">
594
+6 -2
--- src/shell.c
+++ src/shell.c
@@ -2128,14 +2128,16 @@
21282128
rc = sqlite3_open(zNewDb, &newDb);
21292129
if( rc ){
21302130
fprintf(stderr, "Cannot create output database: %s\n",
21312131
sqlite3_errmsg(newDb));
21322132
}else{
2133
+ sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
21332134
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
21342135
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
21352136
tryToCloneSchema(p, newDb, "type!='table'", 0);
21362137
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
2138
+ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
21372139
}
21382140
sqlite3_close(newDb);
21392141
}
21402142
21412143
/*
@@ -3023,10 +3025,11 @@
30233025
{ "always", SQLITE_TESTCTRL_ALWAYS },
30243026
{ "reserve", SQLITE_TESTCTRL_RESERVE },
30253027
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
30263028
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
30273029
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
3030
+ { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
30283031
};
30293032
int testctrl = -1;
30303033
int rc = 0;
30313034
int i, n;
30323035
open_db(p, 0);
@@ -3063,13 +3066,14 @@
30633066
azArg[1]);
30643067
}
30653068
break;
30663069
30673070
/* sqlite3_test_control(int) */
3068
- case SQLITE_TESTCTRL_PRNG_SAVE:
3069
- case SQLITE_TESTCTRL_PRNG_RESTORE:
3071
+ case SQLITE_TESTCTRL_PRNG_SAVE:
3072
+ case SQLITE_TESTCTRL_PRNG_RESTORE:
30703073
case SQLITE_TESTCTRL_PRNG_RESET:
3074
+ case SQLITE_TESTCTRL_BYTEORDER:
30713075
if( nArg==2 ){
30723076
rc = sqlite3_test_control(testctrl);
30733077
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
30743078
} else {
30753079
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
30763080
--- src/shell.c
+++ src/shell.c
@@ -2128,14 +2128,16 @@
2128 rc = sqlite3_open(zNewDb, &newDb);
2129 if( rc ){
2130 fprintf(stderr, "Cannot create output database: %s\n",
2131 sqlite3_errmsg(newDb));
2132 }else{
 
2133 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
2134 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
2135 tryToCloneSchema(p, newDb, "type!='table'", 0);
2136 sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
 
2137 }
2138 sqlite3_close(newDb);
2139 }
2140
2141 /*
@@ -3023,10 +3025,11 @@
3023 { "always", SQLITE_TESTCTRL_ALWAYS },
3024 { "reserve", SQLITE_TESTCTRL_RESERVE },
3025 { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
3026 { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
3027 { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
 
3028 };
3029 int testctrl = -1;
3030 int rc = 0;
3031 int i, n;
3032 open_db(p, 0);
@@ -3063,13 +3066,14 @@
3063 azArg[1]);
3064 }
3065 break;
3066
3067 /* sqlite3_test_control(int) */
3068 case SQLITE_TESTCTRL_PRNG_SAVE:
3069 case SQLITE_TESTCTRL_PRNG_RESTORE:
3070 case SQLITE_TESTCTRL_PRNG_RESET:
 
3071 if( nArg==2 ){
3072 rc = sqlite3_test_control(testctrl);
3073 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3074 } else {
3075 fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
3076
--- src/shell.c
+++ src/shell.c
@@ -2128,14 +2128,16 @@
2128 rc = sqlite3_open(zNewDb, &newDb);
2129 if( rc ){
2130 fprintf(stderr, "Cannot create output database: %s\n",
2131 sqlite3_errmsg(newDb));
2132 }else{
2133 sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
2134 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
2135 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
2136 tryToCloneSchema(p, newDb, "type!='table'", 0);
2137 sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
2138 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
2139 }
2140 sqlite3_close(newDb);
2141 }
2142
2143 /*
@@ -3023,10 +3025,11 @@
3025 { "always", SQLITE_TESTCTRL_ALWAYS },
3026 { "reserve", SQLITE_TESTCTRL_RESERVE },
3027 { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
3028 { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
3029 { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
3030 { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
3031 };
3032 int testctrl = -1;
3033 int rc = 0;
3034 int i, n;
3035 open_db(p, 0);
@@ -3063,13 +3066,14 @@
3066 azArg[1]);
3067 }
3068 break;
3069
3070 /* sqlite3_test_control(int) */
3071 case SQLITE_TESTCTRL_PRNG_SAVE:
3072 case SQLITE_TESTCTRL_PRNG_RESTORE:
3073 case SQLITE_TESTCTRL_PRNG_RESET:
3074 case SQLITE_TESTCTRL_BYTEORDER:
3075 if( nArg==2 ){
3076 rc = sqlite3_test_control(testctrl);
3077 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3078 } else {
3079 fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
3080
+3 -3
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -112,15 +112,15 @@
112112
static int sqlcmd_autoinit(
113113
sqlite3 *db,
114114
const char **pzErrMsg,
115115
const void *notUsed
116116
){
117
- sqlite3_create_function(db, "content", 1, SQLITE_ANY, 0,
117
+ sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
118118
sqlcmd_content, 0, 0);
119
- sqlite3_create_function(db, "compress", 1, SQLITE_ANY, 0,
119
+ sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
120120
sqlcmd_compress, 0, 0);
121
- sqlite3_create_function(db, "decompress", 1, SQLITE_ANY, 0,
121
+ sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
122122
sqlcmd_decompress, 0, 0);
123123
re_add_sql_func(db);
124124
g.repositoryOpen = 1;
125125
g.db = db;
126126
return SQLITE_OK;
127127
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -112,15 +112,15 @@
112 static int sqlcmd_autoinit(
113 sqlite3 *db,
114 const char **pzErrMsg,
115 const void *notUsed
116 ){
117 sqlite3_create_function(db, "content", 1, SQLITE_ANY, 0,
118 sqlcmd_content, 0, 0);
119 sqlite3_create_function(db, "compress", 1, SQLITE_ANY, 0,
120 sqlcmd_compress, 0, 0);
121 sqlite3_create_function(db, "decompress", 1, SQLITE_ANY, 0,
122 sqlcmd_decompress, 0, 0);
123 re_add_sql_func(db);
124 g.repositoryOpen = 1;
125 g.db = db;
126 return SQLITE_OK;
127
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -112,15 +112,15 @@
112 static int sqlcmd_autoinit(
113 sqlite3 *db,
114 const char **pzErrMsg,
115 const void *notUsed
116 ){
117 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
118 sqlcmd_content, 0, 0);
119 sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
120 sqlcmd_compress, 0, 0);
121 sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
122 sqlcmd_decompress, 0, 0);
123 re_add_sql_func(db);
124 g.repositoryOpen = 1;
125 g.db = db;
126 return SQLITE_OK;
127
+1252 -686
--- 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.8.4.1. By combining all the individual C code files into this
3
+** version 3.8.5. 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.
@@ -220,13 +220,13 @@
220220
**
221221
** See also: [sqlite3_libversion()],
222222
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
223223
** [sqlite_version()] and [sqlite_source_id()].
224224
*/
225
-#define SQLITE_VERSION "3.8.4.1"
226
-#define SQLITE_VERSION_NUMBER 3008004
227
-#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0"
225
+#define SQLITE_VERSION "3.8.5"
226
+#define SQLITE_VERSION_NUMBER 3008005
227
+#define SQLITE_SOURCE_ID "2014-04-18 22:20:31 9a5d38c79d2482a23bcfbc3ff35ca4fa269c768d"
228228
229229
/*
230230
** CAPI3REF: Run-Time Library Version Numbers
231231
** KEYWORDS: sqlite3_version, sqlite3_sourceid
232232
**
@@ -6236,11 +6236,12 @@
62366236
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
62376237
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
62386238
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
62396239
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
62406240
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
6241
-#define SQLITE_TESTCTRL_LAST 21
6241
+#define SQLITE_TESTCTRL_BYTEORDER 22
6242
+#define SQLITE_TESTCTRL_LAST 22
62426243
62436244
/*
62446245
** CAPI3REF: SQLite Runtime Status
62456246
**
62466247
** ^This interface is used to retrieve runtime status information
@@ -8437,26 +8438,43 @@
84378438
*/
84388439
typedef INT16_TYPE LogEst;
84398440
84408441
/*
84418442
** Macros to determine whether the machine is big or little endian,
8442
-** evaluated at runtime.
8443
+** and whether or not that determination is run-time or compile-time.
8444
+**
8445
+** For best performance, an attempt is made to guess at the byte-order
8446
+** using C-preprocessor macros. If that is unsuccessful, or if
8447
+** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
8448
+** at run-time.
84438449
*/
84448450
#ifdef SQLITE_AMALGAMATION
84458451
SQLITE_PRIVATE const int sqlite3one = 1;
84468452
#else
84478453
SQLITE_PRIVATE const int sqlite3one;
84488454
#endif
8449
-#if defined(i386) || defined(__i386__) || defined(_M_IX86)\
8450
- || defined(__x86_64) || defined(__x86_64__)
8455
+#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
8456
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
8457
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
8458
+ defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
8459
+# define SQLITE_BYTEORDER 1234
84518460
# define SQLITE_BIGENDIAN 0
84528461
# define SQLITE_LITTLEENDIAN 1
84538462
# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
8454
-#else
8463
+#endif
8464
+#if (defined(sparc) || defined(__ppc__)) \
8465
+ && !defined(SQLITE_RUNTIME_BYTEORDER)
8466
+# define SQLITE_BYTEORDER 4321
8467
+# define SQLITE_BIGENDIAN 1
8468
+# define SQLITE_LITTLEENDIAN 0
8469
+# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
8470
+#endif
8471
+#if !defined(SQLITE_BYTEORDER)
8472
+# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
84558473
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
84568474
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
8457
-# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
8475
+# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
84588476
#endif
84598477
84608478
/*
84618479
** Constants for the largest and smallest possible 64-bit signed integers.
84628480
** These macros are designed to work correctly on both 32-bit and 64-bit
@@ -8767,11 +8785,13 @@
87678785
#define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */
87688786
#define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */
87698787
87708788
SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
87718789
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
8772
-SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
8790
+#if SQLITE_MAX_MMAP_SIZE>0
8791
+SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
8792
+#endif
87738793
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
87748794
SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
87758795
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
87768796
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
87778797
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
@@ -8817,10 +8837,11 @@
88178837
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
88188838
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
88198839
88208840
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
88218841
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
8842
+SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*);
88228843
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
88238844
88248845
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
88258846
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
88268847
@@ -8891,11 +8912,11 @@
88918912
88928913
SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
88938914
SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
88948915
88958916
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
8896
-SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *);
8917
+SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
88978918
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
88988919
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
88998920
SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
89008921
89018922
#ifndef NDEBUG
@@ -9134,11 +9155,11 @@
91349155
#define OP_Next 9
91359156
#define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */
91369157
#define OP_Checkpoint 11
91379158
#define OP_JournalMode 12
91389159
#define OP_Vacuum 13
9139
-#define OP_VFilter 14 /* synopsis: iPlan=r[P3] zPlan='P4' */
9160
+#define OP_VFilter 14 /* synopsis: iplan=r[P3] zplan='P4' */
91409161
#define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */
91419162
#define OP_Goto 16
91429163
#define OP_Gosub 17
91439164
#define OP_Return 18
91449165
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
@@ -9161,11 +9182,11 @@
91619182
#define OP_CollSeq 36
91629183
#define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */
91639184
#define OP_MustBeInt 38
91649185
#define OP_RealAffinity 39
91659186
#define OP_Permutation 40
9166
-#define OP_Compare 41
9187
+#define OP_Compare 41 /* synopsis: r[P1@P3] <-> r[P2@P3] */
91679188
#define OP_Jump 42
91689189
#define OP_Once 43
91699190
#define OP_If 44
91709191
#define OP_IfNot 45
91719192
#define OP_Column 46 /* synopsis: r[P3]=PX */
@@ -9188,11 +9209,11 @@
91889209
#define OP_Seek 63 /* synopsis: intkey=r[P2] */
91899210
#define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */
91909211
#define OP_NotFound 65 /* synopsis: key=r[P3@P4] */
91919212
#define OP_Found 66 /* synopsis: key=r[P3@P4] */
91929213
#define OP_NotExists 67 /* synopsis: intkey=r[P3] */
9193
-#define OP_Sequence 68 /* synopsis: r[P2]=rowid */
9214
+#define OP_Sequence 68 /* synopsis: r[P2]=cursor[P1].ctr++ */
91949215
#define OP_NewRowid 69 /* synopsis: r[P2]=rowid */
91959216
#define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */
91969217
#define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
91979218
#define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
91989219
#define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */
@@ -9236,51 +9257,52 @@
92369257
#define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */
92379258
#define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */
92389259
#define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */
92399260
#define OP_Destroy 114
92409261
#define OP_Clear 115
9241
-#define OP_CreateIndex 116 /* synopsis: r[P2]=root iDb=P1 */
9242
-#define OP_CreateTable 117 /* synopsis: r[P2]=root iDb=P1 */
9243
-#define OP_ParseSchema 118
9244
-#define OP_LoadAnalysis 119
9245
-#define OP_DropTable 120
9246
-#define OP_DropIndex 121
9247
-#define OP_DropTrigger 122
9248
-#define OP_IntegrityCk 123
9249
-#define OP_RowSetAdd 124 /* synopsis: rowset(P1)=r[P2] */
9250
-#define OP_RowSetRead 125 /* synopsis: r[P3]=rowset(P1) */
9251
-#define OP_RowSetTest 126 /* synopsis: if r[P3] in rowset(P1) goto P2 */
9252
-#define OP_Program 127
9253
-#define OP_Param 128
9254
-#define OP_FkCounter 129 /* synopsis: fkctr[P1]+=P2 */
9255
-#define OP_FkIfZero 130 /* synopsis: if fkctr[P1]==0 goto P2 */
9256
-#define OP_MemMax 131 /* synopsis: r[P1]=max(r[P1],r[P2]) */
9257
-#define OP_IfPos 132 /* synopsis: if r[P1]>0 goto P2 */
9262
+#define OP_ResetSorter 116
9263
+#define OP_CreateIndex 117 /* synopsis: r[P2]=root iDb=P1 */
9264
+#define OP_CreateTable 118 /* synopsis: r[P2]=root iDb=P1 */
9265
+#define OP_ParseSchema 119
9266
+#define OP_LoadAnalysis 120
9267
+#define OP_DropTable 121
9268
+#define OP_DropIndex 122
9269
+#define OP_DropTrigger 123
9270
+#define OP_IntegrityCk 124
9271
+#define OP_RowSetAdd 125 /* synopsis: rowset(P1)=r[P2] */
9272
+#define OP_RowSetRead 126 /* synopsis: r[P3]=rowset(P1) */
9273
+#define OP_RowSetTest 127 /* synopsis: if r[P3] in rowset(P1) goto P2 */
9274
+#define OP_Program 128
9275
+#define OP_Param 129
9276
+#define OP_FkCounter 130 /* synopsis: fkctr[P1]+=P2 */
9277
+#define OP_FkIfZero 131 /* synopsis: if fkctr[P1]==0 goto P2 */
9278
+#define OP_MemMax 132 /* synopsis: r[P1]=max(r[P1],r[P2]) */
92589279
#define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
9259
-#define OP_IfNeg 134 /* synopsis: if r[P1]<0 goto P2 */
9260
-#define OP_IfZero 135 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
9261
-#define OP_AggFinal 136 /* synopsis: accum=r[P1] N=P2 */
9262
-#define OP_IncrVacuum 137
9263
-#define OP_Expire 138
9264
-#define OP_TableLock 139 /* synopsis: iDb=P1 root=P2 write=P3 */
9265
-#define OP_VBegin 140
9266
-#define OP_VCreate 141
9267
-#define OP_VDestroy 142
9280
+#define OP_IfPos 134 /* synopsis: if r[P1]>0 goto P2 */
9281
+#define OP_IfNeg 135 /* synopsis: if r[P1]<0 goto P2 */
9282
+#define OP_IfZero 136 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
9283
+#define OP_AggFinal 137 /* synopsis: accum=r[P1] N=P2 */
9284
+#define OP_IncrVacuum 138
9285
+#define OP_Expire 139
9286
+#define OP_TableLock 140 /* synopsis: iDb=P1 root=P2 write=P3 */
9287
+#define OP_VBegin 141
9288
+#define OP_VCreate 142
92689289
#define OP_ToText 143 /* same as TK_TO_TEXT */
92699290
#define OP_ToBlob 144 /* same as TK_TO_BLOB */
92709291
#define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */
92719292
#define OP_ToInt 146 /* same as TK_TO_INT */
92729293
#define OP_ToReal 147 /* same as TK_TO_REAL */
9273
-#define OP_VOpen 148
9274
-#define OP_VColumn 149 /* synopsis: r[P3]=vcolumn(P2) */
9275
-#define OP_VNext 150
9276
-#define OP_VRename 151
9277
-#define OP_Pagecount 152
9278
-#define OP_MaxPgcnt 153
9279
-#define OP_Init 154 /* synopsis: Start at P2 */
9280
-#define OP_Noop 155
9281
-#define OP_Explain 156
9294
+#define OP_VDestroy 148
9295
+#define OP_VOpen 149
9296
+#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */
9297
+#define OP_VNext 151
9298
+#define OP_VRename 152
9299
+#define OP_Pagecount 153
9300
+#define OP_MaxPgcnt 154
9301
+#define OP_Init 155 /* synopsis: Start at P2 */
9302
+#define OP_Noop 156
9303
+#define OP_Explain 157
92829304
92839305
92849306
/* Properties such as "out2" or "jump" that are specified in
92859307
** comments following the "case" for each opcode in the vdbe.c
92869308
** are encoded into bitvectors as follows:
@@ -9305,16 +9327,16 @@
93059327
/* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\
93069328
/* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\
93079329
/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\
93089330
/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
93099331
/* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\
9310
-/* 112 */ 0x01, 0x01, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00,\
9311
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15, 0x01,\
9312
-/* 128 */ 0x02, 0x00, 0x01, 0x08, 0x05, 0x02, 0x05, 0x05,\
9313
-/* 136 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\
9314
-/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x01, 0x00,\
9315
-/* 152 */ 0x02, 0x02, 0x01, 0x00, 0x00,}
9332
+/* 112 */ 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00,\
9333
+/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15,\
9334
+/* 128 */ 0x01, 0x02, 0x00, 0x01, 0x08, 0x02, 0x05, 0x05,\
9335
+/* 136 */ 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,\
9336
+/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x01,\
9337
+/* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,}
93169338
93179339
/************** End of opcodes.h *********************************************/
93189340
/************** Continuing where we left off in vdbe.h ***********************/
93199341
93209342
/*
@@ -9367,14 +9389,14 @@
93679389
#ifndef SQLITE_OMIT_TRACE
93689390
SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
93699391
#endif
93709392
93719393
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
9372
-SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int);
9394
+SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
93739395
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
93749396
9375
-typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int);
9397
+typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
93769398
SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
93779399
93789400
#ifndef SQLITE_OMIT_TRIGGER
93799401
SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
93809402
#endif
@@ -10996,10 +11018,11 @@
1099611018
*/
1099711019
struct UnpackedRecord {
1099811020
KeyInfo *pKeyInfo; /* Collation and sort-order information */
1099911021
u16 nField; /* Number of entries in apMem[] */
1100011022
i8 default_rc; /* Comparison result if keys are equal */
11023
+ u8 isCorrupt; /* Corruption detected by xRecordCompare() */
1100111024
Mem *aMem; /* Values */
1100211025
int r1; /* Value to return if (lhs > rhs) */
1100311026
int r2; /* Value to return if (rhs < lhs) */
1100411027
};
1100511028
@@ -11262,12 +11285,12 @@
1126211285
#define EP_Error 0x000008 /* Expression contains one or more errors */
1126311286
#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
1126411287
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
1126511288
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
1126611289
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
11267
-#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
11268
- /* unused 0x000200 */
11290
+#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
11291
+#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
1126911292
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
1127011293
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
1127111294
#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
1127211295
#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
1127311296
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
@@ -11327,11 +11350,10 @@
1132711350
** of the result column in the form: DATABASE.TABLE.COLUMN. This later
1132811351
** form is used for name resolution with nested FROM clauses.
1132911352
*/
1133011353
struct ExprList {
1133111354
int nExpr; /* Number of expressions on the list */
11332
- int iECursor; /* VDBE Cursor associated with this ExprList */
1133311355
struct ExprList_item { /* For each expression in the list */
1133411356
Expr *pExpr; /* The list of expressions */
1133511357
char *zName; /* Token associated with this expression */
1133611358
char *zSpan; /* Original text of the expression */
1133711359
u8 sortOrder; /* 1 for DESC or 0 for ASC */
@@ -11551,11 +11573,11 @@
1155111573
struct Select {
1155211574
ExprList *pEList; /* The fields of the result */
1155311575
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
1155411576
u16 selFlags; /* Various SF_* values */
1155511577
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
11556
- int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
11578
+ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
1155711579
u64 nSelectRow; /* Estimated number of result rows */
1155811580
SrcList *pSrc; /* The FROM clause */
1155911581
Expr *pWhere; /* The WHERE clause */
1156011582
ExprList *pGroupBy; /* The GROUP BY clause */
1156111583
Expr *pHaving; /* The HAVING clause */
@@ -11575,13 +11597,13 @@
1157511597
#define SF_Resolved 0x0002 /* Identifiers have been resolved */
1157611598
#define SF_Aggregate 0x0004 /* Contains aggregate functions */
1157711599
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
1157811600
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
1157911601
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
11580
-#define SF_UseSorter 0x0040 /* Sort using a sorter */
11602
+ /* 0x0040 NOT USED */
1158111603
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
11582
-#define SF_Materialize 0x0100 /* NOT USED */
11604
+ /* 0x0100 NOT USED */
1158311605
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
1158411606
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
1158511607
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
1158611608
#define SF_Compound 0x1000 /* Part of a compound query */
1158711609
@@ -11630,17 +11652,19 @@
1163011652
** of the co-routine is stored in register pDest->iSDParm
1163111653
** and the result row is stored in pDest->nDest registers
1163211654
** starting with pDest->iSdst.
1163311655
**
1163411656
** SRT_Table Store results in temporary table pDest->iSDParm.
11635
-** This is like SRT_EphemTab except that the table
11636
-** is assumed to already be open.
11657
+** SRT_Fifo This is like SRT_EphemTab except that the table
11658
+** is assumed to already be open. SRT_Fifo has
11659
+** the additional property of being able to ignore
11660
+** the ORDER BY clause.
1163711661
**
11638
-** SRT_DistTable Store results in a temporary table pDest->iSDParm.
11662
+** SRT_DistFifo Store results in a temporary table pDest->iSDParm.
1163911663
** But also use temporary table pDest->iSDParm+1 as
1164011664
** a record of all prior results and ignore any duplicate
11641
-** rows. Name means: "Distinct Table".
11665
+** rows. Name means: "Distinct Fifo".
1164211666
**
1164311667
** SRT_Queue Store results in priority queue pDest->iSDParm (really
1164411668
** an index). Append a sequence number so that all entries
1164511669
** are distinct.
1164611670
**
@@ -11650,23 +11674,24 @@
1165011674
*/
1165111675
#define SRT_Union 1 /* Store result as keys in an index */
1165211676
#define SRT_Except 2 /* Remove result from a UNION index */
1165311677
#define SRT_Exists 3 /* Store 1 if the result is not empty */
1165411678
#define SRT_Discard 4 /* Do not save the results anywhere */
11679
+#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
11680
+#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
11681
+#define SRT_Queue 7 /* Store result in an queue */
11682
+#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
1165511683
1165611684
/* The ORDER BY clause is ignored for all of the above */
11657
-#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard)
11658
-
11659
-#define SRT_Output 5 /* Output each row of result */
11660
-#define SRT_Mem 6 /* Store result in a memory cell */
11661
-#define SRT_Set 7 /* Store results as keys in an index */
11662
-#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
11663
-#define SRT_Coroutine 9 /* Generate a single row of result */
11664
-#define SRT_Table 10 /* Store result as data with an automatic rowid */
11665
-#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */
11666
-#define SRT_Queue 12 /* Store result in an queue */
11667
-#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */
11685
+#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
11686
+
11687
+#define SRT_Output 9 /* Output each row of result */
11688
+#define SRT_Mem 10 /* Store result in a memory cell */
11689
+#define SRT_Set 11 /* Store results as keys in an index */
11690
+#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
11691
+#define SRT_Coroutine 13 /* Generate a single row of result */
11692
+#define SRT_Table 14 /* Store result as data with an automatic rowid */
1166811693
1166911694
/*
1167011695
** An instance of this object describes where to put of the results of
1167111696
** a SELECT statement.
1167211697
*/
@@ -11760,12 +11785,10 @@
1176011785
int rc; /* Return code from execution */
1176111786
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
1176211787
u8 checkSchema; /* Causes schema cookie check after an error */
1176311788
u8 nested; /* Number of nested calls to the parser/code generator */
1176411789
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
11765
- u8 nColCache; /* Number of entries in aColCache[] */
11766
- u8 iColCache; /* Next entry in aColCache[] to replace */
1176711790
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
1176811791
u8 mayAbort; /* True if statement may throw an ABORT exception */
1176911792
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
1177011793
u8 okConstFactor; /* OK to factor out constants */
1177111794
int aTempReg[8]; /* Holding area for temporary registers */
@@ -12387,11 +12410,11 @@
1238712410
SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
1238812411
1238912412
SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
1239012413
SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*);
1239112414
SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
12392
-SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, u8 iBatch, i64);
12415
+SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64);
1239312416
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
1239412417
1239512418
SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
1239612419
1239712420
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -12451,11 +12474,11 @@
1245112474
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
1245212475
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
1245312476
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
1245412477
SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
1245512478
SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*);
12456
-SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int);
12479
+SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*);
1245712480
SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
1245812481
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
1245912482
SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
1246012483
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
1246112484
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
@@ -12503,10 +12526,11 @@
1250312526
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
1250412527
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
1250512528
SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
1250612529
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
1250712530
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
12531
+SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int);
1250812532
SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
1250912533
u8,u8,int,int*);
1251012534
SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
1251112535
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
1251212536
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
@@ -12660,11 +12684,11 @@
1266012684
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
1266112685
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
1266212686
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
1266312687
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
1266412688
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
12665
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
12689
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
1266612690
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
1266712691
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
1266812692
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
1266912693
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
1267012694
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
@@ -13745,10 +13769,11 @@
1374513769
u16 nHdrParsed; /* Number of header fields parsed so far */
1374613770
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
1374713771
u8 nullRow; /* True if pointing to a row with no data */
1374813772
u8 rowidIsValid; /* True if lastRowid is valid */
1374913773
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
13774
+ Bool isEphemeral:1; /* True for an ephemeral table */
1375013775
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
1375113776
Bool isTable:1; /* True if a table requiring integer keys */
1375213777
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
1375313778
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
1375413779
i64 seqCount; /* Sequence counter */
@@ -14064,11 +14089,11 @@
1406414089
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
1406514090
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
1406614091
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
1406714092
1406814093
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
14069
-SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*);
14094
+SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
1407014095
SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
1407114096
SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
1407214097
SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
1407314098
SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
1407414099
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
@@ -14110,10 +14135,11 @@
1411014135
SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
1411114136
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
1411214137
SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
1411314138
1411414139
SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
14140
+SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
1411514141
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
1411614142
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
1411714143
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
1411814144
SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
1411914145
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
@@ -17849,11 +17875,11 @@
1784917875
1785017876
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
1785117877
** block. If not, then split a block of the next larger power of
1785217878
** two in order to create a new free block of size iLogsize.
1785317879
*/
17854
- for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
17880
+ for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
1785517881
if( iBin>LOGMAX ){
1785617882
testcase( sqlite3GlobalConfig.xLog!=0 );
1785717883
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
1785817884
return 0;
1785917885
}
@@ -20159,24 +20185,10 @@
2015920185
*val = (*val - d)*10.0;
2016020186
return (char)digit;
2016120187
}
2016220188
#endif /* SQLITE_OMIT_FLOATING_POINT */
2016320189
20164
-/*
20165
-** Append N space characters to the given string buffer.
20166
-*/
20167
-SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){
20168
- static const char zSpaces[] = " ";
20169
- while( N>=(int)sizeof(zSpaces)-1 ){
20170
- sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
20171
- N -= sizeof(zSpaces)-1;
20172
- }
20173
- if( N>0 ){
20174
- sqlite3StrAccumAppend(pAccum, zSpaces, N);
20175
- }
20176
-}
20177
-
2017820190
/*
2017920191
** Set the StrAccum object to an error mode.
2018020192
*/
2018120193
static void setStrAccumError(StrAccum *p, u8 eError){
2018220194
p->accError = eError;
@@ -20262,15 +20274,13 @@
2026220274
}else{
2026320275
bArgList = useIntern = 0;
2026420276
}
2026520277
for(; (c=(*fmt))!=0; ++fmt){
2026620278
if( c!='%' ){
20267
- int amt;
2026820279
bufpt = (char *)fmt;
20269
- amt = 1;
20270
- while( (c=(*++fmt))!='%' && c!=0 ) amt++;
20271
- sqlite3StrAccumAppend(pAccum, bufpt, amt);
20280
+ while( (c=(*++fmt))!='%' && c!=0 ){};
20281
+ sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
2027220282
if( c==0 ) break;
2027320283
}
2027420284
if( (c=(*++fmt))==0 ){
2027520285
sqlite3StrAccumAppend(pAccum, "%", 1);
2027620286
break;
@@ -20447,14 +20457,12 @@
2044720457
}
2044820458
*(--bufpt) = zOrd[x*2+1];
2044920459
*(--bufpt) = zOrd[x*2];
2045020460
}
2045120461
{
20452
- register const char *cset; /* Use registers for speed */
20453
- register int base;
20454
- cset = &aDigits[infop->charset];
20455
- base = infop->base;
20462
+ const char *cset = &aDigits[infop->charset];
20463
+ u8 base = infop->base;
2045620464
do{ /* Convert to ascii */
2045720465
*(--bufpt) = cset[longvalue%base];
2045820466
longvalue = longvalue/base;
2045920467
}while( longvalue>0 );
2046020468
}
@@ -20754,77 +20762,102 @@
2075420762
/*
2075520763
** The text of the conversion is pointed to by "bufpt" and is
2075620764
** "length" characters long. The field width is "width". Do
2075720765
** the output.
2075820766
*/
20759
- if( !flag_leftjustify ){
20760
- register int nspace;
20761
- nspace = width-length;
20762
- if( nspace>0 ){
20763
- sqlite3AppendSpace(pAccum, nspace);
20764
- }
20765
- }
20766
- if( length>0 ){
20767
- sqlite3StrAccumAppend(pAccum, bufpt, length);
20768
- }
20769
- if( flag_leftjustify ){
20770
- register int nspace;
20771
- nspace = width-length;
20772
- if( nspace>0 ){
20773
- sqlite3AppendSpace(pAccum, nspace);
20774
- }
20775
- }
20767
+ width -= length;
20768
+ if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
20769
+ sqlite3StrAccumAppend(pAccum, bufpt, length);
20770
+ if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
20771
+
2077620772
if( zExtra ) sqlite3_free(zExtra);
2077720773
}/* End for loop over the format string */
2077820774
} /* End of function */
2077920775
2078020776
/*
20781
-** Append N bytes of text from z to the StrAccum object.
20777
+** Enlarge the memory allocation on a StrAccum object so that it is
20778
+** able to accept at least N more bytes of text.
20779
+**
20780
+** Return the number of bytes of text that StrAccum is able to accept
20781
+** after the attempted enlargement. The value returned might be zero.
20782
+*/
20783
+static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
20784
+ char *zNew;
20785
+ assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
20786
+ if( p->accError ){
20787
+ testcase(p->accError==STRACCUM_TOOBIG);
20788
+ testcase(p->accError==STRACCUM_NOMEM);
20789
+ return 0;
20790
+ }
20791
+ if( !p->useMalloc ){
20792
+ N = p->nAlloc - p->nChar - 1;
20793
+ setStrAccumError(p, STRACCUM_TOOBIG);
20794
+ return N;
20795
+ }else{
20796
+ char *zOld = (p->zText==p->zBase ? 0 : p->zText);
20797
+ i64 szNew = p->nChar;
20798
+ szNew += N + 1;
20799
+ if( szNew > p->mxAlloc ){
20800
+ sqlite3StrAccumReset(p);
20801
+ setStrAccumError(p, STRACCUM_TOOBIG);
20802
+ return 0;
20803
+ }else{
20804
+ p->nAlloc = (int)szNew;
20805
+ }
20806
+ if( p->useMalloc==1 ){
20807
+ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
20808
+ }else{
20809
+ zNew = sqlite3_realloc(zOld, p->nAlloc);
20810
+ }
20811
+ if( zNew ){
20812
+ if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
20813
+ p->zText = zNew;
20814
+ }else{
20815
+ sqlite3StrAccumReset(p);
20816
+ setStrAccumError(p, STRACCUM_NOMEM);
20817
+ return 0;
20818
+ }
20819
+ }
20820
+ return N;
20821
+}
20822
+
20823
+/*
20824
+** Append N space characters to the given string buffer.
20825
+*/
20826
+SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){
20827
+ if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
20828
+ while( (N--)>0 ) p->zText[p->nChar++] = ' ';
20829
+}
20830
+
20831
+/*
20832
+** The StrAccum "p" is not large enough to accept N new bytes of z[].
20833
+** So enlarge if first, then do the append.
20834
+**
20835
+** This is a helper routine to sqlite3StrAccumAppend() that does special-case
20836
+** work (enlarging the buffer) using tail recursion, so that the
20837
+** sqlite3StrAccumAppend() routine can use fast calling semantics.
20838
+*/
20839
+static void enlargeAndAppend(StrAccum *p, const char *z, int N){
20840
+ N = sqlite3StrAccumEnlarge(p, N);
20841
+ if( N>0 ){
20842
+ memcpy(&p->zText[p->nChar], z, N);
20843
+ p->nChar += N;
20844
+ }
20845
+}
20846
+
20847
+/*
20848
+** Append N bytes of text from z to the StrAccum object. Increase the
20849
+** size of the memory allocation for StrAccum if necessary.
2078220850
*/
2078320851
SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
2078420852
assert( z!=0 );
2078520853
assert( p->zText!=0 || p->nChar==0 || p->accError );
2078620854
assert( N>=0 );
2078720855
assert( p->accError==0 || p->nAlloc==0 );
2078820856
if( p->nChar+N >= p->nAlloc ){
20789
- char *zNew;
20790
- if( p->accError ){
20791
- testcase(p->accError==STRACCUM_TOOBIG);
20792
- testcase(p->accError==STRACCUM_NOMEM);
20793
- return;
20794
- }
20795
- if( !p->useMalloc ){
20796
- N = p->nAlloc - p->nChar - 1;
20797
- setStrAccumError(p, STRACCUM_TOOBIG);
20798
- if( N<=0 ){
20799
- return;
20800
- }
20801
- }else{
20802
- char *zOld = (p->zText==p->zBase ? 0 : p->zText);
20803
- i64 szNew = p->nChar;
20804
- szNew += N + 1;
20805
- if( szNew > p->mxAlloc ){
20806
- sqlite3StrAccumReset(p);
20807
- setStrAccumError(p, STRACCUM_TOOBIG);
20808
- return;
20809
- }else{
20810
- p->nAlloc = (int)szNew;
20811
- }
20812
- if( p->useMalloc==1 ){
20813
- zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
20814
- }else{
20815
- zNew = sqlite3_realloc(zOld, p->nAlloc);
20816
- }
20817
- if( zNew ){
20818
- if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
20819
- p->zText = zNew;
20820
- }else{
20821
- sqlite3StrAccumReset(p);
20822
- setStrAccumError(p, STRACCUM_NOMEM);
20823
- return;
20824
- }
20825
- }
20857
+ enlargeAndAppend(p,z,N);
20858
+ return;
2082620859
}
2082720860
assert( p->zText );
2082820861
memcpy(&p->zText[p->nChar], z, N);
2082920862
p->nChar += N;
2083020863
}
@@ -23328,11 +23361,11 @@
2332823361
/* 9 */ "Next" OpHelp(""),
2332923362
/* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
2333023363
/* 11 */ "Checkpoint" OpHelp(""),
2333123364
/* 12 */ "JournalMode" OpHelp(""),
2333223365
/* 13 */ "Vacuum" OpHelp(""),
23333
- /* 14 */ "VFilter" OpHelp("iPlan=r[P3] zPlan='P4'"),
23366
+ /* 14 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
2333423367
/* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"),
2333523368
/* 16 */ "Goto" OpHelp(""),
2333623369
/* 17 */ "Gosub" OpHelp(""),
2333723370
/* 18 */ "Return" OpHelp(""),
2333823371
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
@@ -23355,11 +23388,11 @@
2335523388
/* 36 */ "CollSeq" OpHelp(""),
2335623389
/* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
2335723390
/* 38 */ "MustBeInt" OpHelp(""),
2335823391
/* 39 */ "RealAffinity" OpHelp(""),
2335923392
/* 40 */ "Permutation" OpHelp(""),
23360
- /* 41 */ "Compare" OpHelp(""),
23393
+ /* 41 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
2336123394
/* 42 */ "Jump" OpHelp(""),
2336223395
/* 43 */ "Once" OpHelp(""),
2336323396
/* 44 */ "If" OpHelp(""),
2336423397
/* 45 */ "IfNot" OpHelp(""),
2336523398
/* 46 */ "Column" OpHelp("r[P3]=PX"),
@@ -23382,11 +23415,11 @@
2338223415
/* 63 */ "Seek" OpHelp("intkey=r[P2]"),
2338323416
/* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"),
2338423417
/* 65 */ "NotFound" OpHelp("key=r[P3@P4]"),
2338523418
/* 66 */ "Found" OpHelp("key=r[P3@P4]"),
2338623419
/* 67 */ "NotExists" OpHelp("intkey=r[P3]"),
23387
- /* 68 */ "Sequence" OpHelp("r[P2]=rowid"),
23420
+ /* 68 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
2338823421
/* 69 */ "NewRowid" OpHelp("r[P2]=rowid"),
2338923422
/* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
2339023423
/* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
2339123424
/* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
2339223425
/* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
@@ -23430,51 +23463,52 @@
2343023463
/* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"),
2343123464
/* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"),
2343223465
/* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"),
2343323466
/* 114 */ "Destroy" OpHelp(""),
2343423467
/* 115 */ "Clear" OpHelp(""),
23435
- /* 116 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
23436
- /* 117 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
23437
- /* 118 */ "ParseSchema" OpHelp(""),
23438
- /* 119 */ "LoadAnalysis" OpHelp(""),
23439
- /* 120 */ "DropTable" OpHelp(""),
23440
- /* 121 */ "DropIndex" OpHelp(""),
23441
- /* 122 */ "DropTrigger" OpHelp(""),
23442
- /* 123 */ "IntegrityCk" OpHelp(""),
23443
- /* 124 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
23444
- /* 125 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
23445
- /* 126 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
23446
- /* 127 */ "Program" OpHelp(""),
23447
- /* 128 */ "Param" OpHelp(""),
23448
- /* 129 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
23449
- /* 130 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
23450
- /* 131 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
23451
- /* 132 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
23468
+ /* 116 */ "ResetSorter" OpHelp(""),
23469
+ /* 117 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
23470
+ /* 118 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
23471
+ /* 119 */ "ParseSchema" OpHelp(""),
23472
+ /* 120 */ "LoadAnalysis" OpHelp(""),
23473
+ /* 121 */ "DropTable" OpHelp(""),
23474
+ /* 122 */ "DropIndex" OpHelp(""),
23475
+ /* 123 */ "DropTrigger" OpHelp(""),
23476
+ /* 124 */ "IntegrityCk" OpHelp(""),
23477
+ /* 125 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
23478
+ /* 126 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
23479
+ /* 127 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
23480
+ /* 128 */ "Program" OpHelp(""),
23481
+ /* 129 */ "Param" OpHelp(""),
23482
+ /* 130 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
23483
+ /* 131 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
23484
+ /* 132 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
2345223485
/* 133 */ "Real" OpHelp("r[P2]=P4"),
23453
- /* 134 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"),
23454
- /* 135 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
23455
- /* 136 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
23456
- /* 137 */ "IncrVacuum" OpHelp(""),
23457
- /* 138 */ "Expire" OpHelp(""),
23458
- /* 139 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
23459
- /* 140 */ "VBegin" OpHelp(""),
23460
- /* 141 */ "VCreate" OpHelp(""),
23461
- /* 142 */ "VDestroy" OpHelp(""),
23486
+ /* 134 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
23487
+ /* 135 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"),
23488
+ /* 136 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
23489
+ /* 137 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
23490
+ /* 138 */ "IncrVacuum" OpHelp(""),
23491
+ /* 139 */ "Expire" OpHelp(""),
23492
+ /* 140 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
23493
+ /* 141 */ "VBegin" OpHelp(""),
23494
+ /* 142 */ "VCreate" OpHelp(""),
2346223495
/* 143 */ "ToText" OpHelp(""),
2346323496
/* 144 */ "ToBlob" OpHelp(""),
2346423497
/* 145 */ "ToNumeric" OpHelp(""),
2346523498
/* 146 */ "ToInt" OpHelp(""),
2346623499
/* 147 */ "ToReal" OpHelp(""),
23467
- /* 148 */ "VOpen" OpHelp(""),
23468
- /* 149 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
23469
- /* 150 */ "VNext" OpHelp(""),
23470
- /* 151 */ "VRename" OpHelp(""),
23471
- /* 152 */ "Pagecount" OpHelp(""),
23472
- /* 153 */ "MaxPgcnt" OpHelp(""),
23473
- /* 154 */ "Init" OpHelp("Start at P2"),
23474
- /* 155 */ "Noop" OpHelp(""),
23475
- /* 156 */ "Explain" OpHelp(""),
23500
+ /* 148 */ "VDestroy" OpHelp(""),
23501
+ /* 149 */ "VOpen" OpHelp(""),
23502
+ /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
23503
+ /* 151 */ "VNext" OpHelp(""),
23504
+ /* 152 */ "VRename" OpHelp(""),
23505
+ /* 153 */ "Pagecount" OpHelp(""),
23506
+ /* 154 */ "MaxPgcnt" OpHelp(""),
23507
+ /* 155 */ "Init" OpHelp("Start at P2"),
23508
+ /* 156 */ "Noop" OpHelp(""),
23509
+ /* 157 */ "Explain" OpHelp(""),
2347623510
};
2347723511
return azName[i];
2347823512
}
2347923513
#endif
2348023514
@@ -24010,10 +24044,11 @@
2401024044
return geteuid() ? 0 : fchown(fd,uid,gid);
2401124045
}
2401224046
2401324047
/* Forward reference */
2401424048
static int openDirectory(const char*, int*);
24049
+static int unixGetpagesize(void);
2401524050
2401624051
/*
2401724052
** Many system calls are accessed through pointer-to-functions so that
2401824053
** they may be overridden at runtime to facilitate fault injection during
2401924054
** testing and sandboxing. The following array holds the names and pointers
@@ -24132,10 +24167,13 @@
2413224167
#else
2413324168
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
2413424169
#endif
2413524170
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
2413624171
#endif
24172
+
24173
+ { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
24174
+#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
2413724175
2413824176
}; /* End of the overrideable system calls */
2413924177
2414024178
/*
2414124179
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -27792,10 +27830,40 @@
2779227830
#endif
2779327831
2779427832
return rc;
2779527833
}
2779627834
27835
+/*
27836
+** Return the system page size.
27837
+**
27838
+** This function should not be called directly by other code in this file.
27839
+** Instead, it should be called via macro osGetpagesize().
27840
+*/
27841
+static int unixGetpagesize(void){
27842
+#if defined(_BSD_SOURCE)
27843
+ return getpagesize();
27844
+#else
27845
+ return (int)sysconf(_SC_PAGESIZE);
27846
+#endif
27847
+}
27848
+
27849
+/*
27850
+** Return the minimum number of 32KB shm regions that should be mapped at
27851
+** a time, assuming that each mapping must be an integer multiple of the
27852
+** current system page-size.
27853
+**
27854
+** Usually, this is 1. The exception seems to be systems that are configured
27855
+** to use 64KB pages - in this case each mapping must cover at least two
27856
+** shm regions.
27857
+*/
27858
+static int unixShmRegionPerMap(void){
27859
+ int shmsz = 32*1024; /* SHM region size */
27860
+ int pgsz = osGetpagesize(); /* System page size */
27861
+ assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
27862
+ if( pgsz<shmsz ) return 1;
27863
+ return pgsz/shmsz;
27864
+}
2779727865
2779827866
/*
2779927867
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
2780027868
**
2780127869
** This is not a VFS shared-memory method; it is a utility function called
@@ -27803,14 +27871,15 @@
2780327871
*/
2780427872
static void unixShmPurge(unixFile *pFd){
2780527873
unixShmNode *p = pFd->pInode->pShmNode;
2780627874
assert( unixMutexHeld() );
2780727875
if( p && p->nRef==0 ){
27876
+ int nShmPerMap = unixShmRegionPerMap();
2780827877
int i;
2780927878
assert( p->pInode==pFd->pInode );
2781027879
sqlite3_mutex_free(p->mutex);
27811
- for(i=0; i<p->nRegion; i++){
27880
+ for(i=0; i<p->nRegion; i+=nShmPerMap){
2781227881
if( p->h>=0 ){
2781327882
osMunmap(p->apRegion[i], p->szRegion);
2781427883
}else{
2781527884
sqlite3_free(p->apRegion[i]);
2781627885
}
@@ -28013,10 +28082,12 @@
2801328082
){
2801428083
unixFile *pDbFd = (unixFile*)fd;
2801528084
unixShm *p;
2801628085
unixShmNode *pShmNode;
2801728086
int rc = SQLITE_OK;
28087
+ int nShmPerMap = unixShmRegionPerMap();
28088
+ int nReqRegion;
2801828089
2801928090
/* If the shared-memory file has not yet been opened, open it now. */
2802028091
if( pDbFd->pShm==0 ){
2802128092
rc = unixOpenSharedMemory(pDbFd);
2802228093
if( rc!=SQLITE_OK ) return rc;
@@ -28028,13 +28099,16 @@
2802828099
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
2802928100
assert( pShmNode->pInode==pDbFd->pInode );
2803028101
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
2803128102
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
2803228103
28033
- if( pShmNode->nRegion<=iRegion ){
28104
+ /* Minimum number of regions required to be mapped. */
28105
+ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
28106
+
28107
+ if( pShmNode->nRegion<nReqRegion ){
2803428108
char **apNew; /* New apRegion[] array */
28035
- int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
28109
+ int nByte = nReqRegion*szRegion; /* Minimum required file size */
2803628110
struct stat sStat; /* Used by fstat() */
2803728111
2803828112
pShmNode->szRegion = szRegion;
2803928113
2804028114
if( pShmNode->h>=0 ){
@@ -28079,21 +28153,23 @@
2807928153
}
2808028154
}
2808128155
2808228156
/* Map the requested memory region into this processes address space. */
2808328157
apNew = (char **)sqlite3_realloc(
28084
- pShmNode->apRegion, (iRegion+1)*sizeof(char *)
28158
+ pShmNode->apRegion, nReqRegion*sizeof(char *)
2808528159
);
2808628160
if( !apNew ){
2808728161
rc = SQLITE_IOERR_NOMEM;
2808828162
goto shmpage_out;
2808928163
}
2809028164
pShmNode->apRegion = apNew;
28091
- while(pShmNode->nRegion<=iRegion){
28165
+ while( pShmNode->nRegion<nReqRegion ){
28166
+ int nMap = szRegion*nShmPerMap;
28167
+ int i;
2809228168
void *pMem;
2809328169
if( pShmNode->h>=0 ){
28094
- pMem = osMmap(0, szRegion,
28170
+ pMem = osMmap(0, nMap,
2809528171
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
2809628172
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
2809728173
);
2809828174
if( pMem==MAP_FAILED ){
2809928175
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
@@ -28105,12 +28181,15 @@
2810528181
rc = SQLITE_NOMEM;
2810628182
goto shmpage_out;
2810728183
}
2810828184
memset(pMem, 0, szRegion);
2810928185
}
28110
- pShmNode->apRegion[pShmNode->nRegion] = pMem;
28111
- pShmNode->nRegion++;
28186
+
28187
+ for(i=0; i<nShmPerMap; i++){
28188
+ pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
28189
+ }
28190
+ pShmNode->nRegion += nShmPerMap;
2811228191
}
2811328192
}
2811428193
2811528194
shmpage_out:
2811628195
if( pShmNode->nRegion>iRegion ){
@@ -28320,23 +28399,10 @@
2832028399
pFd->mmapSize = 0;
2832128400
pFd->mmapSizeActual = 0;
2832228401
}
2832328402
}
2832428403
28325
-/*
28326
-** Return the system page size.
28327
-*/
28328
-static int unixGetPagesize(void){
28329
-#if HAVE_MREMAP
28330
- return 512;
28331
-#elif defined(_BSD_SOURCE)
28332
- return getpagesize();
28333
-#else
28334
- return (int)sysconf(_SC_PAGESIZE);
28335
-#endif
28336
-}
28337
-
2833828404
/*
2833928405
** Attempt to set the size of the memory mapping maintained by file
2834028406
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
2834128407
**
2834228408
** If successful, this function sets the following variables:
@@ -28369,12 +28435,16 @@
2836928435
assert( MAP_FAILED!=0 );
2837028436
2837128437
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
2837228438
2837328439
if( pOrig ){
28374
- const int szSyspage = unixGetPagesize();
28440
+#if HAVE_MREMAP
28441
+ i64 nReuse = pFd->mmapSize;
28442
+#else
28443
+ const int szSyspage = osGetpagesize();
2837528444
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
28445
+#endif
2837628446
u8 *pReq = &pOrig[nReuse];
2837728447
2837828448
/* Unmap any pages of the existing mapping that cannot be reused. */
2837928449
if( nReuse!=nOrig ){
2838028450
osMunmap(pReq, nOrig-nReuse);
@@ -31116,11 +31186,11 @@
3111631186
};
3111731187
unsigned int i; /* Loop counter */
3111831188
3111931189
/* Double-check that the aSyscall[] array has been constructed
3112031190
** correctly. See ticket [bb3a86e890c8e96ab] */
31121
- assert( ArraySize(aSyscall)==24 );
31191
+ assert( ArraySize(aSyscall)==25 );
3112231192
3112331193
/* Register all VFSes defined in the aVfs[] array */
3112431194
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
3112531195
sqlite3_vfs_register(&aVfs[i], i==0);
3112631196
}
@@ -38997,12 +39067,12 @@
3899739067
struct RowSetEntry *pEntry; /* List of entries using pRight */
3899839068
struct RowSetEntry *pLast; /* Last entry on the pEntry list */
3899939069
struct RowSetEntry *pFresh; /* Source of new entry objects */
3900039070
struct RowSetEntry *pForest; /* List of binary trees of entries */
3900139071
u16 nFresh; /* Number of objects on pFresh */
39002
- u8 rsFlags; /* Various flags */
39003
- u8 iBatch; /* Current insert batch */
39072
+ u16 rsFlags; /* Various flags */
39073
+ int iBatch; /* Current insert batch */
3900439074
};
3900539075
3900639076
/*
3900739077
** Allowed values for RowSet.rsFlags
3900839078
*/
@@ -39332,11 +39402,11 @@
3933239402
**
3933339403
** If this is the first test of a new batch and if there exist entires
3933439404
** on pRowSet->pEntry, then sort those entires into the forest at
3933539405
** pRowSet->pForest so that they can be tested.
3933639406
*/
39337
-SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
39407
+SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
3933839408
struct RowSetEntry *p, *pTree;
3933939409
3934039410
/* This routine is never called after sqlite3RowSetNext() */
3934139411
assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
3934239412
@@ -41159,16 +41229,15 @@
4115941229
assert( pPager->setMaster==0 );
4116041230
assert( !pagerUseWal(pPager) );
4116141231
4116241232
if( !zMaster
4116341233
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
41164
- || pPager->journalMode==PAGER_JOURNALMODE_OFF
41234
+ || !isOpen(pPager->jfd)
4116541235
){
4116641236
return SQLITE_OK;
4116741237
}
4116841238
pPager->setMaster = 1;
41169
- assert( isOpen(pPager->jfd) );
4117041239
assert( pPager->journalHdr <= pPager->journalOff );
4117141240
4117241241
/* Calculate the length in bytes and the checksum of zMaster */
4117341242
for(nMaster=0; zMaster[nMaster]; nMaster++){
4117441243
cksum += zMaster[nMaster];
@@ -50371,31 +50440,34 @@
5037150440
struct BtCursor {
5037250441
Btree *pBtree; /* The Btree to which this cursor belongs */
5037350442
BtShared *pBt; /* The BtShared this cursor points to */
5037450443
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
5037550444
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
50376
-#ifndef SQLITE_OMIT_INCRBLOB
5037750445
Pgno *aOverflow; /* Cache of overflow page locations */
50378
-#endif
50446
+ CellInfo info; /* A parse of the cell we are pointing at */
50447
+ i64 nKey; /* Size of pKey, or last integer key */
50448
+ void *pKey; /* Saved key that was cursor last known position */
5037950449
Pgno pgnoRoot; /* The root page of this tree */
50380
- CellInfo info; /* A parse of the cell we are pointing at */
50381
- i64 nKey; /* Size of pKey, or last integer key */
50382
- void *pKey; /* Saved key that was cursor's last known position */
50450
+ int nOvflAlloc; /* Allocated size of aOverflow[] array */
5038350451
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
50384
- u8 wrFlag; /* True if writable */
50385
- u8 atLast; /* Cursor pointing to the last entry */
50386
- u8 validNKey; /* True if info.nKey is valid */
50452
+ u8 curFlags; /* zero or more BTCF_* flags defined below */
5038750453
u8 eState; /* One of the CURSOR_XXX constants (see below) */
50388
-#ifndef SQLITE_OMIT_INCRBLOB
50389
- u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
50390
-#endif
5039150454
u8 hints; /* As configured by CursorSetHints() */
5039250455
i16 iPage; /* Index of current page in apPage */
5039350456
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
5039450457
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
5039550458
};
5039650459
50460
+/*
50461
+** Legal values for BtCursor.curFlags
50462
+*/
50463
+#define BTCF_WriteFlag 0x01 /* True if a write cursor */
50464
+#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
50465
+#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
50466
+#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
50467
+#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
50468
+
5039750469
/*
5039850470
** Potential values for BtCursor.eState.
5039950471
**
5040050472
** CURSOR_INVALID:
5040150473
** Cursor does not point to a valid entry. This can happen (for example)
@@ -51262,20 +51334,15 @@
5126251334
static int cursorHoldsMutex(BtCursor *p){
5126351335
return sqlite3_mutex_held(p->pBt->mutex);
5126451336
}
5126551337
#endif
5126651338
51267
-
51268
-#ifndef SQLITE_OMIT_INCRBLOB
5126951339
/*
51270
-** Invalidate the overflow page-list cache for cursor pCur, if any.
51340
+** Invalidate the overflow cache of the cursor passed as the first argument.
51341
+** on the shared btree structure pBt.
5127151342
*/
51272
-static void invalidateOverflowCache(BtCursor *pCur){
51273
- assert( cursorHoldsMutex(pCur) );
51274
- sqlite3_free(pCur->aOverflow);
51275
- pCur->aOverflow = 0;
51276
-}
51343
+#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
5127751344
5127851345
/*
5127951346
** Invalidate the overflow page-list cache for all cursors opened
5128051347
** on the shared btree structure pBt.
5128151348
*/
@@ -51285,10 +51352,11 @@
5128551352
for(p=pBt->pCursor; p; p=p->pNext){
5128651353
invalidateOverflowCache(p);
5128751354
}
5128851355
}
5128951356
51357
+#ifndef SQLITE_OMIT_INCRBLOB
5129051358
/*
5129151359
** This function is called before modifying the contents of a table
5129251360
** to invalidate any incrblob cursors that are open on the
5129351361
** row or one of the rows being modified.
5129451362
**
@@ -51307,20 +51375,18 @@
5130751375
){
5130851376
BtCursor *p;
5130951377
BtShared *pBt = pBtree->pBt;
5131051378
assert( sqlite3BtreeHoldsMutex(pBtree) );
5131151379
for(p=pBt->pCursor; p; p=p->pNext){
51312
- if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){
51380
+ if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
5131351381
p->eState = CURSOR_INVALID;
5131451382
}
5131551383
}
5131651384
}
5131751385
5131851386
#else
51319
- /* Stub functions when INCRBLOB is omitted */
51320
- #define invalidateOverflowCache(x)
51321
- #define invalidateAllOverflowCache(x)
51387
+ /* Stub function when INCRBLOB is omitted */
5132251388
#define invalidateIncrblobCursors(x,y,z)
5132351389
#endif /* SQLITE_OMIT_INCRBLOB */
5132451390
5132551391
/*
5132651392
** Set bit pgno of the BtShared.pHasContent bitvec. This is called
@@ -51562,24 +51628,36 @@
5156251628
** Determine whether or not a cursor has moved from the position it
5156351629
** was last placed at. Cursors can move when the row they are pointing
5156451630
** at is deleted out from under them.
5156551631
**
5156651632
** This routine returns an error code if something goes wrong. The
51567
-** integer *pHasMoved is set to one if the cursor has moved and 0 if not.
51633
+** integer *pHasMoved is set as follows:
51634
+**
51635
+** 0: The cursor is unchanged
51636
+** 1: The cursor is still pointing at the same row, but the pointers
51637
+** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
51638
+** might now be invalid because of a balance() or other change to the
51639
+** b-tree.
51640
+** 2: The cursor is no longer pointing to the row. The row might have
51641
+** been deleted out from under the cursor.
5156851642
*/
5156951643
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
5157051644
int rc;
5157151645
51646
+ if( pCur->eState==CURSOR_VALID ){
51647
+ *pHasMoved = 0;
51648
+ return SQLITE_OK;
51649
+ }
5157251650
rc = restoreCursorPosition(pCur);
5157351651
if( rc ){
51574
- *pHasMoved = 1;
51652
+ *pHasMoved = 2;
5157551653
return rc;
5157651654
}
5157751655
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
51656
+ *pHasMoved = 2;
51657
+ }else{
5157851658
*pHasMoved = 1;
51579
- }else{
51580
- *pHasMoved = 0;
5158151659
}
5158251660
return SQLITE_OK;
5158351661
}
5158451662
5158551663
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -52977,10 +53055,11 @@
5297753055
sqlite3PagerSetCachesize(pBt->pPager, mxPage);
5297853056
sqlite3BtreeLeave(p);
5297953057
return SQLITE_OK;
5298053058
}
5298153059
53060
+#if SQLITE_MAX_MMAP_SIZE>0
5298253061
/*
5298353062
** Change the limit on the amount of the database file that may be
5298453063
** memory mapped.
5298553064
*/
5298653065
SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
@@ -52989,10 +53068,11 @@
5298953068
sqlite3BtreeEnter(p);
5299053069
sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
5299153070
sqlite3BtreeLeave(p);
5299253071
return SQLITE_OK;
5299353072
}
53073
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
5299453074
5299553075
/*
5299653076
** Change the way data is synced to disk in order to increase or decrease
5299753077
** how well the database resists damage due to OS crashes and power
5299853078
** failures. Level 1 is the same as asynchronous (no syncs() occur and
@@ -53365,11 +53445,12 @@
5336553445
*/
5336653446
static int countValidCursors(BtShared *pBt, int wrOnly){
5336753447
BtCursor *pCur;
5336853448
int r = 0;
5336953449
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
53370
- if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
53450
+ if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
53451
+ && pCur->eState!=CURSOR_FAULT ) r++;
5337153452
}
5337253453
return r;
5337353454
}
5337453455
#endif
5337553456
@@ -54440,11 +54521,12 @@
5444054521
pCur->pgnoRoot = (Pgno)iTable;
5444154522
pCur->iPage = -1;
5444254523
pCur->pKeyInfo = pKeyInfo;
5444354524
pCur->pBtree = p;
5444454525
pCur->pBt = pBt;
54445
- pCur->wrFlag = (u8)wrFlag;
54526
+ assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
54527
+ pCur->curFlags = wrFlag;
5444654528
pCur->pNext = pBt->pCursor;
5444754529
if( pCur->pNext ){
5444854530
pCur->pNext->pPrev = pCur;
5444954531
}
5445054532
pBt->pCursor = pCur;
@@ -54510,11 +54592,11 @@
5451054592
}
5451154593
for(i=0; i<=pCur->iPage; i++){
5451254594
releasePage(pCur->apPage[i]);
5451354595
}
5451454596
unlockBtreeIfUnused(pBt);
54515
- invalidateOverflowCache(pCur);
54597
+ sqlite3DbFree(pBtree->db, pCur->aOverflow);
5451654598
/* sqlite3_free(pCur); */
5451754599
sqlite3BtreeLeave(pBtree);
5451854600
}
5451954601
return SQLITE_OK;
5452054602
}
@@ -54549,22 +54631,22 @@
5454954631
/* Use a real function in MSVC to work around bugs in that compiler. */
5455054632
static void getCellInfo(BtCursor *pCur){
5455154633
if( pCur->info.nSize==0 ){
5455254634
int iPage = pCur->iPage;
5455354635
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
54554
- pCur->validNKey = 1;
54636
+ pCur->curFlags |= BTCF_ValidNKey;
5455554637
}else{
5455654638
assertCellInfo(pCur);
5455754639
}
5455854640
}
5455954641
#else /* if not _MSC_VER */
5456054642
/* Use a macro in all other compilers so that the function is inlined */
5456154643
#define getCellInfo(pCur) \
5456254644
if( pCur->info.nSize==0 ){ \
5456354645
int iPage = pCur->iPage; \
54564
- btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
54565
- pCur->validNKey = 1; \
54646
+ btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
54647
+ pCur->curFlags |= BTCF_ValidNKey; \
5456654648
}else{ \
5456754649
assertCellInfo(pCur); \
5456854650
}
5456954651
#endif /* _MSC_VER */
5457054652
@@ -54731,26 +54813,28 @@
5473154813
return SQLITE_OK;
5473254814
}
5473354815
5473454816
/*
5473554817
** This function is used to read or overwrite payload information
54736
-** for the entry that the pCur cursor is pointing to. If the eOp
54737
-** parameter is 0, this is a read operation (data copied into
54738
-** buffer pBuf). If it is non-zero, a write (data copied from
54739
-** buffer pBuf).
54818
+** for the entry that the pCur cursor is pointing to. The eOp
54819
+** argument is interpreted as follows:
54820
+**
54821
+** 0: The operation is a read. Populate the overflow cache.
54822
+** 1: The operation is a write. Populate the overflow cache.
54823
+** 2: The operation is a read. Do not populate the overflow cache.
5474054824
**
5474154825
** A total of "amt" bytes are read or written beginning at "offset".
5474254826
** Data is read to or from the buffer pBuf.
5474354827
**
5474454828
** The content being read or written might appear on the main page
5474554829
** or be scattered out on multiple overflow pages.
5474654830
**
54747
-** If the BtCursor.isIncrblobHandle flag is set, and the current
54748
-** cursor entry uses one or more overflow pages, this function
54749
-** allocates space for and lazily popluates the overflow page-list
54750
-** cache array (BtCursor.aOverflow). Subsequent calls use this
54751
-** cache to make seeking to the supplied offset more efficient.
54831
+** If the current cursor entry uses one or more overflow pages and the
54832
+** eOp argument is not 2, this function may allocate space for and lazily
54833
+** popluates the overflow page-list cache array (BtCursor.aOverflow).
54834
+** Subsequent calls use this cache to make seeking to the supplied offset
54835
+** more efficient.
5475254836
**
5475354837
** Once an overflow page-list cache has been allocated, it may be
5475454838
** invalidated if some other cursor writes to the same table, or if
5475554839
** the cursor is moved to a different row. Additionally, in auto-vacuum
5475654840
** mode, the following events may invalidate an overflow page-list cache.
@@ -54770,19 +54854,26 @@
5477054854
int rc = SQLITE_OK;
5477154855
u32 nKey;
5477254856
int iIdx = 0;
5477354857
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
5477454858
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
54859
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
54860
+ int bEnd; /* True if reading to end of data */
54861
+#endif
5477554862
5477654863
assert( pPage );
5477754864
assert( pCur->eState==CURSOR_VALID );
5477854865
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
5477954866
assert( cursorHoldsMutex(pCur) );
54867
+ assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
5478054868
5478154869
getCellInfo(pCur);
5478254870
aPayload = pCur->info.pCell + pCur->info.nHeader;
5478354871
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
54872
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
54873
+ bEnd = (offset+amt==nKey+pCur->info.nData);
54874
+#endif
5478454875
5478554876
if( NEVER(offset+amt > nKey+pCur->info.nData)
5478654877
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
5478754878
){
5478854879
/* Trying to read or write past the end of the data is an error */
@@ -54793,11 +54884,11 @@
5479354884
if( offset<pCur->info.nLocal ){
5479454885
int a = amt;
5479554886
if( a+offset>pCur->info.nLocal ){
5479654887
a = pCur->info.nLocal - offset;
5479754888
}
54798
- rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
54889
+ rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
5479954890
offset = 0;
5480054891
pBuf += a;
5480154892
amt -= a;
5480254893
}else{
5480354894
offset -= pCur->info.nLocal;
@@ -54807,62 +54898,72 @@
5480754898
const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
5480854899
Pgno nextPage;
5480954900
5481054901
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
5481154902
54812
-#ifndef SQLITE_OMIT_INCRBLOB
54813
- /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
54814
- ** has not been allocated, allocate it now. The array is sized at
54815
- ** one entry for each overflow page in the overflow chain. The
54816
- ** page number of the first overflow page is stored in aOverflow[0],
54817
- ** etc. A value of 0 in the aOverflow[] array means "not yet known"
54818
- ** (the cache is lazily populated).
54903
+ /* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
54904
+ ** Except, do not allocate aOverflow[] for eOp==2.
54905
+ **
54906
+ ** The aOverflow[] array is sized at one entry for each overflow page
54907
+ ** in the overflow chain. The page number of the first overflow page is
54908
+ ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
54909
+ ** means "not yet known" (the cache is lazily populated).
5481954910
*/
54820
- if( pCur->isIncrblobHandle && !pCur->aOverflow ){
54911
+ if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
5482154912
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
54822
- pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl);
54823
- /* nOvfl is always positive. If it were zero, fetchPayload would have
54824
- ** been used instead of this routine. */
54825
- if( ALWAYS(nOvfl) && !pCur->aOverflow ){
54826
- rc = SQLITE_NOMEM;
54913
+ if( nOvfl>pCur->nOvflAlloc ){
54914
+ Pgno *aNew = (Pgno*)sqlite3DbRealloc(
54915
+ pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
54916
+ );
54917
+ if( aNew==0 ){
54918
+ rc = SQLITE_NOMEM;
54919
+ }else{
54920
+ pCur->nOvflAlloc = nOvfl*2;
54921
+ pCur->aOverflow = aNew;
54922
+ }
54923
+ }
54924
+ if( rc==SQLITE_OK ){
54925
+ memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
54926
+ pCur->curFlags |= BTCF_ValidOvfl;
5482754927
}
5482854928
}
5482954929
5483054930
/* If the overflow page-list cache has been allocated and the
5483154931
** entry for the first required overflow page is valid, skip
5483254932
** directly to it.
5483354933
*/
54834
- if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
54934
+ if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
5483554935
iIdx = (offset/ovflSize);
5483654936
nextPage = pCur->aOverflow[iIdx];
5483754937
offset = (offset%ovflSize);
5483854938
}
54839
-#endif
5484054939
5484154940
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
5484254941
54843
-#ifndef SQLITE_OMIT_INCRBLOB
5484454942
/* If required, populate the overflow page-list cache. */
54845
- if( pCur->aOverflow ){
54943
+ if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
5484654944
assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
5484754945
pCur->aOverflow[iIdx] = nextPage;
5484854946
}
54849
-#endif
5485054947
5485154948
if( offset>=ovflSize ){
5485254949
/* The only reason to read this page is to obtain the page
5485354950
** number for the next page in the overflow chain. The page
5485454951
** data is not required. So first try to lookup the overflow
5485554952
** page-list cache, if any, then fall back to the getOverflowPage()
5485654953
** function.
54954
+ **
54955
+ ** Note that the aOverflow[] array must be allocated because eOp!=2
54956
+ ** here. If eOp==2, then offset==0 and this branch is never taken.
5485754957
*/
54858
-#ifndef SQLITE_OMIT_INCRBLOB
54859
- if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
54958
+ assert( eOp!=2 );
54959
+ assert( pCur->curFlags & BTCF_ValidOvfl );
54960
+ if( pCur->aOverflow[iIdx+1] ){
5486054961
nextPage = pCur->aOverflow[iIdx+1];
54861
- } else
54862
-#endif
54962
+ }else{
5486354963
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
54964
+ }
5486454965
offset -= ovflSize;
5486554966
}else{
5486654967
/* Need to read this page properly. It contains some of the
5486754968
** range of data that is being read (eOp==0) or written (eOp!=0).
5486854969
*/
@@ -54880,17 +54981,19 @@
5488054981
** 1) this is a read operation, and
5488154982
** 2) data is required from the start of this overflow page, and
5488254983
** 3) the database is file-backed, and
5488354984
** 4) there is no open write-transaction, and
5488454985
** 5) the database is not a WAL database,
54986
+ ** 6) all data from the page is being read.
5488554987
**
5488654988
** then data can be read directly from the database file into the
5488754989
** output buffer, bypassing the page-cache altogether. This speeds
5488854990
** up loading large records that span many overflow pages.
5488954991
*/
54890
- if( eOp==0 /* (1) */
54992
+ if( (eOp&0x01)==0 /* (1) */
5489154993
&& offset==0 /* (2) */
54994
+ && (bEnd || a==ovflSize) /* (6) */
5489254995
&& pBt->inTransaction==TRANS_READ /* (4) */
5489354996
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
5489454997
&& pBt->pPage1->aData[19]==0x01 /* (5) */
5489554998
){
5489654999
u8 aSave[4];
@@ -54903,16 +55006,16 @@
5490355006
#endif
5490455007
5490555008
{
5490655009
DbPage *pDbPage;
5490755010
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
54908
- (eOp==0 ? PAGER_GET_READONLY : 0)
55011
+ ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
5490955012
);
5491055013
if( rc==SQLITE_OK ){
5491155014
aPayload = sqlite3PagerGetData(pDbPage);
5491255015
nextPage = get4byte(aPayload);
54913
- rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
55016
+ rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
5491455017
sqlite3PagerUnref(pDbPage);
5491555018
offset = 0;
5491655019
}
5491755020
}
5491855021
amt -= a;
@@ -55002,14 +55105,17 @@
5500255105
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
5500355106
assert( pCur->eState==CURSOR_VALID );
5500455107
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
5500555108
assert( cursorHoldsMutex(pCur) );
5500655109
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
55110
+ assert( pCur->info.nSize>0 );
55111
+#if 0
5500755112
if( pCur->info.nSize==0 ){
5500855113
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
5500955114
&pCur->info);
5501055115
}
55116
+#endif
5501155117
*pAmt = pCur->info.nLocal;
5501255118
return (void*)(pCur->info.pCell + pCur->info.nHeader);
5501355119
}
5501455120
5501555121
@@ -55056,18 +55162,18 @@
5505655162
assert( pCur->iPage>=0 );
5505755163
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
5505855164
return SQLITE_CORRUPT_BKPT;
5505955165
}
5506055166
rc = getAndInitPage(pBt, newPgno, &pNewPage,
55061
- pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
55167
+ (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
5506255168
if( rc ) return rc;
5506355169
pCur->apPage[i+1] = pNewPage;
5506455170
pCur->aiIdx[i+1] = 0;
5506555171
pCur->iPage++;
5506655172
5506755173
pCur->info.nSize = 0;
55068
- pCur->validNKey = 0;
55174
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
5506955175
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
5507055176
return SQLITE_CORRUPT_BKPT;
5507155177
}
5507255178
return SQLITE_OK;
5507355179
}
@@ -55121,11 +55227,11 @@
5512155227
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
5512255228
5512355229
releasePage(pCur->apPage[pCur->iPage]);
5512455230
pCur->iPage--;
5512555231
pCur->info.nSize = 0;
55126
- pCur->validNKey = 0;
55232
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
5512755233
}
5512855234
5512955235
/*
5513055236
** Move the cursor to point to the root page of its b-tree structure.
5513155237
**
@@ -55168,11 +55274,11 @@
5516855274
}else if( pCur->pgnoRoot==0 ){
5516955275
pCur->eState = CURSOR_INVALID;
5517055276
return SQLITE_OK;
5517155277
}else{
5517255278
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
55173
- pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
55279
+ (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
5517455280
if( rc!=SQLITE_OK ){
5517555281
pCur->eState = CURSOR_INVALID;
5517655282
return rc;
5517755283
}
5517855284
pCur->iPage = 0;
@@ -55195,12 +55301,11 @@
5519555301
return SQLITE_CORRUPT_BKPT;
5519655302
}
5519755303
5519855304
pCur->aiIdx[0] = 0;
5519955305
pCur->info.nSize = 0;
55200
- pCur->atLast = 0;
55201
- pCur->validNKey = 0;
55306
+ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
5520255307
5520355308
if( pRoot->nCell>0 ){
5520455309
pCur->eState = CURSOR_VALID;
5520555310
}else if( !pRoot->leaf ){
5520655311
Pgno subpage;
@@ -55259,11 +55364,11 @@
5525955364
rc = moveToChild(pCur, pgno);
5526055365
}
5526155366
if( rc==SQLITE_OK ){
5526255367
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
5526355368
pCur->info.nSize = 0;
55264
- pCur->validNKey = 0;
55369
+ pCur->curFlags &= ~BTCF_ValidNKey;
5526555370
}
5526655371
return rc;
5526755372
}
5526855373
5526955374
/* Move the cursor to the first entry in the table. Return SQLITE_OK
@@ -55298,11 +55403,11 @@
5529855403
5529955404
assert( cursorHoldsMutex(pCur) );
5530055405
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
5530155406
5530255407
/* If the cursor already points to the last entry, this is a no-op. */
55303
- if( CURSOR_VALID==pCur->eState && pCur->atLast ){
55408
+ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
5530455409
#ifdef SQLITE_DEBUG
5530555410
/* This block serves to assert() that the cursor really does point
5530655411
** to the last entry in the b-tree. */
5530755412
int ii;
5530855413
for(ii=0; ii<pCur->iPage; ii++){
@@ -55321,11 +55426,16 @@
5532155426
*pRes = 1;
5532255427
}else{
5532355428
assert( pCur->eState==CURSOR_VALID );
5532455429
*pRes = 0;
5532555430
rc = moveToRightmost(pCur);
55326
- pCur->atLast = rc==SQLITE_OK ?1:0;
55431
+ if( rc==SQLITE_OK ){
55432
+ pCur->curFlags |= BTCF_AtLast;
55433
+ }else{
55434
+ pCur->curFlags &= ~BTCF_AtLast;
55435
+ }
55436
+
5532755437
}
5532855438
}
5532955439
return rc;
5533055440
}
5533155441
@@ -55372,25 +55482,26 @@
5537255482
assert( pRes );
5537355483
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
5537455484
5537555485
/* If the cursor is already positioned at the point we are trying
5537655486
** to move to, then just return without doing any work */
55377
- if( pCur->eState==CURSOR_VALID && pCur->validNKey
55487
+ if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
5537855488
&& pCur->apPage[0]->intKey
5537955489
){
5538055490
if( pCur->info.nKey==intKey ){
5538155491
*pRes = 0;
5538255492
return SQLITE_OK;
5538355493
}
55384
- if( pCur->atLast && pCur->info.nKey<intKey ){
55494
+ if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
5538555495
*pRes = -1;
5538655496
return SQLITE_OK;
5538755497
}
5538855498
}
5538955499
5539055500
if( pIdxKey ){
5539155501
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
55502
+ pIdxKey->isCorrupt = 0;
5539255503
assert( pIdxKey->default_rc==1
5539355504
|| pIdxKey->default_rc==0
5539455505
|| pIdxKey->default_rc==-1
5539555506
);
5539655507
}else{
@@ -55445,11 +55556,11 @@
5544555556
}else if( nCellKey>intKey ){
5544655557
upr = idx-1;
5544755558
if( lwr>upr ){ c = +1; break; }
5544855559
}else{
5544955560
assert( nCellKey==intKey );
55450
- pCur->validNKey = 1;
55561
+ pCur->curFlags |= BTCF_ValidNKey;
5545155562
pCur->info.nKey = nCellKey;
5545255563
pCur->aiIdx[pCur->iPage] = (u16)idx;
5545355564
if( !pPage->leaf ){
5545455565
lwr = idx;
5545555566
goto moveto_next_layer;
@@ -55502,27 +55613,29 @@
5550255613
if( pCellKey==0 ){
5550355614
rc = SQLITE_NOMEM;
5550455615
goto moveto_finish;
5550555616
}
5550655617
pCur->aiIdx[pCur->iPage] = (u16)idx;
55507
- rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
55618
+ rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
5550855619
if( rc ){
5550955620
sqlite3_free(pCellKey);
5551055621
goto moveto_finish;
5551155622
}
5551255623
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
5551355624
sqlite3_free(pCellKey);
5551455625
}
55626
+ assert( pIdxKey->isCorrupt==0 || c==0 );
5551555627
if( c<0 ){
5551655628
lwr = idx+1;
5551755629
}else if( c>0 ){
5551855630
upr = idx-1;
5551955631
}else{
5552055632
assert( c==0 );
5552155633
*pRes = 0;
5552255634
rc = SQLITE_OK;
5552355635
pCur->aiIdx[pCur->iPage] = (u16)idx;
55636
+ if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
5552455637
goto moveto_finish;
5552555638
}
5552655639
if( lwr>upr ) break;
5552755640
assert( lwr+upr>=0 );
5552855641
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
@@ -55547,11 +55660,11 @@
5554755660
rc = moveToChild(pCur, chldPg);
5554855661
if( rc ) break;
5554955662
}
5555055663
moveto_finish:
5555155664
pCur->info.nSize = 0;
55552
- pCur->validNKey = 0;
55665
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
5555355666
return rc;
5555455667
}
5555555668
5555655669
5555755670
/*
@@ -55592,10 +55705,11 @@
5559255705
assert( cursorHoldsMutex(pCur) );
5559355706
assert( pRes!=0 );
5559455707
assert( *pRes==0 || *pRes==1 );
5559555708
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
5559655709
if( pCur->eState!=CURSOR_VALID ){
55710
+ invalidateOverflowCache(pCur);
5559755711
rc = restoreCursorPosition(pCur);
5559855712
if( rc!=SQLITE_OK ){
5559955713
*pRes = 0;
5560055714
return rc;
5560155715
}
@@ -55625,11 +55739,11 @@
5562555739
** only happen if the database is corrupt in such a way as to link the
5562655740
** page into more than one b-tree structure. */
5562755741
testcase( idx>pPage->nCell );
5562855742
5562955743
pCur->info.nSize = 0;
55630
- pCur->validNKey = 0;
55744
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
5563155745
if( idx>=pPage->nCell ){
5563255746
if( !pPage->leaf ){
5563355747
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
5563455748
if( rc ){
5563555749
*pRes = 0;
@@ -55686,11 +55800,11 @@
5568655800
5568755801
assert( cursorHoldsMutex(pCur) );
5568855802
assert( pRes!=0 );
5568955803
assert( *pRes==0 || *pRes==1 );
5569055804
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
55691
- pCur->atLast = 0;
55805
+ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
5569255806
if( pCur->eState!=CURSOR_VALID ){
5569355807
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
5569455808
rc = btreeRestoreCursorPosition(pCur);
5569555809
if( rc!=SQLITE_OK ){
5569655810
*pRes = 0;
@@ -55731,11 +55845,11 @@
5573155845
return SQLITE_OK;
5573255846
}
5573355847
moveToParent(pCur);
5573455848
}
5573555849
pCur->info.nSize = 0;
55736
- pCur->validNKey = 0;
55850
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
5573755851
5573855852
pCur->aiIdx[pCur->iPage]--;
5573955853
pPage = pCur->apPage[pCur->iPage];
5574055854
if( pPage->intKey && !pPage->leaf ){
5574155855
rc = sqlite3BtreePrevious(pCur, pRes);
@@ -57756,11 +57870,11 @@
5775657870
assert( pCur->skipNext!=SQLITE_OK );
5775757871
return pCur->skipNext;
5775857872
}
5775957873
5776057874
assert( cursorHoldsMutex(pCur) );
57761
- assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
57875
+ assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
5776257876
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
5776357877
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
5776457878
5776557879
/* Assert that the caller has been consistent. If this cursor was opened
5776657880
** expecting an index b-tree, then the caller should be inserting blob
@@ -57789,11 +57903,11 @@
5778957903
invalidateIncrblobCursors(p, nKey, 0);
5779057904
5779157905
/* If the cursor is currently on the last row and we are appending a
5779257906
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
5779357907
** call */
57794
- if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
57908
+ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
5779557909
loc = -1;
5779657910
}
5779757911
}
5779857912
5779957913
if( !loc ){
@@ -57842,11 +57956,11 @@
5784257956
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
5784357957
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
5784457958
5784557959
/* If no error has occurred and pPage has an overflow cell, call balance()
5784657960
** to redistribute the cells within the tree. Since balance() may move
57847
- ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
57961
+ ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
5784857962
** variables.
5784957963
**
5785057964
** Previous versions of SQLite called moveToRoot() to move the cursor
5785157965
** back to the root page as balance() used to invalidate the contents
5785257966
** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that,
@@ -57862,11 +57976,11 @@
5786257976
** larger than the largest existing key, it is possible to insert the
5786357977
** row without seeking the cursor. This can be a big performance boost.
5786457978
*/
5786557979
pCur->info.nSize = 0;
5786657980
if( rc==SQLITE_OK && pPage->nOverflow ){
57867
- pCur->validNKey = 0;
57981
+ pCur->curFlags &= ~(BTCF_ValidNKey);
5786857982
rc = balance(pCur);
5786957983
5787057984
/* Must make sure nOverflow is reset to zero even if the balance()
5787157985
** fails. Internal data structure corruption will result otherwise.
5787257986
** Also, set the cursor state to invalid. This stops saveCursorPosition()
@@ -57894,11 +58008,11 @@
5789458008
int iCellDepth; /* Depth of node containing pCell */
5789558009
5789658010
assert( cursorHoldsMutex(pCur) );
5789758011
assert( pBt->inTransaction==TRANS_WRITE );
5789858012
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
57899
- assert( pCur->wrFlag );
58013
+ assert( pCur->curFlags & BTCF_WriteFlag );
5790058014
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
5790158015
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
5790258016
5790358017
if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
5790458018
|| NEVER(pCur->eState!=CURSOR_VALID)
@@ -58238,10 +58352,19 @@
5823858352
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
5823958353
}
5824058354
sqlite3BtreeLeave(p);
5824158355
return rc;
5824258356
}
58357
+
58358
+/*
58359
+** Delete all information from the single table that pCur is open on.
58360
+**
58361
+** This routine only work for pCur on an ephemeral table.
58362
+*/
58363
+SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
58364
+ return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
58365
+}
5824358366
5824458367
/*
5824558368
** Erase all information in a table and add the root of the table to
5824658369
** the freelist. Except, the root of the principle table (the one on
5824758370
** page 1) is never added to the freelist.
@@ -59198,11 +59321,11 @@
5919859321
*/
5919959322
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
5920059323
int rc;
5920159324
assert( cursorHoldsMutex(pCsr) );
5920259325
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
59203
- assert( pCsr->isIncrblobHandle );
59326
+ assert( pCsr->curFlags & BTCF_Incrblob );
5920459327
5920559328
rc = restoreCursorPosition(pCsr);
5920659329
if( rc!=SQLITE_OK ){
5920759330
return rc;
5920859331
}
@@ -59227,11 +59350,11 @@
5922759350
** (b) there is a read/write transaction open,
5922859351
** (c) the connection holds a write-lock on the table (if required),
5922959352
** (d) there are no conflicting read-locks, and
5923059353
** (e) the cursor points at a valid row of an intKey table.
5923159354
*/
59232
- if( !pCsr->wrFlag ){
59355
+ if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
5923359356
return SQLITE_READONLY;
5923459357
}
5923559358
assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
5923659359
&& pCsr->pBt->inTransaction==TRANS_WRITE );
5923759360
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
@@ -59240,24 +59363,14 @@
5924059363
5924159364
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
5924259365
}
5924359366
5924459367
/*
59245
-** Set a flag on this cursor to cache the locations of pages from the
59246
-** overflow list for the current row. This is used by cursors opened
59247
-** for incremental blob IO only.
59248
-**
59249
-** This function sets a flag only. The actual page location cache
59250
-** (stored in BtCursor.aOverflow[]) is allocated and used by function
59251
-** accessPayload() (the worker function for sqlite3BtreeData() and
59252
-** sqlite3BtreePutData()).
59368
+** Mark this cursor as an incremental blob cursor.
5925359369
*/
59254
-SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
59255
- assert( cursorHoldsMutex(pCur) );
59256
- assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
59257
- invalidateOverflowCache(pCur);
59258
- pCur->isIncrblobHandle = 1;
59370
+SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
59371
+ pCur->curFlags |= BTCF_Incrblob;
5925959372
}
5926059373
#endif
5926159374
5926259375
/*
5926359376
** Set both the "read version" (single byte at byte offset 18) and
@@ -61624,11 +61737,11 @@
6162461737
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
6162561738
Parse *p = v->pParse;
6162661739
int j = -1-x;
6162761740
assert( v->magic==VDBE_MAGIC_INIT );
6162861741
assert( j<p->nLabel );
61629
- if( j>=0 && p->aLabel ){
61742
+ if( ALWAYS(j>=0) && p->aLabel ){
6163061743
p->aLabel[j] = v->nOp;
6163161744
}
6163261745
p->iFixedOp = v->nOp - 1;
6163361746
}
6163461747
@@ -62131,11 +62244,13 @@
6213162244
assert( addr<p->nOp );
6213262245
if( addr<0 ){
6213362246
addr = p->nOp - 1;
6213462247
}
6213562248
pOp = &p->aOp[addr];
62136
- assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
62249
+ assert( pOp->p4type==P4_NOTUSED
62250
+ || pOp->p4type==P4_INT32
62251
+ || pOp->p4type==P4_KEYINFO );
6213762252
freeP4(db, pOp->p4type, pOp->p4.p);
6213862253
pOp->p4.p = 0;
6213962254
if( n==P4_INT32 ){
6214062255
/* Note: this cast is safe, because the origin data point was an int
6214162256
** that was cast to a (const char *). */
@@ -64081,11 +64196,11 @@
6408164196
int hasMoved;
6408264197
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
6408364198
if( rc ) return rc;
6408464199
if( hasMoved ){
6408564200
p->cacheStatus = CACHE_STALE;
64086
- p->nullRow = 1;
64201
+ if( hasMoved==2 ) p->nullRow = 1;
6408764202
}
6408864203
}
6408964204
return SQLITE_OK;
6409064205
}
6409164206
@@ -64751,14 +64866,17 @@
6475164866
** determined that the first fields of the keys are equal.
6475264867
**
6475364868
** Key1 and Key2 do not have to contain the same number of fields. If all
6475464869
** fields that appear in both keys are equal, then pPKey2->default_rc is
6475564870
** returned.
64871
+**
64872
+** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
64873
+** and return 0.
6475664874
*/
6475764875
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
6475864876
int nKey1, const void *pKey1, /* Left key */
64759
- const UnpackedRecord *pPKey2, /* Right key */
64877
+ UnpackedRecord *pPKey2, /* Right key */
6476064878
int bSkip /* If true, skip the first field */
6476164879
){
6476264880
u32 d1; /* Offset into aKey[] of next data element */
6476364881
int i; /* Index of next field to compare */
6476464882
u32 szHdr1; /* Size of record header in bytes */
@@ -64780,10 +64898,14 @@
6478064898
i = 1;
6478164899
pRhs++;
6478264900
}else{
6478364901
idx1 = getVarint32(aKey1, szHdr1);
6478464902
d1 = szHdr1;
64903
+ if( d1>(unsigned)nKey1 ){
64904
+ pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
64905
+ return 0; /* Corruption */
64906
+ }
6478564907
i = 0;
6478664908
}
6478764909
6478864910
VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
6478964911
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
@@ -64856,11 +64978,12 @@
6485664978
}else{
6485764979
mem1.n = (serial_type - 12) / 2;
6485864980
testcase( (d1+mem1.n)==(unsigned)nKey1 );
6485964981
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
6486064982
if( (d1+mem1.n) > (unsigned)nKey1 ){
64861
- rc = 1; /* Corruption */
64983
+ pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
64984
+ return 0; /* Corruption */
6486264985
}else if( pKeyInfo->aColl[i] ){
6486364986
mem1.enc = pKeyInfo->enc;
6486464987
mem1.db = pKeyInfo->db;
6486564988
mem1.flags = MEM_Str;
6486664989
mem1.z = (char*)&aKey1[d1];
@@ -64882,11 +65005,12 @@
6488265005
}else{
6488365006
int nStr = (serial_type - 12) / 2;
6488465007
testcase( (d1+nStr)==(unsigned)nKey1 );
6488565008
testcase( (d1+nStr+1)==(unsigned)nKey1 );
6488665009
if( (d1+nStr) > (unsigned)nKey1 ){
64887
- rc = 1; /* Corruption */
65010
+ pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
65011
+ return 0; /* Corruption */
6488865012
}else{
6488965013
int nCmp = MIN(nStr, pRhs->n);
6489065014
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
6489165015
if( rc==0 ) rc = nStr - pRhs->n;
6489265016
}
@@ -64935,14 +65059,17 @@
6493565059
/*
6493665060
** This function is an optimized version of sqlite3VdbeRecordCompare()
6493765061
** that (a) the first field of pPKey2 is an integer, and (b) the
6493865062
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
6493965063
** byte (i.e. is less than 128).
65064
+**
65065
+** To avoid concerns about buffer overreads, this routine is only used
65066
+** on schemas where the maximum valid header size is 63 bytes or less.
6494065067
*/
6494165068
static int vdbeRecordCompareInt(
6494265069
int nKey1, const void *pKey1, /* Left key */
64943
- const UnpackedRecord *pPKey2, /* Right key */
65070
+ UnpackedRecord *pPKey2, /* Right key */
6494465071
int bSkip /* Ignored */
6494565072
){
6494665073
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
6494765074
int serial_type = ((const u8*)pKey1)[1];
6494865075
int res;
@@ -64951,10 +65078,11 @@
6495165078
i64 v = pPKey2->aMem[0].u.i;
6495265079
i64 lhs;
6495365080
UNUSED_PARAMETER(bSkip);
6495465081
6495565082
assert( bSkip==0 );
65083
+ assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
6495665084
switch( serial_type ){
6495765085
case 1: { /* 1-byte signed integer */
6495865086
lhs = ONE_BYTE_INT(aKey);
6495965087
testcase( lhs<0 );
6496065088
break;
@@ -65035,11 +65163,11 @@
6503565163
** uses the collation sequence BINARY and (c) that the size-of-header varint
6503665164
** at the start of (pKey1/nKey1) fits in a single byte.
6503765165
*/
6503865166
static int vdbeRecordCompareString(
6503965167
int nKey1, const void *pKey1, /* Left key */
65040
- const UnpackedRecord *pPKey2, /* Right key */
65168
+ UnpackedRecord *pPKey2, /* Right key */
6504165169
int bSkip
6504265170
){
6504365171
const u8 *aKey1 = (const u8*)pKey1;
6504465172
int serial_type;
6504565173
int res;
@@ -65056,11 +65184,14 @@
6505665184
int nCmp;
6505765185
int nStr;
6505865186
int szHdr = aKey1[0];
6505965187
6506065188
nStr = (serial_type-12) / 2;
65061
- if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */
65189
+ if( (szHdr + nStr) > nKey1 ){
65190
+ pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
65191
+ return 0; /* Corruption */
65192
+ }
6506265193
nCmp = MIN( pPKey2->aMem[0].n, nStr );
6506365194
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
6506465195
6506565196
if( res==0 ){
6506665197
res = nStr - pPKey2->aMem[0].n;
@@ -65221,11 +65352,11 @@
6522165352
** is ignored as well. Hence, this routine only compares the prefixes
6522265353
** of the keys prior to the final rowid, not the entire key.
6522365354
*/
6522465355
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
6522565356
VdbeCursor *pC, /* The cursor to compare against */
65226
- const UnpackedRecord *pUnpacked, /* Unpacked version of key */
65357
+ UnpackedRecord *pUnpacked, /* Unpacked version of key */
6522765358
int *res /* Write the comparison result here */
6522865359
){
6522965360
i64 nCellKey = 0;
6523065361
int rc;
6523165362
BtCursor *pCur = pC->pCursor;
@@ -67311,10 +67442,33 @@
6731167442
u8 affinity,
6731267443
u8 enc
6731367444
){
6731467445
applyAffinity((Mem *)pVal, affinity, enc);
6731567446
}
67447
+
67448
+/*
67449
+** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
67450
+** none.
67451
+**
67452
+** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
67453
+** But it does set pMem->r and pMem->u.i appropriately.
67454
+*/
67455
+static u16 numericType(Mem *pMem){
67456
+ if( pMem->flags & (MEM_Int|MEM_Real) ){
67457
+ return pMem->flags & (MEM_Int|MEM_Real);
67458
+ }
67459
+ if( pMem->flags & (MEM_Str|MEM_Blob) ){
67460
+ if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
67461
+ return 0;
67462
+ }
67463
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
67464
+ return MEM_Int;
67465
+ }
67466
+ return MEM_Real;
67467
+ }
67468
+ return 0;
67469
+}
6731667470
6731767471
#ifdef SQLITE_DEBUG
6731867472
/*
6731967473
** Write a nice string representation of the contents of cell pMem
6732067474
** into buffer zBuf, length nBuf.
@@ -68171,14 +68325,15 @@
6817168325
}
6817268326
6817368327
/* Opcode: Move P1 P2 P3 * *
6817468328
** Synopsis: r[P2@P3]=r[P1@P3]
6817568329
**
68176
-** Move the values in register P1..P1+P3 over into
68177
-** registers P2..P2+P3. Registers P1..P1+P3 are
68330
+** Move the P3 values in register P1..P1+P3-1 over into
68331
+** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
6817868332
** left holding a NULL. It is an error for register ranges
68179
-** P1..P1+P3 and P2..P2+P3 to overlap.
68333
+** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error
68334
+** for P3 to be less than 1.
6818068335
*/
6818168336
case OP_Move: {
6818268337
char *zMalloc; /* Holding variable for allocated memory */
6818368338
int n; /* Number of registers left to copy */
6818468339
int p1; /* Register to copy from */
@@ -68185,11 +68340,11 @@
6818568340
int p2; /* Register to copy to */
6818668341
6818768342
n = pOp->p3;
6818868343
p1 = pOp->p1;
6818968344
p2 = pOp->p2;
68190
- assert( n>=0 && p1>0 && p2>0 );
68345
+ assert( n>0 && p1>0 && p2>0 );
6819168346
assert( p1+n<=p2 || p2+n<=p1 );
6819268347
6819368348
pIn1 = &aMem[p1];
6819468349
pOut = &aMem[p2];
6819568350
do{
@@ -68209,11 +68364,11 @@
6820968364
pIn1->xDel = 0;
6821068365
pIn1->zMalloc = zMalloc;
6821168366
REGISTER_TRACE(p2++, pOut);
6821268367
pIn1++;
6821368368
pOut++;
68214
- }while( n-- );
68369
+ }while( --n );
6821568370
break;
6821668371
}
6821768372
6821868373
/* Opcode: Copy P1 P2 P3 * *
6821968374
** Synopsis: r[P2@P3+1]=r[P1@P3+1]
@@ -68441,24 +68596,26 @@
6844168596
case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
6844268597
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
6844368598
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
6844468599
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
6844568600
char bIntint; /* Started out as two integer operands */
68446
- int flags; /* Combined MEM_* flags from both inputs */
68601
+ u16 flags; /* Combined MEM_* flags from both inputs */
68602
+ u16 type1; /* Numeric type of left operand */
68603
+ u16 type2; /* Numeric type of right operand */
6844768604
i64 iA; /* Integer value of left operand */
6844868605
i64 iB; /* Integer value of right operand */
6844968606
double rA; /* Real value of left operand */
6845068607
double rB; /* Real value of right operand */
6845168608
6845268609
pIn1 = &aMem[pOp->p1];
68453
- applyNumericAffinity(pIn1);
68610
+ type1 = numericType(pIn1);
6845468611
pIn2 = &aMem[pOp->p2];
68455
- applyNumericAffinity(pIn2);
68612
+ type2 = numericType(pIn2);
6845668613
pOut = &aMem[pOp->p3];
6845768614
flags = pIn1->flags | pIn2->flags;
6845868615
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
68459
- if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
68616
+ if( (type1 & type2 & MEM_Int)!=0 ){
6846068617
iA = pIn1->u.i;
6846168618
iB = pIn2->u.i;
6846268619
bIntint = 1;
6846368620
switch( pOp->opcode ){
6846468621
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
@@ -68510,11 +68667,11 @@
6851068667
if( sqlite3IsNaN(rB) ){
6851168668
goto arithmetic_result_is_null;
6851268669
}
6851368670
pOut->r = rB;
6851468671
MemSetTypeFlag(pOut, MEM_Real);
68515
- if( (flags & MEM_Real)==0 && !bIntint ){
68672
+ if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
6851668673
sqlite3VdbeIntegerAffinity(pOut);
6851768674
}
6851868675
#endif
6851968676
}
6852068677
break;
@@ -69086,10 +69243,11 @@
6908669243
aPermute = pOp->p4.ai;
6908769244
break;
6908869245
}
6908969246
6909069247
/* Opcode: Compare P1 P2 P3 P4 P5
69248
+** Synopsis: r[P1@P3] <-> r[P2@P3]
6909169249
**
6909269250
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
6909369251
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
6909469252
** the comparison for use by the next OP_Jump instruct.
6909569253
**
@@ -70421,10 +70579,11 @@
7042170579
assert( pOp->p1>=0 );
7042270580
assert( pOp->p2>=0 );
7042370581
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
7042470582
if( pCx==0 ) goto no_mem;
7042570583
pCx->nullRow = 1;
70584
+ pCx->isEphemeral = 1;
7042670585
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
7042770586
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
7042870587
if( rc==SQLITE_OK ){
7042970588
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
7043070589
}
@@ -70911,11 +71070,11 @@
7091171070
pC->seekResult = res;
7091271071
break;
7091371072
}
7091471073
7091571074
/* Opcode: Sequence P1 P2 * * *
70916
-** Synopsis: r[P2]=rowid
71075
+** Synopsis: r[P2]=cursor[P1].ctr++
7091771076
**
7091871077
** Find the next available sequence number for cursor P1.
7091971078
** Write the sequence number into register P2.
7092071079
** The sequence number on the cursor is incremented after this
7092171080
** instruction.
@@ -71602,10 +71761,11 @@
7160271761
VdbeCursor *pC;
7160371762
int res;
7160471763
7160571764
pC = p->apCsr[pOp->p1];
7160671765
assert( isSorter(pC) );
71766
+ res = 0;
7160771767
rc = sqlite3VdbeSorterNext(db, pC, &res);
7160871768
goto next_tail;
7160971769
case OP_PrevIfOpen: /* jump */
7161071770
case OP_NextIfOpen: /* jump */
7161171771
if( p->apCsr[pOp->p1]==0 ) break;
@@ -71959,10 +72119,33 @@
7195972119
aMem[pOp->p3].u.i += nChange;
7196072120
}
7196172121
}
7196272122
break;
7196372123
}
72124
+
72125
+/* Opcode: ResetSorter P1 * * * *
72126
+**
72127
+** Delete all contents from the ephemeral table or sorter
72128
+** that is open on cursor P1.
72129
+**
72130
+** This opcode only works for cursors used for sorting and
72131
+** opened with OP_OpenEphemeral or OP_SorterOpen.
72132
+*/
72133
+case OP_ResetSorter: {
72134
+ VdbeCursor *pC;
72135
+
72136
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
72137
+ pC = p->apCsr[pOp->p1];
72138
+ assert( pC!=0 );
72139
+ if( pC->pSorter ){
72140
+ sqlite3VdbeSorterReset(db, pC->pSorter);
72141
+ }else{
72142
+ assert( pC->isEphemeral );
72143
+ rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
72144
+ }
72145
+ break;
72146
+}
7196472147
7196572148
/* Opcode: CreateTable P1 P2 * * *
7196672149
** Synopsis: r[P2]=root iDb=P1
7196772150
**
7196872151
** Allocate a new table in the main database file if P1==0 or in the
@@ -72266,13 +72449,11 @@
7226672449
}
7226772450
7226872451
assert( pOp->p4type==P4_INT32 );
7226972452
assert( iSet==-1 || iSet>=0 );
7227072453
if( iSet ){
72271
- exists = sqlite3RowSetTest(pIn1->u.pRowSet,
72272
- (u8)(iSet>=0 ? iSet & 0xf : 0xff),
72273
- pIn3->u.i);
72454
+ exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
7227472455
VdbeBranchTaken(exists!=0,2);
7227572456
if( exists ){
7227672457
pc = pOp->p2 - 1;
7227772458
break;
7227872459
}
@@ -72968,11 +73149,11 @@
7296873149
}
7296973150
#endif /* SQLITE_OMIT_VIRTUALTABLE */
7297073151
7297173152
#ifndef SQLITE_OMIT_VIRTUALTABLE
7297273153
/* Opcode: VFilter P1 P2 P3 P4 *
72973
-** Synopsis: iPlan=r[P3] zPlan='P4'
73154
+** Synopsis: iplan=r[P3] zplan='P4'
7297473155
**
7297573156
** P1 is a cursor opened using VOpen. P2 is an address to jump to if
7297673157
** the filtered result set is empty.
7297773158
**
7297873159
** P4 is either NULL or a string that was generated by the xBestIndex
@@ -73536,13 +73717,11 @@
7353673717
p->pStmt = 0;
7353773718
}else{
7353873719
p->iOffset = pC->aType[p->iCol + pC->nField];
7353973720
p->nByte = sqlite3VdbeSerialTypeLen(type);
7354073721
p->pCsr = pC->pCursor;
73541
- sqlite3BtreeEnterCursor(p->pCsr);
73542
- sqlite3BtreeCacheOverflow(p->pCsr);
73543
- sqlite3BtreeLeaveCursor(p->pCsr);
73722
+ sqlite3BtreeIncrblobCursor(p->pCsr);
7354473723
}
7354573724
}
7354673725
7354773726
if( rc==SQLITE_ROW ){
7354873727
rc = SQLITE_OK;
@@ -74431,28 +74610,45 @@
7443174610
for(p=pRecord; p; p=pNext){
7443274611
pNext = p->pNext;
7443374612
sqlite3DbFree(db, p);
7443474613
}
7443574614
}
74615
+
74616
+/*
74617
+** Reset a sorting cursor back to its original empty state.
74618
+*/
74619
+SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
74620
+ if( pSorter->aIter ){
74621
+ int i;
74622
+ for(i=0; i<pSorter->nTree; i++){
74623
+ vdbeSorterIterZero(db, &pSorter->aIter[i]);
74624
+ }
74625
+ sqlite3DbFree(db, pSorter->aIter);
74626
+ pSorter->aIter = 0;
74627
+ }
74628
+ if( pSorter->pTemp1 ){
74629
+ sqlite3OsCloseFree(pSorter->pTemp1);
74630
+ pSorter->pTemp1 = 0;
74631
+ }
74632
+ vdbeSorterRecordFree(db, pSorter->pRecord);
74633
+ pSorter->pRecord = 0;
74634
+ pSorter->iWriteOff = 0;
74635
+ pSorter->iReadOff = 0;
74636
+ pSorter->nInMemory = 0;
74637
+ pSorter->nTree = 0;
74638
+ pSorter->nPMA = 0;
74639
+ pSorter->aTree = 0;
74640
+}
74641
+
7443674642
7443774643
/*
7443874644
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
7443974645
*/
7444074646
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
7444174647
VdbeSorter *pSorter = pCsr->pSorter;
7444274648
if( pSorter ){
74443
- if( pSorter->aIter ){
74444
- int i;
74445
- for(i=0; i<pSorter->nTree; i++){
74446
- vdbeSorterIterZero(db, &pSorter->aIter[i]);
74447
- }
74448
- sqlite3DbFree(db, pSorter->aIter);
74449
- }
74450
- if( pSorter->pTemp1 ){
74451
- sqlite3OsCloseFree(pSorter->pTemp1);
74452
- }
74453
- vdbeSorterRecordFree(db, pSorter->pRecord);
74649
+ sqlite3VdbeSorterReset(db, pSorter);
7445474650
sqlite3DbFree(db, pSorter->pUnpacked);
7445574651
sqlite3DbFree(db, pSorter);
7445674652
pCsr->pSorter = 0;
7445774653
}
7445874654
}
@@ -74884,18 +75080,59 @@
7488475080
VdbeSorter *pSorter = pCsr->pSorter;
7488575081
int rc; /* Return code */
7488675082
7488775083
if( pSorter->aTree ){
7488875084
int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
74889
- int i; /* Index of aTree[] to recalculate */
74890
-
7489175085
rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
74892
- for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){
74893
- rc = vdbeSorterDoCompare(pCsr, i);
75086
+ if( rc==SQLITE_OK ){
75087
+ int i; /* Index of aTree[] to recalculate */
75088
+ VdbeSorterIter *pIter1; /* First iterator to compare */
75089
+ VdbeSorterIter *pIter2; /* Second iterator to compare */
75090
+ u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */
75091
+
75092
+ /* Find the first two iterators to compare. The one that was just
75093
+ ** advanced (iPrev) and the one next to it in the array. */
75094
+ pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)];
75095
+ pIter2 = &pSorter->aIter[(iPrev | 0x0001)];
75096
+ pKey2 = pIter2->aKey;
75097
+
75098
+ for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){
75099
+ /* Compare pIter1 and pIter2. Store the result in variable iRes. */
75100
+ int iRes;
75101
+ if( pIter1->pFile==0 ){
75102
+ iRes = +1;
75103
+ }else if( pIter2->pFile==0 ){
75104
+ iRes = -1;
75105
+ }else{
75106
+ vdbeSorterCompare(pCsr, 0,
75107
+ pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes
75108
+ );
75109
+ }
75110
+
75111
+ /* If pIter1 contained the smaller value, set aTree[i] to its index.
75112
+ ** Then set pIter2 to the next iterator to compare to pIter1. In this
75113
+ ** case there is no cache of pIter2 in pSorter->pUnpacked, so set
75114
+ ** pKey2 to point to the record belonging to pIter2.
75115
+ **
75116
+ ** Alternatively, if pIter2 contains the smaller of the two values,
75117
+ ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare()
75118
+ ** was actually called above, then pSorter->pUnpacked now contains
75119
+ ** a value equivalent to pIter2. So set pKey2 to NULL to prevent
75120
+ ** vdbeSorterCompare() from decoding pIter2 again. */
75121
+ if( iRes<=0 ){
75122
+ pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter);
75123
+ pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
75124
+ pKey2 = pIter2->aKey;
75125
+ }else{
75126
+ if( pIter1->pFile ) pKey2 = 0;
75127
+ pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter);
75128
+ pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
75129
+ }
75130
+
75131
+ }
75132
+ *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
7489475133
}
74895
-
74896
- *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
7489775134
}else{
7489875135
SorterRecord *pFree = pSorter->pRecord;
7489975136
pSorter->pRecord = pFree->pNext;
7490075137
pFree->pNext = 0;
7490175138
vdbeSorterRecordFree(db, pFree);
@@ -77127,10 +77364,11 @@
7712777364
** SELECT * FROM t1 WHERE (select a from t1);
7712877365
*/
7712977366
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
7713077367
int op;
7713177368
pExpr = sqlite3ExprSkipCollate(pExpr);
77369
+ if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
7713277370
op = pExpr->op;
7713377371
if( op==TK_SELECT ){
7713477372
assert( pExpr->flags&EP_xIsSelect );
7713577373
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
7713677374
}
@@ -77159,11 +77397,15 @@
7715977397
** implements the COLLATE operator.
7716077398
**
7716177399
** If a memory allocation error occurs, that fact is recorded in pParse->db
7716277400
** and the pExpr parameter is returned unchanged.
7716377401
*/
77164
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
77402
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
77403
+ Parse *pParse, /* Parsing context */
77404
+ Expr *pExpr, /* Add the "COLLATE" clause to this expression */
77405
+ const Token *pCollName /* Name of collating sequence */
77406
+){
7716577407
if( pCollName->n>0 ){
7716677408
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
7716777409
if( pNew ){
7716877410
pNew->pLeft = pExpr;
7716977411
pNew->flags |= EP_Collate|EP_Skip;
@@ -77212,10 +77454,11 @@
7721277454
sqlite3 *db = pParse->db;
7721377455
CollSeq *pColl = 0;
7721477456
Expr *p = pExpr;
7721577457
while( p ){
7721677458
int op = p->op;
77459
+ if( p->flags & EP_Generic ) break;
7721777460
if( op==TK_CAST || op==TK_UPLUS ){
7721877461
p = p->pLeft;
7721977462
continue;
7722077463
}
7722177464
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
@@ -78043,11 +78286,10 @@
7804378286
struct ExprList_item *pItem, *pOldItem;
7804478287
int i;
7804578288
if( p==0 ) return 0;
7804678289
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
7804778290
if( pNew==0 ) return 0;
78048
- pNew->iECursor = 0;
7804978291
pNew->nExpr = i = p->nExpr;
7805078292
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
7805178293
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
7805278294
if( pItem==0 ){
7805378295
sqlite3DbFree(db, pNew);
@@ -78156,11 +78398,10 @@
7815678398
pNew->iLimit = 0;
7815778399
pNew->iOffset = 0;
7815878400
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
7815978401
pNew->addrOpenEphm[0] = -1;
7816078402
pNew->addrOpenEphm[1] = -1;
78161
- pNew->addrOpenEphm[2] = -1;
7816278403
pNew->nSelectRow = p->nSelectRow;
7816378404
pNew->pWith = withDup(db, p->pWith);
7816478405
return pNew;
7816578406
}
7816678407
#else
@@ -78724,11 +78965,10 @@
7872478965
eType = IN_INDEX_EPH;
7872578966
if( prNotFound ){
7872678967
*prNotFound = rMayHaveNull = ++pParse->nMem;
7872778968
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
7872878969
}else{
78729
- testcase( pParse->nQueryLoop>0 );
7873078970
pParse->nQueryLoop = 0;
7873178971
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
7873278972
eType = IN_INDEX_ROWID;
7873378973
}
7873478974
}
@@ -78974,11 +79214,11 @@
7897479214
}
7897579215
7897679216
if( testAddr>=0 ){
7897779217
sqlite3VdbeJumpHere(v, testAddr);
7897879218
}
78979
- sqlite3ExprCachePop(pParse, 1);
79219
+ sqlite3ExprCachePop(pParse);
7898079220
7898179221
return rReg;
7898279222
}
7898379223
#endif /* SQLITE_OMIT_SUBQUERY */
7898479224
@@ -79109,11 +79349,11 @@
7910979349
*/
7911079350
sqlite3VdbeJumpHere(v, j1);
7911179351
}
7911279352
}
7911379353
sqlite3ReleaseTempReg(pParse, r1);
79114
- sqlite3ExprCachePop(pParse, 1);
79354
+ sqlite3ExprCachePop(pParse);
7911579355
VdbeComment((v, "end IN expr"));
7911679356
}
7911779357
#endif /* SQLITE_OMIT_SUBQUERY */
7911879358
7911979359
/*
@@ -79292,19 +79532,18 @@
7929279532
#endif
7929379533
}
7929479534
7929579535
/*
7929679536
** Remove from the column cache any entries that were added since the
79297
-** the previous N Push operations. In other words, restore the cache
79298
-** to the state it was in N Pushes ago.
79537
+** the previous sqlite3ExprCachePush operation. In other words, restore
79538
+** the cache to the state it was in prior the most recent Push.
7929979539
*/
79300
-SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse, int N){
79540
+SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
7930179541
int i;
7930279542
struct yColCache *p;
79303
- assert( N>0 );
79304
- assert( pParse->iCacheLevel>=N );
79305
- pParse->iCacheLevel -= N;
79543
+ assert( pParse->iCacheLevel>=1 );
79544
+ pParse->iCacheLevel--;
7930679545
#ifdef SQLITE_DEBUG
7930779546
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
7930879547
printf("POP to %d\n", pParse->iCacheLevel);
7930979548
}
7931079549
#endif
@@ -79429,11 +79668,11 @@
7942979668
*/
7943079669
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
7943179670
int i;
7943279671
struct yColCache *p;
7943379672
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
79434
- sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
79673
+ sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
7943579674
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
7943679675
int x = p->iReg;
7943779676
if( x>=iFrom && x<iFrom+nReg ){
7943879677
p->iReg += iTo-iFrom;
7943979678
}
@@ -79778,11 +80017,11 @@
7977880017
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
7977980018
VdbeCoverage(v);
7978080019
sqlite3ExprCacheRemove(pParse, target, 1);
7978180020
sqlite3ExprCachePush(pParse);
7978280021
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
79783
- sqlite3ExprCachePop(pParse, 1);
80022
+ sqlite3ExprCachePop(pParse);
7978480023
}
7978580024
sqlite3VdbeResolveLabel(v, endCoalesce);
7978680025
break;
7978780026
}
7978880027
@@ -79830,13 +80069,13 @@
7983080069
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
7983180070
}
7983280071
}
7983380072
7983480073
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
79835
- sqlite3ExprCodeExprList(pParse, pFarg, r1,
80074
+ sqlite3ExprCodeExprList(pParse, pFarg, r1,
7983680075
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
79837
- sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
80076
+ sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
7983880077
}else{
7983980078
r1 = 0;
7984080079
}
7984180080
#ifndef SQLITE_OMIT_VIRTUALTABLE
7984280081
/* Possibly overload the function if the first argument is
@@ -80052,17 +80291,17 @@
8005280291
testcase( pTest->op==TK_COLUMN );
8005380292
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
8005480293
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
8005580294
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
8005680295
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
80057
- sqlite3ExprCachePop(pParse, 1);
80296
+ sqlite3ExprCachePop(pParse);
8005880297
sqlite3VdbeResolveLabel(v, nextCase);
8005980298
}
8006080299
if( (nExpr&1)!=0 ){
8006180300
sqlite3ExprCachePush(pParse);
8006280301
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
80063
- sqlite3ExprCachePop(pParse, 1);
80302
+ sqlite3ExprCachePop(pParse);
8006480303
}else{
8006580304
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
8006680305
}
8006780306
assert( db->mallocFailed || pParse->nErr>0
8006880307
|| pParse->iCacheLevel==iCacheLevel );
@@ -80637,19 +80876,19 @@
8063780876
testcase( jumpIfNull==0 );
8063880877
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
8063980878
sqlite3ExprCachePush(pParse);
8064080879
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
8064180880
sqlite3VdbeResolveLabel(v, d2);
80642
- sqlite3ExprCachePop(pParse, 1);
80881
+ sqlite3ExprCachePop(pParse);
8064380882
break;
8064480883
}
8064580884
case TK_OR: {
8064680885
testcase( jumpIfNull==0 );
8064780886
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
8064880887
sqlite3ExprCachePush(pParse);
8064980888
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
80650
- sqlite3ExprCachePop(pParse, 1);
80889
+ sqlite3ExprCachePop(pParse);
8065180890
break;
8065280891
}
8065380892
case TK_NOT: {
8065480893
testcase( jumpIfNull==0 );
8065580894
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
@@ -80791,21 +81030,21 @@
8079181030
case TK_AND: {
8079281031
testcase( jumpIfNull==0 );
8079381032
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
8079481033
sqlite3ExprCachePush(pParse);
8079581034
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
80796
- sqlite3ExprCachePop(pParse, 1);
81035
+ sqlite3ExprCachePop(pParse);
8079781036
break;
8079881037
}
8079981038
case TK_OR: {
8080081039
int d2 = sqlite3VdbeMakeLabel(v);
8080181040
testcase( jumpIfNull==0 );
8080281041
sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
8080381042
sqlite3ExprCachePush(pParse);
8080481043
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
8080581044
sqlite3VdbeResolveLabel(v, d2);
80806
- sqlite3ExprCachePop(pParse, 1);
81045
+ sqlite3ExprCachePop(pParse);
8080781046
break;
8080881047
}
8080981048
case TK_NOT: {
8081081049
testcase( jumpIfNull==0 );
8081181050
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
@@ -81465,10 +81704,11 @@
8146581704
unsigned const char *z; /* Pointer to token */
8146681705
int n; /* Length of token z */
8146781706
int token; /* Type of token */
8146881707
8146981708
UNUSED_PARAMETER(NotUsed);
81709
+ if( zInput==0 || zOld==0 ) return;
8147081710
for(z=zInput; *z; z=z+n){
8147181711
n = sqlite3GetToken(z, &token);
8147281712
if( token==TK_REFERENCES ){
8147381713
char *zParent;
8147481714
do {
@@ -87459,11 +87699,11 @@
8745987699
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
8746087700
regRecord = sqlite3GetTempReg(pParse);
8746187701
8746287702
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
8746387703
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
87464
- sqlite3VdbeResolveLabel(v, iPartIdxLabel);
87704
+ sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
8746587705
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
8746687706
sqlite3VdbeJumpHere(v, addr1);
8746787707
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
8746887708
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
8746987709
(char *)pKey, P4_KEYINFO);
@@ -90236,11 +90476,11 @@
9023690476
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
9023790477
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
9023890478
&iPartIdxLabel, pPrior, r1);
9023990479
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
9024090480
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
90241
- sqlite3VdbeResolveLabel(v, iPartIdxLabel);
90481
+ sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
9024290482
pPrior = pIdx;
9024390483
}
9024490484
}
9024590485
9024690486
/*
@@ -90255,14 +90495,15 @@
9025590495
** block of registers has already been deallocated by the time
9025690496
** this routine returns.
9025790497
**
9025890498
** If *piPartIdxLabel is not NULL, fill it in with a label and jump
9025990499
** to that label if pIdx is a partial index that should be skipped.
90500
+** The label should be resolved using sqlite3ResolvePartIdxLabel().
9026090501
** A partial index should be skipped if its WHERE clause evaluates
9026190502
** to false or null. If pIdx is not a partial index, *piPartIdxLabel
9026290503
** will be set to zero which is an empty label that is ignored by
90263
-** sqlite3VdbeResolveLabel().
90504
+** sqlite3ResolvePartIdxLabel().
9026490505
**
9026590506
** The pPrior and regPrior parameters are used to implement a cache to
9026690507
** avoid unnecessary register loads. If pPrior is not NULL, then it is
9026790508
** a pointer to a different index for which an index key has just been
9026890509
** computed into register regPrior. If the current pIdx index is generating
@@ -90291,10 +90532,11 @@
9029190532
9029290533
if( piPartIdxLabel ){
9029390534
if( pIdx->pPartIdxWhere ){
9029490535
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
9029590536
pParse->iPartIdxTab = iDataCur;
90537
+ sqlite3ExprCachePush(pParse);
9029690538
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
9029790539
SQLITE_JUMPIFNULL);
9029890540
}else{
9029990541
*piPartIdxLabel = 0;
9030090542
}
@@ -90318,10 +90560,22 @@
9031890560
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
9031990561
}
9032090562
sqlite3ReleaseTempRange(pParse, regBase, nCol);
9032190563
return regBase;
9032290564
}
90565
+
90566
+/*
90567
+** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
90568
+** because it was a partial index, then this routine should be called to
90569
+** resolve that label.
90570
+*/
90571
+SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
90572
+ if( iLabel ){
90573
+ sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
90574
+ sqlite3ExprCachePop(pParse);
90575
+ }
90576
+}
9032390577
9032490578
/************** End of delete.c **********************************************/
9032590579
/************** Begin file func.c ********************************************/
9032690580
/*
9032790581
** 2002 February 23
@@ -98716,11 +98970,11 @@
9871698970
sqlite3VdbeChangeP5(v, (u8)i);
9871798971
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
9871898972
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
9871998973
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
9872098974
P4_DYNAMIC);
98721
- sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
98975
+ sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
9872298976
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
9872398977
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
9872498978
sqlite3VdbeJumpHere(v, addr);
9872598979
9872698980
/* Make sure all the indices are constructed correctly.
@@ -98769,11 +99023,11 @@
9876999023
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
9877099024
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
9877199025
sqlite3VdbeAddOp0(v, OP_Halt);
9877299026
sqlite3VdbeJumpHere(v, jmp4);
9877399027
sqlite3VdbeJumpHere(v, jmp2);
98774
- sqlite3VdbeResolveLabel(v, jmp3);
99028
+ sqlite3ResolvePartIdxLabel(pParse, jmp3);
9877599029
}
9877699030
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
9877799031
sqlite3VdbeJumpHere(v, loopTop-1);
9877899032
#ifndef SQLITE_OMIT_BTREECOUNT
9877999033
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
@@ -100054,10 +100308,38 @@
100054100308
*************************************************************************
100055100309
** This file contains C code routines that are called by the parser
100056100310
** to handle SELECT statements in SQLite.
100057100311
*/
100058100312
100313
+/*
100314
+** An instance of the following object is used to record information about
100315
+** how to process the DISTINCT keyword, to simplify passing that information
100316
+** into the selectInnerLoop() routine.
100317
+*/
100318
+typedef struct DistinctCtx DistinctCtx;
100319
+struct DistinctCtx {
100320
+ u8 isTnct; /* True if the DISTINCT keyword is present */
100321
+ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
100322
+ int tabTnct; /* Ephemeral table used for DISTINCT processing */
100323
+ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
100324
+};
100325
+
100326
+/*
100327
+** An instance of the following object is used to record information about
100328
+** the ORDER BY (or GROUP BY) clause of query is being coded.
100329
+*/
100330
+typedef struct SortCtx SortCtx;
100331
+struct SortCtx {
100332
+ ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
100333
+ int nOBSat; /* Number of ORDER BY terms satisfied by indices */
100334
+ int iECursor; /* Cursor number for the sorter */
100335
+ int regReturn; /* Register holding block-output return address */
100336
+ int labelBkOut; /* Start label for the block-output subroutine */
100337
+ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
100338
+ u8 sortFlags; /* Zero or more SORTFLAG_* bits */
100339
+};
100340
+#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
100059100341
100060100342
/*
100061100343
** Delete all the content of a Select structure but do not deallocate
100062100344
** the select structure itself.
100063100345
*/
@@ -100127,11 +100409,10 @@
100127100409
pNew->pLimit = pLimit;
100128100410
pNew->pOffset = pOffset;
100129100411
assert( pOffset==0 || pLimit!=0 );
100130100412
pNew->addrOpenEphm[0] = -1;
100131100413
pNew->addrOpenEphm[1] = -1;
100132
- pNew->addrOpenEphm[2] = -1;
100133100414
if( db->mallocFailed ) {
100134100415
clearSelect(db, pNew);
100135100416
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
100136100417
pNew = 0;
100137100418
}else{
@@ -100459,38 +100740,79 @@
100459100740
}
100460100741
}
100461100742
return 0;
100462100743
}
100463100744
100745
+/* Forward reference */
100746
+static KeyInfo *keyInfoFromExprList(
100747
+ Parse *pParse, /* Parsing context */
100748
+ ExprList *pList, /* Form the KeyInfo object from this ExprList */
100749
+ int iStart, /* Begin with this column of pList */
100750
+ int nExtra /* Add this many extra columns to the end */
100751
+);
100752
+
100464100753
/*
100465
-** Insert code into "v" that will push the record on the top of the
100466
-** stack into the sorter.
100754
+** Insert code into "v" that will push the record in register regData
100755
+** into the sorter.
100467100756
*/
100468100757
static void pushOntoSorter(
100469100758
Parse *pParse, /* Parser context */
100470
- ExprList *pOrderBy, /* The ORDER BY clause */
100759
+ SortCtx *pSort, /* Information about the ORDER BY clause */
100471100760
Select *pSelect, /* The whole SELECT statement */
100472100761
int regData /* Register holding data to be sorted */
100473100762
){
100474100763
Vdbe *v = pParse->pVdbe;
100475
- int nExpr = pOrderBy->nExpr;
100764
+ int nExpr = pSort->pOrderBy->nExpr;
100476100765
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
100477100766
int regRecord = sqlite3GetTempReg(pParse);
100767
+ int nOBSat = pSort->nOBSat;
100478100768
int op;
100479100769
sqlite3ExprCacheClear(pParse);
100480
- sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
100481
- sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
100770
+ sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
100771
+ sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
100482100772
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
100483
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
100484
- if( pSelect->selFlags & SF_UseSorter ){
100773
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat, regRecord);
100774
+ if( nOBSat>0 ){
100775
+ int regPrevKey; /* The first nOBSat columns of the previous row */
100776
+ int addrFirst; /* Address of the OP_IfNot opcode */
100777
+ int addrJmp; /* Address of the OP_Jump opcode */
100778
+ VdbeOp *pOp; /* Opcode that opens the sorter */
100779
+ int nKey; /* Number of sorting key columns, including OP_Sequence */
100780
+ KeyInfo *pKI; /* Original KeyInfo on the sorter table */
100781
+
100782
+ regPrevKey = pParse->nMem+1;
100783
+ pParse->nMem += pSort->nOBSat;
100784
+ nKey = nExpr - pSort->nOBSat + 1;
100785
+ addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v);
100786
+ sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
100787
+ pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
100788
+ if( pParse->db->mallocFailed ) return;
100789
+ pOp->p2 = nKey + 1;
100790
+ pKI = pOp->p4.pKeyInfo;
100791
+ memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
100792
+ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
100793
+ pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
100794
+ addrJmp = sqlite3VdbeCurrentAddr(v);
100795
+ sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
100796
+ pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
100797
+ pSort->regReturn = ++pParse->nMem;
100798
+ sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
100799
+ sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
100800
+ sqlite3VdbeJumpHere(v, addrFirst);
100801
+ sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
100802
+ sqlite3VdbeJumpHere(v, addrJmp);
100803
+ }
100804
+ if( pSort->sortFlags & SORTFLAG_UseSorter ){
100485100805
op = OP_SorterInsert;
100486100806
}else{
100487100807
op = OP_IdxInsert;
100488100808
}
100489
- sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord);
100490
- sqlite3ReleaseTempReg(pParse, regRecord);
100491
- sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
100809
+ sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
100810
+ if( nOBSat==0 ){
100811
+ sqlite3ReleaseTempReg(pParse, regRecord);
100812
+ sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
100813
+ }
100492100814
if( pSelect->iLimit ){
100493100815
int addr1, addr2;
100494100816
int iLimit;
100495100817
if( pSelect->iOffset ){
100496100818
iLimit = pSelect->iOffset+1;
@@ -100499,12 +100821,12 @@
100499100821
}
100500100822
addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
100501100823
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
100502100824
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
100503100825
sqlite3VdbeJumpHere(v, addr1);
100504
- sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
100505
- sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
100826
+ sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
100827
+ sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
100506100828
sqlite3VdbeJumpHere(v, addr2);
100507100829
}
100508100830
}
100509100831
100510100832
/*
@@ -100513,11 +100835,11 @@
100513100835
static void codeOffset(
100514100836
Vdbe *v, /* Generate code into this VM */
100515100837
int iOffset, /* Register holding the offset counter */
100516100838
int iContinue /* Jump here to skip the current record */
100517100839
){
100518
- if( iOffset>0 && iContinue!=0 ){
100840
+ if( iOffset>0 ){
100519100841
int addr;
100520100842
sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
100521100843
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
100522100844
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
100523100845
VdbeComment((v, "skip OFFSET records"));
@@ -100574,23 +100896,10 @@
100574100896
return 0;
100575100897
}
100576100898
}
100577100899
#endif
100578100900
100579
-/*
100580
-** An instance of the following object is used to record information about
100581
-** how to process the DISTINCT keyword, to simplify passing that information
100582
-** into the selectInnerLoop() routine.
100583
-*/
100584
-typedef struct DistinctCtx DistinctCtx;
100585
-struct DistinctCtx {
100586
- u8 isTnct; /* True if the DISTINCT keyword is present */
100587
- u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
100588
- int tabTnct; /* Ephemeral table used for DISTINCT processing */
100589
- int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
100590
-};
100591
-
100592100901
/*
100593100902
** This routine generates the code for the inside of the inner loop
100594100903
** of a SELECT.
100595100904
**
100596100905
** If srcTab is negative, then the pEList expressions
@@ -100601,11 +100910,11 @@
100601100910
static void selectInnerLoop(
100602100911
Parse *pParse, /* The parser context */
100603100912
Select *p, /* The complete select statement being coded */
100604100913
ExprList *pEList, /* List of values being extracted */
100605100914
int srcTab, /* Pull data from this table */
100606
- ExprList *pOrderBy, /* If not NULL, sort results using this key */
100915
+ SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
100607100916
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
100608100917
SelectDest *pDest, /* How to dispose of the results */
100609100918
int iContinue, /* Jump here to continue with next row */
100610100919
int iBreak /* Jump here to break out of the inner loop */
100611100920
){
@@ -100618,11 +100927,13 @@
100618100927
int nResultCol; /* Number of result columns */
100619100928
100620100929
assert( v );
100621100930
assert( pEList!=0 );
100622100931
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
100623
- if( pOrderBy==0 && !hasDistinct ){
100932
+ if( pSort && pSort->pOrderBy==0 ) pSort = 0;
100933
+ if( pSort==0 && !hasDistinct ){
100934
+ assert( iContinue!=0 );
100624100935
codeOffset(v, p->iOffset, iContinue);
100625100936
}
100626100937
100627100938
/* Pull the requested columns.
100628100939
*/
@@ -100708,11 +101019,11 @@
100708101019
assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
100709101020
codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
100710101021
break;
100711101022
}
100712101023
}
100713
- if( pOrderBy==0 ){
101024
+ if( pSort==0 ){
100714101025
codeOffset(v, p->iOffset, iContinue);
100715101026
}
100716101027
}
100717101028
100718101029
switch( eDest ){
@@ -100739,32 +101050,33 @@
100739101050
}
100740101051
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
100741101052
100742101053
/* Store the result as data using a unique key.
100743101054
*/
100744
- case SRT_DistTable:
101055
+ case SRT_Fifo:
101056
+ case SRT_DistFifo:
100745101057
case SRT_Table:
100746101058
case SRT_EphemTab: {
100747101059
int r1 = sqlite3GetTempReg(pParse);
100748101060
testcase( eDest==SRT_Table );
100749101061
testcase( eDest==SRT_EphemTab );
100750101062
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
100751101063
#ifndef SQLITE_OMIT_CTE
100752
- if( eDest==SRT_DistTable ){
100753
- /* If the destination is DistTable, then cursor (iParm+1) is open
101064
+ if( eDest==SRT_DistFifo ){
101065
+ /* If the destination is DistFifo, then cursor (iParm+1) is open
100754101066
** on an ephemeral index. If the current row is already present
100755101067
** in the index, do not write it to the output. If not, add the
100756101068
** current row to the index and proceed with writing it to the
100757101069
** output table as well. */
100758101070
int addr = sqlite3VdbeCurrentAddr(v) + 4;
100759101071
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
100760101072
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
100761
- assert( pOrderBy==0 );
101073
+ assert( pSort==0 );
100762101074
}
100763101075
#endif
100764
- if( pOrderBy ){
100765
- pushOntoSorter(pParse, pOrderBy, p, r1);
101076
+ if( pSort ){
101077
+ pushOntoSorter(pParse, pSort, p, r1);
100766101078
}else{
100767101079
int r2 = sqlite3GetTempReg(pParse);
100768101080
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
100769101081
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
100770101082
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -100781,16 +101093,16 @@
100781101093
*/
100782101094
case SRT_Set: {
100783101095
assert( nResultCol==1 );
100784101096
pDest->affSdst =
100785101097
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
100786
- if( pOrderBy ){
101098
+ if( pSort ){
100787101099
/* At first glance you would think we could optimize out the
100788101100
** ORDER BY in this case since the order of entries in the set
100789101101
** does not matter. But there might be a LIMIT clause, in which
100790101102
** case the order does matter */
100791
- pushOntoSorter(pParse, pOrderBy, p, regResult);
101103
+ pushOntoSorter(pParse, pSort, p, regResult);
100792101104
}else{
100793101105
int r1 = sqlite3GetTempReg(pParse);
100794101106
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
100795101107
sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
100796101108
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
@@ -100811,12 +101123,12 @@
100811101123
** store the results in the appropriate memory cell and break out
100812101124
** of the scan loop.
100813101125
*/
100814101126
case SRT_Mem: {
100815101127
assert( nResultCol==1 );
100816
- if( pOrderBy ){
100817
- pushOntoSorter(pParse, pOrderBy, p, regResult);
101128
+ if( pSort ){
101129
+ pushOntoSorter(pParse, pSort, p, regResult);
100818101130
}else{
100819101131
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
100820101132
/* The LIMIT clause will jump out of the loop for us */
100821101133
}
100822101134
break;
@@ -100825,14 +101137,14 @@
100825101137
100826101138
case SRT_Coroutine: /* Send data to a co-routine */
100827101139
case SRT_Output: { /* Return the results */
100828101140
testcase( eDest==SRT_Coroutine );
100829101141
testcase( eDest==SRT_Output );
100830
- if( pOrderBy ){
101142
+ if( pSort ){
100831101143
int r1 = sqlite3GetTempReg(pParse);
100832101144
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
100833
- pushOntoSorter(pParse, pOrderBy, p, r1);
101145
+ pushOntoSorter(pParse, pSort, p, r1);
100834101146
sqlite3ReleaseTempReg(pParse, r1);
100835101147
}else if( eDest==SRT_Coroutine ){
100836101148
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
100837101149
}else{
100838101150
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
@@ -100905,11 +101217,11 @@
100905101217
100906101218
/* Jump to the end of the loop if the LIMIT is reached. Except, if
100907101219
** there is a sorter, in which case the sorter has already limited
100908101220
** the output for us.
100909101221
*/
100910
- if( pOrderBy==0 && p->iLimit ){
101222
+ if( pSort==0 && p->iLimit ){
100911101223
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
100912101224
}
100913101225
}
100914101226
100915101227
/*
@@ -100976,27 +101288,32 @@
100976101288
**
100977101289
** Space to hold the KeyInfo structure is obtain from malloc. The calling
100978101290
** function is responsible for seeing that this structure is eventually
100979101291
** freed.
100980101292
*/
100981
-static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
101293
+static KeyInfo *keyInfoFromExprList(
101294
+ Parse *pParse, /* Parsing context */
101295
+ ExprList *pList, /* Form the KeyInfo object from this ExprList */
101296
+ int iStart, /* Begin with this column of pList */
101297
+ int nExtra /* Add this many extra columns to the end */
101298
+){
100982101299
int nExpr;
100983101300
KeyInfo *pInfo;
100984101301
struct ExprList_item *pItem;
100985101302
sqlite3 *db = pParse->db;
100986101303
int i;
100987101304
100988101305
nExpr = pList->nExpr;
100989
- pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1);
101306
+ pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
100990101307
if( pInfo ){
100991101308
assert( sqlite3KeyInfoIsWriteable(pInfo) );
100992
- for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
101309
+ for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
100993101310
CollSeq *pColl;
100994101311
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
100995101312
if( !pColl ) pColl = db->pDfltColl;
100996
- pInfo->aColl[i] = pColl;
100997
- pInfo->aSortOrder[i] = pItem->sortOrder;
101313
+ pInfo->aColl[i-iStart] = pColl;
101314
+ pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
100998101315
}
100999101316
}
101000101317
return pInfo;
101001101318
}
101002101319
@@ -101094,50 +101411,60 @@
101094101411
** routine generates the code needed to do that.
101095101412
*/
101096101413
static void generateSortTail(
101097101414
Parse *pParse, /* Parsing context */
101098101415
Select *p, /* The SELECT statement */
101099
- Vdbe *v, /* Generate code into this VDBE */
101416
+ SortCtx *pSort, /* Information on the ORDER BY clause */
101100101417
int nColumn, /* Number of columns of data */
101101101418
SelectDest *pDest /* Write the sorted results here */
101102101419
){
101420
+ Vdbe *v = pParse->pVdbe; /* The prepared statement */
101103101421
int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
101104101422
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
101105101423
int addr;
101424
+ int addrOnce = 0;
101106101425
int iTab;
101107101426
int pseudoTab = 0;
101108
- ExprList *pOrderBy = p->pOrderBy;
101109
-
101427
+ ExprList *pOrderBy = pSort->pOrderBy;
101110101428
int eDest = pDest->eDest;
101111101429
int iParm = pDest->iSDParm;
101112
-
101113101430
int regRow;
101114101431
int regRowid;
101432
+ int nKey;
101115101433
101116
- iTab = pOrderBy->iECursor;
101434
+ if( pSort->labelBkOut ){
101435
+ sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
101436
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
101437
+ sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
101438
+ addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
101439
+ }
101440
+ iTab = pSort->iECursor;
101117101441
regRow = sqlite3GetTempReg(pParse);
101118101442
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
101119101443
pseudoTab = pParse->nTab++;
101120101444
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
101121101445
regRowid = 0;
101122101446
}else{
101123101447
regRowid = sqlite3GetTempReg(pParse);
101124101448
}
101125
- if( p->selFlags & SF_UseSorter ){
101449
+ nKey = pOrderBy->nExpr - pSort->nOBSat;
101450
+ if( pSort->sortFlags & SORTFLAG_UseSorter ){
101126101451
int regSortOut = ++pParse->nMem;
101127101452
int ptab2 = pParse->nTab++;
101128
- sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2);
101453
+ sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2);
101454
+ if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
101129101455
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
101130101456
VdbeCoverage(v);
101131101457
codeOffset(v, p->iOffset, addrContinue);
101132101458
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
101133
- sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow);
101459
+ sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow);
101134101460
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
101135101461
}else{
101462
+ if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
101136101463
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
101137101464
codeOffset(v, p->iOffset, addrContinue);
101138
- sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow);
101465
+ sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow);
101139101466
}
101140101467
switch( eDest ){
101141101468
case SRT_Table:
101142101469
case SRT_EphemTab: {
101143101470
testcase( eDest==SRT_Table );
@@ -101188,15 +101515,16 @@
101188101515
sqlite3ReleaseTempReg(pParse, regRowid);
101189101516
101190101517
/* The bottom of the loop
101191101518
*/
101192101519
sqlite3VdbeResolveLabel(v, addrContinue);
101193
- if( p->selFlags & SF_UseSorter ){
101520
+ if( pSort->sortFlags & SORTFLAG_UseSorter ){
101194101521
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
101195101522
}else{
101196101523
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
101197101524
}
101525
+ if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
101198101526
sqlite3VdbeResolveLabel(v, addrBreak);
101199101527
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
101200101528
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
101201101529
}
101202101530
}
@@ -101874,11 +102202,11 @@
101874102202
int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
101875102203
int iCurrent = 0; /* The Current table */
101876102204
int regCurrent; /* Register holding Current table */
101877102205
int iQueue; /* The Queue table */
101878102206
int iDistinct = 0; /* To ensure unique results if UNION */
101879
- int eDest = SRT_Table; /* How to write to Queue */
102207
+ int eDest = SRT_Fifo; /* How to write to Queue */
101880102208
SelectDest destQueue; /* SelectDest targetting the Queue table */
101881102209
int i; /* Loop counter */
101882102210
int rc; /* Result code */
101883102211
ExprList *pOrderBy; /* The ORDER BY clause */
101884102212
Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */
@@ -101906,17 +102234,17 @@
101906102234
}
101907102235
}
101908102236
101909102237
/* Allocate cursors numbers for Queue and Distinct. The cursor number for
101910102238
** the Distinct table must be exactly one greater than Queue in order
101911
- ** for the SRT_DistTable and SRT_DistQueue destinations to work. */
102239
+ ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */
101912102240
iQueue = pParse->nTab++;
101913102241
if( p->op==TK_UNION ){
101914
- eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable;
102242
+ eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
101915102243
iDistinct = pParse->nTab++;
101916102244
}else{
101917
- eDest = pOrderBy ? SRT_Queue : SRT_Table;
102245
+ eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
101918102246
}
101919102247
sqlite3SelectDestInit(&destQueue, eDest, iQueue);
101920102248
101921102249
/* Allocate cursors for Current, Queue, and Distinct. */
101922102250
regCurrent = ++pParse->nMem;
@@ -101978,10 +102306,11 @@
101978102306
/* Keep running the loop until the Queue is empty */
101979102307
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
101980102308
sqlite3VdbeResolveLabel(v, addrBreak);
101981102309
101982102310
end_of_recursive_query:
102311
+ sqlite3ExprListDelete(pParse->db, p->pOrderBy);
101983102312
p->pOrderBy = pOrderBy;
101984102313
p->pLimit = pLimit;
101985102314
p->pOffset = pOffset;
101986102315
return;
101987102316
}
@@ -104349,11 +104678,11 @@
104349104678
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
104350104679
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
104351104680
"argument");
104352104681
pFunc->iDistinct = -1;
104353104682
}else{
104354
- KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0);
104683
+ KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
104355104684
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
104356104685
(char*)pKeyInfo, P4_KEYINFO);
104357104686
}
104358104687
}
104359104688
}
@@ -104504,16 +104833,15 @@
104504104833
Vdbe *v; /* The virtual machine under construction */
104505104834
int isAgg; /* True for select lists like "count(*)" */
104506104835
ExprList *pEList; /* List of columns to extract. */
104507104836
SrcList *pTabList; /* List of tables to select from */
104508104837
Expr *pWhere; /* The WHERE clause. May be NULL */
104509
- ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
104510104838
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
104511104839
Expr *pHaving; /* The HAVING clause. May be NULL */
104512104840
int rc = 1; /* Value to return from this function */
104513
- int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
104514104841
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
104842
+ SortCtx sSort; /* Info on how to code the ORDER BY clause */
104515104843
AggInfo sAggInfo; /* Information used by aggregate queries */
104516104844
int iEnd; /* Address of the end of the query */
104517104845
sqlite3 *db; /* The database connection */
104518104846
104519104847
#ifndef SQLITE_OMIT_EXPLAIN
@@ -104526,21 +104854,28 @@
104526104854
return 1;
104527104855
}
104528104856
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
104529104857
memset(&sAggInfo, 0, sizeof(sAggInfo));
104530104858
104859
+ assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
104860
+ assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
104861
+ assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
104862
+ assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
104531104863
if( IgnorableOrderby(pDest) ){
104532104864
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
104533
- pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard);
104865
+ pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
104866
+ pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
104867
+ pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
104534104868
/* If ORDER BY makes no difference in the output then neither does
104535104869
** DISTINCT so it can be removed too. */
104536104870
sqlite3ExprListDelete(db, p->pOrderBy);
104537104871
p->pOrderBy = 0;
104538104872
p->selFlags &= ~SF_Distinct;
104539104873
}
104540104874
sqlite3SelectPrep(pParse, p, 0);
104541
- pOrderBy = p->pOrderBy;
104875
+ memset(&sSort, 0, sizeof(sSort));
104876
+ sSort.pOrderBy = p->pOrderBy;
104542104877
pTabList = p->pSrc;
104543104878
pEList = p->pEList;
104544104879
if( pParse->nErr || db->mallocFailed ){
104545104880
goto select_end;
104546104881
}
@@ -104658,11 +104993,11 @@
104658104993
goto select_end;
104659104994
}
104660104995
pParse->nHeight -= sqlite3SelectExprHeight(p);
104661104996
pTabList = p->pSrc;
104662104997
if( !IgnorableOrderby(pDest) ){
104663
- pOrderBy = p->pOrderBy;
104998
+ sSort.pOrderBy = p->pOrderBy;
104664104999
}
104665105000
}
104666105001
pEList = p->pEList;
104667105002
#endif
104668105003
pWhere = p->pWhere;
@@ -104685,13 +105020,13 @@
104685105020
** will cause elements to come out in the correct order. This is
104686105021
** an optimization - the correct answer should result regardless.
104687105022
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
104688105023
** to disable this optimization for testing purposes.
104689105024
*/
104690
- if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0
105025
+ if( sqlite3ExprListCompare(p->pGroupBy, sSort.pOrderBy, -1)==0
104691105026
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
104692
- pOrderBy = 0;
105027
+ sSort.pOrderBy = 0;
104693105028
}
104694105029
104695105030
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
104696105031
** if the select-list is the same as the ORDER BY list, then this query
104697105032
** can be rewritten as a GROUP BY. In other words, this:
@@ -104706,16 +105041,16 @@
104706105041
** used for both the ORDER BY and DISTINCT processing. As originally
104707105042
** written the query must use a temp-table for at least one of the ORDER
104708105043
** BY and DISTINCT, and an index or separate temp-table for the other.
104709105044
*/
104710105045
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
104711
- && sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0
105046
+ && sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
104712105047
){
104713105048
p->selFlags &= ~SF_Distinct;
104714105049
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
104715105050
pGroupBy = p->pGroupBy;
104716
- pOrderBy = 0;
105051
+ sSort.pOrderBy = 0;
104717105052
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
104718105053
** the sDistinct.isTnct is still set. Hence, isTnct represents the
104719105054
** original setting of the SF_Distinct flag, not the current setting */
104720105055
assert( sDistinct.isTnct );
104721105056
}
@@ -104725,20 +105060,20 @@
104725105060
** extracted in pre-sorted order. If that is the case, then the
104726105061
** OP_OpenEphemeral instruction will be changed to an OP_Noop once
104727105062
** we figure out that the sorting index is not needed. The addrSortIndex
104728105063
** variable is used to facilitate that change.
104729105064
*/
104730
- if( pOrderBy ){
105065
+ if( sSort.pOrderBy ){
104731105066
KeyInfo *pKeyInfo;
104732
- pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0);
104733
- pOrderBy->iECursor = pParse->nTab++;
104734
- p->addrOpenEphm[2] = addrSortIndex =
105067
+ pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
105068
+ sSort.iECursor = pParse->nTab++;
105069
+ sSort.addrSortIndex =
104735105070
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
104736
- pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
105071
+ sSort.iECursor, sSort.pOrderBy->nExpr+2, 0,
104737105072
(char*)pKeyInfo, P4_KEYINFO);
104738105073
}else{
104739
- addrSortIndex = -1;
105074
+ sSort.addrSortIndex = -1;
104740105075
}
104741105076
104742105077
/* If the output is destined for a temporary table, open that table.
104743105078
*/
104744105079
if( pDest->eDest==SRT_EphemTab ){
@@ -104748,22 +105083,22 @@
104748105083
/* Set the limiter.
104749105084
*/
104750105085
iEnd = sqlite3VdbeMakeLabel(v);
104751105086
p->nSelectRow = LARGEST_INT64;
104752105087
computeLimitRegisters(pParse, p, iEnd);
104753
- if( p->iLimit==0 && addrSortIndex>=0 ){
104754
- sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen;
104755
- p->selFlags |= SF_UseSorter;
105088
+ if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
105089
+ sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
105090
+ sSort.sortFlags |= SORTFLAG_UseSorter;
104756105091
}
104757105092
104758105093
/* Open a virtual index to use for the distinct set.
104759105094
*/
104760105095
if( p->selFlags & SF_Distinct ){
104761105096
sDistinct.tabTnct = pParse->nTab++;
104762105097
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
104763105098
sDistinct.tabTnct, 0, 0,
104764
- (char*)keyInfoFromExprList(pParse, p->pEList, 0),
105099
+ (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
104765105100
P4_KEYINFO);
104766105101
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
104767105102
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
104768105103
}else{
104769105104
sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
@@ -104772,32 +105107,36 @@
104772105107
if( !isAgg && pGroupBy==0 ){
104773105108
/* No aggregate functions and no GROUP BY clause */
104774105109
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
104775105110
104776105111
/* Begin the database scan. */
104777
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList,
104778
- wctrlFlags, 0);
105112
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
105113
+ p->pEList, wctrlFlags, 0);
104779105114
if( pWInfo==0 ) goto select_end;
104780105115
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
104781105116
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
104782105117
}
104783105118
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
104784105119
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
104785105120
}
104786
- if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0;
105121
+ if( sSort.pOrderBy ){
105122
+ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
105123
+ if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
105124
+ sSort.pOrderBy = 0;
105125
+ }
105126
+ }
104787105127
104788105128
/* If sorting index that was created by a prior OP_OpenEphemeral
104789105129
** instruction ended up not being needed, then change the OP_OpenEphemeral
104790105130
** into an OP_Noop.
104791105131
*/
104792
- if( addrSortIndex>=0 && pOrderBy==0 ){
104793
- sqlite3VdbeChangeToNoop(v, addrSortIndex);
104794
- p->addrOpenEphm[2] = -1;
105132
+ if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
105133
+ sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
104795105134
}
104796105135
104797105136
/* Use the standard inner loop. */
104798
- selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest,
105137
+ selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
104799105138
sqlite3WhereContinueLabel(pWInfo),
104800105139
sqlite3WhereBreakLabel(pWInfo));
104801105140
104802105141
/* End the database scan loop.
104803105142
*/
@@ -104849,11 +105188,11 @@
104849105188
sNC.pAggInfo = &sAggInfo;
104850105189
sAggInfo.mnReg = pParse->nMem+1;
104851105190
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
104852105191
sAggInfo.pGroupBy = pGroupBy;
104853105192
sqlite3ExprAnalyzeAggList(&sNC, pEList);
104854
- sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
105193
+ sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
104855105194
if( pHaving ){
104856105195
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
104857105196
}
104858105197
sAggInfo.nAccumulator = sAggInfo.nColumn;
104859105198
for(i=0; i<sAggInfo.nFunc; i++){
@@ -104883,11 +105222,11 @@
104883105222
** implement it. Allocate that sorting index now. If it turns out
104884105223
** that we do not need it after all, the OP_SorterOpen instruction
104885105224
** will be converted into a Noop.
104886105225
*/
104887105226
sAggInfo.sortingIdx = pParse->nTab++;
104888
- pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0);
105227
+ pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
104889105228
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
104890105229
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
104891105230
0, (char*)pKeyInfo, P4_KEYINFO);
104892105231
104893105232
/* Initialize memory locations used by GROUP BY aggregate processing
@@ -104912,14 +105251,14 @@
104912105251
** This might involve two separate loops with an OP_Sort in between, or
104913105252
** it might be a single loop that uses an index to extract information
104914105253
** in the right order to begin with.
104915105254
*/
104916105255
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
104917
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
105256
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
104918105257
WHERE_GROUPBY, 0);
104919105258
if( pWInfo==0 ) goto select_end;
104920
- if( sqlite3WhereIsOrdered(pWInfo) ){
105259
+ if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
104921105260
/* The optimizer is able to deliver rows in group by order so
104922105261
** we do not have to sort. The OP_OpenEphemeral table will be
104923105262
** cancelled later because we still need to use the pKeyInfo
104924105263
*/
104925105264
groupBySort = 0;
@@ -105066,11 +105405,11 @@
105066105405
sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
105067105406
VdbeComment((v, "Groupby result generator entry point"));
105068105407
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
105069105408
finalizeAggFunctions(pParse, &sAggInfo);
105070105409
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
105071
- selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy,
105410
+ selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
105072105411
&sDistinct, pDest,
105073105412
addrOutputRow+1, addrSetAbort);
105074105413
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
105075105414
VdbeComment((v, "end groupby result generator"));
105076105415
@@ -105198,20 +105537,20 @@
105198105537
sqlite3ExprListDelete(db, pDel);
105199105538
goto select_end;
105200105539
}
105201105540
updateAccumulator(pParse, &sAggInfo);
105202105541
assert( pMinMax==0 || pMinMax->nExpr==1 );
105203
- if( sqlite3WhereIsOrdered(pWInfo) ){
105542
+ if( sqlite3WhereIsOrdered(pWInfo)>0 ){
105204105543
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
105205105544
VdbeComment((v, "%s() by index",
105206105545
(flag==WHERE_ORDERBY_MIN?"min":"max")));
105207105546
}
105208105547
sqlite3WhereEnd(pWInfo);
105209105548
finalizeAggFunctions(pParse, &sAggInfo);
105210105549
}
105211105550
105212
- pOrderBy = 0;
105551
+ sSort.pOrderBy = 0;
105213105552
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
105214105553
selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
105215105554
pDest, addrEnd, addrEnd);
105216105555
sqlite3ExprListDelete(db, pDel);
105217105556
}
@@ -105224,13 +105563,13 @@
105224105563
}
105225105564
105226105565
/* If there is an ORDER BY clause, then we need to sort the results
105227105566
** and send them to the callback one by one.
105228105567
*/
105229
- if( pOrderBy ){
105230
- explainTempTable(pParse, "ORDER BY");
105231
- generateSortTail(pParse, p, v, pEList->nExpr, pDest);
105568
+ if( sSort.pOrderBy ){
105569
+ explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
105570
+ generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
105232105571
}
105233105572
105234105573
/* Jump here to skip this query
105235105574
*/
105236105575
sqlite3VdbeResolveLabel(v, iEnd);
@@ -109064,11 +109403,11 @@
109064109403
Index *pIndex; /* Index used, or NULL */
109065109404
} btree;
109066109405
struct { /* Information for virtual tables */
109067109406
int idxNum; /* Index number */
109068109407
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
109069
- u8 isOrdered; /* True if satisfies ORDER BY */
109408
+ i8 isOrdered; /* True if satisfies ORDER BY */
109070109409
u16 omitMask; /* Terms that may be omitted */
109071109410
char *idxStr; /* Index identifier string */
109072109411
} vtab;
109073109412
} u;
109074109413
u32 wsFlags; /* WHERE_* flags describing the plan */
@@ -109126,12 +109465,11 @@
109126109465
struct WherePath {
109127109466
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
109128109467
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
109129109468
LogEst nRow; /* Estimated number of rows generated by this path */
109130109469
LogEst rCost; /* Total cost of this path */
109131
- u8 isOrdered; /* True if this path satisfies ORDER BY */
109132
- u8 isOrderedValid; /* True if the isOrdered field is valid */
109470
+ i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
109133109471
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
109134109472
};
109135109473
109136109474
/*
109137109475
** The query generator uses an array of instances of this structure to
@@ -109341,11 +109679,11 @@
109341109679
ExprList *pResultSet; /* Result set. DISTINCT operates on these */
109342109680
WhereLoop *pLoops; /* List of all WhereLoop objects */
109343109681
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
109344109682
LogEst nRowOut; /* Estimated number of output rows */
109345109683
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
109346
- u8 bOBSat; /* ORDER BY satisfied by indices */
109684
+ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
109347109685
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
109348109686
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
109349109687
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
109350109688
u8 nLevel; /* Number of nested loop */
109351109689
int iTop; /* The very beginning of the WHERE loop */
@@ -109425,18 +109763,19 @@
109425109763
/*
109426109764
** Return TRUE if the WHERE clause returns rows in ORDER BY order.
109427109765
** Return FALSE if the output needs to be sorted.
109428109766
*/
109429109767
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
109430
- return pWInfo->bOBSat!=0;
109768
+ return pWInfo->nOBSat;
109431109769
}
109432109770
109433109771
/*
109434109772
** Return the VDBE address or label to jump to in order to continue
109435109773
** immediately with the next row of a WHERE clause.
109436109774
*/
109437109775
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
109776
+ assert( pWInfo->iContinue!=0 );
109438109777
return pWInfo->iContinue;
109439109778
}
109440109779
109441109780
/*
109442109781
** Return the VDBE address or label to jump to in order to break
@@ -112226,11 +112565,11 @@
112226112565
}
112227112566
pLevel->op = OP_VNext;
112228112567
pLevel->p1 = iCur;
112229112568
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
112230112569
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
112231
- sqlite3ExprCachePop(pParse, 1);
112570
+ sqlite3ExprCachePop(pParse);
112232112571
}else
112233112572
#endif /* SQLITE_OMIT_VIRTUALTABLE */
112234112573
112235112574
if( (pLoop->wsFlags & WHERE_IPK)!=0
112236112575
&& (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
@@ -112422,12 +112761,15 @@
112422112761
** a single iteration. This means that the first row returned
112423112762
** should not have a NULL value stored in 'x'. If column 'x' is
112424112763
** the first one after the nEq equality constraints in the index,
112425112764
** this requires some special handling.
112426112765
*/
112766
+ assert( pWInfo->pOrderBy==0
112767
+ || pWInfo->pOrderBy->nExpr==1
112768
+ || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
112427112769
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
112428
- && (pWInfo->bOBSat!=0)
112770
+ && pWInfo->nOBSat>0
112429112771
&& (pIdx->nKeyCol>nEq)
112430112772
){
112431112773
assert( pLoop->u.btree.nSkip==0 );
112432112774
bSeekPastNull = 1;
112433112775
nExtraReg = 1;
@@ -112594,12 +112936,11 @@
112594112936
pLevel->op = OP_Prev;
112595112937
}else{
112596112938
pLevel->op = OP_Next;
112597112939
}
112598112940
pLevel->p1 = iIdxCur;
112599
- assert( (WHERE_UNQ_WANTED>>16)==1 );
112600
- pLevel->p3 = (pLoop->wsFlags>>16)&1;
112941
+ pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
112601112942
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
112602112943
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
112603112944
}else{
112604112945
assert( pLevel->p5==0 );
112605112946
}
@@ -113093,10 +113434,141 @@
113093113434
whereLoopDelete(db, p);
113094113435
}
113095113436
sqlite3DbFree(db, pWInfo);
113096113437
}
113097113438
}
113439
+
113440
+/*
113441
+** Return TRUE if both of the following are true:
113442
+**
113443
+** (1) X has the same or lower cost that Y
113444
+** (2) X is a proper subset of Y
113445
+**
113446
+** By "proper subset" we mean that X uses fewer WHERE clause terms
113447
+** than Y and that every WHERE clause term used by X is also used
113448
+** by Y.
113449
+**
113450
+** If X is a proper subset of Y then Y is a better choice and ought
113451
+** to have a lower cost. This routine returns TRUE when that cost
113452
+** relationship is inverted and needs to be adjusted.
113453
+*/
113454
+static int whereLoopCheaperProperSubset(
113455
+ const WhereLoop *pX, /* First WhereLoop to compare */
113456
+ const WhereLoop *pY /* Compare against this WhereLoop */
113457
+){
113458
+ int i, j;
113459
+ if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
113460
+ if( pX->rRun >= pY->rRun ){
113461
+ if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
113462
+ if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
113463
+ }
113464
+ for(j=0, i=pX->nLTerm-1; i>=0; i--){
113465
+ for(j=pY->nLTerm-1; j>=0; j--){
113466
+ if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
113467
+ }
113468
+ if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
113469
+ }
113470
+ return 1; /* All conditions meet */
113471
+}
113472
+
113473
+/*
113474
+** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
113475
+** that:
113476
+**
113477
+** (1) pTemplate costs less than any other WhereLoops that are a proper
113478
+** subset of pTemplate
113479
+**
113480
+** (2) pTemplate costs more than any other WhereLoops for which pTemplate
113481
+** is a proper subset.
113482
+**
113483
+** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
113484
+** WHERE clause terms than Y and that every WHERE clause term used by X is
113485
+** also used by Y.
113486
+*/
113487
+static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
113488
+ if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
113489
+ for(; p; p=p->pNextLoop){
113490
+ if( p->iTab!=pTemplate->iTab ) continue;
113491
+ if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
113492
+ if( whereLoopCheaperProperSubset(p, pTemplate) ){
113493
+ /* Adjust pTemplate cost downward so that it is cheaper than its
113494
+ ** subset p */
113495
+ pTemplate->rRun = p->rRun;
113496
+ pTemplate->nOut = p->nOut - 1;
113497
+ }else if( whereLoopCheaperProperSubset(pTemplate, p) ){
113498
+ /* Adjust pTemplate cost upward so that it is costlier than p since
113499
+ ** pTemplate is a proper subset of p */
113500
+ pTemplate->rRun = p->rRun;
113501
+ pTemplate->nOut = p->nOut + 1;
113502
+ }
113503
+ }
113504
+}
113505
+
113506
+/*
113507
+** Search the list of WhereLoops in *ppPrev looking for one that can be
113508
+** supplanted by pTemplate.
113509
+**
113510
+** Return NULL if the WhereLoop list contains an entry that can supplant
113511
+** pTemplate, in other words if pTemplate does not belong on the list.
113512
+**
113513
+** If pX is a WhereLoop that pTemplate can supplant, then return the
113514
+** link that points to pX.
113515
+**
113516
+** If pTemplate cannot supplant any existing element of the list but needs
113517
+** to be added to the list, then return a pointer to the tail of the list.
113518
+*/
113519
+static WhereLoop **whereLoopFindLesser(
113520
+ WhereLoop **ppPrev,
113521
+ const WhereLoop *pTemplate
113522
+){
113523
+ WhereLoop *p;
113524
+ for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){
113525
+ if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
113526
+ /* If either the iTab or iSortIdx values for two WhereLoop are different
113527
+ ** then those WhereLoops need to be considered separately. Neither is
113528
+ ** a candidate to replace the other. */
113529
+ continue;
113530
+ }
113531
+ /* In the current implementation, the rSetup value is either zero
113532
+ ** or the cost of building an automatic index (NlogN) and the NlogN
113533
+ ** is the same for compatible WhereLoops. */
113534
+ assert( p->rSetup==0 || pTemplate->rSetup==0
113535
+ || p->rSetup==pTemplate->rSetup );
113536
+
113537
+ /* whereLoopAddBtree() always generates and inserts the automatic index
113538
+ ** case first. Hence compatible candidate WhereLoops never have a larger
113539
+ ** rSetup. Call this SETUP-INVARIANT */
113540
+ assert( p->rSetup>=pTemplate->rSetup );
113541
+
113542
+ /* If existing WhereLoop p is better than pTemplate, pTemplate can be
113543
+ ** discarded. WhereLoop p is better if:
113544
+ ** (1) p has no more dependencies than pTemplate, and
113545
+ ** (2) p has an equal or lower cost than pTemplate
113546
+ */
113547
+ if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */
113548
+ && p->rSetup<=pTemplate->rSetup /* (2a) */
113549
+ && p->rRun<=pTemplate->rRun /* (2b) */
113550
+ && p->nOut<=pTemplate->nOut /* (2c) */
113551
+ ){
113552
+ return 0; /* Discard pTemplate */
113553
+ }
113554
+
113555
+ /* If pTemplate is always better than p, then cause p to be overwritten
113556
+ ** with pTemplate. pTemplate is better than p if:
113557
+ ** (1) pTemplate has no more dependences than p, and
113558
+ ** (2) pTemplate has an equal or lower cost than p.
113559
+ */
113560
+ if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
113561
+ && p->rRun>=pTemplate->rRun /* (2a) */
113562
+ && p->nOut>=pTemplate->nOut /* (2b) */
113563
+ ){
113564
+ assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
113565
+ break; /* Cause p to be overwritten by pTemplate */
113566
+ }
113567
+ }
113568
+ return ppPrev;
113569
+}
113098113570
113099113571
/*
113100113572
** Insert or replace a WhereLoop entry using the template supplied.
113101113573
**
113102113574
** An existing WhereLoop entry might be overwritten if the new template
@@ -113103,29 +113575,27 @@
113103113575
** is better and has fewer dependencies. Or the template will be ignored
113104113576
** and no insert will occur if an existing WhereLoop is faster and has
113105113577
** fewer dependencies than the template. Otherwise a new WhereLoop is
113106113578
** added based on the template.
113107113579
**
113108
-** If pBuilder->pOrSet is not NULL then we only care about only the
113580
+** If pBuilder->pOrSet is not NULL then we care about only the
113109113581
** prerequisites and rRun and nOut costs of the N best loops. That
113110113582
** information is gathered in the pBuilder->pOrSet object. This special
113111113583
** processing mode is used only for OR clause processing.
113112113584
**
113113113585
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
113114113586
** still might overwrite similar loops with the new template if the
113115
-** template is better. Loops may be overwritten if the following
113587
+** new template is better. Loops may be overwritten if the following
113116113588
** conditions are met:
113117113589
**
113118113590
** (1) They have the same iTab.
113119113591
** (2) They have the same iSortIdx.
113120113592
** (3) The template has same or fewer dependencies than the current loop
113121113593
** (4) The template has the same or lower cost than the current loop
113122
-** (5) The template uses more terms of the same index but has no additional
113123
-** dependencies
113124113594
*/
113125113595
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
113126
- WhereLoop **ppPrev, *p, *pNext = 0;
113596
+ WhereLoop **ppPrev, *p;
113127113597
WhereInfo *pWInfo = pBuilder->pWInfo;
113128113598
sqlite3 *db = pWInfo->pParse->db;
113129113599
113130113600
/* If pBuilder->pOrSet is defined, then only keep track of the costs
113131113601
** and prereqs.
@@ -113144,68 +113614,27 @@
113144113614
}
113145113615
#endif
113146113616
return SQLITE_OK;
113147113617
}
113148113618
113149
- /* Search for an existing WhereLoop to overwrite, or which takes
113150
- ** priority over pTemplate.
113619
+ /* Look for an existing WhereLoop to replace with pTemplate
113151113620
*/
113152
- for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){
113153
- if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
113154
- /* If either the iTab or iSortIdx values for two WhereLoop are different
113155
- ** then those WhereLoops need to be considered separately. Neither is
113156
- ** a candidate to replace the other. */
113157
- continue;
113158
- }
113159
- /* In the current implementation, the rSetup value is either zero
113160
- ** or the cost of building an automatic index (NlogN) and the NlogN
113161
- ** is the same for compatible WhereLoops. */
113162
- assert( p->rSetup==0 || pTemplate->rSetup==0
113163
- || p->rSetup==pTemplate->rSetup );
113164
-
113165
- /* whereLoopAddBtree() always generates and inserts the automatic index
113166
- ** case first. Hence compatible candidate WhereLoops never have a larger
113167
- ** rSetup. Call this SETUP-INVARIANT */
113168
- assert( p->rSetup>=pTemplate->rSetup );
113169
-
113170
- if( (p->prereq & pTemplate->prereq)==p->prereq
113171
- && p->rSetup<=pTemplate->rSetup
113172
- && p->rRun<=pTemplate->rRun
113173
- && p->nOut<=pTemplate->nOut
113174
- ){
113175
- /* This branch taken when p is equal or better than pTemplate in
113176
- ** all of (1) dependencies (2) setup-cost, (3) run-cost, and
113177
- ** (4) number of output rows. */
113178
- assert( p->rSetup==pTemplate->rSetup );
113179
- if( p->prereq==pTemplate->prereq
113180
- && p->nLTerm<pTemplate->nLTerm
113181
- && (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0
113182
- && (p->u.btree.pIndex==pTemplate->u.btree.pIndex
113183
- || pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm)
113184
- ){
113185
- /* Overwrite an existing WhereLoop with an similar one that uses
113186
- ** more terms of the index */
113187
- pNext = p->pNextLoop;
113188
- break;
113189
- }else{
113190
- /* pTemplate is not helpful.
113191
- ** Return without changing or adding anything */
113192
- goto whereLoopInsert_noop;
113193
- }
113194
- }
113195
- if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
113196
- && p->rRun>=pTemplate->rRun
113197
- && p->nOut>=pTemplate->nOut
113198
- ){
113199
- /* Overwrite an existing WhereLoop with a better one: one that is
113200
- ** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
113201
- ** or (4) number of output rows, and is no worse in any of those
113202
- ** categories. */
113203
- assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
113204
- pNext = p->pNextLoop;
113205
- break;
113206
- }
113621
+ whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
113622
+ ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
113623
+
113624
+ if( ppPrev==0 ){
113625
+ /* There already exists a WhereLoop on the list that is better
113626
+ ** than pTemplate, so just ignore pTemplate */
113627
+#if WHERETRACE_ENABLED /* 0x8 */
113628
+ if( sqlite3WhereTrace & 0x8 ){
113629
+ sqlite3DebugPrintf("ins-noop: ");
113630
+ whereLoopPrint(pTemplate, pBuilder->pWC);
113631
+ }
113632
+#endif
113633
+ return SQLITE_OK;
113634
+ }else{
113635
+ p = *ppPrev;
113207113636
}
113208113637
113209113638
/* If we reach this point it means that either p[] should be overwritten
113210113639
** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
113211113640
** WhereLoop and insert it.
@@ -113219,34 +113648,44 @@
113219113648
sqlite3DebugPrintf("ins-new: ");
113220113649
whereLoopPrint(pTemplate, pBuilder->pWC);
113221113650
}
113222113651
#endif
113223113652
if( p==0 ){
113224
- p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
113653
+ /* Allocate a new WhereLoop to add to the end of the list */
113654
+ *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
113225113655
if( p==0 ) return SQLITE_NOMEM;
113226113656
whereLoopInit(p);
113657
+ p->pNextLoop = 0;
113658
+ }else{
113659
+ /* We will be overwriting WhereLoop p[]. But before we do, first
113660
+ ** go through the rest of the list and delete any other entries besides
113661
+ ** p[] that are also supplated by pTemplate */
113662
+ WhereLoop **ppTail = &p->pNextLoop;
113663
+ WhereLoop *pToDel;
113664
+ while( *ppTail ){
113665
+ ppTail = whereLoopFindLesser(ppTail, pTemplate);
113666
+ if( NEVER(ppTail==0) ) break;
113667
+ pToDel = *ppTail;
113668
+ if( pToDel==0 ) break;
113669
+ *ppTail = pToDel->pNextLoop;
113670
+#if WHERETRACE_ENABLED /* 0x8 */
113671
+ if( sqlite3WhereTrace & 0x8 ){
113672
+ sqlite3DebugPrintf("ins-del: ");
113673
+ whereLoopPrint(pToDel, pBuilder->pWC);
113674
+ }
113675
+#endif
113676
+ whereLoopDelete(db, pToDel);
113677
+ }
113227113678
}
113228113679
whereLoopXfer(db, p, pTemplate);
113229
- p->pNextLoop = pNext;
113230
- *ppPrev = p;
113231113680
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
113232113681
Index *pIndex = p->u.btree.pIndex;
113233113682
if( pIndex && pIndex->tnum==0 ){
113234113683
p->u.btree.pIndex = 0;
113235113684
}
113236113685
}
113237113686
return SQLITE_OK;
113238
-
113239
- /* Jump here if the insert is a no-op */
113240
-whereLoopInsert_noop:
113241
-#if WHERETRACE_ENABLED /* 0x8 */
113242
- if( sqlite3WhereTrace & 0x8 ){
113243
- sqlite3DebugPrintf("ins-noop: ");
113244
- whereLoopPrint(pTemplate, pBuilder->pWC);
113245
- }
113246
-#endif
113247
- return SQLITE_OK;
113248113687
}
113249113688
113250113689
/*
113251113690
** Adjust the WhereLoop.nOut value downward to account for terms of the
113252113691
** WHERE clause that reference the loop but which are not used by an
@@ -113396,10 +113835,12 @@
113396113835
nIn = 46; assert( 46==sqlite3LogEst(25) );
113397113836
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
113398113837
/* "x IN (value, value, ...)" */
113399113838
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
113400113839
}
113840
+ assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
113841
+ ** changes "x IN (?)" into "x=?". */
113401113842
pNew->rRun += nIn;
113402113843
pNew->u.btree.nEq++;
113403113844
pNew->nOut = nRowEst + nInMul + nIn;
113404113845
}else if( pTerm->eOperator & (WO_EQ) ){
113405113846
assert(
@@ -113709,22 +114150,38 @@
113709114150
&& sqlite3GlobalConfig.bUseCis
113710114151
&& OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
113711114152
)
113712114153
){
113713114154
pNew->iSortIdx = b ? iSortIdx : 0;
114155
+ /* TUNING: The base cost of an index scan is N + log2(N).
114156
+ ** The log2(N) is for the initial seek to the beginning and the N
114157
+ ** is for the scan itself. */
114158
+ pNew->rRun = sqlite3LogEstAdd(rSize, rLogSize);
113714114159
if( m==0 ){
113715114160
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
113716114161
** + The extra factor K of between 1.1 and 3.0 that depends
113717114162
** on the relative sizes of the table and the index. K
113718114163
** is smaller for smaller indices, thus favoring them.
114164
+ ** The upper bound on K (3.0) matches the penalty factor
114165
+ ** on a full table scan that tries to encourage the use of
114166
+ ** indexed lookups over full scans.
114167
+ */
114168
+ pNew->rRun += 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
114169
+ }else{
114170
+ /* TUNING: The cost of scanning a non-covering index is multiplied
114171
+ ** by log2(N) to account for the binary search of the main table
114172
+ ** that must happen for each row of the index.
114173
+ ** TODO: Should there be a multiplier here, analogous to the 3x
114174
+ ** multiplier for a fulltable scan or covering index scan, to
114175
+ ** further discourage the use of an index scan? Or is the log2(N)
114176
+ ** term sufficient discouragement?
114177
+ ** TODO: What if some or all of the WHERE clause terms can be
114178
+ ** computed without reference to the original table. Then the
114179
+ ** penality should reduce to logK where K is the number of output
114180
+ ** rows.
113719114181
*/
113720
- pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
113721
- (15*pProbe->szIdxRow)/pTab->szTabRow;
113722
- }else{
113723
- /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
113724
- ** which we will simplify to just N*log2(N) */
113725
- pNew->rRun = rSize + rLogSize;
114182
+ pNew->rRun += rLogSize;
113726114183
}
113727114184
whereLoopOutputAdjust(pWC, pNew);
113728114185
rc = whereLoopInsert(pBuilder, pNew);
113729114186
pNew->nOut = rSize;
113730114187
if( rc ) break;
@@ -113892,12 +114349,12 @@
113892114349
assert( pNew->nLTerm<=pNew->nLSlot );
113893114350
pNew->u.vtab.idxNum = pIdxInfo->idxNum;
113894114351
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
113895114352
pIdxInfo->needToFreeIdxStr = 0;
113896114353
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
113897
- pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
113898
- && pIdxInfo->orderByConsumed);
114354
+ pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
114355
+ pIdxInfo->nOrderBy : 0);
113899114356
pNew->rSetup = 0;
113900114357
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
113901114358
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
113902114359
whereLoopInsert(pBuilder, pNew);
113903114360
if( pNew->u.vtab.needFree ){
@@ -114054,25 +114511,25 @@
114054114511
}
114055114512
114056114513
/*
114057114514
** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
114058114515
** parameters) to see if it outputs rows in the requested ORDER BY
114059
-** (or GROUP BY) without requiring a separate sort operation. Return:
114516
+** (or GROUP BY) without requiring a separate sort operation. Return N:
114060114517
**
114061
-** 0: ORDER BY is not satisfied. Sorting required
114062
-** 1: ORDER BY is satisfied. Omit sorting
114063
-** -1: Unknown at this time
114518
+** N>0: N terms of the ORDER BY clause are satisfied
114519
+** N==0: No terms of the ORDER BY clause are satisfied
114520
+** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
114064114521
**
114065114522
** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
114066114523
** strict. With GROUP BY and DISTINCT the only requirement is that
114067114524
** equivalent rows appear immediately adjacent to one another. GROUP BY
114068114525
** and DISTINT do not require rows to appear in any particular order as long
114069114526
** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT
114070114527
** the pOrderBy terms can be matched in any order. With ORDER BY, the
114071114528
** pOrderBy terms must be matched in strict left-to-right order.
114072114529
*/
114073
-static int wherePathSatisfiesOrderBy(
114530
+static i8 wherePathSatisfiesOrderBy(
114074114531
WhereInfo *pWInfo, /* The WHERE clause */
114075114532
ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
114076114533
WherePath *pPath, /* The WherePath to check */
114077114534
u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
114078114535
u16 nLoop, /* Number of entries in pPath->aLoop[] */
@@ -114252,28 +114709,28 @@
114252114709
if( !pColl ) pColl = db->pDfltColl;
114253114710
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
114254114711
}
114255114712
isMatch = 1;
114256114713
break;
114714
+ }
114715
+ if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
114716
+ /* Make sure the sort order is compatible in an ORDER BY clause.
114717
+ ** Sort order is irrelevant for a GROUP BY clause. */
114718
+ if( revSet ){
114719
+ if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
114720
+ }else{
114721
+ rev = revIdx ^ pOrderBy->a[i].sortOrder;
114722
+ if( rev ) *pRevMask |= MASKBIT(iLoop);
114723
+ revSet = 1;
114724
+ }
114257114725
}
114258114726
if( isMatch ){
114259114727
if( iColumn<0 ){
114260114728
testcase( distinctColumns==0 );
114261114729
distinctColumns = 1;
114262114730
}
114263114731
obSat |= MASKBIT(i);
114264
- if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
114265
- /* Make sure the sort order is compatible in an ORDER BY clause.
114266
- ** Sort order is irrelevant for a GROUP BY clause. */
114267
- if( revSet ){
114268
- if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0;
114269
- }else{
114270
- rev = revIdx ^ pOrderBy->a[i].sortOrder;
114271
- if( rev ) *pRevMask |= MASKBIT(iLoop);
114272
- revSet = 1;
114273
- }
114274
- }
114275114732
}else{
114276114733
/* No match found */
114277114734
if( j==0 || j<nKeyCol ){
114278114735
testcase( isOrderDistinct!=0 );
114279114736
isOrderDistinct = 0;
@@ -114301,12 +114758,18 @@
114301114758
obSat |= MASKBIT(i);
114302114759
}
114303114760
}
114304114761
}
114305114762
} /* End the loop over all WhereLoops from outer-most down to inner-most */
114306
- if( obSat==obDone ) return 1;
114307
- if( !isOrderDistinct ) return 0;
114763
+ if( obSat==obDone ) return (i8)nOrderBy;
114764
+ if( !isOrderDistinct ){
114765
+ for(i=nOrderBy-1; i>0; i--){
114766
+ Bitmask m = MASKBIT(i) - 1;
114767
+ if( (obSat&m)==m ) return i;
114768
+ }
114769
+ return 0;
114770
+ }
114308114771
return -1;
114309114772
}
114310114773
114311114774
#ifdef WHERETRACE_ENABLED
114312114775
/* For debugging use only: */
@@ -114339,15 +114802,15 @@
114339114802
Parse *pParse; /* Parsing context */
114340114803
sqlite3 *db; /* The database connection */
114341114804
int iLoop; /* Loop counter over the terms of the join */
114342114805
int ii, jj; /* Loop counters */
114343114806
int mxI = 0; /* Index of next entry to replace */
114807
+ int nOrderBy; /* Number of ORDER BY clause terms */
114344114808
LogEst rCost; /* Cost of a path */
114345114809
LogEst nOut; /* Number of outputs */
114346114810
LogEst mxCost = 0; /* Maximum cost of a set of paths */
114347114811
LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
114348
- LogEst rSortCost; /* Cost to do a sort */
114349114812
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
114350114813
WherePath *aFrom; /* All nFrom paths at the previous level */
114351114814
WherePath *aTo; /* The nTo best paths at the current level */
114352114815
WherePath *pFrom; /* An element of aFrom[] that we are working on */
114353114816
WherePath *pTo; /* An element of aTo[] that we are working on */
@@ -114385,20 +114848,16 @@
114385114848
aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
114386114849
nFrom = 1;
114387114850
114388114851
/* Precompute the cost of sorting the final result set, if the caller
114389114852
** to sqlite3WhereBegin() was concerned about sorting */
114390
- rSortCost = 0;
114391114853
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
114392
- aFrom[0].isOrderedValid = 1;
114854
+ aFrom[0].isOrdered = 0;
114855
+ nOrderBy = 0;
114393114856
}else{
114394
- /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
114395
- ** number of output rows. The 48 is the expected size of a row to sort.
114396
- ** FIXME: compute a better estimate of the 48 multiplier based on the
114397
- ** result set expressions. */
114398
- rSortCost = nRowEst + estLog(nRowEst);
114399
- WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
114857
+ aFrom[0].isOrdered = -1;
114858
+ nOrderBy = pWInfo->pOrderBy->nExpr;
114400114859
}
114401114860
114402114861
/* Compute successively longer WherePaths using the previous generation
114403114862
** of WherePaths as the basis for the next. Keep track of the mxChoice
114404114863
** best paths at each generation */
@@ -114406,43 +114865,56 @@
114406114865
nTo = 0;
114407114866
for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
114408114867
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
114409114868
Bitmask maskNew;
114410114869
Bitmask revMask = 0;
114411
- u8 isOrderedValid = pFrom->isOrderedValid;
114412
- u8 isOrdered = pFrom->isOrdered;
114870
+ i8 isOrdered = pFrom->isOrdered;
114413114871
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
114414114872
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
114415114873
/* At this point, pWLoop is a candidate to be the next loop.
114416114874
** Compute its cost */
114417114875
rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
114418114876
rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
114419114877
nOut = pFrom->nRow + pWLoop->nOut;
114420114878
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
114421
- if( !isOrderedValid ){
114422
- switch( wherePathSatisfiesOrderBy(pWInfo,
114879
+ if( isOrdered<0 ){
114880
+ isOrdered = wherePathSatisfiesOrderBy(pWInfo,
114423114881
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
114424
- iLoop, pWLoop, &revMask) ){
114425
- case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */
114426
- isOrdered = 1;
114427
- isOrderedValid = 1;
114428
- break;
114429
- case 0: /* No. pFrom+pWLoop will require a separate sort */
114430
- isOrdered = 0;
114431
- isOrderedValid = 1;
114432
- rCost = sqlite3LogEstAdd(rCost, rSortCost);
114433
- break;
114434
- default: /* Cannot tell yet. Try again on the next iteration */
114435
- break;
114882
+ iLoop, pWLoop, &revMask);
114883
+ if( isOrdered>=0 && isOrdered<nOrderBy ){
114884
+ /* TUNING: Estimated cost of sorting is N*log(N).
114885
+ ** If the order-by clause has X terms but only the last Y terms
114886
+ ** are out of order, then block-sorting will reduce the sorting
114887
+ ** cost to N*log(N)*log(Y/X). The log(Y/X) term is computed
114888
+ ** by rScale.
114889
+ ** TODO: Should the sorting cost get a small multiplier to help
114890
+ ** discourage the use of sorting and encourage the use of index
114891
+ ** scans instead?
114892
+ */
114893
+ LogEst rScale, rSortCost;
114894
+ assert( nOrderBy>0 );
114895
+ rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
114896
+ rSortCost = nRowEst + estLog(nRowEst) + rScale;
114897
+ /* TUNING: The cost of implementing DISTINCT using a B-TREE is
114898
+ ** also N*log(N) but it has a larger constant of proportionality.
114899
+ ** Multiply by 3.0. */
114900
+ if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
114901
+ rSortCost += 16;
114902
+ }
114903
+ WHERETRACE(0x002,
114904
+ ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
114905
+ rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost,
114906
+ sqlite3LogEstAdd(rCost,rSortCost)));
114907
+ rCost = sqlite3LogEstAdd(rCost, rSortCost);
114436114908
}
114437114909
}else{
114438114910
revMask = pFrom->revLoop;
114439114911
}
114440114912
/* Check to see if pWLoop should be added to the mxChoice best so far */
114441114913
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
114442114914
if( pTo->maskLoop==maskNew
114443
- && pTo->isOrderedValid==isOrderedValid
114915
+ && ((pTo->isOrdered^isOrdered)&80)==0
114444114916
&& ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
114445114917
(pTo->rCost>=rCost && pTo->nRow>=nOut))
114446114918
){
114447114919
testcase( jj==nTo-1 );
114448114920
break;
@@ -114452,11 +114924,11 @@
114452114924
if( nTo>=mxChoice && rCost>=mxCost ){
114453114925
#ifdef WHERETRACE_ENABLED /* 0x4 */
114454114926
if( sqlite3WhereTrace&0x4 ){
114455114927
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
114456114928
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114457
- isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114929
+ isOrdered>=0 ? isOrdered+'0' : '?');
114458114930
}
114459114931
#endif
114460114932
continue;
114461114933
}
114462114934
/* Add a new Path to the aTo[] set */
@@ -114470,24 +114942,24 @@
114470114942
pTo = &aTo[jj];
114471114943
#ifdef WHERETRACE_ENABLED /* 0x4 */
114472114944
if( sqlite3WhereTrace&0x4 ){
114473114945
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
114474114946
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114475
- isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114947
+ isOrdered>=0 ? isOrdered+'0' : '?');
114476114948
}
114477114949
#endif
114478114950
}else{
114479114951
if( pTo->rCost<=rCost && pTo->nRow<=nOut ){
114480114952
#ifdef WHERETRACE_ENABLED /* 0x4 */
114481114953
if( sqlite3WhereTrace&0x4 ){
114482114954
sqlite3DebugPrintf(
114483114955
"Skip %s cost=%-3d,%3d order=%c",
114484114956
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114485
- isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114957
+ isOrdered>=0 ? isOrdered+'0' : '?');
114486114958
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
114487114959
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114488
- pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
114960
+ pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
114489114961
}
114490114962
#endif
114491114963
testcase( pTo->rCost==rCost );
114492114964
continue;
114493114965
}
@@ -114496,23 +114968,22 @@
114496114968
#ifdef WHERETRACE_ENABLED /* 0x4 */
114497114969
if( sqlite3WhereTrace&0x4 ){
114498114970
sqlite3DebugPrintf(
114499114971
"Update %s cost=%-3d,%3d order=%c",
114500114972
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114501
- isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114973
+ isOrdered>=0 ? isOrdered+'0' : '?');
114502114974
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
114503114975
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114504
- pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
114976
+ pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
114505114977
}
114506114978
#endif
114507114979
}
114508114980
/* pWLoop is a winner. Add it to the set of best so far */
114509114981
pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
114510114982
pTo->revLoop = revMask;
114511114983
pTo->nRow = nOut;
114512114984
pTo->rCost = rCost;
114513
- pTo->isOrderedValid = isOrderedValid;
114514114985
pTo->isOrdered = isOrdered;
114515114986
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
114516114987
pTo->aLoop[iLoop] = pWLoop;
114517114988
if( nTo>=mxChoice ){
114518114989
mxI = 0;
@@ -114533,12 +115004,12 @@
114533115004
if( sqlite3WhereTrace>=2 ){
114534115005
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
114535115006
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
114536115007
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
114537115008
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114538
- pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
114539
- if( pTo->isOrderedValid && pTo->isOrdered ){
115009
+ pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
115010
+ if( pTo->isOrdered>0 ){
114540115011
sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
114541115012
}else{
114542115013
sqlite3DebugPrintf("\n");
114543115014
}
114544115015
}
@@ -114577,17 +115048,22 @@
114577115048
&& nRowEst
114578115049
){
114579115050
Bitmask notUsed;
114580115051
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
114581115052
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
114582
- if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
115053
+ if( rc==pWInfo->pResultSet->nExpr ){
115054
+ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
115055
+ }
114583115056
}
114584
- if( pFrom->isOrdered ){
115057
+ if( pWInfo->pOrderBy ){
114585115058
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
114586
- pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
115059
+ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
115060
+ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
115061
+ }
114587115062
}else{
114588
- pWInfo->bOBSat = 1;
115063
+ pWInfo->nOBSat = pFrom->isOrdered;
115064
+ if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
114589115065
pWInfo->revMask = pFrom->revLoop;
114590115066
}
114591115067
}
114592115068
pWInfo->nRowOut = pFrom->nRow;
114593115069
@@ -114668,11 +115144,11 @@
114668115144
pLoop->nOut = (LogEst)1;
114669115145
pWInfo->a[0].pWLoop = pLoop;
114670115146
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
114671115147
pWInfo->a[0].iTabCur = iCur;
114672115148
pWInfo->nRowOut = 1;
114673
- if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
115149
+ if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
114674115150
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
114675115151
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
114676115152
}
114677115153
#ifdef SQLITE_DEBUG
114678115154
pLoop->cId = '0';
@@ -114772,11 +115248,11 @@
114772115248
*/
114773115249
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
114774115250
Parse *pParse, /* The parser context */
114775115251
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
114776115252
Expr *pWhere, /* The WHERE clause */
114777
- ExprList *pOrderBy, /* An ORDER BY clause, or NULL */
115253
+ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
114778115254
ExprList *pResultSet, /* Result set of the query */
114779115255
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
114780115256
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
114781115257
){
114782115258
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
@@ -114794,10 +115270,14 @@
114794115270
114795115271
114796115272
/* Variable initialization */
114797115273
db = pParse->db;
114798115274
memset(&sWLB, 0, sizeof(sWLB));
115275
+
115276
+ /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
115277
+ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
115278
+ if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
114799115279
sWLB.pOrderBy = pOrderBy;
114800115280
114801115281
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
114802115282
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
114803115283
if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
@@ -114838,11 +115318,11 @@
114838115318
pWInfo->nLevel = nTabList;
114839115319
pWInfo->pParse = pParse;
114840115320
pWInfo->pTabList = pTabList;
114841115321
pWInfo->pOrderBy = pOrderBy;
114842115322
pWInfo->pResultSet = pResultSet;
114843
- pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
115323
+ pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
114844115324
pWInfo->wctrlFlags = wctrlFlags;
114845115325
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
114846115326
pMaskSet = &pWInfo->sMaskSet;
114847115327
sWLB.pWInfo = pWInfo;
114848115328
sWLB.pWC = &pWInfo->sWC;
@@ -114872,11 +115352,11 @@
114872115352
}
114873115353
114874115354
/* Special case: No FROM clause
114875115355
*/
114876115356
if( nTabList==0 ){
114877
- if( pOrderBy ) pWInfo->bOBSat = 1;
115357
+ if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
114878115358
if( wctrlFlags & WHERE_WANT_DISTINCT ){
114879115359
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
114880115360
}
114881115361
}
114882115362
@@ -114983,12 +115463,12 @@
114983115463
}
114984115464
#ifdef WHERETRACE_ENABLED /* !=0 */
114985115465
if( sqlite3WhereTrace ){
114986115466
int ii;
114987115467
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
114988
- if( pWInfo->bOBSat ){
114989
- sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask);
115468
+ if( pWInfo->nOBSat>0 ){
115469
+ sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
114990115470
}
114991115471
switch( pWInfo->eDistinct ){
114992115472
case WHERE_DISTINCT_UNIQUE: {
114993115473
sqlite3DebugPrintf(" DISTINCT=unique");
114994115474
break;
@@ -115266,11 +115746,11 @@
115266115746
k = pLevel->addrBody;
115267115747
pOp = sqlite3VdbeGetOp(v, k);
115268115748
for(; k<last; k++, pOp++){
115269115749
if( pOp->p1!=pLevel->iTabCur ) continue;
115270115750
if( pOp->opcode==OP_Column ){
115271
- pOp->opcode = OP_SCopy;
115751
+ pOp->opcode = OP_Copy;
115272115752
pOp->p1 = pOp->p2 + pTabItem->regResult;
115273115753
pOp->p2 = pOp->p3;
115274115754
pOp->p3 = 0;
115275115755
}else if( pOp->opcode==OP_Rowid ){
115276115756
pOp->opcode = OP_Null;
@@ -118214,10 +118694,37 @@
118214118694
** simplify to constants 0 (false) and 1 (true), respectively,
118215118695
** regardless of the value of expr1.
118216118696
*/
118217118697
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]);
118218118698
sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr);
118699
+ }else if( yymsp[-1].minor.yy14->nExpr==1 ){
118700
+ /* Expressions of the form:
118701
+ **
118702
+ ** expr1 IN (?1)
118703
+ ** expr1 NOT IN (?2)
118704
+ **
118705
+ ** with exactly one value on the RHS can be simplified to something
118706
+ ** like this:
118707
+ **
118708
+ ** expr1 == ?1
118709
+ ** expr1 <> ?2
118710
+ **
118711
+ ** But, the RHS of the == or <> is marked with the EP_Generic flag
118712
+ ** so that it may not contribute to the computation of comparison
118713
+ ** affinity or the collating sequence to use for comparison. Otherwise,
118714
+ ** the semantics would be subtly different from IN or NOT IN.
118715
+ */
118716
+ Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
118717
+ yymsp[-1].minor.yy14->a[0].pExpr = 0;
118718
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
118719
+ /* pRHS cannot be NULL because a malloc error would have been detected
118720
+ ** before now and control would have never reached this point */
118721
+ if( ALWAYS(pRHS) ){
118722
+ pRHS->flags &= ~EP_Collate;
118723
+ pRHS->flags |= EP_Generic;
118724
+ }
118725
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy328 ? TK_NE : TK_EQ, yymsp[-4].minor.yy346.pExpr, pRHS, 0);
118219118726
}else{
118220118727
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
118221118728
if( yygotominor.yy346.pExpr ){
118222118729
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
118223118730
sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
@@ -120834,10 +121341,11 @@
120834121341
Table *pTab = (Table *)sqliteHashData(p);
120835121342
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
120836121343
}
120837121344
}
120838121345
}
121346
+ sqlite3VtabUnlockList(db);
120839121347
sqlite3BtreeLeaveAll(db);
120840121348
#else
120841121349
UNUSED_PARAMETER(db);
120842121350
#endif
120843121351
}
@@ -123237,10 +123745,26 @@
123237123745
case SQLITE_TESTCTRL_ALWAYS: {
123238123746
int x = va_arg(ap,int);
123239123747
rc = ALWAYS(x);
123240123748
break;
123241123749
}
123750
+
123751
+ /*
123752
+ ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
123753
+ **
123754
+ ** The integer returned reveals the byte-order of the computer on which
123755
+ ** SQLite is running:
123756
+ **
123757
+ ** 1 big-endian, determined at run-time
123758
+ ** 10 little-endian, determined at run-time
123759
+ ** 432101 big-endian, determined at compile-time
123760
+ ** 123410 little-endian, determined at compile-time
123761
+ */
123762
+ case SQLITE_TESTCTRL_BYTEORDER: {
123763
+ rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
123764
+ break;
123765
+ }
123242123766
123243123767
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
123244123768
**
123245123769
** Set the nReserve size to N for the main database on the database
123246123770
** connection db.
@@ -124573,11 +125097,11 @@
124573125097
char *zReadExprlist;
124574125098
char *zWriteExprlist;
124575125099
124576125100
int nNodeSize; /* Soft limit for node size */
124577125101
u8 bFts4; /* True for FTS4, false for FTS3 */
124578
- u8 bHasStat; /* True if %_stat table exists */
125102
+ u8 bHasStat; /* True if %_stat table exists (2==unknown) */
124579125103
u8 bHasDocsize; /* True if %_docsize table exists */
124580125104
u8 bDescIdx; /* True if doclists are in reverse order */
124581125105
u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
124582125106
int nPgsz; /* Page size for host database */
124583125107
char *zSegmentsTbl; /* Name of %_segments table */
@@ -126065,14 +126589,11 @@
126065126589
126066126590
/* Check to see if a legacy fts3 table has been "upgraded" by the
126067126591
** addition of a %_stat table so that it can use incremental merge.
126068126592
*/
126069126593
if( !isFts4 && !isCreate ){
126070
- int rc2 = SQLITE_OK;
126071
- fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
126072
- p->zDb, p->zName);
126073
- if( rc2==SQLITE_OK ) p->bHasStat = 1;
126594
+ p->bHasStat = 2;
126074126595
}
126075126596
126076126597
/* Figure out the page-size for the database. This is required in order to
126077126598
** estimate the cost of loading large doclists from the database. */
126078126599
fts3DatabasePageSize(&rc, p);
@@ -127975,11 +128496,38 @@
127975128496
sqlite3Fts3SegmentsClose(p);
127976128497
return rc;
127977128498
}
127978128499
127979128500
/*
127980
-** Implementation of xBegin() method. This is a no-op.
128501
+** If it is currently unknown whether or not the FTS table has an %_stat
128502
+** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat
128503
+** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code
128504
+** if an error occurs.
128505
+*/
128506
+static int fts3SetHasStat(Fts3Table *p){
128507
+ int rc = SQLITE_OK;
128508
+ if( p->bHasStat==2 ){
128509
+ const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
128510
+ char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
128511
+ if( zSql ){
128512
+ sqlite3_stmt *pStmt = 0;
128513
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
128514
+ if( rc==SQLITE_OK ){
128515
+ int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
128516
+ rc = sqlite3_finalize(pStmt);
128517
+ if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
128518
+ }
128519
+ sqlite3_free(zSql);
128520
+ }else{
128521
+ rc = SQLITE_NOMEM;
128522
+ }
128523
+ }
128524
+ return rc;
128525
+}
128526
+
128527
+/*
128528
+** Implementation of xBegin() method.
127981128529
*/
127982128530
static int fts3BeginMethod(sqlite3_vtab *pVtab){
127983128531
Fts3Table *p = (Fts3Table*)pVtab;
127984128532
UNUSED_PARAMETER(pVtab);
127985128533
assert( p->pSegments==0 );
@@ -127986,11 +128534,11 @@
127986128534
assert( p->nPendingData==0 );
127987128535
assert( p->inTransaction!=1 );
127988128536
TESTONLY( p->inTransaction = 1 );
127989128537
TESTONLY( p->mxSavepoint = -1; );
127990128538
p->nLeafAdd = 0;
127991
- return SQLITE_OK;
128539
+ return fts3SetHasStat(p);
127992128540
}
127993128541
127994128542
/*
127995128543
** Implementation of xCommit() method. This is a no-op. The contents of
127996128544
** the pending-terms hash-table have already been flushed into the database
@@ -128235,18 +128783,24 @@
128235128783
){
128236128784
Fts3Table *p = (Fts3Table *)pVtab;
128237128785
sqlite3 *db = p->db; /* Database connection */
128238128786
int rc; /* Return Code */
128239128787
128788
+ /* At this point it must be known if the %_stat table exists or not.
128789
+ ** So bHasStat may not be 2. */
128790
+ rc = fts3SetHasStat(p);
128791
+
128240128792
/* As it happens, the pending terms table is always empty here. This is
128241128793
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
128242128794
** always opens a savepoint transaction. And the xSavepoint() method
128243128795
** flushes the pending terms table. But leave the (no-op) call to
128244128796
** PendingTermsFlush() in in case that changes.
128245128797
*/
128246128798
assert( p->nPendingData==0 );
128247
- rc = sqlite3Fts3PendingTermsFlush(p);
128799
+ if( rc==SQLITE_OK ){
128800
+ rc = sqlite3Fts3PendingTermsFlush(p);
128801
+ }
128248128802
128249128803
if( p->zContentTbl==0 ){
128250128804
fts3DbExec(&rc, db,
128251128805
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
128252128806
p->zDb, p->zName, zName
@@ -139754,10 +140308,14 @@
139754140308
u32 *aSzIns = 0; /* Sizes of inserted documents */
139755140309
u32 *aSzDel = 0; /* Sizes of deleted documents */
139756140310
int nChng = 0; /* Net change in number of documents */
139757140311
int bInsertDone = 0;
139758140312
140313
+ /* At this point it must be known if the %_stat table exists or not.
140314
+ ** So bHasStat may not be 2. */
140315
+ assert( p->bHasStat==0 || p->bHasStat==1 );
140316
+
139759140317
assert( p->pSegments==0 );
139760140318
assert(
139761140319
nArg==1 /* DELETE operations */
139762140320
|| nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
139763140321
);
@@ -145135,30 +145693,36 @@
145135145693
** This function populates the pRtree->nRowEst variable with an estimate
145136145694
** of the number of rows in the virtual table. If possible, this is based
145137145695
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
145138145696
*/
145139145697
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
145140
- const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'";
145698
+ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
145699
+ char *zSql;
145141145700
sqlite3_stmt *p;
145142145701
int rc;
145143145702
i64 nRow = 0;
145144145703
145145
- rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
145146
- if( rc==SQLITE_OK ){
145147
- sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC);
145148
- if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
145149
- rc = sqlite3_finalize(p);
145150
- }else if( rc!=SQLITE_NOMEM ){
145151
- rc = SQLITE_OK;
145152
- }
145153
-
145154
- if( rc==SQLITE_OK ){
145155
- if( nRow==0 ){
145156
- pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
145157
- }else{
145158
- pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
145159
- }
145704
+ zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
145705
+ if( zSql==0 ){
145706
+ rc = SQLITE_NOMEM;
145707
+ }else{
145708
+ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
145709
+ if( rc==SQLITE_OK ){
145710
+ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
145711
+ rc = sqlite3_finalize(p);
145712
+ }else if( rc!=SQLITE_NOMEM ){
145713
+ rc = SQLITE_OK;
145714
+ }
145715
+
145716
+ if( rc==SQLITE_OK ){
145717
+ if( nRow==0 ){
145718
+ pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
145719
+ }else{
145720
+ pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
145721
+ }
145722
+ }
145723
+ sqlite3_free(zSql);
145160145724
}
145161145725
145162145726
return rc;
145163145727
}
145164145728
@@ -145423,10 +145987,12 @@
145423145987
}
145424145988
145425145989
if( rc==SQLITE_OK ){
145426145990
*ppVtab = (sqlite3_vtab *)pRtree;
145427145991
}else{
145992
+ assert( *ppVtab==0 );
145993
+ assert( pRtree->nBusy==1 );
145428145994
rtreeRelease(pRtree);
145429145995
}
145430145996
return rc;
145431145997
}
145432145998
145433145999
--- 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.8.4.1. 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.
@@ -220,13 +220,13 @@
220 **
221 ** See also: [sqlite3_libversion()],
222 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
223 ** [sqlite_version()] and [sqlite_source_id()].
224 */
225 #define SQLITE_VERSION "3.8.4.1"
226 #define SQLITE_VERSION_NUMBER 3008004
227 #define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0"
228
229 /*
230 ** CAPI3REF: Run-Time Library Version Numbers
231 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
232 **
@@ -6236,11 +6236,12 @@
6236 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17
6237 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
6238 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19
6239 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20
6240 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21
6241 #define SQLITE_TESTCTRL_LAST 21
 
6242
6243 /*
6244 ** CAPI3REF: SQLite Runtime Status
6245 **
6246 ** ^This interface is used to retrieve runtime status information
@@ -8437,26 +8438,43 @@
8437 */
8438 typedef INT16_TYPE LogEst;
8439
8440 /*
8441 ** Macros to determine whether the machine is big or little endian,
8442 ** evaluated at runtime.
 
 
 
 
 
8443 */
8444 #ifdef SQLITE_AMALGAMATION
8445 SQLITE_PRIVATE const int sqlite3one = 1;
8446 #else
8447 SQLITE_PRIVATE const int sqlite3one;
8448 #endif
8449 #if defined(i386) || defined(__i386__) || defined(_M_IX86)\
8450 || defined(__x86_64) || defined(__x86_64__)
 
 
 
8451 # define SQLITE_BIGENDIAN 0
8452 # define SQLITE_LITTLEENDIAN 1
8453 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE
8454 #else
 
 
 
 
 
 
 
 
 
8455 # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
8456 # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
8457 # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
8458 #endif
8459
8460 /*
8461 ** Constants for the largest and smallest possible 64-bit signed integers.
8462 ** These macros are designed to work correctly on both 32-bit and 64-bit
@@ -8767,11 +8785,13 @@
8767 #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */
8768 #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */
8769
8770 SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
8771 SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
8772 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
 
 
8773 SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
8774 SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
8775 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
8776 SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
8777 SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
@@ -8817,10 +8837,11 @@
8817 #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
8818 #define BTREE_BLOBKEY 2 /* Table has keys only - no data */
8819
8820 SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
8821 SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
 
8822 SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
8823
8824 SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
8825 SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
8826
@@ -8891,11 +8912,11 @@
8891
8892 SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
8893 SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
8894
8895 SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
8896 SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *);
8897 SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
8898 SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
8899 SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
8900
8901 #ifndef NDEBUG
@@ -9134,11 +9155,11 @@
9134 #define OP_Next 9
9135 #define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */
9136 #define OP_Checkpoint 11
9137 #define OP_JournalMode 12
9138 #define OP_Vacuum 13
9139 #define OP_VFilter 14 /* synopsis: iPlan=r[P3] zPlan='P4' */
9140 #define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */
9141 #define OP_Goto 16
9142 #define OP_Gosub 17
9143 #define OP_Return 18
9144 #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
@@ -9161,11 +9182,11 @@
9161 #define OP_CollSeq 36
9162 #define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */
9163 #define OP_MustBeInt 38
9164 #define OP_RealAffinity 39
9165 #define OP_Permutation 40
9166 #define OP_Compare 41
9167 #define OP_Jump 42
9168 #define OP_Once 43
9169 #define OP_If 44
9170 #define OP_IfNot 45
9171 #define OP_Column 46 /* synopsis: r[P3]=PX */
@@ -9188,11 +9209,11 @@
9188 #define OP_Seek 63 /* synopsis: intkey=r[P2] */
9189 #define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */
9190 #define OP_NotFound 65 /* synopsis: key=r[P3@P4] */
9191 #define OP_Found 66 /* synopsis: key=r[P3@P4] */
9192 #define OP_NotExists 67 /* synopsis: intkey=r[P3] */
9193 #define OP_Sequence 68 /* synopsis: r[P2]=rowid */
9194 #define OP_NewRowid 69 /* synopsis: r[P2]=rowid */
9195 #define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */
9196 #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
9197 #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
9198 #define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */
@@ -9236,51 +9257,52 @@
9236 #define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */
9237 #define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */
9238 #define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */
9239 #define OP_Destroy 114
9240 #define OP_Clear 115
9241 #define OP_CreateIndex 116 /* synopsis: r[P2]=root iDb=P1 */
9242 #define OP_CreateTable 117 /* synopsis: r[P2]=root iDb=P1 */
9243 #define OP_ParseSchema 118
9244 #define OP_LoadAnalysis 119
9245 #define OP_DropTable 120
9246 #define OP_DropIndex 121
9247 #define OP_DropTrigger 122
9248 #define OP_IntegrityCk 123
9249 #define OP_RowSetAdd 124 /* synopsis: rowset(P1)=r[P2] */
9250 #define OP_RowSetRead 125 /* synopsis: r[P3]=rowset(P1) */
9251 #define OP_RowSetTest 126 /* synopsis: if r[P3] in rowset(P1) goto P2 */
9252 #define OP_Program 127
9253 #define OP_Param 128
9254 #define OP_FkCounter 129 /* synopsis: fkctr[P1]+=P2 */
9255 #define OP_FkIfZero 130 /* synopsis: if fkctr[P1]==0 goto P2 */
9256 #define OP_MemMax 131 /* synopsis: r[P1]=max(r[P1],r[P2]) */
9257 #define OP_IfPos 132 /* synopsis: if r[P1]>0 goto P2 */
9258 #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
9259 #define OP_IfNeg 134 /* synopsis: if r[P1]<0 goto P2 */
9260 #define OP_IfZero 135 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
9261 #define OP_AggFinal 136 /* synopsis: accum=r[P1] N=P2 */
9262 #define OP_IncrVacuum 137
9263 #define OP_Expire 138
9264 #define OP_TableLock 139 /* synopsis: iDb=P1 root=P2 write=P3 */
9265 #define OP_VBegin 140
9266 #define OP_VCreate 141
9267 #define OP_VDestroy 142
9268 #define OP_ToText 143 /* same as TK_TO_TEXT */
9269 #define OP_ToBlob 144 /* same as TK_TO_BLOB */
9270 #define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */
9271 #define OP_ToInt 146 /* same as TK_TO_INT */
9272 #define OP_ToReal 147 /* same as TK_TO_REAL */
9273 #define OP_VOpen 148
9274 #define OP_VColumn 149 /* synopsis: r[P3]=vcolumn(P2) */
9275 #define OP_VNext 150
9276 #define OP_VRename 151
9277 #define OP_Pagecount 152
9278 #define OP_MaxPgcnt 153
9279 #define OP_Init 154 /* synopsis: Start at P2 */
9280 #define OP_Noop 155
9281 #define OP_Explain 156
 
9282
9283
9284 /* Properties such as "out2" or "jump" that are specified in
9285 ** comments following the "case" for each opcode in the vdbe.c
9286 ** are encoded into bitvectors as follows:
@@ -9305,16 +9327,16 @@
9305 /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\
9306 /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\
9307 /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\
9308 /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
9309 /* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\
9310 /* 112 */ 0x01, 0x01, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00,\
9311 /* 120 */ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15, 0x01,\
9312 /* 128 */ 0x02, 0x00, 0x01, 0x08, 0x05, 0x02, 0x05, 0x05,\
9313 /* 136 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\
9314 /* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x01, 0x00,\
9315 /* 152 */ 0x02, 0x02, 0x01, 0x00, 0x00,}
9316
9317 /************** End of opcodes.h *********************************************/
9318 /************** Continuing where we left off in vdbe.h ***********************/
9319
9320 /*
@@ -9367,14 +9389,14 @@
9367 #ifndef SQLITE_OMIT_TRACE
9368 SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
9369 #endif
9370
9371 SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
9372 SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int);
9373 SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
9374
9375 typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int);
9376 SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
9377
9378 #ifndef SQLITE_OMIT_TRIGGER
9379 SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
9380 #endif
@@ -10996,10 +11018,11 @@
10996 */
10997 struct UnpackedRecord {
10998 KeyInfo *pKeyInfo; /* Collation and sort-order information */
10999 u16 nField; /* Number of entries in apMem[] */
11000 i8 default_rc; /* Comparison result if keys are equal */
 
11001 Mem *aMem; /* Values */
11002 int r1; /* Value to return if (lhs > rhs) */
11003 int r2; /* Value to return if (rhs < lhs) */
11004 };
11005
@@ -11262,12 +11285,12 @@
11262 #define EP_Error 0x000008 /* Expression contains one or more errors */
11263 #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
11264 #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
11265 #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
11266 #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
11267 #define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
11268 /* unused 0x000200 */
11269 #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
11270 #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
11271 #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
11272 #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
11273 #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
@@ -11327,11 +11350,10 @@
11327 ** of the result column in the form: DATABASE.TABLE.COLUMN. This later
11328 ** form is used for name resolution with nested FROM clauses.
11329 */
11330 struct ExprList {
11331 int nExpr; /* Number of expressions on the list */
11332 int iECursor; /* VDBE Cursor associated with this ExprList */
11333 struct ExprList_item { /* For each expression in the list */
11334 Expr *pExpr; /* The list of expressions */
11335 char *zName; /* Token associated with this expression */
11336 char *zSpan; /* Original text of the expression */
11337 u8 sortOrder; /* 1 for DESC or 0 for ASC */
@@ -11551,11 +11573,11 @@
11551 struct Select {
11552 ExprList *pEList; /* The fields of the result */
11553 u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
11554 u16 selFlags; /* Various SF_* values */
11555 int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
11556 int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
11557 u64 nSelectRow; /* Estimated number of result rows */
11558 SrcList *pSrc; /* The FROM clause */
11559 Expr *pWhere; /* The WHERE clause */
11560 ExprList *pGroupBy; /* The GROUP BY clause */
11561 Expr *pHaving; /* The HAVING clause */
@@ -11575,13 +11597,13 @@
11575 #define SF_Resolved 0x0002 /* Identifiers have been resolved */
11576 #define SF_Aggregate 0x0004 /* Contains aggregate functions */
11577 #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
11578 #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
11579 #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
11580 #define SF_UseSorter 0x0040 /* Sort using a sorter */
11581 #define SF_Values 0x0080 /* Synthesized from VALUES clause */
11582 #define SF_Materialize 0x0100 /* NOT USED */
11583 #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
11584 #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
11585 #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
11586 #define SF_Compound 0x1000 /* Part of a compound query */
11587
@@ -11630,17 +11652,19 @@
11630 ** of the co-routine is stored in register pDest->iSDParm
11631 ** and the result row is stored in pDest->nDest registers
11632 ** starting with pDest->iSdst.
11633 **
11634 ** SRT_Table Store results in temporary table pDest->iSDParm.
11635 ** This is like SRT_EphemTab except that the table
11636 ** is assumed to already be open.
 
 
11637 **
11638 ** SRT_DistTable Store results in a temporary table pDest->iSDParm.
11639 ** But also use temporary table pDest->iSDParm+1 as
11640 ** a record of all prior results and ignore any duplicate
11641 ** rows. Name means: "Distinct Table".
11642 **
11643 ** SRT_Queue Store results in priority queue pDest->iSDParm (really
11644 ** an index). Append a sequence number so that all entries
11645 ** are distinct.
11646 **
@@ -11650,23 +11674,24 @@
11650 */
11651 #define SRT_Union 1 /* Store result as keys in an index */
11652 #define SRT_Except 2 /* Remove result from a UNION index */
11653 #define SRT_Exists 3 /* Store 1 if the result is not empty */
11654 #define SRT_Discard 4 /* Do not save the results anywhere */
 
 
 
 
11655
11656 /* The ORDER BY clause is ignored for all of the above */
11657 #define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard)
11658
11659 #define SRT_Output 5 /* Output each row of result */
11660 #define SRT_Mem 6 /* Store result in a memory cell */
11661 #define SRT_Set 7 /* Store results as keys in an index */
11662 #define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
11663 #define SRT_Coroutine 9 /* Generate a single row of result */
11664 #define SRT_Table 10 /* Store result as data with an automatic rowid */
11665 #define SRT_DistTable 11 /* Like SRT_Table, but unique results only */
11666 #define SRT_Queue 12 /* Store result in an queue */
11667 #define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */
11668
11669 /*
11670 ** An instance of this object describes where to put of the results of
11671 ** a SELECT statement.
11672 */
@@ -11760,12 +11785,10 @@
11760 int rc; /* Return code from execution */
11761 u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
11762 u8 checkSchema; /* Causes schema cookie check after an error */
11763 u8 nested; /* Number of nested calls to the parser/code generator */
11764 u8 nTempReg; /* Number of temporary registers in aTempReg[] */
11765 u8 nColCache; /* Number of entries in aColCache[] */
11766 u8 iColCache; /* Next entry in aColCache[] to replace */
11767 u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
11768 u8 mayAbort; /* True if statement may throw an ABORT exception */
11769 u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
11770 u8 okConstFactor; /* OK to factor out constants */
11771 int aTempReg[8]; /* Holding area for temporary registers */
@@ -12387,11 +12410,11 @@
12387 SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
12388
12389 SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
12390 SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*);
12391 SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
12392 SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, u8 iBatch, i64);
12393 SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
12394
12395 SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
12396
12397 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -12451,11 +12474,11 @@
12451 SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
12452 SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
12453 SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
12454 SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
12455 SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*);
12456 SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int);
12457 SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
12458 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
12459 SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
12460 SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
12461 SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
@@ -12503,10 +12526,11 @@
12503 SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
12504 SQLITE_PRIVATE int sqlite3IsRowid(const char*);
12505 SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
12506 SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
12507 SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
 
12508 SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
12509 u8,u8,int,int*);
12510 SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
12511 SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
12512 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
@@ -12660,11 +12684,11 @@
12660 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
12661 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
12662 SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
12663 SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
12664 SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
12665 SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
12666 SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
12667 SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
12668 SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
12669 SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
12670 SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
@@ -13745,10 +13769,11 @@
13745 u16 nHdrParsed; /* Number of header fields parsed so far */
13746 i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
13747 u8 nullRow; /* True if pointing to a row with no data */
13748 u8 rowidIsValid; /* True if lastRowid is valid */
13749 u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
 
13750 Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
13751 Bool isTable:1; /* True if a table requiring integer keys */
13752 Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
13753 sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
13754 i64 seqCount; /* Sequence counter */
@@ -14064,11 +14089,11 @@
14064 SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
14065 SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
14066 SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
14067
14068 int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
14069 SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*);
14070 SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
14071 SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
14072 SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
14073 SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
14074 SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
@@ -14110,10 +14135,11 @@
14110 SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
14111 SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
14112 SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
14113
14114 SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
 
14115 SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
14116 SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
14117 SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
14118 SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
14119 SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
@@ -17849,11 +17875,11 @@
17849
17850 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
17851 ** block. If not, then split a block of the next larger power of
17852 ** two in order to create a new free block of size iLogsize.
17853 */
17854 for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
17855 if( iBin>LOGMAX ){
17856 testcase( sqlite3GlobalConfig.xLog!=0 );
17857 sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
17858 return 0;
17859 }
@@ -20159,24 +20185,10 @@
20159 *val = (*val - d)*10.0;
20160 return (char)digit;
20161 }
20162 #endif /* SQLITE_OMIT_FLOATING_POINT */
20163
20164 /*
20165 ** Append N space characters to the given string buffer.
20166 */
20167 SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){
20168 static const char zSpaces[] = " ";
20169 while( N>=(int)sizeof(zSpaces)-1 ){
20170 sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
20171 N -= sizeof(zSpaces)-1;
20172 }
20173 if( N>0 ){
20174 sqlite3StrAccumAppend(pAccum, zSpaces, N);
20175 }
20176 }
20177
20178 /*
20179 ** Set the StrAccum object to an error mode.
20180 */
20181 static void setStrAccumError(StrAccum *p, u8 eError){
20182 p->accError = eError;
@@ -20262,15 +20274,13 @@
20262 }else{
20263 bArgList = useIntern = 0;
20264 }
20265 for(; (c=(*fmt))!=0; ++fmt){
20266 if( c!='%' ){
20267 int amt;
20268 bufpt = (char *)fmt;
20269 amt = 1;
20270 while( (c=(*++fmt))!='%' && c!=0 ) amt++;
20271 sqlite3StrAccumAppend(pAccum, bufpt, amt);
20272 if( c==0 ) break;
20273 }
20274 if( (c=(*++fmt))==0 ){
20275 sqlite3StrAccumAppend(pAccum, "%", 1);
20276 break;
@@ -20447,14 +20457,12 @@
20447 }
20448 *(--bufpt) = zOrd[x*2+1];
20449 *(--bufpt) = zOrd[x*2];
20450 }
20451 {
20452 register const char *cset; /* Use registers for speed */
20453 register int base;
20454 cset = &aDigits[infop->charset];
20455 base = infop->base;
20456 do{ /* Convert to ascii */
20457 *(--bufpt) = cset[longvalue%base];
20458 longvalue = longvalue/base;
20459 }while( longvalue>0 );
20460 }
@@ -20754,77 +20762,102 @@
20754 /*
20755 ** The text of the conversion is pointed to by "bufpt" and is
20756 ** "length" characters long. The field width is "width". Do
20757 ** the output.
20758 */
20759 if( !flag_leftjustify ){
20760 register int nspace;
20761 nspace = width-length;
20762 if( nspace>0 ){
20763 sqlite3AppendSpace(pAccum, nspace);
20764 }
20765 }
20766 if( length>0 ){
20767 sqlite3StrAccumAppend(pAccum, bufpt, length);
20768 }
20769 if( flag_leftjustify ){
20770 register int nspace;
20771 nspace = width-length;
20772 if( nspace>0 ){
20773 sqlite3AppendSpace(pAccum, nspace);
20774 }
20775 }
20776 if( zExtra ) sqlite3_free(zExtra);
20777 }/* End for loop over the format string */
20778 } /* End of function */
20779
20780 /*
20781 ** Append N bytes of text from z to the StrAccum object.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20782 */
20783 SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
20784 assert( z!=0 );
20785 assert( p->zText!=0 || p->nChar==0 || p->accError );
20786 assert( N>=0 );
20787 assert( p->accError==0 || p->nAlloc==0 );
20788 if( p->nChar+N >= p->nAlloc ){
20789 char *zNew;
20790 if( p->accError ){
20791 testcase(p->accError==STRACCUM_TOOBIG);
20792 testcase(p->accError==STRACCUM_NOMEM);
20793 return;
20794 }
20795 if( !p->useMalloc ){
20796 N = p->nAlloc - p->nChar - 1;
20797 setStrAccumError(p, STRACCUM_TOOBIG);
20798 if( N<=0 ){
20799 return;
20800 }
20801 }else{
20802 char *zOld = (p->zText==p->zBase ? 0 : p->zText);
20803 i64 szNew = p->nChar;
20804 szNew += N + 1;
20805 if( szNew > p->mxAlloc ){
20806 sqlite3StrAccumReset(p);
20807 setStrAccumError(p, STRACCUM_TOOBIG);
20808 return;
20809 }else{
20810 p->nAlloc = (int)szNew;
20811 }
20812 if( p->useMalloc==1 ){
20813 zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
20814 }else{
20815 zNew = sqlite3_realloc(zOld, p->nAlloc);
20816 }
20817 if( zNew ){
20818 if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
20819 p->zText = zNew;
20820 }else{
20821 sqlite3StrAccumReset(p);
20822 setStrAccumError(p, STRACCUM_NOMEM);
20823 return;
20824 }
20825 }
20826 }
20827 assert( p->zText );
20828 memcpy(&p->zText[p->nChar], z, N);
20829 p->nChar += N;
20830 }
@@ -23328,11 +23361,11 @@
23328 /* 9 */ "Next" OpHelp(""),
23329 /* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
23330 /* 11 */ "Checkpoint" OpHelp(""),
23331 /* 12 */ "JournalMode" OpHelp(""),
23332 /* 13 */ "Vacuum" OpHelp(""),
23333 /* 14 */ "VFilter" OpHelp("iPlan=r[P3] zPlan='P4'"),
23334 /* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"),
23335 /* 16 */ "Goto" OpHelp(""),
23336 /* 17 */ "Gosub" OpHelp(""),
23337 /* 18 */ "Return" OpHelp(""),
23338 /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
@@ -23355,11 +23388,11 @@
23355 /* 36 */ "CollSeq" OpHelp(""),
23356 /* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
23357 /* 38 */ "MustBeInt" OpHelp(""),
23358 /* 39 */ "RealAffinity" OpHelp(""),
23359 /* 40 */ "Permutation" OpHelp(""),
23360 /* 41 */ "Compare" OpHelp(""),
23361 /* 42 */ "Jump" OpHelp(""),
23362 /* 43 */ "Once" OpHelp(""),
23363 /* 44 */ "If" OpHelp(""),
23364 /* 45 */ "IfNot" OpHelp(""),
23365 /* 46 */ "Column" OpHelp("r[P3]=PX"),
@@ -23382,11 +23415,11 @@
23382 /* 63 */ "Seek" OpHelp("intkey=r[P2]"),
23383 /* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"),
23384 /* 65 */ "NotFound" OpHelp("key=r[P3@P4]"),
23385 /* 66 */ "Found" OpHelp("key=r[P3@P4]"),
23386 /* 67 */ "NotExists" OpHelp("intkey=r[P3]"),
23387 /* 68 */ "Sequence" OpHelp("r[P2]=rowid"),
23388 /* 69 */ "NewRowid" OpHelp("r[P2]=rowid"),
23389 /* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
23390 /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
23391 /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
23392 /* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
@@ -23430,51 +23463,52 @@
23430 /* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"),
23431 /* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"),
23432 /* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"),
23433 /* 114 */ "Destroy" OpHelp(""),
23434 /* 115 */ "Clear" OpHelp(""),
23435 /* 116 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
23436 /* 117 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
23437 /* 118 */ "ParseSchema" OpHelp(""),
23438 /* 119 */ "LoadAnalysis" OpHelp(""),
23439 /* 120 */ "DropTable" OpHelp(""),
23440 /* 121 */ "DropIndex" OpHelp(""),
23441 /* 122 */ "DropTrigger" OpHelp(""),
23442 /* 123 */ "IntegrityCk" OpHelp(""),
23443 /* 124 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
23444 /* 125 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
23445 /* 126 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
23446 /* 127 */ "Program" OpHelp(""),
23447 /* 128 */ "Param" OpHelp(""),
23448 /* 129 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
23449 /* 130 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
23450 /* 131 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
23451 /* 132 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
23452 /* 133 */ "Real" OpHelp("r[P2]=P4"),
23453 /* 134 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"),
23454 /* 135 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
23455 /* 136 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
23456 /* 137 */ "IncrVacuum" OpHelp(""),
23457 /* 138 */ "Expire" OpHelp(""),
23458 /* 139 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
23459 /* 140 */ "VBegin" OpHelp(""),
23460 /* 141 */ "VCreate" OpHelp(""),
23461 /* 142 */ "VDestroy" OpHelp(""),
23462 /* 143 */ "ToText" OpHelp(""),
23463 /* 144 */ "ToBlob" OpHelp(""),
23464 /* 145 */ "ToNumeric" OpHelp(""),
23465 /* 146 */ "ToInt" OpHelp(""),
23466 /* 147 */ "ToReal" OpHelp(""),
23467 /* 148 */ "VOpen" OpHelp(""),
23468 /* 149 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
23469 /* 150 */ "VNext" OpHelp(""),
23470 /* 151 */ "VRename" OpHelp(""),
23471 /* 152 */ "Pagecount" OpHelp(""),
23472 /* 153 */ "MaxPgcnt" OpHelp(""),
23473 /* 154 */ "Init" OpHelp("Start at P2"),
23474 /* 155 */ "Noop" OpHelp(""),
23475 /* 156 */ "Explain" OpHelp(""),
 
23476 };
23477 return azName[i];
23478 }
23479 #endif
23480
@@ -24010,10 +24044,11 @@
24010 return geteuid() ? 0 : fchown(fd,uid,gid);
24011 }
24012
24013 /* Forward reference */
24014 static int openDirectory(const char*, int*);
 
24015
24016 /*
24017 ** Many system calls are accessed through pointer-to-functions so that
24018 ** they may be overridden at runtime to facilitate fault injection during
24019 ** testing and sandboxing. The following array holds the names and pointers
@@ -24132,10 +24167,13 @@
24132 #else
24133 { "mremap", (sqlite3_syscall_ptr)0, 0 },
24134 #endif
24135 #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
24136 #endif
 
 
 
24137
24138 }; /* End of the overrideable system calls */
24139
24140 /*
24141 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -27792,10 +27830,40 @@
27792 #endif
27793
27794 return rc;
27795 }
27796
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27797
27798 /*
27799 ** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
27800 **
27801 ** This is not a VFS shared-memory method; it is a utility function called
@@ -27803,14 +27871,15 @@
27803 */
27804 static void unixShmPurge(unixFile *pFd){
27805 unixShmNode *p = pFd->pInode->pShmNode;
27806 assert( unixMutexHeld() );
27807 if( p && p->nRef==0 ){
 
27808 int i;
27809 assert( p->pInode==pFd->pInode );
27810 sqlite3_mutex_free(p->mutex);
27811 for(i=0; i<p->nRegion; i++){
27812 if( p->h>=0 ){
27813 osMunmap(p->apRegion[i], p->szRegion);
27814 }else{
27815 sqlite3_free(p->apRegion[i]);
27816 }
@@ -28013,10 +28082,12 @@
28013 ){
28014 unixFile *pDbFd = (unixFile*)fd;
28015 unixShm *p;
28016 unixShmNode *pShmNode;
28017 int rc = SQLITE_OK;
 
 
28018
28019 /* If the shared-memory file has not yet been opened, open it now. */
28020 if( pDbFd->pShm==0 ){
28021 rc = unixOpenSharedMemory(pDbFd);
28022 if( rc!=SQLITE_OK ) return rc;
@@ -28028,13 +28099,16 @@
28028 assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
28029 assert( pShmNode->pInode==pDbFd->pInode );
28030 assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
28031 assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
28032
28033 if( pShmNode->nRegion<=iRegion ){
 
 
 
28034 char **apNew; /* New apRegion[] array */
28035 int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
28036 struct stat sStat; /* Used by fstat() */
28037
28038 pShmNode->szRegion = szRegion;
28039
28040 if( pShmNode->h>=0 ){
@@ -28079,21 +28153,23 @@
28079 }
28080 }
28081
28082 /* Map the requested memory region into this processes address space. */
28083 apNew = (char **)sqlite3_realloc(
28084 pShmNode->apRegion, (iRegion+1)*sizeof(char *)
28085 );
28086 if( !apNew ){
28087 rc = SQLITE_IOERR_NOMEM;
28088 goto shmpage_out;
28089 }
28090 pShmNode->apRegion = apNew;
28091 while(pShmNode->nRegion<=iRegion){
 
 
28092 void *pMem;
28093 if( pShmNode->h>=0 ){
28094 pMem = osMmap(0, szRegion,
28095 pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
28096 MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
28097 );
28098 if( pMem==MAP_FAILED ){
28099 rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
@@ -28105,12 +28181,15 @@
28105 rc = SQLITE_NOMEM;
28106 goto shmpage_out;
28107 }
28108 memset(pMem, 0, szRegion);
28109 }
28110 pShmNode->apRegion[pShmNode->nRegion] = pMem;
28111 pShmNode->nRegion++;
 
 
 
28112 }
28113 }
28114
28115 shmpage_out:
28116 if( pShmNode->nRegion>iRegion ){
@@ -28320,23 +28399,10 @@
28320 pFd->mmapSize = 0;
28321 pFd->mmapSizeActual = 0;
28322 }
28323 }
28324
28325 /*
28326 ** Return the system page size.
28327 */
28328 static int unixGetPagesize(void){
28329 #if HAVE_MREMAP
28330 return 512;
28331 #elif defined(_BSD_SOURCE)
28332 return getpagesize();
28333 #else
28334 return (int)sysconf(_SC_PAGESIZE);
28335 #endif
28336 }
28337
28338 /*
28339 ** Attempt to set the size of the memory mapping maintained by file
28340 ** descriptor pFd to nNew bytes. Any existing mapping is discarded.
28341 **
28342 ** If successful, this function sets the following variables:
@@ -28369,12 +28435,16 @@
28369 assert( MAP_FAILED!=0 );
28370
28371 if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
28372
28373 if( pOrig ){
28374 const int szSyspage = unixGetPagesize();
 
 
 
28375 i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
 
28376 u8 *pReq = &pOrig[nReuse];
28377
28378 /* Unmap any pages of the existing mapping that cannot be reused. */
28379 if( nReuse!=nOrig ){
28380 osMunmap(pReq, nOrig-nReuse);
@@ -31116,11 +31186,11 @@
31116 };
31117 unsigned int i; /* Loop counter */
31118
31119 /* Double-check that the aSyscall[] array has been constructed
31120 ** correctly. See ticket [bb3a86e890c8e96ab] */
31121 assert( ArraySize(aSyscall)==24 );
31122
31123 /* Register all VFSes defined in the aVfs[] array */
31124 for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
31125 sqlite3_vfs_register(&aVfs[i], i==0);
31126 }
@@ -38997,12 +39067,12 @@
38997 struct RowSetEntry *pEntry; /* List of entries using pRight */
38998 struct RowSetEntry *pLast; /* Last entry on the pEntry list */
38999 struct RowSetEntry *pFresh; /* Source of new entry objects */
39000 struct RowSetEntry *pForest; /* List of binary trees of entries */
39001 u16 nFresh; /* Number of objects on pFresh */
39002 u8 rsFlags; /* Various flags */
39003 u8 iBatch; /* Current insert batch */
39004 };
39005
39006 /*
39007 ** Allowed values for RowSet.rsFlags
39008 */
@@ -39332,11 +39402,11 @@
39332 **
39333 ** If this is the first test of a new batch and if there exist entires
39334 ** on pRowSet->pEntry, then sort those entires into the forest at
39335 ** pRowSet->pForest so that they can be tested.
39336 */
39337 SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
39338 struct RowSetEntry *p, *pTree;
39339
39340 /* This routine is never called after sqlite3RowSetNext() */
39341 assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
39342
@@ -41159,16 +41229,15 @@
41159 assert( pPager->setMaster==0 );
41160 assert( !pagerUseWal(pPager) );
41161
41162 if( !zMaster
41163 || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
41164 || pPager->journalMode==PAGER_JOURNALMODE_OFF
41165 ){
41166 return SQLITE_OK;
41167 }
41168 pPager->setMaster = 1;
41169 assert( isOpen(pPager->jfd) );
41170 assert( pPager->journalHdr <= pPager->journalOff );
41171
41172 /* Calculate the length in bytes and the checksum of zMaster */
41173 for(nMaster=0; zMaster[nMaster]; nMaster++){
41174 cksum += zMaster[nMaster];
@@ -50371,31 +50440,34 @@
50371 struct BtCursor {
50372 Btree *pBtree; /* The Btree to which this cursor belongs */
50373 BtShared *pBt; /* The BtShared this cursor points to */
50374 BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
50375 struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
50376 #ifndef SQLITE_OMIT_INCRBLOB
50377 Pgno *aOverflow; /* Cache of overflow page locations */
50378 #endif
 
 
50379 Pgno pgnoRoot; /* The root page of this tree */
50380 CellInfo info; /* A parse of the cell we are pointing at */
50381 i64 nKey; /* Size of pKey, or last integer key */
50382 void *pKey; /* Saved key that was cursor's last known position */
50383 int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
50384 u8 wrFlag; /* True if writable */
50385 u8 atLast; /* Cursor pointing to the last entry */
50386 u8 validNKey; /* True if info.nKey is valid */
50387 u8 eState; /* One of the CURSOR_XXX constants (see below) */
50388 #ifndef SQLITE_OMIT_INCRBLOB
50389 u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
50390 #endif
50391 u8 hints; /* As configured by CursorSetHints() */
50392 i16 iPage; /* Index of current page in apPage */
50393 u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
50394 MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
50395 };
50396
 
 
 
 
 
 
 
 
 
50397 /*
50398 ** Potential values for BtCursor.eState.
50399 **
50400 ** CURSOR_INVALID:
50401 ** Cursor does not point to a valid entry. This can happen (for example)
@@ -51262,20 +51334,15 @@
51262 static int cursorHoldsMutex(BtCursor *p){
51263 return sqlite3_mutex_held(p->pBt->mutex);
51264 }
51265 #endif
51266
51267
51268 #ifndef SQLITE_OMIT_INCRBLOB
51269 /*
51270 ** Invalidate the overflow page-list cache for cursor pCur, if any.
 
51271 */
51272 static void invalidateOverflowCache(BtCursor *pCur){
51273 assert( cursorHoldsMutex(pCur) );
51274 sqlite3_free(pCur->aOverflow);
51275 pCur->aOverflow = 0;
51276 }
51277
51278 /*
51279 ** Invalidate the overflow page-list cache for all cursors opened
51280 ** on the shared btree structure pBt.
51281 */
@@ -51285,10 +51352,11 @@
51285 for(p=pBt->pCursor; p; p=p->pNext){
51286 invalidateOverflowCache(p);
51287 }
51288 }
51289
 
51290 /*
51291 ** This function is called before modifying the contents of a table
51292 ** to invalidate any incrblob cursors that are open on the
51293 ** row or one of the rows being modified.
51294 **
@@ -51307,20 +51375,18 @@
51307 ){
51308 BtCursor *p;
51309 BtShared *pBt = pBtree->pBt;
51310 assert( sqlite3BtreeHoldsMutex(pBtree) );
51311 for(p=pBt->pCursor; p; p=p->pNext){
51312 if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){
51313 p->eState = CURSOR_INVALID;
51314 }
51315 }
51316 }
51317
51318 #else
51319 /* Stub functions when INCRBLOB is omitted */
51320 #define invalidateOverflowCache(x)
51321 #define invalidateAllOverflowCache(x)
51322 #define invalidateIncrblobCursors(x,y,z)
51323 #endif /* SQLITE_OMIT_INCRBLOB */
51324
51325 /*
51326 ** Set bit pgno of the BtShared.pHasContent bitvec. This is called
@@ -51562,24 +51628,36 @@
51562 ** Determine whether or not a cursor has moved from the position it
51563 ** was last placed at. Cursors can move when the row they are pointing
51564 ** at is deleted out from under them.
51565 **
51566 ** This routine returns an error code if something goes wrong. The
51567 ** integer *pHasMoved is set to one if the cursor has moved and 0 if not.
 
 
 
 
 
 
 
 
51568 */
51569 SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
51570 int rc;
51571
 
 
 
 
51572 rc = restoreCursorPosition(pCur);
51573 if( rc ){
51574 *pHasMoved = 1;
51575 return rc;
51576 }
51577 if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
 
 
51578 *pHasMoved = 1;
51579 }else{
51580 *pHasMoved = 0;
51581 }
51582 return SQLITE_OK;
51583 }
51584
51585 #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -52977,10 +53055,11 @@
52977 sqlite3PagerSetCachesize(pBt->pPager, mxPage);
52978 sqlite3BtreeLeave(p);
52979 return SQLITE_OK;
52980 }
52981
 
52982 /*
52983 ** Change the limit on the amount of the database file that may be
52984 ** memory mapped.
52985 */
52986 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
@@ -52989,10 +53068,11 @@
52989 sqlite3BtreeEnter(p);
52990 sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
52991 sqlite3BtreeLeave(p);
52992 return SQLITE_OK;
52993 }
 
52994
52995 /*
52996 ** Change the way data is synced to disk in order to increase or decrease
52997 ** how well the database resists damage due to OS crashes and power
52998 ** failures. Level 1 is the same as asynchronous (no syncs() occur and
@@ -53365,11 +53445,12 @@
53365 */
53366 static int countValidCursors(BtShared *pBt, int wrOnly){
53367 BtCursor *pCur;
53368 int r = 0;
53369 for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
53370 if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
 
53371 }
53372 return r;
53373 }
53374 #endif
53375
@@ -54440,11 +54521,12 @@
54440 pCur->pgnoRoot = (Pgno)iTable;
54441 pCur->iPage = -1;
54442 pCur->pKeyInfo = pKeyInfo;
54443 pCur->pBtree = p;
54444 pCur->pBt = pBt;
54445 pCur->wrFlag = (u8)wrFlag;
 
54446 pCur->pNext = pBt->pCursor;
54447 if( pCur->pNext ){
54448 pCur->pNext->pPrev = pCur;
54449 }
54450 pBt->pCursor = pCur;
@@ -54510,11 +54592,11 @@
54510 }
54511 for(i=0; i<=pCur->iPage; i++){
54512 releasePage(pCur->apPage[i]);
54513 }
54514 unlockBtreeIfUnused(pBt);
54515 invalidateOverflowCache(pCur);
54516 /* sqlite3_free(pCur); */
54517 sqlite3BtreeLeave(pBtree);
54518 }
54519 return SQLITE_OK;
54520 }
@@ -54549,22 +54631,22 @@
54549 /* Use a real function in MSVC to work around bugs in that compiler. */
54550 static void getCellInfo(BtCursor *pCur){
54551 if( pCur->info.nSize==0 ){
54552 int iPage = pCur->iPage;
54553 btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
54554 pCur->validNKey = 1;
54555 }else{
54556 assertCellInfo(pCur);
54557 }
54558 }
54559 #else /* if not _MSC_VER */
54560 /* Use a macro in all other compilers so that the function is inlined */
54561 #define getCellInfo(pCur) \
54562 if( pCur->info.nSize==0 ){ \
54563 int iPage = pCur->iPage; \
54564 btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
54565 pCur->validNKey = 1; \
54566 }else{ \
54567 assertCellInfo(pCur); \
54568 }
54569 #endif /* _MSC_VER */
54570
@@ -54731,26 +54813,28 @@
54731 return SQLITE_OK;
54732 }
54733
54734 /*
54735 ** This function is used to read or overwrite payload information
54736 ** for the entry that the pCur cursor is pointing to. If the eOp
54737 ** parameter is 0, this is a read operation (data copied into
54738 ** buffer pBuf). If it is non-zero, a write (data copied from
54739 ** buffer pBuf).
 
 
54740 **
54741 ** A total of "amt" bytes are read or written beginning at "offset".
54742 ** Data is read to or from the buffer pBuf.
54743 **
54744 ** The content being read or written might appear on the main page
54745 ** or be scattered out on multiple overflow pages.
54746 **
54747 ** If the BtCursor.isIncrblobHandle flag is set, and the current
54748 ** cursor entry uses one or more overflow pages, this function
54749 ** allocates space for and lazily popluates the overflow page-list
54750 ** cache array (BtCursor.aOverflow). Subsequent calls use this
54751 ** cache to make seeking to the supplied offset more efficient.
54752 **
54753 ** Once an overflow page-list cache has been allocated, it may be
54754 ** invalidated if some other cursor writes to the same table, or if
54755 ** the cursor is moved to a different row. Additionally, in auto-vacuum
54756 ** mode, the following events may invalidate an overflow page-list cache.
@@ -54770,19 +54854,26 @@
54770 int rc = SQLITE_OK;
54771 u32 nKey;
54772 int iIdx = 0;
54773 MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
54774 BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
 
 
 
54775
54776 assert( pPage );
54777 assert( pCur->eState==CURSOR_VALID );
54778 assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
54779 assert( cursorHoldsMutex(pCur) );
 
54780
54781 getCellInfo(pCur);
54782 aPayload = pCur->info.pCell + pCur->info.nHeader;
54783 nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
 
 
 
54784
54785 if( NEVER(offset+amt > nKey+pCur->info.nData)
54786 || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
54787 ){
54788 /* Trying to read or write past the end of the data is an error */
@@ -54793,11 +54884,11 @@
54793 if( offset<pCur->info.nLocal ){
54794 int a = amt;
54795 if( a+offset>pCur->info.nLocal ){
54796 a = pCur->info.nLocal - offset;
54797 }
54798 rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
54799 offset = 0;
54800 pBuf += a;
54801 amt -= a;
54802 }else{
54803 offset -= pCur->info.nLocal;
@@ -54807,62 +54898,72 @@
54807 const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
54808 Pgno nextPage;
54809
54810 nextPage = get4byte(&aPayload[pCur->info.nLocal]);
54811
54812 #ifndef SQLITE_OMIT_INCRBLOB
54813 /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
54814 ** has not been allocated, allocate it now. The array is sized at
54815 ** one entry for each overflow page in the overflow chain. The
54816 ** page number of the first overflow page is stored in aOverflow[0],
54817 ** etc. A value of 0 in the aOverflow[] array means "not yet known"
54818 ** (the cache is lazily populated).
54819 */
54820 if( pCur->isIncrblobHandle && !pCur->aOverflow ){
54821 int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
54822 pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl);
54823 /* nOvfl is always positive. If it were zero, fetchPayload would have
54824 ** been used instead of this routine. */
54825 if( ALWAYS(nOvfl) && !pCur->aOverflow ){
54826 rc = SQLITE_NOMEM;
 
 
 
 
 
 
 
 
 
54827 }
54828 }
54829
54830 /* If the overflow page-list cache has been allocated and the
54831 ** entry for the first required overflow page is valid, skip
54832 ** directly to it.
54833 */
54834 if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
54835 iIdx = (offset/ovflSize);
54836 nextPage = pCur->aOverflow[iIdx];
54837 offset = (offset%ovflSize);
54838 }
54839 #endif
54840
54841 for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
54842
54843 #ifndef SQLITE_OMIT_INCRBLOB
54844 /* If required, populate the overflow page-list cache. */
54845 if( pCur->aOverflow ){
54846 assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
54847 pCur->aOverflow[iIdx] = nextPage;
54848 }
54849 #endif
54850
54851 if( offset>=ovflSize ){
54852 /* The only reason to read this page is to obtain the page
54853 ** number for the next page in the overflow chain. The page
54854 ** data is not required. So first try to lookup the overflow
54855 ** page-list cache, if any, then fall back to the getOverflowPage()
54856 ** function.
 
 
 
54857 */
54858 #ifndef SQLITE_OMIT_INCRBLOB
54859 if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
 
54860 nextPage = pCur->aOverflow[iIdx+1];
54861 } else
54862 #endif
54863 rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
 
54864 offset -= ovflSize;
54865 }else{
54866 /* Need to read this page properly. It contains some of the
54867 ** range of data that is being read (eOp==0) or written (eOp!=0).
54868 */
@@ -54880,17 +54981,19 @@
54880 ** 1) this is a read operation, and
54881 ** 2) data is required from the start of this overflow page, and
54882 ** 3) the database is file-backed, and
54883 ** 4) there is no open write-transaction, and
54884 ** 5) the database is not a WAL database,
 
54885 **
54886 ** then data can be read directly from the database file into the
54887 ** output buffer, bypassing the page-cache altogether. This speeds
54888 ** up loading large records that span many overflow pages.
54889 */
54890 if( eOp==0 /* (1) */
54891 && offset==0 /* (2) */
 
54892 && pBt->inTransaction==TRANS_READ /* (4) */
54893 && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
54894 && pBt->pPage1->aData[19]==0x01 /* (5) */
54895 ){
54896 u8 aSave[4];
@@ -54903,16 +55006,16 @@
54903 #endif
54904
54905 {
54906 DbPage *pDbPage;
54907 rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
54908 (eOp==0 ? PAGER_GET_READONLY : 0)
54909 );
54910 if( rc==SQLITE_OK ){
54911 aPayload = sqlite3PagerGetData(pDbPage);
54912 nextPage = get4byte(aPayload);
54913 rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
54914 sqlite3PagerUnref(pDbPage);
54915 offset = 0;
54916 }
54917 }
54918 amt -= a;
@@ -55002,14 +55105,17 @@
55002 assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
55003 assert( pCur->eState==CURSOR_VALID );
55004 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
55005 assert( cursorHoldsMutex(pCur) );
55006 assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
 
 
55007 if( pCur->info.nSize==0 ){
55008 btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
55009 &pCur->info);
55010 }
 
55011 *pAmt = pCur->info.nLocal;
55012 return (void*)(pCur->info.pCell + pCur->info.nHeader);
55013 }
55014
55015
@@ -55056,18 +55162,18 @@
55056 assert( pCur->iPage>=0 );
55057 if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
55058 return SQLITE_CORRUPT_BKPT;
55059 }
55060 rc = getAndInitPage(pBt, newPgno, &pNewPage,
55061 pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
55062 if( rc ) return rc;
55063 pCur->apPage[i+1] = pNewPage;
55064 pCur->aiIdx[i+1] = 0;
55065 pCur->iPage++;
55066
55067 pCur->info.nSize = 0;
55068 pCur->validNKey = 0;
55069 if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
55070 return SQLITE_CORRUPT_BKPT;
55071 }
55072 return SQLITE_OK;
55073 }
@@ -55121,11 +55227,11 @@
55121 testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
55122
55123 releasePage(pCur->apPage[pCur->iPage]);
55124 pCur->iPage--;
55125 pCur->info.nSize = 0;
55126 pCur->validNKey = 0;
55127 }
55128
55129 /*
55130 ** Move the cursor to point to the root page of its b-tree structure.
55131 **
@@ -55168,11 +55274,11 @@
55168 }else if( pCur->pgnoRoot==0 ){
55169 pCur->eState = CURSOR_INVALID;
55170 return SQLITE_OK;
55171 }else{
55172 rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
55173 pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
55174 if( rc!=SQLITE_OK ){
55175 pCur->eState = CURSOR_INVALID;
55176 return rc;
55177 }
55178 pCur->iPage = 0;
@@ -55195,12 +55301,11 @@
55195 return SQLITE_CORRUPT_BKPT;
55196 }
55197
55198 pCur->aiIdx[0] = 0;
55199 pCur->info.nSize = 0;
55200 pCur->atLast = 0;
55201 pCur->validNKey = 0;
55202
55203 if( pRoot->nCell>0 ){
55204 pCur->eState = CURSOR_VALID;
55205 }else if( !pRoot->leaf ){
55206 Pgno subpage;
@@ -55259,11 +55364,11 @@
55259 rc = moveToChild(pCur, pgno);
55260 }
55261 if( rc==SQLITE_OK ){
55262 pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
55263 pCur->info.nSize = 0;
55264 pCur->validNKey = 0;
55265 }
55266 return rc;
55267 }
55268
55269 /* Move the cursor to the first entry in the table. Return SQLITE_OK
@@ -55298,11 +55403,11 @@
55298
55299 assert( cursorHoldsMutex(pCur) );
55300 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
55301
55302 /* If the cursor already points to the last entry, this is a no-op. */
55303 if( CURSOR_VALID==pCur->eState && pCur->atLast ){
55304 #ifdef SQLITE_DEBUG
55305 /* This block serves to assert() that the cursor really does point
55306 ** to the last entry in the b-tree. */
55307 int ii;
55308 for(ii=0; ii<pCur->iPage; ii++){
@@ -55321,11 +55426,16 @@
55321 *pRes = 1;
55322 }else{
55323 assert( pCur->eState==CURSOR_VALID );
55324 *pRes = 0;
55325 rc = moveToRightmost(pCur);
55326 pCur->atLast = rc==SQLITE_OK ?1:0;
 
 
 
 
 
55327 }
55328 }
55329 return rc;
55330 }
55331
@@ -55372,25 +55482,26 @@
55372 assert( pRes );
55373 assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
55374
55375 /* If the cursor is already positioned at the point we are trying
55376 ** to move to, then just return without doing any work */
55377 if( pCur->eState==CURSOR_VALID && pCur->validNKey
55378 && pCur->apPage[0]->intKey
55379 ){
55380 if( pCur->info.nKey==intKey ){
55381 *pRes = 0;
55382 return SQLITE_OK;
55383 }
55384 if( pCur->atLast && pCur->info.nKey<intKey ){
55385 *pRes = -1;
55386 return SQLITE_OK;
55387 }
55388 }
55389
55390 if( pIdxKey ){
55391 xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
 
55392 assert( pIdxKey->default_rc==1
55393 || pIdxKey->default_rc==0
55394 || pIdxKey->default_rc==-1
55395 );
55396 }else{
@@ -55445,11 +55556,11 @@
55445 }else if( nCellKey>intKey ){
55446 upr = idx-1;
55447 if( lwr>upr ){ c = +1; break; }
55448 }else{
55449 assert( nCellKey==intKey );
55450 pCur->validNKey = 1;
55451 pCur->info.nKey = nCellKey;
55452 pCur->aiIdx[pCur->iPage] = (u16)idx;
55453 if( !pPage->leaf ){
55454 lwr = idx;
55455 goto moveto_next_layer;
@@ -55502,27 +55613,29 @@
55502 if( pCellKey==0 ){
55503 rc = SQLITE_NOMEM;
55504 goto moveto_finish;
55505 }
55506 pCur->aiIdx[pCur->iPage] = (u16)idx;
55507 rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
55508 if( rc ){
55509 sqlite3_free(pCellKey);
55510 goto moveto_finish;
55511 }
55512 c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
55513 sqlite3_free(pCellKey);
55514 }
 
55515 if( c<0 ){
55516 lwr = idx+1;
55517 }else if( c>0 ){
55518 upr = idx-1;
55519 }else{
55520 assert( c==0 );
55521 *pRes = 0;
55522 rc = SQLITE_OK;
55523 pCur->aiIdx[pCur->iPage] = (u16)idx;
 
55524 goto moveto_finish;
55525 }
55526 if( lwr>upr ) break;
55527 assert( lwr+upr>=0 );
55528 idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
@@ -55547,11 +55660,11 @@
55547 rc = moveToChild(pCur, chldPg);
55548 if( rc ) break;
55549 }
55550 moveto_finish:
55551 pCur->info.nSize = 0;
55552 pCur->validNKey = 0;
55553 return rc;
55554 }
55555
55556
55557 /*
@@ -55592,10 +55705,11 @@
55592 assert( cursorHoldsMutex(pCur) );
55593 assert( pRes!=0 );
55594 assert( *pRes==0 || *pRes==1 );
55595 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
55596 if( pCur->eState!=CURSOR_VALID ){
 
55597 rc = restoreCursorPosition(pCur);
55598 if( rc!=SQLITE_OK ){
55599 *pRes = 0;
55600 return rc;
55601 }
@@ -55625,11 +55739,11 @@
55625 ** only happen if the database is corrupt in such a way as to link the
55626 ** page into more than one b-tree structure. */
55627 testcase( idx>pPage->nCell );
55628
55629 pCur->info.nSize = 0;
55630 pCur->validNKey = 0;
55631 if( idx>=pPage->nCell ){
55632 if( !pPage->leaf ){
55633 rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
55634 if( rc ){
55635 *pRes = 0;
@@ -55686,11 +55800,11 @@
55686
55687 assert( cursorHoldsMutex(pCur) );
55688 assert( pRes!=0 );
55689 assert( *pRes==0 || *pRes==1 );
55690 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
55691 pCur->atLast = 0;
55692 if( pCur->eState!=CURSOR_VALID ){
55693 if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
55694 rc = btreeRestoreCursorPosition(pCur);
55695 if( rc!=SQLITE_OK ){
55696 *pRes = 0;
@@ -55731,11 +55845,11 @@
55731 return SQLITE_OK;
55732 }
55733 moveToParent(pCur);
55734 }
55735 pCur->info.nSize = 0;
55736 pCur->validNKey = 0;
55737
55738 pCur->aiIdx[pCur->iPage]--;
55739 pPage = pCur->apPage[pCur->iPage];
55740 if( pPage->intKey && !pPage->leaf ){
55741 rc = sqlite3BtreePrevious(pCur, pRes);
@@ -57756,11 +57870,11 @@
57756 assert( pCur->skipNext!=SQLITE_OK );
57757 return pCur->skipNext;
57758 }
57759
57760 assert( cursorHoldsMutex(pCur) );
57761 assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
57762 && (pBt->btsFlags & BTS_READ_ONLY)==0 );
57763 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
57764
57765 /* Assert that the caller has been consistent. If this cursor was opened
57766 ** expecting an index b-tree, then the caller should be inserting blob
@@ -57789,11 +57903,11 @@
57789 invalidateIncrblobCursors(p, nKey, 0);
57790
57791 /* If the cursor is currently on the last row and we are appending a
57792 ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
57793 ** call */
57794 if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
57795 loc = -1;
57796 }
57797 }
57798
57799 if( !loc ){
@@ -57842,11 +57956,11 @@
57842 insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
57843 assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
57844
57845 /* If no error has occurred and pPage has an overflow cell, call balance()
57846 ** to redistribute the cells within the tree. Since balance() may move
57847 ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
57848 ** variables.
57849 **
57850 ** Previous versions of SQLite called moveToRoot() to move the cursor
57851 ** back to the root page as balance() used to invalidate the contents
57852 ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that,
@@ -57862,11 +57976,11 @@
57862 ** larger than the largest existing key, it is possible to insert the
57863 ** row without seeking the cursor. This can be a big performance boost.
57864 */
57865 pCur->info.nSize = 0;
57866 if( rc==SQLITE_OK && pPage->nOverflow ){
57867 pCur->validNKey = 0;
57868 rc = balance(pCur);
57869
57870 /* Must make sure nOverflow is reset to zero even if the balance()
57871 ** fails. Internal data structure corruption will result otherwise.
57872 ** Also, set the cursor state to invalid. This stops saveCursorPosition()
@@ -57894,11 +58008,11 @@
57894 int iCellDepth; /* Depth of node containing pCell */
57895
57896 assert( cursorHoldsMutex(pCur) );
57897 assert( pBt->inTransaction==TRANS_WRITE );
57898 assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
57899 assert( pCur->wrFlag );
57900 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
57901 assert( !hasReadConflicts(p, pCur->pgnoRoot) );
57902
57903 if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
57904 || NEVER(pCur->eState!=CURSOR_VALID)
@@ -58238,10 +58352,19 @@
58238 rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
58239 }
58240 sqlite3BtreeLeave(p);
58241 return rc;
58242 }
 
 
 
 
 
 
 
 
 
58243
58244 /*
58245 ** Erase all information in a table and add the root of the table to
58246 ** the freelist. Except, the root of the principle table (the one on
58247 ** page 1) is never added to the freelist.
@@ -59198,11 +59321,11 @@
59198 */
59199 SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
59200 int rc;
59201 assert( cursorHoldsMutex(pCsr) );
59202 assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
59203 assert( pCsr->isIncrblobHandle );
59204
59205 rc = restoreCursorPosition(pCsr);
59206 if( rc!=SQLITE_OK ){
59207 return rc;
59208 }
@@ -59227,11 +59350,11 @@
59227 ** (b) there is a read/write transaction open,
59228 ** (c) the connection holds a write-lock on the table (if required),
59229 ** (d) there are no conflicting read-locks, and
59230 ** (e) the cursor points at a valid row of an intKey table.
59231 */
59232 if( !pCsr->wrFlag ){
59233 return SQLITE_READONLY;
59234 }
59235 assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
59236 && pCsr->pBt->inTransaction==TRANS_WRITE );
59237 assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
@@ -59240,24 +59363,14 @@
59240
59241 return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
59242 }
59243
59244 /*
59245 ** Set a flag on this cursor to cache the locations of pages from the
59246 ** overflow list for the current row. This is used by cursors opened
59247 ** for incremental blob IO only.
59248 **
59249 ** This function sets a flag only. The actual page location cache
59250 ** (stored in BtCursor.aOverflow[]) is allocated and used by function
59251 ** accessPayload() (the worker function for sqlite3BtreeData() and
59252 ** sqlite3BtreePutData()).
59253 */
59254 SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
59255 assert( cursorHoldsMutex(pCur) );
59256 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
59257 invalidateOverflowCache(pCur);
59258 pCur->isIncrblobHandle = 1;
59259 }
59260 #endif
59261
59262 /*
59263 ** Set both the "read version" (single byte at byte offset 18) and
@@ -61624,11 +61737,11 @@
61624 SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
61625 Parse *p = v->pParse;
61626 int j = -1-x;
61627 assert( v->magic==VDBE_MAGIC_INIT );
61628 assert( j<p->nLabel );
61629 if( j>=0 && p->aLabel ){
61630 p->aLabel[j] = v->nOp;
61631 }
61632 p->iFixedOp = v->nOp - 1;
61633 }
61634
@@ -62131,11 +62244,13 @@
62131 assert( addr<p->nOp );
62132 if( addr<0 ){
62133 addr = p->nOp - 1;
62134 }
62135 pOp = &p->aOp[addr];
62136 assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
 
 
62137 freeP4(db, pOp->p4type, pOp->p4.p);
62138 pOp->p4.p = 0;
62139 if( n==P4_INT32 ){
62140 /* Note: this cast is safe, because the origin data point was an int
62141 ** that was cast to a (const char *). */
@@ -64081,11 +64196,11 @@
64081 int hasMoved;
64082 int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
64083 if( rc ) return rc;
64084 if( hasMoved ){
64085 p->cacheStatus = CACHE_STALE;
64086 p->nullRow = 1;
64087 }
64088 }
64089 return SQLITE_OK;
64090 }
64091
@@ -64751,14 +64866,17 @@
64751 ** determined that the first fields of the keys are equal.
64752 **
64753 ** Key1 and Key2 do not have to contain the same number of fields. If all
64754 ** fields that appear in both keys are equal, then pPKey2->default_rc is
64755 ** returned.
 
 
 
64756 */
64757 SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
64758 int nKey1, const void *pKey1, /* Left key */
64759 const UnpackedRecord *pPKey2, /* Right key */
64760 int bSkip /* If true, skip the first field */
64761 ){
64762 u32 d1; /* Offset into aKey[] of next data element */
64763 int i; /* Index of next field to compare */
64764 u32 szHdr1; /* Size of record header in bytes */
@@ -64780,10 +64898,14 @@
64780 i = 1;
64781 pRhs++;
64782 }else{
64783 idx1 = getVarint32(aKey1, szHdr1);
64784 d1 = szHdr1;
 
 
 
 
64785 i = 0;
64786 }
64787
64788 VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
64789 assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
@@ -64856,11 +64978,12 @@
64856 }else{
64857 mem1.n = (serial_type - 12) / 2;
64858 testcase( (d1+mem1.n)==(unsigned)nKey1 );
64859 testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
64860 if( (d1+mem1.n) > (unsigned)nKey1 ){
64861 rc = 1; /* Corruption */
 
64862 }else if( pKeyInfo->aColl[i] ){
64863 mem1.enc = pKeyInfo->enc;
64864 mem1.db = pKeyInfo->db;
64865 mem1.flags = MEM_Str;
64866 mem1.z = (char*)&aKey1[d1];
@@ -64882,11 +65005,12 @@
64882 }else{
64883 int nStr = (serial_type - 12) / 2;
64884 testcase( (d1+nStr)==(unsigned)nKey1 );
64885 testcase( (d1+nStr+1)==(unsigned)nKey1 );
64886 if( (d1+nStr) > (unsigned)nKey1 ){
64887 rc = 1; /* Corruption */
 
64888 }else{
64889 int nCmp = MIN(nStr, pRhs->n);
64890 rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
64891 if( rc==0 ) rc = nStr - pRhs->n;
64892 }
@@ -64935,14 +65059,17 @@
64935 /*
64936 ** This function is an optimized version of sqlite3VdbeRecordCompare()
64937 ** that (a) the first field of pPKey2 is an integer, and (b) the
64938 ** size-of-header varint at the start of (pKey1/nKey1) fits in a single
64939 ** byte (i.e. is less than 128).
 
 
 
64940 */
64941 static int vdbeRecordCompareInt(
64942 int nKey1, const void *pKey1, /* Left key */
64943 const UnpackedRecord *pPKey2, /* Right key */
64944 int bSkip /* Ignored */
64945 ){
64946 const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
64947 int serial_type = ((const u8*)pKey1)[1];
64948 int res;
@@ -64951,10 +65078,11 @@
64951 i64 v = pPKey2->aMem[0].u.i;
64952 i64 lhs;
64953 UNUSED_PARAMETER(bSkip);
64954
64955 assert( bSkip==0 );
 
64956 switch( serial_type ){
64957 case 1: { /* 1-byte signed integer */
64958 lhs = ONE_BYTE_INT(aKey);
64959 testcase( lhs<0 );
64960 break;
@@ -65035,11 +65163,11 @@
65035 ** uses the collation sequence BINARY and (c) that the size-of-header varint
65036 ** at the start of (pKey1/nKey1) fits in a single byte.
65037 */
65038 static int vdbeRecordCompareString(
65039 int nKey1, const void *pKey1, /* Left key */
65040 const UnpackedRecord *pPKey2, /* Right key */
65041 int bSkip
65042 ){
65043 const u8 *aKey1 = (const u8*)pKey1;
65044 int serial_type;
65045 int res;
@@ -65056,11 +65184,14 @@
65056 int nCmp;
65057 int nStr;
65058 int szHdr = aKey1[0];
65059
65060 nStr = (serial_type-12) / 2;
65061 if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */
 
 
 
65062 nCmp = MIN( pPKey2->aMem[0].n, nStr );
65063 res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
65064
65065 if( res==0 ){
65066 res = nStr - pPKey2->aMem[0].n;
@@ -65221,11 +65352,11 @@
65221 ** is ignored as well. Hence, this routine only compares the prefixes
65222 ** of the keys prior to the final rowid, not the entire key.
65223 */
65224 SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
65225 VdbeCursor *pC, /* The cursor to compare against */
65226 const UnpackedRecord *pUnpacked, /* Unpacked version of key */
65227 int *res /* Write the comparison result here */
65228 ){
65229 i64 nCellKey = 0;
65230 int rc;
65231 BtCursor *pCur = pC->pCursor;
@@ -67311,10 +67442,33 @@
67311 u8 affinity,
67312 u8 enc
67313 ){
67314 applyAffinity((Mem *)pVal, affinity, enc);
67315 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67316
67317 #ifdef SQLITE_DEBUG
67318 /*
67319 ** Write a nice string representation of the contents of cell pMem
67320 ** into buffer zBuf, length nBuf.
@@ -68171,14 +68325,15 @@
68171 }
68172
68173 /* Opcode: Move P1 P2 P3 * *
68174 ** Synopsis: r[P2@P3]=r[P1@P3]
68175 **
68176 ** Move the values in register P1..P1+P3 over into
68177 ** registers P2..P2+P3. Registers P1..P1+P3 are
68178 ** left holding a NULL. It is an error for register ranges
68179 ** P1..P1+P3 and P2..P2+P3 to overlap.
 
68180 */
68181 case OP_Move: {
68182 char *zMalloc; /* Holding variable for allocated memory */
68183 int n; /* Number of registers left to copy */
68184 int p1; /* Register to copy from */
@@ -68185,11 +68340,11 @@
68185 int p2; /* Register to copy to */
68186
68187 n = pOp->p3;
68188 p1 = pOp->p1;
68189 p2 = pOp->p2;
68190 assert( n>=0 && p1>0 && p2>0 );
68191 assert( p1+n<=p2 || p2+n<=p1 );
68192
68193 pIn1 = &aMem[p1];
68194 pOut = &aMem[p2];
68195 do{
@@ -68209,11 +68364,11 @@
68209 pIn1->xDel = 0;
68210 pIn1->zMalloc = zMalloc;
68211 REGISTER_TRACE(p2++, pOut);
68212 pIn1++;
68213 pOut++;
68214 }while( n-- );
68215 break;
68216 }
68217
68218 /* Opcode: Copy P1 P2 P3 * *
68219 ** Synopsis: r[P2@P3+1]=r[P1@P3+1]
@@ -68441,24 +68596,26 @@
68441 case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
68442 case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
68443 case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
68444 case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
68445 char bIntint; /* Started out as two integer operands */
68446 int flags; /* Combined MEM_* flags from both inputs */
 
 
68447 i64 iA; /* Integer value of left operand */
68448 i64 iB; /* Integer value of right operand */
68449 double rA; /* Real value of left operand */
68450 double rB; /* Real value of right operand */
68451
68452 pIn1 = &aMem[pOp->p1];
68453 applyNumericAffinity(pIn1);
68454 pIn2 = &aMem[pOp->p2];
68455 applyNumericAffinity(pIn2);
68456 pOut = &aMem[pOp->p3];
68457 flags = pIn1->flags | pIn2->flags;
68458 if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
68459 if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
68460 iA = pIn1->u.i;
68461 iB = pIn2->u.i;
68462 bIntint = 1;
68463 switch( pOp->opcode ){
68464 case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
@@ -68510,11 +68667,11 @@
68510 if( sqlite3IsNaN(rB) ){
68511 goto arithmetic_result_is_null;
68512 }
68513 pOut->r = rB;
68514 MemSetTypeFlag(pOut, MEM_Real);
68515 if( (flags & MEM_Real)==0 && !bIntint ){
68516 sqlite3VdbeIntegerAffinity(pOut);
68517 }
68518 #endif
68519 }
68520 break;
@@ -69086,10 +69243,11 @@
69086 aPermute = pOp->p4.ai;
69087 break;
69088 }
69089
69090 /* Opcode: Compare P1 P2 P3 P4 P5
 
69091 **
69092 ** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
69093 ** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
69094 ** the comparison for use by the next OP_Jump instruct.
69095 **
@@ -70421,10 +70579,11 @@
70421 assert( pOp->p1>=0 );
70422 assert( pOp->p2>=0 );
70423 pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
70424 if( pCx==0 ) goto no_mem;
70425 pCx->nullRow = 1;
 
70426 rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
70427 BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
70428 if( rc==SQLITE_OK ){
70429 rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
70430 }
@@ -70911,11 +71070,11 @@
70911 pC->seekResult = res;
70912 break;
70913 }
70914
70915 /* Opcode: Sequence P1 P2 * * *
70916 ** Synopsis: r[P2]=rowid
70917 **
70918 ** Find the next available sequence number for cursor P1.
70919 ** Write the sequence number into register P2.
70920 ** The sequence number on the cursor is incremented after this
70921 ** instruction.
@@ -71602,10 +71761,11 @@
71602 VdbeCursor *pC;
71603 int res;
71604
71605 pC = p->apCsr[pOp->p1];
71606 assert( isSorter(pC) );
 
71607 rc = sqlite3VdbeSorterNext(db, pC, &res);
71608 goto next_tail;
71609 case OP_PrevIfOpen: /* jump */
71610 case OP_NextIfOpen: /* jump */
71611 if( p->apCsr[pOp->p1]==0 ) break;
@@ -71959,10 +72119,33 @@
71959 aMem[pOp->p3].u.i += nChange;
71960 }
71961 }
71962 break;
71963 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71964
71965 /* Opcode: CreateTable P1 P2 * * *
71966 ** Synopsis: r[P2]=root iDb=P1
71967 **
71968 ** Allocate a new table in the main database file if P1==0 or in the
@@ -72266,13 +72449,11 @@
72266 }
72267
72268 assert( pOp->p4type==P4_INT32 );
72269 assert( iSet==-1 || iSet>=0 );
72270 if( iSet ){
72271 exists = sqlite3RowSetTest(pIn1->u.pRowSet,
72272 (u8)(iSet>=0 ? iSet & 0xf : 0xff),
72273 pIn3->u.i);
72274 VdbeBranchTaken(exists!=0,2);
72275 if( exists ){
72276 pc = pOp->p2 - 1;
72277 break;
72278 }
@@ -72968,11 +73149,11 @@
72968 }
72969 #endif /* SQLITE_OMIT_VIRTUALTABLE */
72970
72971 #ifndef SQLITE_OMIT_VIRTUALTABLE
72972 /* Opcode: VFilter P1 P2 P3 P4 *
72973 ** Synopsis: iPlan=r[P3] zPlan='P4'
72974 **
72975 ** P1 is a cursor opened using VOpen. P2 is an address to jump to if
72976 ** the filtered result set is empty.
72977 **
72978 ** P4 is either NULL or a string that was generated by the xBestIndex
@@ -73536,13 +73717,11 @@
73536 p->pStmt = 0;
73537 }else{
73538 p->iOffset = pC->aType[p->iCol + pC->nField];
73539 p->nByte = sqlite3VdbeSerialTypeLen(type);
73540 p->pCsr = pC->pCursor;
73541 sqlite3BtreeEnterCursor(p->pCsr);
73542 sqlite3BtreeCacheOverflow(p->pCsr);
73543 sqlite3BtreeLeaveCursor(p->pCsr);
73544 }
73545 }
73546
73547 if( rc==SQLITE_ROW ){
73548 rc = SQLITE_OK;
@@ -74431,28 +74610,45 @@
74431 for(p=pRecord; p; p=pNext){
74432 pNext = p->pNext;
74433 sqlite3DbFree(db, p);
74434 }
74435 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74436
74437 /*
74438 ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
74439 */
74440 SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
74441 VdbeSorter *pSorter = pCsr->pSorter;
74442 if( pSorter ){
74443 if( pSorter->aIter ){
74444 int i;
74445 for(i=0; i<pSorter->nTree; i++){
74446 vdbeSorterIterZero(db, &pSorter->aIter[i]);
74447 }
74448 sqlite3DbFree(db, pSorter->aIter);
74449 }
74450 if( pSorter->pTemp1 ){
74451 sqlite3OsCloseFree(pSorter->pTemp1);
74452 }
74453 vdbeSorterRecordFree(db, pSorter->pRecord);
74454 sqlite3DbFree(db, pSorter->pUnpacked);
74455 sqlite3DbFree(db, pSorter);
74456 pCsr->pSorter = 0;
74457 }
74458 }
@@ -74884,18 +75080,59 @@
74884 VdbeSorter *pSorter = pCsr->pSorter;
74885 int rc; /* Return code */
74886
74887 if( pSorter->aTree ){
74888 int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
74889 int i; /* Index of aTree[] to recalculate */
74890
74891 rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
74892 for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){
74893 rc = vdbeSorterDoCompare(pCsr, i);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74894 }
74895
74896 *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
74897 }else{
74898 SorterRecord *pFree = pSorter->pRecord;
74899 pSorter->pRecord = pFree->pNext;
74900 pFree->pNext = 0;
74901 vdbeSorterRecordFree(db, pFree);
@@ -77127,10 +77364,11 @@
77127 ** SELECT * FROM t1 WHERE (select a from t1);
77128 */
77129 SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
77130 int op;
77131 pExpr = sqlite3ExprSkipCollate(pExpr);
 
77132 op = pExpr->op;
77133 if( op==TK_SELECT ){
77134 assert( pExpr->flags&EP_xIsSelect );
77135 return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
77136 }
@@ -77159,11 +77397,15 @@
77159 ** implements the COLLATE operator.
77160 **
77161 ** If a memory allocation error occurs, that fact is recorded in pParse->db
77162 ** and the pExpr parameter is returned unchanged.
77163 */
77164 SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
 
 
 
 
77165 if( pCollName->n>0 ){
77166 Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
77167 if( pNew ){
77168 pNew->pLeft = pExpr;
77169 pNew->flags |= EP_Collate|EP_Skip;
@@ -77212,10 +77454,11 @@
77212 sqlite3 *db = pParse->db;
77213 CollSeq *pColl = 0;
77214 Expr *p = pExpr;
77215 while( p ){
77216 int op = p->op;
 
77217 if( op==TK_CAST || op==TK_UPLUS ){
77218 p = p->pLeft;
77219 continue;
77220 }
77221 if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
@@ -78043,11 +78286,10 @@
78043 struct ExprList_item *pItem, *pOldItem;
78044 int i;
78045 if( p==0 ) return 0;
78046 pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
78047 if( pNew==0 ) return 0;
78048 pNew->iECursor = 0;
78049 pNew->nExpr = i = p->nExpr;
78050 if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
78051 pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
78052 if( pItem==0 ){
78053 sqlite3DbFree(db, pNew);
@@ -78156,11 +78398,10 @@
78156 pNew->iLimit = 0;
78157 pNew->iOffset = 0;
78158 pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
78159 pNew->addrOpenEphm[0] = -1;
78160 pNew->addrOpenEphm[1] = -1;
78161 pNew->addrOpenEphm[2] = -1;
78162 pNew->nSelectRow = p->nSelectRow;
78163 pNew->pWith = withDup(db, p->pWith);
78164 return pNew;
78165 }
78166 #else
@@ -78724,11 +78965,10 @@
78724 eType = IN_INDEX_EPH;
78725 if( prNotFound ){
78726 *prNotFound = rMayHaveNull = ++pParse->nMem;
78727 sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
78728 }else{
78729 testcase( pParse->nQueryLoop>0 );
78730 pParse->nQueryLoop = 0;
78731 if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
78732 eType = IN_INDEX_ROWID;
78733 }
78734 }
@@ -78974,11 +79214,11 @@
78974 }
78975
78976 if( testAddr>=0 ){
78977 sqlite3VdbeJumpHere(v, testAddr);
78978 }
78979 sqlite3ExprCachePop(pParse, 1);
78980
78981 return rReg;
78982 }
78983 #endif /* SQLITE_OMIT_SUBQUERY */
78984
@@ -79109,11 +79349,11 @@
79109 */
79110 sqlite3VdbeJumpHere(v, j1);
79111 }
79112 }
79113 sqlite3ReleaseTempReg(pParse, r1);
79114 sqlite3ExprCachePop(pParse, 1);
79115 VdbeComment((v, "end IN expr"));
79116 }
79117 #endif /* SQLITE_OMIT_SUBQUERY */
79118
79119 /*
@@ -79292,19 +79532,18 @@
79292 #endif
79293 }
79294
79295 /*
79296 ** Remove from the column cache any entries that were added since the
79297 ** the previous N Push operations. In other words, restore the cache
79298 ** to the state it was in N Pushes ago.
79299 */
79300 SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse, int N){
79301 int i;
79302 struct yColCache *p;
79303 assert( N>0 );
79304 assert( pParse->iCacheLevel>=N );
79305 pParse->iCacheLevel -= N;
79306 #ifdef SQLITE_DEBUG
79307 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
79308 printf("POP to %d\n", pParse->iCacheLevel);
79309 }
79310 #endif
@@ -79429,11 +79668,11 @@
79429 */
79430 SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
79431 int i;
79432 struct yColCache *p;
79433 assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
79434 sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
79435 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
79436 int x = p->iReg;
79437 if( x>=iFrom && x<iFrom+nReg ){
79438 p->iReg += iTo-iFrom;
79439 }
@@ -79778,11 +80017,11 @@
79778 sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
79779 VdbeCoverage(v);
79780 sqlite3ExprCacheRemove(pParse, target, 1);
79781 sqlite3ExprCachePush(pParse);
79782 sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
79783 sqlite3ExprCachePop(pParse, 1);
79784 }
79785 sqlite3VdbeResolveLabel(v, endCoalesce);
79786 break;
79787 }
79788
@@ -79830,13 +80069,13 @@
79830 pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
79831 }
79832 }
79833
79834 sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
79835 sqlite3ExprCodeExprList(pParse, pFarg, r1,
79836 SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
79837 sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
79838 }else{
79839 r1 = 0;
79840 }
79841 #ifndef SQLITE_OMIT_VIRTUALTABLE
79842 /* Possibly overload the function if the first argument is
@@ -80052,17 +80291,17 @@
80052 testcase( pTest->op==TK_COLUMN );
80053 sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
80054 testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
80055 sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
80056 sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
80057 sqlite3ExprCachePop(pParse, 1);
80058 sqlite3VdbeResolveLabel(v, nextCase);
80059 }
80060 if( (nExpr&1)!=0 ){
80061 sqlite3ExprCachePush(pParse);
80062 sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
80063 sqlite3ExprCachePop(pParse, 1);
80064 }else{
80065 sqlite3VdbeAddOp2(v, OP_Null, 0, target);
80066 }
80067 assert( db->mallocFailed || pParse->nErr>0
80068 || pParse->iCacheLevel==iCacheLevel );
@@ -80637,19 +80876,19 @@
80637 testcase( jumpIfNull==0 );
80638 sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
80639 sqlite3ExprCachePush(pParse);
80640 sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
80641 sqlite3VdbeResolveLabel(v, d2);
80642 sqlite3ExprCachePop(pParse, 1);
80643 break;
80644 }
80645 case TK_OR: {
80646 testcase( jumpIfNull==0 );
80647 sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
80648 sqlite3ExprCachePush(pParse);
80649 sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
80650 sqlite3ExprCachePop(pParse, 1);
80651 break;
80652 }
80653 case TK_NOT: {
80654 testcase( jumpIfNull==0 );
80655 sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
@@ -80791,21 +81030,21 @@
80791 case TK_AND: {
80792 testcase( jumpIfNull==0 );
80793 sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
80794 sqlite3ExprCachePush(pParse);
80795 sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
80796 sqlite3ExprCachePop(pParse, 1);
80797 break;
80798 }
80799 case TK_OR: {
80800 int d2 = sqlite3VdbeMakeLabel(v);
80801 testcase( jumpIfNull==0 );
80802 sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
80803 sqlite3ExprCachePush(pParse);
80804 sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
80805 sqlite3VdbeResolveLabel(v, d2);
80806 sqlite3ExprCachePop(pParse, 1);
80807 break;
80808 }
80809 case TK_NOT: {
80810 testcase( jumpIfNull==0 );
80811 sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
@@ -81465,10 +81704,11 @@
81465 unsigned const char *z; /* Pointer to token */
81466 int n; /* Length of token z */
81467 int token; /* Type of token */
81468
81469 UNUSED_PARAMETER(NotUsed);
 
81470 for(z=zInput; *z; z=z+n){
81471 n = sqlite3GetToken(z, &token);
81472 if( token==TK_REFERENCES ){
81473 char *zParent;
81474 do {
@@ -87459,11 +87699,11 @@
87459 addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
87460 regRecord = sqlite3GetTempReg(pParse);
87461
87462 sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
87463 sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
87464 sqlite3VdbeResolveLabel(v, iPartIdxLabel);
87465 sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
87466 sqlite3VdbeJumpHere(v, addr1);
87467 if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
87468 sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
87469 (char *)pKey, P4_KEYINFO);
@@ -90236,11 +90476,11 @@
90236 VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
90237 r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
90238 &iPartIdxLabel, pPrior, r1);
90239 sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
90240 pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
90241 sqlite3VdbeResolveLabel(v, iPartIdxLabel);
90242 pPrior = pIdx;
90243 }
90244 }
90245
90246 /*
@@ -90255,14 +90495,15 @@
90255 ** block of registers has already been deallocated by the time
90256 ** this routine returns.
90257 **
90258 ** If *piPartIdxLabel is not NULL, fill it in with a label and jump
90259 ** to that label if pIdx is a partial index that should be skipped.
 
90260 ** A partial index should be skipped if its WHERE clause evaluates
90261 ** to false or null. If pIdx is not a partial index, *piPartIdxLabel
90262 ** will be set to zero which is an empty label that is ignored by
90263 ** sqlite3VdbeResolveLabel().
90264 **
90265 ** The pPrior and regPrior parameters are used to implement a cache to
90266 ** avoid unnecessary register loads. If pPrior is not NULL, then it is
90267 ** a pointer to a different index for which an index key has just been
90268 ** computed into register regPrior. If the current pIdx index is generating
@@ -90291,10 +90532,11 @@
90291
90292 if( piPartIdxLabel ){
90293 if( pIdx->pPartIdxWhere ){
90294 *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
90295 pParse->iPartIdxTab = iDataCur;
 
90296 sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
90297 SQLITE_JUMPIFNULL);
90298 }else{
90299 *piPartIdxLabel = 0;
90300 }
@@ -90318,10 +90560,22 @@
90318 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
90319 }
90320 sqlite3ReleaseTempRange(pParse, regBase, nCol);
90321 return regBase;
90322 }
 
 
 
 
 
 
 
 
 
 
 
 
90323
90324 /************** End of delete.c **********************************************/
90325 /************** Begin file func.c ********************************************/
90326 /*
90327 ** 2002 February 23
@@ -98716,11 +98970,11 @@
98716 sqlite3VdbeChangeP5(v, (u8)i);
98717 addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
98718 sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
98719 sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
98720 P4_DYNAMIC);
98721 sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
98722 sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
98723 sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
98724 sqlite3VdbeJumpHere(v, addr);
98725
98726 /* Make sure all the indices are constructed correctly.
@@ -98769,11 +99023,11 @@
98769 sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
98770 jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
98771 sqlite3VdbeAddOp0(v, OP_Halt);
98772 sqlite3VdbeJumpHere(v, jmp4);
98773 sqlite3VdbeJumpHere(v, jmp2);
98774 sqlite3VdbeResolveLabel(v, jmp3);
98775 }
98776 sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
98777 sqlite3VdbeJumpHere(v, loopTop-1);
98778 #ifndef SQLITE_OMIT_BTREECOUNT
98779 sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
@@ -100054,10 +100308,38 @@
100054 *************************************************************************
100055 ** This file contains C code routines that are called by the parser
100056 ** to handle SELECT statements in SQLite.
100057 */
100058
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100059
100060 /*
100061 ** Delete all the content of a Select structure but do not deallocate
100062 ** the select structure itself.
100063 */
@@ -100127,11 +100409,10 @@
100127 pNew->pLimit = pLimit;
100128 pNew->pOffset = pOffset;
100129 assert( pOffset==0 || pLimit!=0 );
100130 pNew->addrOpenEphm[0] = -1;
100131 pNew->addrOpenEphm[1] = -1;
100132 pNew->addrOpenEphm[2] = -1;
100133 if( db->mallocFailed ) {
100134 clearSelect(db, pNew);
100135 if( pNew!=&standin ) sqlite3DbFree(db, pNew);
100136 pNew = 0;
100137 }else{
@@ -100459,38 +100740,79 @@
100459 }
100460 }
100461 return 0;
100462 }
100463
 
 
 
 
 
 
 
 
100464 /*
100465 ** Insert code into "v" that will push the record on the top of the
100466 ** stack into the sorter.
100467 */
100468 static void pushOntoSorter(
100469 Parse *pParse, /* Parser context */
100470 ExprList *pOrderBy, /* The ORDER BY clause */
100471 Select *pSelect, /* The whole SELECT statement */
100472 int regData /* Register holding data to be sorted */
100473 ){
100474 Vdbe *v = pParse->pVdbe;
100475 int nExpr = pOrderBy->nExpr;
100476 int regBase = sqlite3GetTempRange(pParse, nExpr+2);
100477 int regRecord = sqlite3GetTempReg(pParse);
 
100478 int op;
100479 sqlite3ExprCacheClear(pParse);
100480 sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
100481 sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
100482 sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
100483 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
100484 if( pSelect->selFlags & SF_UseSorter ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100485 op = OP_SorterInsert;
100486 }else{
100487 op = OP_IdxInsert;
100488 }
100489 sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord);
100490 sqlite3ReleaseTempReg(pParse, regRecord);
100491 sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
 
 
100492 if( pSelect->iLimit ){
100493 int addr1, addr2;
100494 int iLimit;
100495 if( pSelect->iOffset ){
100496 iLimit = pSelect->iOffset+1;
@@ -100499,12 +100821,12 @@
100499 }
100500 addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
100501 sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
100502 addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
100503 sqlite3VdbeJumpHere(v, addr1);
100504 sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
100505 sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
100506 sqlite3VdbeJumpHere(v, addr2);
100507 }
100508 }
100509
100510 /*
@@ -100513,11 +100835,11 @@
100513 static void codeOffset(
100514 Vdbe *v, /* Generate code into this VM */
100515 int iOffset, /* Register holding the offset counter */
100516 int iContinue /* Jump here to skip the current record */
100517 ){
100518 if( iOffset>0 && iContinue!=0 ){
100519 int addr;
100520 sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
100521 addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
100522 sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
100523 VdbeComment((v, "skip OFFSET records"));
@@ -100574,23 +100896,10 @@
100574 return 0;
100575 }
100576 }
100577 #endif
100578
100579 /*
100580 ** An instance of the following object is used to record information about
100581 ** how to process the DISTINCT keyword, to simplify passing that information
100582 ** into the selectInnerLoop() routine.
100583 */
100584 typedef struct DistinctCtx DistinctCtx;
100585 struct DistinctCtx {
100586 u8 isTnct; /* True if the DISTINCT keyword is present */
100587 u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
100588 int tabTnct; /* Ephemeral table used for DISTINCT processing */
100589 int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
100590 };
100591
100592 /*
100593 ** This routine generates the code for the inside of the inner loop
100594 ** of a SELECT.
100595 **
100596 ** If srcTab is negative, then the pEList expressions
@@ -100601,11 +100910,11 @@
100601 static void selectInnerLoop(
100602 Parse *pParse, /* The parser context */
100603 Select *p, /* The complete select statement being coded */
100604 ExprList *pEList, /* List of values being extracted */
100605 int srcTab, /* Pull data from this table */
100606 ExprList *pOrderBy, /* If not NULL, sort results using this key */
100607 DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
100608 SelectDest *pDest, /* How to dispose of the results */
100609 int iContinue, /* Jump here to continue with next row */
100610 int iBreak /* Jump here to break out of the inner loop */
100611 ){
@@ -100618,11 +100927,13 @@
100618 int nResultCol; /* Number of result columns */
100619
100620 assert( v );
100621 assert( pEList!=0 );
100622 hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
100623 if( pOrderBy==0 && !hasDistinct ){
 
 
100624 codeOffset(v, p->iOffset, iContinue);
100625 }
100626
100627 /* Pull the requested columns.
100628 */
@@ -100708,11 +101019,11 @@
100708 assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
100709 codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
100710 break;
100711 }
100712 }
100713 if( pOrderBy==0 ){
100714 codeOffset(v, p->iOffset, iContinue);
100715 }
100716 }
100717
100718 switch( eDest ){
@@ -100739,32 +101050,33 @@
100739 }
100740 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
100741
100742 /* Store the result as data using a unique key.
100743 */
100744 case SRT_DistTable:
 
100745 case SRT_Table:
100746 case SRT_EphemTab: {
100747 int r1 = sqlite3GetTempReg(pParse);
100748 testcase( eDest==SRT_Table );
100749 testcase( eDest==SRT_EphemTab );
100750 sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
100751 #ifndef SQLITE_OMIT_CTE
100752 if( eDest==SRT_DistTable ){
100753 /* If the destination is DistTable, then cursor (iParm+1) is open
100754 ** on an ephemeral index. If the current row is already present
100755 ** in the index, do not write it to the output. If not, add the
100756 ** current row to the index and proceed with writing it to the
100757 ** output table as well. */
100758 int addr = sqlite3VdbeCurrentAddr(v) + 4;
100759 sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
100760 sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
100761 assert( pOrderBy==0 );
100762 }
100763 #endif
100764 if( pOrderBy ){
100765 pushOntoSorter(pParse, pOrderBy, p, r1);
100766 }else{
100767 int r2 = sqlite3GetTempReg(pParse);
100768 sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
100769 sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
100770 sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -100781,16 +101093,16 @@
100781 */
100782 case SRT_Set: {
100783 assert( nResultCol==1 );
100784 pDest->affSdst =
100785 sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
100786 if( pOrderBy ){
100787 /* At first glance you would think we could optimize out the
100788 ** ORDER BY in this case since the order of entries in the set
100789 ** does not matter. But there might be a LIMIT clause, in which
100790 ** case the order does matter */
100791 pushOntoSorter(pParse, pOrderBy, p, regResult);
100792 }else{
100793 int r1 = sqlite3GetTempReg(pParse);
100794 sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
100795 sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
100796 sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
@@ -100811,12 +101123,12 @@
100811 ** store the results in the appropriate memory cell and break out
100812 ** of the scan loop.
100813 */
100814 case SRT_Mem: {
100815 assert( nResultCol==1 );
100816 if( pOrderBy ){
100817 pushOntoSorter(pParse, pOrderBy, p, regResult);
100818 }else{
100819 sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
100820 /* The LIMIT clause will jump out of the loop for us */
100821 }
100822 break;
@@ -100825,14 +101137,14 @@
100825
100826 case SRT_Coroutine: /* Send data to a co-routine */
100827 case SRT_Output: { /* Return the results */
100828 testcase( eDest==SRT_Coroutine );
100829 testcase( eDest==SRT_Output );
100830 if( pOrderBy ){
100831 int r1 = sqlite3GetTempReg(pParse);
100832 sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
100833 pushOntoSorter(pParse, pOrderBy, p, r1);
100834 sqlite3ReleaseTempReg(pParse, r1);
100835 }else if( eDest==SRT_Coroutine ){
100836 sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
100837 }else{
100838 sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
@@ -100905,11 +101217,11 @@
100905
100906 /* Jump to the end of the loop if the LIMIT is reached. Except, if
100907 ** there is a sorter, in which case the sorter has already limited
100908 ** the output for us.
100909 */
100910 if( pOrderBy==0 && p->iLimit ){
100911 sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
100912 }
100913 }
100914
100915 /*
@@ -100976,27 +101288,32 @@
100976 **
100977 ** Space to hold the KeyInfo structure is obtain from malloc. The calling
100978 ** function is responsible for seeing that this structure is eventually
100979 ** freed.
100980 */
100981 static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
 
 
 
 
 
100982 int nExpr;
100983 KeyInfo *pInfo;
100984 struct ExprList_item *pItem;
100985 sqlite3 *db = pParse->db;
100986 int i;
100987
100988 nExpr = pList->nExpr;
100989 pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1);
100990 if( pInfo ){
100991 assert( sqlite3KeyInfoIsWriteable(pInfo) );
100992 for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
100993 CollSeq *pColl;
100994 pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
100995 if( !pColl ) pColl = db->pDfltColl;
100996 pInfo->aColl[i] = pColl;
100997 pInfo->aSortOrder[i] = pItem->sortOrder;
100998 }
100999 }
101000 return pInfo;
101001 }
101002
@@ -101094,50 +101411,60 @@
101094 ** routine generates the code needed to do that.
101095 */
101096 static void generateSortTail(
101097 Parse *pParse, /* Parsing context */
101098 Select *p, /* The SELECT statement */
101099 Vdbe *v, /* Generate code into this VDBE */
101100 int nColumn, /* Number of columns of data */
101101 SelectDest *pDest /* Write the sorted results here */
101102 ){
 
101103 int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
101104 int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
101105 int addr;
 
101106 int iTab;
101107 int pseudoTab = 0;
101108 ExprList *pOrderBy = p->pOrderBy;
101109
101110 int eDest = pDest->eDest;
101111 int iParm = pDest->iSDParm;
101112
101113 int regRow;
101114 int regRowid;
 
101115
101116 iTab = pOrderBy->iECursor;
 
 
 
 
 
 
101117 regRow = sqlite3GetTempReg(pParse);
101118 if( eDest==SRT_Output || eDest==SRT_Coroutine ){
101119 pseudoTab = pParse->nTab++;
101120 sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
101121 regRowid = 0;
101122 }else{
101123 regRowid = sqlite3GetTempReg(pParse);
101124 }
101125 if( p->selFlags & SF_UseSorter ){
 
101126 int regSortOut = ++pParse->nMem;
101127 int ptab2 = pParse->nTab++;
101128 sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2);
 
101129 addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
101130 VdbeCoverage(v);
101131 codeOffset(v, p->iOffset, addrContinue);
101132 sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
101133 sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow);
101134 sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
101135 }else{
 
101136 addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
101137 codeOffset(v, p->iOffset, addrContinue);
101138 sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow);
101139 }
101140 switch( eDest ){
101141 case SRT_Table:
101142 case SRT_EphemTab: {
101143 testcase( eDest==SRT_Table );
@@ -101188,15 +101515,16 @@
101188 sqlite3ReleaseTempReg(pParse, regRowid);
101189
101190 /* The bottom of the loop
101191 */
101192 sqlite3VdbeResolveLabel(v, addrContinue);
101193 if( p->selFlags & SF_UseSorter ){
101194 sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
101195 }else{
101196 sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
101197 }
 
101198 sqlite3VdbeResolveLabel(v, addrBreak);
101199 if( eDest==SRT_Output || eDest==SRT_Coroutine ){
101200 sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
101201 }
101202 }
@@ -101874,11 +102202,11 @@
101874 int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
101875 int iCurrent = 0; /* The Current table */
101876 int regCurrent; /* Register holding Current table */
101877 int iQueue; /* The Queue table */
101878 int iDistinct = 0; /* To ensure unique results if UNION */
101879 int eDest = SRT_Table; /* How to write to Queue */
101880 SelectDest destQueue; /* SelectDest targetting the Queue table */
101881 int i; /* Loop counter */
101882 int rc; /* Result code */
101883 ExprList *pOrderBy; /* The ORDER BY clause */
101884 Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */
@@ -101906,17 +102234,17 @@
101906 }
101907 }
101908
101909 /* Allocate cursors numbers for Queue and Distinct. The cursor number for
101910 ** the Distinct table must be exactly one greater than Queue in order
101911 ** for the SRT_DistTable and SRT_DistQueue destinations to work. */
101912 iQueue = pParse->nTab++;
101913 if( p->op==TK_UNION ){
101914 eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable;
101915 iDistinct = pParse->nTab++;
101916 }else{
101917 eDest = pOrderBy ? SRT_Queue : SRT_Table;
101918 }
101919 sqlite3SelectDestInit(&destQueue, eDest, iQueue);
101920
101921 /* Allocate cursors for Current, Queue, and Distinct. */
101922 regCurrent = ++pParse->nMem;
@@ -101978,10 +102306,11 @@
101978 /* Keep running the loop until the Queue is empty */
101979 sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
101980 sqlite3VdbeResolveLabel(v, addrBreak);
101981
101982 end_of_recursive_query:
 
101983 p->pOrderBy = pOrderBy;
101984 p->pLimit = pLimit;
101985 p->pOffset = pOffset;
101986 return;
101987 }
@@ -104349,11 +104678,11 @@
104349 if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
104350 sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
104351 "argument");
104352 pFunc->iDistinct = -1;
104353 }else{
104354 KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0);
104355 sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
104356 (char*)pKeyInfo, P4_KEYINFO);
104357 }
104358 }
104359 }
@@ -104504,16 +104833,15 @@
104504 Vdbe *v; /* The virtual machine under construction */
104505 int isAgg; /* True for select lists like "count(*)" */
104506 ExprList *pEList; /* List of columns to extract. */
104507 SrcList *pTabList; /* List of tables to select from */
104508 Expr *pWhere; /* The WHERE clause. May be NULL */
104509 ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
104510 ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
104511 Expr *pHaving; /* The HAVING clause. May be NULL */
104512 int rc = 1; /* Value to return from this function */
104513 int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
104514 DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
 
104515 AggInfo sAggInfo; /* Information used by aggregate queries */
104516 int iEnd; /* Address of the end of the query */
104517 sqlite3 *db; /* The database connection */
104518
104519 #ifndef SQLITE_OMIT_EXPLAIN
@@ -104526,21 +104854,28 @@
104526 return 1;
104527 }
104528 if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
104529 memset(&sAggInfo, 0, sizeof(sAggInfo));
104530
 
 
 
 
104531 if( IgnorableOrderby(pDest) ){
104532 assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
104533 pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard);
 
 
104534 /* If ORDER BY makes no difference in the output then neither does
104535 ** DISTINCT so it can be removed too. */
104536 sqlite3ExprListDelete(db, p->pOrderBy);
104537 p->pOrderBy = 0;
104538 p->selFlags &= ~SF_Distinct;
104539 }
104540 sqlite3SelectPrep(pParse, p, 0);
104541 pOrderBy = p->pOrderBy;
 
104542 pTabList = p->pSrc;
104543 pEList = p->pEList;
104544 if( pParse->nErr || db->mallocFailed ){
104545 goto select_end;
104546 }
@@ -104658,11 +104993,11 @@
104658 goto select_end;
104659 }
104660 pParse->nHeight -= sqlite3SelectExprHeight(p);
104661 pTabList = p->pSrc;
104662 if( !IgnorableOrderby(pDest) ){
104663 pOrderBy = p->pOrderBy;
104664 }
104665 }
104666 pEList = p->pEList;
104667 #endif
104668 pWhere = p->pWhere;
@@ -104685,13 +105020,13 @@
104685 ** will cause elements to come out in the correct order. This is
104686 ** an optimization - the correct answer should result regardless.
104687 ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
104688 ** to disable this optimization for testing purposes.
104689 */
104690 if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0
104691 && OptimizationEnabled(db, SQLITE_GroupByOrder) ){
104692 pOrderBy = 0;
104693 }
104694
104695 /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
104696 ** if the select-list is the same as the ORDER BY list, then this query
104697 ** can be rewritten as a GROUP BY. In other words, this:
@@ -104706,16 +105041,16 @@
104706 ** used for both the ORDER BY and DISTINCT processing. As originally
104707 ** written the query must use a temp-table for at least one of the ORDER
104708 ** BY and DISTINCT, and an index or separate temp-table for the other.
104709 */
104710 if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
104711 && sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0
104712 ){
104713 p->selFlags &= ~SF_Distinct;
104714 p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
104715 pGroupBy = p->pGroupBy;
104716 pOrderBy = 0;
104717 /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
104718 ** the sDistinct.isTnct is still set. Hence, isTnct represents the
104719 ** original setting of the SF_Distinct flag, not the current setting */
104720 assert( sDistinct.isTnct );
104721 }
@@ -104725,20 +105060,20 @@
104725 ** extracted in pre-sorted order. If that is the case, then the
104726 ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
104727 ** we figure out that the sorting index is not needed. The addrSortIndex
104728 ** variable is used to facilitate that change.
104729 */
104730 if( pOrderBy ){
104731 KeyInfo *pKeyInfo;
104732 pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0);
104733 pOrderBy->iECursor = pParse->nTab++;
104734 p->addrOpenEphm[2] = addrSortIndex =
104735 sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
104736 pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
104737 (char*)pKeyInfo, P4_KEYINFO);
104738 }else{
104739 addrSortIndex = -1;
104740 }
104741
104742 /* If the output is destined for a temporary table, open that table.
104743 */
104744 if( pDest->eDest==SRT_EphemTab ){
@@ -104748,22 +105083,22 @@
104748 /* Set the limiter.
104749 */
104750 iEnd = sqlite3VdbeMakeLabel(v);
104751 p->nSelectRow = LARGEST_INT64;
104752 computeLimitRegisters(pParse, p, iEnd);
104753 if( p->iLimit==0 && addrSortIndex>=0 ){
104754 sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen;
104755 p->selFlags |= SF_UseSorter;
104756 }
104757
104758 /* Open a virtual index to use for the distinct set.
104759 */
104760 if( p->selFlags & SF_Distinct ){
104761 sDistinct.tabTnct = pParse->nTab++;
104762 sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
104763 sDistinct.tabTnct, 0, 0,
104764 (char*)keyInfoFromExprList(pParse, p->pEList, 0),
104765 P4_KEYINFO);
104766 sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
104767 sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
104768 }else{
104769 sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
@@ -104772,32 +105107,36 @@
104772 if( !isAgg && pGroupBy==0 ){
104773 /* No aggregate functions and no GROUP BY clause */
104774 u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
104775
104776 /* Begin the database scan. */
104777 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList,
104778 wctrlFlags, 0);
104779 if( pWInfo==0 ) goto select_end;
104780 if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
104781 p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
104782 }
104783 if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
104784 sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
104785 }
104786 if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0;
 
 
 
 
 
104787
104788 /* If sorting index that was created by a prior OP_OpenEphemeral
104789 ** instruction ended up not being needed, then change the OP_OpenEphemeral
104790 ** into an OP_Noop.
104791 */
104792 if( addrSortIndex>=0 && pOrderBy==0 ){
104793 sqlite3VdbeChangeToNoop(v, addrSortIndex);
104794 p->addrOpenEphm[2] = -1;
104795 }
104796
104797 /* Use the standard inner loop. */
104798 selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest,
104799 sqlite3WhereContinueLabel(pWInfo),
104800 sqlite3WhereBreakLabel(pWInfo));
104801
104802 /* End the database scan loop.
104803 */
@@ -104849,11 +105188,11 @@
104849 sNC.pAggInfo = &sAggInfo;
104850 sAggInfo.mnReg = pParse->nMem+1;
104851 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
104852 sAggInfo.pGroupBy = pGroupBy;
104853 sqlite3ExprAnalyzeAggList(&sNC, pEList);
104854 sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
104855 if( pHaving ){
104856 sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
104857 }
104858 sAggInfo.nAccumulator = sAggInfo.nColumn;
104859 for(i=0; i<sAggInfo.nFunc; i++){
@@ -104883,11 +105222,11 @@
104883 ** implement it. Allocate that sorting index now. If it turns out
104884 ** that we do not need it after all, the OP_SorterOpen instruction
104885 ** will be converted into a Noop.
104886 */
104887 sAggInfo.sortingIdx = pParse->nTab++;
104888 pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0);
104889 addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
104890 sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
104891 0, (char*)pKeyInfo, P4_KEYINFO);
104892
104893 /* Initialize memory locations used by GROUP BY aggregate processing
@@ -104912,14 +105251,14 @@
104912 ** This might involve two separate loops with an OP_Sort in between, or
104913 ** it might be a single loop that uses an index to extract information
104914 ** in the right order to begin with.
104915 */
104916 sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
104917 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
104918 WHERE_GROUPBY, 0);
104919 if( pWInfo==0 ) goto select_end;
104920 if( sqlite3WhereIsOrdered(pWInfo) ){
104921 /* The optimizer is able to deliver rows in group by order so
104922 ** we do not have to sort. The OP_OpenEphemeral table will be
104923 ** cancelled later because we still need to use the pKeyInfo
104924 */
104925 groupBySort = 0;
@@ -105066,11 +105405,11 @@
105066 sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
105067 VdbeComment((v, "Groupby result generator entry point"));
105068 sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
105069 finalizeAggFunctions(pParse, &sAggInfo);
105070 sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
105071 selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy,
105072 &sDistinct, pDest,
105073 addrOutputRow+1, addrSetAbort);
105074 sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
105075 VdbeComment((v, "end groupby result generator"));
105076
@@ -105198,20 +105537,20 @@
105198 sqlite3ExprListDelete(db, pDel);
105199 goto select_end;
105200 }
105201 updateAccumulator(pParse, &sAggInfo);
105202 assert( pMinMax==0 || pMinMax->nExpr==1 );
105203 if( sqlite3WhereIsOrdered(pWInfo) ){
105204 sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
105205 VdbeComment((v, "%s() by index",
105206 (flag==WHERE_ORDERBY_MIN?"min":"max")));
105207 }
105208 sqlite3WhereEnd(pWInfo);
105209 finalizeAggFunctions(pParse, &sAggInfo);
105210 }
105211
105212 pOrderBy = 0;
105213 sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
105214 selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
105215 pDest, addrEnd, addrEnd);
105216 sqlite3ExprListDelete(db, pDel);
105217 }
@@ -105224,13 +105563,13 @@
105224 }
105225
105226 /* If there is an ORDER BY clause, then we need to sort the results
105227 ** and send them to the callback one by one.
105228 */
105229 if( pOrderBy ){
105230 explainTempTable(pParse, "ORDER BY");
105231 generateSortTail(pParse, p, v, pEList->nExpr, pDest);
105232 }
105233
105234 /* Jump here to skip this query
105235 */
105236 sqlite3VdbeResolveLabel(v, iEnd);
@@ -109064,11 +109403,11 @@
109064 Index *pIndex; /* Index used, or NULL */
109065 } btree;
109066 struct { /* Information for virtual tables */
109067 int idxNum; /* Index number */
109068 u8 needFree; /* True if sqlite3_free(idxStr) is needed */
109069 u8 isOrdered; /* True if satisfies ORDER BY */
109070 u16 omitMask; /* Terms that may be omitted */
109071 char *idxStr; /* Index identifier string */
109072 } vtab;
109073 } u;
109074 u32 wsFlags; /* WHERE_* flags describing the plan */
@@ -109126,12 +109465,11 @@
109126 struct WherePath {
109127 Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
109128 Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
109129 LogEst nRow; /* Estimated number of rows generated by this path */
109130 LogEst rCost; /* Total cost of this path */
109131 u8 isOrdered; /* True if this path satisfies ORDER BY */
109132 u8 isOrderedValid; /* True if the isOrdered field is valid */
109133 WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
109134 };
109135
109136 /*
109137 ** The query generator uses an array of instances of this structure to
@@ -109341,11 +109679,11 @@
109341 ExprList *pResultSet; /* Result set. DISTINCT operates on these */
109342 WhereLoop *pLoops; /* List of all WhereLoop objects */
109343 Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
109344 LogEst nRowOut; /* Estimated number of output rows */
109345 u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
109346 u8 bOBSat; /* ORDER BY satisfied by indices */
109347 u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
109348 u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
109349 u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
109350 u8 nLevel; /* Number of nested loop */
109351 int iTop; /* The very beginning of the WHERE loop */
@@ -109425,18 +109763,19 @@
109425 /*
109426 ** Return TRUE if the WHERE clause returns rows in ORDER BY order.
109427 ** Return FALSE if the output needs to be sorted.
109428 */
109429 SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
109430 return pWInfo->bOBSat!=0;
109431 }
109432
109433 /*
109434 ** Return the VDBE address or label to jump to in order to continue
109435 ** immediately with the next row of a WHERE clause.
109436 */
109437 SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
 
109438 return pWInfo->iContinue;
109439 }
109440
109441 /*
109442 ** Return the VDBE address or label to jump to in order to break
@@ -112226,11 +112565,11 @@
112226 }
112227 pLevel->op = OP_VNext;
112228 pLevel->p1 = iCur;
112229 pLevel->p2 = sqlite3VdbeCurrentAddr(v);
112230 sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
112231 sqlite3ExprCachePop(pParse, 1);
112232 }else
112233 #endif /* SQLITE_OMIT_VIRTUALTABLE */
112234
112235 if( (pLoop->wsFlags & WHERE_IPK)!=0
112236 && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
@@ -112422,12 +112761,15 @@
112422 ** a single iteration. This means that the first row returned
112423 ** should not have a NULL value stored in 'x'. If column 'x' is
112424 ** the first one after the nEq equality constraints in the index,
112425 ** this requires some special handling.
112426 */
 
 
 
112427 if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
112428 && (pWInfo->bOBSat!=0)
112429 && (pIdx->nKeyCol>nEq)
112430 ){
112431 assert( pLoop->u.btree.nSkip==0 );
112432 bSeekPastNull = 1;
112433 nExtraReg = 1;
@@ -112594,12 +112936,11 @@
112594 pLevel->op = OP_Prev;
112595 }else{
112596 pLevel->op = OP_Next;
112597 }
112598 pLevel->p1 = iIdxCur;
112599 assert( (WHERE_UNQ_WANTED>>16)==1 );
112600 pLevel->p3 = (pLoop->wsFlags>>16)&1;
112601 if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
112602 pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
112603 }else{
112604 assert( pLevel->p5==0 );
112605 }
@@ -113093,10 +113434,141 @@
113093 whereLoopDelete(db, p);
113094 }
113095 sqlite3DbFree(db, pWInfo);
113096 }
113097 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113098
113099 /*
113100 ** Insert or replace a WhereLoop entry using the template supplied.
113101 **
113102 ** An existing WhereLoop entry might be overwritten if the new template
@@ -113103,29 +113575,27 @@
113103 ** is better and has fewer dependencies. Or the template will be ignored
113104 ** and no insert will occur if an existing WhereLoop is faster and has
113105 ** fewer dependencies than the template. Otherwise a new WhereLoop is
113106 ** added based on the template.
113107 **
113108 ** If pBuilder->pOrSet is not NULL then we only care about only the
113109 ** prerequisites and rRun and nOut costs of the N best loops. That
113110 ** information is gathered in the pBuilder->pOrSet object. This special
113111 ** processing mode is used only for OR clause processing.
113112 **
113113 ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
113114 ** still might overwrite similar loops with the new template if the
113115 ** template is better. Loops may be overwritten if the following
113116 ** conditions are met:
113117 **
113118 ** (1) They have the same iTab.
113119 ** (2) They have the same iSortIdx.
113120 ** (3) The template has same or fewer dependencies than the current loop
113121 ** (4) The template has the same or lower cost than the current loop
113122 ** (5) The template uses more terms of the same index but has no additional
113123 ** dependencies
113124 */
113125 static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
113126 WhereLoop **ppPrev, *p, *pNext = 0;
113127 WhereInfo *pWInfo = pBuilder->pWInfo;
113128 sqlite3 *db = pWInfo->pParse->db;
113129
113130 /* If pBuilder->pOrSet is defined, then only keep track of the costs
113131 ** and prereqs.
@@ -113144,68 +113614,27 @@
113144 }
113145 #endif
113146 return SQLITE_OK;
113147 }
113148
113149 /* Search for an existing WhereLoop to overwrite, or which takes
113150 ** priority over pTemplate.
113151 */
113152 for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){
113153 if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
113154 /* If either the iTab or iSortIdx values for two WhereLoop are different
113155 ** then those WhereLoops need to be considered separately. Neither is
113156 ** a candidate to replace the other. */
113157 continue;
113158 }
113159 /* In the current implementation, the rSetup value is either zero
113160 ** or the cost of building an automatic index (NlogN) and the NlogN
113161 ** is the same for compatible WhereLoops. */
113162 assert( p->rSetup==0 || pTemplate->rSetup==0
113163 || p->rSetup==pTemplate->rSetup );
113164
113165 /* whereLoopAddBtree() always generates and inserts the automatic index
113166 ** case first. Hence compatible candidate WhereLoops never have a larger
113167 ** rSetup. Call this SETUP-INVARIANT */
113168 assert( p->rSetup>=pTemplate->rSetup );
113169
113170 if( (p->prereq & pTemplate->prereq)==p->prereq
113171 && p->rSetup<=pTemplate->rSetup
113172 && p->rRun<=pTemplate->rRun
113173 && p->nOut<=pTemplate->nOut
113174 ){
113175 /* This branch taken when p is equal or better than pTemplate in
113176 ** all of (1) dependencies (2) setup-cost, (3) run-cost, and
113177 ** (4) number of output rows. */
113178 assert( p->rSetup==pTemplate->rSetup );
113179 if( p->prereq==pTemplate->prereq
113180 && p->nLTerm<pTemplate->nLTerm
113181 && (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0
113182 && (p->u.btree.pIndex==pTemplate->u.btree.pIndex
113183 || pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm)
113184 ){
113185 /* Overwrite an existing WhereLoop with an similar one that uses
113186 ** more terms of the index */
113187 pNext = p->pNextLoop;
113188 break;
113189 }else{
113190 /* pTemplate is not helpful.
113191 ** Return without changing or adding anything */
113192 goto whereLoopInsert_noop;
113193 }
113194 }
113195 if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
113196 && p->rRun>=pTemplate->rRun
113197 && p->nOut>=pTemplate->nOut
113198 ){
113199 /* Overwrite an existing WhereLoop with a better one: one that is
113200 ** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
113201 ** or (4) number of output rows, and is no worse in any of those
113202 ** categories. */
113203 assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
113204 pNext = p->pNextLoop;
113205 break;
113206 }
113207 }
113208
113209 /* If we reach this point it means that either p[] should be overwritten
113210 ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
113211 ** WhereLoop and insert it.
@@ -113219,34 +113648,44 @@
113219 sqlite3DebugPrintf("ins-new: ");
113220 whereLoopPrint(pTemplate, pBuilder->pWC);
113221 }
113222 #endif
113223 if( p==0 ){
113224 p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
 
113225 if( p==0 ) return SQLITE_NOMEM;
113226 whereLoopInit(p);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113227 }
113228 whereLoopXfer(db, p, pTemplate);
113229 p->pNextLoop = pNext;
113230 *ppPrev = p;
113231 if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
113232 Index *pIndex = p->u.btree.pIndex;
113233 if( pIndex && pIndex->tnum==0 ){
113234 p->u.btree.pIndex = 0;
113235 }
113236 }
113237 return SQLITE_OK;
113238
113239 /* Jump here if the insert is a no-op */
113240 whereLoopInsert_noop:
113241 #if WHERETRACE_ENABLED /* 0x8 */
113242 if( sqlite3WhereTrace & 0x8 ){
113243 sqlite3DebugPrintf("ins-noop: ");
113244 whereLoopPrint(pTemplate, pBuilder->pWC);
113245 }
113246 #endif
113247 return SQLITE_OK;
113248 }
113249
113250 /*
113251 ** Adjust the WhereLoop.nOut value downward to account for terms of the
113252 ** WHERE clause that reference the loop but which are not used by an
@@ -113396,10 +113835,12 @@
113396 nIn = 46; assert( 46==sqlite3LogEst(25) );
113397 }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
113398 /* "x IN (value, value, ...)" */
113399 nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
113400 }
 
 
113401 pNew->rRun += nIn;
113402 pNew->u.btree.nEq++;
113403 pNew->nOut = nRowEst + nInMul + nIn;
113404 }else if( pTerm->eOperator & (WO_EQ) ){
113405 assert(
@@ -113709,22 +114150,38 @@
113709 && sqlite3GlobalConfig.bUseCis
113710 && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
113711 )
113712 ){
113713 pNew->iSortIdx = b ? iSortIdx : 0;
 
 
 
 
113714 if( m==0 ){
113715 /* TUNING: Cost of a covering index scan is K*(N + log2(N)).
113716 ** + The extra factor K of between 1.1 and 3.0 that depends
113717 ** on the relative sizes of the table and the index. K
113718 ** is smaller for smaller indices, thus favoring them.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113719 */
113720 pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
113721 (15*pProbe->szIdxRow)/pTab->szTabRow;
113722 }else{
113723 /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
113724 ** which we will simplify to just N*log2(N) */
113725 pNew->rRun = rSize + rLogSize;
113726 }
113727 whereLoopOutputAdjust(pWC, pNew);
113728 rc = whereLoopInsert(pBuilder, pNew);
113729 pNew->nOut = rSize;
113730 if( rc ) break;
@@ -113892,12 +114349,12 @@
113892 assert( pNew->nLTerm<=pNew->nLSlot );
113893 pNew->u.vtab.idxNum = pIdxInfo->idxNum;
113894 pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
113895 pIdxInfo->needToFreeIdxStr = 0;
113896 pNew->u.vtab.idxStr = pIdxInfo->idxStr;
113897 pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
113898 && pIdxInfo->orderByConsumed);
113899 pNew->rSetup = 0;
113900 pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
113901 pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
113902 whereLoopInsert(pBuilder, pNew);
113903 if( pNew->u.vtab.needFree ){
@@ -114054,25 +114511,25 @@
114054 }
114055
114056 /*
114057 ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
114058 ** parameters) to see if it outputs rows in the requested ORDER BY
114059 ** (or GROUP BY) without requiring a separate sort operation. Return:
114060 **
114061 ** 0: ORDER BY is not satisfied. Sorting required
114062 ** 1: ORDER BY is satisfied. Omit sorting
114063 ** -1: Unknown at this time
114064 **
114065 ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
114066 ** strict. With GROUP BY and DISTINCT the only requirement is that
114067 ** equivalent rows appear immediately adjacent to one another. GROUP BY
114068 ** and DISTINT do not require rows to appear in any particular order as long
114069 ** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT
114070 ** the pOrderBy terms can be matched in any order. With ORDER BY, the
114071 ** pOrderBy terms must be matched in strict left-to-right order.
114072 */
114073 static int wherePathSatisfiesOrderBy(
114074 WhereInfo *pWInfo, /* The WHERE clause */
114075 ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
114076 WherePath *pPath, /* The WherePath to check */
114077 u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
114078 u16 nLoop, /* Number of entries in pPath->aLoop[] */
@@ -114252,28 +114709,28 @@
114252 if( !pColl ) pColl = db->pDfltColl;
114253 if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
114254 }
114255 isMatch = 1;
114256 break;
 
 
 
 
 
 
 
 
 
 
 
114257 }
114258 if( isMatch ){
114259 if( iColumn<0 ){
114260 testcase( distinctColumns==0 );
114261 distinctColumns = 1;
114262 }
114263 obSat |= MASKBIT(i);
114264 if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
114265 /* Make sure the sort order is compatible in an ORDER BY clause.
114266 ** Sort order is irrelevant for a GROUP BY clause. */
114267 if( revSet ){
114268 if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0;
114269 }else{
114270 rev = revIdx ^ pOrderBy->a[i].sortOrder;
114271 if( rev ) *pRevMask |= MASKBIT(iLoop);
114272 revSet = 1;
114273 }
114274 }
114275 }else{
114276 /* No match found */
114277 if( j==0 || j<nKeyCol ){
114278 testcase( isOrderDistinct!=0 );
114279 isOrderDistinct = 0;
@@ -114301,12 +114758,18 @@
114301 obSat |= MASKBIT(i);
114302 }
114303 }
114304 }
114305 } /* End the loop over all WhereLoops from outer-most down to inner-most */
114306 if( obSat==obDone ) return 1;
114307 if( !isOrderDistinct ) return 0;
 
 
 
 
 
 
114308 return -1;
114309 }
114310
114311 #ifdef WHERETRACE_ENABLED
114312 /* For debugging use only: */
@@ -114339,15 +114802,15 @@
114339 Parse *pParse; /* Parsing context */
114340 sqlite3 *db; /* The database connection */
114341 int iLoop; /* Loop counter over the terms of the join */
114342 int ii, jj; /* Loop counters */
114343 int mxI = 0; /* Index of next entry to replace */
 
114344 LogEst rCost; /* Cost of a path */
114345 LogEst nOut; /* Number of outputs */
114346 LogEst mxCost = 0; /* Maximum cost of a set of paths */
114347 LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
114348 LogEst rSortCost; /* Cost to do a sort */
114349 int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
114350 WherePath *aFrom; /* All nFrom paths at the previous level */
114351 WherePath *aTo; /* The nTo best paths at the current level */
114352 WherePath *pFrom; /* An element of aFrom[] that we are working on */
114353 WherePath *pTo; /* An element of aTo[] that we are working on */
@@ -114385,20 +114848,16 @@
114385 aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
114386 nFrom = 1;
114387
114388 /* Precompute the cost of sorting the final result set, if the caller
114389 ** to sqlite3WhereBegin() was concerned about sorting */
114390 rSortCost = 0;
114391 if( pWInfo->pOrderBy==0 || nRowEst==0 ){
114392 aFrom[0].isOrderedValid = 1;
 
114393 }else{
114394 /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
114395 ** number of output rows. The 48 is the expected size of a row to sort.
114396 ** FIXME: compute a better estimate of the 48 multiplier based on the
114397 ** result set expressions. */
114398 rSortCost = nRowEst + estLog(nRowEst);
114399 WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
114400 }
114401
114402 /* Compute successively longer WherePaths using the previous generation
114403 ** of WherePaths as the basis for the next. Keep track of the mxChoice
114404 ** best paths at each generation */
@@ -114406,43 +114865,56 @@
114406 nTo = 0;
114407 for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
114408 for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
114409 Bitmask maskNew;
114410 Bitmask revMask = 0;
114411 u8 isOrderedValid = pFrom->isOrderedValid;
114412 u8 isOrdered = pFrom->isOrdered;
114413 if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
114414 if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
114415 /* At this point, pWLoop is a candidate to be the next loop.
114416 ** Compute its cost */
114417 rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
114418 rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
114419 nOut = pFrom->nRow + pWLoop->nOut;
114420 maskNew = pFrom->maskLoop | pWLoop->maskSelf;
114421 if( !isOrderedValid ){
114422 switch( wherePathSatisfiesOrderBy(pWInfo,
114423 pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
114424 iLoop, pWLoop, &revMask) ){
114425 case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */
114426 isOrdered = 1;
114427 isOrderedValid = 1;
114428 break;
114429 case 0: /* No. pFrom+pWLoop will require a separate sort */
114430 isOrdered = 0;
114431 isOrderedValid = 1;
114432 rCost = sqlite3LogEstAdd(rCost, rSortCost);
114433 break;
114434 default: /* Cannot tell yet. Try again on the next iteration */
114435 break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114436 }
114437 }else{
114438 revMask = pFrom->revLoop;
114439 }
114440 /* Check to see if pWLoop should be added to the mxChoice best so far */
114441 for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
114442 if( pTo->maskLoop==maskNew
114443 && pTo->isOrderedValid==isOrderedValid
114444 && ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
114445 (pTo->rCost>=rCost && pTo->nRow>=nOut))
114446 ){
114447 testcase( jj==nTo-1 );
114448 break;
@@ -114452,11 +114924,11 @@
114452 if( nTo>=mxChoice && rCost>=mxCost ){
114453 #ifdef WHERETRACE_ENABLED /* 0x4 */
114454 if( sqlite3WhereTrace&0x4 ){
114455 sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
114456 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114457 isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114458 }
114459 #endif
114460 continue;
114461 }
114462 /* Add a new Path to the aTo[] set */
@@ -114470,24 +114942,24 @@
114470 pTo = &aTo[jj];
114471 #ifdef WHERETRACE_ENABLED /* 0x4 */
114472 if( sqlite3WhereTrace&0x4 ){
114473 sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
114474 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114475 isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114476 }
114477 #endif
114478 }else{
114479 if( pTo->rCost<=rCost && pTo->nRow<=nOut ){
114480 #ifdef WHERETRACE_ENABLED /* 0x4 */
114481 if( sqlite3WhereTrace&0x4 ){
114482 sqlite3DebugPrintf(
114483 "Skip %s cost=%-3d,%3d order=%c",
114484 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114485 isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114486 sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
114487 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114488 pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
114489 }
114490 #endif
114491 testcase( pTo->rCost==rCost );
114492 continue;
114493 }
@@ -114496,23 +114968,22 @@
114496 #ifdef WHERETRACE_ENABLED /* 0x4 */
114497 if( sqlite3WhereTrace&0x4 ){
114498 sqlite3DebugPrintf(
114499 "Update %s cost=%-3d,%3d order=%c",
114500 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114501 isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
114502 sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
114503 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114504 pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
114505 }
114506 #endif
114507 }
114508 /* pWLoop is a winner. Add it to the set of best so far */
114509 pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
114510 pTo->revLoop = revMask;
114511 pTo->nRow = nOut;
114512 pTo->rCost = rCost;
114513 pTo->isOrderedValid = isOrderedValid;
114514 pTo->isOrdered = isOrdered;
114515 memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
114516 pTo->aLoop[iLoop] = pWLoop;
114517 if( nTo>=mxChoice ){
114518 mxI = 0;
@@ -114533,12 +115004,12 @@
114533 if( sqlite3WhereTrace>=2 ){
114534 sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
114535 for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
114536 sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
114537 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114538 pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
114539 if( pTo->isOrderedValid && pTo->isOrdered ){
114540 sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
114541 }else{
114542 sqlite3DebugPrintf("\n");
114543 }
114544 }
@@ -114577,17 +115048,22 @@
114577 && nRowEst
114578 ){
114579 Bitmask notUsed;
114580 int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
114581 WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
114582 if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
 
 
114583 }
114584 if( pFrom->isOrdered ){
114585 if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
114586 pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
 
 
114587 }else{
114588 pWInfo->bOBSat = 1;
 
114589 pWInfo->revMask = pFrom->revLoop;
114590 }
114591 }
114592 pWInfo->nRowOut = pFrom->nRow;
114593
@@ -114668,11 +115144,11 @@
114668 pLoop->nOut = (LogEst)1;
114669 pWInfo->a[0].pWLoop = pLoop;
114670 pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
114671 pWInfo->a[0].iTabCur = iCur;
114672 pWInfo->nRowOut = 1;
114673 if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
114674 if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
114675 pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
114676 }
114677 #ifdef SQLITE_DEBUG
114678 pLoop->cId = '0';
@@ -114772,11 +115248,11 @@
114772 */
114773 SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
114774 Parse *pParse, /* The parser context */
114775 SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
114776 Expr *pWhere, /* The WHERE clause */
114777 ExprList *pOrderBy, /* An ORDER BY clause, or NULL */
114778 ExprList *pResultSet, /* Result set of the query */
114779 u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
114780 int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
114781 ){
114782 int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
@@ -114794,10 +115270,14 @@
114794
114795
114796 /* Variable initialization */
114797 db = pParse->db;
114798 memset(&sWLB, 0, sizeof(sWLB));
 
 
 
 
114799 sWLB.pOrderBy = pOrderBy;
114800
114801 /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
114802 ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
114803 if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
@@ -114838,11 +115318,11 @@
114838 pWInfo->nLevel = nTabList;
114839 pWInfo->pParse = pParse;
114840 pWInfo->pTabList = pTabList;
114841 pWInfo->pOrderBy = pOrderBy;
114842 pWInfo->pResultSet = pResultSet;
114843 pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
114844 pWInfo->wctrlFlags = wctrlFlags;
114845 pWInfo->savedNQueryLoop = pParse->nQueryLoop;
114846 pMaskSet = &pWInfo->sMaskSet;
114847 sWLB.pWInfo = pWInfo;
114848 sWLB.pWC = &pWInfo->sWC;
@@ -114872,11 +115352,11 @@
114872 }
114873
114874 /* Special case: No FROM clause
114875 */
114876 if( nTabList==0 ){
114877 if( pOrderBy ) pWInfo->bOBSat = 1;
114878 if( wctrlFlags & WHERE_WANT_DISTINCT ){
114879 pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
114880 }
114881 }
114882
@@ -114983,12 +115463,12 @@
114983 }
114984 #ifdef WHERETRACE_ENABLED /* !=0 */
114985 if( sqlite3WhereTrace ){
114986 int ii;
114987 sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
114988 if( pWInfo->bOBSat ){
114989 sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask);
114990 }
114991 switch( pWInfo->eDistinct ){
114992 case WHERE_DISTINCT_UNIQUE: {
114993 sqlite3DebugPrintf(" DISTINCT=unique");
114994 break;
@@ -115266,11 +115746,11 @@
115266 k = pLevel->addrBody;
115267 pOp = sqlite3VdbeGetOp(v, k);
115268 for(; k<last; k++, pOp++){
115269 if( pOp->p1!=pLevel->iTabCur ) continue;
115270 if( pOp->opcode==OP_Column ){
115271 pOp->opcode = OP_SCopy;
115272 pOp->p1 = pOp->p2 + pTabItem->regResult;
115273 pOp->p2 = pOp->p3;
115274 pOp->p3 = 0;
115275 }else if( pOp->opcode==OP_Rowid ){
115276 pOp->opcode = OP_Null;
@@ -118214,10 +118694,37 @@
118214 ** simplify to constants 0 (false) and 1 (true), respectively,
118215 ** regardless of the value of expr1.
118216 */
118217 yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]);
118218 sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118219 }else{
118220 yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
118221 if( yygotominor.yy346.pExpr ){
118222 yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
118223 sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
@@ -120834,10 +121341,11 @@
120834 Table *pTab = (Table *)sqliteHashData(p);
120835 if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
120836 }
120837 }
120838 }
 
120839 sqlite3BtreeLeaveAll(db);
120840 #else
120841 UNUSED_PARAMETER(db);
120842 #endif
120843 }
@@ -123237,10 +123745,26 @@
123237 case SQLITE_TESTCTRL_ALWAYS: {
123238 int x = va_arg(ap,int);
123239 rc = ALWAYS(x);
123240 break;
123241 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123242
123243 /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
123244 **
123245 ** Set the nReserve size to N for the main database on the database
123246 ** connection db.
@@ -124573,11 +125097,11 @@
124573 char *zReadExprlist;
124574 char *zWriteExprlist;
124575
124576 int nNodeSize; /* Soft limit for node size */
124577 u8 bFts4; /* True for FTS4, false for FTS3 */
124578 u8 bHasStat; /* True if %_stat table exists */
124579 u8 bHasDocsize; /* True if %_docsize table exists */
124580 u8 bDescIdx; /* True if doclists are in reverse order */
124581 u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
124582 int nPgsz; /* Page size for host database */
124583 char *zSegmentsTbl; /* Name of %_segments table */
@@ -126065,14 +126589,11 @@
126065
126066 /* Check to see if a legacy fts3 table has been "upgraded" by the
126067 ** addition of a %_stat table so that it can use incremental merge.
126068 */
126069 if( !isFts4 && !isCreate ){
126070 int rc2 = SQLITE_OK;
126071 fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
126072 p->zDb, p->zName);
126073 if( rc2==SQLITE_OK ) p->bHasStat = 1;
126074 }
126075
126076 /* Figure out the page-size for the database. This is required in order to
126077 ** estimate the cost of loading large doclists from the database. */
126078 fts3DatabasePageSize(&rc, p);
@@ -127975,11 +128496,38 @@
127975 sqlite3Fts3SegmentsClose(p);
127976 return rc;
127977 }
127978
127979 /*
127980 ** Implementation of xBegin() method. This is a no-op.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127981 */
127982 static int fts3BeginMethod(sqlite3_vtab *pVtab){
127983 Fts3Table *p = (Fts3Table*)pVtab;
127984 UNUSED_PARAMETER(pVtab);
127985 assert( p->pSegments==0 );
@@ -127986,11 +128534,11 @@
127986 assert( p->nPendingData==0 );
127987 assert( p->inTransaction!=1 );
127988 TESTONLY( p->inTransaction = 1 );
127989 TESTONLY( p->mxSavepoint = -1; );
127990 p->nLeafAdd = 0;
127991 return SQLITE_OK;
127992 }
127993
127994 /*
127995 ** Implementation of xCommit() method. This is a no-op. The contents of
127996 ** the pending-terms hash-table have already been flushed into the database
@@ -128235,18 +128783,24 @@
128235 ){
128236 Fts3Table *p = (Fts3Table *)pVtab;
128237 sqlite3 *db = p->db; /* Database connection */
128238 int rc; /* Return Code */
128239
 
 
 
 
128240 /* As it happens, the pending terms table is always empty here. This is
128241 ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
128242 ** always opens a savepoint transaction. And the xSavepoint() method
128243 ** flushes the pending terms table. But leave the (no-op) call to
128244 ** PendingTermsFlush() in in case that changes.
128245 */
128246 assert( p->nPendingData==0 );
128247 rc = sqlite3Fts3PendingTermsFlush(p);
 
 
128248
128249 if( p->zContentTbl==0 ){
128250 fts3DbExec(&rc, db,
128251 "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
128252 p->zDb, p->zName, zName
@@ -139754,10 +140308,14 @@
139754 u32 *aSzIns = 0; /* Sizes of inserted documents */
139755 u32 *aSzDel = 0; /* Sizes of deleted documents */
139756 int nChng = 0; /* Net change in number of documents */
139757 int bInsertDone = 0;
139758
 
 
 
 
139759 assert( p->pSegments==0 );
139760 assert(
139761 nArg==1 /* DELETE operations */
139762 || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
139763 );
@@ -145135,30 +145693,36 @@
145135 ** This function populates the pRtree->nRowEst variable with an estimate
145136 ** of the number of rows in the virtual table. If possible, this is based
145137 ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
145138 */
145139 static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
145140 const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'";
 
145141 sqlite3_stmt *p;
145142 int rc;
145143 i64 nRow = 0;
145144
145145 rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
145146 if( rc==SQLITE_OK ){
145147 sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC);
145148 if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
145149 rc = sqlite3_finalize(p);
145150 }else if( rc!=SQLITE_NOMEM ){
145151 rc = SQLITE_OK;
145152 }
145153
145154 if( rc==SQLITE_OK ){
145155 if( nRow==0 ){
145156 pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
145157 }else{
145158 pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
145159 }
 
 
 
 
 
145160 }
145161
145162 return rc;
145163 }
145164
@@ -145423,10 +145987,12 @@
145423 }
145424
145425 if( rc==SQLITE_OK ){
145426 *ppVtab = (sqlite3_vtab *)pRtree;
145427 }else{
 
 
145428 rtreeRelease(pRtree);
145429 }
145430 return rc;
145431 }
145432
145433
--- 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.8.5. 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.
@@ -220,13 +220,13 @@
220 **
221 ** See also: [sqlite3_libversion()],
222 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
223 ** [sqlite_version()] and [sqlite_source_id()].
224 */
225 #define SQLITE_VERSION "3.8.5"
226 #define SQLITE_VERSION_NUMBER 3008005
227 #define SQLITE_SOURCE_ID "2014-04-18 22:20:31 9a5d38c79d2482a23bcfbc3ff35ca4fa269c768d"
228
229 /*
230 ** CAPI3REF: Run-Time Library Version Numbers
231 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
232 **
@@ -6236,11 +6236,12 @@
6236 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17
6237 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
6238 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19
6239 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20
6240 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21
6241 #define SQLITE_TESTCTRL_BYTEORDER 22
6242 #define SQLITE_TESTCTRL_LAST 22
6243
6244 /*
6245 ** CAPI3REF: SQLite Runtime Status
6246 **
6247 ** ^This interface is used to retrieve runtime status information
@@ -8437,26 +8438,43 @@
8438 */
8439 typedef INT16_TYPE LogEst;
8440
8441 /*
8442 ** Macros to determine whether the machine is big or little endian,
8443 ** and whether or not that determination is run-time or compile-time.
8444 **
8445 ** For best performance, an attempt is made to guess at the byte-order
8446 ** using C-preprocessor macros. If that is unsuccessful, or if
8447 ** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
8448 ** at run-time.
8449 */
8450 #ifdef SQLITE_AMALGAMATION
8451 SQLITE_PRIVATE const int sqlite3one = 1;
8452 #else
8453 SQLITE_PRIVATE const int sqlite3one;
8454 #endif
8455 #if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
8456 defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
8457 defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
8458 defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
8459 # define SQLITE_BYTEORDER 1234
8460 # define SQLITE_BIGENDIAN 0
8461 # define SQLITE_LITTLEENDIAN 1
8462 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE
8463 #endif
8464 #if (defined(sparc) || defined(__ppc__)) \
8465 && !defined(SQLITE_RUNTIME_BYTEORDER)
8466 # define SQLITE_BYTEORDER 4321
8467 # define SQLITE_BIGENDIAN 1
8468 # define SQLITE_LITTLEENDIAN 0
8469 # define SQLITE_UTF16NATIVE SQLITE_UTF16BE
8470 #endif
8471 #if !defined(SQLITE_BYTEORDER)
8472 # define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
8473 # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
8474 # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
8475 # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
8476 #endif
8477
8478 /*
8479 ** Constants for the largest and smallest possible 64-bit signed integers.
8480 ** These macros are designed to work correctly on both 32-bit and 64-bit
@@ -8767,11 +8785,13 @@
8785 #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */
8786 #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */
8787
8788 SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
8789 SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
8790 #if SQLITE_MAX_MMAP_SIZE>0
8791 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
8792 #endif
8793 SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
8794 SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
8795 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
8796 SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
8797 SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
@@ -8817,10 +8837,11 @@
8837 #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
8838 #define BTREE_BLOBKEY 2 /* Table has keys only - no data */
8839
8840 SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
8841 SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
8842 SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*);
8843 SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
8844
8845 SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
8846 SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
8847
@@ -8891,11 +8912,11 @@
8912
8913 SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
8914 SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
8915
8916 SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
8917 SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
8918 SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
8919 SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
8920 SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
8921
8922 #ifndef NDEBUG
@@ -9134,11 +9155,11 @@
9155 #define OP_Next 9
9156 #define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */
9157 #define OP_Checkpoint 11
9158 #define OP_JournalMode 12
9159 #define OP_Vacuum 13
9160 #define OP_VFilter 14 /* synopsis: iplan=r[P3] zplan='P4' */
9161 #define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */
9162 #define OP_Goto 16
9163 #define OP_Gosub 17
9164 #define OP_Return 18
9165 #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
@@ -9161,11 +9182,11 @@
9182 #define OP_CollSeq 36
9183 #define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */
9184 #define OP_MustBeInt 38
9185 #define OP_RealAffinity 39
9186 #define OP_Permutation 40
9187 #define OP_Compare 41 /* synopsis: r[P1@P3] <-> r[P2@P3] */
9188 #define OP_Jump 42
9189 #define OP_Once 43
9190 #define OP_If 44
9191 #define OP_IfNot 45
9192 #define OP_Column 46 /* synopsis: r[P3]=PX */
@@ -9188,11 +9209,11 @@
9209 #define OP_Seek 63 /* synopsis: intkey=r[P2] */
9210 #define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */
9211 #define OP_NotFound 65 /* synopsis: key=r[P3@P4] */
9212 #define OP_Found 66 /* synopsis: key=r[P3@P4] */
9213 #define OP_NotExists 67 /* synopsis: intkey=r[P3] */
9214 #define OP_Sequence 68 /* synopsis: r[P2]=cursor[P1].ctr++ */
9215 #define OP_NewRowid 69 /* synopsis: r[P2]=rowid */
9216 #define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */
9217 #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
9218 #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
9219 #define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */
@@ -9236,51 +9257,52 @@
9257 #define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */
9258 #define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */
9259 #define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */
9260 #define OP_Destroy 114
9261 #define OP_Clear 115
9262 #define OP_ResetSorter 116
9263 #define OP_CreateIndex 117 /* synopsis: r[P2]=root iDb=P1 */
9264 #define OP_CreateTable 118 /* synopsis: r[P2]=root iDb=P1 */
9265 #define OP_ParseSchema 119
9266 #define OP_LoadAnalysis 120
9267 #define OP_DropTable 121
9268 #define OP_DropIndex 122
9269 #define OP_DropTrigger 123
9270 #define OP_IntegrityCk 124
9271 #define OP_RowSetAdd 125 /* synopsis: rowset(P1)=r[P2] */
9272 #define OP_RowSetRead 126 /* synopsis: r[P3]=rowset(P1) */
9273 #define OP_RowSetTest 127 /* synopsis: if r[P3] in rowset(P1) goto P2 */
9274 #define OP_Program 128
9275 #define OP_Param 129
9276 #define OP_FkCounter 130 /* synopsis: fkctr[P1]+=P2 */
9277 #define OP_FkIfZero 131 /* synopsis: if fkctr[P1]==0 goto P2 */
9278 #define OP_MemMax 132 /* synopsis: r[P1]=max(r[P1],r[P2]) */
9279 #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
9280 #define OP_IfPos 134 /* synopsis: if r[P1]>0 goto P2 */
9281 #define OP_IfNeg 135 /* synopsis: if r[P1]<0 goto P2 */
9282 #define OP_IfZero 136 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
9283 #define OP_AggFinal 137 /* synopsis: accum=r[P1] N=P2 */
9284 #define OP_IncrVacuum 138
9285 #define OP_Expire 139
9286 #define OP_TableLock 140 /* synopsis: iDb=P1 root=P2 write=P3 */
9287 #define OP_VBegin 141
9288 #define OP_VCreate 142
9289 #define OP_ToText 143 /* same as TK_TO_TEXT */
9290 #define OP_ToBlob 144 /* same as TK_TO_BLOB */
9291 #define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */
9292 #define OP_ToInt 146 /* same as TK_TO_INT */
9293 #define OP_ToReal 147 /* same as TK_TO_REAL */
9294 #define OP_VDestroy 148
9295 #define OP_VOpen 149
9296 #define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */
9297 #define OP_VNext 151
9298 #define OP_VRename 152
9299 #define OP_Pagecount 153
9300 #define OP_MaxPgcnt 154
9301 #define OP_Init 155 /* synopsis: Start at P2 */
9302 #define OP_Noop 156
9303 #define OP_Explain 157
9304
9305
9306 /* Properties such as "out2" or "jump" that are specified in
9307 ** comments following the "case" for each opcode in the vdbe.c
9308 ** are encoded into bitvectors as follows:
@@ -9305,16 +9327,16 @@
9327 /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\
9328 /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\
9329 /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\
9330 /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
9331 /* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\
9332 /* 112 */ 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00,\
9333 /* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15,\
9334 /* 128 */ 0x01, 0x02, 0x00, 0x01, 0x08, 0x02, 0x05, 0x05,\
9335 /* 136 */ 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,\
9336 /* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x01,\
9337 /* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,}
9338
9339 /************** End of opcodes.h *********************************************/
9340 /************** Continuing where we left off in vdbe.h ***********************/
9341
9342 /*
@@ -9367,14 +9389,14 @@
9389 #ifndef SQLITE_OMIT_TRACE
9390 SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
9391 #endif
9392
9393 SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
9394 SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
9395 SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
9396
9397 typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
9398 SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
9399
9400 #ifndef SQLITE_OMIT_TRIGGER
9401 SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
9402 #endif
@@ -10996,10 +11018,11 @@
11018 */
11019 struct UnpackedRecord {
11020 KeyInfo *pKeyInfo; /* Collation and sort-order information */
11021 u16 nField; /* Number of entries in apMem[] */
11022 i8 default_rc; /* Comparison result if keys are equal */
11023 u8 isCorrupt; /* Corruption detected by xRecordCompare() */
11024 Mem *aMem; /* Values */
11025 int r1; /* Value to return if (lhs > rhs) */
11026 int r2; /* Value to return if (rhs < lhs) */
11027 };
11028
@@ -11262,12 +11285,12 @@
11285 #define EP_Error 0x000008 /* Expression contains one or more errors */
11286 #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
11287 #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
11288 #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
11289 #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
11290 #define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
11291 #define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
11292 #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
11293 #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
11294 #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
11295 #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
11296 #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
@@ -11327,11 +11350,10 @@
11350 ** of the result column in the form: DATABASE.TABLE.COLUMN. This later
11351 ** form is used for name resolution with nested FROM clauses.
11352 */
11353 struct ExprList {
11354 int nExpr; /* Number of expressions on the list */
 
11355 struct ExprList_item { /* For each expression in the list */
11356 Expr *pExpr; /* The list of expressions */
11357 char *zName; /* Token associated with this expression */
11358 char *zSpan; /* Original text of the expression */
11359 u8 sortOrder; /* 1 for DESC or 0 for ASC */
@@ -11551,11 +11573,11 @@
11573 struct Select {
11574 ExprList *pEList; /* The fields of the result */
11575 u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
11576 u16 selFlags; /* Various SF_* values */
11577 int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
11578 int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
11579 u64 nSelectRow; /* Estimated number of result rows */
11580 SrcList *pSrc; /* The FROM clause */
11581 Expr *pWhere; /* The WHERE clause */
11582 ExprList *pGroupBy; /* The GROUP BY clause */
11583 Expr *pHaving; /* The HAVING clause */
@@ -11575,13 +11597,13 @@
11597 #define SF_Resolved 0x0002 /* Identifiers have been resolved */
11598 #define SF_Aggregate 0x0004 /* Contains aggregate functions */
11599 #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
11600 #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
11601 #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
11602 /* 0x0040 NOT USED */
11603 #define SF_Values 0x0080 /* Synthesized from VALUES clause */
11604 /* 0x0100 NOT USED */
11605 #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
11606 #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
11607 #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
11608 #define SF_Compound 0x1000 /* Part of a compound query */
11609
@@ -11630,17 +11652,19 @@
11652 ** of the co-routine is stored in register pDest->iSDParm
11653 ** and the result row is stored in pDest->nDest registers
11654 ** starting with pDest->iSdst.
11655 **
11656 ** SRT_Table Store results in temporary table pDest->iSDParm.
11657 ** SRT_Fifo This is like SRT_EphemTab except that the table
11658 ** is assumed to already be open. SRT_Fifo has
11659 ** the additional property of being able to ignore
11660 ** the ORDER BY clause.
11661 **
11662 ** SRT_DistFifo Store results in a temporary table pDest->iSDParm.
11663 ** But also use temporary table pDest->iSDParm+1 as
11664 ** a record of all prior results and ignore any duplicate
11665 ** rows. Name means: "Distinct Fifo".
11666 **
11667 ** SRT_Queue Store results in priority queue pDest->iSDParm (really
11668 ** an index). Append a sequence number so that all entries
11669 ** are distinct.
11670 **
@@ -11650,23 +11674,24 @@
11674 */
11675 #define SRT_Union 1 /* Store result as keys in an index */
11676 #define SRT_Except 2 /* Remove result from a UNION index */
11677 #define SRT_Exists 3 /* Store 1 if the result is not empty */
11678 #define SRT_Discard 4 /* Do not save the results anywhere */
11679 #define SRT_Fifo 5 /* Store result as data with an automatic rowid */
11680 #define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
11681 #define SRT_Queue 7 /* Store result in an queue */
11682 #define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
11683
11684 /* The ORDER BY clause is ignored for all of the above */
11685 #define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
11686
11687 #define SRT_Output 9 /* Output each row of result */
11688 #define SRT_Mem 10 /* Store result in a memory cell */
11689 #define SRT_Set 11 /* Store results as keys in an index */
11690 #define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
11691 #define SRT_Coroutine 13 /* Generate a single row of result */
11692 #define SRT_Table 14 /* Store result as data with an automatic rowid */
 
 
 
11693
11694 /*
11695 ** An instance of this object describes where to put of the results of
11696 ** a SELECT statement.
11697 */
@@ -11760,12 +11785,10 @@
11785 int rc; /* Return code from execution */
11786 u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
11787 u8 checkSchema; /* Causes schema cookie check after an error */
11788 u8 nested; /* Number of nested calls to the parser/code generator */
11789 u8 nTempReg; /* Number of temporary registers in aTempReg[] */
 
 
11790 u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
11791 u8 mayAbort; /* True if statement may throw an ABORT exception */
11792 u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
11793 u8 okConstFactor; /* OK to factor out constants */
11794 int aTempReg[8]; /* Holding area for temporary registers */
@@ -12387,11 +12410,11 @@
12410 SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
12411
12412 SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
12413 SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*);
12414 SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
12415 SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64);
12416 SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
12417
12418 SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
12419
12420 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -12451,11 +12474,11 @@
12474 SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
12475 SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
12476 SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
12477 SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
12478 SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*);
12479 SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*);
12480 SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
12481 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
12482 SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
12483 SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
12484 SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
@@ -12503,10 +12526,11 @@
12526 SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
12527 SQLITE_PRIVATE int sqlite3IsRowid(const char*);
12528 SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
12529 SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
12530 SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
12531 SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int);
12532 SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
12533 u8,u8,int,int*);
12534 SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
12535 SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
12536 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
@@ -12660,11 +12684,11 @@
12684 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
12685 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
12686 SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
12687 SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
12688 SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
12689 SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
12690 SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
12691 SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
12692 SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
12693 SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
12694 SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
@@ -13745,10 +13769,11 @@
13769 u16 nHdrParsed; /* Number of header fields parsed so far */
13770 i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
13771 u8 nullRow; /* True if pointing to a row with no data */
13772 u8 rowidIsValid; /* True if lastRowid is valid */
13773 u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
13774 Bool isEphemeral:1; /* True for an ephemeral table */
13775 Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
13776 Bool isTable:1; /* True if a table requiring integer keys */
13777 Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
13778 sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
13779 i64 seqCount; /* Sequence counter */
@@ -14064,11 +14089,11 @@
14089 SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
14090 SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
14091 SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
14092
14093 int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
14094 SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
14095 SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
14096 SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
14097 SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
14098 SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
14099 SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
@@ -14110,10 +14135,11 @@
14135 SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
14136 SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
14137 SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
14138
14139 SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
14140 SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
14141 SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
14142 SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
14143 SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
14144 SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
14145 SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
@@ -17849,11 +17875,11 @@
17875
17876 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
17877 ** block. If not, then split a block of the next larger power of
17878 ** two in order to create a new free block of size iLogsize.
17879 */
17880 for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
17881 if( iBin>LOGMAX ){
17882 testcase( sqlite3GlobalConfig.xLog!=0 );
17883 sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
17884 return 0;
17885 }
@@ -20159,24 +20185,10 @@
20185 *val = (*val - d)*10.0;
20186 return (char)digit;
20187 }
20188 #endif /* SQLITE_OMIT_FLOATING_POINT */
20189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20190 /*
20191 ** Set the StrAccum object to an error mode.
20192 */
20193 static void setStrAccumError(StrAccum *p, u8 eError){
20194 p->accError = eError;
@@ -20262,15 +20274,13 @@
20274 }else{
20275 bArgList = useIntern = 0;
20276 }
20277 for(; (c=(*fmt))!=0; ++fmt){
20278 if( c!='%' ){
 
20279 bufpt = (char *)fmt;
20280 while( (c=(*++fmt))!='%' && c!=0 ){};
20281 sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
 
20282 if( c==0 ) break;
20283 }
20284 if( (c=(*++fmt))==0 ){
20285 sqlite3StrAccumAppend(pAccum, "%", 1);
20286 break;
@@ -20447,14 +20457,12 @@
20457 }
20458 *(--bufpt) = zOrd[x*2+1];
20459 *(--bufpt) = zOrd[x*2];
20460 }
20461 {
20462 const char *cset = &aDigits[infop->charset];
20463 u8 base = infop->base;
 
 
20464 do{ /* Convert to ascii */
20465 *(--bufpt) = cset[longvalue%base];
20466 longvalue = longvalue/base;
20467 }while( longvalue>0 );
20468 }
@@ -20754,77 +20762,102 @@
20762 /*
20763 ** The text of the conversion is pointed to by "bufpt" and is
20764 ** "length" characters long. The field width is "width". Do
20765 ** the output.
20766 */
20767 width -= length;
20768 if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
20769 sqlite3StrAccumAppend(pAccum, bufpt, length);
20770 if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
20771
 
 
 
 
 
 
 
 
 
 
 
 
20772 if( zExtra ) sqlite3_free(zExtra);
20773 }/* End for loop over the format string */
20774 } /* End of function */
20775
20776 /*
20777 ** Enlarge the memory allocation on a StrAccum object so that it is
20778 ** able to accept at least N more bytes of text.
20779 **
20780 ** Return the number of bytes of text that StrAccum is able to accept
20781 ** after the attempted enlargement. The value returned might be zero.
20782 */
20783 static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
20784 char *zNew;
20785 assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
20786 if( p->accError ){
20787 testcase(p->accError==STRACCUM_TOOBIG);
20788 testcase(p->accError==STRACCUM_NOMEM);
20789 return 0;
20790 }
20791 if( !p->useMalloc ){
20792 N = p->nAlloc - p->nChar - 1;
20793 setStrAccumError(p, STRACCUM_TOOBIG);
20794 return N;
20795 }else{
20796 char *zOld = (p->zText==p->zBase ? 0 : p->zText);
20797 i64 szNew = p->nChar;
20798 szNew += N + 1;
20799 if( szNew > p->mxAlloc ){
20800 sqlite3StrAccumReset(p);
20801 setStrAccumError(p, STRACCUM_TOOBIG);
20802 return 0;
20803 }else{
20804 p->nAlloc = (int)szNew;
20805 }
20806 if( p->useMalloc==1 ){
20807 zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
20808 }else{
20809 zNew = sqlite3_realloc(zOld, p->nAlloc);
20810 }
20811 if( zNew ){
20812 if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
20813 p->zText = zNew;
20814 }else{
20815 sqlite3StrAccumReset(p);
20816 setStrAccumError(p, STRACCUM_NOMEM);
20817 return 0;
20818 }
20819 }
20820 return N;
20821 }
20822
20823 /*
20824 ** Append N space characters to the given string buffer.
20825 */
20826 SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){
20827 if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
20828 while( (N--)>0 ) p->zText[p->nChar++] = ' ';
20829 }
20830
20831 /*
20832 ** The StrAccum "p" is not large enough to accept N new bytes of z[].
20833 ** So enlarge if first, then do the append.
20834 **
20835 ** This is a helper routine to sqlite3StrAccumAppend() that does special-case
20836 ** work (enlarging the buffer) using tail recursion, so that the
20837 ** sqlite3StrAccumAppend() routine can use fast calling semantics.
20838 */
20839 static void enlargeAndAppend(StrAccum *p, const char *z, int N){
20840 N = sqlite3StrAccumEnlarge(p, N);
20841 if( N>0 ){
20842 memcpy(&p->zText[p->nChar], z, N);
20843 p->nChar += N;
20844 }
20845 }
20846
20847 /*
20848 ** Append N bytes of text from z to the StrAccum object. Increase the
20849 ** size of the memory allocation for StrAccum if necessary.
20850 */
20851 SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
20852 assert( z!=0 );
20853 assert( p->zText!=0 || p->nChar==0 || p->accError );
20854 assert( N>=0 );
20855 assert( p->accError==0 || p->nAlloc==0 );
20856 if( p->nChar+N >= p->nAlloc ){
20857 enlargeAndAppend(p,z,N);
20858 return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20859 }
20860 assert( p->zText );
20861 memcpy(&p->zText[p->nChar], z, N);
20862 p->nChar += N;
20863 }
@@ -23328,11 +23361,11 @@
23361 /* 9 */ "Next" OpHelp(""),
23362 /* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
23363 /* 11 */ "Checkpoint" OpHelp(""),
23364 /* 12 */ "JournalMode" OpHelp(""),
23365 /* 13 */ "Vacuum" OpHelp(""),
23366 /* 14 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
23367 /* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"),
23368 /* 16 */ "Goto" OpHelp(""),
23369 /* 17 */ "Gosub" OpHelp(""),
23370 /* 18 */ "Return" OpHelp(""),
23371 /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
@@ -23355,11 +23388,11 @@
23388 /* 36 */ "CollSeq" OpHelp(""),
23389 /* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
23390 /* 38 */ "MustBeInt" OpHelp(""),
23391 /* 39 */ "RealAffinity" OpHelp(""),
23392 /* 40 */ "Permutation" OpHelp(""),
23393 /* 41 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
23394 /* 42 */ "Jump" OpHelp(""),
23395 /* 43 */ "Once" OpHelp(""),
23396 /* 44 */ "If" OpHelp(""),
23397 /* 45 */ "IfNot" OpHelp(""),
23398 /* 46 */ "Column" OpHelp("r[P3]=PX"),
@@ -23382,11 +23415,11 @@
23415 /* 63 */ "Seek" OpHelp("intkey=r[P2]"),
23416 /* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"),
23417 /* 65 */ "NotFound" OpHelp("key=r[P3@P4]"),
23418 /* 66 */ "Found" OpHelp("key=r[P3@P4]"),
23419 /* 67 */ "NotExists" OpHelp("intkey=r[P3]"),
23420 /* 68 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
23421 /* 69 */ "NewRowid" OpHelp("r[P2]=rowid"),
23422 /* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
23423 /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
23424 /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
23425 /* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
@@ -23430,51 +23463,52 @@
23463 /* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"),
23464 /* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"),
23465 /* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"),
23466 /* 114 */ "Destroy" OpHelp(""),
23467 /* 115 */ "Clear" OpHelp(""),
23468 /* 116 */ "ResetSorter" OpHelp(""),
23469 /* 117 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
23470 /* 118 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
23471 /* 119 */ "ParseSchema" OpHelp(""),
23472 /* 120 */ "LoadAnalysis" OpHelp(""),
23473 /* 121 */ "DropTable" OpHelp(""),
23474 /* 122 */ "DropIndex" OpHelp(""),
23475 /* 123 */ "DropTrigger" OpHelp(""),
23476 /* 124 */ "IntegrityCk" OpHelp(""),
23477 /* 125 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
23478 /* 126 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
23479 /* 127 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
23480 /* 128 */ "Program" OpHelp(""),
23481 /* 129 */ "Param" OpHelp(""),
23482 /* 130 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
23483 /* 131 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
23484 /* 132 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
23485 /* 133 */ "Real" OpHelp("r[P2]=P4"),
23486 /* 134 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
23487 /* 135 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"),
23488 /* 136 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
23489 /* 137 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
23490 /* 138 */ "IncrVacuum" OpHelp(""),
23491 /* 139 */ "Expire" OpHelp(""),
23492 /* 140 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
23493 /* 141 */ "VBegin" OpHelp(""),
23494 /* 142 */ "VCreate" OpHelp(""),
23495 /* 143 */ "ToText" OpHelp(""),
23496 /* 144 */ "ToBlob" OpHelp(""),
23497 /* 145 */ "ToNumeric" OpHelp(""),
23498 /* 146 */ "ToInt" OpHelp(""),
23499 /* 147 */ "ToReal" OpHelp(""),
23500 /* 148 */ "VDestroy" OpHelp(""),
23501 /* 149 */ "VOpen" OpHelp(""),
23502 /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
23503 /* 151 */ "VNext" OpHelp(""),
23504 /* 152 */ "VRename" OpHelp(""),
23505 /* 153 */ "Pagecount" OpHelp(""),
23506 /* 154 */ "MaxPgcnt" OpHelp(""),
23507 /* 155 */ "Init" OpHelp("Start at P2"),
23508 /* 156 */ "Noop" OpHelp(""),
23509 /* 157 */ "Explain" OpHelp(""),
23510 };
23511 return azName[i];
23512 }
23513 #endif
23514
@@ -24010,10 +24044,11 @@
24044 return geteuid() ? 0 : fchown(fd,uid,gid);
24045 }
24046
24047 /* Forward reference */
24048 static int openDirectory(const char*, int*);
24049 static int unixGetpagesize(void);
24050
24051 /*
24052 ** Many system calls are accessed through pointer-to-functions so that
24053 ** they may be overridden at runtime to facilitate fault injection during
24054 ** testing and sandboxing. The following array holds the names and pointers
@@ -24132,10 +24167,13 @@
24167 #else
24168 { "mremap", (sqlite3_syscall_ptr)0, 0 },
24169 #endif
24170 #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
24171 #endif
24172
24173 { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
24174 #define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
24175
24176 }; /* End of the overrideable system calls */
24177
24178 /*
24179 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
@@ -27792,10 +27830,40 @@
27830 #endif
27831
27832 return rc;
27833 }
27834
27835 /*
27836 ** Return the system page size.
27837 **
27838 ** This function should not be called directly by other code in this file.
27839 ** Instead, it should be called via macro osGetpagesize().
27840 */
27841 static int unixGetpagesize(void){
27842 #if defined(_BSD_SOURCE)
27843 return getpagesize();
27844 #else
27845 return (int)sysconf(_SC_PAGESIZE);
27846 #endif
27847 }
27848
27849 /*
27850 ** Return the minimum number of 32KB shm regions that should be mapped at
27851 ** a time, assuming that each mapping must be an integer multiple of the
27852 ** current system page-size.
27853 **
27854 ** Usually, this is 1. The exception seems to be systems that are configured
27855 ** to use 64KB pages - in this case each mapping must cover at least two
27856 ** shm regions.
27857 */
27858 static int unixShmRegionPerMap(void){
27859 int shmsz = 32*1024; /* SHM region size */
27860 int pgsz = osGetpagesize(); /* System page size */
27861 assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
27862 if( pgsz<shmsz ) return 1;
27863 return pgsz/shmsz;
27864 }
27865
27866 /*
27867 ** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
27868 **
27869 ** This is not a VFS shared-memory method; it is a utility function called
@@ -27803,14 +27871,15 @@
27871 */
27872 static void unixShmPurge(unixFile *pFd){
27873 unixShmNode *p = pFd->pInode->pShmNode;
27874 assert( unixMutexHeld() );
27875 if( p && p->nRef==0 ){
27876 int nShmPerMap = unixShmRegionPerMap();
27877 int i;
27878 assert( p->pInode==pFd->pInode );
27879 sqlite3_mutex_free(p->mutex);
27880 for(i=0; i<p->nRegion; i+=nShmPerMap){
27881 if( p->h>=0 ){
27882 osMunmap(p->apRegion[i], p->szRegion);
27883 }else{
27884 sqlite3_free(p->apRegion[i]);
27885 }
@@ -28013,10 +28082,12 @@
28082 ){
28083 unixFile *pDbFd = (unixFile*)fd;
28084 unixShm *p;
28085 unixShmNode *pShmNode;
28086 int rc = SQLITE_OK;
28087 int nShmPerMap = unixShmRegionPerMap();
28088 int nReqRegion;
28089
28090 /* If the shared-memory file has not yet been opened, open it now. */
28091 if( pDbFd->pShm==0 ){
28092 rc = unixOpenSharedMemory(pDbFd);
28093 if( rc!=SQLITE_OK ) return rc;
@@ -28028,13 +28099,16 @@
28099 assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
28100 assert( pShmNode->pInode==pDbFd->pInode );
28101 assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
28102 assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
28103
28104 /* Minimum number of regions required to be mapped. */
28105 nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
28106
28107 if( pShmNode->nRegion<nReqRegion ){
28108 char **apNew; /* New apRegion[] array */
28109 int nByte = nReqRegion*szRegion; /* Minimum required file size */
28110 struct stat sStat; /* Used by fstat() */
28111
28112 pShmNode->szRegion = szRegion;
28113
28114 if( pShmNode->h>=0 ){
@@ -28079,21 +28153,23 @@
28153 }
28154 }
28155
28156 /* Map the requested memory region into this processes address space. */
28157 apNew = (char **)sqlite3_realloc(
28158 pShmNode->apRegion, nReqRegion*sizeof(char *)
28159 );
28160 if( !apNew ){
28161 rc = SQLITE_IOERR_NOMEM;
28162 goto shmpage_out;
28163 }
28164 pShmNode->apRegion = apNew;
28165 while( pShmNode->nRegion<nReqRegion ){
28166 int nMap = szRegion*nShmPerMap;
28167 int i;
28168 void *pMem;
28169 if( pShmNode->h>=0 ){
28170 pMem = osMmap(0, nMap,
28171 pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
28172 MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
28173 );
28174 if( pMem==MAP_FAILED ){
28175 rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
@@ -28105,12 +28181,15 @@
28181 rc = SQLITE_NOMEM;
28182 goto shmpage_out;
28183 }
28184 memset(pMem, 0, szRegion);
28185 }
28186
28187 for(i=0; i<nShmPerMap; i++){
28188 pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
28189 }
28190 pShmNode->nRegion += nShmPerMap;
28191 }
28192 }
28193
28194 shmpage_out:
28195 if( pShmNode->nRegion>iRegion ){
@@ -28320,23 +28399,10 @@
28399 pFd->mmapSize = 0;
28400 pFd->mmapSizeActual = 0;
28401 }
28402 }
28403
 
 
 
 
 
 
 
 
 
 
 
 
 
28404 /*
28405 ** Attempt to set the size of the memory mapping maintained by file
28406 ** descriptor pFd to nNew bytes. Any existing mapping is discarded.
28407 **
28408 ** If successful, this function sets the following variables:
@@ -28369,12 +28435,16 @@
28435 assert( MAP_FAILED!=0 );
28436
28437 if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
28438
28439 if( pOrig ){
28440 #if HAVE_MREMAP
28441 i64 nReuse = pFd->mmapSize;
28442 #else
28443 const int szSyspage = osGetpagesize();
28444 i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
28445 #endif
28446 u8 *pReq = &pOrig[nReuse];
28447
28448 /* Unmap any pages of the existing mapping that cannot be reused. */
28449 if( nReuse!=nOrig ){
28450 osMunmap(pReq, nOrig-nReuse);
@@ -31116,11 +31186,11 @@
31186 };
31187 unsigned int i; /* Loop counter */
31188
31189 /* Double-check that the aSyscall[] array has been constructed
31190 ** correctly. See ticket [bb3a86e890c8e96ab] */
31191 assert( ArraySize(aSyscall)==25 );
31192
31193 /* Register all VFSes defined in the aVfs[] array */
31194 for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
31195 sqlite3_vfs_register(&aVfs[i], i==0);
31196 }
@@ -38997,12 +39067,12 @@
39067 struct RowSetEntry *pEntry; /* List of entries using pRight */
39068 struct RowSetEntry *pLast; /* Last entry on the pEntry list */
39069 struct RowSetEntry *pFresh; /* Source of new entry objects */
39070 struct RowSetEntry *pForest; /* List of binary trees of entries */
39071 u16 nFresh; /* Number of objects on pFresh */
39072 u16 rsFlags; /* Various flags */
39073 int iBatch; /* Current insert batch */
39074 };
39075
39076 /*
39077 ** Allowed values for RowSet.rsFlags
39078 */
@@ -39332,11 +39402,11 @@
39402 **
39403 ** If this is the first test of a new batch and if there exist entires
39404 ** on pRowSet->pEntry, then sort those entires into the forest at
39405 ** pRowSet->pForest so that they can be tested.
39406 */
39407 SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
39408 struct RowSetEntry *p, *pTree;
39409
39410 /* This routine is never called after sqlite3RowSetNext() */
39411 assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
39412
@@ -41159,16 +41229,15 @@
41229 assert( pPager->setMaster==0 );
41230 assert( !pagerUseWal(pPager) );
41231
41232 if( !zMaster
41233 || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
41234 || !isOpen(pPager->jfd)
41235 ){
41236 return SQLITE_OK;
41237 }
41238 pPager->setMaster = 1;
 
41239 assert( pPager->journalHdr <= pPager->journalOff );
41240
41241 /* Calculate the length in bytes and the checksum of zMaster */
41242 for(nMaster=0; zMaster[nMaster]; nMaster++){
41243 cksum += zMaster[nMaster];
@@ -50371,31 +50440,34 @@
50440 struct BtCursor {
50441 Btree *pBtree; /* The Btree to which this cursor belongs */
50442 BtShared *pBt; /* The BtShared this cursor points to */
50443 BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
50444 struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
 
50445 Pgno *aOverflow; /* Cache of overflow page locations */
50446 CellInfo info; /* A parse of the cell we are pointing at */
50447 i64 nKey; /* Size of pKey, or last integer key */
50448 void *pKey; /* Saved key that was cursor last known position */
50449 Pgno pgnoRoot; /* The root page of this tree */
50450 int nOvflAlloc; /* Allocated size of aOverflow[] array */
 
 
50451 int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
50452 u8 curFlags; /* zero or more BTCF_* flags defined below */
 
 
50453 u8 eState; /* One of the CURSOR_XXX constants (see below) */
 
 
 
50454 u8 hints; /* As configured by CursorSetHints() */
50455 i16 iPage; /* Index of current page in apPage */
50456 u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
50457 MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
50458 };
50459
50460 /*
50461 ** Legal values for BtCursor.curFlags
50462 */
50463 #define BTCF_WriteFlag 0x01 /* True if a write cursor */
50464 #define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
50465 #define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
50466 #define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
50467 #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
50468
50469 /*
50470 ** Potential values for BtCursor.eState.
50471 **
50472 ** CURSOR_INVALID:
50473 ** Cursor does not point to a valid entry. This can happen (for example)
@@ -51262,20 +51334,15 @@
51334 static int cursorHoldsMutex(BtCursor *p){
51335 return sqlite3_mutex_held(p->pBt->mutex);
51336 }
51337 #endif
51338
 
 
51339 /*
51340 ** Invalidate the overflow cache of the cursor passed as the first argument.
51341 ** on the shared btree structure pBt.
51342 */
51343 #define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
 
 
 
 
51344
51345 /*
51346 ** Invalidate the overflow page-list cache for all cursors opened
51347 ** on the shared btree structure pBt.
51348 */
@@ -51285,10 +51352,11 @@
51352 for(p=pBt->pCursor; p; p=p->pNext){
51353 invalidateOverflowCache(p);
51354 }
51355 }
51356
51357 #ifndef SQLITE_OMIT_INCRBLOB
51358 /*
51359 ** This function is called before modifying the contents of a table
51360 ** to invalidate any incrblob cursors that are open on the
51361 ** row or one of the rows being modified.
51362 **
@@ -51307,20 +51375,18 @@
51375 ){
51376 BtCursor *p;
51377 BtShared *pBt = pBtree->pBt;
51378 assert( sqlite3BtreeHoldsMutex(pBtree) );
51379 for(p=pBt->pCursor; p; p=p->pNext){
51380 if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
51381 p->eState = CURSOR_INVALID;
51382 }
51383 }
51384 }
51385
51386 #else
51387 /* Stub function when INCRBLOB is omitted */
 
 
51388 #define invalidateIncrblobCursors(x,y,z)
51389 #endif /* SQLITE_OMIT_INCRBLOB */
51390
51391 /*
51392 ** Set bit pgno of the BtShared.pHasContent bitvec. This is called
@@ -51562,24 +51628,36 @@
51628 ** Determine whether or not a cursor has moved from the position it
51629 ** was last placed at. Cursors can move when the row they are pointing
51630 ** at is deleted out from under them.
51631 **
51632 ** This routine returns an error code if something goes wrong. The
51633 ** integer *pHasMoved is set as follows:
51634 **
51635 ** 0: The cursor is unchanged
51636 ** 1: The cursor is still pointing at the same row, but the pointers
51637 ** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
51638 ** might now be invalid because of a balance() or other change to the
51639 ** b-tree.
51640 ** 2: The cursor is no longer pointing to the row. The row might have
51641 ** been deleted out from under the cursor.
51642 */
51643 SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
51644 int rc;
51645
51646 if( pCur->eState==CURSOR_VALID ){
51647 *pHasMoved = 0;
51648 return SQLITE_OK;
51649 }
51650 rc = restoreCursorPosition(pCur);
51651 if( rc ){
51652 *pHasMoved = 2;
51653 return rc;
51654 }
51655 if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
51656 *pHasMoved = 2;
51657 }else{
51658 *pHasMoved = 1;
 
 
51659 }
51660 return SQLITE_OK;
51661 }
51662
51663 #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -52977,10 +53055,11 @@
53055 sqlite3PagerSetCachesize(pBt->pPager, mxPage);
53056 sqlite3BtreeLeave(p);
53057 return SQLITE_OK;
53058 }
53059
53060 #if SQLITE_MAX_MMAP_SIZE>0
53061 /*
53062 ** Change the limit on the amount of the database file that may be
53063 ** memory mapped.
53064 */
53065 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
@@ -52989,10 +53068,11 @@
53068 sqlite3BtreeEnter(p);
53069 sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
53070 sqlite3BtreeLeave(p);
53071 return SQLITE_OK;
53072 }
53073 #endif /* SQLITE_MAX_MMAP_SIZE>0 */
53074
53075 /*
53076 ** Change the way data is synced to disk in order to increase or decrease
53077 ** how well the database resists damage due to OS crashes and power
53078 ** failures. Level 1 is the same as asynchronous (no syncs() occur and
@@ -53365,11 +53445,12 @@
53445 */
53446 static int countValidCursors(BtShared *pBt, int wrOnly){
53447 BtCursor *pCur;
53448 int r = 0;
53449 for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
53450 if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
53451 && pCur->eState!=CURSOR_FAULT ) r++;
53452 }
53453 return r;
53454 }
53455 #endif
53456
@@ -54440,11 +54521,12 @@
54521 pCur->pgnoRoot = (Pgno)iTable;
54522 pCur->iPage = -1;
54523 pCur->pKeyInfo = pKeyInfo;
54524 pCur->pBtree = p;
54525 pCur->pBt = pBt;
54526 assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
54527 pCur->curFlags = wrFlag;
54528 pCur->pNext = pBt->pCursor;
54529 if( pCur->pNext ){
54530 pCur->pNext->pPrev = pCur;
54531 }
54532 pBt->pCursor = pCur;
@@ -54510,11 +54592,11 @@
54592 }
54593 for(i=0; i<=pCur->iPage; i++){
54594 releasePage(pCur->apPage[i]);
54595 }
54596 unlockBtreeIfUnused(pBt);
54597 sqlite3DbFree(pBtree->db, pCur->aOverflow);
54598 /* sqlite3_free(pCur); */
54599 sqlite3BtreeLeave(pBtree);
54600 }
54601 return SQLITE_OK;
54602 }
@@ -54549,22 +54631,22 @@
54631 /* Use a real function in MSVC to work around bugs in that compiler. */
54632 static void getCellInfo(BtCursor *pCur){
54633 if( pCur->info.nSize==0 ){
54634 int iPage = pCur->iPage;
54635 btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
54636 pCur->curFlags |= BTCF_ValidNKey;
54637 }else{
54638 assertCellInfo(pCur);
54639 }
54640 }
54641 #else /* if not _MSC_VER */
54642 /* Use a macro in all other compilers so that the function is inlined */
54643 #define getCellInfo(pCur) \
54644 if( pCur->info.nSize==0 ){ \
54645 int iPage = pCur->iPage; \
54646 btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
54647 pCur->curFlags |= BTCF_ValidNKey; \
54648 }else{ \
54649 assertCellInfo(pCur); \
54650 }
54651 #endif /* _MSC_VER */
54652
@@ -54731,26 +54813,28 @@
54813 return SQLITE_OK;
54814 }
54815
54816 /*
54817 ** This function is used to read or overwrite payload information
54818 ** for the entry that the pCur cursor is pointing to. The eOp
54819 ** argument is interpreted as follows:
54820 **
54821 ** 0: The operation is a read. Populate the overflow cache.
54822 ** 1: The operation is a write. Populate the overflow cache.
54823 ** 2: The operation is a read. Do not populate the overflow cache.
54824 **
54825 ** A total of "amt" bytes are read or written beginning at "offset".
54826 ** Data is read to or from the buffer pBuf.
54827 **
54828 ** The content being read or written might appear on the main page
54829 ** or be scattered out on multiple overflow pages.
54830 **
54831 ** If the current cursor entry uses one or more overflow pages and the
54832 ** eOp argument is not 2, this function may allocate space for and lazily
54833 ** popluates the overflow page-list cache array (BtCursor.aOverflow).
54834 ** Subsequent calls use this cache to make seeking to the supplied offset
54835 ** more efficient.
54836 **
54837 ** Once an overflow page-list cache has been allocated, it may be
54838 ** invalidated if some other cursor writes to the same table, or if
54839 ** the cursor is moved to a different row. Additionally, in auto-vacuum
54840 ** mode, the following events may invalidate an overflow page-list cache.
@@ -54770,19 +54854,26 @@
54854 int rc = SQLITE_OK;
54855 u32 nKey;
54856 int iIdx = 0;
54857 MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
54858 BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
54859 #ifdef SQLITE_DIRECT_OVERFLOW_READ
54860 int bEnd; /* True if reading to end of data */
54861 #endif
54862
54863 assert( pPage );
54864 assert( pCur->eState==CURSOR_VALID );
54865 assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
54866 assert( cursorHoldsMutex(pCur) );
54867 assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
54868
54869 getCellInfo(pCur);
54870 aPayload = pCur->info.pCell + pCur->info.nHeader;
54871 nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
54872 #ifdef SQLITE_DIRECT_OVERFLOW_READ
54873 bEnd = (offset+amt==nKey+pCur->info.nData);
54874 #endif
54875
54876 if( NEVER(offset+amt > nKey+pCur->info.nData)
54877 || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
54878 ){
54879 /* Trying to read or write past the end of the data is an error */
@@ -54793,11 +54884,11 @@
54884 if( offset<pCur->info.nLocal ){
54885 int a = amt;
54886 if( a+offset>pCur->info.nLocal ){
54887 a = pCur->info.nLocal - offset;
54888 }
54889 rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
54890 offset = 0;
54891 pBuf += a;
54892 amt -= a;
54893 }else{
54894 offset -= pCur->info.nLocal;
@@ -54807,62 +54898,72 @@
54898 const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
54899 Pgno nextPage;
54900
54901 nextPage = get4byte(&aPayload[pCur->info.nLocal]);
54902
54903 /* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
54904 ** Except, do not allocate aOverflow[] for eOp==2.
54905 **
54906 ** The aOverflow[] array is sized at one entry for each overflow page
54907 ** in the overflow chain. The page number of the first overflow page is
54908 ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
54909 ** means "not yet known" (the cache is lazily populated).
54910 */
54911 if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
54912 int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
54913 if( nOvfl>pCur->nOvflAlloc ){
54914 Pgno *aNew = (Pgno*)sqlite3DbRealloc(
54915 pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
54916 );
54917 if( aNew==0 ){
54918 rc = SQLITE_NOMEM;
54919 }else{
54920 pCur->nOvflAlloc = nOvfl*2;
54921 pCur->aOverflow = aNew;
54922 }
54923 }
54924 if( rc==SQLITE_OK ){
54925 memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
54926 pCur->curFlags |= BTCF_ValidOvfl;
54927 }
54928 }
54929
54930 /* If the overflow page-list cache has been allocated and the
54931 ** entry for the first required overflow page is valid, skip
54932 ** directly to it.
54933 */
54934 if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
54935 iIdx = (offset/ovflSize);
54936 nextPage = pCur->aOverflow[iIdx];
54937 offset = (offset%ovflSize);
54938 }
 
54939
54940 for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
54941
 
54942 /* If required, populate the overflow page-list cache. */
54943 if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
54944 assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
54945 pCur->aOverflow[iIdx] = nextPage;
54946 }
 
54947
54948 if( offset>=ovflSize ){
54949 /* The only reason to read this page is to obtain the page
54950 ** number for the next page in the overflow chain. The page
54951 ** data is not required. So first try to lookup the overflow
54952 ** page-list cache, if any, then fall back to the getOverflowPage()
54953 ** function.
54954 **
54955 ** Note that the aOverflow[] array must be allocated because eOp!=2
54956 ** here. If eOp==2, then offset==0 and this branch is never taken.
54957 */
54958 assert( eOp!=2 );
54959 assert( pCur->curFlags & BTCF_ValidOvfl );
54960 if( pCur->aOverflow[iIdx+1] ){
54961 nextPage = pCur->aOverflow[iIdx+1];
54962 }else{
 
54963 rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
54964 }
54965 offset -= ovflSize;
54966 }else{
54967 /* Need to read this page properly. It contains some of the
54968 ** range of data that is being read (eOp==0) or written (eOp!=0).
54969 */
@@ -54880,17 +54981,19 @@
54981 ** 1) this is a read operation, and
54982 ** 2) data is required from the start of this overflow page, and
54983 ** 3) the database is file-backed, and
54984 ** 4) there is no open write-transaction, and
54985 ** 5) the database is not a WAL database,
54986 ** 6) all data from the page is being read.
54987 **
54988 ** then data can be read directly from the database file into the
54989 ** output buffer, bypassing the page-cache altogether. This speeds
54990 ** up loading large records that span many overflow pages.
54991 */
54992 if( (eOp&0x01)==0 /* (1) */
54993 && offset==0 /* (2) */
54994 && (bEnd || a==ovflSize) /* (6) */
54995 && pBt->inTransaction==TRANS_READ /* (4) */
54996 && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
54997 && pBt->pPage1->aData[19]==0x01 /* (5) */
54998 ){
54999 u8 aSave[4];
@@ -54903,16 +55006,16 @@
55006 #endif
55007
55008 {
55009 DbPage *pDbPage;
55010 rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
55011 ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
55012 );
55013 if( rc==SQLITE_OK ){
55014 aPayload = sqlite3PagerGetData(pDbPage);
55015 nextPage = get4byte(aPayload);
55016 rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
55017 sqlite3PagerUnref(pDbPage);
55018 offset = 0;
55019 }
55020 }
55021 amt -= a;
@@ -55002,14 +55105,17 @@
55105 assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
55106 assert( pCur->eState==CURSOR_VALID );
55107 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
55108 assert( cursorHoldsMutex(pCur) );
55109 assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
55110 assert( pCur->info.nSize>0 );
55111 #if 0
55112 if( pCur->info.nSize==0 ){
55113 btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
55114 &pCur->info);
55115 }
55116 #endif
55117 *pAmt = pCur->info.nLocal;
55118 return (void*)(pCur->info.pCell + pCur->info.nHeader);
55119 }
55120
55121
@@ -55056,18 +55162,18 @@
55162 assert( pCur->iPage>=0 );
55163 if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
55164 return SQLITE_CORRUPT_BKPT;
55165 }
55166 rc = getAndInitPage(pBt, newPgno, &pNewPage,
55167 (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
55168 if( rc ) return rc;
55169 pCur->apPage[i+1] = pNewPage;
55170 pCur->aiIdx[i+1] = 0;
55171 pCur->iPage++;
55172
55173 pCur->info.nSize = 0;
55174 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
55175 if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
55176 return SQLITE_CORRUPT_BKPT;
55177 }
55178 return SQLITE_OK;
55179 }
@@ -55121,11 +55227,11 @@
55227 testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
55228
55229 releasePage(pCur->apPage[pCur->iPage]);
55230 pCur->iPage--;
55231 pCur->info.nSize = 0;
55232 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
55233 }
55234
55235 /*
55236 ** Move the cursor to point to the root page of its b-tree structure.
55237 **
@@ -55168,11 +55274,11 @@
55274 }else if( pCur->pgnoRoot==0 ){
55275 pCur->eState = CURSOR_INVALID;
55276 return SQLITE_OK;
55277 }else{
55278 rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
55279 (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
55280 if( rc!=SQLITE_OK ){
55281 pCur->eState = CURSOR_INVALID;
55282 return rc;
55283 }
55284 pCur->iPage = 0;
@@ -55195,12 +55301,11 @@
55301 return SQLITE_CORRUPT_BKPT;
55302 }
55303
55304 pCur->aiIdx[0] = 0;
55305 pCur->info.nSize = 0;
55306 pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
 
55307
55308 if( pRoot->nCell>0 ){
55309 pCur->eState = CURSOR_VALID;
55310 }else if( !pRoot->leaf ){
55311 Pgno subpage;
@@ -55259,11 +55364,11 @@
55364 rc = moveToChild(pCur, pgno);
55365 }
55366 if( rc==SQLITE_OK ){
55367 pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
55368 pCur->info.nSize = 0;
55369 pCur->curFlags &= ~BTCF_ValidNKey;
55370 }
55371 return rc;
55372 }
55373
55374 /* Move the cursor to the first entry in the table. Return SQLITE_OK
@@ -55298,11 +55403,11 @@
55403
55404 assert( cursorHoldsMutex(pCur) );
55405 assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
55406
55407 /* If the cursor already points to the last entry, this is a no-op. */
55408 if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
55409 #ifdef SQLITE_DEBUG
55410 /* This block serves to assert() that the cursor really does point
55411 ** to the last entry in the b-tree. */
55412 int ii;
55413 for(ii=0; ii<pCur->iPage; ii++){
@@ -55321,11 +55426,16 @@
55426 *pRes = 1;
55427 }else{
55428 assert( pCur->eState==CURSOR_VALID );
55429 *pRes = 0;
55430 rc = moveToRightmost(pCur);
55431 if( rc==SQLITE_OK ){
55432 pCur->curFlags |= BTCF_AtLast;
55433 }else{
55434 pCur->curFlags &= ~BTCF_AtLast;
55435 }
55436
55437 }
55438 }
55439 return rc;
55440 }
55441
@@ -55372,25 +55482,26 @@
55482 assert( pRes );
55483 assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
55484
55485 /* If the cursor is already positioned at the point we are trying
55486 ** to move to, then just return without doing any work */
55487 if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
55488 && pCur->apPage[0]->intKey
55489 ){
55490 if( pCur->info.nKey==intKey ){
55491 *pRes = 0;
55492 return SQLITE_OK;
55493 }
55494 if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
55495 *pRes = -1;
55496 return SQLITE_OK;
55497 }
55498 }
55499
55500 if( pIdxKey ){
55501 xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
55502 pIdxKey->isCorrupt = 0;
55503 assert( pIdxKey->default_rc==1
55504 || pIdxKey->default_rc==0
55505 || pIdxKey->default_rc==-1
55506 );
55507 }else{
@@ -55445,11 +55556,11 @@
55556 }else if( nCellKey>intKey ){
55557 upr = idx-1;
55558 if( lwr>upr ){ c = +1; break; }
55559 }else{
55560 assert( nCellKey==intKey );
55561 pCur->curFlags |= BTCF_ValidNKey;
55562 pCur->info.nKey = nCellKey;
55563 pCur->aiIdx[pCur->iPage] = (u16)idx;
55564 if( !pPage->leaf ){
55565 lwr = idx;
55566 goto moveto_next_layer;
@@ -55502,27 +55613,29 @@
55613 if( pCellKey==0 ){
55614 rc = SQLITE_NOMEM;
55615 goto moveto_finish;
55616 }
55617 pCur->aiIdx[pCur->iPage] = (u16)idx;
55618 rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
55619 if( rc ){
55620 sqlite3_free(pCellKey);
55621 goto moveto_finish;
55622 }
55623 c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
55624 sqlite3_free(pCellKey);
55625 }
55626 assert( pIdxKey->isCorrupt==0 || c==0 );
55627 if( c<0 ){
55628 lwr = idx+1;
55629 }else if( c>0 ){
55630 upr = idx-1;
55631 }else{
55632 assert( c==0 );
55633 *pRes = 0;
55634 rc = SQLITE_OK;
55635 pCur->aiIdx[pCur->iPage] = (u16)idx;
55636 if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
55637 goto moveto_finish;
55638 }
55639 if( lwr>upr ) break;
55640 assert( lwr+upr>=0 );
55641 idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
@@ -55547,11 +55660,11 @@
55660 rc = moveToChild(pCur, chldPg);
55661 if( rc ) break;
55662 }
55663 moveto_finish:
55664 pCur->info.nSize = 0;
55665 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
55666 return rc;
55667 }
55668
55669
55670 /*
@@ -55592,10 +55705,11 @@
55705 assert( cursorHoldsMutex(pCur) );
55706 assert( pRes!=0 );
55707 assert( *pRes==0 || *pRes==1 );
55708 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
55709 if( pCur->eState!=CURSOR_VALID ){
55710 invalidateOverflowCache(pCur);
55711 rc = restoreCursorPosition(pCur);
55712 if( rc!=SQLITE_OK ){
55713 *pRes = 0;
55714 return rc;
55715 }
@@ -55625,11 +55739,11 @@
55739 ** only happen if the database is corrupt in such a way as to link the
55740 ** page into more than one b-tree structure. */
55741 testcase( idx>pPage->nCell );
55742
55743 pCur->info.nSize = 0;
55744 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
55745 if( idx>=pPage->nCell ){
55746 if( !pPage->leaf ){
55747 rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
55748 if( rc ){
55749 *pRes = 0;
@@ -55686,11 +55800,11 @@
55800
55801 assert( cursorHoldsMutex(pCur) );
55802 assert( pRes!=0 );
55803 assert( *pRes==0 || *pRes==1 );
55804 assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
55805 pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
55806 if( pCur->eState!=CURSOR_VALID ){
55807 if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
55808 rc = btreeRestoreCursorPosition(pCur);
55809 if( rc!=SQLITE_OK ){
55810 *pRes = 0;
@@ -55731,11 +55845,11 @@
55845 return SQLITE_OK;
55846 }
55847 moveToParent(pCur);
55848 }
55849 pCur->info.nSize = 0;
55850 pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
55851
55852 pCur->aiIdx[pCur->iPage]--;
55853 pPage = pCur->apPage[pCur->iPage];
55854 if( pPage->intKey && !pPage->leaf ){
55855 rc = sqlite3BtreePrevious(pCur, pRes);
@@ -57756,11 +57870,11 @@
57870 assert( pCur->skipNext!=SQLITE_OK );
57871 return pCur->skipNext;
57872 }
57873
57874 assert( cursorHoldsMutex(pCur) );
57875 assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
57876 && (pBt->btsFlags & BTS_READ_ONLY)==0 );
57877 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
57878
57879 /* Assert that the caller has been consistent. If this cursor was opened
57880 ** expecting an index b-tree, then the caller should be inserting blob
@@ -57789,11 +57903,11 @@
57903 invalidateIncrblobCursors(p, nKey, 0);
57904
57905 /* If the cursor is currently on the last row and we are appending a
57906 ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
57907 ** call */
57908 if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
57909 loc = -1;
57910 }
57911 }
57912
57913 if( !loc ){
@@ -57842,11 +57956,11 @@
57956 insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
57957 assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
57958
57959 /* If no error has occurred and pPage has an overflow cell, call balance()
57960 ** to redistribute the cells within the tree. Since balance() may move
57961 ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
57962 ** variables.
57963 **
57964 ** Previous versions of SQLite called moveToRoot() to move the cursor
57965 ** back to the root page as balance() used to invalidate the contents
57966 ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that,
@@ -57862,11 +57976,11 @@
57976 ** larger than the largest existing key, it is possible to insert the
57977 ** row without seeking the cursor. This can be a big performance boost.
57978 */
57979 pCur->info.nSize = 0;
57980 if( rc==SQLITE_OK && pPage->nOverflow ){
57981 pCur->curFlags &= ~(BTCF_ValidNKey);
57982 rc = balance(pCur);
57983
57984 /* Must make sure nOverflow is reset to zero even if the balance()
57985 ** fails. Internal data structure corruption will result otherwise.
57986 ** Also, set the cursor state to invalid. This stops saveCursorPosition()
@@ -57894,11 +58008,11 @@
58008 int iCellDepth; /* Depth of node containing pCell */
58009
58010 assert( cursorHoldsMutex(pCur) );
58011 assert( pBt->inTransaction==TRANS_WRITE );
58012 assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
58013 assert( pCur->curFlags & BTCF_WriteFlag );
58014 assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
58015 assert( !hasReadConflicts(p, pCur->pgnoRoot) );
58016
58017 if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
58018 || NEVER(pCur->eState!=CURSOR_VALID)
@@ -58238,10 +58352,19 @@
58352 rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
58353 }
58354 sqlite3BtreeLeave(p);
58355 return rc;
58356 }
58357
58358 /*
58359 ** Delete all information from the single table that pCur is open on.
58360 **
58361 ** This routine only work for pCur on an ephemeral table.
58362 */
58363 SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
58364 return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
58365 }
58366
58367 /*
58368 ** Erase all information in a table and add the root of the table to
58369 ** the freelist. Except, the root of the principle table (the one on
58370 ** page 1) is never added to the freelist.
@@ -59198,11 +59321,11 @@
59321 */
59322 SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
59323 int rc;
59324 assert( cursorHoldsMutex(pCsr) );
59325 assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
59326 assert( pCsr->curFlags & BTCF_Incrblob );
59327
59328 rc = restoreCursorPosition(pCsr);
59329 if( rc!=SQLITE_OK ){
59330 return rc;
59331 }
@@ -59227,11 +59350,11 @@
59350 ** (b) there is a read/write transaction open,
59351 ** (c) the connection holds a write-lock on the table (if required),
59352 ** (d) there are no conflicting read-locks, and
59353 ** (e) the cursor points at a valid row of an intKey table.
59354 */
59355 if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
59356 return SQLITE_READONLY;
59357 }
59358 assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
59359 && pCsr->pBt->inTransaction==TRANS_WRITE );
59360 assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
@@ -59240,24 +59363,14 @@
59363
59364 return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
59365 }
59366
59367 /*
59368 ** Mark this cursor as an incremental blob cursor.
 
 
 
 
 
 
 
59369 */
59370 SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
59371 pCur->curFlags |= BTCF_Incrblob;
 
 
 
59372 }
59373 #endif
59374
59375 /*
59376 ** Set both the "read version" (single byte at byte offset 18) and
@@ -61624,11 +61737,11 @@
61737 SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
61738 Parse *p = v->pParse;
61739 int j = -1-x;
61740 assert( v->magic==VDBE_MAGIC_INIT );
61741 assert( j<p->nLabel );
61742 if( ALWAYS(j>=0) && p->aLabel ){
61743 p->aLabel[j] = v->nOp;
61744 }
61745 p->iFixedOp = v->nOp - 1;
61746 }
61747
@@ -62131,11 +62244,13 @@
62244 assert( addr<p->nOp );
62245 if( addr<0 ){
62246 addr = p->nOp - 1;
62247 }
62248 pOp = &p->aOp[addr];
62249 assert( pOp->p4type==P4_NOTUSED
62250 || pOp->p4type==P4_INT32
62251 || pOp->p4type==P4_KEYINFO );
62252 freeP4(db, pOp->p4type, pOp->p4.p);
62253 pOp->p4.p = 0;
62254 if( n==P4_INT32 ){
62255 /* Note: this cast is safe, because the origin data point was an int
62256 ** that was cast to a (const char *). */
@@ -64081,11 +64196,11 @@
64196 int hasMoved;
64197 int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
64198 if( rc ) return rc;
64199 if( hasMoved ){
64200 p->cacheStatus = CACHE_STALE;
64201 if( hasMoved==2 ) p->nullRow = 1;
64202 }
64203 }
64204 return SQLITE_OK;
64205 }
64206
@@ -64751,14 +64866,17 @@
64866 ** determined that the first fields of the keys are equal.
64867 **
64868 ** Key1 and Key2 do not have to contain the same number of fields. If all
64869 ** fields that appear in both keys are equal, then pPKey2->default_rc is
64870 ** returned.
64871 **
64872 ** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
64873 ** and return 0.
64874 */
64875 SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
64876 int nKey1, const void *pKey1, /* Left key */
64877 UnpackedRecord *pPKey2, /* Right key */
64878 int bSkip /* If true, skip the first field */
64879 ){
64880 u32 d1; /* Offset into aKey[] of next data element */
64881 int i; /* Index of next field to compare */
64882 u32 szHdr1; /* Size of record header in bytes */
@@ -64780,10 +64898,14 @@
64898 i = 1;
64899 pRhs++;
64900 }else{
64901 idx1 = getVarint32(aKey1, szHdr1);
64902 d1 = szHdr1;
64903 if( d1>(unsigned)nKey1 ){
64904 pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
64905 return 0; /* Corruption */
64906 }
64907 i = 0;
64908 }
64909
64910 VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
64911 assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
@@ -64856,11 +64978,12 @@
64978 }else{
64979 mem1.n = (serial_type - 12) / 2;
64980 testcase( (d1+mem1.n)==(unsigned)nKey1 );
64981 testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
64982 if( (d1+mem1.n) > (unsigned)nKey1 ){
64983 pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
64984 return 0; /* Corruption */
64985 }else if( pKeyInfo->aColl[i] ){
64986 mem1.enc = pKeyInfo->enc;
64987 mem1.db = pKeyInfo->db;
64988 mem1.flags = MEM_Str;
64989 mem1.z = (char*)&aKey1[d1];
@@ -64882,11 +65005,12 @@
65005 }else{
65006 int nStr = (serial_type - 12) / 2;
65007 testcase( (d1+nStr)==(unsigned)nKey1 );
65008 testcase( (d1+nStr+1)==(unsigned)nKey1 );
65009 if( (d1+nStr) > (unsigned)nKey1 ){
65010 pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
65011 return 0; /* Corruption */
65012 }else{
65013 int nCmp = MIN(nStr, pRhs->n);
65014 rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
65015 if( rc==0 ) rc = nStr - pRhs->n;
65016 }
@@ -64935,14 +65059,17 @@
65059 /*
65060 ** This function is an optimized version of sqlite3VdbeRecordCompare()
65061 ** that (a) the first field of pPKey2 is an integer, and (b) the
65062 ** size-of-header varint at the start of (pKey1/nKey1) fits in a single
65063 ** byte (i.e. is less than 128).
65064 **
65065 ** To avoid concerns about buffer overreads, this routine is only used
65066 ** on schemas where the maximum valid header size is 63 bytes or less.
65067 */
65068 static int vdbeRecordCompareInt(
65069 int nKey1, const void *pKey1, /* Left key */
65070 UnpackedRecord *pPKey2, /* Right key */
65071 int bSkip /* Ignored */
65072 ){
65073 const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
65074 int serial_type = ((const u8*)pKey1)[1];
65075 int res;
@@ -64951,10 +65078,11 @@
65078 i64 v = pPKey2->aMem[0].u.i;
65079 i64 lhs;
65080 UNUSED_PARAMETER(bSkip);
65081
65082 assert( bSkip==0 );
65083 assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
65084 switch( serial_type ){
65085 case 1: { /* 1-byte signed integer */
65086 lhs = ONE_BYTE_INT(aKey);
65087 testcase( lhs<0 );
65088 break;
@@ -65035,11 +65163,11 @@
65163 ** uses the collation sequence BINARY and (c) that the size-of-header varint
65164 ** at the start of (pKey1/nKey1) fits in a single byte.
65165 */
65166 static int vdbeRecordCompareString(
65167 int nKey1, const void *pKey1, /* Left key */
65168 UnpackedRecord *pPKey2, /* Right key */
65169 int bSkip
65170 ){
65171 const u8 *aKey1 = (const u8*)pKey1;
65172 int serial_type;
65173 int res;
@@ -65056,11 +65184,14 @@
65184 int nCmp;
65185 int nStr;
65186 int szHdr = aKey1[0];
65187
65188 nStr = (serial_type-12) / 2;
65189 if( (szHdr + nStr) > nKey1 ){
65190 pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
65191 return 0; /* Corruption */
65192 }
65193 nCmp = MIN( pPKey2->aMem[0].n, nStr );
65194 res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
65195
65196 if( res==0 ){
65197 res = nStr - pPKey2->aMem[0].n;
@@ -65221,11 +65352,11 @@
65352 ** is ignored as well. Hence, this routine only compares the prefixes
65353 ** of the keys prior to the final rowid, not the entire key.
65354 */
65355 SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
65356 VdbeCursor *pC, /* The cursor to compare against */
65357 UnpackedRecord *pUnpacked, /* Unpacked version of key */
65358 int *res /* Write the comparison result here */
65359 ){
65360 i64 nCellKey = 0;
65361 int rc;
65362 BtCursor *pCur = pC->pCursor;
@@ -67311,10 +67442,33 @@
67442 u8 affinity,
67443 u8 enc
67444 ){
67445 applyAffinity((Mem *)pVal, affinity, enc);
67446 }
67447
67448 /*
67449 ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
67450 ** none.
67451 **
67452 ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
67453 ** But it does set pMem->r and pMem->u.i appropriately.
67454 */
67455 static u16 numericType(Mem *pMem){
67456 if( pMem->flags & (MEM_Int|MEM_Real) ){
67457 return pMem->flags & (MEM_Int|MEM_Real);
67458 }
67459 if( pMem->flags & (MEM_Str|MEM_Blob) ){
67460 if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
67461 return 0;
67462 }
67463 if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
67464 return MEM_Int;
67465 }
67466 return MEM_Real;
67467 }
67468 return 0;
67469 }
67470
67471 #ifdef SQLITE_DEBUG
67472 /*
67473 ** Write a nice string representation of the contents of cell pMem
67474 ** into buffer zBuf, length nBuf.
@@ -68171,14 +68325,15 @@
68325 }
68326
68327 /* Opcode: Move P1 P2 P3 * *
68328 ** Synopsis: r[P2@P3]=r[P1@P3]
68329 **
68330 ** Move the P3 values in register P1..P1+P3-1 over into
68331 ** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
68332 ** left holding a NULL. It is an error for register ranges
68333 ** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error
68334 ** for P3 to be less than 1.
68335 */
68336 case OP_Move: {
68337 char *zMalloc; /* Holding variable for allocated memory */
68338 int n; /* Number of registers left to copy */
68339 int p1; /* Register to copy from */
@@ -68185,11 +68340,11 @@
68340 int p2; /* Register to copy to */
68341
68342 n = pOp->p3;
68343 p1 = pOp->p1;
68344 p2 = pOp->p2;
68345 assert( n>0 && p1>0 && p2>0 );
68346 assert( p1+n<=p2 || p2+n<=p1 );
68347
68348 pIn1 = &aMem[p1];
68349 pOut = &aMem[p2];
68350 do{
@@ -68209,11 +68364,11 @@
68364 pIn1->xDel = 0;
68365 pIn1->zMalloc = zMalloc;
68366 REGISTER_TRACE(p2++, pOut);
68367 pIn1++;
68368 pOut++;
68369 }while( --n );
68370 break;
68371 }
68372
68373 /* Opcode: Copy P1 P2 P3 * *
68374 ** Synopsis: r[P2@P3+1]=r[P1@P3+1]
@@ -68441,24 +68596,26 @@
68596 case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
68597 case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
68598 case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
68599 case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
68600 char bIntint; /* Started out as two integer operands */
68601 u16 flags; /* Combined MEM_* flags from both inputs */
68602 u16 type1; /* Numeric type of left operand */
68603 u16 type2; /* Numeric type of right operand */
68604 i64 iA; /* Integer value of left operand */
68605 i64 iB; /* Integer value of right operand */
68606 double rA; /* Real value of left operand */
68607 double rB; /* Real value of right operand */
68608
68609 pIn1 = &aMem[pOp->p1];
68610 type1 = numericType(pIn1);
68611 pIn2 = &aMem[pOp->p2];
68612 type2 = numericType(pIn2);
68613 pOut = &aMem[pOp->p3];
68614 flags = pIn1->flags | pIn2->flags;
68615 if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
68616 if( (type1 & type2 & MEM_Int)!=0 ){
68617 iA = pIn1->u.i;
68618 iB = pIn2->u.i;
68619 bIntint = 1;
68620 switch( pOp->opcode ){
68621 case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
@@ -68510,11 +68667,11 @@
68667 if( sqlite3IsNaN(rB) ){
68668 goto arithmetic_result_is_null;
68669 }
68670 pOut->r = rB;
68671 MemSetTypeFlag(pOut, MEM_Real);
68672 if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
68673 sqlite3VdbeIntegerAffinity(pOut);
68674 }
68675 #endif
68676 }
68677 break;
@@ -69086,10 +69243,11 @@
69243 aPermute = pOp->p4.ai;
69244 break;
69245 }
69246
69247 /* Opcode: Compare P1 P2 P3 P4 P5
69248 ** Synopsis: r[P1@P3] <-> r[P2@P3]
69249 **
69250 ** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
69251 ** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
69252 ** the comparison for use by the next OP_Jump instruct.
69253 **
@@ -70421,10 +70579,11 @@
70579 assert( pOp->p1>=0 );
70580 assert( pOp->p2>=0 );
70581 pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
70582 if( pCx==0 ) goto no_mem;
70583 pCx->nullRow = 1;
70584 pCx->isEphemeral = 1;
70585 rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
70586 BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
70587 if( rc==SQLITE_OK ){
70588 rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
70589 }
@@ -70911,11 +71070,11 @@
71070 pC->seekResult = res;
71071 break;
71072 }
71073
71074 /* Opcode: Sequence P1 P2 * * *
71075 ** Synopsis: r[P2]=cursor[P1].ctr++
71076 **
71077 ** Find the next available sequence number for cursor P1.
71078 ** Write the sequence number into register P2.
71079 ** The sequence number on the cursor is incremented after this
71080 ** instruction.
@@ -71602,10 +71761,11 @@
71761 VdbeCursor *pC;
71762 int res;
71763
71764 pC = p->apCsr[pOp->p1];
71765 assert( isSorter(pC) );
71766 res = 0;
71767 rc = sqlite3VdbeSorterNext(db, pC, &res);
71768 goto next_tail;
71769 case OP_PrevIfOpen: /* jump */
71770 case OP_NextIfOpen: /* jump */
71771 if( p->apCsr[pOp->p1]==0 ) break;
@@ -71959,10 +72119,33 @@
72119 aMem[pOp->p3].u.i += nChange;
72120 }
72121 }
72122 break;
72123 }
72124
72125 /* Opcode: ResetSorter P1 * * * *
72126 **
72127 ** Delete all contents from the ephemeral table or sorter
72128 ** that is open on cursor P1.
72129 **
72130 ** This opcode only works for cursors used for sorting and
72131 ** opened with OP_OpenEphemeral or OP_SorterOpen.
72132 */
72133 case OP_ResetSorter: {
72134 VdbeCursor *pC;
72135
72136 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
72137 pC = p->apCsr[pOp->p1];
72138 assert( pC!=0 );
72139 if( pC->pSorter ){
72140 sqlite3VdbeSorterReset(db, pC->pSorter);
72141 }else{
72142 assert( pC->isEphemeral );
72143 rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
72144 }
72145 break;
72146 }
72147
72148 /* Opcode: CreateTable P1 P2 * * *
72149 ** Synopsis: r[P2]=root iDb=P1
72150 **
72151 ** Allocate a new table in the main database file if P1==0 or in the
@@ -72266,13 +72449,11 @@
72449 }
72450
72451 assert( pOp->p4type==P4_INT32 );
72452 assert( iSet==-1 || iSet>=0 );
72453 if( iSet ){
72454 exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
 
 
72455 VdbeBranchTaken(exists!=0,2);
72456 if( exists ){
72457 pc = pOp->p2 - 1;
72458 break;
72459 }
@@ -72968,11 +73149,11 @@
73149 }
73150 #endif /* SQLITE_OMIT_VIRTUALTABLE */
73151
73152 #ifndef SQLITE_OMIT_VIRTUALTABLE
73153 /* Opcode: VFilter P1 P2 P3 P4 *
73154 ** Synopsis: iplan=r[P3] zplan='P4'
73155 **
73156 ** P1 is a cursor opened using VOpen. P2 is an address to jump to if
73157 ** the filtered result set is empty.
73158 **
73159 ** P4 is either NULL or a string that was generated by the xBestIndex
@@ -73536,13 +73717,11 @@
73717 p->pStmt = 0;
73718 }else{
73719 p->iOffset = pC->aType[p->iCol + pC->nField];
73720 p->nByte = sqlite3VdbeSerialTypeLen(type);
73721 p->pCsr = pC->pCursor;
73722 sqlite3BtreeIncrblobCursor(p->pCsr);
 
 
73723 }
73724 }
73725
73726 if( rc==SQLITE_ROW ){
73727 rc = SQLITE_OK;
@@ -74431,28 +74610,45 @@
74610 for(p=pRecord; p; p=pNext){
74611 pNext = p->pNext;
74612 sqlite3DbFree(db, p);
74613 }
74614 }
74615
74616 /*
74617 ** Reset a sorting cursor back to its original empty state.
74618 */
74619 SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
74620 if( pSorter->aIter ){
74621 int i;
74622 for(i=0; i<pSorter->nTree; i++){
74623 vdbeSorterIterZero(db, &pSorter->aIter[i]);
74624 }
74625 sqlite3DbFree(db, pSorter->aIter);
74626 pSorter->aIter = 0;
74627 }
74628 if( pSorter->pTemp1 ){
74629 sqlite3OsCloseFree(pSorter->pTemp1);
74630 pSorter->pTemp1 = 0;
74631 }
74632 vdbeSorterRecordFree(db, pSorter->pRecord);
74633 pSorter->pRecord = 0;
74634 pSorter->iWriteOff = 0;
74635 pSorter->iReadOff = 0;
74636 pSorter->nInMemory = 0;
74637 pSorter->nTree = 0;
74638 pSorter->nPMA = 0;
74639 pSorter->aTree = 0;
74640 }
74641
74642
74643 /*
74644 ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
74645 */
74646 SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
74647 VdbeSorter *pSorter = pCsr->pSorter;
74648 if( pSorter ){
74649 sqlite3VdbeSorterReset(db, pSorter);
 
 
 
 
 
 
 
 
 
 
74650 sqlite3DbFree(db, pSorter->pUnpacked);
74651 sqlite3DbFree(db, pSorter);
74652 pCsr->pSorter = 0;
74653 }
74654 }
@@ -74884,18 +75080,59 @@
75080 VdbeSorter *pSorter = pCsr->pSorter;
75081 int rc; /* Return code */
75082
75083 if( pSorter->aTree ){
75084 int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
 
 
75085 rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
75086 if( rc==SQLITE_OK ){
75087 int i; /* Index of aTree[] to recalculate */
75088 VdbeSorterIter *pIter1; /* First iterator to compare */
75089 VdbeSorterIter *pIter2; /* Second iterator to compare */
75090 u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */
75091
75092 /* Find the first two iterators to compare. The one that was just
75093 ** advanced (iPrev) and the one next to it in the array. */
75094 pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)];
75095 pIter2 = &pSorter->aIter[(iPrev | 0x0001)];
75096 pKey2 = pIter2->aKey;
75097
75098 for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){
75099 /* Compare pIter1 and pIter2. Store the result in variable iRes. */
75100 int iRes;
75101 if( pIter1->pFile==0 ){
75102 iRes = +1;
75103 }else if( pIter2->pFile==0 ){
75104 iRes = -1;
75105 }else{
75106 vdbeSorterCompare(pCsr, 0,
75107 pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes
75108 );
75109 }
75110
75111 /* If pIter1 contained the smaller value, set aTree[i] to its index.
75112 ** Then set pIter2 to the next iterator to compare to pIter1. In this
75113 ** case there is no cache of pIter2 in pSorter->pUnpacked, so set
75114 ** pKey2 to point to the record belonging to pIter2.
75115 **
75116 ** Alternatively, if pIter2 contains the smaller of the two values,
75117 ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare()
75118 ** was actually called above, then pSorter->pUnpacked now contains
75119 ** a value equivalent to pIter2. So set pKey2 to NULL to prevent
75120 ** vdbeSorterCompare() from decoding pIter2 again. */
75121 if( iRes<=0 ){
75122 pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter);
75123 pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
75124 pKey2 = pIter2->aKey;
75125 }else{
75126 if( pIter1->pFile ) pKey2 = 0;
75127 pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter);
75128 pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
75129 }
75130
75131 }
75132 *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
75133 }
 
 
75134 }else{
75135 SorterRecord *pFree = pSorter->pRecord;
75136 pSorter->pRecord = pFree->pNext;
75137 pFree->pNext = 0;
75138 vdbeSorterRecordFree(db, pFree);
@@ -77127,10 +77364,11 @@
77364 ** SELECT * FROM t1 WHERE (select a from t1);
77365 */
77366 SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
77367 int op;
77368 pExpr = sqlite3ExprSkipCollate(pExpr);
77369 if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
77370 op = pExpr->op;
77371 if( op==TK_SELECT ){
77372 assert( pExpr->flags&EP_xIsSelect );
77373 return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
77374 }
@@ -77159,11 +77397,15 @@
77397 ** implements the COLLATE operator.
77398 **
77399 ** If a memory allocation error occurs, that fact is recorded in pParse->db
77400 ** and the pExpr parameter is returned unchanged.
77401 */
77402 SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
77403 Parse *pParse, /* Parsing context */
77404 Expr *pExpr, /* Add the "COLLATE" clause to this expression */
77405 const Token *pCollName /* Name of collating sequence */
77406 ){
77407 if( pCollName->n>0 ){
77408 Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
77409 if( pNew ){
77410 pNew->pLeft = pExpr;
77411 pNew->flags |= EP_Collate|EP_Skip;
@@ -77212,10 +77454,11 @@
77454 sqlite3 *db = pParse->db;
77455 CollSeq *pColl = 0;
77456 Expr *p = pExpr;
77457 while( p ){
77458 int op = p->op;
77459 if( p->flags & EP_Generic ) break;
77460 if( op==TK_CAST || op==TK_UPLUS ){
77461 p = p->pLeft;
77462 continue;
77463 }
77464 if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
@@ -78043,11 +78286,10 @@
78286 struct ExprList_item *pItem, *pOldItem;
78287 int i;
78288 if( p==0 ) return 0;
78289 pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
78290 if( pNew==0 ) return 0;
 
78291 pNew->nExpr = i = p->nExpr;
78292 if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
78293 pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
78294 if( pItem==0 ){
78295 sqlite3DbFree(db, pNew);
@@ -78156,11 +78398,10 @@
78398 pNew->iLimit = 0;
78399 pNew->iOffset = 0;
78400 pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
78401 pNew->addrOpenEphm[0] = -1;
78402 pNew->addrOpenEphm[1] = -1;
 
78403 pNew->nSelectRow = p->nSelectRow;
78404 pNew->pWith = withDup(db, p->pWith);
78405 return pNew;
78406 }
78407 #else
@@ -78724,11 +78965,10 @@
78965 eType = IN_INDEX_EPH;
78966 if( prNotFound ){
78967 *prNotFound = rMayHaveNull = ++pParse->nMem;
78968 sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
78969 }else{
 
78970 pParse->nQueryLoop = 0;
78971 if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
78972 eType = IN_INDEX_ROWID;
78973 }
78974 }
@@ -78974,11 +79214,11 @@
79214 }
79215
79216 if( testAddr>=0 ){
79217 sqlite3VdbeJumpHere(v, testAddr);
79218 }
79219 sqlite3ExprCachePop(pParse);
79220
79221 return rReg;
79222 }
79223 #endif /* SQLITE_OMIT_SUBQUERY */
79224
@@ -79109,11 +79349,11 @@
79349 */
79350 sqlite3VdbeJumpHere(v, j1);
79351 }
79352 }
79353 sqlite3ReleaseTempReg(pParse, r1);
79354 sqlite3ExprCachePop(pParse);
79355 VdbeComment((v, "end IN expr"));
79356 }
79357 #endif /* SQLITE_OMIT_SUBQUERY */
79358
79359 /*
@@ -79292,19 +79532,18 @@
79532 #endif
79533 }
79534
79535 /*
79536 ** Remove from the column cache any entries that were added since the
79537 ** the previous sqlite3ExprCachePush operation. In other words, restore
79538 ** the cache to the state it was in prior the most recent Push.
79539 */
79540 SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
79541 int i;
79542 struct yColCache *p;
79543 assert( pParse->iCacheLevel>=1 );
79544 pParse->iCacheLevel--;
 
79545 #ifdef SQLITE_DEBUG
79546 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
79547 printf("POP to %d\n", pParse->iCacheLevel);
79548 }
79549 #endif
@@ -79429,11 +79668,11 @@
79668 */
79669 SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
79670 int i;
79671 struct yColCache *p;
79672 assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
79673 sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
79674 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
79675 int x = p->iReg;
79676 if( x>=iFrom && x<iFrom+nReg ){
79677 p->iReg += iTo-iFrom;
79678 }
@@ -79778,11 +80017,11 @@
80017 sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
80018 VdbeCoverage(v);
80019 sqlite3ExprCacheRemove(pParse, target, 1);
80020 sqlite3ExprCachePush(pParse);
80021 sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
80022 sqlite3ExprCachePop(pParse);
80023 }
80024 sqlite3VdbeResolveLabel(v, endCoalesce);
80025 break;
80026 }
80027
@@ -79830,13 +80069,13 @@
80069 pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
80070 }
80071 }
80072
80073 sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
80074 sqlite3ExprCodeExprList(pParse, pFarg, r1,
80075 SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
80076 sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
80077 }else{
80078 r1 = 0;
80079 }
80080 #ifndef SQLITE_OMIT_VIRTUALTABLE
80081 /* Possibly overload the function if the first argument is
@@ -80052,17 +80291,17 @@
80291 testcase( pTest->op==TK_COLUMN );
80292 sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
80293 testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
80294 sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
80295 sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
80296 sqlite3ExprCachePop(pParse);
80297 sqlite3VdbeResolveLabel(v, nextCase);
80298 }
80299 if( (nExpr&1)!=0 ){
80300 sqlite3ExprCachePush(pParse);
80301 sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
80302 sqlite3ExprCachePop(pParse);
80303 }else{
80304 sqlite3VdbeAddOp2(v, OP_Null, 0, target);
80305 }
80306 assert( db->mallocFailed || pParse->nErr>0
80307 || pParse->iCacheLevel==iCacheLevel );
@@ -80637,19 +80876,19 @@
80876 testcase( jumpIfNull==0 );
80877 sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
80878 sqlite3ExprCachePush(pParse);
80879 sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
80880 sqlite3VdbeResolveLabel(v, d2);
80881 sqlite3ExprCachePop(pParse);
80882 break;
80883 }
80884 case TK_OR: {
80885 testcase( jumpIfNull==0 );
80886 sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
80887 sqlite3ExprCachePush(pParse);
80888 sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
80889 sqlite3ExprCachePop(pParse);
80890 break;
80891 }
80892 case TK_NOT: {
80893 testcase( jumpIfNull==0 );
80894 sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
@@ -80791,21 +81030,21 @@
81030 case TK_AND: {
81031 testcase( jumpIfNull==0 );
81032 sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
81033 sqlite3ExprCachePush(pParse);
81034 sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
81035 sqlite3ExprCachePop(pParse);
81036 break;
81037 }
81038 case TK_OR: {
81039 int d2 = sqlite3VdbeMakeLabel(v);
81040 testcase( jumpIfNull==0 );
81041 sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
81042 sqlite3ExprCachePush(pParse);
81043 sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
81044 sqlite3VdbeResolveLabel(v, d2);
81045 sqlite3ExprCachePop(pParse);
81046 break;
81047 }
81048 case TK_NOT: {
81049 testcase( jumpIfNull==0 );
81050 sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
@@ -81465,10 +81704,11 @@
81704 unsigned const char *z; /* Pointer to token */
81705 int n; /* Length of token z */
81706 int token; /* Type of token */
81707
81708 UNUSED_PARAMETER(NotUsed);
81709 if( zInput==0 || zOld==0 ) return;
81710 for(z=zInput; *z; z=z+n){
81711 n = sqlite3GetToken(z, &token);
81712 if( token==TK_REFERENCES ){
81713 char *zParent;
81714 do {
@@ -87459,11 +87699,11 @@
87699 addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
87700 regRecord = sqlite3GetTempReg(pParse);
87701
87702 sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
87703 sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
87704 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
87705 sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
87706 sqlite3VdbeJumpHere(v, addr1);
87707 if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
87708 sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
87709 (char *)pKey, P4_KEYINFO);
@@ -90236,11 +90476,11 @@
90476 VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
90477 r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
90478 &iPartIdxLabel, pPrior, r1);
90479 sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
90480 pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
90481 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
90482 pPrior = pIdx;
90483 }
90484 }
90485
90486 /*
@@ -90255,14 +90495,15 @@
90495 ** block of registers has already been deallocated by the time
90496 ** this routine returns.
90497 **
90498 ** If *piPartIdxLabel is not NULL, fill it in with a label and jump
90499 ** to that label if pIdx is a partial index that should be skipped.
90500 ** The label should be resolved using sqlite3ResolvePartIdxLabel().
90501 ** A partial index should be skipped if its WHERE clause evaluates
90502 ** to false or null. If pIdx is not a partial index, *piPartIdxLabel
90503 ** will be set to zero which is an empty label that is ignored by
90504 ** sqlite3ResolvePartIdxLabel().
90505 **
90506 ** The pPrior and regPrior parameters are used to implement a cache to
90507 ** avoid unnecessary register loads. If pPrior is not NULL, then it is
90508 ** a pointer to a different index for which an index key has just been
90509 ** computed into register regPrior. If the current pIdx index is generating
@@ -90291,10 +90532,11 @@
90532
90533 if( piPartIdxLabel ){
90534 if( pIdx->pPartIdxWhere ){
90535 *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
90536 pParse->iPartIdxTab = iDataCur;
90537 sqlite3ExprCachePush(pParse);
90538 sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
90539 SQLITE_JUMPIFNULL);
90540 }else{
90541 *piPartIdxLabel = 0;
90542 }
@@ -90318,10 +90560,22 @@
90560 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
90561 }
90562 sqlite3ReleaseTempRange(pParse, regBase, nCol);
90563 return regBase;
90564 }
90565
90566 /*
90567 ** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
90568 ** because it was a partial index, then this routine should be called to
90569 ** resolve that label.
90570 */
90571 SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
90572 if( iLabel ){
90573 sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
90574 sqlite3ExprCachePop(pParse);
90575 }
90576 }
90577
90578 /************** End of delete.c **********************************************/
90579 /************** Begin file func.c ********************************************/
90580 /*
90581 ** 2002 February 23
@@ -98716,11 +98970,11 @@
98970 sqlite3VdbeChangeP5(v, (u8)i);
98971 addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
98972 sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
98973 sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
98974 P4_DYNAMIC);
98975 sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
98976 sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
98977 sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
98978 sqlite3VdbeJumpHere(v, addr);
98979
98980 /* Make sure all the indices are constructed correctly.
@@ -98769,11 +99023,11 @@
99023 sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
99024 jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
99025 sqlite3VdbeAddOp0(v, OP_Halt);
99026 sqlite3VdbeJumpHere(v, jmp4);
99027 sqlite3VdbeJumpHere(v, jmp2);
99028 sqlite3ResolvePartIdxLabel(pParse, jmp3);
99029 }
99030 sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
99031 sqlite3VdbeJumpHere(v, loopTop-1);
99032 #ifndef SQLITE_OMIT_BTREECOUNT
99033 sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
@@ -100054,10 +100308,38 @@
100308 *************************************************************************
100309 ** This file contains C code routines that are called by the parser
100310 ** to handle SELECT statements in SQLite.
100311 */
100312
100313 /*
100314 ** An instance of the following object is used to record information about
100315 ** how to process the DISTINCT keyword, to simplify passing that information
100316 ** into the selectInnerLoop() routine.
100317 */
100318 typedef struct DistinctCtx DistinctCtx;
100319 struct DistinctCtx {
100320 u8 isTnct; /* True if the DISTINCT keyword is present */
100321 u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
100322 int tabTnct; /* Ephemeral table used for DISTINCT processing */
100323 int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
100324 };
100325
100326 /*
100327 ** An instance of the following object is used to record information about
100328 ** the ORDER BY (or GROUP BY) clause of query is being coded.
100329 */
100330 typedef struct SortCtx SortCtx;
100331 struct SortCtx {
100332 ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
100333 int nOBSat; /* Number of ORDER BY terms satisfied by indices */
100334 int iECursor; /* Cursor number for the sorter */
100335 int regReturn; /* Register holding block-output return address */
100336 int labelBkOut; /* Start label for the block-output subroutine */
100337 int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
100338 u8 sortFlags; /* Zero or more SORTFLAG_* bits */
100339 };
100340 #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
100341
100342 /*
100343 ** Delete all the content of a Select structure but do not deallocate
100344 ** the select structure itself.
100345 */
@@ -100127,11 +100409,10 @@
100409 pNew->pLimit = pLimit;
100410 pNew->pOffset = pOffset;
100411 assert( pOffset==0 || pLimit!=0 );
100412 pNew->addrOpenEphm[0] = -1;
100413 pNew->addrOpenEphm[1] = -1;
 
100414 if( db->mallocFailed ) {
100415 clearSelect(db, pNew);
100416 if( pNew!=&standin ) sqlite3DbFree(db, pNew);
100417 pNew = 0;
100418 }else{
@@ -100459,38 +100740,79 @@
100740 }
100741 }
100742 return 0;
100743 }
100744
100745 /* Forward reference */
100746 static KeyInfo *keyInfoFromExprList(
100747 Parse *pParse, /* Parsing context */
100748 ExprList *pList, /* Form the KeyInfo object from this ExprList */
100749 int iStart, /* Begin with this column of pList */
100750 int nExtra /* Add this many extra columns to the end */
100751 );
100752
100753 /*
100754 ** Insert code into "v" that will push the record in register regData
100755 ** into the sorter.
100756 */
100757 static void pushOntoSorter(
100758 Parse *pParse, /* Parser context */
100759 SortCtx *pSort, /* Information about the ORDER BY clause */
100760 Select *pSelect, /* The whole SELECT statement */
100761 int regData /* Register holding data to be sorted */
100762 ){
100763 Vdbe *v = pParse->pVdbe;
100764 int nExpr = pSort->pOrderBy->nExpr;
100765 int regBase = sqlite3GetTempRange(pParse, nExpr+2);
100766 int regRecord = sqlite3GetTempReg(pParse);
100767 int nOBSat = pSort->nOBSat;
100768 int op;
100769 sqlite3ExprCacheClear(pParse);
100770 sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
100771 sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
100772 sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
100773 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat, regRecord);
100774 if( nOBSat>0 ){
100775 int regPrevKey; /* The first nOBSat columns of the previous row */
100776 int addrFirst; /* Address of the OP_IfNot opcode */
100777 int addrJmp; /* Address of the OP_Jump opcode */
100778 VdbeOp *pOp; /* Opcode that opens the sorter */
100779 int nKey; /* Number of sorting key columns, including OP_Sequence */
100780 KeyInfo *pKI; /* Original KeyInfo on the sorter table */
100781
100782 regPrevKey = pParse->nMem+1;
100783 pParse->nMem += pSort->nOBSat;
100784 nKey = nExpr - pSort->nOBSat + 1;
100785 addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v);
100786 sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
100787 pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
100788 if( pParse->db->mallocFailed ) return;
100789 pOp->p2 = nKey + 1;
100790 pKI = pOp->p4.pKeyInfo;
100791 memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
100792 sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
100793 pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
100794 addrJmp = sqlite3VdbeCurrentAddr(v);
100795 sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
100796 pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
100797 pSort->regReturn = ++pParse->nMem;
100798 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
100799 sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
100800 sqlite3VdbeJumpHere(v, addrFirst);
100801 sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
100802 sqlite3VdbeJumpHere(v, addrJmp);
100803 }
100804 if( pSort->sortFlags & SORTFLAG_UseSorter ){
100805 op = OP_SorterInsert;
100806 }else{
100807 op = OP_IdxInsert;
100808 }
100809 sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
100810 if( nOBSat==0 ){
100811 sqlite3ReleaseTempReg(pParse, regRecord);
100812 sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
100813 }
100814 if( pSelect->iLimit ){
100815 int addr1, addr2;
100816 int iLimit;
100817 if( pSelect->iOffset ){
100818 iLimit = pSelect->iOffset+1;
@@ -100499,12 +100821,12 @@
100821 }
100822 addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
100823 sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
100824 addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
100825 sqlite3VdbeJumpHere(v, addr1);
100826 sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
100827 sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
100828 sqlite3VdbeJumpHere(v, addr2);
100829 }
100830 }
100831
100832 /*
@@ -100513,11 +100835,11 @@
100835 static void codeOffset(
100836 Vdbe *v, /* Generate code into this VM */
100837 int iOffset, /* Register holding the offset counter */
100838 int iContinue /* Jump here to skip the current record */
100839 ){
100840 if( iOffset>0 ){
100841 int addr;
100842 sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
100843 addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
100844 sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
100845 VdbeComment((v, "skip OFFSET records"));
@@ -100574,23 +100896,10 @@
100896 return 0;
100897 }
100898 }
100899 #endif
100900
 
 
 
 
 
 
 
 
 
 
 
 
 
100901 /*
100902 ** This routine generates the code for the inside of the inner loop
100903 ** of a SELECT.
100904 **
100905 ** If srcTab is negative, then the pEList expressions
@@ -100601,11 +100910,11 @@
100910 static void selectInnerLoop(
100911 Parse *pParse, /* The parser context */
100912 Select *p, /* The complete select statement being coded */
100913 ExprList *pEList, /* List of values being extracted */
100914 int srcTab, /* Pull data from this table */
100915 SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
100916 DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
100917 SelectDest *pDest, /* How to dispose of the results */
100918 int iContinue, /* Jump here to continue with next row */
100919 int iBreak /* Jump here to break out of the inner loop */
100920 ){
@@ -100618,11 +100927,13 @@
100927 int nResultCol; /* Number of result columns */
100928
100929 assert( v );
100930 assert( pEList!=0 );
100931 hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
100932 if( pSort && pSort->pOrderBy==0 ) pSort = 0;
100933 if( pSort==0 && !hasDistinct ){
100934 assert( iContinue!=0 );
100935 codeOffset(v, p->iOffset, iContinue);
100936 }
100937
100938 /* Pull the requested columns.
100939 */
@@ -100708,11 +101019,11 @@
101019 assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
101020 codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
101021 break;
101022 }
101023 }
101024 if( pSort==0 ){
101025 codeOffset(v, p->iOffset, iContinue);
101026 }
101027 }
101028
101029 switch( eDest ){
@@ -100739,32 +101050,33 @@
101050 }
101051 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
101052
101053 /* Store the result as data using a unique key.
101054 */
101055 case SRT_Fifo:
101056 case SRT_DistFifo:
101057 case SRT_Table:
101058 case SRT_EphemTab: {
101059 int r1 = sqlite3GetTempReg(pParse);
101060 testcase( eDest==SRT_Table );
101061 testcase( eDest==SRT_EphemTab );
101062 sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
101063 #ifndef SQLITE_OMIT_CTE
101064 if( eDest==SRT_DistFifo ){
101065 /* If the destination is DistFifo, then cursor (iParm+1) is open
101066 ** on an ephemeral index. If the current row is already present
101067 ** in the index, do not write it to the output. If not, add the
101068 ** current row to the index and proceed with writing it to the
101069 ** output table as well. */
101070 int addr = sqlite3VdbeCurrentAddr(v) + 4;
101071 sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
101072 sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
101073 assert( pSort==0 );
101074 }
101075 #endif
101076 if( pSort ){
101077 pushOntoSorter(pParse, pSort, p, r1);
101078 }else{
101079 int r2 = sqlite3GetTempReg(pParse);
101080 sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
101081 sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
101082 sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -100781,16 +101093,16 @@
101093 */
101094 case SRT_Set: {
101095 assert( nResultCol==1 );
101096 pDest->affSdst =
101097 sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
101098 if( pSort ){
101099 /* At first glance you would think we could optimize out the
101100 ** ORDER BY in this case since the order of entries in the set
101101 ** does not matter. But there might be a LIMIT clause, in which
101102 ** case the order does matter */
101103 pushOntoSorter(pParse, pSort, p, regResult);
101104 }else{
101105 int r1 = sqlite3GetTempReg(pParse);
101106 sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
101107 sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
101108 sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
@@ -100811,12 +101123,12 @@
101123 ** store the results in the appropriate memory cell and break out
101124 ** of the scan loop.
101125 */
101126 case SRT_Mem: {
101127 assert( nResultCol==1 );
101128 if( pSort ){
101129 pushOntoSorter(pParse, pSort, p, regResult);
101130 }else{
101131 sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
101132 /* The LIMIT clause will jump out of the loop for us */
101133 }
101134 break;
@@ -100825,14 +101137,14 @@
101137
101138 case SRT_Coroutine: /* Send data to a co-routine */
101139 case SRT_Output: { /* Return the results */
101140 testcase( eDest==SRT_Coroutine );
101141 testcase( eDest==SRT_Output );
101142 if( pSort ){
101143 int r1 = sqlite3GetTempReg(pParse);
101144 sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
101145 pushOntoSorter(pParse, pSort, p, r1);
101146 sqlite3ReleaseTempReg(pParse, r1);
101147 }else if( eDest==SRT_Coroutine ){
101148 sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
101149 }else{
101150 sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
@@ -100905,11 +101217,11 @@
101217
101218 /* Jump to the end of the loop if the LIMIT is reached. Except, if
101219 ** there is a sorter, in which case the sorter has already limited
101220 ** the output for us.
101221 */
101222 if( pSort==0 && p->iLimit ){
101223 sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
101224 }
101225 }
101226
101227 /*
@@ -100976,27 +101288,32 @@
101288 **
101289 ** Space to hold the KeyInfo structure is obtain from malloc. The calling
101290 ** function is responsible for seeing that this structure is eventually
101291 ** freed.
101292 */
101293 static KeyInfo *keyInfoFromExprList(
101294 Parse *pParse, /* Parsing context */
101295 ExprList *pList, /* Form the KeyInfo object from this ExprList */
101296 int iStart, /* Begin with this column of pList */
101297 int nExtra /* Add this many extra columns to the end */
101298 ){
101299 int nExpr;
101300 KeyInfo *pInfo;
101301 struct ExprList_item *pItem;
101302 sqlite3 *db = pParse->db;
101303 int i;
101304
101305 nExpr = pList->nExpr;
101306 pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
101307 if( pInfo ){
101308 assert( sqlite3KeyInfoIsWriteable(pInfo) );
101309 for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
101310 CollSeq *pColl;
101311 pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
101312 if( !pColl ) pColl = db->pDfltColl;
101313 pInfo->aColl[i-iStart] = pColl;
101314 pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
101315 }
101316 }
101317 return pInfo;
101318 }
101319
@@ -101094,50 +101411,60 @@
101411 ** routine generates the code needed to do that.
101412 */
101413 static void generateSortTail(
101414 Parse *pParse, /* Parsing context */
101415 Select *p, /* The SELECT statement */
101416 SortCtx *pSort, /* Information on the ORDER BY clause */
101417 int nColumn, /* Number of columns of data */
101418 SelectDest *pDest /* Write the sorted results here */
101419 ){
101420 Vdbe *v = pParse->pVdbe; /* The prepared statement */
101421 int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
101422 int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
101423 int addr;
101424 int addrOnce = 0;
101425 int iTab;
101426 int pseudoTab = 0;
101427 ExprList *pOrderBy = pSort->pOrderBy;
 
101428 int eDest = pDest->eDest;
101429 int iParm = pDest->iSDParm;
 
101430 int regRow;
101431 int regRowid;
101432 int nKey;
101433
101434 if( pSort->labelBkOut ){
101435 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
101436 sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
101437 sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
101438 addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
101439 }
101440 iTab = pSort->iECursor;
101441 regRow = sqlite3GetTempReg(pParse);
101442 if( eDest==SRT_Output || eDest==SRT_Coroutine ){
101443 pseudoTab = pParse->nTab++;
101444 sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
101445 regRowid = 0;
101446 }else{
101447 regRowid = sqlite3GetTempReg(pParse);
101448 }
101449 nKey = pOrderBy->nExpr - pSort->nOBSat;
101450 if( pSort->sortFlags & SORTFLAG_UseSorter ){
101451 int regSortOut = ++pParse->nMem;
101452 int ptab2 = pParse->nTab++;
101453 sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2);
101454 if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
101455 addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
101456 VdbeCoverage(v);
101457 codeOffset(v, p->iOffset, addrContinue);
101458 sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
101459 sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow);
101460 sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
101461 }else{
101462 if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
101463 addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
101464 codeOffset(v, p->iOffset, addrContinue);
101465 sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow);
101466 }
101467 switch( eDest ){
101468 case SRT_Table:
101469 case SRT_EphemTab: {
101470 testcase( eDest==SRT_Table );
@@ -101188,15 +101515,16 @@
101515 sqlite3ReleaseTempReg(pParse, regRowid);
101516
101517 /* The bottom of the loop
101518 */
101519 sqlite3VdbeResolveLabel(v, addrContinue);
101520 if( pSort->sortFlags & SORTFLAG_UseSorter ){
101521 sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
101522 }else{
101523 sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
101524 }
101525 if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
101526 sqlite3VdbeResolveLabel(v, addrBreak);
101527 if( eDest==SRT_Output || eDest==SRT_Coroutine ){
101528 sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
101529 }
101530 }
@@ -101874,11 +102202,11 @@
102202 int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
102203 int iCurrent = 0; /* The Current table */
102204 int regCurrent; /* Register holding Current table */
102205 int iQueue; /* The Queue table */
102206 int iDistinct = 0; /* To ensure unique results if UNION */
102207 int eDest = SRT_Fifo; /* How to write to Queue */
102208 SelectDest destQueue; /* SelectDest targetting the Queue table */
102209 int i; /* Loop counter */
102210 int rc; /* Result code */
102211 ExprList *pOrderBy; /* The ORDER BY clause */
102212 Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */
@@ -101906,17 +102234,17 @@
102234 }
102235 }
102236
102237 /* Allocate cursors numbers for Queue and Distinct. The cursor number for
102238 ** the Distinct table must be exactly one greater than Queue in order
102239 ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */
102240 iQueue = pParse->nTab++;
102241 if( p->op==TK_UNION ){
102242 eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
102243 iDistinct = pParse->nTab++;
102244 }else{
102245 eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
102246 }
102247 sqlite3SelectDestInit(&destQueue, eDest, iQueue);
102248
102249 /* Allocate cursors for Current, Queue, and Distinct. */
102250 regCurrent = ++pParse->nMem;
@@ -101978,10 +102306,11 @@
102306 /* Keep running the loop until the Queue is empty */
102307 sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
102308 sqlite3VdbeResolveLabel(v, addrBreak);
102309
102310 end_of_recursive_query:
102311 sqlite3ExprListDelete(pParse->db, p->pOrderBy);
102312 p->pOrderBy = pOrderBy;
102313 p->pLimit = pLimit;
102314 p->pOffset = pOffset;
102315 return;
102316 }
@@ -104349,11 +104678,11 @@
104678 if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
104679 sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
104680 "argument");
104681 pFunc->iDistinct = -1;
104682 }else{
104683 KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
104684 sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
104685 (char*)pKeyInfo, P4_KEYINFO);
104686 }
104687 }
104688 }
@@ -104504,16 +104833,15 @@
104833 Vdbe *v; /* The virtual machine under construction */
104834 int isAgg; /* True for select lists like "count(*)" */
104835 ExprList *pEList; /* List of columns to extract. */
104836 SrcList *pTabList; /* List of tables to select from */
104837 Expr *pWhere; /* The WHERE clause. May be NULL */
 
104838 ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
104839 Expr *pHaving; /* The HAVING clause. May be NULL */
104840 int rc = 1; /* Value to return from this function */
 
104841 DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
104842 SortCtx sSort; /* Info on how to code the ORDER BY clause */
104843 AggInfo sAggInfo; /* Information used by aggregate queries */
104844 int iEnd; /* Address of the end of the query */
104845 sqlite3 *db; /* The database connection */
104846
104847 #ifndef SQLITE_OMIT_EXPLAIN
@@ -104526,21 +104854,28 @@
104854 return 1;
104855 }
104856 if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
104857 memset(&sAggInfo, 0, sizeof(sAggInfo));
104858
104859 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
104860 assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
104861 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
104862 assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
104863 if( IgnorableOrderby(pDest) ){
104864 assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
104865 pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
104866 pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
104867 pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
104868 /* If ORDER BY makes no difference in the output then neither does
104869 ** DISTINCT so it can be removed too. */
104870 sqlite3ExprListDelete(db, p->pOrderBy);
104871 p->pOrderBy = 0;
104872 p->selFlags &= ~SF_Distinct;
104873 }
104874 sqlite3SelectPrep(pParse, p, 0);
104875 memset(&sSort, 0, sizeof(sSort));
104876 sSort.pOrderBy = p->pOrderBy;
104877 pTabList = p->pSrc;
104878 pEList = p->pEList;
104879 if( pParse->nErr || db->mallocFailed ){
104880 goto select_end;
104881 }
@@ -104658,11 +104993,11 @@
104993 goto select_end;
104994 }
104995 pParse->nHeight -= sqlite3SelectExprHeight(p);
104996 pTabList = p->pSrc;
104997 if( !IgnorableOrderby(pDest) ){
104998 sSort.pOrderBy = p->pOrderBy;
104999 }
105000 }
105001 pEList = p->pEList;
105002 #endif
105003 pWhere = p->pWhere;
@@ -104685,13 +105020,13 @@
105020 ** will cause elements to come out in the correct order. This is
105021 ** an optimization - the correct answer should result regardless.
105022 ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
105023 ** to disable this optimization for testing purposes.
105024 */
105025 if( sqlite3ExprListCompare(p->pGroupBy, sSort.pOrderBy, -1)==0
105026 && OptimizationEnabled(db, SQLITE_GroupByOrder) ){
105027 sSort.pOrderBy = 0;
105028 }
105029
105030 /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
105031 ** if the select-list is the same as the ORDER BY list, then this query
105032 ** can be rewritten as a GROUP BY. In other words, this:
@@ -104706,16 +105041,16 @@
105041 ** used for both the ORDER BY and DISTINCT processing. As originally
105042 ** written the query must use a temp-table for at least one of the ORDER
105043 ** BY and DISTINCT, and an index or separate temp-table for the other.
105044 */
105045 if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
105046 && sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
105047 ){
105048 p->selFlags &= ~SF_Distinct;
105049 p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
105050 pGroupBy = p->pGroupBy;
105051 sSort.pOrderBy = 0;
105052 /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
105053 ** the sDistinct.isTnct is still set. Hence, isTnct represents the
105054 ** original setting of the SF_Distinct flag, not the current setting */
105055 assert( sDistinct.isTnct );
105056 }
@@ -104725,20 +105060,20 @@
105060 ** extracted in pre-sorted order. If that is the case, then the
105061 ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
105062 ** we figure out that the sorting index is not needed. The addrSortIndex
105063 ** variable is used to facilitate that change.
105064 */
105065 if( sSort.pOrderBy ){
105066 KeyInfo *pKeyInfo;
105067 pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
105068 sSort.iECursor = pParse->nTab++;
105069 sSort.addrSortIndex =
105070 sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
105071 sSort.iECursor, sSort.pOrderBy->nExpr+2, 0,
105072 (char*)pKeyInfo, P4_KEYINFO);
105073 }else{
105074 sSort.addrSortIndex = -1;
105075 }
105076
105077 /* If the output is destined for a temporary table, open that table.
105078 */
105079 if( pDest->eDest==SRT_EphemTab ){
@@ -104748,22 +105083,22 @@
105083 /* Set the limiter.
105084 */
105085 iEnd = sqlite3VdbeMakeLabel(v);
105086 p->nSelectRow = LARGEST_INT64;
105087 computeLimitRegisters(pParse, p, iEnd);
105088 if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
105089 sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
105090 sSort.sortFlags |= SORTFLAG_UseSorter;
105091 }
105092
105093 /* Open a virtual index to use for the distinct set.
105094 */
105095 if( p->selFlags & SF_Distinct ){
105096 sDistinct.tabTnct = pParse->nTab++;
105097 sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
105098 sDistinct.tabTnct, 0, 0,
105099 (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
105100 P4_KEYINFO);
105101 sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
105102 sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
105103 }else{
105104 sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
@@ -104772,32 +105107,36 @@
105107 if( !isAgg && pGroupBy==0 ){
105108 /* No aggregate functions and no GROUP BY clause */
105109 u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
105110
105111 /* Begin the database scan. */
105112 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
105113 p->pEList, wctrlFlags, 0);
105114 if( pWInfo==0 ) goto select_end;
105115 if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
105116 p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
105117 }
105118 if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
105119 sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
105120 }
105121 if( sSort.pOrderBy ){
105122 sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
105123 if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
105124 sSort.pOrderBy = 0;
105125 }
105126 }
105127
105128 /* If sorting index that was created by a prior OP_OpenEphemeral
105129 ** instruction ended up not being needed, then change the OP_OpenEphemeral
105130 ** into an OP_Noop.
105131 */
105132 if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
105133 sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
 
105134 }
105135
105136 /* Use the standard inner loop. */
105137 selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
105138 sqlite3WhereContinueLabel(pWInfo),
105139 sqlite3WhereBreakLabel(pWInfo));
105140
105141 /* End the database scan loop.
105142 */
@@ -104849,11 +105188,11 @@
105188 sNC.pAggInfo = &sAggInfo;
105189 sAggInfo.mnReg = pParse->nMem+1;
105190 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
105191 sAggInfo.pGroupBy = pGroupBy;
105192 sqlite3ExprAnalyzeAggList(&sNC, pEList);
105193 sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
105194 if( pHaving ){
105195 sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
105196 }
105197 sAggInfo.nAccumulator = sAggInfo.nColumn;
105198 for(i=0; i<sAggInfo.nFunc; i++){
@@ -104883,11 +105222,11 @@
105222 ** implement it. Allocate that sorting index now. If it turns out
105223 ** that we do not need it after all, the OP_SorterOpen instruction
105224 ** will be converted into a Noop.
105225 */
105226 sAggInfo.sortingIdx = pParse->nTab++;
105227 pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
105228 addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
105229 sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
105230 0, (char*)pKeyInfo, P4_KEYINFO);
105231
105232 /* Initialize memory locations used by GROUP BY aggregate processing
@@ -104912,14 +105251,14 @@
105251 ** This might involve two separate loops with an OP_Sort in between, or
105252 ** it might be a single loop that uses an index to extract information
105253 ** in the right order to begin with.
105254 */
105255 sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
105256 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
105257 WHERE_GROUPBY, 0);
105258 if( pWInfo==0 ) goto select_end;
105259 if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
105260 /* The optimizer is able to deliver rows in group by order so
105261 ** we do not have to sort. The OP_OpenEphemeral table will be
105262 ** cancelled later because we still need to use the pKeyInfo
105263 */
105264 groupBySort = 0;
@@ -105066,11 +105405,11 @@
105405 sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
105406 VdbeComment((v, "Groupby result generator entry point"));
105407 sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
105408 finalizeAggFunctions(pParse, &sAggInfo);
105409 sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
105410 selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
105411 &sDistinct, pDest,
105412 addrOutputRow+1, addrSetAbort);
105413 sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
105414 VdbeComment((v, "end groupby result generator"));
105415
@@ -105198,20 +105537,20 @@
105537 sqlite3ExprListDelete(db, pDel);
105538 goto select_end;
105539 }
105540 updateAccumulator(pParse, &sAggInfo);
105541 assert( pMinMax==0 || pMinMax->nExpr==1 );
105542 if( sqlite3WhereIsOrdered(pWInfo)>0 ){
105543 sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
105544 VdbeComment((v, "%s() by index",
105545 (flag==WHERE_ORDERBY_MIN?"min":"max")));
105546 }
105547 sqlite3WhereEnd(pWInfo);
105548 finalizeAggFunctions(pParse, &sAggInfo);
105549 }
105550
105551 sSort.pOrderBy = 0;
105552 sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
105553 selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
105554 pDest, addrEnd, addrEnd);
105555 sqlite3ExprListDelete(db, pDel);
105556 }
@@ -105224,13 +105563,13 @@
105563 }
105564
105565 /* If there is an ORDER BY clause, then we need to sort the results
105566 ** and send them to the callback one by one.
105567 */
105568 if( sSort.pOrderBy ){
105569 explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
105570 generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
105571 }
105572
105573 /* Jump here to skip this query
105574 */
105575 sqlite3VdbeResolveLabel(v, iEnd);
@@ -109064,11 +109403,11 @@
109403 Index *pIndex; /* Index used, or NULL */
109404 } btree;
109405 struct { /* Information for virtual tables */
109406 int idxNum; /* Index number */
109407 u8 needFree; /* True if sqlite3_free(idxStr) is needed */
109408 i8 isOrdered; /* True if satisfies ORDER BY */
109409 u16 omitMask; /* Terms that may be omitted */
109410 char *idxStr; /* Index identifier string */
109411 } vtab;
109412 } u;
109413 u32 wsFlags; /* WHERE_* flags describing the plan */
@@ -109126,12 +109465,11 @@
109465 struct WherePath {
109466 Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
109467 Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
109468 LogEst nRow; /* Estimated number of rows generated by this path */
109469 LogEst rCost; /* Total cost of this path */
109470 i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
 
109471 WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
109472 };
109473
109474 /*
109475 ** The query generator uses an array of instances of this structure to
@@ -109341,11 +109679,11 @@
109679 ExprList *pResultSet; /* Result set. DISTINCT operates on these */
109680 WhereLoop *pLoops; /* List of all WhereLoop objects */
109681 Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
109682 LogEst nRowOut; /* Estimated number of output rows */
109683 u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
109684 i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
109685 u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
109686 u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
109687 u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
109688 u8 nLevel; /* Number of nested loop */
109689 int iTop; /* The very beginning of the WHERE loop */
@@ -109425,18 +109763,19 @@
109763 /*
109764 ** Return TRUE if the WHERE clause returns rows in ORDER BY order.
109765 ** Return FALSE if the output needs to be sorted.
109766 */
109767 SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
109768 return pWInfo->nOBSat;
109769 }
109770
109771 /*
109772 ** Return the VDBE address or label to jump to in order to continue
109773 ** immediately with the next row of a WHERE clause.
109774 */
109775 SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
109776 assert( pWInfo->iContinue!=0 );
109777 return pWInfo->iContinue;
109778 }
109779
109780 /*
109781 ** Return the VDBE address or label to jump to in order to break
@@ -112226,11 +112565,11 @@
112565 }
112566 pLevel->op = OP_VNext;
112567 pLevel->p1 = iCur;
112568 pLevel->p2 = sqlite3VdbeCurrentAddr(v);
112569 sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
112570 sqlite3ExprCachePop(pParse);
112571 }else
112572 #endif /* SQLITE_OMIT_VIRTUALTABLE */
112573
112574 if( (pLoop->wsFlags & WHERE_IPK)!=0
112575 && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
@@ -112422,12 +112761,15 @@
112761 ** a single iteration. This means that the first row returned
112762 ** should not have a NULL value stored in 'x'. If column 'x' is
112763 ** the first one after the nEq equality constraints in the index,
112764 ** this requires some special handling.
112765 */
112766 assert( pWInfo->pOrderBy==0
112767 || pWInfo->pOrderBy->nExpr==1
112768 || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
112769 if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
112770 && pWInfo->nOBSat>0
112771 && (pIdx->nKeyCol>nEq)
112772 ){
112773 assert( pLoop->u.btree.nSkip==0 );
112774 bSeekPastNull = 1;
112775 nExtraReg = 1;
@@ -112594,12 +112936,11 @@
112936 pLevel->op = OP_Prev;
112937 }else{
112938 pLevel->op = OP_Next;
112939 }
112940 pLevel->p1 = iIdxCur;
112941 pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
 
112942 if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
112943 pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
112944 }else{
112945 assert( pLevel->p5==0 );
112946 }
@@ -113093,10 +113434,141 @@
113434 whereLoopDelete(db, p);
113435 }
113436 sqlite3DbFree(db, pWInfo);
113437 }
113438 }
113439
113440 /*
113441 ** Return TRUE if both of the following are true:
113442 **
113443 ** (1) X has the same or lower cost that Y
113444 ** (2) X is a proper subset of Y
113445 **
113446 ** By "proper subset" we mean that X uses fewer WHERE clause terms
113447 ** than Y and that every WHERE clause term used by X is also used
113448 ** by Y.
113449 **
113450 ** If X is a proper subset of Y then Y is a better choice and ought
113451 ** to have a lower cost. This routine returns TRUE when that cost
113452 ** relationship is inverted and needs to be adjusted.
113453 */
113454 static int whereLoopCheaperProperSubset(
113455 const WhereLoop *pX, /* First WhereLoop to compare */
113456 const WhereLoop *pY /* Compare against this WhereLoop */
113457 ){
113458 int i, j;
113459 if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
113460 if( pX->rRun >= pY->rRun ){
113461 if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
113462 if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
113463 }
113464 for(j=0, i=pX->nLTerm-1; i>=0; i--){
113465 for(j=pY->nLTerm-1; j>=0; j--){
113466 if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
113467 }
113468 if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
113469 }
113470 return 1; /* All conditions meet */
113471 }
113472
113473 /*
113474 ** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
113475 ** that:
113476 **
113477 ** (1) pTemplate costs less than any other WhereLoops that are a proper
113478 ** subset of pTemplate
113479 **
113480 ** (2) pTemplate costs more than any other WhereLoops for which pTemplate
113481 ** is a proper subset.
113482 **
113483 ** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
113484 ** WHERE clause terms than Y and that every WHERE clause term used by X is
113485 ** also used by Y.
113486 */
113487 static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
113488 if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
113489 for(; p; p=p->pNextLoop){
113490 if( p->iTab!=pTemplate->iTab ) continue;
113491 if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
113492 if( whereLoopCheaperProperSubset(p, pTemplate) ){
113493 /* Adjust pTemplate cost downward so that it is cheaper than its
113494 ** subset p */
113495 pTemplate->rRun = p->rRun;
113496 pTemplate->nOut = p->nOut - 1;
113497 }else if( whereLoopCheaperProperSubset(pTemplate, p) ){
113498 /* Adjust pTemplate cost upward so that it is costlier than p since
113499 ** pTemplate is a proper subset of p */
113500 pTemplate->rRun = p->rRun;
113501 pTemplate->nOut = p->nOut + 1;
113502 }
113503 }
113504 }
113505
113506 /*
113507 ** Search the list of WhereLoops in *ppPrev looking for one that can be
113508 ** supplanted by pTemplate.
113509 **
113510 ** Return NULL if the WhereLoop list contains an entry that can supplant
113511 ** pTemplate, in other words if pTemplate does not belong on the list.
113512 **
113513 ** If pX is a WhereLoop that pTemplate can supplant, then return the
113514 ** link that points to pX.
113515 **
113516 ** If pTemplate cannot supplant any existing element of the list but needs
113517 ** to be added to the list, then return a pointer to the tail of the list.
113518 */
113519 static WhereLoop **whereLoopFindLesser(
113520 WhereLoop **ppPrev,
113521 const WhereLoop *pTemplate
113522 ){
113523 WhereLoop *p;
113524 for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){
113525 if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
113526 /* If either the iTab or iSortIdx values for two WhereLoop are different
113527 ** then those WhereLoops need to be considered separately. Neither is
113528 ** a candidate to replace the other. */
113529 continue;
113530 }
113531 /* In the current implementation, the rSetup value is either zero
113532 ** or the cost of building an automatic index (NlogN) and the NlogN
113533 ** is the same for compatible WhereLoops. */
113534 assert( p->rSetup==0 || pTemplate->rSetup==0
113535 || p->rSetup==pTemplate->rSetup );
113536
113537 /* whereLoopAddBtree() always generates and inserts the automatic index
113538 ** case first. Hence compatible candidate WhereLoops never have a larger
113539 ** rSetup. Call this SETUP-INVARIANT */
113540 assert( p->rSetup>=pTemplate->rSetup );
113541
113542 /* If existing WhereLoop p is better than pTemplate, pTemplate can be
113543 ** discarded. WhereLoop p is better if:
113544 ** (1) p has no more dependencies than pTemplate, and
113545 ** (2) p has an equal or lower cost than pTemplate
113546 */
113547 if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */
113548 && p->rSetup<=pTemplate->rSetup /* (2a) */
113549 && p->rRun<=pTemplate->rRun /* (2b) */
113550 && p->nOut<=pTemplate->nOut /* (2c) */
113551 ){
113552 return 0; /* Discard pTemplate */
113553 }
113554
113555 /* If pTemplate is always better than p, then cause p to be overwritten
113556 ** with pTemplate. pTemplate is better than p if:
113557 ** (1) pTemplate has no more dependences than p, and
113558 ** (2) pTemplate has an equal or lower cost than p.
113559 */
113560 if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
113561 && p->rRun>=pTemplate->rRun /* (2a) */
113562 && p->nOut>=pTemplate->nOut /* (2b) */
113563 ){
113564 assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
113565 break; /* Cause p to be overwritten by pTemplate */
113566 }
113567 }
113568 return ppPrev;
113569 }
113570
113571 /*
113572 ** Insert or replace a WhereLoop entry using the template supplied.
113573 **
113574 ** An existing WhereLoop entry might be overwritten if the new template
@@ -113103,29 +113575,27 @@
113575 ** is better and has fewer dependencies. Or the template will be ignored
113576 ** and no insert will occur if an existing WhereLoop is faster and has
113577 ** fewer dependencies than the template. Otherwise a new WhereLoop is
113578 ** added based on the template.
113579 **
113580 ** If pBuilder->pOrSet is not NULL then we care about only the
113581 ** prerequisites and rRun and nOut costs of the N best loops. That
113582 ** information is gathered in the pBuilder->pOrSet object. This special
113583 ** processing mode is used only for OR clause processing.
113584 **
113585 ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
113586 ** still might overwrite similar loops with the new template if the
113587 ** new template is better. Loops may be overwritten if the following
113588 ** conditions are met:
113589 **
113590 ** (1) They have the same iTab.
113591 ** (2) They have the same iSortIdx.
113592 ** (3) The template has same or fewer dependencies than the current loop
113593 ** (4) The template has the same or lower cost than the current loop
 
 
113594 */
113595 static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
113596 WhereLoop **ppPrev, *p;
113597 WhereInfo *pWInfo = pBuilder->pWInfo;
113598 sqlite3 *db = pWInfo->pParse->db;
113599
113600 /* If pBuilder->pOrSet is defined, then only keep track of the costs
113601 ** and prereqs.
@@ -113144,68 +113614,27 @@
113614 }
113615 #endif
113616 return SQLITE_OK;
113617 }
113618
113619 /* Look for an existing WhereLoop to replace with pTemplate
 
113620 */
113621 whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
113622 ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
113623
113624 if( ppPrev==0 ){
113625 /* There already exists a WhereLoop on the list that is better
113626 ** than pTemplate, so just ignore pTemplate */
113627 #if WHERETRACE_ENABLED /* 0x8 */
113628 if( sqlite3WhereTrace & 0x8 ){
113629 sqlite3DebugPrintf("ins-noop: ");
113630 whereLoopPrint(pTemplate, pBuilder->pWC);
113631 }
113632 #endif
113633 return SQLITE_OK;
113634 }else{
113635 p = *ppPrev;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113636 }
113637
113638 /* If we reach this point it means that either p[] should be overwritten
113639 ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
113640 ** WhereLoop and insert it.
@@ -113219,34 +113648,44 @@
113648 sqlite3DebugPrintf("ins-new: ");
113649 whereLoopPrint(pTemplate, pBuilder->pWC);
113650 }
113651 #endif
113652 if( p==0 ){
113653 /* Allocate a new WhereLoop to add to the end of the list */
113654 *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
113655 if( p==0 ) return SQLITE_NOMEM;
113656 whereLoopInit(p);
113657 p->pNextLoop = 0;
113658 }else{
113659 /* We will be overwriting WhereLoop p[]. But before we do, first
113660 ** go through the rest of the list and delete any other entries besides
113661 ** p[] that are also supplated by pTemplate */
113662 WhereLoop **ppTail = &p->pNextLoop;
113663 WhereLoop *pToDel;
113664 while( *ppTail ){
113665 ppTail = whereLoopFindLesser(ppTail, pTemplate);
113666 if( NEVER(ppTail==0) ) break;
113667 pToDel = *ppTail;
113668 if( pToDel==0 ) break;
113669 *ppTail = pToDel->pNextLoop;
113670 #if WHERETRACE_ENABLED /* 0x8 */
113671 if( sqlite3WhereTrace & 0x8 ){
113672 sqlite3DebugPrintf("ins-del: ");
113673 whereLoopPrint(pToDel, pBuilder->pWC);
113674 }
113675 #endif
113676 whereLoopDelete(db, pToDel);
113677 }
113678 }
113679 whereLoopXfer(db, p, pTemplate);
 
 
113680 if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
113681 Index *pIndex = p->u.btree.pIndex;
113682 if( pIndex && pIndex->tnum==0 ){
113683 p->u.btree.pIndex = 0;
113684 }
113685 }
113686 return SQLITE_OK;
 
 
 
 
 
 
 
 
 
 
113687 }
113688
113689 /*
113690 ** Adjust the WhereLoop.nOut value downward to account for terms of the
113691 ** WHERE clause that reference the loop but which are not used by an
@@ -113396,10 +113835,12 @@
113835 nIn = 46; assert( 46==sqlite3LogEst(25) );
113836 }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
113837 /* "x IN (value, value, ...)" */
113838 nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
113839 }
113840 assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
113841 ** changes "x IN (?)" into "x=?". */
113842 pNew->rRun += nIn;
113843 pNew->u.btree.nEq++;
113844 pNew->nOut = nRowEst + nInMul + nIn;
113845 }else if( pTerm->eOperator & (WO_EQ) ){
113846 assert(
@@ -113709,22 +114150,38 @@
114150 && sqlite3GlobalConfig.bUseCis
114151 && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
114152 )
114153 ){
114154 pNew->iSortIdx = b ? iSortIdx : 0;
114155 /* TUNING: The base cost of an index scan is N + log2(N).
114156 ** The log2(N) is for the initial seek to the beginning and the N
114157 ** is for the scan itself. */
114158 pNew->rRun = sqlite3LogEstAdd(rSize, rLogSize);
114159 if( m==0 ){
114160 /* TUNING: Cost of a covering index scan is K*(N + log2(N)).
114161 ** + The extra factor K of between 1.1 and 3.0 that depends
114162 ** on the relative sizes of the table and the index. K
114163 ** is smaller for smaller indices, thus favoring them.
114164 ** The upper bound on K (3.0) matches the penalty factor
114165 ** on a full table scan that tries to encourage the use of
114166 ** indexed lookups over full scans.
114167 */
114168 pNew->rRun += 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
114169 }else{
114170 /* TUNING: The cost of scanning a non-covering index is multiplied
114171 ** by log2(N) to account for the binary search of the main table
114172 ** that must happen for each row of the index.
114173 ** TODO: Should there be a multiplier here, analogous to the 3x
114174 ** multiplier for a fulltable scan or covering index scan, to
114175 ** further discourage the use of an index scan? Or is the log2(N)
114176 ** term sufficient discouragement?
114177 ** TODO: What if some or all of the WHERE clause terms can be
114178 ** computed without reference to the original table. Then the
114179 ** penality should reduce to logK where K is the number of output
114180 ** rows.
114181 */
114182 pNew->rRun += rLogSize;
 
 
 
 
 
114183 }
114184 whereLoopOutputAdjust(pWC, pNew);
114185 rc = whereLoopInsert(pBuilder, pNew);
114186 pNew->nOut = rSize;
114187 if( rc ) break;
@@ -113892,12 +114349,12 @@
114349 assert( pNew->nLTerm<=pNew->nLSlot );
114350 pNew->u.vtab.idxNum = pIdxInfo->idxNum;
114351 pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
114352 pIdxInfo->needToFreeIdxStr = 0;
114353 pNew->u.vtab.idxStr = pIdxInfo->idxStr;
114354 pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
114355 pIdxInfo->nOrderBy : 0);
114356 pNew->rSetup = 0;
114357 pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
114358 pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
114359 whereLoopInsert(pBuilder, pNew);
114360 if( pNew->u.vtab.needFree ){
@@ -114054,25 +114511,25 @@
114511 }
114512
114513 /*
114514 ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
114515 ** parameters) to see if it outputs rows in the requested ORDER BY
114516 ** (or GROUP BY) without requiring a separate sort operation. Return N:
114517 **
114518 ** N>0: N terms of the ORDER BY clause are satisfied
114519 ** N==0: No terms of the ORDER BY clause are satisfied
114520 ** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
114521 **
114522 ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
114523 ** strict. With GROUP BY and DISTINCT the only requirement is that
114524 ** equivalent rows appear immediately adjacent to one another. GROUP BY
114525 ** and DISTINT do not require rows to appear in any particular order as long
114526 ** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT
114527 ** the pOrderBy terms can be matched in any order. With ORDER BY, the
114528 ** pOrderBy terms must be matched in strict left-to-right order.
114529 */
114530 static i8 wherePathSatisfiesOrderBy(
114531 WhereInfo *pWInfo, /* The WHERE clause */
114532 ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
114533 WherePath *pPath, /* The WherePath to check */
114534 u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
114535 u16 nLoop, /* Number of entries in pPath->aLoop[] */
@@ -114252,28 +114709,28 @@
114709 if( !pColl ) pColl = db->pDfltColl;
114710 if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
114711 }
114712 isMatch = 1;
114713 break;
114714 }
114715 if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
114716 /* Make sure the sort order is compatible in an ORDER BY clause.
114717 ** Sort order is irrelevant for a GROUP BY clause. */
114718 if( revSet ){
114719 if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
114720 }else{
114721 rev = revIdx ^ pOrderBy->a[i].sortOrder;
114722 if( rev ) *pRevMask |= MASKBIT(iLoop);
114723 revSet = 1;
114724 }
114725 }
114726 if( isMatch ){
114727 if( iColumn<0 ){
114728 testcase( distinctColumns==0 );
114729 distinctColumns = 1;
114730 }
114731 obSat |= MASKBIT(i);
 
 
 
 
 
 
 
 
 
 
 
114732 }else{
114733 /* No match found */
114734 if( j==0 || j<nKeyCol ){
114735 testcase( isOrderDistinct!=0 );
114736 isOrderDistinct = 0;
@@ -114301,12 +114758,18 @@
114758 obSat |= MASKBIT(i);
114759 }
114760 }
114761 }
114762 } /* End the loop over all WhereLoops from outer-most down to inner-most */
114763 if( obSat==obDone ) return (i8)nOrderBy;
114764 if( !isOrderDistinct ){
114765 for(i=nOrderBy-1; i>0; i--){
114766 Bitmask m = MASKBIT(i) - 1;
114767 if( (obSat&m)==m ) return i;
114768 }
114769 return 0;
114770 }
114771 return -1;
114772 }
114773
114774 #ifdef WHERETRACE_ENABLED
114775 /* For debugging use only: */
@@ -114339,15 +114802,15 @@
114802 Parse *pParse; /* Parsing context */
114803 sqlite3 *db; /* The database connection */
114804 int iLoop; /* Loop counter over the terms of the join */
114805 int ii, jj; /* Loop counters */
114806 int mxI = 0; /* Index of next entry to replace */
114807 int nOrderBy; /* Number of ORDER BY clause terms */
114808 LogEst rCost; /* Cost of a path */
114809 LogEst nOut; /* Number of outputs */
114810 LogEst mxCost = 0; /* Maximum cost of a set of paths */
114811 LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
 
114812 int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
114813 WherePath *aFrom; /* All nFrom paths at the previous level */
114814 WherePath *aTo; /* The nTo best paths at the current level */
114815 WherePath *pFrom; /* An element of aFrom[] that we are working on */
114816 WherePath *pTo; /* An element of aTo[] that we are working on */
@@ -114385,20 +114848,16 @@
114848 aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
114849 nFrom = 1;
114850
114851 /* Precompute the cost of sorting the final result set, if the caller
114852 ** to sqlite3WhereBegin() was concerned about sorting */
 
114853 if( pWInfo->pOrderBy==0 || nRowEst==0 ){
114854 aFrom[0].isOrdered = 0;
114855 nOrderBy = 0;
114856 }else{
114857 aFrom[0].isOrdered = -1;
114858 nOrderBy = pWInfo->pOrderBy->nExpr;
 
 
 
 
114859 }
114860
114861 /* Compute successively longer WherePaths using the previous generation
114862 ** of WherePaths as the basis for the next. Keep track of the mxChoice
114863 ** best paths at each generation */
@@ -114406,43 +114865,56 @@
114865 nTo = 0;
114866 for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
114867 for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
114868 Bitmask maskNew;
114869 Bitmask revMask = 0;
114870 i8 isOrdered = pFrom->isOrdered;
 
114871 if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
114872 if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
114873 /* At this point, pWLoop is a candidate to be the next loop.
114874 ** Compute its cost */
114875 rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
114876 rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
114877 nOut = pFrom->nRow + pWLoop->nOut;
114878 maskNew = pFrom->maskLoop | pWLoop->maskSelf;
114879 if( isOrdered<0 ){
114880 isOrdered = wherePathSatisfiesOrderBy(pWInfo,
114881 pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
114882 iLoop, pWLoop, &revMask);
114883 if( isOrdered>=0 && isOrdered<nOrderBy ){
114884 /* TUNING: Estimated cost of sorting is N*log(N).
114885 ** If the order-by clause has X terms but only the last Y terms
114886 ** are out of order, then block-sorting will reduce the sorting
114887 ** cost to N*log(N)*log(Y/X). The log(Y/X) term is computed
114888 ** by rScale.
114889 ** TODO: Should the sorting cost get a small multiplier to help
114890 ** discourage the use of sorting and encourage the use of index
114891 ** scans instead?
114892 */
114893 LogEst rScale, rSortCost;
114894 assert( nOrderBy>0 );
114895 rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
114896 rSortCost = nRowEst + estLog(nRowEst) + rScale;
114897 /* TUNING: The cost of implementing DISTINCT using a B-TREE is
114898 ** also N*log(N) but it has a larger constant of proportionality.
114899 ** Multiply by 3.0. */
114900 if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
114901 rSortCost += 16;
114902 }
114903 WHERETRACE(0x002,
114904 ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
114905 rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost,
114906 sqlite3LogEstAdd(rCost,rSortCost)));
114907 rCost = sqlite3LogEstAdd(rCost, rSortCost);
114908 }
114909 }else{
114910 revMask = pFrom->revLoop;
114911 }
114912 /* Check to see if pWLoop should be added to the mxChoice best so far */
114913 for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
114914 if( pTo->maskLoop==maskNew
114915 && ((pTo->isOrdered^isOrdered)&80)==0
114916 && ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
114917 (pTo->rCost>=rCost && pTo->nRow>=nOut))
114918 ){
114919 testcase( jj==nTo-1 );
114920 break;
@@ -114452,11 +114924,11 @@
114924 if( nTo>=mxChoice && rCost>=mxCost ){
114925 #ifdef WHERETRACE_ENABLED /* 0x4 */
114926 if( sqlite3WhereTrace&0x4 ){
114927 sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
114928 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114929 isOrdered>=0 ? isOrdered+'0' : '?');
114930 }
114931 #endif
114932 continue;
114933 }
114934 /* Add a new Path to the aTo[] set */
@@ -114470,24 +114942,24 @@
114942 pTo = &aTo[jj];
114943 #ifdef WHERETRACE_ENABLED /* 0x4 */
114944 if( sqlite3WhereTrace&0x4 ){
114945 sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
114946 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114947 isOrdered>=0 ? isOrdered+'0' : '?');
114948 }
114949 #endif
114950 }else{
114951 if( pTo->rCost<=rCost && pTo->nRow<=nOut ){
114952 #ifdef WHERETRACE_ENABLED /* 0x4 */
114953 if( sqlite3WhereTrace&0x4 ){
114954 sqlite3DebugPrintf(
114955 "Skip %s cost=%-3d,%3d order=%c",
114956 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114957 isOrdered>=0 ? isOrdered+'0' : '?');
114958 sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
114959 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114960 pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
114961 }
114962 #endif
114963 testcase( pTo->rCost==rCost );
114964 continue;
114965 }
@@ -114496,23 +114968,22 @@
114968 #ifdef WHERETRACE_ENABLED /* 0x4 */
114969 if( sqlite3WhereTrace&0x4 ){
114970 sqlite3DebugPrintf(
114971 "Update %s cost=%-3d,%3d order=%c",
114972 wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
114973 isOrdered>=0 ? isOrdered+'0' : '?');
114974 sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
114975 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
114976 pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
114977 }
114978 #endif
114979 }
114980 /* pWLoop is a winner. Add it to the set of best so far */
114981 pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
114982 pTo->revLoop = revMask;
114983 pTo->nRow = nOut;
114984 pTo->rCost = rCost;
 
114985 pTo->isOrdered = isOrdered;
114986 memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
114987 pTo->aLoop[iLoop] = pWLoop;
114988 if( nTo>=mxChoice ){
114989 mxI = 0;
@@ -114533,12 +115004,12 @@
115004 if( sqlite3WhereTrace>=2 ){
115005 sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
115006 for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
115007 sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
115008 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
115009 pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
115010 if( pTo->isOrdered>0 ){
115011 sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
115012 }else{
115013 sqlite3DebugPrintf("\n");
115014 }
115015 }
@@ -114577,17 +115048,22 @@
115048 && nRowEst
115049 ){
115050 Bitmask notUsed;
115051 int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
115052 WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
115053 if( rc==pWInfo->pResultSet->nExpr ){
115054 pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
115055 }
115056 }
115057 if( pWInfo->pOrderBy ){
115058 if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
115059 if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
115060 pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
115061 }
115062 }else{
115063 pWInfo->nOBSat = pFrom->isOrdered;
115064 if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
115065 pWInfo->revMask = pFrom->revLoop;
115066 }
115067 }
115068 pWInfo->nRowOut = pFrom->nRow;
115069
@@ -114668,11 +115144,11 @@
115144 pLoop->nOut = (LogEst)1;
115145 pWInfo->a[0].pWLoop = pLoop;
115146 pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
115147 pWInfo->a[0].iTabCur = iCur;
115148 pWInfo->nRowOut = 1;
115149 if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
115150 if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
115151 pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
115152 }
115153 #ifdef SQLITE_DEBUG
115154 pLoop->cId = '0';
@@ -114772,11 +115248,11 @@
115248 */
115249 SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
115250 Parse *pParse, /* The parser context */
115251 SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
115252 Expr *pWhere, /* The WHERE clause */
115253 ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
115254 ExprList *pResultSet, /* Result set of the query */
115255 u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
115256 int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
115257 ){
115258 int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
@@ -114794,10 +115270,14 @@
115270
115271
115272 /* Variable initialization */
115273 db = pParse->db;
115274 memset(&sWLB, 0, sizeof(sWLB));
115275
115276 /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
115277 testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
115278 if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
115279 sWLB.pOrderBy = pOrderBy;
115280
115281 /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
115282 ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
115283 if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
@@ -114838,11 +115318,11 @@
115318 pWInfo->nLevel = nTabList;
115319 pWInfo->pParse = pParse;
115320 pWInfo->pTabList = pTabList;
115321 pWInfo->pOrderBy = pOrderBy;
115322 pWInfo->pResultSet = pResultSet;
115323 pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
115324 pWInfo->wctrlFlags = wctrlFlags;
115325 pWInfo->savedNQueryLoop = pParse->nQueryLoop;
115326 pMaskSet = &pWInfo->sMaskSet;
115327 sWLB.pWInfo = pWInfo;
115328 sWLB.pWC = &pWInfo->sWC;
@@ -114872,11 +115352,11 @@
115352 }
115353
115354 /* Special case: No FROM clause
115355 */
115356 if( nTabList==0 ){
115357 if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
115358 if( wctrlFlags & WHERE_WANT_DISTINCT ){
115359 pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
115360 }
115361 }
115362
@@ -114983,12 +115463,12 @@
115463 }
115464 #ifdef WHERETRACE_ENABLED /* !=0 */
115465 if( sqlite3WhereTrace ){
115466 int ii;
115467 sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
115468 if( pWInfo->nOBSat>0 ){
115469 sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
115470 }
115471 switch( pWInfo->eDistinct ){
115472 case WHERE_DISTINCT_UNIQUE: {
115473 sqlite3DebugPrintf(" DISTINCT=unique");
115474 break;
@@ -115266,11 +115746,11 @@
115746 k = pLevel->addrBody;
115747 pOp = sqlite3VdbeGetOp(v, k);
115748 for(; k<last; k++, pOp++){
115749 if( pOp->p1!=pLevel->iTabCur ) continue;
115750 if( pOp->opcode==OP_Column ){
115751 pOp->opcode = OP_Copy;
115752 pOp->p1 = pOp->p2 + pTabItem->regResult;
115753 pOp->p2 = pOp->p3;
115754 pOp->p3 = 0;
115755 }else if( pOp->opcode==OP_Rowid ){
115756 pOp->opcode = OP_Null;
@@ -118214,10 +118694,37 @@
118694 ** simplify to constants 0 (false) and 1 (true), respectively,
118695 ** regardless of the value of expr1.
118696 */
118697 yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]);
118698 sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr);
118699 }else if( yymsp[-1].minor.yy14->nExpr==1 ){
118700 /* Expressions of the form:
118701 **
118702 ** expr1 IN (?1)
118703 ** expr1 NOT IN (?2)
118704 **
118705 ** with exactly one value on the RHS can be simplified to something
118706 ** like this:
118707 **
118708 ** expr1 == ?1
118709 ** expr1 <> ?2
118710 **
118711 ** But, the RHS of the == or <> is marked with the EP_Generic flag
118712 ** so that it may not contribute to the computation of comparison
118713 ** affinity or the collating sequence to use for comparison. Otherwise,
118714 ** the semantics would be subtly different from IN or NOT IN.
118715 */
118716 Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
118717 yymsp[-1].minor.yy14->a[0].pExpr = 0;
118718 sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
118719 /* pRHS cannot be NULL because a malloc error would have been detected
118720 ** before now and control would have never reached this point */
118721 if( ALWAYS(pRHS) ){
118722 pRHS->flags &= ~EP_Collate;
118723 pRHS->flags |= EP_Generic;
118724 }
118725 yygotominor.yy346.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy328 ? TK_NE : TK_EQ, yymsp[-4].minor.yy346.pExpr, pRHS, 0);
118726 }else{
118727 yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
118728 if( yygotominor.yy346.pExpr ){
118729 yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
118730 sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
@@ -120834,10 +121341,11 @@
121341 Table *pTab = (Table *)sqliteHashData(p);
121342 if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
121343 }
121344 }
121345 }
121346 sqlite3VtabUnlockList(db);
121347 sqlite3BtreeLeaveAll(db);
121348 #else
121349 UNUSED_PARAMETER(db);
121350 #endif
121351 }
@@ -123237,10 +123745,26 @@
123745 case SQLITE_TESTCTRL_ALWAYS: {
123746 int x = va_arg(ap,int);
123747 rc = ALWAYS(x);
123748 break;
123749 }
123750
123751 /*
123752 ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
123753 **
123754 ** The integer returned reveals the byte-order of the computer on which
123755 ** SQLite is running:
123756 **
123757 ** 1 big-endian, determined at run-time
123758 ** 10 little-endian, determined at run-time
123759 ** 432101 big-endian, determined at compile-time
123760 ** 123410 little-endian, determined at compile-time
123761 */
123762 case SQLITE_TESTCTRL_BYTEORDER: {
123763 rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
123764 break;
123765 }
123766
123767 /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
123768 **
123769 ** Set the nReserve size to N for the main database on the database
123770 ** connection db.
@@ -124573,11 +125097,11 @@
125097 char *zReadExprlist;
125098 char *zWriteExprlist;
125099
125100 int nNodeSize; /* Soft limit for node size */
125101 u8 bFts4; /* True for FTS4, false for FTS3 */
125102 u8 bHasStat; /* True if %_stat table exists (2==unknown) */
125103 u8 bHasDocsize; /* True if %_docsize table exists */
125104 u8 bDescIdx; /* True if doclists are in reverse order */
125105 u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
125106 int nPgsz; /* Page size for host database */
125107 char *zSegmentsTbl; /* Name of %_segments table */
@@ -126065,14 +126589,11 @@
126589
126590 /* Check to see if a legacy fts3 table has been "upgraded" by the
126591 ** addition of a %_stat table so that it can use incremental merge.
126592 */
126593 if( !isFts4 && !isCreate ){
126594 p->bHasStat = 2;
 
 
 
126595 }
126596
126597 /* Figure out the page-size for the database. This is required in order to
126598 ** estimate the cost of loading large doclists from the database. */
126599 fts3DatabasePageSize(&rc, p);
@@ -127975,11 +128496,38 @@
128496 sqlite3Fts3SegmentsClose(p);
128497 return rc;
128498 }
128499
128500 /*
128501 ** If it is currently unknown whether or not the FTS table has an %_stat
128502 ** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat
128503 ** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code
128504 ** if an error occurs.
128505 */
128506 static int fts3SetHasStat(Fts3Table *p){
128507 int rc = SQLITE_OK;
128508 if( p->bHasStat==2 ){
128509 const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
128510 char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
128511 if( zSql ){
128512 sqlite3_stmt *pStmt = 0;
128513 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
128514 if( rc==SQLITE_OK ){
128515 int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
128516 rc = sqlite3_finalize(pStmt);
128517 if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
128518 }
128519 sqlite3_free(zSql);
128520 }else{
128521 rc = SQLITE_NOMEM;
128522 }
128523 }
128524 return rc;
128525 }
128526
128527 /*
128528 ** Implementation of xBegin() method.
128529 */
128530 static int fts3BeginMethod(sqlite3_vtab *pVtab){
128531 Fts3Table *p = (Fts3Table*)pVtab;
128532 UNUSED_PARAMETER(pVtab);
128533 assert( p->pSegments==0 );
@@ -127986,11 +128534,11 @@
128534 assert( p->nPendingData==0 );
128535 assert( p->inTransaction!=1 );
128536 TESTONLY( p->inTransaction = 1 );
128537 TESTONLY( p->mxSavepoint = -1; );
128538 p->nLeafAdd = 0;
128539 return fts3SetHasStat(p);
128540 }
128541
128542 /*
128543 ** Implementation of xCommit() method. This is a no-op. The contents of
128544 ** the pending-terms hash-table have already been flushed into the database
@@ -128235,18 +128783,24 @@
128783 ){
128784 Fts3Table *p = (Fts3Table *)pVtab;
128785 sqlite3 *db = p->db; /* Database connection */
128786 int rc; /* Return Code */
128787
128788 /* At this point it must be known if the %_stat table exists or not.
128789 ** So bHasStat may not be 2. */
128790 rc = fts3SetHasStat(p);
128791
128792 /* As it happens, the pending terms table is always empty here. This is
128793 ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
128794 ** always opens a savepoint transaction. And the xSavepoint() method
128795 ** flushes the pending terms table. But leave the (no-op) call to
128796 ** PendingTermsFlush() in in case that changes.
128797 */
128798 assert( p->nPendingData==0 );
128799 if( rc==SQLITE_OK ){
128800 rc = sqlite3Fts3PendingTermsFlush(p);
128801 }
128802
128803 if( p->zContentTbl==0 ){
128804 fts3DbExec(&rc, db,
128805 "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
128806 p->zDb, p->zName, zName
@@ -139754,10 +140308,14 @@
140308 u32 *aSzIns = 0; /* Sizes of inserted documents */
140309 u32 *aSzDel = 0; /* Sizes of deleted documents */
140310 int nChng = 0; /* Net change in number of documents */
140311 int bInsertDone = 0;
140312
140313 /* At this point it must be known if the %_stat table exists or not.
140314 ** So bHasStat may not be 2. */
140315 assert( p->bHasStat==0 || p->bHasStat==1 );
140316
140317 assert( p->pSegments==0 );
140318 assert(
140319 nArg==1 /* DELETE operations */
140320 || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
140321 );
@@ -145135,30 +145693,36 @@
145693 ** This function populates the pRtree->nRowEst variable with an estimate
145694 ** of the number of rows in the virtual table. If possible, this is based
145695 ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
145696 */
145697 static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
145698 const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
145699 char *zSql;
145700 sqlite3_stmt *p;
145701 int rc;
145702 i64 nRow = 0;
145703
145704 zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
145705 if( zSql==0 ){
145706 rc = SQLITE_NOMEM;
145707 }else{
145708 rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
145709 if( rc==SQLITE_OK ){
145710 if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
145711 rc = sqlite3_finalize(p);
145712 }else if( rc!=SQLITE_NOMEM ){
145713 rc = SQLITE_OK;
145714 }
145715
145716 if( rc==SQLITE_OK ){
145717 if( nRow==0 ){
145718 pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
145719 }else{
145720 pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
145721 }
145722 }
145723 sqlite3_free(zSql);
145724 }
145725
145726 return rc;
145727 }
145728
@@ -145423,10 +145987,12 @@
145987 }
145988
145989 if( rc==SQLITE_OK ){
145990 *ppVtab = (sqlite3_vtab *)pRtree;
145991 }else{
145992 assert( *ppVtab==0 );
145993 assert( pRtree->nBusy==1 );
145994 rtreeRelease(pRtree);
145995 }
145996 return rc;
145997 }
145998
145999
+5 -4
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -105,13 +105,13 @@
105105
**
106106
** See also: [sqlite3_libversion()],
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110
-#define SQLITE_VERSION "3.8.4.1"
111
-#define SQLITE_VERSION_NUMBER 3008004
112
-#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0"
110
+#define SQLITE_VERSION "3.8.5"
111
+#define SQLITE_VERSION_NUMBER 3008005
112
+#define SQLITE_SOURCE_ID "2014-04-18 22:20:31 9a5d38c79d2482a23bcfbc3ff35ca4fa269c768d"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -6121,11 +6121,12 @@
61216121
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
61226122
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
61236123
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
61246124
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
61256125
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
6126
-#define SQLITE_TESTCTRL_LAST 21
6126
+#define SQLITE_TESTCTRL_BYTEORDER 22
6127
+#define SQLITE_TESTCTRL_LAST 22
61276128
61286129
/*
61296130
** CAPI3REF: SQLite Runtime Status
61306131
**
61316132
** ^This interface is used to retrieve runtime status information
61326133
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -105,13 +105,13 @@
105 **
106 ** See also: [sqlite3_libversion()],
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.4.1"
111 #define SQLITE_VERSION_NUMBER 3008004
112 #define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -6121,11 +6121,12 @@
6121 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17
6122 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
6123 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19
6124 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20
6125 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21
6126 #define SQLITE_TESTCTRL_LAST 21
 
6127
6128 /*
6129 ** CAPI3REF: SQLite Runtime Status
6130 **
6131 ** ^This interface is used to retrieve runtime status information
6132
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -105,13 +105,13 @@
105 **
106 ** See also: [sqlite3_libversion()],
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.5"
111 #define SQLITE_VERSION_NUMBER 3008005
112 #define SQLITE_SOURCE_ID "2014-04-18 22:20:31 9a5d38c79d2482a23bcfbc3ff35ca4fa269c768d"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -6121,11 +6121,12 @@
6121 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17
6122 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
6123 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19
6124 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20
6125 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21
6126 #define SQLITE_TESTCTRL_BYTEORDER 22
6127 #define SQLITE_TESTCTRL_LAST 22
6128
6129 /*
6130 ** CAPI3REF: SQLite Runtime Status
6131 **
6132 ** ^This interface is used to retrieve runtime status information
6133
+13 -3
--- src/stash.c
+++ src/stash.c
@@ -463,11 +463,11 @@
463463
**
464464
** SUMMARY:
465465
** fossil stash
466466
** fossil stash save ?-m|--comment COMMENT? ?FILES...?
467467
** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...?
468
-** fossil stash list|ls ?-v|--verbose?
468
+** fossil stash list|ls ?-v|--verbose? ?-W|--width <num>?
469469
** fossil stash show ?STASHID? ?DIFF-OPTIONS?
470470
** fossil stash pop
471471
** fossil stash apply ?STASHID?
472472
** fossil stash goto ?STASHID?
473473
** fossil stash rm|drop ?STASHID? ?-a|--all?
@@ -516,12 +516,22 @@
516516
if( memcmp(zCmd, "snapshot", nCmd)==0 ){
517517
stash_create();
518518
}else
519519
if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
520520
Stmt q, q2;
521
- int n = 0;
521
+ int n = 0, width;
522522
int verboseFlag = find_option("verbose","v",0)!=0;
523
+ const char *zWidth = find_option("width","W",1);
524
+
525
+ if( zWidth ){
526
+ width = atoi(zWidth);
527
+ if( (width!=0) && (width<=46) ){
528
+ fossil_fatal("-W|--width value must be >46 or 0");
529
+ }
530
+ }else{
531
+ width = 79;
532
+ }
523533
if( !verboseFlag ){
524534
verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
525535
}
526536
verify_all_options();
527537
db_prepare(&q,
@@ -543,11 +553,11 @@
543553
db_column_text(&q, 3)
544554
);
545555
zCom = db_column_text(&q, 2);
546556
if( zCom && zCom[0] ){
547557
fossil_print(" ");
548
- comment_print(zCom, 7, 79);
558
+ comment_print(zCom, 7, width);
549559
}
550560
if( verboseFlag ){
551561
db_bind_int(&q2, "$id", stashid);
552562
while( db_step(&q2)==SQLITE_ROW ){
553563
int isAdded = db_column_int(&q2, 0);
554564
--- src/stash.c
+++ src/stash.c
@@ -463,11 +463,11 @@
463 **
464 ** SUMMARY:
465 ** fossil stash
466 ** fossil stash save ?-m|--comment COMMENT? ?FILES...?
467 ** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...?
468 ** fossil stash list|ls ?-v|--verbose?
469 ** fossil stash show ?STASHID? ?DIFF-OPTIONS?
470 ** fossil stash pop
471 ** fossil stash apply ?STASHID?
472 ** fossil stash goto ?STASHID?
473 ** fossil stash rm|drop ?STASHID? ?-a|--all?
@@ -516,12 +516,22 @@
516 if( memcmp(zCmd, "snapshot", nCmd)==0 ){
517 stash_create();
518 }else
519 if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
520 Stmt q, q2;
521 int n = 0;
522 int verboseFlag = find_option("verbose","v",0)!=0;
 
 
 
 
 
 
 
 
 
 
523 if( !verboseFlag ){
524 verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
525 }
526 verify_all_options();
527 db_prepare(&q,
@@ -543,11 +553,11 @@
543 db_column_text(&q, 3)
544 );
545 zCom = db_column_text(&q, 2);
546 if( zCom && zCom[0] ){
547 fossil_print(" ");
548 comment_print(zCom, 7, 79);
549 }
550 if( verboseFlag ){
551 db_bind_int(&q2, "$id", stashid);
552 while( db_step(&q2)==SQLITE_ROW ){
553 int isAdded = db_column_int(&q2, 0);
554
--- src/stash.c
+++ src/stash.c
@@ -463,11 +463,11 @@
463 **
464 ** SUMMARY:
465 ** fossil stash
466 ** fossil stash save ?-m|--comment COMMENT? ?FILES...?
467 ** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...?
468 ** fossil stash list|ls ?-v|--verbose? ?-W|--width <num>?
469 ** fossil stash show ?STASHID? ?DIFF-OPTIONS?
470 ** fossil stash pop
471 ** fossil stash apply ?STASHID?
472 ** fossil stash goto ?STASHID?
473 ** fossil stash rm|drop ?STASHID? ?-a|--all?
@@ -516,12 +516,22 @@
516 if( memcmp(zCmd, "snapshot", nCmd)==0 ){
517 stash_create();
518 }else
519 if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
520 Stmt q, q2;
521 int n = 0, width;
522 int verboseFlag = find_option("verbose","v",0)!=0;
523 const char *zWidth = find_option("width","W",1);
524
525 if( zWidth ){
526 width = atoi(zWidth);
527 if( (width!=0) && (width<=46) ){
528 fossil_fatal("-W|--width value must be >46 or 0");
529 }
530 }else{
531 width = 79;
532 }
533 if( !verboseFlag ){
534 verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
535 }
536 verify_all_options();
537 db_prepare(&q,
@@ -543,11 +553,11 @@
553 db_column_text(&q, 3)
554 );
555 zCom = db_column_text(&q, 2);
556 if( zCom && zCom[0] ){
557 fossil_print(" ");
558 comment_print(zCom, 7, width);
559 }
560 if( verboseFlag ){
561 db_bind_int(&q2, "$id", stashid);
562 while( db_step(&q2)==SQLITE_ROW ){
563 int isAdded = db_column_int(&q2, 0);
564
+1 -1
--- src/style.c
+++ src/style.c
@@ -1152,11 +1152,11 @@
11521152
"format for th1 script errors",
11531153
@ white-space: pre-wrap;
11541154
@ word-wrap: break-word;
11551155
@ color: red;
11561156
},
1157
- { "table.tale-value th",
1157
+ { "table.label-value th",
11581158
"The label/value pairs on (for example) the ci page",
11591159
@ vertical-align: top;
11601160
@ text-align: right;
11611161
@ padding: 0.2ex 2ex;
11621162
},
11631163
--- src/style.c
+++ src/style.c
@@ -1152,11 +1152,11 @@
1152 "format for th1 script errors",
1153 @ white-space: pre-wrap;
1154 @ word-wrap: break-word;
1155 @ color: red;
1156 },
1157 { "table.tale-value th",
1158 "The label/value pairs on (for example) the ci page",
1159 @ vertical-align: top;
1160 @ text-align: right;
1161 @ padding: 0.2ex 2ex;
1162 },
1163
--- src/style.c
+++ src/style.c
@@ -1152,11 +1152,11 @@
1152 "format for th1 script errors",
1153 @ white-space: pre-wrap;
1154 @ word-wrap: break-word;
1155 @ color: red;
1156 },
1157 { "table.label-value th",
1158 "The label/value pairs on (for example) the ci page",
1159 @ vertical-align: top;
1160 @ text-align: right;
1161 @ padding: 0.2ex 2ex;
1162 },
1163
+10 -10
--- src/sync.c
+++ src/sync.c
@@ -48,14 +48,14 @@
4848
}
4949
}else{
5050
/* Autosync defaults on. To make it default off, "return" here. */
5151
}
5252
url_parse(0, URL_REMEMBER);
53
- if( g.urlProtocol==0 ) return 0;
54
- if( g.urlUser!=0 && g.urlPasswd==0 ){
55
- g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56
- g.urlFlags |= URL_PROMPT_PW;
53
+ if( g.url.protocol==0 ) return 0;
54
+ if( g.url.user!=0 && g.url.passwd==0 ){
55
+ g.url.passwd = unobscure(db_get("last-sync-pw", 0));
56
+ g.url.flags |= URL_PROMPT_PW;
5757
url_prompt_for_password();
5858
}
5959
g.zHttpAuth = get_httpauth();
6060
url_remember();
6161
#if 0 /* Disabled for now */
@@ -69,11 +69,11 @@
6969
*/
7070
configSync = CONFIGSET_SHUN;
7171
}
7272
#endif
7373
if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
74
- fossil_print("Autosync: %s\n", g.urlCanonical);
74
+ fossil_print("Autosync: %s\n", g.url.canonical);
7575
url_enable_proxy("via proxy: ");
7676
rc = client_sync(flags, configSync, 0);
7777
if( rc ) fossil_warning("Autosync failed");
7878
return rc;
7979
}
@@ -121,22 +121,22 @@
121121
clone_ssh_db_set_options();
122122
}
123123
url_parse(zUrl, urlFlags);
124124
remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
125125
url_remember();
126
- if( g.urlProtocol==0 ){
126
+ if( g.url.protocol==0 ){
127127
if( urlOptional ) fossil_exit(0);
128128
usage("URL");
129129
}
130130
user_select();
131131
if( g.argc==2 ){
132132
if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
133
- fossil_print("Sync with %s\n", g.urlCanonical);
133
+ fossil_print("Sync with %s\n", g.url.canonical);
134134
}else if( (*pSyncFlags) & SYNC_PUSH ){
135
- fossil_print("Push to %s\n", g.urlCanonical);
135
+ fossil_print("Push to %s\n", g.url.canonical);
136136
}else if( (*pSyncFlags) & SYNC_PULL ){
137
- fossil_print("Pull from %s\n", g.urlCanonical);
137
+ fossil_print("Pull from %s\n", g.url.canonical);
138138
}
139139
}
140140
url_enable_proxy("via proxy: ");
141141
*pConfigFlags |= configSync;
142142
}
@@ -278,8 +278,8 @@
278278
if( zUrl==0 ){
279279
fossil_print("off\n");
280280
return;
281281
}else{
282282
url_parse(zUrl, 0);
283
- fossil_print("%s\n", g.urlCanonical);
283
+ fossil_print("%s\n", g.url.canonical);
284284
}
285285
}
286286
--- src/sync.c
+++ src/sync.c
@@ -48,14 +48,14 @@
48 }
49 }else{
50 /* Autosync defaults on. To make it default off, "return" here. */
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.urlProtocol==0 ) return 0;
54 if( g.urlUser!=0 && g.urlPasswd==0 ){
55 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56 g.urlFlags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
59 g.zHttpAuth = get_httpauth();
60 url_remember();
61 #if 0 /* Disabled for now */
@@ -69,11 +69,11 @@
69 */
70 configSync = CONFIGSET_SHUN;
71 }
72 #endif
73 if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
74 fossil_print("Autosync: %s\n", g.urlCanonical);
75 url_enable_proxy("via proxy: ");
76 rc = client_sync(flags, configSync, 0);
77 if( rc ) fossil_warning("Autosync failed");
78 return rc;
79 }
@@ -121,22 +121,22 @@
121 clone_ssh_db_set_options();
122 }
123 url_parse(zUrl, urlFlags);
124 remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
125 url_remember();
126 if( g.urlProtocol==0 ){
127 if( urlOptional ) fossil_exit(0);
128 usage("URL");
129 }
130 user_select();
131 if( g.argc==2 ){
132 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
133 fossil_print("Sync with %s\n", g.urlCanonical);
134 }else if( (*pSyncFlags) & SYNC_PUSH ){
135 fossil_print("Push to %s\n", g.urlCanonical);
136 }else if( (*pSyncFlags) & SYNC_PULL ){
137 fossil_print("Pull from %s\n", g.urlCanonical);
138 }
139 }
140 url_enable_proxy("via proxy: ");
141 *pConfigFlags |= configSync;
142 }
@@ -278,8 +278,8 @@
278 if( zUrl==0 ){
279 fossil_print("off\n");
280 return;
281 }else{
282 url_parse(zUrl, 0);
283 fossil_print("%s\n", g.urlCanonical);
284 }
285 }
286
--- src/sync.c
+++ src/sync.c
@@ -48,14 +48,14 @@
48 }
49 }else{
50 /* Autosync defaults on. To make it default off, "return" here. */
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.url.protocol==0 ) return 0;
54 if( g.url.user!=0 && g.url.passwd==0 ){
55 g.url.passwd = unobscure(db_get("last-sync-pw", 0));
56 g.url.flags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
59 g.zHttpAuth = get_httpauth();
60 url_remember();
61 #if 0 /* Disabled for now */
@@ -69,11 +69,11 @@
69 */
70 configSync = CONFIGSET_SHUN;
71 }
72 #endif
73 if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
74 fossil_print("Autosync: %s\n", g.url.canonical);
75 url_enable_proxy("via proxy: ");
76 rc = client_sync(flags, configSync, 0);
77 if( rc ) fossil_warning("Autosync failed");
78 return rc;
79 }
@@ -121,22 +121,22 @@
121 clone_ssh_db_set_options();
122 }
123 url_parse(zUrl, urlFlags);
124 remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
125 url_remember();
126 if( g.url.protocol==0 ){
127 if( urlOptional ) fossil_exit(0);
128 usage("URL");
129 }
130 user_select();
131 if( g.argc==2 ){
132 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
133 fossil_print("Sync with %s\n", g.url.canonical);
134 }else if( (*pSyncFlags) & SYNC_PUSH ){
135 fossil_print("Push to %s\n", g.url.canonical);
136 }else if( (*pSyncFlags) & SYNC_PULL ){
137 fossil_print("Pull from %s\n", g.url.canonical);
138 }
139 }
140 url_enable_proxy("via proxy: ");
141 *pConfigFlags |= configSync;
142 }
@@ -278,8 +278,8 @@
278 if( zUrl==0 ){
279 fossil_print("off\n");
280 return;
281 }else{
282 url_parse(zUrl, 0);
283 fossil_print("%s\n", g.url.canonical);
284 }
285 }
286
+90 -10
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128128
*/
129129
static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130130
static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131131
static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132132
static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
133
+static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
133134
static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
134135
135136
/*
136137
** Given that the input string (z, n) contains a language construct of
137138
** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,43 @@
18661867
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
18671868
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
18681869
18691870
{0,0,0,0}
18701871
};
1872
+
1873
+/*
1874
+** The first part of the string (zInput,nInput) contains an integer.
1875
+** Set *pnVarname to the number of bytes in the numeric string.
1876
+*/
1877
+static int thNextInteger(
1878
+ Th_Interp *interp,
1879
+ const char *zInput,
1880
+ int nInput,
1881
+ int *pnLiteral
1882
+){
1883
+ int i;
1884
+ int (*isdigit)(char) = th_isdigit;
1885
+ char c;
1886
+
1887
+ if( nInput<2) return TH_ERROR;
1888
+ assert(zInput[0]=='0');
1889
+ c = zInput[1];
1890
+ if( c>='A' && c<='Z' ) c += 'a' - 'A';
1891
+ if( c=='x' ){
1892
+ isdigit = th_ishexdig;
1893
+ }else if( c!='o' && c!='b' ){
1894
+ return TH_ERROR;
1895
+ }
1896
+ for(i=2; i<nInput; i++){
1897
+ c = zInput[i];
1898
+ if( !isdigit(c) ){
1899
+ break;
1900
+ }
1901
+ }
1902
+ *pnLiteral = i;
1903
+ return TH_OK;
1904
+}
18711905
18721906
/*
18731907
** The first part of the string (zInput,nInput) contains a number.
18741908
** Set *pnVarname to the number of bytes in the numeric string.
18751909
*/
@@ -1877,13 +1911,13 @@
18771911
Th_Interp *interp,
18781912
const char *zInput,
18791913
int nInput,
18801914
int *pnLiteral
18811915
){
1882
- int i;
1916
+ int i = 0;
18831917
int seenDot = 0;
1884
- for(i=0; i<nInput; i++){
1918
+ for(; i<nInput; i++){
18851919
char c = zInput[i];
18861920
if( (seenDot || c!='.') && !th_isdigit(c) ) break;
18871921
if( c=='.' ) seenDot = 1;
18881922
}
18891923
*pnLiteral = i;
@@ -1996,10 +2030,11 @@
19962030
case OP_BITWISE_OR: iRes = iLeft|iRight; break;
19972031
case OP_LOGICAL_AND: iRes = iLeft&&iRight; break;
19982032
case OP_LOGICAL_OR: iRes = iLeft||iRight; break;
19992033
case OP_UNARY_MINUS: iRes = -iLeft; break;
20002034
case OP_UNARY_PLUS: iRes = +iLeft; break;
2035
+ case OP_BITWISE_NOT: iRes = ~iLeft; break;
20012036
case OP_LOGICAL_NOT: iRes = !iLeft; break;
20022037
default: assert(!"Internal error");
20032038
}
20042039
Th_SetResultInt(interp, iRes);
20052040
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
@@ -2154,12 +2189,17 @@
21542189
}else{
21552190
Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
21562191
const char *z = &zExpr[i];
21572192
21582193
switch (c) {
2159
- case '0': case '1': case '2': case '3': case '4':
2160
- case '5': case '6': case '7': case '8': case '9':
2194
+ case '0':
2195
+ if( thNextInteger(interp, z, nExpr-i, &pNew->nValue)==TH_OK ){
2196
+ break;
2197
+ }
2198
+ /* fall through */
2199
+ case '1': case '2': case '3': case '4': case '5':
2200
+ case '6': case '7': case '8': case '9':
21612201
thNextNumber(interp, z, nExpr-i, &pNew->nValue);
21622202
break;
21632203
21642204
case '$':
21652205
thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2410,11 +2450,12 @@
24102450
** '\f' 0x0C
24112451
** '\r' 0x0D
24122452
**
24132453
** Whitespace characters have the 0x01 flag set. Decimal digits have the
24142454
** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
2415
-** Alphabet characters have the 0x8 bit set.
2455
+** Alphabet characters have the 0x8 bit set. Hexadecimal digits have the
2456
+** 0x20 flag set.
24162457
**
24172458
** The special list characters have the 0x10 flag set
24182459
**
24192460
** { } [ ] \ ; ' "
24202461
**
@@ -2423,14 +2464,14 @@
24232464
*/
24242465
static unsigned char aCharProp[256] = {
24252466
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* 0x0. */
24262467
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1. */
24272468
5, 4, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x2. */
2428
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 20, 4, 4, 4, 4, /* 0x3. */
2429
- 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */
2469
+ 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 4, 20, 4, 4, 4, 4, /* 0x3. */
2470
+ 4, 44, 44, 44, 44, 44, 44, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */
24302471
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 4, 4, /* 0x5. */
2431
- 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */
2472
+ 4, 44, 44, 44, 44, 44, 44, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */
24322473
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 4, 20, 4, 4, /* 0x7. */
24332474
24342475
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8. */
24352476
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9. */
24362477
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA. */
@@ -2454,10 +2495,22 @@
24542495
return (aCharProp[(unsigned char)c] & 0x11);
24552496
}
24562497
int th_isalnum(char c){
24572498
return (aCharProp[(unsigned char)c] & 0x0A);
24582499
}
2500
+int th_isalpha(char c){
2501
+ return (aCharProp[(unsigned char)c] & 0x08);
2502
+}
2503
+int th_ishexdig(char c){
2504
+ return (aCharProp[(unsigned char)c] & 0x20);
2505
+}
2506
+int th_isoctdig(char c){
2507
+ return ((c|7) == '7');
2508
+}
2509
+int th_isbindig(char c){
2510
+ return ((c|1) == '1');
2511
+}
24592512
24602513
#ifndef LONGDOUBLE_TYPE
24612514
# define LONGDOUBLE_TYPE long double
24622515
#endif
24632516
@@ -2570,24 +2623,51 @@
25702623
** interpreter result too.
25712624
*/
25722625
int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
25732626
int i = 0;
25742627
int iOut = 0;
2628
+ int base = 10;
2629
+ int (*isdigit)(char) = th_isdigit;
25752630
25762631
if( n<0 ){
25772632
n = th_strlen(z);
25782633
}
25792634
25802635
if( n>0 && (z[0]=='-' || z[0]=='+') ){
25812636
i = 1;
2637
+ }
2638
+ if( n>2 ){
2639
+ if( z[i]=='0' ){
2640
+ if( z[i+1]=='x' || z[i+1]=='X' ){
2641
+ i += 2;
2642
+ base = 16;
2643
+ isdigit = th_ishexdig;
2644
+ }else if( z[i+1]=='o' || z[i+1]=='O' ){
2645
+ i += 2;
2646
+ base = 8;
2647
+ isdigit = th_isoctdig;
2648
+ }else if( z[i+1]=='b' || z[i+1]=='B' ){
2649
+ i += 2;
2650
+ base = 2;
2651
+ isdigit = th_isbindig;
2652
+ }
2653
+ }
25822654
}
25832655
for(; i<n; i++){
2584
- if( !th_isdigit(z[i]) ){
2656
+ char c = z[i];
2657
+ if( !isdigit(c) ){
25852658
Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
25862659
return TH_ERROR;
25872660
}
2588
- iOut = iOut * 10 + (z[i] - 48);
2661
+ if( c>='a' ){
2662
+ c -= 'a'-10;
2663
+ }else if( c>='A' ){
2664
+ c -= 'A'-10;
2665
+ }else{
2666
+ c -= '0';
2667
+ }
2668
+ iOut = iOut * base + c;
25892669
}
25902670
25912671
if( n>0 && z[0]=='-' ){
25922672
iOut *= -1;
25932673
}
25942674
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128 */
129 static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130 static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131 static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132 static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
 
133 static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
134
135 /*
136 ** Given that the input string (z, n) contains a language construct of
137 ** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,43 @@
1866 {"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
1867 {"|", OP_BITWISE_OR, 10, ARG_INTEGER},
1868
1869 {0,0,0,0}
1870 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1871
1872 /*
1873 ** The first part of the string (zInput,nInput) contains a number.
1874 ** Set *pnVarname to the number of bytes in the numeric string.
1875 */
@@ -1877,13 +1911,13 @@
1877 Th_Interp *interp,
1878 const char *zInput,
1879 int nInput,
1880 int *pnLiteral
1881 ){
1882 int i;
1883 int seenDot = 0;
1884 for(i=0; i<nInput; i++){
1885 char c = zInput[i];
1886 if( (seenDot || c!='.') && !th_isdigit(c) ) break;
1887 if( c=='.' ) seenDot = 1;
1888 }
1889 *pnLiteral = i;
@@ -1996,10 +2030,11 @@
1996 case OP_BITWISE_OR: iRes = iLeft|iRight; break;
1997 case OP_LOGICAL_AND: iRes = iLeft&&iRight; break;
1998 case OP_LOGICAL_OR: iRes = iLeft||iRight; break;
1999 case OP_UNARY_MINUS: iRes = -iLeft; break;
2000 case OP_UNARY_PLUS: iRes = +iLeft; break;
 
2001 case OP_LOGICAL_NOT: iRes = !iLeft; break;
2002 default: assert(!"Internal error");
2003 }
2004 Th_SetResultInt(interp, iRes);
2005 }else if( rc==TH_OK && eArgType==ARG_NUMBER ){
@@ -2154,12 +2189,17 @@
2154 }else{
2155 Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
2156 const char *z = &zExpr[i];
2157
2158 switch (c) {
2159 case '0': case '1': case '2': case '3': case '4':
2160 case '5': case '6': case '7': case '8': case '9':
 
 
 
 
 
2161 thNextNumber(interp, z, nExpr-i, &pNew->nValue);
2162 break;
2163
2164 case '$':
2165 thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2410,11 +2450,12 @@
2410 ** '\f' 0x0C
2411 ** '\r' 0x0D
2412 **
2413 ** Whitespace characters have the 0x01 flag set. Decimal digits have the
2414 ** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
2415 ** Alphabet characters have the 0x8 bit set.
 
2416 **
2417 ** The special list characters have the 0x10 flag set
2418 **
2419 ** { } [ ] \ ; ' "
2420 **
@@ -2423,14 +2464,14 @@
2423 */
2424 static unsigned char aCharProp[256] = {
2425 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* 0x0. */
2426 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1. */
2427 5, 4, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x2. */
2428 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 20, 4, 4, 4, 4, /* 0x3. */
2429 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */
2430 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 4, 4, /* 0x5. */
2431 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */
2432 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 4, 20, 4, 4, /* 0x7. */
2433
2434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8. */
2435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9. */
2436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA. */
@@ -2454,10 +2495,22 @@
2454 return (aCharProp[(unsigned char)c] & 0x11);
2455 }
2456 int th_isalnum(char c){
2457 return (aCharProp[(unsigned char)c] & 0x0A);
2458 }
 
 
 
 
 
 
 
 
 
 
 
 
2459
2460 #ifndef LONGDOUBLE_TYPE
2461 # define LONGDOUBLE_TYPE long double
2462 #endif
2463
@@ -2570,24 +2623,51 @@
2570 ** interpreter result too.
2571 */
2572 int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
2573 int i = 0;
2574 int iOut = 0;
 
 
2575
2576 if( n<0 ){
2577 n = th_strlen(z);
2578 }
2579
2580 if( n>0 && (z[0]=='-' || z[0]=='+') ){
2581 i = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2582 }
2583 for(; i<n; i++){
2584 if( !th_isdigit(z[i]) ){
 
2585 Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
2586 return TH_ERROR;
2587 }
2588 iOut = iOut * 10 + (z[i] - 48);
 
 
 
 
 
 
 
2589 }
2590
2591 if( n>0 && z[0]=='-' ){
2592 iOut *= -1;
2593 }
2594
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128 */
129 static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130 static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131 static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132 static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
133 static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
134 static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
135
136 /*
137 ** Given that the input string (z, n) contains a language construct of
138 ** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,43 @@
1867 {"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
1868 {"|", OP_BITWISE_OR, 10, ARG_INTEGER},
1869
1870 {0,0,0,0}
1871 };
1872
1873 /*
1874 ** The first part of the string (zInput,nInput) contains an integer.
1875 ** Set *pnVarname to the number of bytes in the numeric string.
1876 */
1877 static int thNextInteger(
1878 Th_Interp *interp,
1879 const char *zInput,
1880 int nInput,
1881 int *pnLiteral
1882 ){
1883 int i;
1884 int (*isdigit)(char) = th_isdigit;
1885 char c;
1886
1887 if( nInput<2) return TH_ERROR;
1888 assert(zInput[0]=='0');
1889 c = zInput[1];
1890 if( c>='A' && c<='Z' ) c += 'a' - 'A';
1891 if( c=='x' ){
1892 isdigit = th_ishexdig;
1893 }else if( c!='o' && c!='b' ){
1894 return TH_ERROR;
1895 }
1896 for(i=2; i<nInput; i++){
1897 c = zInput[i];
1898 if( !isdigit(c) ){
1899 break;
1900 }
1901 }
1902 *pnLiteral = i;
1903 return TH_OK;
1904 }
1905
1906 /*
1907 ** The first part of the string (zInput,nInput) contains a number.
1908 ** Set *pnVarname to the number of bytes in the numeric string.
1909 */
@@ -1877,13 +1911,13 @@
1911 Th_Interp *interp,
1912 const char *zInput,
1913 int nInput,
1914 int *pnLiteral
1915 ){
1916 int i = 0;
1917 int seenDot = 0;
1918 for(; i<nInput; i++){
1919 char c = zInput[i];
1920 if( (seenDot || c!='.') && !th_isdigit(c) ) break;
1921 if( c=='.' ) seenDot = 1;
1922 }
1923 *pnLiteral = i;
@@ -1996,10 +2030,11 @@
2030 case OP_BITWISE_OR: iRes = iLeft|iRight; break;
2031 case OP_LOGICAL_AND: iRes = iLeft&&iRight; break;
2032 case OP_LOGICAL_OR: iRes = iLeft||iRight; break;
2033 case OP_UNARY_MINUS: iRes = -iLeft; break;
2034 case OP_UNARY_PLUS: iRes = +iLeft; break;
2035 case OP_BITWISE_NOT: iRes = ~iLeft; break;
2036 case OP_LOGICAL_NOT: iRes = !iLeft; break;
2037 default: assert(!"Internal error");
2038 }
2039 Th_SetResultInt(interp, iRes);
2040 }else if( rc==TH_OK && eArgType==ARG_NUMBER ){
@@ -2154,12 +2189,17 @@
2189 }else{
2190 Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
2191 const char *z = &zExpr[i];
2192
2193 switch (c) {
2194 case '0':
2195 if( thNextInteger(interp, z, nExpr-i, &pNew->nValue)==TH_OK ){
2196 break;
2197 }
2198 /* fall through */
2199 case '1': case '2': case '3': case '4': case '5':
2200 case '6': case '7': case '8': case '9':
2201 thNextNumber(interp, z, nExpr-i, &pNew->nValue);
2202 break;
2203
2204 case '$':
2205 thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2410,11 +2450,12 @@
2450 ** '\f' 0x0C
2451 ** '\r' 0x0D
2452 **
2453 ** Whitespace characters have the 0x01 flag set. Decimal digits have the
2454 ** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
2455 ** Alphabet characters have the 0x8 bit set. Hexadecimal digits have the
2456 ** 0x20 flag set.
2457 **
2458 ** The special list characters have the 0x10 flag set
2459 **
2460 ** { } [ ] \ ; ' "
2461 **
@@ -2423,14 +2464,14 @@
2464 */
2465 static unsigned char aCharProp[256] = {
2466 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* 0x0. */
2467 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1. */
2468 5, 4, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x2. */
2469 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 4, 20, 4, 4, 4, 4, /* 0x3. */
2470 4, 44, 44, 44, 44, 44, 44, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */
2471 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 4, 4, /* 0x5. */
2472 4, 44, 44, 44, 44, 44, 44, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */
2473 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 4, 20, 4, 4, /* 0x7. */
2474
2475 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8. */
2476 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9. */
2477 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA. */
@@ -2454,10 +2495,22 @@
2495 return (aCharProp[(unsigned char)c] & 0x11);
2496 }
2497 int th_isalnum(char c){
2498 return (aCharProp[(unsigned char)c] & 0x0A);
2499 }
2500 int th_isalpha(char c){
2501 return (aCharProp[(unsigned char)c] & 0x08);
2502 }
2503 int th_ishexdig(char c){
2504 return (aCharProp[(unsigned char)c] & 0x20);
2505 }
2506 int th_isoctdig(char c){
2507 return ((c|7) == '7');
2508 }
2509 int th_isbindig(char c){
2510 return ((c|1) == '1');
2511 }
2512
2513 #ifndef LONGDOUBLE_TYPE
2514 # define LONGDOUBLE_TYPE long double
2515 #endif
2516
@@ -2570,24 +2623,51 @@
2623 ** interpreter result too.
2624 */
2625 int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
2626 int i = 0;
2627 int iOut = 0;
2628 int base = 10;
2629 int (*isdigit)(char) = th_isdigit;
2630
2631 if( n<0 ){
2632 n = th_strlen(z);
2633 }
2634
2635 if( n>0 && (z[0]=='-' || z[0]=='+') ){
2636 i = 1;
2637 }
2638 if( n>2 ){
2639 if( z[i]=='0' ){
2640 if( z[i+1]=='x' || z[i+1]=='X' ){
2641 i += 2;
2642 base = 16;
2643 isdigit = th_ishexdig;
2644 }else if( z[i+1]=='o' || z[i+1]=='O' ){
2645 i += 2;
2646 base = 8;
2647 isdigit = th_isoctdig;
2648 }else if( z[i+1]=='b' || z[i+1]=='B' ){
2649 i += 2;
2650 base = 2;
2651 isdigit = th_isbindig;
2652 }
2653 }
2654 }
2655 for(; i<n; i++){
2656 char c = z[i];
2657 if( !isdigit(c) ){
2658 Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
2659 return TH_ERROR;
2660 }
2661 if( c>='a' ){
2662 c -= 'a'-10;
2663 }else if( c>='A' ){
2664 c -= 'A'-10;
2665 }else{
2666 c -= '0';
2667 }
2668 iOut = iOut * base + c;
2669 }
2670
2671 if( n>0 && z[0]=='-' ){
2672 iOut *= -1;
2673 }
2674
+4
--- src/th.h
+++ src/th.h
@@ -145,11 +145,15 @@
145145
*/
146146
int th_strlen(const char *);
147147
int th_isdigit(char);
148148
int th_isspace(char);
149149
int th_isalnum(char);
150
+int th_isalpha(char);
150151
int th_isspecial(char);
152
+int th_ishexdig(char);
153
+int th_isoctdig(char);
154
+int th_isbindig(char);
151155
char *th_strdup(Th_Interp *interp, const char *z, int n);
152156
153157
/*
154158
** Interfaces to register the language extensions.
155159
*/
156160
--- src/th.h
+++ src/th.h
@@ -145,11 +145,15 @@
145 */
146 int th_strlen(const char *);
147 int th_isdigit(char);
148 int th_isspace(char);
149 int th_isalnum(char);
 
150 int th_isspecial(char);
 
 
 
151 char *th_strdup(Th_Interp *interp, const char *z, int n);
152
153 /*
154 ** Interfaces to register the language extensions.
155 */
156
--- src/th.h
+++ src/th.h
@@ -145,11 +145,15 @@
145 */
146 int th_strlen(const char *);
147 int th_isdigit(char);
148 int th_isspace(char);
149 int th_isalnum(char);
150 int th_isalpha(char);
151 int th_isspecial(char);
152 int th_ishexdig(char);
153 int th_isoctdig(char);
154 int th_isbindig(char);
155 char *th_strdup(Th_Interp *interp, const char *z, int n);
156
157 /*
158 ** Interfaces to register the language extensions.
159 */
160
+80 -20
--- src/timeline.c
+++ src/timeline.c
@@ -54,23 +54,10 @@
5454
}else{
5555
@ <span class="timelineHistDsp">[%s(z)]</span>
5656
}
5757
}
5858
59
-/*
60
-** Generate a hyperlink to a diff between two versions.
61
-*/
62
-void hyperlink_to_diff(const char *zV1, const char *zV2){
63
- if( g.perm.Hyperlink ){
64
- if( zV2==0 ){
65
- @ %z(href("%R/diff?v2=%s",zV1))[diff]</a>
66
- }else{
67
- @ %z(href("%R/diff?v1=%s&v2=%s",zV1,zV2))[diff]</a>
68
- }
69
- }
70
-}
71
-
7259
/*
7360
** Generate a hyperlink to a date & time.
7461
*/
7562
void hyperlink_to_date(const char *zDate, const char *zSuffix){
7663
if( zSuffix==0 ) zSuffix = "";
@@ -448,11 +435,11 @@
448435
@ (user: %h(zDispUser)%s(zTagList?",":"\051")
449436
}
450437
451438
/* Generate a "detail" link for tags. */
452439
if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
453
- @ [%z(href("%R/info/%S",zUuid))details</a>]
440
+ @ [%z(href("%R/info/%s",zUuid))details</a>]
454441
}
455442
456443
/* Generate the "tags: TAGLIST" at the end of the comment, together
457444
** with hyperlinks to the tag list.
458445
*/
@@ -527,23 +514,23 @@
527514
}
528515
continue;
529516
}
530517
if( isNew ){
531518
@ <li> %h(zFilename) (new file) &nbsp;
532
- @ %z(href("%R/artifact/%S",zNew))[view]</a></li>
519
+ @ %z(href("%R/artifact/%s",zNew))[view]</a></li>
533520
}else if( isDel ){
534521
@ <li> %h(zFilename) (deleted)</li>
535522
}else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
536523
@ <li> %h(zOldName) &rarr; %h(zFilename)
537
- @ %z(href("%R/artifact/%S",zNew))[view]</a></li>
524
+ @ %z(href("%R/artifact/%s",zNew))[view]</a></li>
538525
}else{
539526
if( zOldName!=0 ){
540527
@ <li> %h(zOldName) &rarr; %h(zFilename)
541528
}else{
542529
@ <li> %h(zFilename) &nbsp;
543530
}
544
- @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a></li>
531
+ @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zOld,zNew))[diff]</a></li>
545532
}
546533
}
547534
db_reset(&fchngQuery);
548535
if( inUl ){
549536
@ </ul>
@@ -1442,11 +1429,11 @@
14421429
blob_appendf(&desc, "%d %ss", n, zEType);
14431430
}
14441431
if( zUses ){
14451432
char *zFilenames = names_of_file(zUses);
14461433
blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames,
1447
- href("%R/artifact/%S",zUses), zUses);
1434
+ href("%R/artifact/%s",zUses), zUses);
14481435
tmFlags |= TIMELINE_DISJOINT;
14491436
}
14501437
if( renameOnly ){
14511438
blob_appendf(&desc, " that contain filename changes");
14521439
tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
@@ -1788,11 +1775,11 @@
17881775
n = -20;
17891776
}
17901777
if( zWidth ){
17911778
width = atoi(zWidth);
17921779
if( (width!=0) && (width<=20) ){
1793
- fossil_fatal("--width|-W value must be >20 or 0");
1780
+ fossil_fatal("-W|--width value must be >20 or 0");
17941781
}
17951782
}else{
17961783
width = 79;
17971784
}
17981785
zOffset = find_option("offset",0,1);
@@ -1963,11 +1950,11 @@
19631950
" AND blob.rid=c.cid"
19641951
);
19651952
while( db_step(&q)==SQLITE_ROW ){
19661953
const char *zUuid = db_column_text(&q, 0);
19671954
@ <li>
1968
- @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)&amp;unhide">%S(zUuid)</a>
1955
+ @ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&amp;d=%s(zUuid)&amp;unhide">%S(zUuid)</a>
19691956
}
19701957
db_finalize(&q);
19711958
style_footer();
19721959
}
19731960
@@ -2384,10 +2371,79 @@
23842371
@ </tbody></table>
23852372
db_finalize(&query);
23862373
output_table_sorting_javascript("statsTable","tnx");
23872374
}
23882375
2376
+/*
2377
+** Implements the "byweekday" view for /reports.
2378
+*/
2379
+static void stats_report_day_of_week(){
2380
+ Stmt query = empty_Stmt;
2381
+ int nRowNumber = 0; /* current TR number */
2382
+ int nEventTotal = 0; /* Total event count */
2383
+ int rowClass = 0; /* counter for alternating
2384
+ row colors */
2385
+ Blob sql = empty_blob; /* SQL */
2386
+ int nMaxEvents = 1; /* max number of events for
2387
+ all rows. */
2388
+ static char const * daysOfWeek[] = {
2389
+ "Monday", "Tuesday", "Wednesday", "Thursday",
2390
+ "Friday", "Saturday", "Sunday"
2391
+ };
2392
+
2393
+ stats_report_init_view();
2394
+ stats_report_event_types_menu("byweekday", NULL);
2395
+ blob_append(&sql,
2396
+ "SELECT cast(mtime %% 7 AS INTEGER) dow, "
2397
+ "COUNT(*) AS eventCount "
2398
+ "FROM v_reports "
2399
+ "GROUP BY dow ORDER BY dow",
2400
+ -1);
2401
+ db_prepare(&query, blob_str(&sql));
2402
+ blob_reset(&sql);
2403
+ @ <h1>Timeline Events
2404
+ @ (%s(stats_report_label_for_type())) by Day of the Week</h1>
2405
+ @ <table class='statistics-report-table-events' border='0'
2406
+ @ cellpadding='2' cellspacing='0' id='statsTable'>
2407
+ @ <thead><tr>
2408
+ @ <th>DoW</th>
2409
+ @ <th>Day</th>
2410
+ @ <th>Events</th>
2411
+ @ <th width='90%%'><!-- relative commits graph --></th>
2412
+ @ </tr></thead><tbody>
2413
+ while( SQLITE_ROW == db_step(&query) ){
2414
+ const int nCount = db_column_int(&query, 1);
2415
+ if(nCount>nMaxEvents){
2416
+ nMaxEvents = nCount;
2417
+ }
2418
+ }
2419
+ db_reset(&query);
2420
+ while( SQLITE_ROW == db_step(&query) ){
2421
+ int const dayNum =db_column_int(&query, 0);
2422
+ const int nCount = db_column_int(&query, 1);
2423
+ int nSize = nCount
2424
+ ? (int)(100 * nCount / nMaxEvents)
2425
+ : 0;
2426
+ if(!nCount) continue /* arguable! Possible? */;
2427
+ else if(!nSize) nSize = 1;
2428
+ rowClass = ++nRowNumber % 2;
2429
+ nEventTotal += nCount;
2430
+ @<tr class='row%d(rowClass)'>
2431
+ @ <td>%d(dayNum)</td>
2432
+ @ <td>%s(daysOfWeek[dayNum])</td>
2433
+ @ <td>%d(nCount)</td>
2434
+ @ <td>
2435
+ @ <div class='statistics-report-graph-line'
2436
+ @ style='width:%d(nSize)%%;'>&nbsp;</div>
2437
+ @ </td>
2438
+ @</tr>
2439
+ }
2440
+ @ </tbody></table>
2441
+ db_finalize(&query);
2442
+ output_table_sorting_javascript("statsTable","ntnx");
2443
+}
2444
+
23892445
23902446
/*
23912447
** Helper for stats_report_by_month_year(), which generates a list of
23922448
** week numbers. zTimeframe should be either a timeframe in the form YYYY
23932449
** or YYYY-MM.
@@ -2554,10 +2610,11 @@
25542610
timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
25552611
}
25562612
timeline_submenu(&url, "By Year", "view", "byyear", 0);
25572613
timeline_submenu(&url, "By Month", "view", "bymonth", 0);
25582614
timeline_submenu(&url, "By Week", "view", "byweek", 0);
2615
+ timeline_submenu(&url, "By Weekday", "view", "byweekday", 0);
25592616
timeline_submenu(&url, "By User", "view", "byuser", "user");
25602617
url_reset(&url);
25612618
style_header("Activity Reports");
25622619
if(0==fossil_strcmp(zView,"byyear")){
25632620
stats_report_by_month_year(0, 0, zUserName);
@@ -2565,17 +2622,20 @@
25652622
stats_report_by_month_year(1, 0, zUserName);
25662623
}else if(0==fossil_strcmp(zView,"byweek")){
25672624
stats_report_year_weeks(zUserName);
25682625
}else if(0==fossil_strcmp(zView,"byuser")){
25692626
stats_report_by_user();
2627
+ }else if(0==fossil_strcmp(zView,"byweekday")){
2628
+ stats_report_day_of_week();
25702629
}else{
25712630
@ <h1>Select a report to show:</h1>
25722631
@ <ul>
25732632
@ <li><a href='?view=byyear'>Events by year</a></li>
25742633
@ <li><a href='?view=bymonth'>Events by month</a></li>
25752634
@ <li><a href='?view=byweek'>Events by calendar week</a></li>
2635
+ @ <li><a href='?view=byweekday'>Events by day of the week</a></li>
25762636
@ <li><a href='?view=byuser'>Events by user</a></li>
25772637
@ </ul>
25782638
}
25792639
25802640
style_footer();
25812641
}
25822642
--- src/timeline.c
+++ src/timeline.c
@@ -54,23 +54,10 @@
54 }else{
55 @ <span class="timelineHistDsp">[%s(z)]</span>
56 }
57 }
58
59 /*
60 ** Generate a hyperlink to a diff between two versions.
61 */
62 void hyperlink_to_diff(const char *zV1, const char *zV2){
63 if( g.perm.Hyperlink ){
64 if( zV2==0 ){
65 @ %z(href("%R/diff?v2=%s",zV1))[diff]</a>
66 }else{
67 @ %z(href("%R/diff?v1=%s&v2=%s",zV1,zV2))[diff]</a>
68 }
69 }
70 }
71
72 /*
73 ** Generate a hyperlink to a date & time.
74 */
75 void hyperlink_to_date(const char *zDate, const char *zSuffix){
76 if( zSuffix==0 ) zSuffix = "";
@@ -448,11 +435,11 @@
448 @ (user: %h(zDispUser)%s(zTagList?",":"\051")
449 }
450
451 /* Generate a "detail" link for tags. */
452 if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
453 @ [%z(href("%R/info/%S",zUuid))details</a>]
454 }
455
456 /* Generate the "tags: TAGLIST" at the end of the comment, together
457 ** with hyperlinks to the tag list.
458 */
@@ -527,23 +514,23 @@
527 }
528 continue;
529 }
530 if( isNew ){
531 @ <li> %h(zFilename) (new file) &nbsp;
532 @ %z(href("%R/artifact/%S",zNew))[view]</a></li>
533 }else if( isDel ){
534 @ <li> %h(zFilename) (deleted)</li>
535 }else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
536 @ <li> %h(zOldName) &rarr; %h(zFilename)
537 @ %z(href("%R/artifact/%S",zNew))[view]</a></li>
538 }else{
539 if( zOldName!=0 ){
540 @ <li> %h(zOldName) &rarr; %h(zFilename)
541 }else{
542 @ <li> %h(zFilename) &nbsp;
543 }
544 @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a></li>
545 }
546 }
547 db_reset(&fchngQuery);
548 if( inUl ){
549 @ </ul>
@@ -1442,11 +1429,11 @@
1442 blob_appendf(&desc, "%d %ss", n, zEType);
1443 }
1444 if( zUses ){
1445 char *zFilenames = names_of_file(zUses);
1446 blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames,
1447 href("%R/artifact/%S",zUses), zUses);
1448 tmFlags |= TIMELINE_DISJOINT;
1449 }
1450 if( renameOnly ){
1451 blob_appendf(&desc, " that contain filename changes");
1452 tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
@@ -1788,11 +1775,11 @@
1788 n = -20;
1789 }
1790 if( zWidth ){
1791 width = atoi(zWidth);
1792 if( (width!=0) && (width<=20) ){
1793 fossil_fatal("--width|-W value must be >20 or 0");
1794 }
1795 }else{
1796 width = 79;
1797 }
1798 zOffset = find_option("offset",0,1);
@@ -1963,11 +1950,11 @@
1963 " AND blob.rid=c.cid"
1964 );
1965 while( db_step(&q)==SQLITE_ROW ){
1966 const char *zUuid = db_column_text(&q, 0);
1967 @ <li>
1968 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)&amp;unhide">%S(zUuid)</a>
1969 }
1970 db_finalize(&q);
1971 style_footer();
1972 }
1973
@@ -2384,10 +2371,79 @@
2384 @ </tbody></table>
2385 db_finalize(&query);
2386 output_table_sorting_javascript("statsTable","tnx");
2387 }
2388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2389
2390 /*
2391 ** Helper for stats_report_by_month_year(), which generates a list of
2392 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2393 ** or YYYY-MM.
@@ -2554,10 +2610,11 @@
2554 timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
2555 }
2556 timeline_submenu(&url, "By Year", "view", "byyear", 0);
2557 timeline_submenu(&url, "By Month", "view", "bymonth", 0);
2558 timeline_submenu(&url, "By Week", "view", "byweek", 0);
 
2559 timeline_submenu(&url, "By User", "view", "byuser", "user");
2560 url_reset(&url);
2561 style_header("Activity Reports");
2562 if(0==fossil_strcmp(zView,"byyear")){
2563 stats_report_by_month_year(0, 0, zUserName);
@@ -2565,17 +2622,20 @@
2565 stats_report_by_month_year(1, 0, zUserName);
2566 }else if(0==fossil_strcmp(zView,"byweek")){
2567 stats_report_year_weeks(zUserName);
2568 }else if(0==fossil_strcmp(zView,"byuser")){
2569 stats_report_by_user();
 
 
2570 }else{
2571 @ <h1>Select a report to show:</h1>
2572 @ <ul>
2573 @ <li><a href='?view=byyear'>Events by year</a></li>
2574 @ <li><a href='?view=bymonth'>Events by month</a></li>
2575 @ <li><a href='?view=byweek'>Events by calendar week</a></li>
 
2576 @ <li><a href='?view=byuser'>Events by user</a></li>
2577 @ </ul>
2578 }
2579
2580 style_footer();
2581 }
2582
--- src/timeline.c
+++ src/timeline.c
@@ -54,23 +54,10 @@
54 }else{
55 @ <span class="timelineHistDsp">[%s(z)]</span>
56 }
57 }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
59 /*
60 ** Generate a hyperlink to a date & time.
61 */
62 void hyperlink_to_date(const char *zDate, const char *zSuffix){
63 if( zSuffix==0 ) zSuffix = "";
@@ -448,11 +435,11 @@
435 @ (user: %h(zDispUser)%s(zTagList?",":"\051")
436 }
437
438 /* Generate a "detail" link for tags. */
439 if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
440 @ [%z(href("%R/info/%s",zUuid))details</a>]
441 }
442
443 /* Generate the "tags: TAGLIST" at the end of the comment, together
444 ** with hyperlinks to the tag list.
445 */
@@ -527,23 +514,23 @@
514 }
515 continue;
516 }
517 if( isNew ){
518 @ <li> %h(zFilename) (new file) &nbsp;
519 @ %z(href("%R/artifact/%s",zNew))[view]</a></li>
520 }else if( isDel ){
521 @ <li> %h(zFilename) (deleted)</li>
522 }else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
523 @ <li> %h(zOldName) &rarr; %h(zFilename)
524 @ %z(href("%R/artifact/%s",zNew))[view]</a></li>
525 }else{
526 if( zOldName!=0 ){
527 @ <li> %h(zOldName) &rarr; %h(zFilename)
528 }else{
529 @ <li> %h(zFilename) &nbsp;
530 }
531 @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zOld,zNew))[diff]</a></li>
532 }
533 }
534 db_reset(&fchngQuery);
535 if( inUl ){
536 @ </ul>
@@ -1442,11 +1429,11 @@
1429 blob_appendf(&desc, "%d %ss", n, zEType);
1430 }
1431 if( zUses ){
1432 char *zFilenames = names_of_file(zUses);
1433 blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames,
1434 href("%R/artifact/%s",zUses), zUses);
1435 tmFlags |= TIMELINE_DISJOINT;
1436 }
1437 if( renameOnly ){
1438 blob_appendf(&desc, " that contain filename changes");
1439 tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
@@ -1788,11 +1775,11 @@
1775 n = -20;
1776 }
1777 if( zWidth ){
1778 width = atoi(zWidth);
1779 if( (width!=0) && (width<=20) ){
1780 fossil_fatal("-W|--width value must be >20 or 0");
1781 }
1782 }else{
1783 width = 79;
1784 }
1785 zOffset = find_option("offset",0,1);
@@ -1963,11 +1950,11 @@
1950 " AND blob.rid=c.cid"
1951 );
1952 while( db_step(&q)==SQLITE_ROW ){
1953 const char *zUuid = db_column_text(&q, 0);
1954 @ <li>
1955 @ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&amp;d=%s(zUuid)&amp;unhide">%S(zUuid)</a>
1956 }
1957 db_finalize(&q);
1958 style_footer();
1959 }
1960
@@ -2384,10 +2371,79 @@
2371 @ </tbody></table>
2372 db_finalize(&query);
2373 output_table_sorting_javascript("statsTable","tnx");
2374 }
2375
2376 /*
2377 ** Implements the "byweekday" view for /reports.
2378 */
2379 static void stats_report_day_of_week(){
2380 Stmt query = empty_Stmt;
2381 int nRowNumber = 0; /* current TR number */
2382 int nEventTotal = 0; /* Total event count */
2383 int rowClass = 0; /* counter for alternating
2384 row colors */
2385 Blob sql = empty_blob; /* SQL */
2386 int nMaxEvents = 1; /* max number of events for
2387 all rows. */
2388 static char const * daysOfWeek[] = {
2389 "Monday", "Tuesday", "Wednesday", "Thursday",
2390 "Friday", "Saturday", "Sunday"
2391 };
2392
2393 stats_report_init_view();
2394 stats_report_event_types_menu("byweekday", NULL);
2395 blob_append(&sql,
2396 "SELECT cast(mtime %% 7 AS INTEGER) dow, "
2397 "COUNT(*) AS eventCount "
2398 "FROM v_reports "
2399 "GROUP BY dow ORDER BY dow",
2400 -1);
2401 db_prepare(&query, blob_str(&sql));
2402 blob_reset(&sql);
2403 @ <h1>Timeline Events
2404 @ (%s(stats_report_label_for_type())) by Day of the Week</h1>
2405 @ <table class='statistics-report-table-events' border='0'
2406 @ cellpadding='2' cellspacing='0' id='statsTable'>
2407 @ <thead><tr>
2408 @ <th>DoW</th>
2409 @ <th>Day</th>
2410 @ <th>Events</th>
2411 @ <th width='90%%'><!-- relative commits graph --></th>
2412 @ </tr></thead><tbody>
2413 while( SQLITE_ROW == db_step(&query) ){
2414 const int nCount = db_column_int(&query, 1);
2415 if(nCount>nMaxEvents){
2416 nMaxEvents = nCount;
2417 }
2418 }
2419 db_reset(&query);
2420 while( SQLITE_ROW == db_step(&query) ){
2421 int const dayNum =db_column_int(&query, 0);
2422 const int nCount = db_column_int(&query, 1);
2423 int nSize = nCount
2424 ? (int)(100 * nCount / nMaxEvents)
2425 : 0;
2426 if(!nCount) continue /* arguable! Possible? */;
2427 else if(!nSize) nSize = 1;
2428 rowClass = ++nRowNumber % 2;
2429 nEventTotal += nCount;
2430 @<tr class='row%d(rowClass)'>
2431 @ <td>%d(dayNum)</td>
2432 @ <td>%s(daysOfWeek[dayNum])</td>
2433 @ <td>%d(nCount)</td>
2434 @ <td>
2435 @ <div class='statistics-report-graph-line'
2436 @ style='width:%d(nSize)%%;'>&nbsp;</div>
2437 @ </td>
2438 @</tr>
2439 }
2440 @ </tbody></table>
2441 db_finalize(&query);
2442 output_table_sorting_javascript("statsTable","ntnx");
2443 }
2444
2445
2446 /*
2447 ** Helper for stats_report_by_month_year(), which generates a list of
2448 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2449 ** or YYYY-MM.
@@ -2554,10 +2610,11 @@
2610 timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
2611 }
2612 timeline_submenu(&url, "By Year", "view", "byyear", 0);
2613 timeline_submenu(&url, "By Month", "view", "bymonth", 0);
2614 timeline_submenu(&url, "By Week", "view", "byweek", 0);
2615 timeline_submenu(&url, "By Weekday", "view", "byweekday", 0);
2616 timeline_submenu(&url, "By User", "view", "byuser", "user");
2617 url_reset(&url);
2618 style_header("Activity Reports");
2619 if(0==fossil_strcmp(zView,"byyear")){
2620 stats_report_by_month_year(0, 0, zUserName);
@@ -2565,17 +2622,20 @@
2622 stats_report_by_month_year(1, 0, zUserName);
2623 }else if(0==fossil_strcmp(zView,"byweek")){
2624 stats_report_year_weeks(zUserName);
2625 }else if(0==fossil_strcmp(zView,"byuser")){
2626 stats_report_by_user();
2627 }else if(0==fossil_strcmp(zView,"byweekday")){
2628 stats_report_day_of_week();
2629 }else{
2630 @ <h1>Select a report to show:</h1>
2631 @ <ul>
2632 @ <li><a href='?view=byyear'>Events by year</a></li>
2633 @ <li><a href='?view=bymonth'>Events by month</a></li>
2634 @ <li><a href='?view=byweek'>Events by calendar week</a></li>
2635 @ <li><a href='?view=byweekday'>Events by day of the week</a></li>
2636 @ <li><a href='?view=byuser'>Events by user</a></li>
2637 @ </ul>
2638 }
2639
2640 style_footer();
2641 }
2642
+12 -19
--- src/tkt.c
+++ src/tkt.c
@@ -446,14 +446,14 @@
446446
style_submenu_element("Attach", "Add An Attachment",
447447
"%s/attachadd?tkt=%T&from=%s/tktview/%t",
448448
g.zTop, zUuid, g.zTop, zUuid);
449449
}
450450
if( P("plaintext") ){
451
- style_submenu_element("Formatted", "Formatted", "%R/tktview/%S", zUuid);
451
+ style_submenu_element("Formatted", "Formatted", "%R/tktview/%s", zUuid);
452452
}else{
453453
style_submenu_element("Plaintext", "Plaintext",
454
- "%R/tktview/%S?plaintext", zUuid);
454
+ "%R/tktview/%s?plaintext", zUuid);
455455
}
456456
style_header("View Ticket");
457457
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
458458
ticket_init();
459459
initializeVariablesFromCGI();
@@ -895,14 +895,14 @@
895895
"%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
896896
style_submenu_element("Timeline", "Timeline",
897897
"%s/tkttimeline?name=%s", g.zTop, zUuid);
898898
if( P("plaintext")!=0 ){
899899
style_submenu_element("Formatted", "Formatted",
900
- "%R/tkthistory/%S", zUuid);
900
+ "%R/tkthistory/%s", zUuid);
901901
}else{
902902
style_submenu_element("Plaintext", "Plaintext",
903
- "%R/tkthistory/%S?plaintext", zUuid);
903
+ "%R/tkthistory/%s?plaintext", zUuid);
904904
}
905905
style_header(zTitle);
906906
free(zTitle);
907907
908908
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
@@ -924,17 +924,14 @@
924924
" ORDER BY 1",
925925
timeline_utc(), tagid, timeline_utc(), tagid
926926
);
927927
while( db_step(&q)==SQLITE_ROW ){
928928
Manifest *pTicket;
929
- char zShort[12];
930929
const char *zDate = db_column_text(&q, 0);
931930
int rid = db_column_int(&q, 1);
932931
const char *zChngUuid = db_column_text(&q, 2);
933932
const char *zFile = db_column_text(&q, 4);
934
- memcpy(zShort, zChngUuid, 10);
935
- zShort[10] = 0;
936933
if( nChng==0 ){
937934
@ <ol>
938935
}
939936
nChng++;
940937
if( zFile!=0 ){
@@ -944,22 +941,22 @@
944941
@
945942
@ <li><p>Delete attachment "%h(zFile)"
946943
}else{
947944
@
948945
@ <li><p>Add attachment
949
- @ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>"
946
+ @ "%z(href("%R/artifact/%s",zSrc))%s(zFile)</a>"
950947
}
951
- @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948
+ @ [%z(href("%R/artifact/%s",zChngUuid))%.10s(zChngUuid)</a>]
952949
@ (rid %d(rid)) by
953950
hyperlink_to_user(zUser,zDate," on");
954951
hyperlink_to_date(zDate, ".</p>");
955952
}else{
956953
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
957954
if( pTicket ){
958955
@
959956
@ <li><p>Ticket change
960
- @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
957
+ @ [%z(href("%R/artifact/%s",zChngUuid))%.10s(zChngUuid)</a>]
961958
@ (rid %d(rid)) by
962959
hyperlink_to_user(pTicket->zUser,zDate," on");
963960
hyperlink_to_date(zDate, ":");
964961
@ </p>
965962
ticket_output_change_artifact(pTicket, "a");
@@ -1219,35 +1216,31 @@
12191216
zTktUuid);
12201217
if( tagid==0 ){
12211218
fossil_fatal("no such ticket %h", zTktUuid);
12221219
}
12231220
db_prepare(&q,
1224
- "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL"
1221
+ "SELECT datetime(mtime%s), objid, NULL, NULL, NULL"
12251222
" FROM event, blob"
12261223
" WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
12271224
" AND blob.rid=event.objid"
12281225
" UNION "
1229
- "SELECT datetime(mtime%s), attachid, uuid, src, "
1230
- " filename, user"
1226
+ "SELECT datetime(mtime%s), attachid, filename, "
1227
+ " src, user"
12311228
" FROM attachment, blob"
12321229
" WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
12331230
" AND blob.rid=attachid"
12341231
" ORDER BY 1 DESC",
12351232
timeline_utc(), tagid, timeline_utc(), tagid
12361233
);
12371234
while( db_step(&q)==SQLITE_ROW ){
12381235
Manifest *pTicket;
1239
- char zShort[12];
12401236
const char *zDate = db_column_text(&q, 0);
12411237
int rid = db_column_int(&q, 1);
1242
- const char *zChngUuid = db_column_text(&q, 2);
1243
- const char *zFile = db_column_text(&q, 4);
1244
- memcpy(zShort, zChngUuid, 10);
1245
- zShort[10] = 0;
1238
+ const char *zFile = db_column_text(&q, 2);
12461239
if( zFile!=0 ){
12471240
const char *zSrc = db_column_text(&q, 3);
1248
- const char *zUser = db_column_text(&q, 5);
1241
+ const char *zUser = db_column_text(&q, 4);
12491242
if( zSrc==0 || zSrc[0]==0 ){
12501243
fossil_print("Delete attachment %s\n", zFile);
12511244
}else{
12521245
fossil_print("Add attachment %s\n", zFile);
12531246
}
12541247
--- src/tkt.c
+++ src/tkt.c
@@ -446,14 +446,14 @@
446 style_submenu_element("Attach", "Add An Attachment",
447 "%s/attachadd?tkt=%T&from=%s/tktview/%t",
448 g.zTop, zUuid, g.zTop, zUuid);
449 }
450 if( P("plaintext") ){
451 style_submenu_element("Formatted", "Formatted", "%R/tktview/%S", zUuid);
452 }else{
453 style_submenu_element("Plaintext", "Plaintext",
454 "%R/tktview/%S?plaintext", zUuid);
455 }
456 style_header("View Ticket");
457 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
458 ticket_init();
459 initializeVariablesFromCGI();
@@ -895,14 +895,14 @@
895 "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
896 style_submenu_element("Timeline", "Timeline",
897 "%s/tkttimeline?name=%s", g.zTop, zUuid);
898 if( P("plaintext")!=0 ){
899 style_submenu_element("Formatted", "Formatted",
900 "%R/tkthistory/%S", zUuid);
901 }else{
902 style_submenu_element("Plaintext", "Plaintext",
903 "%R/tkthistory/%S?plaintext", zUuid);
904 }
905 style_header(zTitle);
906 free(zTitle);
907
908 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
@@ -924,17 +924,14 @@
924 " ORDER BY 1",
925 timeline_utc(), tagid, timeline_utc(), tagid
926 );
927 while( db_step(&q)==SQLITE_ROW ){
928 Manifest *pTicket;
929 char zShort[12];
930 const char *zDate = db_column_text(&q, 0);
931 int rid = db_column_int(&q, 1);
932 const char *zChngUuid = db_column_text(&q, 2);
933 const char *zFile = db_column_text(&q, 4);
934 memcpy(zShort, zChngUuid, 10);
935 zShort[10] = 0;
936 if( nChng==0 ){
937 @ <ol>
938 }
939 nChng++;
940 if( zFile!=0 ){
@@ -944,22 +941,22 @@
944 @
945 @ <li><p>Delete attachment "%h(zFile)"
946 }else{
947 @
948 @ <li><p>Add attachment
949 @ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>"
950 }
951 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
952 @ (rid %d(rid)) by
953 hyperlink_to_user(zUser,zDate," on");
954 hyperlink_to_date(zDate, ".</p>");
955 }else{
956 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
957 if( pTicket ){
958 @
959 @ <li><p>Ticket change
960 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
961 @ (rid %d(rid)) by
962 hyperlink_to_user(pTicket->zUser,zDate," on");
963 hyperlink_to_date(zDate, ":");
964 @ </p>
965 ticket_output_change_artifact(pTicket, "a");
@@ -1219,35 +1216,31 @@
1219 zTktUuid);
1220 if( tagid==0 ){
1221 fossil_fatal("no such ticket %h", zTktUuid);
1222 }
1223 db_prepare(&q,
1224 "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL"
1225 " FROM event, blob"
1226 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
1227 " AND blob.rid=event.objid"
1228 " UNION "
1229 "SELECT datetime(mtime%s), attachid, uuid, src, "
1230 " filename, user"
1231 " FROM attachment, blob"
1232 " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
1233 " AND blob.rid=attachid"
1234 " ORDER BY 1 DESC",
1235 timeline_utc(), tagid, timeline_utc(), tagid
1236 );
1237 while( db_step(&q)==SQLITE_ROW ){
1238 Manifest *pTicket;
1239 char zShort[12];
1240 const char *zDate = db_column_text(&q, 0);
1241 int rid = db_column_int(&q, 1);
1242 const char *zChngUuid = db_column_text(&q, 2);
1243 const char *zFile = db_column_text(&q, 4);
1244 memcpy(zShort, zChngUuid, 10);
1245 zShort[10] = 0;
1246 if( zFile!=0 ){
1247 const char *zSrc = db_column_text(&q, 3);
1248 const char *zUser = db_column_text(&q, 5);
1249 if( zSrc==0 || zSrc[0]==0 ){
1250 fossil_print("Delete attachment %s\n", zFile);
1251 }else{
1252 fossil_print("Add attachment %s\n", zFile);
1253 }
1254
--- src/tkt.c
+++ src/tkt.c
@@ -446,14 +446,14 @@
446 style_submenu_element("Attach", "Add An Attachment",
447 "%s/attachadd?tkt=%T&from=%s/tktview/%t",
448 g.zTop, zUuid, g.zTop, zUuid);
449 }
450 if( P("plaintext") ){
451 style_submenu_element("Formatted", "Formatted", "%R/tktview/%s", zUuid);
452 }else{
453 style_submenu_element("Plaintext", "Plaintext",
454 "%R/tktview/%s?plaintext", zUuid);
455 }
456 style_header("View Ticket");
457 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
458 ticket_init();
459 initializeVariablesFromCGI();
@@ -895,14 +895,14 @@
895 "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
896 style_submenu_element("Timeline", "Timeline",
897 "%s/tkttimeline?name=%s", g.zTop, zUuid);
898 if( P("plaintext")!=0 ){
899 style_submenu_element("Formatted", "Formatted",
900 "%R/tkthistory/%s", zUuid);
901 }else{
902 style_submenu_element("Plaintext", "Plaintext",
903 "%R/tkthistory/%s?plaintext", zUuid);
904 }
905 style_header(zTitle);
906 free(zTitle);
907
908 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
@@ -924,17 +924,14 @@
924 " ORDER BY 1",
925 timeline_utc(), tagid, timeline_utc(), tagid
926 );
927 while( db_step(&q)==SQLITE_ROW ){
928 Manifest *pTicket;
 
929 const char *zDate = db_column_text(&q, 0);
930 int rid = db_column_int(&q, 1);
931 const char *zChngUuid = db_column_text(&q, 2);
932 const char *zFile = db_column_text(&q, 4);
 
 
933 if( nChng==0 ){
934 @ <ol>
935 }
936 nChng++;
937 if( zFile!=0 ){
@@ -944,22 +941,22 @@
941 @
942 @ <li><p>Delete attachment "%h(zFile)"
943 }else{
944 @
945 @ <li><p>Add attachment
946 @ "%z(href("%R/artifact/%s",zSrc))%s(zFile)</a>"
947 }
948 @ [%z(href("%R/artifact/%s",zChngUuid))%.10s(zChngUuid)</a>]
949 @ (rid %d(rid)) by
950 hyperlink_to_user(zUser,zDate," on");
951 hyperlink_to_date(zDate, ".</p>");
952 }else{
953 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
954 if( pTicket ){
955 @
956 @ <li><p>Ticket change
957 @ [%z(href("%R/artifact/%s",zChngUuid))%.10s(zChngUuid)</a>]
958 @ (rid %d(rid)) by
959 hyperlink_to_user(pTicket->zUser,zDate," on");
960 hyperlink_to_date(zDate, ":");
961 @ </p>
962 ticket_output_change_artifact(pTicket, "a");
@@ -1219,35 +1216,31 @@
1216 zTktUuid);
1217 if( tagid==0 ){
1218 fossil_fatal("no such ticket %h", zTktUuid);
1219 }
1220 db_prepare(&q,
1221 "SELECT datetime(mtime%s), objid, NULL, NULL, NULL"
1222 " FROM event, blob"
1223 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
1224 " AND blob.rid=event.objid"
1225 " UNION "
1226 "SELECT datetime(mtime%s), attachid, filename, "
1227 " src, user"
1228 " FROM attachment, blob"
1229 " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
1230 " AND blob.rid=attachid"
1231 " ORDER BY 1 DESC",
1232 timeline_utc(), tagid, timeline_utc(), tagid
1233 );
1234 while( db_step(&q)==SQLITE_ROW ){
1235 Manifest *pTicket;
 
1236 const char *zDate = db_column_text(&q, 0);
1237 int rid = db_column_int(&q, 1);
1238 const char *zFile = db_column_text(&q, 2);
 
 
 
1239 if( zFile!=0 ){
1240 const char *zSrc = db_column_text(&q, 3);
1241 const char *zUser = db_column_text(&q, 4);
1242 if( zSrc==0 || zSrc[0]==0 ){
1243 fossil_print("Delete attachment %s\n", zFile);
1244 }else{
1245 fossil_print("Add attachment %s\n", zFile);
1246 }
1247
--- src/update.c
+++ src/update.c
@@ -625,10 +625,12 @@
625625
ManifestFile *pFile;
626626
int rid=0;
627627
628628
if( revision ){
629629
rid = name_to_typed_rid(revision,"ci");
630
+ }else if( !g.localOpen ){
631
+ rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
630632
}else{
631633
rid = db_lget_int("checkout", 0);
632634
}
633635
if( !is_a_version(rid) ){
634636
if( errCode>0 ) return errCode;
635637
--- src/update.c
+++ src/update.c
@@ -625,10 +625,12 @@
625 ManifestFile *pFile;
626 int rid=0;
627
628 if( revision ){
629 rid = name_to_typed_rid(revision,"ci");
 
 
630 }else{
631 rid = db_lget_int("checkout", 0);
632 }
633 if( !is_a_version(rid) ){
634 if( errCode>0 ) return errCode;
635
--- src/update.c
+++ src/update.c
@@ -625,10 +625,12 @@
625 ManifestFile *pFile;
626 int rid=0;
627
628 if( revision ){
629 rid = name_to_typed_rid(revision,"ci");
630 }else if( !g.localOpen ){
631 rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
632 }else{
633 rid = db_lget_int("checkout", 0);
634 }
635 if( !is_a_version(rid) ){
636 if( errCode>0 ) return errCode;
637
+61 -61
--- src/url.c
+++ src/url.c
@@ -275,22 +275,22 @@
275275
276276
/*
277277
** Parse the given URL, which describes a sync server. Populate variables
278278
** in the global "g" structure as follows:
279279
**
280
-** g.urlIsFile True if FILE:
281
-** g.urlIsHttps True if HTTPS:
282
-** g.urlIsSsh True if SSH:
283
-** g.urlProtocol "http" or "https" or "file"
284
-** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
285
-** g.urlPort TCP port number for HTTP or HTTPS.
286
-** g.urlDfltPort Default TCP port number (80 or 443).
287
-** g.urlPath Path name for HTTP or HTTPS.
288
-** g.urlUser Userid.
289
-** g.urlPasswd Password.
290
-** g.urlHostname HOST:PORT or just HOST if port is the default.
291
-** g.urlCanonical The URL in canonical form, omitting the password
280
+** g.url.isFile True if FILE:
281
+** g.url.isHttps True if HTTPS:
282
+** g.url.isSsh True if SSH:
283
+** g.url.protocol "http" or "https" or "file"
284
+** g.url.name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
285
+** g.url.port TCP port number for HTTP or HTTPS.
286
+** g.url.dfltPort Default TCP port number (80 or 443).
287
+** g.url.path Path name for HTTP or HTTPS.
288
+** g.url.user Userid.
289
+** g.url.passwd Password.
290
+** g.url.hostname HOST:PORT or just HOST if port is the default.
291
+** g.url.canonical The URL in canonical form, omitting the password
292292
**
293293
** HTTP url format as follows (HTTPS is the same with a different scheme):
294294
**
295295
** http://userid:password@host:port/path
296296
**
@@ -298,11 +298,11 @@
298298
**
299299
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
300300
**
301301
*/
302302
void url_parse(const char *zUrl, unsigned int urlFlags){
303
- url_parse_local(zUrl, urlFlags, GLOBAL_URL());
303
+ url_parse_local(zUrl, urlFlags, &g.url);
304304
}
305305
306306
/*
307307
** COMMAND: test-urlparser
308308
**
@@ -323,25 +323,25 @@
323323
if( g.argc!=3 && g.argc!=4 ){
324324
usage("URL");
325325
}
326326
url_parse(g.argv[2], fg);
327327
for(i=0; i<2; i++){
328
- fossil_print("g.urlIsFile = %d\n", g.urlIsFile);
329
- fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps);
330
- fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh);
331
- fossil_print("g.urlProtocol = %s\n", g.urlProtocol);
332
- fossil_print("g.urlName = %s\n", g.urlName);
333
- fossil_print("g.urlPort = %d\n", g.urlPort);
334
- fossil_print("g.urlDfltPort = %d\n", g.urlDfltPort);
335
- fossil_print("g.urlHostname = %s\n", g.urlHostname);
336
- fossil_print("g.urlPath = %s\n", g.urlPath);
337
- fossil_print("g.urlUser = %s\n", g.urlUser);
338
- fossil_print("g.urlPasswd = %s\n", g.urlPasswd);
339
- fossil_print("g.urlCanonical = %s\n", g.urlCanonical);
340
- fossil_print("g.urlFossil = %s\n", g.urlFossil);
341
- fossil_print("g.urlFlags = 0x%02x\n", g.urlFlags);
342
- if( g.urlIsFile || g.urlIsSsh ) break;
328
+ fossil_print("g.url.isFile = %d\n", g.url.isFile);
329
+ fossil_print("g.url.isHttps = %d\n", g.url.isHttps);
330
+ fossil_print("g.url.isSsh = %d\n", g.url.isSsh);
331
+ fossil_print("g.url.protocol = %s\n", g.url.protocol);
332
+ fossil_print("g.url.name = %s\n", g.url.name);
333
+ fossil_print("g.url.port = %d\n", g.url.port);
334
+ fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort);
335
+ fossil_print("g.url.hostname = %s\n", g.url.hostname);
336
+ fossil_print("g.url.path = %s\n", g.url.path);
337
+ fossil_print("g.url.user = %s\n", g.url.user);
338
+ fossil_print("g.url.passwd = %s\n", g.url.passwd);
339
+ fossil_print("g.url.canonical = %s\n", g.url.canonical);
340
+ fossil_print("g.url.fossil = %s\n", g.url.fossil);
341
+ fossil_print("g.url.flags = 0x%02x\n", g.url.flags);
342
+ if( g.url.isFile || g.url.isSsh ) break;
343343
if( i==0 ){
344344
fossil_print("********\n");
345345
url_enable_proxy("Using proxy: ");
346346
}
347347
}
@@ -385,38 +385,38 @@
385385
if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
386386
zProxy = fossil_getenv("http_proxy");
387387
}
388388
}
389389
if( zProxy && zProxy[0] && !is_false(zProxy)
390
- && !g.urlIsSsh && !g.urlIsFile ){
391
- char *zOriginalUrl = g.urlCanonical;
392
- char *zOriginalHost = g.urlHostname;
393
- int fOriginalIsHttps = g.urlIsHttps;
394
- char *zOriginalUser = g.urlUser;
395
- char *zOriginalPasswd = g.urlPasswd;
396
- char *zOriginalUrlPath = g.urlPath;
397
- int iOriginalPort = g.urlPort;
398
- unsigned uOriginalFlags = g.urlFlags;
399
- g.urlUser = 0;
400
- g.urlPasswd = "";
390
+ && !g.url.isSsh && !g.url.isFile ){
391
+ char *zOriginalUrl = g.url.canonical;
392
+ char *zOriginalHost = g.url.hostname;
393
+ int fOriginalIsHttps = g.url.isHttps;
394
+ char *zOriginalUser = g.url.user;
395
+ char *zOriginalPasswd = g.url.passwd;
396
+ char *zOriginalUrlPath = g.url.path;
397
+ int iOriginalPort = g.url.port;
398
+ unsigned uOriginalFlags = g.url.flags;
399
+ g.url.user = 0;
400
+ g.url.passwd = "";
401401
url_parse(zProxy, 0);
402
- if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
403
- g.urlPath = zOriginalUrl;
404
- g.urlHostname = zOriginalHost;
405
- if( g.urlUser ){
406
- char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
402
+ if( zMsg ) fossil_print("%s%s\n", zMsg, g.url.canonical);
403
+ g.url.path = zOriginalUrl;
404
+ g.url.hostname = zOriginalHost;
405
+ if( g.url.user ){
406
+ char *zCredentials1 = mprintf("%s:%s", g.url.user, g.url.passwd);
407407
char *zCredentials2 = encode64(zCredentials1, -1);
408
- g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
408
+ g.url.proxyAuth = mprintf("Basic %z", zCredentials2);
409409
free(zCredentials1);
410410
}
411
- g.urlUser = zOriginalUser;
412
- g.urlPasswd = zOriginalPasswd;
413
- g.urlIsHttps = fOriginalIsHttps;
414
- g.useProxy = 1;
415
- g.proxyUrlPath = zOriginalUrlPath;
416
- g.proxyOrigPort = iOriginalPort;
417
- g.urlFlags = uOriginalFlags;
411
+ g.url.user = zOriginalUser;
412
+ g.url.passwd = zOriginalPasswd;
413
+ g.url.isHttps = fOriginalIsHttps;
414
+ g.url.useProxy = 1;
415
+ g.url.proxyUrlPath = zOriginalUrlPath;
416
+ g.url.proxyOrigPort = iOriginalPort;
417
+ g.url.flags = uOriginalFlags;
418418
}
419419
}
420420
421421
#if INTERFACE
422422
/*
@@ -529,35 +529,35 @@
529529
pUrlData->user);
530530
}
531531
}
532532
533533
/*
534
-** Prompt the user for the password for g.urlUser. Store the result
535
-** in g.urlPasswd.
534
+** Prompt the user for the password for g.url.user. Store the result
535
+** in g.url.passwd.
536536
*/
537537
void url_prompt_for_password(void){
538
- url_prompt_for_password_local(GLOBAL_URL());
538
+ url_prompt_for_password_local(&g.url);
539539
}
540540
541541
/*
542542
** Remember the URL and password if requested.
543543
*/
544544
void url_remember(void){
545
- if( g.urlFlags & URL_REMEMBER ){
546
- db_set("last-sync-url", g.urlCanonical, 0);
547
- if( g.urlUser!=0 && g.urlPasswd!=0 && ( g.urlFlags & URL_REMEMBER_PW ) ){
548
- db_set("last-sync-pw", obscure(g.urlPasswd), 0);
545
+ if( g.url.flags & URL_REMEMBER ){
546
+ db_set("last-sync-url", g.url.canonical, 0);
547
+ if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){
548
+ db_set("last-sync-pw", obscure(g.url.passwd), 0);
549549
}
550550
}
551551
}
552552
553553
/* Preemptively prompt for a password if a username is given in the
554554
** URL but no password.
555555
*/
556556
void url_get_password_if_needed(void){
557
- if( (g.urlUser && g.urlUser[0])
558
- && (g.urlPasswd==0 || g.urlPasswd[0]==0)
557
+ if( (g.url.user && g.url.user[0])
558
+ && (g.url.passwd==0 || g.url.passwd[0]==0)
559559
&& isatty(fileno(stdin))
560560
){
561561
url_prompt_for_password();
562562
}
563563
}
564564
--- src/url.c
+++ src/url.c
@@ -275,22 +275,22 @@
275
276 /*
277 ** Parse the given URL, which describes a sync server. Populate variables
278 ** in the global "g" structure as follows:
279 **
280 ** g.urlIsFile True if FILE:
281 ** g.urlIsHttps True if HTTPS:
282 ** g.urlIsSsh True if SSH:
283 ** g.urlProtocol "http" or "https" or "file"
284 ** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
285 ** g.urlPort TCP port number for HTTP or HTTPS.
286 ** g.urlDfltPort Default TCP port number (80 or 443).
287 ** g.urlPath Path name for HTTP or HTTPS.
288 ** g.urlUser Userid.
289 ** g.urlPasswd Password.
290 ** g.urlHostname HOST:PORT or just HOST if port is the default.
291 ** g.urlCanonical The URL in canonical form, omitting the password
292 **
293 ** HTTP url format as follows (HTTPS is the same with a different scheme):
294 **
295 ** http://userid:password@host:port/path
296 **
@@ -298,11 +298,11 @@
298 **
299 ** ssh://userid@host:port/path?fossil=path/to/fossil.exe
300 **
301 */
302 void url_parse(const char *zUrl, unsigned int urlFlags){
303 url_parse_local(zUrl, urlFlags, GLOBAL_URL());
304 }
305
306 /*
307 ** COMMAND: test-urlparser
308 **
@@ -323,25 +323,25 @@
323 if( g.argc!=3 && g.argc!=4 ){
324 usage("URL");
325 }
326 url_parse(g.argv[2], fg);
327 for(i=0; i<2; i++){
328 fossil_print("g.urlIsFile = %d\n", g.urlIsFile);
329 fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps);
330 fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh);
331 fossil_print("g.urlProtocol = %s\n", g.urlProtocol);
332 fossil_print("g.urlName = %s\n", g.urlName);
333 fossil_print("g.urlPort = %d\n", g.urlPort);
334 fossil_print("g.urlDfltPort = %d\n", g.urlDfltPort);
335 fossil_print("g.urlHostname = %s\n", g.urlHostname);
336 fossil_print("g.urlPath = %s\n", g.urlPath);
337 fossil_print("g.urlUser = %s\n", g.urlUser);
338 fossil_print("g.urlPasswd = %s\n", g.urlPasswd);
339 fossil_print("g.urlCanonical = %s\n", g.urlCanonical);
340 fossil_print("g.urlFossil = %s\n", g.urlFossil);
341 fossil_print("g.urlFlags = 0x%02x\n", g.urlFlags);
342 if( g.urlIsFile || g.urlIsSsh ) break;
343 if( i==0 ){
344 fossil_print("********\n");
345 url_enable_proxy("Using proxy: ");
346 }
347 }
@@ -385,38 +385,38 @@
385 if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
386 zProxy = fossil_getenv("http_proxy");
387 }
388 }
389 if( zProxy && zProxy[0] && !is_false(zProxy)
390 && !g.urlIsSsh && !g.urlIsFile ){
391 char *zOriginalUrl = g.urlCanonical;
392 char *zOriginalHost = g.urlHostname;
393 int fOriginalIsHttps = g.urlIsHttps;
394 char *zOriginalUser = g.urlUser;
395 char *zOriginalPasswd = g.urlPasswd;
396 char *zOriginalUrlPath = g.urlPath;
397 int iOriginalPort = g.urlPort;
398 unsigned uOriginalFlags = g.urlFlags;
399 g.urlUser = 0;
400 g.urlPasswd = "";
401 url_parse(zProxy, 0);
402 if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
403 g.urlPath = zOriginalUrl;
404 g.urlHostname = zOriginalHost;
405 if( g.urlUser ){
406 char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
407 char *zCredentials2 = encode64(zCredentials1, -1);
408 g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
409 free(zCredentials1);
410 }
411 g.urlUser = zOriginalUser;
412 g.urlPasswd = zOriginalPasswd;
413 g.urlIsHttps = fOriginalIsHttps;
414 g.useProxy = 1;
415 g.proxyUrlPath = zOriginalUrlPath;
416 g.proxyOrigPort = iOriginalPort;
417 g.urlFlags = uOriginalFlags;
418 }
419 }
420
421 #if INTERFACE
422 /*
@@ -529,35 +529,35 @@
529 pUrlData->user);
530 }
531 }
532
533 /*
534 ** Prompt the user for the password for g.urlUser. Store the result
535 ** in g.urlPasswd.
536 */
537 void url_prompt_for_password(void){
538 url_prompt_for_password_local(GLOBAL_URL());
539 }
540
541 /*
542 ** Remember the URL and password if requested.
543 */
544 void url_remember(void){
545 if( g.urlFlags & URL_REMEMBER ){
546 db_set("last-sync-url", g.urlCanonical, 0);
547 if( g.urlUser!=0 && g.urlPasswd!=0 && ( g.urlFlags & URL_REMEMBER_PW ) ){
548 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
549 }
550 }
551 }
552
553 /* Preemptively prompt for a password if a username is given in the
554 ** URL but no password.
555 */
556 void url_get_password_if_needed(void){
557 if( (g.urlUser && g.urlUser[0])
558 && (g.urlPasswd==0 || g.urlPasswd[0]==0)
559 && isatty(fileno(stdin))
560 ){
561 url_prompt_for_password();
562 }
563 }
564
--- src/url.c
+++ src/url.c
@@ -275,22 +275,22 @@
275
276 /*
277 ** Parse the given URL, which describes a sync server. Populate variables
278 ** in the global "g" structure as follows:
279 **
280 ** g.url.isFile True if FILE:
281 ** g.url.isHttps True if HTTPS:
282 ** g.url.isSsh True if SSH:
283 ** g.url.protocol "http" or "https" or "file"
284 ** g.url.name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
285 ** g.url.port TCP port number for HTTP or HTTPS.
286 ** g.url.dfltPort Default TCP port number (80 or 443).
287 ** g.url.path Path name for HTTP or HTTPS.
288 ** g.url.user Userid.
289 ** g.url.passwd Password.
290 ** g.url.hostname HOST:PORT or just HOST if port is the default.
291 ** g.url.canonical The URL in canonical form, omitting the password
292 **
293 ** HTTP url format as follows (HTTPS is the same with a different scheme):
294 **
295 ** http://userid:password@host:port/path
296 **
@@ -298,11 +298,11 @@
298 **
299 ** ssh://userid@host:port/path?fossil=path/to/fossil.exe
300 **
301 */
302 void url_parse(const char *zUrl, unsigned int urlFlags){
303 url_parse_local(zUrl, urlFlags, &g.url);
304 }
305
306 /*
307 ** COMMAND: test-urlparser
308 **
@@ -323,25 +323,25 @@
323 if( g.argc!=3 && g.argc!=4 ){
324 usage("URL");
325 }
326 url_parse(g.argv[2], fg);
327 for(i=0; i<2; i++){
328 fossil_print("g.url.isFile = %d\n", g.url.isFile);
329 fossil_print("g.url.isHttps = %d\n", g.url.isHttps);
330 fossil_print("g.url.isSsh = %d\n", g.url.isSsh);
331 fossil_print("g.url.protocol = %s\n", g.url.protocol);
332 fossil_print("g.url.name = %s\n", g.url.name);
333 fossil_print("g.url.port = %d\n", g.url.port);
334 fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort);
335 fossil_print("g.url.hostname = %s\n", g.url.hostname);
336 fossil_print("g.url.path = %s\n", g.url.path);
337 fossil_print("g.url.user = %s\n", g.url.user);
338 fossil_print("g.url.passwd = %s\n", g.url.passwd);
339 fossil_print("g.url.canonical = %s\n", g.url.canonical);
340 fossil_print("g.url.fossil = %s\n", g.url.fossil);
341 fossil_print("g.url.flags = 0x%02x\n", g.url.flags);
342 if( g.url.isFile || g.url.isSsh ) break;
343 if( i==0 ){
344 fossil_print("********\n");
345 url_enable_proxy("Using proxy: ");
346 }
347 }
@@ -385,38 +385,38 @@
385 if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
386 zProxy = fossil_getenv("http_proxy");
387 }
388 }
389 if( zProxy && zProxy[0] && !is_false(zProxy)
390 && !g.url.isSsh && !g.url.isFile ){
391 char *zOriginalUrl = g.url.canonical;
392 char *zOriginalHost = g.url.hostname;
393 int fOriginalIsHttps = g.url.isHttps;
394 char *zOriginalUser = g.url.user;
395 char *zOriginalPasswd = g.url.passwd;
396 char *zOriginalUrlPath = g.url.path;
397 int iOriginalPort = g.url.port;
398 unsigned uOriginalFlags = g.url.flags;
399 g.url.user = 0;
400 g.url.passwd = "";
401 url_parse(zProxy, 0);
402 if( zMsg ) fossil_print("%s%s\n", zMsg, g.url.canonical);
403 g.url.path = zOriginalUrl;
404 g.url.hostname = zOriginalHost;
405 if( g.url.user ){
406 char *zCredentials1 = mprintf("%s:%s", g.url.user, g.url.passwd);
407 char *zCredentials2 = encode64(zCredentials1, -1);
408 g.url.proxyAuth = mprintf("Basic %z", zCredentials2);
409 free(zCredentials1);
410 }
411 g.url.user = zOriginalUser;
412 g.url.passwd = zOriginalPasswd;
413 g.url.isHttps = fOriginalIsHttps;
414 g.url.useProxy = 1;
415 g.url.proxyUrlPath = zOriginalUrlPath;
416 g.url.proxyOrigPort = iOriginalPort;
417 g.url.flags = uOriginalFlags;
418 }
419 }
420
421 #if INTERFACE
422 /*
@@ -529,35 +529,35 @@
529 pUrlData->user);
530 }
531 }
532
533 /*
534 ** Prompt the user for the password for g.url.user. Store the result
535 ** in g.url.passwd.
536 */
537 void url_prompt_for_password(void){
538 url_prompt_for_password_local(&g.url);
539 }
540
541 /*
542 ** Remember the URL and password if requested.
543 */
544 void url_remember(void){
545 if( g.url.flags & URL_REMEMBER ){
546 db_set("last-sync-url", g.url.canonical, 0);
547 if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){
548 db_set("last-sync-pw", obscure(g.url.passwd), 0);
549 }
550 }
551 }
552
553 /* Preemptively prompt for a password if a username is given in the
554 ** URL but no password.
555 */
556 void url_get_password_if_needed(void){
557 if( (g.url.user && g.url.user[0])
558 && (g.url.passwd==0 || g.url.passwd[0]==0)
559 && isatty(fileno(stdin))
560 ){
561 url_prompt_for_password();
562 }
563 }
564
+1 -1
--- src/user.c
+++ src/user.c
@@ -375,11 +375,11 @@
375375
if( attempt_user(fossil_getenv("LOGNAME")) ) return;
376376
377377
if( attempt_user(fossil_getenv("USERNAME")) ) return;
378378
379379
url_parse(0, 0);
380
- if( g.urlUser && attempt_user(g.urlUser) ) return;
380
+ if( g.url.user && attempt_user(g.url.user) ) return;
381381
382382
fossil_print(
383383
"Cannot figure out who you are! Consider using the --user\n"
384384
"command line option, setting your USER environment variable,\n"
385385
"or setting a default user with \"fossil user default USER\".\n"
386386
--- src/user.c
+++ src/user.c
@@ -375,11 +375,11 @@
375 if( attempt_user(fossil_getenv("LOGNAME")) ) return;
376
377 if( attempt_user(fossil_getenv("USERNAME")) ) return;
378
379 url_parse(0, 0);
380 if( g.urlUser && attempt_user(g.urlUser) ) return;
381
382 fossil_print(
383 "Cannot figure out who you are! Consider using the --user\n"
384 "command line option, setting your USER environment variable,\n"
385 "or setting a default user with \"fossil user default USER\".\n"
386
--- src/user.c
+++ src/user.c
@@ -375,11 +375,11 @@
375 if( attempt_user(fossil_getenv("LOGNAME")) ) return;
376
377 if( attempt_user(fossil_getenv("USERNAME")) ) return;
378
379 url_parse(0, 0);
380 if( g.url.user && attempt_user(g.url.user) ) return;
381
382 fossil_print(
383 "Cannot figure out who you are! Consider using the --user\n"
384 "command line option, setting your USER environment variable,\n"
385 "or setting a default user with \"fossil user default USER\".\n"
386
+10
--- src/util.c
+++ src/util.c
@@ -312,5 +312,15 @@
312312
return 1;
313313
#else
314314
return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
315315
#endif
316316
}
317
+
318
+/*
319
+** Returns TRUE if zSym is exactly UUID_SIZE bytes long and contains
320
+** only lower-case ASCII hexadecimal values.
321
+*/
322
+int fossil_is_uuid(char const * zSym){
323
+ return zSym
324
+ && (UUID_SIZE==strlen(zSym))
325
+ && validate16(zSym, UUID_SIZE);
326
+}
317327
--- src/util.c
+++ src/util.c
@@ -312,5 +312,15 @@
312 return 1;
313 #else
314 return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
315 #endif
316 }
 
 
 
 
 
 
 
 
 
 
317
--- src/util.c
+++ src/util.c
@@ -312,5 +312,15 @@
312 return 1;
313 #else
314 return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
315 #endif
316 }
317
318 /*
319 ** Returns TRUE if zSym is exactly UUID_SIZE bytes long and contains
320 ** only lower-case ASCII hexadecimal values.
321 */
322 int fossil_is_uuid(char const * zSym){
323 return zSym
324 && (UUID_SIZE==strlen(zSym))
325 && validate16(zSym, UUID_SIZE);
326 }
327
+3 -3
--- src/wiki.c
+++ src/wiki.c
@@ -241,11 +241,11 @@
241241
if( rid ){
242242
style_submenu_element("Diff", "Last change",
243243
"%R/wdiff?name=%T&a=%d", zPageName, rid);
244244
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
245245
style_submenu_element("Details", "Details",
246
- "%R/info/%S", zUuid);
246
+ "%R/info/%s", zUuid);
247247
}
248248
if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
249249
if( db_get_boolean("wysiwyg-wiki", 0) ){
250250
style_submenu_element("Edit", "Edit Wiki Page",
251251
"%s/wikiedit?name=%T&wysiwyg=1",
@@ -891,11 +891,11 @@
891891
@ <li>Blank lines are paragraph breaks</li>
892892
@ <li>Bullets are "*" surrounded by two spaces at the beginning of the
893893
@ line.</li>
894894
@ <li>Enumeration items are "#" surrounded by two spaces at the beginning of
895895
@ a line.</li>
896
- @ <li>Indented pargraphs begin with a tab or two spaces.</li>
896
+ @ <li>Indented paragraphs begin with a tab or two spaces.</li>
897897
@ <li>Hyperlinks are contained with square brackets: "[target]" or
898898
@ "[target|name]".</li>
899899
@ <li>Most ordinary HTML works.</li>
900900
@ <li>&lt;verbatim&gt; and &lt;nowiki&gt;.</li>
901901
@ </ol>
@@ -927,11 +927,11 @@
927927
@ target can be a wiki page name, the artifact ID of a check-in or ticket,
928928
@ the name of an image, or a URL. By default, the target is displayed
929929
@ as the text of the hyperlink. But you can specify alternative text
930930
@ after the target name separated by a "|" character.</p>
931931
@ <p>You can also link to internal anchor names using [#anchor-name], providing
932
- @ you have added the necessary "&lt;a name="anchor-name"&gt;&lt;/a&gt;"
932
+ @ you have added the necessary "&lt;a name='anchor-name'&gt;&lt;/a&gt;"
933933
@ tag to your wiki page.</p></li>
934934
@ <li> <p><span class="wikiruleHead">HTML</span>.
935935
@ The following standard HTML elements may be used:
936936
show_allowed_wiki_markup();
937937
@ . There are two non-standard elements available:
938938
--- src/wiki.c
+++ src/wiki.c
@@ -241,11 +241,11 @@
241 if( rid ){
242 style_submenu_element("Diff", "Last change",
243 "%R/wdiff?name=%T&a=%d", zPageName, rid);
244 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
245 style_submenu_element("Details", "Details",
246 "%R/info/%S", zUuid);
247 }
248 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
249 if( db_get_boolean("wysiwyg-wiki", 0) ){
250 style_submenu_element("Edit", "Edit Wiki Page",
251 "%s/wikiedit?name=%T&wysiwyg=1",
@@ -891,11 +891,11 @@
891 @ <li>Blank lines are paragraph breaks</li>
892 @ <li>Bullets are "*" surrounded by two spaces at the beginning of the
893 @ line.</li>
894 @ <li>Enumeration items are "#" surrounded by two spaces at the beginning of
895 @ a line.</li>
896 @ <li>Indented pargraphs begin with a tab or two spaces.</li>
897 @ <li>Hyperlinks are contained with square brackets: "[target]" or
898 @ "[target|name]".</li>
899 @ <li>Most ordinary HTML works.</li>
900 @ <li>&lt;verbatim&gt; and &lt;nowiki&gt;.</li>
901 @ </ol>
@@ -927,11 +927,11 @@
927 @ target can be a wiki page name, the artifact ID of a check-in or ticket,
928 @ the name of an image, or a URL. By default, the target is displayed
929 @ as the text of the hyperlink. But you can specify alternative text
930 @ after the target name separated by a "|" character.</p>
931 @ <p>You can also link to internal anchor names using [#anchor-name], providing
932 @ you have added the necessary "&lt;a name="anchor-name"&gt;&lt;/a&gt;"
933 @ tag to your wiki page.</p></li>
934 @ <li> <p><span class="wikiruleHead">HTML</span>.
935 @ The following standard HTML elements may be used:
936 show_allowed_wiki_markup();
937 @ . There are two non-standard elements available:
938
--- src/wiki.c
+++ src/wiki.c
@@ -241,11 +241,11 @@
241 if( rid ){
242 style_submenu_element("Diff", "Last change",
243 "%R/wdiff?name=%T&a=%d", zPageName, rid);
244 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
245 style_submenu_element("Details", "Details",
246 "%R/info/%s", zUuid);
247 }
248 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
249 if( db_get_boolean("wysiwyg-wiki", 0) ){
250 style_submenu_element("Edit", "Edit Wiki Page",
251 "%s/wikiedit?name=%T&wysiwyg=1",
@@ -891,11 +891,11 @@
891 @ <li>Blank lines are paragraph breaks</li>
892 @ <li>Bullets are "*" surrounded by two spaces at the beginning of the
893 @ line.</li>
894 @ <li>Enumeration items are "#" surrounded by two spaces at the beginning of
895 @ a line.</li>
896 @ <li>Indented paragraphs begin with a tab or two spaces.</li>
897 @ <li>Hyperlinks are contained with square brackets: "[target]" or
898 @ "[target|name]".</li>
899 @ <li>Most ordinary HTML works.</li>
900 @ <li>&lt;verbatim&gt; and &lt;nowiki&gt;.</li>
901 @ </ol>
@@ -927,11 +927,11 @@
927 @ target can be a wiki page name, the artifact ID of a check-in or ticket,
928 @ the name of an image, or a URL. By default, the target is displayed
929 @ as the text of the hyperlink. But you can specify alternative text
930 @ after the target name separated by a "|" character.</p>
931 @ <p>You can also link to internal anchor names using [#anchor-name], providing
932 @ you have added the necessary "&lt;a name='anchor-name'&gt;&lt;/a&gt;"
933 @ tag to your wiki page.</p></li>
934 @ <li> <p><span class="wikiruleHead">HTML</span>.
935 @ The following standard HTML elements may be used:
936 show_allowed_wiki_markup();
937 @ . There are two non-standard elements available:
938
+6 -6
--- src/xfer.c
+++ src/xfer.c
@@ -1375,11 +1375,11 @@
13751375
static double fossil_fabs(double x){
13761376
return x>0.0 ? x : -x;
13771377
}
13781378
13791379
/*
1380
-** Sync to the host identified in g.urlName and g.urlPath. This
1380
+** Sync to the host identified in g.url.name and g.url.path. This
13811381
** routine is called by the client.
13821382
**
13831383
** Records are pushed to the server if pushFlag is true. Records
13841384
** are pulled if pullFlag is true. A full sync occurs if both are
13851385
** true.
@@ -1823,15 +1823,15 @@
18231823
defossilize(zMsg);
18241824
fossil_force_newline();
18251825
fossil_print("Error: %s\n", zMsg);
18261826
if( fossil_strcmp(zMsg, "login failed")==0 ){
18271827
if( nCycle<2 ){
1828
- g.urlPasswd = 0;
1828
+ g.url.passwd = 0;
18291829
go = 1;
18301830
if( g.cgiOutput==0 ){
1831
- g.urlFlags |= URL_PROMPT_PW;
1832
- g.urlFlags &= ~URL_PROMPTED;
1831
+ g.url.flags |= URL_PROMPT_PW;
1832
+ g.url.flags &= ~URL_PROMPTED;
18331833
url_prompt_for_password();
18341834
url_remember();
18351835
}
18361836
}
18371837
}else{
@@ -1926,13 +1926,13 @@
19261926
19271927
fossil_force_newline();
19281928
fossil_print(
19291929
"%s finished with %lld bytes sent, %lld bytes received\n",
19301930
zOpType, nSent, nRcvd);
1931
- transport_close(GLOBAL_URL());
1932
- transport_global_shutdown(GLOBAL_URL());
1931
+ transport_close(&g.url);
1932
+ transport_global_shutdown(&g.url);
19331933
db_multi_exec("DROP TABLE onremote");
19341934
manifest_crosslink_end(MC_PERMIT_HOOKS);
19351935
content_enable_dephantomize(1);
19361936
db_end_transaction(0);
19371937
return nErr;
19381938
}
19391939
--- src/xfer.c
+++ src/xfer.c
@@ -1375,11 +1375,11 @@
1375 static double fossil_fabs(double x){
1376 return x>0.0 ? x : -x;
1377 }
1378
1379 /*
1380 ** Sync to the host identified in g.urlName and g.urlPath. This
1381 ** routine is called by the client.
1382 **
1383 ** Records are pushed to the server if pushFlag is true. Records
1384 ** are pulled if pullFlag is true. A full sync occurs if both are
1385 ** true.
@@ -1823,15 +1823,15 @@
1823 defossilize(zMsg);
1824 fossil_force_newline();
1825 fossil_print("Error: %s\n", zMsg);
1826 if( fossil_strcmp(zMsg, "login failed")==0 ){
1827 if( nCycle<2 ){
1828 g.urlPasswd = 0;
1829 go = 1;
1830 if( g.cgiOutput==0 ){
1831 g.urlFlags |= URL_PROMPT_PW;
1832 g.urlFlags &= ~URL_PROMPTED;
1833 url_prompt_for_password();
1834 url_remember();
1835 }
1836 }
1837 }else{
@@ -1926,13 +1926,13 @@
1926
1927 fossil_force_newline();
1928 fossil_print(
1929 "%s finished with %lld bytes sent, %lld bytes received\n",
1930 zOpType, nSent, nRcvd);
1931 transport_close(GLOBAL_URL());
1932 transport_global_shutdown(GLOBAL_URL());
1933 db_multi_exec("DROP TABLE onremote");
1934 manifest_crosslink_end(MC_PERMIT_HOOKS);
1935 content_enable_dephantomize(1);
1936 db_end_transaction(0);
1937 return nErr;
1938 }
1939
--- src/xfer.c
+++ src/xfer.c
@@ -1375,11 +1375,11 @@
1375 static double fossil_fabs(double x){
1376 return x>0.0 ? x : -x;
1377 }
1378
1379 /*
1380 ** Sync to the host identified in g.url.name and g.url.path. This
1381 ** routine is called by the client.
1382 **
1383 ** Records are pushed to the server if pushFlag is true. Records
1384 ** are pulled if pullFlag is true. A full sync occurs if both are
1385 ** true.
@@ -1823,15 +1823,15 @@
1823 defossilize(zMsg);
1824 fossil_force_newline();
1825 fossil_print("Error: %s\n", zMsg);
1826 if( fossil_strcmp(zMsg, "login failed")==0 ){
1827 if( nCycle<2 ){
1828 g.url.passwd = 0;
1829 go = 1;
1830 if( g.cgiOutput==0 ){
1831 g.url.flags |= URL_PROMPT_PW;
1832 g.url.flags &= ~URL_PROMPTED;
1833 url_prompt_for_password();
1834 url_remember();
1835 }
1836 }
1837 }else{
@@ -1926,13 +1926,13 @@
1926
1927 fossil_force_newline();
1928 fossil_print(
1929 "%s finished with %lld bytes sent, %lld bytes received\n",
1930 zOpType, nSent, nRcvd);
1931 transport_close(&g.url);
1932 transport_global_shutdown(&g.url);
1933 db_multi_exec("DROP TABLE onremote");
1934 manifest_crosslink_end(MC_PERMIT_HOOKS);
1935 content_enable_dephantomize(1);
1936 db_end_transaction(0);
1937 return nErr;
1938 }
1939
+3 -3
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -44,11 +44,11 @@
4444
setup_menu_entry("Ticket", "xfersetup_ticket",
4545
"Specific TH1 code to run after processing a ticket change.");
4646
@ </table>
4747
4848
url_parse(0, 0);
49
- if( g.urlProtocol ){
49
+ if( g.url.protocol ){
5050
unsigned syncFlags;
5151
const char *zButton;
5252
char *zWarning;
5353
5454
if( db_get_boolean("dont-push", 0) ){
@@ -57,19 +57,19 @@
5757
zWarning = 0;
5858
}else{
5959
syncFlags = SYNC_PUSH | SYNC_PULL;
6060
zButton = "Synchronize";
6161
zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
62
- g.urlCanonical);
62
+ g.url.canonical);
6363
}
6464
if( P("sync") ){
6565
user_select();
6666
url_enable_proxy(0);
6767
client_sync(syncFlags, 0, 0);
6868
}
6969
@ <p>Press the %h(zButton) button below to synchronize with the
70
- @ "%h(g.urlCanonical)" repository now. This may be useful when
70
+ @ "%h(g.url.canonical)" repository now. This may be useful when
7171
@ testing the various transfer scripts.</p>
7272
@ <p>You can use the "http -async" command in your scripts, but
7373
@ make sure the "th1-uri-regexp" setting is set first.</p>
7474
if( zWarning ){
7575
@
7676
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -44,11 +44,11 @@
44 setup_menu_entry("Ticket", "xfersetup_ticket",
45 "Specific TH1 code to run after processing a ticket change.");
46 @ </table>
47
48 url_parse(0, 0);
49 if( g.urlProtocol ){
50 unsigned syncFlags;
51 const char *zButton;
52 char *zWarning;
53
54 if( db_get_boolean("dont-push", 0) ){
@@ -57,19 +57,19 @@
57 zWarning = 0;
58 }else{
59 syncFlags = SYNC_PUSH | SYNC_PULL;
60 zButton = "Synchronize";
61 zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
62 g.urlCanonical);
63 }
64 if( P("sync") ){
65 user_select();
66 url_enable_proxy(0);
67 client_sync(syncFlags, 0, 0);
68 }
69 @ <p>Press the %h(zButton) button below to synchronize with the
70 @ "%h(g.urlCanonical)" repository now. This may be useful when
71 @ testing the various transfer scripts.</p>
72 @ <p>You can use the "http -async" command in your scripts, but
73 @ make sure the "th1-uri-regexp" setting is set first.</p>
74 if( zWarning ){
75 @
76
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -44,11 +44,11 @@
44 setup_menu_entry("Ticket", "xfersetup_ticket",
45 "Specific TH1 code to run after processing a ticket change.");
46 @ </table>
47
48 url_parse(0, 0);
49 if( g.url.protocol ){
50 unsigned syncFlags;
51 const char *zButton;
52 char *zWarning;
53
54 if( db_get_boolean("dont-push", 0) ){
@@ -57,19 +57,19 @@
57 zWarning = 0;
58 }else{
59 syncFlags = SYNC_PUSH | SYNC_PULL;
60 zButton = "Synchronize";
61 zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
62 g.url.canonical);
63 }
64 if( P("sync") ){
65 user_select();
66 url_enable_proxy(0);
67 client_sync(syncFlags, 0, 0);
68 }
69 @ <p>Press the %h(zButton) button below to synchronize with the
70 @ "%h(g.url.canonical)" repository now. This may be useful when
71 @ testing the various transfer scripts.</p>
72 @ <p>You can use the "http -async" command in your scripts, but
73 @ make sure the "th1-uri-regexp" setting is set first.</p>
74 if( zWarning ){
75 @
76
--- test/file1.test
+++ test/file1.test
@@ -24,10 +24,19 @@
2424
fossil test-simplify-name $path
2525
test simplify-name-$testname.$i {$::RESULT=="\[$path\] -> \[$result\]"}
2626
incr i
2727
}
2828
}
29
+
30
+proc relative-name {testname args} {
31
+ set i 1
32
+ foreach {subdir path result} $args {
33
+ fossil test-relative-name --chdir $subdir $path
34
+ test relative-name-$testname.$i {$::RESULT==$result}
35
+ incr i
36
+ }
37
+}
2938
3039
simplify-name 100 . . .// . .. .. ..///// ..
3140
simplify-name 101 {} {} / / ///////// / ././././ .
3241
simplify-name 102 x x /x /x ///x //x
3342
simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b
@@ -38,5 +47,16 @@
3847
3948
if {$::tcl_platform(os)=="Windows NT"} {
4049
simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
4150
simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
4251
}
52
+
53
+# Those directories are only needed for the testcase being able to "--chdir" to it.
54
+file mkdir test1
55
+file mkdir test1/test2
56
+
57
+relative-name 100 . . . test1 [pwd] .. test1 [pwd]/ .. test1 [pwd]/test ../test
58
+relative-name 101 test1/test2 [pwd] ../.. test1/test2 [pwd]/ ../.. test1/test2 [pwd]/test ../../test
59
+relative-name 102 test1 [pwd]/test ../test . [pwd]/file1 ./file1 . [pwd]/file1/file2 ./file1/file2
60
+
61
+catch {file delete test1/test2}
62
+catch {file delete test1}
4363
--- test/file1.test
+++ test/file1.test
@@ -24,10 +24,19 @@
24 fossil test-simplify-name $path
25 test simplify-name-$testname.$i {$::RESULT=="\[$path\] -> \[$result\]"}
26 incr i
27 }
28 }
 
 
 
 
 
 
 
 
 
29
30 simplify-name 100 . . .// . .. .. ..///// ..
31 simplify-name 101 {} {} / / ///////// / ././././ .
32 simplify-name 102 x x /x /x ///x //x
33 simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b
@@ -38,5 +47,16 @@
38
39 if {$::tcl_platform(os)=="Windows NT"} {
40 simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
41 simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
42 }
 
 
 
 
 
 
 
 
 
 
 
43
--- test/file1.test
+++ test/file1.test
@@ -24,10 +24,19 @@
24 fossil test-simplify-name $path
25 test simplify-name-$testname.$i {$::RESULT=="\[$path\] -> \[$result\]"}
26 incr i
27 }
28 }
29
30 proc relative-name {testname args} {
31 set i 1
32 foreach {subdir path result} $args {
33 fossil test-relative-name --chdir $subdir $path
34 test relative-name-$testname.$i {$::RESULT==$result}
35 incr i
36 }
37 }
38
39 simplify-name 100 . . .// . .. .. ..///// ..
40 simplify-name 101 {} {} / / ///////// / ././././ .
41 simplify-name 102 x x /x /x ///x //x
42 simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b
@@ -38,5 +47,16 @@
47
48 if {$::tcl_platform(os)=="Windows NT"} {
49 simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
50 simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
51 }
52
53 # Those directories are only needed for the testcase being able to "--chdir" to it.
54 file mkdir test1
55 file mkdir test1/test2
56
57 relative-name 100 . . . test1 [pwd] .. test1 [pwd]/ .. test1 [pwd]/test ../test
58 relative-name 101 test1/test2 [pwd] ../.. test1/test2 [pwd]/ ../.. test1/test2 [pwd]/test ../../test
59 relative-name 102 test1 [pwd]/test ../test . [pwd]/file1 ./file1 . [pwd]/file1/file2 ./file1/file2
60
61 catch {file delete test1/test2}
62 catch {file delete test1}
63
+113
--- test/th1.test
+++ test/th1.test
@@ -362,5 +362,118 @@
362362
363363
###############################################################################
364364
365365
fossil test-th-eval "expr +2147483649.0"
366366
test th1-expr-13 {$RESULT eq {2147483649.0}}
367
+
368
+###############################################################################
369
+
370
+fossil test-th-eval "expr ~(-1)"
371
+test th1-expr-14 {$RESULT eq {0}}
372
+
373
+###############################################################################
374
+
375
+fossil test-th-eval "expr ~-1"
376
+test th1-expr-15 {$RESULT eq {0}}
377
+
378
+###############################################################################
379
+
380
+fossil test-th-eval "expr ~0"
381
+test th1-expr-16 {$RESULT eq {-1}}
382
+
383
+###############################################################################
384
+
385
+fossil test-th-eval "expr ~+0"
386
+test th1-expr-17 {$RESULT eq {-1}}
387
+
388
+###############################################################################
389
+
390
+fossil test-th-eval "expr ~-0"
391
+test th1-expr-18 {$RESULT eq {-1}}
392
+
393
+###############################################################################
394
+
395
+fossil test-th-eval "expr ~(+0)"
396
+test th1-expr-19 {$RESULT eq {-1}}
397
+
398
+###############################################################################
399
+
400
+fossil test-th-eval "expr ~(-0)"
401
+test th1-expr-20 {$RESULT eq {-1}}
402
+
403
+###############################################################################
404
+
405
+fossil test-th-eval "expr ~1"
406
+test th1-expr-21 {$RESULT eq {-2}}
407
+
408
+###############################################################################
409
+
410
+fossil test-th-eval "expr ~+1"
411
+test th1-expr-22 {$RESULT eq {-2}}
412
+
413
+###############################################################################
414
+
415
+fossil test-th-eval "expr ~(+1)"
416
+test th1-expr-23 {$RESULT eq {-2}}
417
+
418
+###############################################################################
419
+
420
+fossil test-th-eval "expr 0+0b11"
421
+test th1-expr-24 {$RESULT eq 3}
422
+
423
+###############################################################################
424
+
425
+fossil test-th-eval "expr 0+0o15"
426
+test th1-expr-25 {$RESULT eq 13}
427
+
428
+###############################################################################
429
+
430
+fossil test-th-eval "expr 0+0x15"
431
+test th1-expr-26 {$RESULT eq 21}
432
+
433
+###############################################################################
434
+
435
+fossil test-th-eval "expr 0+0b2"
436
+test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
437
+
438
+###############################################################################
439
+
440
+fossil test-th-eval "expr 0+0o8"
441
+test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
442
+
443
+###############################################################################
444
+
445
+fossil test-th-eval "expr 0+0xg"
446
+test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
447
+
448
+###############################################################################
449
+
450
+fossil test-th-eval "expr 0+0b1."
451
+test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
452
+
453
+###############################################################################
454
+
455
+fossil test-th-eval "expr 0+0o1."
456
+test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
457
+
458
+###############################################################################
459
+
460
+fossil test-th-eval "expr 0+0x1."
461
+test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
462
+
463
+###############################################################################
464
+
465
+fossil test-th-eval "expr 0ne5"
466
+test th1-expr-33 {$RESULT eq {1}}
467
+
468
+###############################################################################
469
+
470
+fossil test-th-eval "expr 0b1+5"
471
+test th1-expr-34 {$RESULT eq {6}}
472
+
473
+
474
+###############################################################################
475
+
476
+fossil test-th-eval "expr 0+0b"
477
+test th1-expr-35 {$RESULT eq {TH_ERROR: expected number, got: "0b"}}
478
+
479
+
367480
--- test/th1.test
+++ test/th1.test
@@ -362,5 +362,118 @@
362
363 ###############################################################################
364
365 fossil test-th-eval "expr +2147483649.0"
366 test th1-expr-13 {$RESULT eq {2147483649.0}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
--- test/th1.test
+++ test/th1.test
@@ -362,5 +362,118 @@
362
363 ###############################################################################
364
365 fossil test-th-eval "expr +2147483649.0"
366 test th1-expr-13 {$RESULT eq {2147483649.0}}
367
368 ###############################################################################
369
370 fossil test-th-eval "expr ~(-1)"
371 test th1-expr-14 {$RESULT eq {0}}
372
373 ###############################################################################
374
375 fossil test-th-eval "expr ~-1"
376 test th1-expr-15 {$RESULT eq {0}}
377
378 ###############################################################################
379
380 fossil test-th-eval "expr ~0"
381 test th1-expr-16 {$RESULT eq {-1}}
382
383 ###############################################################################
384
385 fossil test-th-eval "expr ~+0"
386 test th1-expr-17 {$RESULT eq {-1}}
387
388 ###############################################################################
389
390 fossil test-th-eval "expr ~-0"
391 test th1-expr-18 {$RESULT eq {-1}}
392
393 ###############################################################################
394
395 fossil test-th-eval "expr ~(+0)"
396 test th1-expr-19 {$RESULT eq {-1}}
397
398 ###############################################################################
399
400 fossil test-th-eval "expr ~(-0)"
401 test th1-expr-20 {$RESULT eq {-1}}
402
403 ###############################################################################
404
405 fossil test-th-eval "expr ~1"
406 test th1-expr-21 {$RESULT eq {-2}}
407
408 ###############################################################################
409
410 fossil test-th-eval "expr ~+1"
411 test th1-expr-22 {$RESULT eq {-2}}
412
413 ###############################################################################
414
415 fossil test-th-eval "expr ~(+1)"
416 test th1-expr-23 {$RESULT eq {-2}}
417
418 ###############################################################################
419
420 fossil test-th-eval "expr 0+0b11"
421 test th1-expr-24 {$RESULT eq 3}
422
423 ###############################################################################
424
425 fossil test-th-eval "expr 0+0o15"
426 test th1-expr-25 {$RESULT eq 13}
427
428 ###############################################################################
429
430 fossil test-th-eval "expr 0+0x15"
431 test th1-expr-26 {$RESULT eq 21}
432
433 ###############################################################################
434
435 fossil test-th-eval "expr 0+0b2"
436 test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
437
438 ###############################################################################
439
440 fossil test-th-eval "expr 0+0o8"
441 test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
442
443 ###############################################################################
444
445 fossil test-th-eval "expr 0+0xg"
446 test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
447
448 ###############################################################################
449
450 fossil test-th-eval "expr 0+0b1."
451 test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
452
453 ###############################################################################
454
455 fossil test-th-eval "expr 0+0o1."
456 test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
457
458 ###############################################################################
459
460 fossil test-th-eval "expr 0+0x1."
461 test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
462
463 ###############################################################################
464
465 fossil test-th-eval "expr 0ne5"
466 test th1-expr-33 {$RESULT eq {1}}
467
468 ###############################################################################
469
470 fossil test-th-eval "expr 0b1+5"
471 test th1-expr-34 {$RESULT eq {6}}
472
473
474 ###############################################################################
475
476 fossil test-th-eval "expr 0+0b"
477 test th1-expr-35 {$RESULT eq {TH_ERROR: expected number, got: "0b"}}
478
479
480
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -84,12 +84,12 @@
8484
#### The directories where the OpenSSL include and library files are located.
8585
# The recommended usage here is to use the Sysinternals junction tool
8686
# to create a hard link between an "openssl-1.x" sub-directory of the
8787
# Fossil source code directory and the target OpenSSL source directory.
8888
#
89
-OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include
90
-OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f
89
+OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include
90
+OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g
9191
9292
#### Either the directory where the Tcl library is installed or the Tcl
9393
# source code directory resides (depending on the value of the macro
9494
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
9595
# this directory must have "include" and "lib" sub-directories. If
@@ -669,15 +669,11 @@
669669
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
670670
671671
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
672672
$(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
673673
674
-EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/cson_amalgamation.o
675
-
676
-ifdef FOSSIL_ENABLE_TCL
677
-EXTRAOBJ += $(OBJDIR)/th_tcl.o
678
-endif
674
+EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o
679675
680676
zlib:
681677
$(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
682678
683679
clean-zlib:
@@ -1745,9 +1741,8 @@
17451741
$(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
17461742
17471743
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
17481744
$(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
17491745
1750
-ifdef FOSSIL_ENABLE_TCL
17511746
$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
17521747
$(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1753
-endif
1748
+
17541749
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include
90 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -669,15 +669,11 @@
669 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
670
671 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
672 $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
673
674 EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/cson_amalgamation.o
675
676 ifdef FOSSIL_ENABLE_TCL
677 EXTRAOBJ += $(OBJDIR)/th_tcl.o
678 endif
679
680 zlib:
681 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
682
683 clean-zlib:
@@ -1745,9 +1741,8 @@
1745 $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
1746
1747 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
1748 $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
1749
1750 ifdef FOSSIL_ENABLE_TCL
1751 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1752 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1753 endif
1754
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include
90 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -669,15 +669,11 @@
669 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
670
671 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
672 $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
673
674 EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o
 
 
 
 
675
676 zlib:
677 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
678
679 clean-zlib:
@@ -1745,9 +1741,8 @@
1741 $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
1742
1743 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
1744 $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
1745
 
1746 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1747 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1748
1749
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -84,12 +84,12 @@
8484
#### The directories where the OpenSSL include and library files are located.
8585
# The recommended usage here is to use the Sysinternals junction tool
8686
# to create a hard link between an "openssl-1.x" sub-directory of the
8787
# Fossil source code directory and the target OpenSSL source directory.
8888
#
89
-OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include
90
-OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f
89
+OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include
90
+OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g
9191
9292
#### Either the directory where the Tcl library is installed or the Tcl
9393
# source code directory resides (depending on the value of the macro
9494
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
9595
# this directory must have "include" and "lib" sub-directories. If
@@ -669,15 +669,11 @@
669669
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
670670
671671
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
672672
$(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
673673
674
-EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/cson_amalgamation.o
675
-
676
-ifdef FOSSIL_ENABLE_TCL
677
-EXTRAOBJ += $(OBJDIR)/th_tcl.o
678
-endif
674
+EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o
679675
680676
zlib:
681677
$(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
682678
683679
clean-zlib:
@@ -1745,9 +1741,7 @@
17451741
$(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
17461742
17471743
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
17481744
$(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
17491745
1750
-ifdef FOSSIL_ENABLE_TCL
17511746
$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
17521747
$(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1753
-endif
17541748
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include
90 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -669,15 +669,11 @@
669 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
670
671 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
672 $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
673
674 EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/cson_amalgamation.o
675
676 ifdef FOSSIL_ENABLE_TCL
677 EXTRAOBJ += $(OBJDIR)/th_tcl.o
678 endif
679
680 zlib:
681 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
682
683 clean-zlib:
@@ -1745,9 +1741,7 @@
1745 $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
1746
1747 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
1748 $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
1749
1750 ifdef FOSSIL_ENABLE_TCL
1751 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1752 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1753 endif
1754
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include
90 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -669,15 +669,11 @@
669 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
670
671 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
672 $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
673
674 EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o
 
 
 
 
675
676 zlib:
677 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
678
679 clean-zlib:
@@ -1745,9 +1741,7 @@
1741 $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
1742
1743 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
1744 $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
1745
 
1746 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1747 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
 
1748
+4 -10
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -26,12 +26,12 @@
2626
2727
# Uncomment to enable Tcl support
2828
# FOSSIL_ENABLE_TCL = 1
2929
3030
!ifdef FOSSIL_ENABLE_SSL
31
-SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
32
-SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
31
+SSLINCDIR = $(B)\compat\openssl-1.0.1g\include
32
+SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32
3333
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
3434
!endif
3535
3636
!ifdef FOSSIL_ENABLE_TCL
3737
TCLDIR = $(B)\compat\tcl-8.6
@@ -310,10 +310,11 @@
310310
$(OX)\tag$O \
311311
$(OX)\tar$O \
312312
$(OX)\th$O \
313313
$(OX)\th_lang$O \
314314
$(OX)\th_main$O \
315
+ $(OX)\th_tcl$O \
315316
$(OX)\timeline$O \
316317
$(OX)\tkt$O \
317318
$(OX)\tktsetup$O \
318319
$(OX)\undo$O \
319320
$(OX)\unicode$O \
@@ -332,13 +333,10 @@
332333
$(OX)\xfer$O \
333334
$(OX)\xfersetup$O \
334335
$(OX)\zip$O \
335336
$(OX)\fossil.res
336337
337
-!ifdef FOSSIL_ENABLE_TCL
338
-OBJ = $(OBJ) $(OX)\th_tcl$O
339
-!endif
340338
341339
APPNAME = $(OX)\fossil$(E)
342340
PDBNAME = $(OX)\fossil$(P)
343341
344342
all: $(OX) $(APPNAME)
@@ -444,10 +442,11 @@
444442
echo $(OX)\tag.obj >> $@
445443
echo $(OX)\tar.obj >> $@
446444
echo $(OX)\th.obj >> $@
447445
echo $(OX)\th_lang.obj >> $@
448446
echo $(OX)\th_main.obj >> $@
447
+ echo $(OX)\th_tcl.obj >> $@
449448
echo $(OX)\timeline.obj >> $@
450449
echo $(OX)\tkt.obj >> $@
451450
echo $(OX)\tktsetup.obj >> $@
452451
echo $(OX)\undo.obj >> $@
453452
echo $(OX)\unicode.obj >> $@
@@ -464,13 +463,10 @@
464463
echo $(OX)\winhttp.obj >> $@
465464
echo $(OX)\wysiwyg.obj >> $@
466465
echo $(OX)\xfer.obj >> $@
467466
echo $(OX)\xfersetup.obj >> $@
468467
echo $(OX)\zip.obj >> $@
469
-!ifdef FOSSIL_ENABLE_TCL
470
- echo $(OX)\th_tcl.obj >> $@
471
-!endif
472468
echo $(LIBS) >> $@
473469
474470
$(OX):
475471
@-mkdir $@
476472
@@ -496,14 +492,12 @@
496492
$(TCC) /Fo$@ -c $**
497493
498494
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
499495
$(TCC) /Fo$@ -c $**
500496
501
-!ifdef FOSSIL_ENABLE_TCL
502497
$(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
503498
$(TCC) /Fo$@ -c $**
504
-!endif
505499
506500
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
507501
$** > $@
508502
$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
509503
$(TCC) /Fo$@ /c $**
510504
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -26,12 +26,12 @@
26
27 # Uncomment to enable Tcl support
28 # FOSSIL_ENABLE_TCL = 1
29
30 !ifdef FOSSIL_ENABLE_SSL
31 SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
32 SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
33 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
34 !endif
35
36 !ifdef FOSSIL_ENABLE_TCL
37 TCLDIR = $(B)\compat\tcl-8.6
@@ -310,10 +310,11 @@
310 $(OX)\tag$O \
311 $(OX)\tar$O \
312 $(OX)\th$O \
313 $(OX)\th_lang$O \
314 $(OX)\th_main$O \
 
315 $(OX)\timeline$O \
316 $(OX)\tkt$O \
317 $(OX)\tktsetup$O \
318 $(OX)\undo$O \
319 $(OX)\unicode$O \
@@ -332,13 +333,10 @@
332 $(OX)\xfer$O \
333 $(OX)\xfersetup$O \
334 $(OX)\zip$O \
335 $(OX)\fossil.res
336
337 !ifdef FOSSIL_ENABLE_TCL
338 OBJ = $(OBJ) $(OX)\th_tcl$O
339 !endif
340
341 APPNAME = $(OX)\fossil$(E)
342 PDBNAME = $(OX)\fossil$(P)
343
344 all: $(OX) $(APPNAME)
@@ -444,10 +442,11 @@
444 echo $(OX)\tag.obj >> $@
445 echo $(OX)\tar.obj >> $@
446 echo $(OX)\th.obj >> $@
447 echo $(OX)\th_lang.obj >> $@
448 echo $(OX)\th_main.obj >> $@
 
449 echo $(OX)\timeline.obj >> $@
450 echo $(OX)\tkt.obj >> $@
451 echo $(OX)\tktsetup.obj >> $@
452 echo $(OX)\undo.obj >> $@
453 echo $(OX)\unicode.obj >> $@
@@ -464,13 +463,10 @@
464 echo $(OX)\winhttp.obj >> $@
465 echo $(OX)\wysiwyg.obj >> $@
466 echo $(OX)\xfer.obj >> $@
467 echo $(OX)\xfersetup.obj >> $@
468 echo $(OX)\zip.obj >> $@
469 !ifdef FOSSIL_ENABLE_TCL
470 echo $(OX)\th_tcl.obj >> $@
471 !endif
472 echo $(LIBS) >> $@
473
474 $(OX):
475 @-mkdir $@
476
@@ -496,14 +492,12 @@
496 $(TCC) /Fo$@ -c $**
497
498 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
499 $(TCC) /Fo$@ -c $**
500
501 !ifdef FOSSIL_ENABLE_TCL
502 $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
503 $(TCC) /Fo$@ -c $**
504 !endif
505
506 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
507 $** > $@
508 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
509 $(TCC) /Fo$@ /c $**
510
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -26,12 +26,12 @@
26
27 # Uncomment to enable Tcl support
28 # FOSSIL_ENABLE_TCL = 1
29
30 !ifdef FOSSIL_ENABLE_SSL
31 SSLINCDIR = $(B)\compat\openssl-1.0.1g\include
32 SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32
33 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
34 !endif
35
36 !ifdef FOSSIL_ENABLE_TCL
37 TCLDIR = $(B)\compat\tcl-8.6
@@ -310,10 +310,11 @@
310 $(OX)\tag$O \
311 $(OX)\tar$O \
312 $(OX)\th$O \
313 $(OX)\th_lang$O \
314 $(OX)\th_main$O \
315 $(OX)\th_tcl$O \
316 $(OX)\timeline$O \
317 $(OX)\tkt$O \
318 $(OX)\tktsetup$O \
319 $(OX)\undo$O \
320 $(OX)\unicode$O \
@@ -332,13 +333,10 @@
333 $(OX)\xfer$O \
334 $(OX)\xfersetup$O \
335 $(OX)\zip$O \
336 $(OX)\fossil.res
337
 
 
 
338
339 APPNAME = $(OX)\fossil$(E)
340 PDBNAME = $(OX)\fossil$(P)
341
342 all: $(OX) $(APPNAME)
@@ -444,10 +442,11 @@
442 echo $(OX)\tag.obj >> $@
443 echo $(OX)\tar.obj >> $@
444 echo $(OX)\th.obj >> $@
445 echo $(OX)\th_lang.obj >> $@
446 echo $(OX)\th_main.obj >> $@
447 echo $(OX)\th_tcl.obj >> $@
448 echo $(OX)\timeline.obj >> $@
449 echo $(OX)\tkt.obj >> $@
450 echo $(OX)\tktsetup.obj >> $@
451 echo $(OX)\undo.obj >> $@
452 echo $(OX)\unicode.obj >> $@
@@ -464,13 +463,10 @@
463 echo $(OX)\winhttp.obj >> $@
464 echo $(OX)\wysiwyg.obj >> $@
465 echo $(OX)\xfer.obj >> $@
466 echo $(OX)\xfersetup.obj >> $@
467 echo $(OX)\zip.obj >> $@
 
 
 
468 echo $(LIBS) >> $@
469
470 $(OX):
471 @-mkdir $@
472
@@ -496,14 +492,12 @@
492 $(TCC) /Fo$@ -c $**
493
494 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
495 $(TCC) /Fo$@ -c $**
496
 
497 $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
498 $(TCC) /Fo$@ -c $**
 
499
500 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
501 $** > $@
502 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
503 $(TCC) /Fo$@ /c $**
504
+28 -1
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,11 +1,12 @@
11
<title>Change Log</title>
22
33
<h2>Changes For Version 1.29 (as yet unreleased)</h2>
44
* Add the ability to display content, diffs and annotations for UTF16
55
text files in the web interface.
6
- * Add the "SaveAs..." button to the graphical diff display that results
6
+ * Add the "SaveAs..." and "Invert" buttons
7
+ to the graphical diff display that results
78
from using the --tk option with the [/help/diff | fossil diff] command.
89
* Honor timezones in imports from git.
910
* The [/reports] page now requires Read ("o") permissions. The "byweek"
1011
report now properly propagates the selected year through the event type
1112
filter links.
@@ -18,10 +19,36 @@
1819
[/help?cmd=diff|fossil (g)diff], [/help?cmd=stash|fossil stash diff].
1920
* Add --strip-trailing-cr option to [/help?cmd=diff|fossil (g)diff] and
2021
[/help?cmd=stash|fossil stash diff].
2122
* Add button "Ignore Whitespace" to /annotate, /blame, /ci, /fdiff
2223
and /vdiff UI pages.
24
+ * Enhance [/reports?view=byweekday|/reports] with a "byweekday" view.
25
+ * Enhance the [/help?cmd=cat|fossil cat] command so that it works outside
26
+ of a checkout when using the -R command-line option.
27
+ * Use full-length SHA1 hashes, not abbreviations, in most hyperlinks.
28
+ * Correctly render the &lt;title&gt; markup on wiki pages in the
29
+ [/help?cmd=/artifact|/artifact] webpage.
30
+ * Enhance the [/help?cmd=whatis|fossil whatis] command to report on attachments
31
+ and cluster artifacts. Added the [/help?cmd=test-whatis-all] command for
32
+ testing purposes.
33
+ * Add support for HTTP Basic Authentication on [/help?cmd=clone|clone] and
34
+ [/help?cmd=sync|sync].
35
+ * Fix the [/help?cmd=stash|stash] so that it remembers added files and re-adds
36
+ them when the stash is applied.
37
+ * Fix the server so that it avoids writing to the database (and thus avoids
38
+ database locking issues) on a
39
+ [/help?cmd=pull|pull] or [/help?cmd=clone|clone].
40
+ * Add support for [./server.wiki#loadmgmt|server load management].
41
+ * Add the [/help?cmd=praise|fossil praise] command as an alias for
42
+ [/help?cmd=blame|fossil blame] for subversion compatibility.
43
+ * Enhance the [/help?cmd=test-diff|fossil test-diff] command with -y or --tk
44
+ options so that it shows both filenames above their respective columns in
45
+ the side-by-side diff output.
46
+ * Issue a warning if a [/help?cmd=add|fossil add] command tries to add a file
47
+ that matches the ignore-glob.
48
+ * Add option -W|--width to "[/help?cmd=stash|fossil stash ls]"
49
+ and "[/help?cmd=leaves|fossil leaves]" commands.
2350
2451
<h2>Changes For Version 1.28 (2014-01-27)</h2>
2552
* Enhance [/help?cmd=/reports | /reports] to support event type filtering.
2653
* When cloning a repository, the user name passed via the URL (if any)
2754
is now used as the default local admin user's name.
2855
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,11 +1,12 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.29 (as yet unreleased)</h2>
4 * Add the ability to display content, diffs and annotations for UTF16
5 text files in the web interface.
6 * Add the "SaveAs..." button to the graphical diff display that results
 
7 from using the --tk option with the [/help/diff | fossil diff] command.
8 * Honor timezones in imports from git.
9 * The [/reports] page now requires Read ("o") permissions. The "byweek"
10 report now properly propagates the selected year through the event type
11 filter links.
@@ -18,10 +19,36 @@
18 [/help?cmd=diff|fossil (g)diff], [/help?cmd=stash|fossil stash diff].
19 * Add --strip-trailing-cr option to [/help?cmd=diff|fossil (g)diff] and
20 [/help?cmd=stash|fossil stash diff].
21 * Add button "Ignore Whitespace" to /annotate, /blame, /ci, /fdiff
22 and /vdiff UI pages.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
24 <h2>Changes For Version 1.28 (2014-01-27)</h2>
25 * Enhance [/help?cmd=/reports | /reports] to support event type filtering.
26 * When cloning a repository, the user name passed via the URL (if any)
27 is now used as the default local admin user's name.
28
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,11 +1,12 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.29 (as yet unreleased)</h2>
4 * Add the ability to display content, diffs and annotations for UTF16
5 text files in the web interface.
6 * Add the "SaveAs..." and "Invert" buttons
7 to the graphical diff display that results
8 from using the --tk option with the [/help/diff | fossil diff] command.
9 * Honor timezones in imports from git.
10 * The [/reports] page now requires Read ("o") permissions. The "byweek"
11 report now properly propagates the selected year through the event type
12 filter links.
@@ -18,10 +19,36 @@
19 [/help?cmd=diff|fossil (g)diff], [/help?cmd=stash|fossil stash diff].
20 * Add --strip-trailing-cr option to [/help?cmd=diff|fossil (g)diff] and
21 [/help?cmd=stash|fossil stash diff].
22 * Add button "Ignore Whitespace" to /annotate, /blame, /ci, /fdiff
23 and /vdiff UI pages.
24 * Enhance [/reports?view=byweekday|/reports] with a "byweekday" view.
25 * Enhance the [/help?cmd=cat|fossil cat] command so that it works outside
26 of a checkout when using the -R command-line option.
27 * Use full-length SHA1 hashes, not abbreviations, in most hyperlinks.
28 * Correctly render the &lt;title&gt; markup on wiki pages in the
29 [/help?cmd=/artifact|/artifact] webpage.
30 * Enhance the [/help?cmd=whatis|fossil whatis] command to report on attachments
31 and cluster artifacts. Added the [/help?cmd=test-whatis-all] command for
32 testing purposes.
33 * Add support for HTTP Basic Authentication on [/help?cmd=clone|clone] and
34 [/help?cmd=sync|sync].
35 * Fix the [/help?cmd=stash|stash] so that it remembers added files and re-adds
36 them when the stash is applied.
37 * Fix the server so that it avoids writing to the database (and thus avoids
38 database locking issues) on a
39 [/help?cmd=pull|pull] or [/help?cmd=clone|clone].
40 * Add support for [./server.wiki#loadmgmt|server load management].
41 * Add the [/help?cmd=praise|fossil praise] command as an alias for
42 [/help?cmd=blame|fossil blame] for subversion compatibility.
43 * Enhance the [/help?cmd=test-diff|fossil test-diff] command with -y or --tk
44 options so that it shows both filenames above their respective columns in
45 the side-by-side diff output.
46 * Issue a warning if a [/help?cmd=add|fossil add] command tries to add a file
47 that matches the ignore-glob.
48 * Add option -W|--width to "[/help?cmd=stash|fossil stash ls]"
49 and "[/help?cmd=leaves|fossil leaves]" commands.
50
51 <h2>Changes For Version 1.28 (2014-01-27)</h2>
52 * Enhance [/help?cmd=/reports | /reports] to support event type filtering.
53 * When cloning a repository, the user name passed via the URL (if any)
54 is now used as the default local admin user's name.
55

Keyboard Shortcuts

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