Fossil SCM

Bring branch up-to-date with respect to trunk

andygoth 2020-12-10 21:43 modern-skin-markup-fixes merge
Commit bbc5264066b88f772da23732c2315e9eaeff2691490285a38e66a8d2352fe548
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -27,15 +27,15 @@
2727
if {[hascap oh]} {
2828
if {![info exists current_checkin]} {set current_checkin tip}
2929
menulink /dir?ci=$current_checkin Files desktoponly
3030
}
3131
if {[hascap o]} {
32
- menulink /brlist Branches desktoponly
32
+ menulink /brlist Branches wideonly
3333
menulink /taglist Tags wideonly
3434
}
3535
if {[anycap 23456] || [anoncap 2] || [anoncap 3]} {
36
- menulink /forum Forum wideonly
36
+ menulink /forum Forum desktoponly
3737
}
3838
if {[hascap r]} {
3939
menulink /ticket Tickets wideonly
4040
}
4141
if {[hascap j]} {
4242
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -27,15 +27,15 @@
27 if {[hascap oh]} {
28 if {![info exists current_checkin]} {set current_checkin tip}
29 menulink /dir?ci=$current_checkin Files desktoponly
30 }
31 if {[hascap o]} {
32 menulink /brlist Branches desktoponly
33 menulink /taglist Tags wideonly
34 }
35 if {[anycap 23456] || [anoncap 2] || [anoncap 3]} {
36 menulink /forum Forum wideonly
37 }
38 if {[hascap r]} {
39 menulink /ticket Tickets wideonly
40 }
41 if {[hascap j]} {
42
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -27,15 +27,15 @@
27 if {[hascap oh]} {
28 if {![info exists current_checkin]} {set current_checkin tip}
29 menulink /dir?ci=$current_checkin Files desktoponly
30 }
31 if {[hascap o]} {
32 menulink /brlist Branches wideonly
33 menulink /taglist Tags wideonly
34 }
35 if {[anycap 23456] || [anoncap 2] || [anoncap 3]} {
36 menulink /forum Forum desktoponly
37 }
38 if {[hascap r]} {
39 menulink /ticket Tickets wideonly
40 }
41 if {[hascap j]} {
42
+17 -1
--- src/allrepo.c
+++ src/allrepo.c
@@ -91,10 +91,13 @@
9191
** line options supported by the extra command itself, if any
9292
** are present, are passed along verbatim.
9393
**
9494
** fts-config Run the "fts-config" command on all repositories.
9595
**
96
+** git export Do the "git export" command on all repositories for which
97
+** a Git mirror has been previously established.
98
+**
9699
** info Run the "info" command on all repositories.
97100
**
98101
** pull Run a "pull" operation on all repositories. Only the
99102
** --verbose option is supported.
100103
**
@@ -236,10 +239,23 @@
236239
collect_argument_value(&extra, "ignore");
237240
collect_argument(&extra, "rel-paths",0);
238241
useCheckouts = 1;
239242
stopOnError = 0;
240243
quiet = 1;
244
+ }else if( strncmp(zCmd, "git", n)==0 ){
245
+ if( g.argc<4 ){
246
+ usage("git (export|status)");
247
+ }else{
248
+ int n3 = (int)strlen(g.argv[3]);
249
+ if( strncmp(g.argv[3], "export", n3)==0 ){
250
+ zCmd = "git export --if-mirrored -R";
251
+ }else if( strncmp(g.argv[3], "status", n3)==0 ){
252
+ zCmd = "git status -R";
253
+ }else{
254
+ usage("git (export|status)");
255
+ }
256
+ }
241257
}else if( strncmp(zCmd, "push", n)==0 ){
242258
zCmd = "push -autourl -R";
243259
collect_argument(&extra, "verbose","v");
244260
}else if( strncmp(zCmd, "pull", n)==0 ){
245261
zCmd = "pull -autourl -R";
@@ -358,11 +374,11 @@
358374
zCmd = "cache -R";
359375
showLabel = 1;
360376
collect_argv(&extra, 3);
361377
}else{
362378
fossil_fatal("\"all\" subcommand should be one of: "
363
- "add cache changes clean dbstat extras fts-config ignore "
379
+ "add cache changes clean dbstat extras fts-config git ignore "
364380
"info list ls pull push rebuild server setting sync ui unset");
365381
}
366382
verify_all_options();
367383
db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
368384
if( useCheckouts ){
369385
--- src/allrepo.c
+++ src/allrepo.c
@@ -91,10 +91,13 @@
91 ** line options supported by the extra command itself, if any
92 ** are present, are passed along verbatim.
93 **
94 ** fts-config Run the "fts-config" command on all repositories.
95 **
 
 
 
96 ** info Run the "info" command on all repositories.
97 **
98 ** pull Run a "pull" operation on all repositories. Only the
99 ** --verbose option is supported.
100 **
@@ -236,10 +239,23 @@
236 collect_argument_value(&extra, "ignore");
237 collect_argument(&extra, "rel-paths",0);
238 useCheckouts = 1;
239 stopOnError = 0;
240 quiet = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
241 }else if( strncmp(zCmd, "push", n)==0 ){
242 zCmd = "push -autourl -R";
243 collect_argument(&extra, "verbose","v");
244 }else if( strncmp(zCmd, "pull", n)==0 ){
245 zCmd = "pull -autourl -R";
@@ -358,11 +374,11 @@
358 zCmd = "cache -R";
359 showLabel = 1;
360 collect_argv(&extra, 3);
361 }else{
362 fossil_fatal("\"all\" subcommand should be one of: "
363 "add cache changes clean dbstat extras fts-config ignore "
364 "info list ls pull push rebuild server setting sync ui unset");
365 }
366 verify_all_options();
367 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
368 if( useCheckouts ){
369
--- src/allrepo.c
+++ src/allrepo.c
@@ -91,10 +91,13 @@
91 ** line options supported by the extra command itself, if any
92 ** are present, are passed along verbatim.
93 **
94 ** fts-config Run the "fts-config" command on all repositories.
95 **
96 ** git export Do the "git export" command on all repositories for which
97 ** a Git mirror has been previously established.
98 **
99 ** info Run the "info" command on all repositories.
100 **
101 ** pull Run a "pull" operation on all repositories. Only the
102 ** --verbose option is supported.
103 **
@@ -236,10 +239,23 @@
239 collect_argument_value(&extra, "ignore");
240 collect_argument(&extra, "rel-paths",0);
241 useCheckouts = 1;
242 stopOnError = 0;
243 quiet = 1;
244 }else if( strncmp(zCmd, "git", n)==0 ){
245 if( g.argc<4 ){
246 usage("git (export|status)");
247 }else{
248 int n3 = (int)strlen(g.argv[3]);
249 if( strncmp(g.argv[3], "export", n3)==0 ){
250 zCmd = "git export --if-mirrored -R";
251 }else if( strncmp(g.argv[3], "status", n3)==0 ){
252 zCmd = "git status -R";
253 }else{
254 usage("git (export|status)");
255 }
256 }
257 }else if( strncmp(zCmd, "push", n)==0 ){
258 zCmd = "push -autourl -R";
259 collect_argument(&extra, "verbose","v");
260 }else if( strncmp(zCmd, "pull", n)==0 ){
261 zCmd = "pull -autourl -R";
@@ -358,11 +374,11 @@
374 zCmd = "cache -R";
375 showLabel = 1;
376 collect_argv(&extra, 3);
377 }else{
378 fossil_fatal("\"all\" subcommand should be one of: "
379 "add cache changes clean dbstat extras fts-config git ignore "
380 "info list ls pull push rebuild server setting sync ui unset");
381 }
382 verify_all_options();
383 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
384 if( useCheckouts ){
385
+1 -1
--- src/backlink.c
+++ src/backlink.c
@@ -130,11 +130,11 @@
130130
int srcid = db_column_int(&q, 2);
131131
const char *zMtime = db_column_text(&q, 3);
132132
@ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
133133
switch( srctype ){
134134
case BKLNK_COMMENT: {
135
- @ <td><a href="%R/info?name=rid:%d(srcid)">comment-%d(srcid)</a>
135
+ @ <td><a href="%R/info?name=rid:%d(srcid)">checkin-%d(srcid)</a>
136136
break;
137137
}
138138
case BKLNK_TICKET: {
139139
@ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
140140
break;
141141
--- src/backlink.c
+++ src/backlink.c
@@ -130,11 +130,11 @@
130 int srcid = db_column_int(&q, 2);
131 const char *zMtime = db_column_text(&q, 3);
132 @ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
133 switch( srctype ){
134 case BKLNK_COMMENT: {
135 @ <td><a href="%R/info?name=rid:%d(srcid)">comment-%d(srcid)</a>
136 break;
137 }
138 case BKLNK_TICKET: {
139 @ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
140 break;
141
--- src/backlink.c
+++ src/backlink.c
@@ -130,11 +130,11 @@
130 int srcid = db_column_int(&q, 2);
131 const char *zMtime = db_column_text(&q, 3);
132 @ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
133 switch( srctype ){
134 case BKLNK_COMMENT: {
135 @ <td><a href="%R/info?name=rid:%d(srcid)">checkin-%d(srcid)</a>
136 break;
137 }
138 case BKLNK_TICKET: {
139 @ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
140 break;
141
+8 -6
--- src/builtin.c
+++ src/builtin.c
@@ -775,13 +775,15 @@
775775
** initialize the window.fossil JS API. The first argument is the NAME
776776
** part of the first API to emit. All subsequent arguments must be
777777
** strings of the NAME part of additional fossil.NAME.js files,
778778
** followed by a NULL argument to terminate the list.
779779
**
780
-** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3 APIs (or
781
-** pass it ("fetch","tabs",0), as "dom" is a dependency of "tabs", so
782
-** it will be automatically loaded). Do not forget the trailing 0!
780
+** e.g. pass it ("fetch", "dom", "tabs", NULL) to load those 3 APIs (or
781
+** pass it ("fetch","tabs",NULL), as "dom" is a dependency of "tabs", so
782
+** it will be automatically loaded). Do not forget the trailing NULL,
783
+** and do not pass 0 instead, since that isn't always equivalent to NULL
784
+** in this context.
783785
**
784786
** If it is JS_BUNDLED then this routine queues up an emit of ALL of
785787
** the JS fossil.XYZ.js APIs which are not strictly specific to a
786788
** single page, and then calls builtin_fulfill_js_requests(). The idea
787789
** is that we can get better bundle caching and reduced HTTP requests
@@ -843,18 +845,18 @@
843845
** builtin_request_js()) with any other app-/page-specific JS it may
844846
** need.
845847
**
846848
** Example usage:
847849
**
848
-** builtin_fossil_js_bundle_or("dom", "fetch", 0);
850
+** builtin_fossil_js_bundle_or("dom", "fetch", NULL);
849851
**
850852
** In bundled mode, that will (the first time it is called) emit all
851853
** builtin fossil JS APIs and "fulfill" the queue immediately. In
852854
** non-bundled mode it will queue up the "dom" and "fetch" APIs to be
853855
** emitted the next time builtin_fulfill_js_requests() is called.
854856
*/
855
-void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
857
+NULL_SENTINEL void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
856858
static int bundled = 0;
857859
const char *zArg;
858860
va_list vargs;
859861
860862
if(JS_BUNDLED == builtin_get_js_delivery_mode()){
@@ -864,12 +866,12 @@
864866
builtin_fulfill_js_requests();
865867
}
866868
return;
867869
}
868870
va_start(vargs,zApi);
869
- for( zArg = zApi; zArg!=0; (zArg = va_arg (vargs, const char *))){
871
+ for( zArg = zApi; zArg!=NULL; (zArg = va_arg (vargs, const char *))){
870872
if(0==builtin_emit_fossil_js_once(zArg)){
871873
fossil_fatal("Unknown fossil JS module: %s\n", zArg);
872874
}
873875
}
874876
va_end(vargs);
875877
}
876878
--- src/builtin.c
+++ src/builtin.c
@@ -775,13 +775,15 @@
775 ** initialize the window.fossil JS API. The first argument is the NAME
776 ** part of the first API to emit. All subsequent arguments must be
777 ** strings of the NAME part of additional fossil.NAME.js files,
778 ** followed by a NULL argument to terminate the list.
779 **
780 ** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3 APIs (or
781 ** pass it ("fetch","tabs",0), as "dom" is a dependency of "tabs", so
782 ** it will be automatically loaded). Do not forget the trailing 0!
 
 
783 **
784 ** If it is JS_BUNDLED then this routine queues up an emit of ALL of
785 ** the JS fossil.XYZ.js APIs which are not strictly specific to a
786 ** single page, and then calls builtin_fulfill_js_requests(). The idea
787 ** is that we can get better bundle caching and reduced HTTP requests
@@ -843,18 +845,18 @@
843 ** builtin_request_js()) with any other app-/page-specific JS it may
844 ** need.
845 **
846 ** Example usage:
847 **
848 ** builtin_fossil_js_bundle_or("dom", "fetch", 0);
849 **
850 ** In bundled mode, that will (the first time it is called) emit all
851 ** builtin fossil JS APIs and "fulfill" the queue immediately. In
852 ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be
853 ** emitted the next time builtin_fulfill_js_requests() is called.
854 */
855 void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
856 static int bundled = 0;
857 const char *zArg;
858 va_list vargs;
859
860 if(JS_BUNDLED == builtin_get_js_delivery_mode()){
@@ -864,12 +866,12 @@
864 builtin_fulfill_js_requests();
865 }
866 return;
867 }
868 va_start(vargs,zApi);
869 for( zArg = zApi; zArg!=0; (zArg = va_arg (vargs, const char *))){
870 if(0==builtin_emit_fossil_js_once(zArg)){
871 fossil_fatal("Unknown fossil JS module: %s\n", zArg);
872 }
873 }
874 va_end(vargs);
875 }
876
--- src/builtin.c
+++ src/builtin.c
@@ -775,13 +775,15 @@
775 ** initialize the window.fossil JS API. The first argument is the NAME
776 ** part of the first API to emit. All subsequent arguments must be
777 ** strings of the NAME part of additional fossil.NAME.js files,
778 ** followed by a NULL argument to terminate the list.
779 **
780 ** e.g. pass it ("fetch", "dom", "tabs", NULL) to load those 3 APIs (or
781 ** pass it ("fetch","tabs",NULL), as "dom" is a dependency of "tabs", so
782 ** it will be automatically loaded). Do not forget the trailing NULL,
783 ** and do not pass 0 instead, since that isn't always equivalent to NULL
784 ** in this context.
785 **
786 ** If it is JS_BUNDLED then this routine queues up an emit of ALL of
787 ** the JS fossil.XYZ.js APIs which are not strictly specific to a
788 ** single page, and then calls builtin_fulfill_js_requests(). The idea
789 ** is that we can get better bundle caching and reduced HTTP requests
@@ -843,18 +845,18 @@
845 ** builtin_request_js()) with any other app-/page-specific JS it may
846 ** need.
847 **
848 ** Example usage:
849 **
850 ** builtin_fossil_js_bundle_or("dom", "fetch", NULL);
851 **
852 ** In bundled mode, that will (the first time it is called) emit all
853 ** builtin fossil JS APIs and "fulfill" the queue immediately. In
854 ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be
855 ** emitted the next time builtin_fulfill_js_requests() is called.
856 */
857 NULL_SENTINEL void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
858 static int bundled = 0;
859 const char *zArg;
860 va_list vargs;
861
862 if(JS_BUNDLED == builtin_get_js_delivery_mode()){
@@ -864,12 +866,12 @@
866 builtin_fulfill_js_requests();
867 }
868 return;
869 }
870 va_start(vargs,zApi);
871 for( zArg = zApi; zArg!=NULL; (zArg = va_arg (vargs, const char *))){
872 if(0==builtin_emit_fossil_js_once(zArg)){
873 fossil_fatal("Unknown fossil JS module: %s\n", zArg);
874 }
875 }
876 va_end(vargs);
877 }
878
+2 -2
--- src/checkout.c
+++ src/checkout.c
@@ -49,13 +49,13 @@
4949
void uncheckout(int vid){
5050
char *zPwd;
5151
if( vid<=0 ) return;
5252
sqlite3_create_function(g.db, "dirname",1,SQLITE_UTF8,0,
5353
file_dirname_sql_function, 0, 0);
54
- sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8,0,
54
+ sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8|SQLITE_DIRECTONLY,0,
5555
file_delete_sql_function, 0, 0);
56
- sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
56
+ sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
5757
file_rmdir_sql_function, 0, 0);
5858
db_multi_exec(
5959
"CREATE TEMP TABLE dir_to_delete(name TEXT %s PRIMARY KEY)WITHOUT ROWID",
6060
filename_collation()
6161
);
6262
--- src/checkout.c
+++ src/checkout.c
@@ -49,13 +49,13 @@
49 void uncheckout(int vid){
50 char *zPwd;
51 if( vid<=0 ) return;
52 sqlite3_create_function(g.db, "dirname",1,SQLITE_UTF8,0,
53 file_dirname_sql_function, 0, 0);
54 sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8,0,
55 file_delete_sql_function, 0, 0);
56 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
57 file_rmdir_sql_function, 0, 0);
58 db_multi_exec(
59 "CREATE TEMP TABLE dir_to_delete(name TEXT %s PRIMARY KEY)WITHOUT ROWID",
60 filename_collation()
61 );
62
--- src/checkout.c
+++ src/checkout.c
@@ -49,13 +49,13 @@
49 void uncheckout(int vid){
50 char *zPwd;
51 if( vid<=0 ) return;
52 sqlite3_create_function(g.db, "dirname",1,SQLITE_UTF8,0,
53 file_dirname_sql_function, 0, 0);
54 sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8|SQLITE_DIRECTONLY,0,
55 file_delete_sql_function, 0, 0);
56 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
57 file_rmdir_sql_function, 0, 0);
58 db_multi_exec(
59 "CREATE TEMP TABLE dir_to_delete(name TEXT %s PRIMARY KEY)WITHOUT ROWID",
60 filename_collation()
61 );
62
+29 -13
--- src/clone.c
+++ src/clone.c
@@ -123,10 +123,12 @@
123123
** the -A|--admin-user parameter.
124124
**
125125
** Options:
126126
** --admin-user|-A USERNAME Make USERNAME the administrator
127127
** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
128
+** --nested Allow opening a repository inside an opened
129
+** checkout
128130
** --nocompress Omit extra delta compression
129131
** --no-open Clone only. Do not open a check-out.
130132
** --once Don't remember the URI.
131133
** --private Also clone private branches
132134
** --save-http-password Remember the HTTP password without asking
@@ -145,12 +147,13 @@
145147
int nErr = 0;
146148
int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
147149
int syncFlags = SYNC_CLONE;
148150
int noCompress = find_option("nocompress",0,0)!=0;
149151
int noOpen = find_option("no-open",0,0)!=0;
152
+ int allowNested = find_option("nested",0,0)!=0; /* Used by open */
150153
const char *zRepo = 0; /* Name of the new local repository file */
151
- const char *zWorkDir = 0; /* Open in this director, if not zero */
154
+ const char *zWorkDir = 0; /* Open in this directory, if not zero */
152155
153156
154157
/* Also clone private branches */
155158
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
156159
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
@@ -189,10 +192,16 @@
189192
}
190193
fossil_free(zBase);
191194
}
192195
if( -1 != file_size(zRepo, ExtFILE) ){
193196
fossil_fatal("file already exists: %s", zRepo);
197
+ }
198
+ /* Fail before clone if open will fail because inside an open checkout */
199
+ if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
200
+ if( db_open_local_v2(0, allowNested) ){
201
+ fossil_fatal("there is already an open tree at %s", g.zLocalRoot);
202
+ }
194203
}
195204
url_parse(g.argv[2], urlFlags);
196205
if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
197206
if( g.url.isFile ){
198207
file_copy(g.url.name, zRepo);
@@ -277,22 +286,29 @@
277286
fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
278287
fossil_print("server-id: %s\n", db_get("server-code", 0));
279288
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
280289
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
281290
if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
282
- char *azNew[6];
283
- fossil_print("opening the new %s repository in directory %s...\n",
284
- zRepo, zWorkDir);
285
- azNew[0] = g.argv[0];
286
- azNew[1] = "open";
287
- azNew[2] = (char*)zRepo;
288
- azNew[3] = "--workdir";
289
- azNew[4] = (char*)zWorkDir;
290
- azNew[5] = 0;
291
- g.argv = azNew;
292
- g.argc = 5;
293
- cmd_open();
291
+ char *azNew[7];
292
+ int nargs = 5;
293
+ fossil_print("opening the new %s repository in directory %s...\n",
294
+ zRepo, zWorkDir);
295
+ azNew[0] = g.argv[0];
296
+ azNew[1] = "open";
297
+ azNew[2] = (char*)zRepo;
298
+ azNew[3] = "--workdir";
299
+ azNew[4] = (char*)zWorkDir;
300
+ if( allowNested ){
301
+ azNew[5] = "--nested";
302
+ nargs++;
303
+ }else{
304
+ azNew[5] = 0;
305
+ }
306
+ azNew[6] = 0;
307
+ g.argv = azNew;
308
+ g.argc = nargs;
309
+ cmd_open();
294310
}
295311
}
296312
297313
/*
298314
** If user chooses to use HTTP Authentication over unencrypted HTTP,
299315
--- src/clone.c
+++ src/clone.c
@@ -123,10 +123,12 @@
123 ** the -A|--admin-user parameter.
124 **
125 ** Options:
126 ** --admin-user|-A USERNAME Make USERNAME the administrator
127 ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
 
 
128 ** --nocompress Omit extra delta compression
129 ** --no-open Clone only. Do not open a check-out.
130 ** --once Don't remember the URI.
131 ** --private Also clone private branches
132 ** --save-http-password Remember the HTTP password without asking
@@ -145,12 +147,13 @@
145 int nErr = 0;
146 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
147 int syncFlags = SYNC_CLONE;
148 int noCompress = find_option("nocompress",0,0)!=0;
149 int noOpen = find_option("no-open",0,0)!=0;
 
150 const char *zRepo = 0; /* Name of the new local repository file */
151 const char *zWorkDir = 0; /* Open in this director, if not zero */
152
153
154 /* Also clone private branches */
155 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
156 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
@@ -189,10 +192,16 @@
189 }
190 fossil_free(zBase);
191 }
192 if( -1 != file_size(zRepo, ExtFILE) ){
193 fossil_fatal("file already exists: %s", zRepo);
 
 
 
 
 
 
194 }
195 url_parse(g.argv[2], urlFlags);
196 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
197 if( g.url.isFile ){
198 file_copy(g.url.name, zRepo);
@@ -277,22 +286,29 @@
277 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
278 fossil_print("server-id: %s\n", db_get("server-code", 0));
279 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
280 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
281 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
282 char *azNew[6];
283 fossil_print("opening the new %s repository in directory %s...\n",
284 zRepo, zWorkDir);
285 azNew[0] = g.argv[0];
286 azNew[1] = "open";
287 azNew[2] = (char*)zRepo;
288 azNew[3] = "--workdir";
289 azNew[4] = (char*)zWorkDir;
290 azNew[5] = 0;
291 g.argv = azNew;
292 g.argc = 5;
293 cmd_open();
 
 
 
 
 
 
 
294 }
295 }
296
297 /*
298 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
299
--- src/clone.c
+++ src/clone.c
@@ -123,10 +123,12 @@
123 ** the -A|--admin-user parameter.
124 **
125 ** Options:
126 ** --admin-user|-A USERNAME Make USERNAME the administrator
127 ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
128 ** --nested Allow opening a repository inside an opened
129 ** checkout
130 ** --nocompress Omit extra delta compression
131 ** --no-open Clone only. Do not open a check-out.
132 ** --once Don't remember the URI.
133 ** --private Also clone private branches
134 ** --save-http-password Remember the HTTP password without asking
@@ -145,12 +147,13 @@
147 int nErr = 0;
148 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
149 int syncFlags = SYNC_CLONE;
150 int noCompress = find_option("nocompress",0,0)!=0;
151 int noOpen = find_option("no-open",0,0)!=0;
152 int allowNested = find_option("nested",0,0)!=0; /* Used by open */
153 const char *zRepo = 0; /* Name of the new local repository file */
154 const char *zWorkDir = 0; /* Open in this directory, if not zero */
155
156
157 /* Also clone private branches */
158 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
159 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
@@ -189,10 +192,16 @@
192 }
193 fossil_free(zBase);
194 }
195 if( -1 != file_size(zRepo, ExtFILE) ){
196 fossil_fatal("file already exists: %s", zRepo);
197 }
198 /* Fail before clone if open will fail because inside an open checkout */
199 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
200 if( db_open_local_v2(0, allowNested) ){
201 fossil_fatal("there is already an open tree at %s", g.zLocalRoot);
202 }
203 }
204 url_parse(g.argv[2], urlFlags);
205 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
206 if( g.url.isFile ){
207 file_copy(g.url.name, zRepo);
@@ -277,22 +286,29 @@
286 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
287 fossil_print("server-id: %s\n", db_get("server-code", 0));
288 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
289 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
290 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
291 char *azNew[7];
292 int nargs = 5;
293 fossil_print("opening the new %s repository in directory %s...\n",
294 zRepo, zWorkDir);
295 azNew[0] = g.argv[0];
296 azNew[1] = "open";
297 azNew[2] = (char*)zRepo;
298 azNew[3] = "--workdir";
299 azNew[4] = (char*)zWorkDir;
300 if( allowNested ){
301 azNew[5] = "--nested";
302 nargs++;
303 }else{
304 azNew[5] = 0;
305 }
306 azNew[6] = 0;
307 g.argv = azNew;
308 g.argc = nargs;
309 cmd_open();
310 }
311 }
312
313 /*
314 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
315
--- src/config.h
+++ src/config.h
@@ -245,14 +245,17 @@
245245
/*
246246
** A marker for functions that never return.
247247
*/
248248
#if defined(__GNUC__) || defined(__clang__)
249249
# define NORETURN __attribute__((__noreturn__))
250
+# define NULL_SENTINEL __attribute__((sentinel))
250251
#elif defined(_MSC_VER) && (_MSC_VER >= 1310)
251252
# define NORETURN __declspec(noreturn)
253
+# define NULL_SENTINEL
252254
#else
253255
# define NORETURN
256
+# define NULL_SENTINEL
254257
#endif
255258
256259
/*
257260
** Number of elements in an array
258261
*/
259262
--- src/config.h
+++ src/config.h
@@ -245,14 +245,17 @@
245 /*
246 ** A marker for functions that never return.
247 */
248 #if defined(__GNUC__) || defined(__clang__)
249 # define NORETURN __attribute__((__noreturn__))
 
250 #elif defined(_MSC_VER) && (_MSC_VER >= 1310)
251 # define NORETURN __declspec(noreturn)
 
252 #else
253 # define NORETURN
 
254 #endif
255
256 /*
257 ** Number of elements in an array
258 */
259
--- src/config.h
+++ src/config.h
@@ -245,14 +245,17 @@
245 /*
246 ** A marker for functions that never return.
247 */
248 #if defined(__GNUC__) || defined(__clang__)
249 # define NORETURN __attribute__((__noreturn__))
250 # define NULL_SENTINEL __attribute__((sentinel))
251 #elif defined(_MSC_VER) && (_MSC_VER >= 1310)
252 # define NORETURN __declspec(noreturn)
253 # define NULL_SENTINEL
254 #else
255 # define NORETURN
256 # define NULL_SENTINEL
257 #endif
258
259 /*
260 ** Number of elements in an array
261 */
262
+5 -1
--- src/db.c
+++ src/db.c
@@ -1617,10 +1617,15 @@
16171617
);
16181618
if( rc!=SQLITE_OK ){
16191619
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
16201620
}
16211621
db_maybe_set_encryption_key(db, zDbName);
1622
+ sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc);
1623
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRUSTED_SCHEMA, 0, &rc);
1624
+ sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, &rc);
1625
+ sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, &rc);
1626
+ sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, &rc);
16221627
sqlite3_busy_timeout(db, 15000);
16231628
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
16241629
sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
16251630
sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
16261631
sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
@@ -1633,11 +1638,10 @@
16331638
);
16341639
if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
16351640
db_add_aux_functions(db);
16361641
re_add_sql_func(db); /* The REGEXP operator */
16371642
foci_register(db); /* The "files_of_checkin" virtual table */
1638
- sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc);
16391643
sqlite3_set_authorizer(db, db_top_authorizer, db);
16401644
return db;
16411645
}
16421646
16431647
16441648
--- src/db.c
+++ src/db.c
@@ -1617,10 +1617,15 @@
1617 );
1618 if( rc!=SQLITE_OK ){
1619 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
1620 }
1621 db_maybe_set_encryption_key(db, zDbName);
 
 
 
 
 
1622 sqlite3_busy_timeout(db, 15000);
1623 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
1624 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
1625 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
1626 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
@@ -1633,11 +1638,10 @@
1633 );
1634 if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
1635 db_add_aux_functions(db);
1636 re_add_sql_func(db); /* The REGEXP operator */
1637 foci_register(db); /* The "files_of_checkin" virtual table */
1638 sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc);
1639 sqlite3_set_authorizer(db, db_top_authorizer, db);
1640 return db;
1641 }
1642
1643
1644
--- src/db.c
+++ src/db.c
@@ -1617,10 +1617,15 @@
1617 );
1618 if( rc!=SQLITE_OK ){
1619 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
1620 }
1621 db_maybe_set_encryption_key(db, zDbName);
1622 sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc);
1623 sqlite3_db_config(db, SQLITE_DBCONFIG_TRUSTED_SCHEMA, 0, &rc);
1624 sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, &rc);
1625 sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, &rc);
1626 sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, &rc);
1627 sqlite3_busy_timeout(db, 15000);
1628 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
1629 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
1630 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
1631 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
@@ -1633,11 +1638,10 @@
1638 );
1639 if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
1640 db_add_aux_functions(db);
1641 re_add_sql_func(db); /* The REGEXP operator */
1642 foci_register(db); /* The "files_of_checkin" virtual table */
 
1643 sqlite3_set_authorizer(db, db_top_authorizer, db);
1644 return db;
1645 }
1646
1647
1648
+11 -5
--- src/dispatch.c
+++ src/dispatch.c
@@ -1008,13 +1008,15 @@
10081008
** -w|--www List all web pages
10091009
**
10101010
** These options can be used when TOPIC is present:
10111011
**
10121012
** -h|--html Format output as HTML rather than plain text
1013
+** -c|--commands Restrict TOPIC search to commands
10131014
*/
10141015
void help_cmd(void){
10151016
int rc;
1017
+ int mask = CMDFLAG_ANY;
10161018
int isPage = 0;
10171019
const char *z;
10181020
const char *zCmdOrPage;
10191021
const CmdOrPage *pCmd = 0;
10201022
int useHtml = 0;
@@ -1056,32 +1058,36 @@
10561058
}
10571059
useHtml = find_option("html","h",0)!=0;
10581060
isPage = ('/' == *g.argv[2]) ? 1 : 0;
10591061
if(isPage){
10601062
zCmdOrPage = "page";
1063
+ }else if( find_option("commands","c",0)!=0 ){
1064
+ mask = CMDFLAG_COMMAND;
1065
+ zCmdOrPage = "command";
10611066
}else{
10621067
zCmdOrPage = "command or setting";
10631068
}
1064
- rc = dispatch_name_search(g.argv[2], CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
1069
+ rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
10651070
if( rc ){
10661071
int i, n;
10671072
const char *az[5];
10681073
if( rc==1 ){
10691074
fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
10701075
}else{
10711076
fossil_print("ambiguous %s prefix: %s\n",
10721077
zCmdOrPage, g.argv[2]);
10731078
}
1074
- fossil_print("Did you mean one of:\n");
1079
+ fossil_print("Did you mean one of these TOPICs:\n");
10751080
n = dispatch_approx_match(g.argv[2], 5, az);
10761081
for(i=0; i<n; i++){
10771082
fossil_print(" * %s\n", az[i]);
10781083
}
10791084
fossil_print("Also consider using:\n");
1080
- fossil_print(" fossil help -a ;# show all commands\n");
1081
- fossil_print(" fossil help -w ;# show all web-pages\n");
1082
- fossil_print(" fossil help -s ;# show all settings\n");
1085
+ fossil_print(" fossil help TOPIC ;# show help on TOPIC\n");
1086
+ fossil_print(" fossil help -a ;# show all commands\n");
1087
+ fossil_print(" fossil help -w ;# show all web-pages\n");
1088
+ fossil_print(" fossil help -s ;# show all settings\n");
10831089
fossil_exit(1);
10841090
}
10851091
z = pCmd->zHelp;
10861092
if( z==0 ){
10871093
fossil_fatal("no help available for the %s %s",
10881094
--- src/dispatch.c
+++ src/dispatch.c
@@ -1008,13 +1008,15 @@
1008 ** -w|--www List all web pages
1009 **
1010 ** These options can be used when TOPIC is present:
1011 **
1012 ** -h|--html Format output as HTML rather than plain text
 
1013 */
1014 void help_cmd(void){
1015 int rc;
 
1016 int isPage = 0;
1017 const char *z;
1018 const char *zCmdOrPage;
1019 const CmdOrPage *pCmd = 0;
1020 int useHtml = 0;
@@ -1056,32 +1058,36 @@
1056 }
1057 useHtml = find_option("html","h",0)!=0;
1058 isPage = ('/' == *g.argv[2]) ? 1 : 0;
1059 if(isPage){
1060 zCmdOrPage = "page";
 
 
 
1061 }else{
1062 zCmdOrPage = "command or setting";
1063 }
1064 rc = dispatch_name_search(g.argv[2], CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
1065 if( rc ){
1066 int i, n;
1067 const char *az[5];
1068 if( rc==1 ){
1069 fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
1070 }else{
1071 fossil_print("ambiguous %s prefix: %s\n",
1072 zCmdOrPage, g.argv[2]);
1073 }
1074 fossil_print("Did you mean one of:\n");
1075 n = dispatch_approx_match(g.argv[2], 5, az);
1076 for(i=0; i<n; i++){
1077 fossil_print(" * %s\n", az[i]);
1078 }
1079 fossil_print("Also consider using:\n");
1080 fossil_print(" fossil help -a ;# show all commands\n");
1081 fossil_print(" fossil help -w ;# show all web-pages\n");
1082 fossil_print(" fossil help -s ;# show all settings\n");
 
1083 fossil_exit(1);
1084 }
1085 z = pCmd->zHelp;
1086 if( z==0 ){
1087 fossil_fatal("no help available for the %s %s",
1088
--- src/dispatch.c
+++ src/dispatch.c
@@ -1008,13 +1008,15 @@
1008 ** -w|--www List all web pages
1009 **
1010 ** These options can be used when TOPIC is present:
1011 **
1012 ** -h|--html Format output as HTML rather than plain text
1013 ** -c|--commands Restrict TOPIC search to commands
1014 */
1015 void help_cmd(void){
1016 int rc;
1017 int mask = CMDFLAG_ANY;
1018 int isPage = 0;
1019 const char *z;
1020 const char *zCmdOrPage;
1021 const CmdOrPage *pCmd = 0;
1022 int useHtml = 0;
@@ -1056,32 +1058,36 @@
1058 }
1059 useHtml = find_option("html","h",0)!=0;
1060 isPage = ('/' == *g.argv[2]) ? 1 : 0;
1061 if(isPage){
1062 zCmdOrPage = "page";
1063 }else if( find_option("commands","c",0)!=0 ){
1064 mask = CMDFLAG_COMMAND;
1065 zCmdOrPage = "command";
1066 }else{
1067 zCmdOrPage = "command or setting";
1068 }
1069 rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
1070 if( rc ){
1071 int i, n;
1072 const char *az[5];
1073 if( rc==1 ){
1074 fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
1075 }else{
1076 fossil_print("ambiguous %s prefix: %s\n",
1077 zCmdOrPage, g.argv[2]);
1078 }
1079 fossil_print("Did you mean one of these TOPICs:\n");
1080 n = dispatch_approx_match(g.argv[2], 5, az);
1081 for(i=0; i<n; i++){
1082 fossil_print(" * %s\n", az[i]);
1083 }
1084 fossil_print("Also consider using:\n");
1085 fossil_print(" fossil help TOPIC ;# show help on TOPIC\n");
1086 fossil_print(" fossil help -a ;# show all commands\n");
1087 fossil_print(" fossil help -w ;# show all web-pages\n");
1088 fossil_print(" fossil help -s ;# show all settings\n");
1089 fossil_exit(1);
1090 }
1091 z = pCmd->zHelp;
1092 if( z==0 ){
1093 fossil_fatal("no help available for the %s %s",
1094
+1 -1
--- src/doc.c
+++ src/doc.c
@@ -408,11 +408,11 @@
408408
** no-ops.
409409
*/
410410
void document_emit_js(void){
411411
static int once = 0;
412412
if(0==once++){
413
- builtin_fossil_js_bundle_or("pikchr", 0);
413
+ builtin_fossil_js_bundle_or("pikchr", NULL);
414414
style_script_begin(__FILE__,__LINE__);
415415
CX("window.addEventListener('load', "
416416
"()=>window.fossil.pikchr.addSrcView(), "
417417
"false);\n");
418418
style_script_end();
419419
--- src/doc.c
+++ src/doc.c
@@ -408,11 +408,11 @@
408 ** no-ops.
409 */
410 void document_emit_js(void){
411 static int once = 0;
412 if(0==once++){
413 builtin_fossil_js_bundle_or("pikchr", 0);
414 style_script_begin(__FILE__,__LINE__);
415 CX("window.addEventListener('load', "
416 "()=>window.fossil.pikchr.addSrcView(), "
417 "false);\n");
418 style_script_end();
419
--- src/doc.c
+++ src/doc.c
@@ -408,11 +408,11 @@
408 ** no-ops.
409 */
410 void document_emit_js(void){
411 static int once = 0;
412 if(0==once++){
413 builtin_fossil_js_bundle_or("pikchr", NULL);
414 style_script_begin(__FILE__,__LINE__);
415 CX("window.addEventListener('load', "
416 "()=>window.fossil.pikchr.addSrcView(), "
417 "false);\n");
418 style_script_end();
419
--- src/export.c
+++ src/export.c
@@ -1300,10 +1300,11 @@
13001300
double rEnd; /* time of most recent export */
13011301
int rc; /* Result code */
13021302
int bForce; /* Do the export and sync even if no changes*/
13031303
int bNeedRepack = 0; /* True if we should run repack at the end */
13041304
int fManifest; /* Current "manifest" setting */
1305
+ int bIfExists; /* The --if-mirrored flag */
13051306
FILE *xCmd; /* Pipe to the "git fast-import" command */
13061307
FILE *pMarks; /* Git mark files */
13071308
Stmt q; /* Queries */
13081309
char zLine[200]; /* One line of a mark file */
13091310
@@ -1314,10 +1315,11 @@
13141315
nLimit = (unsigned int)atoi(zLimit);
13151316
if( nLimit<=0 ) fossil_fatal("--limit must be positive");
13161317
}
13171318
zAutoPush = find_option("autopush",0,1);
13181319
bForce = find_option("force","f",0)!=0;
1320
+ bIfExists = find_option("if-mirrored",0,0)!=0;
13191321
gitmirror_verbosity = VERB_NORMAL;
13201322
while( find_option("quiet","q",0)!=0 ){ gitmirror_verbosity--; }
13211323
while( find_option("verbose","v",0)!=0 ){ gitmirror_verbosity++; }
13221324
verify_all_options();
13231325
if( g.argc!=4 && g.argc!=3 ){ usage("export ?MIRROR?"); }
@@ -1327,10 +1329,11 @@
13271329
db_set("last-git-export-repo", blob_str(&mirror), 0);
13281330
blob_reset(&mirror);
13291331
}
13301332
zMirror = db_get("last-git-export-repo", 0);
13311333
if( zMirror==0 ){
1334
+ if( bIfExists ) return;
13321335
fossil_fatal("no Git repository specified");
13331336
}
13341337
13351338
/* Make sure the GIT repository directory exists */
13361339
rc = file_mkdir(zMirror, ExtFILE, 0);
@@ -1700,10 +1703,11 @@
17001703
** to the same repository. Or if URL is "off" the
17011704
** auto-push mechanism is disabled
17021705
** --debug FILE Write fast-export text to FILE rather than
17031706
** piping it into "git fast-import".
17041707
** --force|-f Do the export even if nothing has changed
1708
+** --if-mirrored No-op if the mirror does not already exist.
17051709
** --limit N Add no more than N new check-ins to MIRROR.
17061710
** Useful for debugging
17071711
** --quiet|-q Reduce output. Repeat for even less output.
17081712
** --verbose|-v More output.
17091713
**
17101714
--- src/export.c
+++ src/export.c
@@ -1300,10 +1300,11 @@
1300 double rEnd; /* time of most recent export */
1301 int rc; /* Result code */
1302 int bForce; /* Do the export and sync even if no changes*/
1303 int bNeedRepack = 0; /* True if we should run repack at the end */
1304 int fManifest; /* Current "manifest" setting */
 
1305 FILE *xCmd; /* Pipe to the "git fast-import" command */
1306 FILE *pMarks; /* Git mark files */
1307 Stmt q; /* Queries */
1308 char zLine[200]; /* One line of a mark file */
1309
@@ -1314,10 +1315,11 @@
1314 nLimit = (unsigned int)atoi(zLimit);
1315 if( nLimit<=0 ) fossil_fatal("--limit must be positive");
1316 }
1317 zAutoPush = find_option("autopush",0,1);
1318 bForce = find_option("force","f",0)!=0;
 
1319 gitmirror_verbosity = VERB_NORMAL;
1320 while( find_option("quiet","q",0)!=0 ){ gitmirror_verbosity--; }
1321 while( find_option("verbose","v",0)!=0 ){ gitmirror_verbosity++; }
1322 verify_all_options();
1323 if( g.argc!=4 && g.argc!=3 ){ usage("export ?MIRROR?"); }
@@ -1327,10 +1329,11 @@
1327 db_set("last-git-export-repo", blob_str(&mirror), 0);
1328 blob_reset(&mirror);
1329 }
1330 zMirror = db_get("last-git-export-repo", 0);
1331 if( zMirror==0 ){
 
1332 fossil_fatal("no Git repository specified");
1333 }
1334
1335 /* Make sure the GIT repository directory exists */
1336 rc = file_mkdir(zMirror, ExtFILE, 0);
@@ -1700,10 +1703,11 @@
1700 ** to the same repository. Or if URL is "off" the
1701 ** auto-push mechanism is disabled
1702 ** --debug FILE Write fast-export text to FILE rather than
1703 ** piping it into "git fast-import".
1704 ** --force|-f Do the export even if nothing has changed
 
1705 ** --limit N Add no more than N new check-ins to MIRROR.
1706 ** Useful for debugging
1707 ** --quiet|-q Reduce output. Repeat for even less output.
1708 ** --verbose|-v More output.
1709 **
1710
--- src/export.c
+++ src/export.c
@@ -1300,10 +1300,11 @@
1300 double rEnd; /* time of most recent export */
1301 int rc; /* Result code */
1302 int bForce; /* Do the export and sync even if no changes*/
1303 int bNeedRepack = 0; /* True if we should run repack at the end */
1304 int fManifest; /* Current "manifest" setting */
1305 int bIfExists; /* The --if-mirrored flag */
1306 FILE *xCmd; /* Pipe to the "git fast-import" command */
1307 FILE *pMarks; /* Git mark files */
1308 Stmt q; /* Queries */
1309 char zLine[200]; /* One line of a mark file */
1310
@@ -1314,10 +1315,11 @@
1315 nLimit = (unsigned int)atoi(zLimit);
1316 if( nLimit<=0 ) fossil_fatal("--limit must be positive");
1317 }
1318 zAutoPush = find_option("autopush",0,1);
1319 bForce = find_option("force","f",0)!=0;
1320 bIfExists = find_option("if-mirrored",0,0)!=0;
1321 gitmirror_verbosity = VERB_NORMAL;
1322 while( find_option("quiet","q",0)!=0 ){ gitmirror_verbosity--; }
1323 while( find_option("verbose","v",0)!=0 ){ gitmirror_verbosity++; }
1324 verify_all_options();
1325 if( g.argc!=4 && g.argc!=3 ){ usage("export ?MIRROR?"); }
@@ -1327,10 +1329,11 @@
1329 db_set("last-git-export-repo", blob_str(&mirror), 0);
1330 blob_reset(&mirror);
1331 }
1332 zMirror = db_get("last-git-export-repo", 0);
1333 if( zMirror==0 ){
1334 if( bIfExists ) return;
1335 fossil_fatal("no Git repository specified");
1336 }
1337
1338 /* Make sure the GIT repository directory exists */
1339 rc = file_mkdir(zMirror, ExtFILE, 0);
@@ -1700,10 +1703,11 @@
1703 ** to the same repository. Or if URL is "off" the
1704 ** auto-push mechanism is disabled
1705 ** --debug FILE Write fast-export text to FILE rather than
1706 ** piping it into "git fast-import".
1707 ** --force|-f Do the export even if nothing has changed
1708 ** --if-mirrored No-op if the mirror does not already exist.
1709 ** --limit N Add no more than N new check-ins to MIRROR.
1710 ** Useful for debugging
1711 ** --quiet|-q Reduce output. Repeat for even less output.
1712 ** --verbose|-v More output.
1713 **
1714
+1 -1
--- src/fileedit.c
+++ src/fileedit.c
@@ -1989,11 +1989,11 @@
19891989
}
19901990
CX("</div>"/*#fileedit-tab-help*/);
19911991
19921992
builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
19931993
"storage", "popupwidget", "copybutton",
1994
- "pikchr", 0);
1994
+ "pikchr", NULL);
19951995
/*
19961996
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
19971997
** used for dynamically toggling certain UI components on and off.
19981998
** Must come after window.fossil has been intialized and before
19991999
** fossil.page.fileedit.js. Potential TODO: move this into the
20002000
--- src/fileedit.c
+++ src/fileedit.c
@@ -1989,11 +1989,11 @@
1989 }
1990 CX("</div>"/*#fileedit-tab-help*/);
1991
1992 builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
1993 "storage", "popupwidget", "copybutton",
1994 "pikchr", 0);
1995 /*
1996 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1997 ** used for dynamically toggling certain UI components on and off.
1998 ** Must come after window.fossil has been intialized and before
1999 ** fossil.page.fileedit.js. Potential TODO: move this into the
2000
--- src/fileedit.c
+++ src/fileedit.c
@@ -1989,11 +1989,11 @@
1989 }
1990 CX("</div>"/*#fileedit-tab-help*/);
1991
1992 builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
1993 "storage", "popupwidget", "copybutton",
1994 "pikchr", NULL);
1995 /*
1996 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1997 ** used for dynamically toggling certain UI components on and off.
1998 ** Must come after window.fossil has been intialized and before
1999 ** fossil.page.fileedit.js. Potential TODO: move this into the
2000
+1 -1
--- src/forum.c
+++ src/forum.c
@@ -743,11 +743,11 @@
743743
** Emit Forum Javascript which applies (or optionally can apply)
744744
** to all forum-related pages. It does not include page-specific
745745
** code (e.g. "forum.js").
746746
*/
747747
static void forum_emit_js(void){
748
- builtin_fossil_js_bundle_or("copybutton", "pikchr", 0);
748
+ builtin_fossil_js_bundle_or("copybutton", "pikchr", NULL);
749749
builtin_request_js("fossil.page.forumpost.js");
750750
}
751751
752752
/*
753753
** WEBPAGE: forumpost
754754
--- src/forum.c
+++ src/forum.c
@@ -743,11 +743,11 @@
743 ** Emit Forum Javascript which applies (or optionally can apply)
744 ** to all forum-related pages. It does not include page-specific
745 ** code (e.g. "forum.js").
746 */
747 static void forum_emit_js(void){
748 builtin_fossil_js_bundle_or("copybutton", "pikchr", 0);
749 builtin_request_js("fossil.page.forumpost.js");
750 }
751
752 /*
753 ** WEBPAGE: forumpost
754
--- src/forum.c
+++ src/forum.c
@@ -743,11 +743,11 @@
743 ** Emit Forum Javascript which applies (or optionally can apply)
744 ** to all forum-related pages. It does not include page-specific
745 ** code (e.g. "forum.js").
746 */
747 static void forum_emit_js(void){
748 builtin_fossil_js_bundle_or("copybutton", "pikchr", NULL);
749 builtin_request_js("fossil.page.forumpost.js");
750 }
751
752 /*
753 ** WEBPAGE: forumpost
754
+4 -1
--- src/info.c
+++ src/info.c
@@ -2136,11 +2136,11 @@
21362136
if(includeJS && !emittedJS){
21372137
emittedJS = 1;
21382138
if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
21392139
builtin_request_js("scroll.js");
21402140
}
2141
- builtin_fossil_js_bundle_or("numbered-lines", 0);
2141
+ builtin_fossil_js_bundle_or("numbered-lines", NULL);
21422142
}
21432143
}
21442144
21452145
/*
21462146
** COMMAND: test-line-numbers
@@ -2398,14 +2398,17 @@
23982398
}
23992399
24002400
if( isFile ){
24012401
if( isSymbolicCI ){
24022402
zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2403
+ style_set_current_page("doc/%t/%T", zCI, zName);
24032404
}else if( zCIUuid && zCIUuid[0] ){
24042405
zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2406
+ style_set_current_page("doc/%S/%T", zCIUuid, zName);
24052407
}else{
24062408
zHeader = mprintf("%s", file_tail(zName));
2409
+ style_set_current_page("doc/tip/%T", zName);
24072410
}
24082411
}else if( descOnly ){
24092412
zHeader = mprintf("Artifact Description [%S]", zUuid);
24102413
}else{
24112414
zHeader = mprintf("Artifact [%S]", zUuid);
24122415
--- src/info.c
+++ src/info.c
@@ -2136,11 +2136,11 @@
2136 if(includeJS && !emittedJS){
2137 emittedJS = 1;
2138 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2139 builtin_request_js("scroll.js");
2140 }
2141 builtin_fossil_js_bundle_or("numbered-lines", 0);
2142 }
2143 }
2144
2145 /*
2146 ** COMMAND: test-line-numbers
@@ -2398,14 +2398,17 @@
2398 }
2399
2400 if( isFile ){
2401 if( isSymbolicCI ){
2402 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
 
2403 }else if( zCIUuid && zCIUuid[0] ){
2404 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
 
2405 }else{
2406 zHeader = mprintf("%s", file_tail(zName));
 
2407 }
2408 }else if( descOnly ){
2409 zHeader = mprintf("Artifact Description [%S]", zUuid);
2410 }else{
2411 zHeader = mprintf("Artifact [%S]", zUuid);
2412
--- src/info.c
+++ src/info.c
@@ -2136,11 +2136,11 @@
2136 if(includeJS && !emittedJS){
2137 emittedJS = 1;
2138 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2139 builtin_request_js("scroll.js");
2140 }
2141 builtin_fossil_js_bundle_or("numbered-lines", NULL);
2142 }
2143 }
2144
2145 /*
2146 ** COMMAND: test-line-numbers
@@ -2398,14 +2398,17 @@
2398 }
2399
2400 if( isFile ){
2401 if( isSymbolicCI ){
2402 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2403 style_set_current_page("doc/%t/%T", zCI, zName);
2404 }else if( zCIUuid && zCIUuid[0] ){
2405 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2406 style_set_current_page("doc/%S/%T", zCIUuid, zName);
2407 }else{
2408 zHeader = mprintf("%s", file_tail(zName));
2409 style_set_current_page("doc/tip/%T", zName);
2410 }
2411 }else if( descOnly ){
2412 zHeader = mprintf("Artifact Description [%S]", zUuid);
2413 }else{
2414 zHeader = mprintf("Artifact [%S]", zUuid);
2415
+5 -4
--- src/main.c
+++ src/main.c
@@ -796,18 +796,19 @@
796796
/* If --help is found anywhere on the command line, translate the command
797797
* to "fossil help cmdname" where "cmdname" is the first argument that
798798
* does not begin with a "-" character. If all arguments start with "-",
799799
* translate to "fossil help argv[1] argv[2]...". */
800800
int i, nNewArgc;
801
- char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );
801
+ char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+3) );
802802
zNewArgv[0] = g.argv[0];
803803
zNewArgv[1] = "help";
804
+ zNewArgv[2] = "-c";
804805
for(i=1; i<g.argc; i++){
805806
if( g.argv[i][0]!='-' ){
806
- nNewArgc = 3;
807
- zNewArgv[2] = g.argv[i];
808
- zNewArgv[3] = 0;
807
+ nNewArgc = 4;
808
+ zNewArgv[3] = g.argv[i];
809
+ zNewArgv[4] = 0;
809810
break;
810811
}
811812
}
812813
if( i==g.argc ){
813814
for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
814815
--- src/main.c
+++ src/main.c
@@ -796,18 +796,19 @@
796 /* If --help is found anywhere on the command line, translate the command
797 * to "fossil help cmdname" where "cmdname" is the first argument that
798 * does not begin with a "-" character. If all arguments start with "-",
799 * translate to "fossil help argv[1] argv[2]...". */
800 int i, nNewArgc;
801 char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );
802 zNewArgv[0] = g.argv[0];
803 zNewArgv[1] = "help";
 
804 for(i=1; i<g.argc; i++){
805 if( g.argv[i][0]!='-' ){
806 nNewArgc = 3;
807 zNewArgv[2] = g.argv[i];
808 zNewArgv[3] = 0;
809 break;
810 }
811 }
812 if( i==g.argc ){
813 for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
814
--- src/main.c
+++ src/main.c
@@ -796,18 +796,19 @@
796 /* If --help is found anywhere on the command line, translate the command
797 * to "fossil help cmdname" where "cmdname" is the first argument that
798 * does not begin with a "-" character. If all arguments start with "-",
799 * translate to "fossil help argv[1] argv[2]...". */
800 int i, nNewArgc;
801 char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+3) );
802 zNewArgv[0] = g.argv[0];
803 zNewArgv[1] = "help";
804 zNewArgv[2] = "-c";
805 for(i=1; i<g.argc; i++){
806 if( g.argv[i][0]!='-' ){
807 nNewArgc = 4;
808 zNewArgv[3] = g.argv[i];
809 zNewArgv[4] = 0;
810 break;
811 }
812 }
813 if( i==g.argc ){
814 for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
815
+8 -37
--- src/manifest.c
+++ src/manifest.c
@@ -2358,14 +2358,14 @@
23582358
}
23592359
if( p->type==CFTYPE_WIKI ){
23602360
char *zTag = mprintf("wiki-%s", p->zWikiTitle);
23612361
int tagid = tag_findid(zTag, 1);
23622362
int prior;
2363
- char *zComment;
2364
- const char *zPrefix;
2363
+ char cPrefix;
23652364
int nWiki;
23662365
char zLength[40];
2366
+
23672367
while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
23682368
nWiki = strlen(p->zWiki);
23692369
sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
23702370
tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
23712371
fossil_free(zTag);
@@ -2377,56 +2377,27 @@
23772377
);
23782378
if( prior ){
23792379
content_deltify(prior, &rid, 1, 0);
23802380
}
23812381
if( nWiki<=0 ){
2382
- zPrefix = "Deleted";
2382
+ cPrefix = '-';
23832383
}else if( !prior ){
2384
- zPrefix = "Added";
2384
+ cPrefix = '+';
23852385
}else{
2386
- zPrefix = "Changes to";
2387
- }
2388
- switch( wiki_page_type(p->zWikiTitle) ){
2389
- case WIKITYPE_CHECKIN: {
2390
- zComment = mprintf("%s wiki for check-in [%S]", zPrefix,
2391
- p->zWikiTitle+8);
2392
- break;
2393
- }
2394
- case WIKITYPE_BRANCH: {
2395
- zComment = mprintf("%s wiki for branch [/timeline?r=%t|%h]",
2396
- zPrefix, p->zWikiTitle+7, p->zWikiTitle+7);
2397
- break;
2398
- }
2399
- case WIKITYPE_TAG: {
2400
- zComment = mprintf("%s wiki for tag [/timeline?t=%t|%h]",
2401
- zPrefix, p->zWikiTitle+4, p->zWikiTitle+4);
2402
- break;
2403
- }
2404
- default: {
2405
- zComment = mprintf("%s wiki page [%h]", zPrefix, p->zWikiTitle);
2406
- break;
2407
- }
2386
+ cPrefix = ':';
24082387
}
24092388
search_doc_touch('w',rid,p->zWikiTitle);
24102389
if( manifest_crosslink_busy ){
24112390
add_pending_crosslink('w',p->zWikiTitle);
24122391
}else{
24132392
backlink_wiki_refresh(p->zWikiTitle);
24142393
}
24152394
db_multi_exec(
2416
- "REPLACE INTO event(type,mtime,objid,user,comment,"
2417
- " bgcolor,euser,ecomment)"
2418
- "VALUES('w',%.17g,%d,%Q,%Q,"
2419
- " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
2420
- " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
2421
- " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
2422
- p->rDate, rid, p->zUser, zComment,
2423
- TAG_BGCOLOR, rid,
2424
- TAG_USER, rid,
2425
- TAG_COMMENT, rid
2395
+ "REPLACE INTO event(type,mtime,objid,user,comment)"
2396
+ "VALUES('w',%.17g,%d,%Q,'%c%q');",
2397
+ p->rDate, rid, p->zUser, cPrefix, p->zWikiTitle
24262398
);
2427
- fossil_free(zComment);
24282399
}
24292400
if( p->type==CFTYPE_EVENT ){
24302401
char *zTag = mprintf("event-%s", p->zEventId);
24312402
int tagid = tag_findid(zTag, 1);
24322403
int prior, subsequent;
24332404
--- src/manifest.c
+++ src/manifest.c
@@ -2358,14 +2358,14 @@
2358 }
2359 if( p->type==CFTYPE_WIKI ){
2360 char *zTag = mprintf("wiki-%s", p->zWikiTitle);
2361 int tagid = tag_findid(zTag, 1);
2362 int prior;
2363 char *zComment;
2364 const char *zPrefix;
2365 int nWiki;
2366 char zLength[40];
 
2367 while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
2368 nWiki = strlen(p->zWiki);
2369 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
2370 tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
2371 fossil_free(zTag);
@@ -2377,56 +2377,27 @@
2377 );
2378 if( prior ){
2379 content_deltify(prior, &rid, 1, 0);
2380 }
2381 if( nWiki<=0 ){
2382 zPrefix = "Deleted";
2383 }else if( !prior ){
2384 zPrefix = "Added";
2385 }else{
2386 zPrefix = "Changes to";
2387 }
2388 switch( wiki_page_type(p->zWikiTitle) ){
2389 case WIKITYPE_CHECKIN: {
2390 zComment = mprintf("%s wiki for check-in [%S]", zPrefix,
2391 p->zWikiTitle+8);
2392 break;
2393 }
2394 case WIKITYPE_BRANCH: {
2395 zComment = mprintf("%s wiki for branch [/timeline?r=%t|%h]",
2396 zPrefix, p->zWikiTitle+7, p->zWikiTitle+7);
2397 break;
2398 }
2399 case WIKITYPE_TAG: {
2400 zComment = mprintf("%s wiki for tag [/timeline?t=%t|%h]",
2401 zPrefix, p->zWikiTitle+4, p->zWikiTitle+4);
2402 break;
2403 }
2404 default: {
2405 zComment = mprintf("%s wiki page [%h]", zPrefix, p->zWikiTitle);
2406 break;
2407 }
2408 }
2409 search_doc_touch('w',rid,p->zWikiTitle);
2410 if( manifest_crosslink_busy ){
2411 add_pending_crosslink('w',p->zWikiTitle);
2412 }else{
2413 backlink_wiki_refresh(p->zWikiTitle);
2414 }
2415 db_multi_exec(
2416 "REPLACE INTO event(type,mtime,objid,user,comment,"
2417 " bgcolor,euser,ecomment)"
2418 "VALUES('w',%.17g,%d,%Q,%Q,"
2419 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
2420 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
2421 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
2422 p->rDate, rid, p->zUser, zComment,
2423 TAG_BGCOLOR, rid,
2424 TAG_USER, rid,
2425 TAG_COMMENT, rid
2426 );
2427 fossil_free(zComment);
2428 }
2429 if( p->type==CFTYPE_EVENT ){
2430 char *zTag = mprintf("event-%s", p->zEventId);
2431 int tagid = tag_findid(zTag, 1);
2432 int prior, subsequent;
2433
--- src/manifest.c
+++ src/manifest.c
@@ -2358,14 +2358,14 @@
2358 }
2359 if( p->type==CFTYPE_WIKI ){
2360 char *zTag = mprintf("wiki-%s", p->zWikiTitle);
2361 int tagid = tag_findid(zTag, 1);
2362 int prior;
2363 char cPrefix;
 
2364 int nWiki;
2365 char zLength[40];
2366
2367 while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
2368 nWiki = strlen(p->zWiki);
2369 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
2370 tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
2371 fossil_free(zTag);
@@ -2377,56 +2377,27 @@
2377 );
2378 if( prior ){
2379 content_deltify(prior, &rid, 1, 0);
2380 }
2381 if( nWiki<=0 ){
2382 cPrefix = '-';
2383 }else if( !prior ){
2384 cPrefix = '+';
2385 }else{
2386 cPrefix = ':';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2387 }
2388 search_doc_touch('w',rid,p->zWikiTitle);
2389 if( manifest_crosslink_busy ){
2390 add_pending_crosslink('w',p->zWikiTitle);
2391 }else{
2392 backlink_wiki_refresh(p->zWikiTitle);
2393 }
2394 db_multi_exec(
2395 "REPLACE INTO event(type,mtime,objid,user,comment)"
2396 "VALUES('w',%.17g,%d,%Q,'%c%q');",
2397 p->rDate, rid, p->zUser, cPrefix, p->zWikiTitle
 
 
 
 
 
 
 
2398 );
 
2399 }
2400 if( p->type==CFTYPE_EVENT ){
2401 char *zTag = mprintf("event-%s", p->zEventId);
2402 int tagid = tag_findid(zTag, 1);
2403 int prior, subsequent;
2404
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -371,11 +371,11 @@
371371
blob_reset(&out);
372372
} CX("</div>"/*#pikchrshow-output*/);
373373
} CX("</fieldset>"/*#pikchrshow-output-wrapper*/);
374374
} CX("</div>"/*sbs-wrapper*/);
375375
builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
376
- "storage", "pikchr", 0);
376
+ "storage", "pikchr", NULL);
377377
builtin_request_js("fossil.page.pikchrshow.js");
378378
builtin_fulfill_js_requests();
379379
style_finish_page("pikchrshow");
380380
}
381381
382382
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -371,11 +371,11 @@
371 blob_reset(&out);
372 } CX("</div>"/*#pikchrshow-output*/);
373 } CX("</fieldset>"/*#pikchrshow-output-wrapper*/);
374 } CX("</div>"/*sbs-wrapper*/);
375 builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
376 "storage", "pikchr", 0);
377 builtin_request_js("fossil.page.pikchrshow.js");
378 builtin_fulfill_js_requests();
379 style_finish_page("pikchrshow");
380 }
381
382
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -371,11 +371,11 @@
371 blob_reset(&out);
372 } CX("</div>"/*#pikchrshow-output*/);
373 } CX("</fieldset>"/*#pikchrshow-output-wrapper*/);
374 } CX("</div>"/*sbs-wrapper*/);
375 builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
376 "storage", "pikchr", NULL);
377 builtin_request_js("fossil.page.pikchrshow.js");
378 builtin_fulfill_js_requests();
379 style_finish_page("pikchrshow");
380 }
381
382
+39 -16
--- src/shell.c
+++ src/shell.c
@@ -5420,14 +5420,14 @@
54205420
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
54215421
** result set of queries against generate_series will look like.
54225422
*/
54235423
static int seriesConnect(
54245424
sqlite3 *db,
5425
- void *pAux,
5426
- int argc, const char *const*argv,
5425
+ void *pUnused,
5426
+ int argcUnused, const char *const*argvUnused,
54275427
sqlite3_vtab **ppVtab,
5428
- char **pzErr
5428
+ char **pzErrUnused
54295429
){
54305430
sqlite3_vtab *pNew;
54315431
int rc;
54325432
54335433
/* Column numbers */
@@ -5434,10 +5434,14 @@
54345434
#define SERIES_COLUMN_VALUE 0
54355435
#define SERIES_COLUMN_START 1
54365436
#define SERIES_COLUMN_STOP 2
54375437
#define SERIES_COLUMN_STEP 3
54385438
5439
+ (void)pUnused;
5440
+ (void)argcUnused;
5441
+ (void)argvUnused;
5442
+ (void)pzErrUnused;
54395443
rc = sqlite3_declare_vtab(db,
54405444
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
54415445
if( rc==SQLITE_OK ){
54425446
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
54435447
if( pNew==0 ) return SQLITE_NOMEM;
@@ -5456,12 +5460,13 @@
54565460
}
54575461
54585462
/*
54595463
** Constructor for a new series_cursor object.
54605464
*/
5461
-static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
5465
+static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
54625466
series_cursor *pCur;
5467
+ (void)pUnused;
54635468
pCur = sqlite3_malloc( sizeof(*pCur) );
54645469
if( pCur==0 ) return SQLITE_NOMEM;
54655470
memset(pCur, 0, sizeof(*pCur));
54665471
*ppCursor = &pCur->base;
54675472
return SQLITE_OK;
@@ -5564,15 +5569,16 @@
55645569
** is pointing at the first row, or pointing off the end of the table
55655570
** (so that seriesEof() will return true) if the table is empty.
55665571
*/
55675572
static int seriesFilter(
55685573
sqlite3_vtab_cursor *pVtabCursor,
5569
- int idxNum, const char *idxStr,
5574
+ int idxNum, const char *idxStrUnused,
55705575
int argc, sqlite3_value **argv
55715576
){
55725577
series_cursor *pCur = (series_cursor *)pVtabCursor;
55735578
int i = 0;
5579
+ (void)idxStrUnused;
55745580
if( idxNum & 1 ){
55755581
pCur->mnValue = sqlite3_value_int64(argv[i++]);
55765582
}else{
55775583
pCur->mnValue = 0;
55785584
}
@@ -5625,11 +5631,11 @@
56255631
** (2) stop = $value -- constraint exists
56265632
** (4) step = $value -- constraint exists
56275633
** (8) output in descending order
56285634
*/
56295635
static int seriesBestIndex(
5630
- sqlite3_vtab *tab,
5636
+ sqlite3_vtab *tabUnused,
56315637
sqlite3_index_info *pIdxInfo
56325638
){
56335639
int i, j; /* Loop over constraints */
56345640
int idxNum = 0; /* The query plan bitmask */
56355641
int unusableMask = 0; /* Mask of unusable constraints */
@@ -5639,10 +5645,11 @@
56395645
56405646
/* This implementation assumes that the start, stop, and step columns
56415647
** are the last three columns in the virtual table. */
56425648
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
56435649
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
5650
+ (void)tabUnused;
56445651
aIdx[0] = aIdx[1] = aIdx[2] = -1;
56455652
pConstraint = pIdxInfo->aConstraint;
56465653
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
56475654
int iCol; /* 0 for start, 1 for stop, 2 for step */
56485655
int iMask; /* bitmask for those column */
@@ -5712,10 +5719,14 @@
57125719
0, /* xSync */
57135720
0, /* xCommit */
57145721
0, /* xRollback */
57155722
0, /* xFindMethod */
57165723
0, /* xRename */
5724
+ 0, /* xSavepoint */
5725
+ 0, /* xRelease */
5726
+ 0, /* xRollbackTo */
5727
+ 0 /* xShadowName */
57175728
};
57185729
57195730
#endif /* SQLITE_OMIT_VIRTUALTABLE */
57205731
57215732
#ifdef _WIN32
@@ -14455,14 +14466,15 @@
1445514466
/*
1445614467
** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
1445714468
*/
1445814469
static void shellUSleepFunc(
1445914470
sqlite3_context *context,
14460
- int argc,
14471
+ int argcUnused,
1446114472
sqlite3_value **argv
1446214473
){
1446314474
int sleep = sqlite3_value_int(argv[0]);
14475
+ (void)argcUnused;
1446414476
sqlite3_sleep(sleep/1000);
1446514477
sqlite3_result_int(context, sleep);
1446614478
}
1446714479
1446814480
/*
@@ -20657,12 +20669,15 @@
2065720669
p->in = fopen(sqliterc,"rb");
2065820670
if( p->in ){
2065920671
if( stdin_is_interactive ){
2066020672
utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
2066120673
}
20662
- process_input(p);
20674
+ if( process_input(p) && bail_on_error ) exit(1);
2066320675
fclose(p->in);
20676
+ }else if( sqliterc_override!=0 ){
20677
+ utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
20678
+ if( bail_on_error ) exit(1);
2066420679
}
2066520680
p->in = inSaved;
2066620681
p->lineno = savedLineno;
2066720682
sqlite3_free(zBuf);
2066820683
}
@@ -21044,10 +21059,12 @@
2104421059
** command, so ignore them */
2104521060
break;
2104621061
#endif
2104721062
}else if( strcmp(z, "-memtrace")==0 ){
2104821063
sqlite3MemTraceActivate(stderr);
21064
+ }else if( strcmp(z,"-bail")==0 ){
21065
+ bail_on_error = 1;
2104921066
}
2105021067
}
2105121068
verify_uninitialized();
2105221069
2105321070
@@ -21190,11 +21207,11 @@
2119021207
** prior to sending the SQL into SQLite. Useful for injecting
2119121208
** crazy bytes in the middle of SQL statements for testing and debugging.
2119221209
*/
2119321210
ShellSetFlag(&data, SHFLG_Backslash);
2119421211
}else if( strcmp(z,"-bail")==0 ){
21195
- bail_on_error = 1;
21212
+ /* No-op. The bail_on_error flag should already be set. */
2119621213
}else if( strcmp(z,"-version")==0 ){
2119721214
printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
2119821215
return 0;
2119921216
}else if( strcmp(z,"-interactive")==0 ){
2120021217
stdin_is_interactive = 1;
@@ -21278,24 +21295,29 @@
2127821295
** the database filename.
2127921296
*/
2128021297
for(i=0; i<nCmd; i++){
2128121298
if( azCmd[i][0]=='.' ){
2128221299
rc = do_meta_command(azCmd[i], &data);
21283
- if( rc ) return rc==2 ? 0 : rc;
21300
+ if( rc ){
21301
+ free(azCmd);
21302
+ return rc==2 ? 0 : rc;
21303
+ }
2128421304
}else{
2128521305
open_db(&data, 0);
2128621306
rc = shell_exec(&data, azCmd[i], &zErrMsg);
21287
- if( zErrMsg!=0 ){
21288
- utf8_printf(stderr,"Error: %s\n", zErrMsg);
21307
+ if( zErrMsg || rc ){
21308
+ if( zErrMsg!=0 ){
21309
+ utf8_printf(stderr,"Error: %s\n", zErrMsg);
21310
+ }else{
21311
+ utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
21312
+ }
21313
+ sqlite3_free(zErrMsg);
21314
+ free(azCmd);
2128921315
return rc!=0 ? rc : 1;
21290
- }else if( rc!=0 ){
21291
- utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
21292
- return rc;
2129321316
}
2129421317
}
2129521318
}
21296
- free(azCmd);
2129721319
}else{
2129821320
/* Run commands received from standard input
2129921321
*/
2130021322
if( stdin_is_interactive ){
2130121323
char *zHome;
@@ -21337,10 +21359,11 @@
2133721359
}else{
2133821360
data.in = stdin;
2133921361
rc = process_input(&data);
2134021362
}
2134121363
}
21364
+ free(azCmd);
2134221365
set_table_name(&data, 0);
2134321366
if( data.db ){
2134421367
session_close_all(&data);
2134521368
close_db(data.db);
2134621369
}
2134721370
--- src/shell.c
+++ src/shell.c
@@ -5420,14 +5420,14 @@
5420 ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
5421 ** result set of queries against generate_series will look like.
5422 */
5423 static int seriesConnect(
5424 sqlite3 *db,
5425 void *pAux,
5426 int argc, const char *const*argv,
5427 sqlite3_vtab **ppVtab,
5428 char **pzErr
5429 ){
5430 sqlite3_vtab *pNew;
5431 int rc;
5432
5433 /* Column numbers */
@@ -5434,10 +5434,14 @@
5434 #define SERIES_COLUMN_VALUE 0
5435 #define SERIES_COLUMN_START 1
5436 #define SERIES_COLUMN_STOP 2
5437 #define SERIES_COLUMN_STEP 3
5438
 
 
 
 
5439 rc = sqlite3_declare_vtab(db,
5440 "CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
5441 if( rc==SQLITE_OK ){
5442 pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
5443 if( pNew==0 ) return SQLITE_NOMEM;
@@ -5456,12 +5460,13 @@
5456 }
5457
5458 /*
5459 ** Constructor for a new series_cursor object.
5460 */
5461 static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
5462 series_cursor *pCur;
 
5463 pCur = sqlite3_malloc( sizeof(*pCur) );
5464 if( pCur==0 ) return SQLITE_NOMEM;
5465 memset(pCur, 0, sizeof(*pCur));
5466 *ppCursor = &pCur->base;
5467 return SQLITE_OK;
@@ -5564,15 +5569,16 @@
5564 ** is pointing at the first row, or pointing off the end of the table
5565 ** (so that seriesEof() will return true) if the table is empty.
5566 */
5567 static int seriesFilter(
5568 sqlite3_vtab_cursor *pVtabCursor,
5569 int idxNum, const char *idxStr,
5570 int argc, sqlite3_value **argv
5571 ){
5572 series_cursor *pCur = (series_cursor *)pVtabCursor;
5573 int i = 0;
 
5574 if( idxNum & 1 ){
5575 pCur->mnValue = sqlite3_value_int64(argv[i++]);
5576 }else{
5577 pCur->mnValue = 0;
5578 }
@@ -5625,11 +5631,11 @@
5625 ** (2) stop = $value -- constraint exists
5626 ** (4) step = $value -- constraint exists
5627 ** (8) output in descending order
5628 */
5629 static int seriesBestIndex(
5630 sqlite3_vtab *tab,
5631 sqlite3_index_info *pIdxInfo
5632 ){
5633 int i, j; /* Loop over constraints */
5634 int idxNum = 0; /* The query plan bitmask */
5635 int unusableMask = 0; /* Mask of unusable constraints */
@@ -5639,10 +5645,11 @@
5639
5640 /* This implementation assumes that the start, stop, and step columns
5641 ** are the last three columns in the virtual table. */
5642 assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
5643 assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
 
5644 aIdx[0] = aIdx[1] = aIdx[2] = -1;
5645 pConstraint = pIdxInfo->aConstraint;
5646 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
5647 int iCol; /* 0 for start, 1 for stop, 2 for step */
5648 int iMask; /* bitmask for those column */
@@ -5712,10 +5719,14 @@
5712 0, /* xSync */
5713 0, /* xCommit */
5714 0, /* xRollback */
5715 0, /* xFindMethod */
5716 0, /* xRename */
 
 
 
 
5717 };
5718
5719 #endif /* SQLITE_OMIT_VIRTUALTABLE */
5720
5721 #ifdef _WIN32
@@ -14455,14 +14466,15 @@
14455 /*
14456 ** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
14457 */
14458 static void shellUSleepFunc(
14459 sqlite3_context *context,
14460 int argc,
14461 sqlite3_value **argv
14462 ){
14463 int sleep = sqlite3_value_int(argv[0]);
 
14464 sqlite3_sleep(sleep/1000);
14465 sqlite3_result_int(context, sleep);
14466 }
14467
14468 /*
@@ -20657,12 +20669,15 @@
20657 p->in = fopen(sqliterc,"rb");
20658 if( p->in ){
20659 if( stdin_is_interactive ){
20660 utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
20661 }
20662 process_input(p);
20663 fclose(p->in);
 
 
 
20664 }
20665 p->in = inSaved;
20666 p->lineno = savedLineno;
20667 sqlite3_free(zBuf);
20668 }
@@ -21044,10 +21059,12 @@
21044 ** command, so ignore them */
21045 break;
21046 #endif
21047 }else if( strcmp(z, "-memtrace")==0 ){
21048 sqlite3MemTraceActivate(stderr);
 
 
21049 }
21050 }
21051 verify_uninitialized();
21052
21053
@@ -21190,11 +21207,11 @@
21190 ** prior to sending the SQL into SQLite. Useful for injecting
21191 ** crazy bytes in the middle of SQL statements for testing and debugging.
21192 */
21193 ShellSetFlag(&data, SHFLG_Backslash);
21194 }else if( strcmp(z,"-bail")==0 ){
21195 bail_on_error = 1;
21196 }else if( strcmp(z,"-version")==0 ){
21197 printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
21198 return 0;
21199 }else if( strcmp(z,"-interactive")==0 ){
21200 stdin_is_interactive = 1;
@@ -21278,24 +21295,29 @@
21278 ** the database filename.
21279 */
21280 for(i=0; i<nCmd; i++){
21281 if( azCmd[i][0]=='.' ){
21282 rc = do_meta_command(azCmd[i], &data);
21283 if( rc ) return rc==2 ? 0 : rc;
 
 
 
21284 }else{
21285 open_db(&data, 0);
21286 rc = shell_exec(&data, azCmd[i], &zErrMsg);
21287 if( zErrMsg!=0 ){
21288 utf8_printf(stderr,"Error: %s\n", zErrMsg);
 
 
 
 
 
 
21289 return rc!=0 ? rc : 1;
21290 }else if( rc!=0 ){
21291 utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
21292 return rc;
21293 }
21294 }
21295 }
21296 free(azCmd);
21297 }else{
21298 /* Run commands received from standard input
21299 */
21300 if( stdin_is_interactive ){
21301 char *zHome;
@@ -21337,10 +21359,11 @@
21337 }else{
21338 data.in = stdin;
21339 rc = process_input(&data);
21340 }
21341 }
 
21342 set_table_name(&data, 0);
21343 if( data.db ){
21344 session_close_all(&data);
21345 close_db(data.db);
21346 }
21347
--- src/shell.c
+++ src/shell.c
@@ -5420,14 +5420,14 @@
5420 ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
5421 ** result set of queries against generate_series will look like.
5422 */
5423 static int seriesConnect(
5424 sqlite3 *db,
5425 void *pUnused,
5426 int argcUnused, const char *const*argvUnused,
5427 sqlite3_vtab **ppVtab,
5428 char **pzErrUnused
5429 ){
5430 sqlite3_vtab *pNew;
5431 int rc;
5432
5433 /* Column numbers */
@@ -5434,10 +5434,14 @@
5434 #define SERIES_COLUMN_VALUE 0
5435 #define SERIES_COLUMN_START 1
5436 #define SERIES_COLUMN_STOP 2
5437 #define SERIES_COLUMN_STEP 3
5438
5439 (void)pUnused;
5440 (void)argcUnused;
5441 (void)argvUnused;
5442 (void)pzErrUnused;
5443 rc = sqlite3_declare_vtab(db,
5444 "CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
5445 if( rc==SQLITE_OK ){
5446 pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
5447 if( pNew==0 ) return SQLITE_NOMEM;
@@ -5456,12 +5460,13 @@
5460 }
5461
5462 /*
5463 ** Constructor for a new series_cursor object.
5464 */
5465 static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
5466 series_cursor *pCur;
5467 (void)pUnused;
5468 pCur = sqlite3_malloc( sizeof(*pCur) );
5469 if( pCur==0 ) return SQLITE_NOMEM;
5470 memset(pCur, 0, sizeof(*pCur));
5471 *ppCursor = &pCur->base;
5472 return SQLITE_OK;
@@ -5564,15 +5569,16 @@
5569 ** is pointing at the first row, or pointing off the end of the table
5570 ** (so that seriesEof() will return true) if the table is empty.
5571 */
5572 static int seriesFilter(
5573 sqlite3_vtab_cursor *pVtabCursor,
5574 int idxNum, const char *idxStrUnused,
5575 int argc, sqlite3_value **argv
5576 ){
5577 series_cursor *pCur = (series_cursor *)pVtabCursor;
5578 int i = 0;
5579 (void)idxStrUnused;
5580 if( idxNum & 1 ){
5581 pCur->mnValue = sqlite3_value_int64(argv[i++]);
5582 }else{
5583 pCur->mnValue = 0;
5584 }
@@ -5625,11 +5631,11 @@
5631 ** (2) stop = $value -- constraint exists
5632 ** (4) step = $value -- constraint exists
5633 ** (8) output in descending order
5634 */
5635 static int seriesBestIndex(
5636 sqlite3_vtab *tabUnused,
5637 sqlite3_index_info *pIdxInfo
5638 ){
5639 int i, j; /* Loop over constraints */
5640 int idxNum = 0; /* The query plan bitmask */
5641 int unusableMask = 0; /* Mask of unusable constraints */
@@ -5639,10 +5645,11 @@
5645
5646 /* This implementation assumes that the start, stop, and step columns
5647 ** are the last three columns in the virtual table. */
5648 assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
5649 assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
5650 (void)tabUnused;
5651 aIdx[0] = aIdx[1] = aIdx[2] = -1;
5652 pConstraint = pIdxInfo->aConstraint;
5653 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
5654 int iCol; /* 0 for start, 1 for stop, 2 for step */
5655 int iMask; /* bitmask for those column */
@@ -5712,10 +5719,14 @@
5719 0, /* xSync */
5720 0, /* xCommit */
5721 0, /* xRollback */
5722 0, /* xFindMethod */
5723 0, /* xRename */
5724 0, /* xSavepoint */
5725 0, /* xRelease */
5726 0, /* xRollbackTo */
5727 0 /* xShadowName */
5728 };
5729
5730 #endif /* SQLITE_OMIT_VIRTUALTABLE */
5731
5732 #ifdef _WIN32
@@ -14455,14 +14466,15 @@
14466 /*
14467 ** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
14468 */
14469 static void shellUSleepFunc(
14470 sqlite3_context *context,
14471 int argcUnused,
14472 sqlite3_value **argv
14473 ){
14474 int sleep = sqlite3_value_int(argv[0]);
14475 (void)argcUnused;
14476 sqlite3_sleep(sleep/1000);
14477 sqlite3_result_int(context, sleep);
14478 }
14479
14480 /*
@@ -20657,12 +20669,15 @@
20669 p->in = fopen(sqliterc,"rb");
20670 if( p->in ){
20671 if( stdin_is_interactive ){
20672 utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
20673 }
20674 if( process_input(p) && bail_on_error ) exit(1);
20675 fclose(p->in);
20676 }else if( sqliterc_override!=0 ){
20677 utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
20678 if( bail_on_error ) exit(1);
20679 }
20680 p->in = inSaved;
20681 p->lineno = savedLineno;
20682 sqlite3_free(zBuf);
20683 }
@@ -21044,10 +21059,12 @@
21059 ** command, so ignore them */
21060 break;
21061 #endif
21062 }else if( strcmp(z, "-memtrace")==0 ){
21063 sqlite3MemTraceActivate(stderr);
21064 }else if( strcmp(z,"-bail")==0 ){
21065 bail_on_error = 1;
21066 }
21067 }
21068 verify_uninitialized();
21069
21070
@@ -21190,11 +21207,11 @@
21207 ** prior to sending the SQL into SQLite. Useful for injecting
21208 ** crazy bytes in the middle of SQL statements for testing and debugging.
21209 */
21210 ShellSetFlag(&data, SHFLG_Backslash);
21211 }else if( strcmp(z,"-bail")==0 ){
21212 /* No-op. The bail_on_error flag should already be set. */
21213 }else if( strcmp(z,"-version")==0 ){
21214 printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
21215 return 0;
21216 }else if( strcmp(z,"-interactive")==0 ){
21217 stdin_is_interactive = 1;
@@ -21278,24 +21295,29 @@
21295 ** the database filename.
21296 */
21297 for(i=0; i<nCmd; i++){
21298 if( azCmd[i][0]=='.' ){
21299 rc = do_meta_command(azCmd[i], &data);
21300 if( rc ){
21301 free(azCmd);
21302 return rc==2 ? 0 : rc;
21303 }
21304 }else{
21305 open_db(&data, 0);
21306 rc = shell_exec(&data, azCmd[i], &zErrMsg);
21307 if( zErrMsg || rc ){
21308 if( zErrMsg!=0 ){
21309 utf8_printf(stderr,"Error: %s\n", zErrMsg);
21310 }else{
21311 utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
21312 }
21313 sqlite3_free(zErrMsg);
21314 free(azCmd);
21315 return rc!=0 ? rc : 1;
 
 
 
21316 }
21317 }
21318 }
 
21319 }else{
21320 /* Run commands received from standard input
21321 */
21322 if( stdin_is_interactive ){
21323 char *zHome;
@@ -21337,10 +21359,11 @@
21359 }else{
21360 data.in = stdin;
21361 rc = process_input(&data);
21362 }
21363 }
21364 free(azCmd);
21365 set_table_name(&data, 0);
21366 if( data.db ){
21367 session_close_all(&data);
21368 close_db(data.db);
21369 }
21370
+93 -13
--- src/sitemap.c
+++ src/sitemap.c
@@ -100,14 +100,11 @@
100100
}
101101
if( g.perm.Read ){
102102
@ <li>%z(href("%R/timeline"))Project Timeline</a>
103103
@ <ul>
104104
@ <li>%z(href("%R/reports"))Activity Reports</a></li>
105
- @ <li>%z(href("%R/timeline?n=all&namechng"))File name changes</a></li>
106
- @ <li>%z(href("%R/timeline?n=all&forks"))Forks</a></li>
107
- @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
108
- @ check-ins</a></li>
105
+ @ <li>%z(href("%R/sitemap-timeline"))Other timelines</a></li>
109106
@ </ul>
110107
@ </li>
111108
}
112109
if( g.perm.Read ){
113110
@ <li>%z(href("%R/brlist"))Branches</a>
@@ -192,11 +189,10 @@
192189
if( g.perm.Admin ){
193190
@ <li>%z(href("%R/urllist"))List of URLs used to access
194191
@ this repository</a></li>
195192
}
196193
@ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
197
- @ <li>%z(href("%R/timewarps"))List of "Timewarp" Check-ins</a></li>
198194
@ </ul>
199195
@ </li>
200196
}
201197
@ <li>%z(href("%R/help"))Help</a>
202198
@ <ul>
@@ -219,22 +215,106 @@
219215
@ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
220216
@ <li>%z(href("%R/admin_log"))Admin log</a></li>
221217
@ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
222218
@ </ul></li>
223219
}
224
- @ <li>Test Pages
225
- @ <ul>
220
+ @ <li>%z(href("%R/sitemap-test"))Test Pages</a></li>
221
+ if( isPopup ){
222
+ @ <li>%z(href("%R/sitemap"))Site Map</a></li>
223
+ }
224
+ @ </ul>
225
+ if( !isPopup ){
226
+ style_finish_page("sitemap");
227
+ }
228
+}
229
+
230
+/*
231
+** WEBPAGE: sitemap-test
232
+**
233
+** List some of the web pages offered by the Fossil web engine for testing
234
+** purposes. This is similar to /sitemap, but is focused only on showing
235
+** pages associated with testing.
236
+*/
237
+void sitemap_test_page(void){
238
+ int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
239
+
240
+ login_check_credentials();
241
+ if( P("popup")!=0 && cgi_csrf_safe(0) ){
242
+ /* If this is a POST from the same origin with the popup=1 parameter,
243
+ ** then disable anti-robot defenses */
244
+ isPopup = 1;
245
+ g.perm.Hyperlink = 1;
246
+ g.javascriptHyperlink = 0;
247
+ }
248
+ if( !isPopup ){
249
+ style_header("Test Page Map");
250
+ style_adunit_config(ADUNIT_RIGHT_OK);
251
+ }
252
+ @ <ul id="sitemap" class="columns" style="column-width:20em">
226253
if( g.perm.Admin || db_get_boolean("test_env_enable",0) ){
227
- @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
254
+ @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
228255
}
229256
if( g.perm.Read ){
230
- @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
257
+ @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
258
+ }
259
+ @ <li>%z(href("%R/test-builtin-files"))List of built-in files</a></li>
260
+ @ <li>%z(href("%R/mimetype_list"))List of MIME types</a></li>
261
+ @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
262
+ @ colors assigned to branch names</a>
263
+ if( g.perm.Admin ){
264
+ @ <li>%z(href("%R/test-backlinks"))List of backlinks</a></li>
265
+ @ <li>%z(href("%R/test-backlink-timeline"))Backlink timeline</a></li>
266
+ @ <li>%z(href("%R/phantoms"))List of phantom artifacts</a></li>
267
+ @ <li>%z(href("%R/test-warning"))Error Log test page</a></li>
268
+ @ <li>%z(href("%R/repo_stat1"))Repository <tt>sqlite_stat1</tt> table</a>
269
+ @ <li>%z(href("%R/repo_schema"))Repository schema</a></li>
270
+ }
271
+ if( g.perm.Read && g.perm.Hyperlink ){
272
+ @ <li>%z(href("%R/timewarps"))Timeline of timewarps</a></li>
273
+ }
274
+ @ <li>%z(href("%R/cookies"))Content of display preference cookie</a></li>
275
+ @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
276
+ @ <li>%z(href("%R/test-piechart"))Pie-Chart generator test</a></li>
277
+ if( !isPopup ){
278
+ style_finish_page("sitemap");
279
+ }
280
+}
281
+
282
+/*
283
+** WEBPAGE: sitemap-timeline
284
+**
285
+** Generate a list of hyperlinks to various (obscure) variations on
286
+** the /timeline page.
287
+*/
288
+void sitemap_timeline_page(void){
289
+ int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
290
+
291
+ login_check_credentials();
292
+ if( P("popup")!=0 && cgi_csrf_safe(0) ){
293
+ /* If this is a POST from the same origin with the popup=1 parameter,
294
+ ** then disable anti-robot defenses */
295
+ isPopup = 1;
296
+ g.perm.Hyperlink = 1;
297
+ g.javascriptHyperlink = 0;
298
+ }
299
+ if( !isPopup ){
300
+ style_header("Timeline Examples");
301
+ style_adunit_config(ADUNIT_RIGHT_OK);
231302
}
232
- @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
233
- @ colors assigned to branch names</a>
234
- @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
235
- @ </ul></li>
303
+ @ <ul id="sitemap" class="columns" style="column-width:20em">
304
+ @ <li>%z(href("%R/timeline?ymd"))Current day</a></li>
305
+ @ <li>%z(href("%R/timeline?yw"))Current week</a></li>
306
+ @ <li>%z(href("%R/timeline?ym"))Current month</a></li>
307
+ @ <li>%z(href("%R/thisdayinhistory"))Today in history</a></li>
308
+ @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
309
+ @ check-ins</a></li>
310
+ @ <li>%z(href("%R/timeline?namechng"))File name changes</a></li>
311
+ @ <li>%z(href("%R/timeline?forks"))Forks</a></li>
312
+ @ <li>%z(href("%R/timeline?cherrypicks"))Cherrypick merges</a></li>
313
+ @ <li>%z(href("%R/timewarps"))Timewarps</a></li>
314
+ @ <li>%z(href("%R/timeline?ubg"))Color-coded by user</a></li>
315
+ @ <li>%z(href("%R/timeline?deltabg"))Delta vs. baseline manifests</a></li>
236316
@ </ul>
237317
if( !isPopup ){
238318
style_finish_page("sitemap");
239319
}
240320
}
241321
--- src/sitemap.c
+++ src/sitemap.c
@@ -100,14 +100,11 @@
100 }
101 if( g.perm.Read ){
102 @ <li>%z(href("%R/timeline"))Project Timeline</a>
103 @ <ul>
104 @ <li>%z(href("%R/reports"))Activity Reports</a></li>
105 @ <li>%z(href("%R/timeline?n=all&namechng"))File name changes</a></li>
106 @ <li>%z(href("%R/timeline?n=all&forks"))Forks</a></li>
107 @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
108 @ check-ins</a></li>
109 @ </ul>
110 @ </li>
111 }
112 if( g.perm.Read ){
113 @ <li>%z(href("%R/brlist"))Branches</a>
@@ -192,11 +189,10 @@
192 if( g.perm.Admin ){
193 @ <li>%z(href("%R/urllist"))List of URLs used to access
194 @ this repository</a></li>
195 }
196 @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
197 @ <li>%z(href("%R/timewarps"))List of "Timewarp" Check-ins</a></li>
198 @ </ul>
199 @ </li>
200 }
201 @ <li>%z(href("%R/help"))Help</a>
202 @ <ul>
@@ -219,22 +215,106 @@
219 @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
220 @ <li>%z(href("%R/admin_log"))Admin log</a></li>
221 @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
222 @ </ul></li>
223 }
224 @ <li>Test Pages
225 @ <ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226 if( g.perm.Admin || db_get_boolean("test_env_enable",0) ){
227 @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
228 }
229 if( g.perm.Read ){
230 @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231 }
232 @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
233 @ colors assigned to branch names</a>
234 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
235 @ </ul></li>
 
 
 
 
 
 
 
 
 
236 @ </ul>
237 if( !isPopup ){
238 style_finish_page("sitemap");
239 }
240 }
241
--- src/sitemap.c
+++ src/sitemap.c
@@ -100,14 +100,11 @@
100 }
101 if( g.perm.Read ){
102 @ <li>%z(href("%R/timeline"))Project Timeline</a>
103 @ <ul>
104 @ <li>%z(href("%R/reports"))Activity Reports</a></li>
105 @ <li>%z(href("%R/sitemap-timeline"))Other timelines</a></li>
 
 
 
106 @ </ul>
107 @ </li>
108 }
109 if( g.perm.Read ){
110 @ <li>%z(href("%R/brlist"))Branches</a>
@@ -192,11 +189,10 @@
189 if( g.perm.Admin ){
190 @ <li>%z(href("%R/urllist"))List of URLs used to access
191 @ this repository</a></li>
192 }
193 @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
 
194 @ </ul>
195 @ </li>
196 }
197 @ <li>%z(href("%R/help"))Help</a>
198 @ <ul>
@@ -219,22 +215,106 @@
215 @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
216 @ <li>%z(href("%R/admin_log"))Admin log</a></li>
217 @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
218 @ </ul></li>
219 }
220 @ <li>%z(href("%R/sitemap-test"))Test Pages</a></li>
221 if( isPopup ){
222 @ <li>%z(href("%R/sitemap"))Site Map</a></li>
223 }
224 @ </ul>
225 if( !isPopup ){
226 style_finish_page("sitemap");
227 }
228 }
229
230 /*
231 ** WEBPAGE: sitemap-test
232 **
233 ** List some of the web pages offered by the Fossil web engine for testing
234 ** purposes. This is similar to /sitemap, but is focused only on showing
235 ** pages associated with testing.
236 */
237 void sitemap_test_page(void){
238 int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
239
240 login_check_credentials();
241 if( P("popup")!=0 && cgi_csrf_safe(0) ){
242 /* If this is a POST from the same origin with the popup=1 parameter,
243 ** then disable anti-robot defenses */
244 isPopup = 1;
245 g.perm.Hyperlink = 1;
246 g.javascriptHyperlink = 0;
247 }
248 if( !isPopup ){
249 style_header("Test Page Map");
250 style_adunit_config(ADUNIT_RIGHT_OK);
251 }
252 @ <ul id="sitemap" class="columns" style="column-width:20em">
253 if( g.perm.Admin || db_get_boolean("test_env_enable",0) ){
254 @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
255 }
256 if( g.perm.Read ){
257 @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
258 }
259 @ <li>%z(href("%R/test-builtin-files"))List of built-in files</a></li>
260 @ <li>%z(href("%R/mimetype_list"))List of MIME types</a></li>
261 @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
262 @ colors assigned to branch names</a>
263 if( g.perm.Admin ){
264 @ <li>%z(href("%R/test-backlinks"))List of backlinks</a></li>
265 @ <li>%z(href("%R/test-backlink-timeline"))Backlink timeline</a></li>
266 @ <li>%z(href("%R/phantoms"))List of phantom artifacts</a></li>
267 @ <li>%z(href("%R/test-warning"))Error Log test page</a></li>
268 @ <li>%z(href("%R/repo_stat1"))Repository <tt>sqlite_stat1</tt> table</a>
269 @ <li>%z(href("%R/repo_schema"))Repository schema</a></li>
270 }
271 if( g.perm.Read && g.perm.Hyperlink ){
272 @ <li>%z(href("%R/timewarps"))Timeline of timewarps</a></li>
273 }
274 @ <li>%z(href("%R/cookies"))Content of display preference cookie</a></li>
275 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
276 @ <li>%z(href("%R/test-piechart"))Pie-Chart generator test</a></li>
277 if( !isPopup ){
278 style_finish_page("sitemap");
279 }
280 }
281
282 /*
283 ** WEBPAGE: sitemap-timeline
284 **
285 ** Generate a list of hyperlinks to various (obscure) variations on
286 ** the /timeline page.
287 */
288 void sitemap_timeline_page(void){
289 int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */
290
291 login_check_credentials();
292 if( P("popup")!=0 && cgi_csrf_safe(0) ){
293 /* If this is a POST from the same origin with the popup=1 parameter,
294 ** then disable anti-robot defenses */
295 isPopup = 1;
296 g.perm.Hyperlink = 1;
297 g.javascriptHyperlink = 0;
298 }
299 if( !isPopup ){
300 style_header("Timeline Examples");
301 style_adunit_config(ADUNIT_RIGHT_OK);
302 }
303 @ <ul id="sitemap" class="columns" style="column-width:20em">
304 @ <li>%z(href("%R/timeline?ymd"))Current day</a></li>
305 @ <li>%z(href("%R/timeline?yw"))Current week</a></li>
306 @ <li>%z(href("%R/timeline?ym"))Current month</a></li>
307 @ <li>%z(href("%R/thisdayinhistory"))Today in history</a></li>
308 @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
309 @ check-ins</a></li>
310 @ <li>%z(href("%R/timeline?namechng"))File name changes</a></li>
311 @ <li>%z(href("%R/timeline?forks"))Forks</a></li>
312 @ <li>%z(href("%R/timeline?cherrypicks"))Cherrypick merges</a></li>
313 @ <li>%z(href("%R/timewarps"))Timewarps</a></li>
314 @ <li>%z(href("%R/timeline?ubg"))Color-coded by user</a></li>
315 @ <li>%z(href("%R/timeline?deltabg"))Delta vs. baseline manifests</a></li>
316 @ </ul>
317 if( !isPopup ){
318 style_finish_page("sitemap");
319 }
320 }
321
+37 -14
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -32,10 +32,15 @@
3232
3333
#ifndef _WIN32
3434
# include "linenoise.h"
3535
#endif
3636
37
+/*
38
+** True if the "fossil sql" command has the --test flag. False otherwise.
39
+*/
40
+static int local_bSqlCmdTest = 0;
41
+
3742
/*
3843
** Implementation of the "content(X)" SQL function. Return the complete
3944
** content of artifact identified by X as a blob.
4045
*/
4146
static void sqlcmd_content(
@@ -114,11 +119,10 @@
114119
pIn = sqlite3_value_blob(argv[0]);
115120
if( pIn==0 ) return;
116121
nIn = sqlite3_value_bytes(argv[0]);
117122
if( nIn<4 ) return;
118123
nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3];
119
- if( nOut<0 ) return;
120124
pOut = sqlite3_malloc( nOut+1 );
121125
rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
122126
if( rc==Z_OK ){
123127
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
124128
}else if( rc==Z_MEM_ERROR ){
@@ -163,33 +167,46 @@
163167
** Undocumented test SQL functions:
164168
**
165169
** db_protect(X)
166170
** db_protect_pop(X)
167171
**
168
-** These invoke the corresponding C routines. Misuse may result in
169
-** an assertion fault.
172
+** These invoke the corresponding C routines.
173
+**
174
+** WARNING:
175
+** Do not instantiate these functions for any Fossil webpage or command
176
+** method of than the "fossil sql" command. If an attacker gains access
177
+** to these functions, he will be able to disable other defense mechanisms.
178
+**
179
+** This routines are for interactiving testing only. They are experimental
180
+** and undocumented (apart from this comments) and might go away or change
181
+** in future releases.
182
+**
183
+** 2020-11-29: This functions are now only available if the "fossil sql"
184
+** command is started with the --test option.
170185
*/
171186
static void sqlcmd_db_protect(
172187
sqlite3_context *context,
173188
int argc,
174189
sqlite3_value **argv
175190
){
176191
unsigned mask = 0;
177192
const char *z = (const char*)sqlite3_value_text(argv[0]);
178
- if( sqlite3_stricmp(z,"user")==0 ) mask |= PROTECT_USER;
179
- if( sqlite3_stricmp(z,"config")==0 ) mask |= PROTECT_CONFIG;
180
- if( sqlite3_stricmp(z,"sensitive")==0 ) mask |= PROTECT_SENSITIVE;
181
- if( sqlite3_stricmp(z,"readonly")==0 ) mask |= PROTECT_READONLY;
182
- if( sqlite3_stricmp(z,"all")==0 ) mask |= PROTECT_ALL;
183
- db_protect(mask);
193
+ if( z!=0 && local_bSqlCmdTest ){
194
+ if( sqlite3_stricmp(z,"user")==0 ) mask |= PROTECT_USER;
195
+ if( sqlite3_stricmp(z,"config")==0 ) mask |= PROTECT_CONFIG;
196
+ if( sqlite3_stricmp(z,"sensitive")==0 ) mask |= PROTECT_SENSITIVE;
197
+ if( sqlite3_stricmp(z,"readonly")==0 ) mask |= PROTECT_READONLY;
198
+ if( sqlite3_stricmp(z,"all")==0 ) mask |= PROTECT_ALL;
199
+ db_protect(mask);
200
+ }
184201
}
185202
static void sqlcmd_db_protect_pop(
186203
sqlite3_context *context,
187204
int argc,
188205
sqlite3_value **argv
189206
){
190
- db_protect_pop();
207
+ if( !local_bSqlCmdTest ) db_protect_pop();
191208
}
192209
193210
194211
195212
@@ -232,14 +249,16 @@
232249
** will get cleaned up when the shell closes the database connection */
233250
if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
234251
sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
235252
db_protect_only(PROTECT_NONE);
236253
sqlite3_set_authorizer(db, db_top_authorizer, db);
237
- sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
238
- sqlcmd_db_protect, 0, 0);
239
- sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
240
- sqlcmd_db_protect_pop, 0, 0);
254
+ if( local_bSqlCmdTest ){
255
+ sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
256
+ sqlcmd_db_protect, 0, 0);
257
+ sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
258
+ sqlcmd_db_protect_pop, 0, 0);
259
+ }
241260
return SQLITE_OK;
242261
}
243262
244263
/*
245264
** atexit() handler that cleans up global state modified by this module.
@@ -329,10 +348,13 @@
329348
** --readonly Open the repository read-only. No changes
330349
** are allowed. This is a recommended safety
331350
** precaution to prevent repository damage.
332351
**
333352
** -R REPOSITORY Use REPOSITORY as the repository database
353
+**
354
+** --test Enable some testing and analysis features
355
+** that are normally disabled.
334356
**
335357
** All of the standard sqlite3 command-line shell options should also
336358
** work.
337359
**
338360
** The following SQL extensions are provided with this Fossil-enhanced
@@ -397,10 +419,11 @@
397419
extern int sqlite3_shell(int, char**);
398420
#ifdef FOSSIL_ENABLE_TH1_HOOKS
399421
g.fNoThHook = 1;
400422
#endif
401423
noRepository = find_option("no-repository", 0, 0)!=0;
424
+ local_bSqlCmdTest = find_option("test",0,0)!=0;
402425
if( !noRepository ){
403426
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
404427
}
405428
db_open_config(1,0);
406429
zConfigDb = fossil_strdup(g.zConfigDbName);
407430
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -32,10 +32,15 @@
32
33 #ifndef _WIN32
34 # include "linenoise.h"
35 #endif
36
 
 
 
 
 
37 /*
38 ** Implementation of the "content(X)" SQL function. Return the complete
39 ** content of artifact identified by X as a blob.
40 */
41 static void sqlcmd_content(
@@ -114,11 +119,10 @@
114 pIn = sqlite3_value_blob(argv[0]);
115 if( pIn==0 ) return;
116 nIn = sqlite3_value_bytes(argv[0]);
117 if( nIn<4 ) return;
118 nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3];
119 if( nOut<0 ) return;
120 pOut = sqlite3_malloc( nOut+1 );
121 rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
122 if( rc==Z_OK ){
123 sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
124 }else if( rc==Z_MEM_ERROR ){
@@ -163,33 +167,46 @@
163 ** Undocumented test SQL functions:
164 **
165 ** db_protect(X)
166 ** db_protect_pop(X)
167 **
168 ** These invoke the corresponding C routines. Misuse may result in
169 ** an assertion fault.
 
 
 
 
 
 
 
 
 
 
 
170 */
171 static void sqlcmd_db_protect(
172 sqlite3_context *context,
173 int argc,
174 sqlite3_value **argv
175 ){
176 unsigned mask = 0;
177 const char *z = (const char*)sqlite3_value_text(argv[0]);
178 if( sqlite3_stricmp(z,"user")==0 ) mask |= PROTECT_USER;
179 if( sqlite3_stricmp(z,"config")==0 ) mask |= PROTECT_CONFIG;
180 if( sqlite3_stricmp(z,"sensitive")==0 ) mask |= PROTECT_SENSITIVE;
181 if( sqlite3_stricmp(z,"readonly")==0 ) mask |= PROTECT_READONLY;
182 if( sqlite3_stricmp(z,"all")==0 ) mask |= PROTECT_ALL;
183 db_protect(mask);
 
 
184 }
185 static void sqlcmd_db_protect_pop(
186 sqlite3_context *context,
187 int argc,
188 sqlite3_value **argv
189 ){
190 db_protect_pop();
191 }
192
193
194
195
@@ -232,14 +249,16 @@
232 ** will get cleaned up when the shell closes the database connection */
233 if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
234 sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
235 db_protect_only(PROTECT_NONE);
236 sqlite3_set_authorizer(db, db_top_authorizer, db);
237 sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
238 sqlcmd_db_protect, 0, 0);
239 sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
240 sqlcmd_db_protect_pop, 0, 0);
 
 
241 return SQLITE_OK;
242 }
243
244 /*
245 ** atexit() handler that cleans up global state modified by this module.
@@ -329,10 +348,13 @@
329 ** --readonly Open the repository read-only. No changes
330 ** are allowed. This is a recommended safety
331 ** precaution to prevent repository damage.
332 **
333 ** -R REPOSITORY Use REPOSITORY as the repository database
 
 
 
334 **
335 ** All of the standard sqlite3 command-line shell options should also
336 ** work.
337 **
338 ** The following SQL extensions are provided with this Fossil-enhanced
@@ -397,10 +419,11 @@
397 extern int sqlite3_shell(int, char**);
398 #ifdef FOSSIL_ENABLE_TH1_HOOKS
399 g.fNoThHook = 1;
400 #endif
401 noRepository = find_option("no-repository", 0, 0)!=0;
 
402 if( !noRepository ){
403 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
404 }
405 db_open_config(1,0);
406 zConfigDb = fossil_strdup(g.zConfigDbName);
407
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -32,10 +32,15 @@
32
33 #ifndef _WIN32
34 # include "linenoise.h"
35 #endif
36
37 /*
38 ** True if the "fossil sql" command has the --test flag. False otherwise.
39 */
40 static int local_bSqlCmdTest = 0;
41
42 /*
43 ** Implementation of the "content(X)" SQL function. Return the complete
44 ** content of artifact identified by X as a blob.
45 */
46 static void sqlcmd_content(
@@ -114,11 +119,10 @@
119 pIn = sqlite3_value_blob(argv[0]);
120 if( pIn==0 ) return;
121 nIn = sqlite3_value_bytes(argv[0]);
122 if( nIn<4 ) return;
123 nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3];
 
124 pOut = sqlite3_malloc( nOut+1 );
125 rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
126 if( rc==Z_OK ){
127 sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
128 }else if( rc==Z_MEM_ERROR ){
@@ -163,33 +167,46 @@
167 ** Undocumented test SQL functions:
168 **
169 ** db_protect(X)
170 ** db_protect_pop(X)
171 **
172 ** These invoke the corresponding C routines.
173 **
174 ** WARNING:
175 ** Do not instantiate these functions for any Fossil webpage or command
176 ** method of than the "fossil sql" command. If an attacker gains access
177 ** to these functions, he will be able to disable other defense mechanisms.
178 **
179 ** This routines are for interactiving testing only. They are experimental
180 ** and undocumented (apart from this comments) and might go away or change
181 ** in future releases.
182 **
183 ** 2020-11-29: This functions are now only available if the "fossil sql"
184 ** command is started with the --test option.
185 */
186 static void sqlcmd_db_protect(
187 sqlite3_context *context,
188 int argc,
189 sqlite3_value **argv
190 ){
191 unsigned mask = 0;
192 const char *z = (const char*)sqlite3_value_text(argv[0]);
193 if( z!=0 && local_bSqlCmdTest ){
194 if( sqlite3_stricmp(z,"user")==0 ) mask |= PROTECT_USER;
195 if( sqlite3_stricmp(z,"config")==0 ) mask |= PROTECT_CONFIG;
196 if( sqlite3_stricmp(z,"sensitive")==0 ) mask |= PROTECT_SENSITIVE;
197 if( sqlite3_stricmp(z,"readonly")==0 ) mask |= PROTECT_READONLY;
198 if( sqlite3_stricmp(z,"all")==0 ) mask |= PROTECT_ALL;
199 db_protect(mask);
200 }
201 }
202 static void sqlcmd_db_protect_pop(
203 sqlite3_context *context,
204 int argc,
205 sqlite3_value **argv
206 ){
207 if( !local_bSqlCmdTest ) db_protect_pop();
208 }
209
210
211
212
@@ -232,14 +249,16 @@
249 ** will get cleaned up when the shell closes the database connection */
250 if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
251 sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
252 db_protect_only(PROTECT_NONE);
253 sqlite3_set_authorizer(db, db_top_authorizer, db);
254 if( local_bSqlCmdTest ){
255 sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
256 sqlcmd_db_protect, 0, 0);
257 sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
258 sqlcmd_db_protect_pop, 0, 0);
259 }
260 return SQLITE_OK;
261 }
262
263 /*
264 ** atexit() handler that cleans up global state modified by this module.
@@ -329,10 +348,13 @@
348 ** --readonly Open the repository read-only. No changes
349 ** are allowed. This is a recommended safety
350 ** precaution to prevent repository damage.
351 **
352 ** -R REPOSITORY Use REPOSITORY as the repository database
353 **
354 ** --test Enable some testing and analysis features
355 ** that are normally disabled.
356 **
357 ** All of the standard sqlite3 command-line shell options should also
358 ** work.
359 **
360 ** The following SQL extensions are provided with this Fossil-enhanced
@@ -397,10 +419,11 @@
419 extern int sqlite3_shell(int, char**);
420 #ifdef FOSSIL_ENABLE_TH1_HOOKS
421 g.fNoThHook = 1;
422 #endif
423 noRepository = find_option("no-repository", 0, 0)!=0;
424 local_bSqlCmdTest = find_option("test",0,0)!=0;
425 if( !noRepository ){
426 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
427 }
428 db_open_config(1,0);
429 zConfigDb = fossil_strdup(g.zConfigDbName);
430
+215 -74
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1171,11 +1171,11 @@
11711171
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
11721172
** [sqlite_version()] and [sqlite_source_id()].
11731173
*/
11741174
#define SQLITE_VERSION "3.34.0"
11751175
#define SQLITE_VERSION_NUMBER 3034000
1176
-#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
1176
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b"
11771177
11781178
/*
11791179
** CAPI3REF: Run-Time Library Version Numbers
11801180
** KEYWORDS: sqlite3_version sqlite3_sourceid
11811181
**
@@ -1550,10 +1550,11 @@
15501550
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
15511551
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
15521552
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
15531553
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
15541554
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
1555
+#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
15551556
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
15561557
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
15571558
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
15581559
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
15591560
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
@@ -7238,11 +7239,11 @@
72387239
** CAPI3REF: Determine the transaction state of a database
72397240
** METHOD: sqlite3
72407241
**
72417242
** ^The sqlite3_txn_state(D,S) interface returns the current
72427243
** [transaction state] of schema S in database connection D. ^If S is NULL,
7243
-** then the highest transaction state of any schema on databse connection D
7244
+** then the highest transaction state of any schema on database connection D
72447245
** is returned. Transaction states are (in order of lowest to highest):
72457246
** <ol>
72467247
** <li value="0"> SQLITE_TXN_NONE
72477248
** <li value="1"> SQLITE_TXN_READ
72487249
** <li value="2"> SQLITE_TXN_WRITE
@@ -8785,11 +8786,10 @@
87858786
*/
87868787
#define SQLITE_TESTCTRL_FIRST 5
87878788
#define SQLITE_TESTCTRL_PRNG_SAVE 5
87888789
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
87898790
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
8790
-#define SQLITE_TESTCTRL_SEEK_COUNT 7
87918791
#define SQLITE_TESTCTRL_BITVEC_TEST 8
87928792
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
87938793
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
87948794
#define SQLITE_TESTCTRL_PENDING_BYTE 11
87958795
#define SQLITE_TESTCTRL_ASSERT 12
@@ -8810,11 +8810,12 @@
88108810
#define SQLITE_TESTCTRL_IMPOSTER 25
88118811
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
88128812
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
88138813
#define SQLITE_TESTCTRL_PRNG_SEED 28
88148814
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8815
-#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
8815
+#define SQLITE_TESTCTRL_SEEK_COUNT 30
8816
+#define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */
88168817
88178818
/*
88188819
** CAPI3REF: SQL Keyword Checking
88198820
**
88208821
** These routines provide access to the set of SQL language keywords
@@ -28182,16 +28183,19 @@
2818228183
EnableLookaside;
2818328184
}
2818428185
}
2818528186
2818628187
/*
28187
-** Take actions at the end of an API call to indicate an OOM error
28188
+** Take actions at the end of an API call to deal with error codes.
2818828189
*/
28189
-static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
28190
- sqlite3OomClear(db);
28191
- sqlite3Error(db, SQLITE_NOMEM);
28192
- return SQLITE_NOMEM_BKPT;
28190
+static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){
28191
+ if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
28192
+ sqlite3OomClear(db);
28193
+ sqlite3Error(db, SQLITE_NOMEM);
28194
+ return SQLITE_NOMEM_BKPT;
28195
+ }
28196
+ return rc & db->errMask;
2819328197
}
2819428198
2819528199
/*
2819628200
** This function must be called before exiting any API function (i.e.
2819728201
** returning control to the user) that has called sqlite3_malloc or
@@ -28209,12 +28213,12 @@
2820928213
** Otherwise the read (and possible write) of db->mallocFailed
2821028214
** is unsafe, as is the call to sqlite3Error().
2821128215
*/
2821228216
assert( db!=0 );
2821328217
assert( sqlite3_mutex_held(db->mutex) );
28214
- if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
28215
- return apiOomError(db);
28218
+ if( db->mallocFailed || rc ){
28219
+ return apiHandleError(db, rc);
2821628220
}
2821728221
return rc & db->errMask;
2821828222
}
2821928223
2822028224
/************** End of malloc.c **********************************************/
@@ -37003,11 +37007,28 @@
3700337007
3700437008
got = seekAndRead(pFile, offset, pBuf, amt);
3700537009
if( got==amt ){
3700637010
return SQLITE_OK;
3700737011
}else if( got<0 ){
37008
- /* lastErrno set by seekAndRead */
37012
+ /* pFile->lastErrno has been set by seekAndRead().
37013
+ ** Usually we return SQLITE_IOERR_READ here, though for some
37014
+ ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
37015
+ ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
37016
+ ** prior to returning to the application by the sqlite3ApiExit()
37017
+ ** routine.
37018
+ */
37019
+ switch( pFile->lastErrno ){
37020
+ case ERANGE:
37021
+ case EIO:
37022
+#ifdef ENXIO
37023
+ case ENXIO:
37024
+#endif
37025
+#ifdef EDEVERR
37026
+ case EDEVERR:
37027
+#endif
37028
+ return SQLITE_IOERR_CORRUPTFS;
37029
+ }
3700937030
return SQLITE_IOERR_READ;
3701037031
}else{
3701137032
storeLastErrno(pFile, 0); /* not a system error */
3701237033
/* Unread parts of the buffer must be zero-filled */
3701337034
memset(&((char*)pBuf)[got], 0, amt-got);
@@ -38535,11 +38556,11 @@
3853538556
if( bUnlock ){
3853638557
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
3853738558
if( rc==SQLITE_OK ){
3853838559
memset(&aLock[ofst], 0, sizeof(int)*n);
3853938560
}
38540
- }else if( p->sharedMask & (1<<ofst) ){
38561
+ }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
3854138562
assert( n==1 && aLock[ofst]>1 );
3854238563
aLock[ofst]--;
3854338564
}
3854438565
3854538566
/* Undo the local locks */
@@ -38568,11 +38589,11 @@
3856838589
/* Make sure no sibling connections hold locks that will block this
3856938590
** lock. If any do, return SQLITE_BUSY right away. */
3857038591
int ii;
3857138592
for(ii=ofst; ii<ofst+n; ii++){
3857238593
assert( (p->sharedMask & mask)==0 );
38573
- if( (p->exclMask & (1<<ii))==0 && aLock[ii] ){
38594
+ if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
3857438595
rc = SQLITE_BUSY;
3857538596
break;
3857638597
}
3857738598
}
3857838599
@@ -39964,19 +39985,39 @@
3996439985
}
3996539986
return SQLITE_OK;
3996639987
}
3996739988
3996839989
/*
39990
+** If the last component of the pathname in z[0]..z[j-1] is something
39991
+** other than ".." then back it out and return true. If the last
39992
+** component is empty or if it is ".." then return false.
39993
+*/
39994
+static int unixBackupDir(const char *z, int *pJ){
39995
+ int j = *pJ;
39996
+ int i;
39997
+ if( j<=0 ) return 0;
39998
+ for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){}
39999
+ if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
40000
+ *pJ = i-1;
40001
+ return 1;
40002
+}
40003
+
40004
+/*
40005
+** Convert a relative pathname into a full pathname. Also
40006
+** simplify the pathname as follows:
3996940007
**
40008
+** Remove all instances of /./
40009
+** Remove all isntances of /X/../ for any X
3997040010
*/
3997140011
static int mkFullPathname(
3997240012
const char *zPath, /* Input path */
3997340013
char *zOut, /* Output buffer */
3997440014
int nOut /* Allocated size of buffer zOut */
3997540015
){
3997640016
int nPath = sqlite3Strlen30(zPath);
3997740017
int iOff = 0;
40018
+ int i, j;
3997840019
if( zPath[0]!='/' ){
3997940020
if( osGetcwd(zOut, nOut-2)==0 ){
3998040021
return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
3998140022
}
3998240023
iOff = sqlite3Strlen30(zOut);
@@ -39987,10 +40028,45 @@
3998740028
** even if it returns an error. */
3998840029
zOut[iOff] = '\0';
3998940030
return SQLITE_CANTOPEN_BKPT;
3999040031
}
3999140032
sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
40033
+
40034
+ /* Remove duplicate '/' characters. Except, two // at the beginning
40035
+ ** of a pathname is allowed since this is important on windows. */
40036
+ for(i=j=1; zOut[i]; i++){
40037
+ zOut[j++] = zOut[i];
40038
+ while( zOut[i]=='/' && zOut[i+1]=='/' ) i++;
40039
+ }
40040
+ zOut[j] = 0;
40041
+
40042
+ assert( zOut[0]=='/' );
40043
+ for(i=j=0; zOut[i]; i++){
40044
+ if( zOut[i]=='/' ){
40045
+ /* Skip over internal "/." directory components */
40046
+ if( zOut[i+1]=='.' && zOut[i+2]=='/' ){
40047
+ i += 1;
40048
+ continue;
40049
+ }
40050
+
40051
+ /* If this is a "/.." directory component then back out the
40052
+ ** previous term of the directory if it is something other than "..".
40053
+ */
40054
+ if( zOut[i+1]=='.'
40055
+ && zOut[i+2]=='.'
40056
+ && zOut[i+3]=='/'
40057
+ && unixBackupDir(zOut, &j)
40058
+ ){
40059
+ i += 2;
40060
+ continue;
40061
+ }
40062
+ }
40063
+ if( ALWAYS(j>=0) ) zOut[j] = zOut[i];
40064
+ j++;
40065
+ }
40066
+ if( NEVER(j==0) ) zOut[j++] = '/';
40067
+ zOut[j] = 0;
3999240068
return SQLITE_OK;
3999340069
}
3999440070
3999540071
/*
3999640072
** Turn a relative pathname into a full pathname. The relative path
@@ -54326,10 +54402,11 @@
5432654402
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
5432754403
char *zSuperJournal = 0; /* Contents of super-journal file */
5432854404
i64 nSuperJournal; /* Size of super-journal file */
5432954405
char *zJournal; /* Pointer to one journal within MJ file */
5433054406
char *zSuperPtr; /* Space to hold super-journal filename */
54407
+ char *zFree = 0; /* Free this buffer */
5433154408
int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
5433254409
5433354410
/* Allocate space for both the pJournal and pSuper file descriptors.
5433454411
** If successful, open the super-journal file for reading.
5433554412
*/
@@ -54350,15 +54427,17 @@
5435054427
** files extracted from regular rollback-journals.
5435154428
*/
5435254429
rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
5435354430
if( rc!=SQLITE_OK ) goto delsuper_out;
5435454431
nSuperPtr = pVfs->mxPathname+1;
54355
- zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2);
54356
- if( !zSuperJournal ){
54432
+ zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
54433
+ if( !zFree ){
5435754434
rc = SQLITE_NOMEM_BKPT;
5435854435
goto delsuper_out;
5435954436
}
54437
+ zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
54438
+ zSuperJournal = &zFree[4];
5436054439
zSuperPtr = &zSuperJournal[nSuperJournal+2];
5436154440
rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
5436254441
if( rc!=SQLITE_OK ) goto delsuper_out;
5436354442
zSuperJournal[nSuperJournal] = 0;
5436454443
zSuperJournal[nSuperJournal+1] = 0;
@@ -54402,11 +54481,11 @@
5440254481
5440354482
sqlite3OsClose(pSuper);
5440454483
rc = sqlite3OsDelete(pVfs, zSuper, 0);
5440554484
5440654485
delsuper_out:
54407
- sqlite3_free(zSuperJournal);
54486
+ sqlite3_free(zFree);
5440854487
if( pSuper ){
5440954488
sqlite3OsClose(pSuper);
5441054489
assert( !isOpen(pJournal) );
5441154490
sqlite3_free(pSuper);
5441254491
}
@@ -54740,11 +54819,15 @@
5474054819
** in case this has happened, clear the changeCountDone flag now.
5474154820
*/
5474254821
pPager->changeCountDone = pPager->tempFile;
5474354822
5474454823
if( rc==SQLITE_OK ){
54745
- zSuper = pPager->pTmpSpace;
54824
+ /* Leave 4 bytes of space before the super-journal filename in memory.
54825
+ ** This is because it may end up being passed to sqlite3OsOpen(), in
54826
+ ** which case it requires 4 0x00 bytes in memory immediately before
54827
+ ** the filename. */
54828
+ zSuper = &pPager->pTmpSpace[4];
5474654829
rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
5474754830
testcase( rc!=SQLITE_OK );
5474854831
}
5474954832
if( rc==SQLITE_OK
5475054833
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -54757,10 +54840,12 @@
5475754840
}
5475854841
if( rc==SQLITE_OK && zSuper[0] && res ){
5475954842
/* If there was a super-journal and this routine will return success,
5476054843
** see if it is possible to delete the super-journal.
5476154844
*/
54845
+ assert( zSuper==&pPager->pTmpSpace[4] );
54846
+ memset(&zSuper[-4], 0, 4);
5476254847
rc = pager_delsuper(pPager, zSuper);
5476354848
testcase( rc!=SQLITE_OK );
5476454849
}
5476554850
if( isHot && nPlayback ){
5476654851
sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
@@ -64746,11 +64831,11 @@
6474664831
#define hasReadConflicts(a, b) 0
6474764832
#endif
6474864833
6474964834
#ifdef SQLITE_DEBUG
6475064835
/*
64751
-** Return an reset the seek counter for a Btree object.
64836
+** Return and reset the seek counter for a Btree object.
6475264837
*/
6475364838
SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
6475464839
u64 n = pBt->nSeek;
6475564840
pBt->nSeek = 0;
6475664841
return n;
@@ -82192,13 +82277,16 @@
8219282277
** equal to, or greater than the second (double).
8219382278
*/
8219482279
static int sqlite3IntFloatCompare(i64 i, double r){
8219582280
if( sizeof(LONGDOUBLE_TYPE)>8 ){
8219682281
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
82282
+ testcase( x<r );
82283
+ testcase( x>r );
82284
+ testcase( x==r );
8219782285
if( x<r ) return -1;
82198
- if( x>r ) return +1;
82199
- return 0;
82286
+ if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
82287
+ return 0; /*NO_TEST*/ /* work around bugs in gcov */
8220082288
}else{
8220182289
i64 y;
8220282290
double s;
8220382291
if( r<-9223372036854775808.0 ) return +1;
8220482292
if( r>=9223372036854775808.0 ) return -1;
@@ -89388,11 +89476,11 @@
8938889476
assert( rc==SQLITE_OK );
8938989477
break;
8939089478
}
8939189479
8939289480
89393
-/* Opcode: OpenEphemeral P1 P2 * P4 P5
89481
+/* Opcode: OpenEphemeral P1 P2 P3 P4 P5
8939489482
** Synopsis: nColumn=P2
8939589483
**
8939689484
** Open a new cursor P1 to a transient table.
8939789485
** The cursor is always opened read/write even if
8939889486
** the main database is read-only. The ephemeral
@@ -89408,10 +89496,14 @@
8940889496
**
8940989497
** The P5 parameter can be a mask of the BTREE_* flags defined
8941089498
** in btree.h. These flags control aspects of the operation of
8941189499
** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are
8941289500
** added automatically.
89501
+**
89502
+** If P3 is positive, then reg[P3] is modified slightly so that it
89503
+** can be used as zero-length data for OP_Insert. This is an optimization
89504
+** that avoids an extra OP_Blob opcode to initialize that register.
8941389505
*/
8941489506
/* Opcode: OpenAutoindex P1 P2 * P4 *
8941589507
** Synopsis: nColumn=P2
8941689508
**
8941789509
** This opcode works the same as OP_OpenEphemeral. It has a
@@ -89430,10 +89522,19 @@
8943089522
SQLITE_OPEN_EXCLUSIVE |
8943189523
SQLITE_OPEN_DELETEONCLOSE |
8943289524
SQLITE_OPEN_TRANSIENT_DB;
8943389525
assert( pOp->p1>=0 );
8943489526
assert( pOp->p2>=0 );
89527
+ if( pOp->p3>0 ){
89528
+ /* Make register reg[P3] into a value that can be used as the data
89529
+ ** form sqlite3BtreeInsert() where the length of the data is zero. */
89530
+ assert( pOp->p2==0 ); /* Only used when number of columns is zero */
89531
+ assert( pOp->opcode==OP_OpenEphemeral );
89532
+ assert( aMem[pOp->p3].flags & MEM_Null );
89533
+ aMem[pOp->p3].n = 0;
89534
+ aMem[pOp->p3].z = "";
89535
+ }
8943589536
pCx = p->apCsr[pOp->p1];
8943689537
if( pCx && pCx->pBtx ){
8943789538
/* If the ephermeral table is already open, erase all existing content
8943889539
** so that the table is empty again, rather than creating a new table. */
8943989540
assert( pCx->isEphemeral );
@@ -90589,11 +90690,11 @@
9058990690
if( pOp->p5 & OPFLAG_ISNOOP ) break;
9059090691
#endif
9059190692
9059290693
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
9059390694
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
90594
- assert( pData->flags & (MEM_Blob|MEM_Str) );
90695
+ assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 );
9059590696
x.pData = pData->z;
9059690697
x.nData = pData->n;
9059790698
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
9059890699
if( pData->flags & MEM_Zero ){
9059990700
x.nZero = pData->u.nZero;
@@ -93644,11 +93745,15 @@
9364493745
9364593746
/* If we reach this point, it means that execution is finished with
9364693747
** an error of some kind.
9364793748
*/
9364893749
abort_due_to_error:
93649
- if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
93750
+ if( db->mallocFailed ){
93751
+ rc = SQLITE_NOMEM_BKPT;
93752
+ }else if( rc==SQLITE_IOERR_CORRUPTFS ){
93753
+ rc = SQLITE_CORRUPT_BKPT;
93754
+ }
9365093755
assert( rc );
9365193756
if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
9365293757
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
9365393758
}
9365493759
p->rc = rc;
@@ -99381,10 +99486,11 @@
9938199486
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
9938299487
int iCol = -1;
9938399488
Expr *pE, *pDup;
9938499489
if( pItem->done ) continue;
9938599490
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
99491
+ if( NEVER(pE==0) ) continue;
9938699492
if( sqlite3ExprIsInteger(pE, &iCol) ){
9938799493
if( iCol<=0 || iCol>pEList->nExpr ){
9938899494
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
9938999495
return 1;
9939099496
}
@@ -99560,10 +99666,11 @@
9956099666
nResult = pSelect->pEList->nExpr;
9956199667
pParse = pNC->pParse;
9956299668
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
9956399669
Expr *pE = pItem->pExpr;
9956499670
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
99671
+ if( NEVER(pE2==0) ) continue;
9956599672
if( zType[0]!='G' ){
9956699673
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
9956799674
if( iCol>0 ){
9956899675
/* If an AS-name match is found, mark this ORDER BY column as being
9956999676
** a copy of the iCol-th result-set column. The subsequent call to
@@ -103679,10 +103786,11 @@
103679103786
** register iReg. The caller must ensure that iReg already contains
103680103787
** the correct value for the expression.
103681103788
*/
103682103789
static void exprToRegister(Expr *pExpr, int iReg){
103683103790
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
103791
+ if( NEVER(p==0) ) return;
103684103792
p->op2 = p->op;
103685103793
p->op = TK_REGISTER;
103686103794
p->iTable = iReg;
103687103795
ExprClearProperty(p, EP_Skip);
103688103796
}
@@ -104666,10 +104774,11 @@
104666104774
*/
104667104775
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
104668104776
int r2;
104669104777
pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
104670104778
if( ConstFactorOk(pParse)
104779
+ && ALWAYS(pExpr!=0)
104671104780
&& pExpr->op!=TK_REGISTER
104672104781
&& sqlite3ExprIsConstantNotJoin(pExpr)
104673104782
){
104674104783
*pReg = 0;
104675104784
r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -119424,10 +119533,12 @@
119424119533
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
119425119534
FUNCTION(replace, 3, 0, 0, replaceFunc ),
119426119535
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
119427119536
FUNCTION(substr, 2, 0, 0, substrFunc ),
119428119537
FUNCTION(substr, 3, 0, 0, substrFunc ),
119538
+ FUNCTION(substring, 2, 0, 0, substrFunc ),
119539
+ FUNCTION(substring, 3, 0, 0, substrFunc ),
119429119540
WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
119430119541
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
119431119542
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
119432119543
WAGGREGATE(count, 0,0,0, countStep,
119433119544
countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
@@ -124310,10 +124421,12 @@
124310124421
/* Version 3.32.0 and later */
124311124422
char *(*create_filename)(const char*,const char*,const char*,
124312124423
int,const char**);
124313124424
void (*free_filename)(char*);
124314124425
sqlite3_file *(*database_file_object)(const char*);
124426
+ /* Version 3.34.0 and later */
124427
+ int (*txn_state)(sqlite3*,const char*);
124315124428
};
124316124429
124317124430
/*
124318124431
** This is the function signature used for all extension entry points. It
124319124432
** is also defined in the file "loadext.c".
@@ -124614,10 +124727,12 @@
124614124727
#define sqlite3_filename_wal sqlite3_api->filename_wal
124615124728
/* Version 3.32.0 and later */
124616124729
#define sqlite3_create_filename sqlite3_api->create_filename
124617124730
#define sqlite3_free_filename sqlite3_api->free_filename
124618124731
#define sqlite3_database_file_object sqlite3_api->database_file_object
124732
+/* Version 3.34.0 and later */
124733
+#define sqlite3_txn_state sqlite3_api->txn_state
124619124734
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
124620124735
124621124736
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
124622124737
/* This case when the file really is being compiled as a loadable
124623124738
** extension */
@@ -125096,10 +125211,12 @@
125096125211
sqlite3_filename_wal,
125097125212
/* Version 3.32.0 and later */
125098125213
sqlite3_create_filename,
125099125214
sqlite3_free_filename,
125100125215
sqlite3_database_file_object,
125216
+ /* Version 3.34.0 and later */
125217
+ sqlite3_txn_state,
125101125218
};
125102125219
125103125220
/* True if x is the directory separator character
125104125221
*/
125105125222
#if SQLITE_OS_WIN
@@ -131654,10 +131771,11 @@
131654131771
Column *aCol, *pCol; /* For looping over result columns */
131655131772
int nCol; /* Number of columns in the result set */
131656131773
char *zName; /* Column name */
131657131774
int nName; /* Size of name in zName[] */
131658131775
Hash ht; /* Hash table of column names */
131776
+ Table *pTab;
131659131777
131660131778
sqlite3HashInit(&ht);
131661131779
if( pEList ){
131662131780
nCol = pEList->nExpr;
131663131781
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
@@ -131676,19 +131794,17 @@
131676131794
*/
131677131795
if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
131678131796
/* If the column contains an "AS <name>" phrase, use <name> as the name */
131679131797
}else{
131680131798
Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
131681
- while( pColExpr->op==TK_DOT ){
131799
+ while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){
131682131800
pColExpr = pColExpr->pRight;
131683131801
assert( pColExpr!=0 );
131684131802
}
131685
- if( pColExpr->op==TK_COLUMN ){
131803
+ if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->y.pTab)!=0 ){
131686131804
/* For columns use the column name name */
131687131805
int iCol = pColExpr->iColumn;
131688
- Table *pTab = pColExpr->y.pTab;
131689
- assert( pTab!=0 );
131690131806
if( iCol<0 ) iCol = pTab->iPKey;
131691131807
zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
131692131808
}else if( pColExpr->op==TK_ID ){
131693131809
assert( !ExprHasProperty(pColExpr, EP_IntValue) );
131694131810
zName = pColExpr->u.zToken;
@@ -136959,26 +137075,15 @@
136959137075
goto trigger_cleanup;
136960137076
}
136961137077
pTab = sqlite3SrcListLookup(pParse, pTableName);
136962137078
if( !pTab ){
136963137079
/* The table does not exist. */
136964
- if( db->init.iDb==1 ){
136965
- /* Ticket #3810.
136966
- ** Normally, whenever a table is dropped, all associated triggers are
136967
- ** dropped too. But if a TEMP trigger is created on a non-TEMP table
136968
- ** and the table is dropped by a different database connection, the
136969
- ** trigger is not visible to the database connection that does the
136970
- ** drop so the trigger cannot be dropped. This results in an
136971
- ** "orphaned trigger" - a trigger whose associated table is missing.
136972
- */
136973
- db->init.orphanTrigger = 1;
136974
- }
136975
- goto trigger_cleanup;
137080
+ goto trigger_orphan_error;
136976137081
}
136977137082
if( IsVirtual(pTab) ){
136978137083
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
136979
- goto trigger_cleanup;
137084
+ goto trigger_orphan_error;
136980137085
}
136981137086
136982137087
/* Check that the trigger name is not reserved and that no trigger of the
136983137088
** specified name exists */
136984137089
zName = sqlite3NameFromToken(db, pName);
@@ -137012,16 +137117,16 @@
137012137117
** of triggers.
137013137118
*/
137014137119
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
137015137120
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
137016137121
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
137017
- goto trigger_cleanup;
137122
+ goto trigger_orphan_error;
137018137123
}
137019137124
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
137020137125
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
137021137126
" trigger on table: %S", pTableName, 0);
137022
- goto trigger_cleanup;
137127
+ goto trigger_orphan_error;
137023137128
}
137024137129
137025137130
#ifndef SQLITE_OMIT_AUTHORIZATION
137026137131
if( !IN_RENAME_OBJECT ){
137027137132
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -137077,10 +137182,27 @@
137077137182
if( !pParse->pNewTrigger ){
137078137183
sqlite3DeleteTrigger(db, pTrigger);
137079137184
}else{
137080137185
assert( pParse->pNewTrigger==pTrigger );
137081137186
}
137187
+ return;
137188
+
137189
+trigger_orphan_error:
137190
+ if( db->init.iDb==1 ){
137191
+ /* Ticket #3810.
137192
+ ** Normally, whenever a table is dropped, all associated triggers are
137193
+ ** dropped too. But if a TEMP trigger is created on a non-TEMP table
137194
+ ** and the table is dropped by a different database connection, the
137195
+ ** trigger is not visible to the database connection that does the
137196
+ ** drop so the trigger cannot be dropped. This results in an
137197
+ ** "orphaned trigger" - a trigger whose associated table is missing.
137198
+ **
137199
+ ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df
137200
+ */
137201
+ db->init.orphanTrigger = 1;
137202
+ }
137203
+ goto trigger_cleanup;
137082137204
}
137083137205
137084137206
/*
137085137207
** This routine is called after all of the trigger actions have been parsed
137086137208
** in order to complete the process of building the trigger.
@@ -138664,10 +138786,12 @@
138664138786
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
138665138787
}
138666138788
138667138789
if( nChangeFrom==0 && HasRowid(pTab) ){
138668138790
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
138791
+ iEph = pParse->nTab++;
138792
+ addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet);
138669138793
}else{
138670138794
assert( pPk!=0 || HasRowid(pTab) );
138671138795
nPk = pPk ? pPk->nKeyCol : 0;
138672138796
iPk = pParse->nMem+1;
138673138797
pParse->nMem += nPk;
@@ -138755,13 +138879,14 @@
138755138879
/* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
138756138880
** mode, write the rowid into the FIFO. In either of the one-pass modes,
138757138881
** leave it in register regOldRowid. */
138758138882
sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
138759138883
if( eOnePass==ONEPASS_OFF ){
138760
- /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
138761138884
aRegIdx[nAllIdx] = ++pParse->nMem;
138762
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
138885
+ sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid);
138886
+ }else{
138887
+ if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen);
138763138888
}
138764138889
}else{
138765138890
/* Read the PK of the current row into an array of registers. In
138766138891
** ONEPASS_OFF mode, serialize the array into a record and store it in
138767138892
** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
@@ -138845,12 +138970,13 @@
138845138970
sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
138846138971
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0);
138847138972
VdbeCoverage(v);
138848138973
}
138849138974
}else{
138850
- labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
138851
- regOldRowid);
138975
+ sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
138976
+ labelContinue = sqlite3VdbeMakeLabel(pParse);
138977
+ addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
138852138978
VdbeCoverage(v);
138853138979
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
138854138980
VdbeCoverage(v);
138855138981
}
138856138982
}
@@ -139096,15 +139222,13 @@
139096139222
if( eOnePass==ONEPASS_SINGLE ){
139097139223
/* Nothing to do at end-of-loop for a single-pass */
139098139224
}else if( eOnePass==ONEPASS_MULTI ){
139099139225
sqlite3VdbeResolveLabel(v, labelContinue);
139100139226
sqlite3WhereEnd(pWInfo);
139101
- }else if( pPk || nChangeFrom ){
139227
+ }else{
139102139228
sqlite3VdbeResolveLabel(v, labelContinue);
139103139229
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
139104
- }else{
139105
- sqlite3VdbeGoto(v, labelContinue);
139106139230
}
139107139231
sqlite3VdbeResolveLabel(v, labelBreak);
139108139232
139109139233
/* Update the sqlite_sequence table by storing the content of the
139110139234
** maximum rowid counter values recorded while inserting into
@@ -145894,10 +146018,11 @@
145894146018
** all terms of the WHERE clause.
145895146019
*/
145896146020
SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
145897146021
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr);
145898146022
pWC->op = op;
146023
+ assert( pE2!=0 || pExpr==0 );
145899146024
if( pE2==0 ) return;
145900146025
if( pE2->op!=op ){
145901146026
whereClauseInsert(pWC, pExpr, 0);
145902146027
}else{
145903146028
sqlite3WhereSplit(pWC, pE2->pLeft, op);
@@ -146292,10 +146417,20 @@
146292146417
*/
146293146418
static void createMask(WhereMaskSet *pMaskSet, int iCursor){
146294146419
assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
146295146420
pMaskSet->ix[pMaskSet->n++] = iCursor;
146296146421
}
146422
+
146423
+/*
146424
+** If the right-hand branch of the expression is a TK_COLUMN, then return
146425
+** a pointer to the right-hand branch. Otherwise, return NULL.
146426
+*/
146427
+static Expr *whereRightSubexprIsColumn(Expr *p){
146428
+ p = sqlite3ExprSkipCollateAndLikely(p->pRight);
146429
+ if( ALWAYS(p!=0) && p->op==TK_COLUMN ) return p;
146430
+ return 0;
146431
+}
146297146432
146298146433
/*
146299146434
** Advance to the next WhereTerm that matches according to the criteria
146300146435
** established when the pScan object was initialized by whereScanInit().
146301146436
** Return NULL if there are no more matching WhereTerms.
@@ -146323,12 +146458,11 @@
146323146458
pScan->pIdxExpr,iCur)==0)
146324146459
&& (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
146325146460
){
146326146461
if( (pTerm->eOperator & WO_EQUIV)!=0
146327146462
&& pScan->nEquiv<ArraySize(pScan->aiCur)
146328
- && (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op
146329
- ==TK_COLUMN
146463
+ && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0
146330146464
){
146331146465
int j;
146332146466
for(j=0; j<pScan->nEquiv; j++){
146333146467
if( pScan->aiCur[j]==pX->iTable
146334146468
&& pScan->aiColumn[j]==pX->iColumn ){
@@ -146520,11 +146654,12 @@
146520146654
int i;
146521146655
const char *zColl = pIdx->azColl[iCol];
146522146656
146523146657
for(i=0; i<pList->nExpr; i++){
146524146658
Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr);
146525
- if( p->op==TK_COLUMN
146659
+ if( ALWAYS(p!=0)
146660
+ && p->op==TK_COLUMN
146526146661
&& p->iColumn==pIdx->aiColumn[iCol]
146527146662
&& p->iTable==iBase
146528146663
){
146529146664
CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
146530146665
if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
@@ -146584,10 +146719,11 @@
146584146719
** true. Note: The (p->iTable==iBase) part of this test may be false if the
146585146720
** current SELECT is a correlated sub-query.
146586146721
*/
146587146722
for(i=0; i<pDistinct->nExpr; i++){
146588146723
Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr);
146724
+ if( NEVER(p==0) ) continue;
146589146725
if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
146590146726
}
146591146727
146592146728
/* Loop through all indices on the table, checking each to see if it makes
146593146729
** the DISTINCT qualifier redundant. It does so if:
@@ -148498,13 +148634,13 @@
148498148634
LogEst rLogSize; /* Logarithm of table size */
148499148635
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
148500148636
148501148637
pNew = pBuilder->pNew;
148502148638
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
148503
- WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n",
148639
+ WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n",
148504148640
pProbe->pTable->zName,pProbe->zName,
148505
- pNew->u.btree.nEq, pNew->nSkip));
148641
+ pNew->u.btree.nEq, pNew->nSkip, pNew->rRun));
148506148642
148507148643
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
148508148644
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
148509148645
if( pNew->wsFlags & WHERE_BTM_LIMIT ){
148510148646
opMask = WO_LT|WO_LE;
@@ -148869,10 +149005,11 @@
148869149005
148870149006
if( pIndex->bUnordered ) return 0;
148871149007
if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
148872149008
for(ii=0; ii<pOB->nExpr; ii++){
148873149009
Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
149010
+ if( NEVER(pExpr==0) ) continue;
148874149011
if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
148875149012
if( pExpr->iColumn<0 ) return 1;
148876149013
for(jj=0; jj<pIndex->nKeyCol; jj++){
148877149014
if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
148878149015
}
@@ -149847,10 +149984,11 @@
149847149984
** loops.
149848149985
*/
149849149986
for(i=0; i<nOrderBy; i++){
149850149987
if( MASKBIT(i) & obSat ) continue;
149851149988
pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
149989
+ if( NEVER(pOBExpr==0) ) continue;
149852149990
if( pOBExpr->op!=TK_COLUMN ) continue;
149853149991
if( pOBExpr->iTable!=iCur ) continue;
149854149992
pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
149855149993
~ready, eqOpMask, 0);
149856149994
if( pTerm==0 ) continue;
@@ -149973,10 +150111,11 @@
149973150111
for(i=0; bOnce && i<nOrderBy; i++){
149974150112
if( MASKBIT(i) & obSat ) continue;
149975150113
pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
149976150114
testcase( wctrlFlags & WHERE_GROUPBY );
149977150115
testcase( wctrlFlags & WHERE_DISTINCTBY );
150116
+ if( NEVER(pOBExpr==0) ) continue;
149978150117
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
149979150118
if( iColumn>=XN_ROWID ){
149980150119
if( pOBExpr->op!=TK_COLUMN ) continue;
149981150120
if( pOBExpr->iTable!=iCur ) continue;
149982150121
if( pOBExpr->iColumn!=iColumn ) continue;
@@ -150136,11 +150275,11 @@
150136150275
rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
150137150276
rSortCost = nRow + rScale + 16;
150138150277
150139150278
/* Multiple by log(M) where M is the number of output rows.
150140150279
** Use the LIMIT for M if it is smaller. Or if this sort is for
150141
- ** a DISTINT operator, M will be the number of distinct output
150280
+ ** a DISTINCT operator, M will be the number of distinct output
150142150281
** rows, so fudge it downwards a bit.
150143150282
*/
150144150283
if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
150145150284
nRow = pWInfo->iLimit;
150146150285
}else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){
@@ -194220,11 +194359,11 @@
194220194359
p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2];
194221194360
p->nEvent = p->nSegment = 0;
194222194361
geopolyAddSegments(p, p1, 1);
194223194362
geopolyAddSegments(p, p2, 2);
194224194363
pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
194225
- rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
194364
+ rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0;
194226194365
memset(aOverlap, 0, sizeof(aOverlap));
194227194366
while( pThisEvent ){
194228194367
if( pThisEvent->x!=rX ){
194229194368
GeoSegment *pPrev = 0;
194230194369
int iMask = 0;
@@ -212129,11 +212268,11 @@
212129212268
Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */
212130212269
){
212131212270
int rc = SQLITE_OK; /* Return code */
212132212271
Fts5Bm25Data *p; /* Object to return */
212133212272
212134
- p = pApi->xGetAuxdata(pFts, 0);
212273
+ p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0);
212135212274
if( p==0 ){
212136212275
int nPhrase; /* Number of phrases in query */
212137212276
sqlite3_int64 nRow = 0; /* Number of rows in table */
212138212277
sqlite3_int64 nToken = 0; /* Number of tokens in table */
212139212278
sqlite3_int64 nByte; /* Bytes of space to allocate */
@@ -212203,11 +212342,11 @@
212203212342
int nVal, /* Number of values in apVal[] array */
212204212343
sqlite3_value **apVal /* Array of trailing arguments */
212205212344
){
212206212345
const double k1 = 1.2; /* Constant "k1" from BM25 formula */
212207212346
const double b = 0.75; /* Constant "b" from BM25 formula */
212208
- int rc = SQLITE_OK; /* Error code */
212347
+ int rc; /* Error code */
212209212348
double score = 0.0; /* SQL function return value */
212210212349
Fts5Bm25Data *pData; /* Values allocated/calculated once only */
212211212350
int i; /* Iterator variable */
212212212351
int nInst = 0; /* Value returned by xInstCount() */
212213212352
double D = 0.0; /* Total number of tokens in row */
@@ -212235,21 +212374,19 @@
212235212374
int nTok;
212236212375
rc = pApi->xColumnSize(pFts, -1, &nTok);
212237212376
D = (double)nTok;
212238212377
}
212239212378
212240
- /* Determine the BM25 score for the current row. */
212241
- for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
212242
- score += pData->aIDF[i] * (
212243
- ( aFreq[i] * (k1 + 1.0) ) /
212244
- ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
212245
- );
212246
- }
212247
-
212248
- /* If no error has occurred, return the calculated score. Otherwise,
212249
- ** throw an SQL exception. */
212379
+ /* Determine and return the BM25 score for the current row. Or, if an
212380
+ ** error has occurred, throw an exception. */
212250212381
if( rc==SQLITE_OK ){
212382
+ for(i=0; i<pData->nPhrase; i++){
212383
+ score += pData->aIDF[i] * (
212384
+ ( aFreq[i] * (k1 + 1.0) ) /
212385
+ ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
212386
+ );
212387
+ }
212251212388
sqlite3_result_double(pCtx, -1.0 * score);
212252212389
}else{
212253212390
sqlite3_result_error_code(pCtx, rc);
212254212391
}
212255212392
}
@@ -223384,10 +223521,11 @@
223384223521
cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
223385223522
}
223386223523
}else{
223387223524
poslist.n = 0;
223388223525
fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
223526
+ fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0");
223389223527
while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
223390223528
int iCol = FTS5_POS2COLUMN(iPos);
223391223529
int iTokOff = FTS5_POS2OFFSET(iPos);
223392223530
cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
223393223531
}
@@ -226679,11 +226817,11 @@
226679226817
int nArg, /* Number of args */
226680226818
sqlite3_value **apUnused /* Function arguments */
226681226819
){
226682226820
assert( nArg==0 );
226683226821
UNUSED_PARAM2(nArg, apUnused);
226684
- sqlite3_result_text(pCtx, "fts5: 2020-10-26 16:22:31 80eba105d6d1b49ba8ca2ad4e14ddec2de0bdc2f6686c2f8a1c1d24fc1fe846f", -1, SQLITE_TRANSIENT);
226822
+ sqlite3_result_text(pCtx, "fts5: 2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b", -1, SQLITE_TRANSIENT);
226685226823
}
226686226824
226687226825
/*
226688226826
** Return true if zName is the extension on one of the shadow tables used
226689226827
** by this module.
@@ -229252,17 +229390,18 @@
229252229390
229253229391
/*
229254229392
** Allocate a trigram tokenizer.
229255229393
*/
229256229394
static int fts5TriCreate(
229257
- void *pCtx,
229395
+ void *pUnused,
229258229396
const char **azArg,
229259229397
int nArg,
229260229398
Fts5Tokenizer **ppOut
229261229399
){
229262229400
int rc = SQLITE_OK;
229263229401
TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
229402
+ UNUSED_PARAM(pUnused);
229264229403
if( pNew==0 ){
229265229404
rc = SQLITE_NOMEM;
229266229405
}else{
229267229406
int i;
229268229407
pNew->bFold = 1;
@@ -229291,11 +229430,11 @@
229291229430
** Trigram tokenizer tokenize routine.
229292229431
*/
229293229432
static int fts5TriTokenize(
229294229433
Fts5Tokenizer *pTok,
229295229434
void *pCtx,
229296
- int flags,
229435
+ int unusedFlags,
229297229436
const char *pText, int nText,
229298229437
int (*xToken)(void*, int, const char*, int, int, int)
229299229438
){
229300229439
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
229301229440
int rc = SQLITE_OK;
@@ -229302,10 +229441,11 @@
229302229441
char aBuf[32];
229303229442
const unsigned char *zIn = (const unsigned char*)pText;
229304229443
const unsigned char *zEof = &zIn[nText];
229305229444
u32 iCode;
229306229445
229446
+ UNUSED_PARAM(unusedFlags);
229307229447
while( 1 ){
229308229448
char *zOut = aBuf;
229309229449
int iStart = zIn - (const unsigned char*)pText;
229310229450
const unsigned char *zNext;
229311229451
@@ -230164,10 +230304,11 @@
230164230304
}
230165230305
iTbl++;
230166230306
}
230167230307
aAscii[0] = 0; /* 0x00 is never a token character */
230168230308
}
230309
+
230169230310
230170230311
/*
230171230312
** 2015 May 30
230172230313
**
230173230314
** The author disclaims copyright to this source code. In place of
@@ -231602,12 +231743,12 @@
231602231743
}
231603231744
#endif /* SQLITE_CORE */
231604231745
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
231605231746
231606231747
/************** End of stmt.c ************************************************/
231607
-#if __LINE__!=231607
231748
+#if __LINE__!=231748
231608231749
#undef SQLITE_SOURCE_ID
231609
-#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692alt2"
231750
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089falt2"
231610231751
#endif
231611231752
/* Return the source-id for this library */
231612231753
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
231613231754
/************************** End of sqlite3.c ******************************/
231614231755
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1171,11 +1171,11 @@
1171 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1172 ** [sqlite_version()] and [sqlite_source_id()].
1173 */
1174 #define SQLITE_VERSION "3.34.0"
1175 #define SQLITE_VERSION_NUMBER 3034000
1176 #define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
1177
1178 /*
1179 ** CAPI3REF: Run-Time Library Version Numbers
1180 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1181 **
@@ -1550,10 +1550,11 @@
1550 #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
1551 #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
1552 #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
1553 #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
1554 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
 
1555 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
1556 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
1557 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
1558 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
1559 #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
@@ -7238,11 +7239,11 @@
7238 ** CAPI3REF: Determine the transaction state of a database
7239 ** METHOD: sqlite3
7240 **
7241 ** ^The sqlite3_txn_state(D,S) interface returns the current
7242 ** [transaction state] of schema S in database connection D. ^If S is NULL,
7243 ** then the highest transaction state of any schema on databse connection D
7244 ** is returned. Transaction states are (in order of lowest to highest):
7245 ** <ol>
7246 ** <li value="0"> SQLITE_TXN_NONE
7247 ** <li value="1"> SQLITE_TXN_READ
7248 ** <li value="2"> SQLITE_TXN_WRITE
@@ -8785,11 +8786,10 @@
8785 */
8786 #define SQLITE_TESTCTRL_FIRST 5
8787 #define SQLITE_TESTCTRL_PRNG_SAVE 5
8788 #define SQLITE_TESTCTRL_PRNG_RESTORE 6
8789 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
8790 #define SQLITE_TESTCTRL_SEEK_COUNT 7
8791 #define SQLITE_TESTCTRL_BITVEC_TEST 8
8792 #define SQLITE_TESTCTRL_FAULT_INSTALL 9
8793 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
8794 #define SQLITE_TESTCTRL_PENDING_BYTE 11
8795 #define SQLITE_TESTCTRL_ASSERT 12
@@ -8810,11 +8810,12 @@
8810 #define SQLITE_TESTCTRL_IMPOSTER 25
8811 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26
8812 #define SQLITE_TESTCTRL_RESULT_INTREAL 27
8813 #define SQLITE_TESTCTRL_PRNG_SEED 28
8814 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8815 #define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
 
8816
8817 /*
8818 ** CAPI3REF: SQL Keyword Checking
8819 **
8820 ** These routines provide access to the set of SQL language keywords
@@ -28182,16 +28183,19 @@
28182 EnableLookaside;
28183 }
28184 }
28185
28186 /*
28187 ** Take actions at the end of an API call to indicate an OOM error
28188 */
28189 static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
28190 sqlite3OomClear(db);
28191 sqlite3Error(db, SQLITE_NOMEM);
28192 return SQLITE_NOMEM_BKPT;
 
 
 
28193 }
28194
28195 /*
28196 ** This function must be called before exiting any API function (i.e.
28197 ** returning control to the user) that has called sqlite3_malloc or
@@ -28209,12 +28213,12 @@
28209 ** Otherwise the read (and possible write) of db->mallocFailed
28210 ** is unsafe, as is the call to sqlite3Error().
28211 */
28212 assert( db!=0 );
28213 assert( sqlite3_mutex_held(db->mutex) );
28214 if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
28215 return apiOomError(db);
28216 }
28217 return rc & db->errMask;
28218 }
28219
28220 /************** End of malloc.c **********************************************/
@@ -37003,11 +37007,28 @@
37003
37004 got = seekAndRead(pFile, offset, pBuf, amt);
37005 if( got==amt ){
37006 return SQLITE_OK;
37007 }else if( got<0 ){
37008 /* lastErrno set by seekAndRead */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37009 return SQLITE_IOERR_READ;
37010 }else{
37011 storeLastErrno(pFile, 0); /* not a system error */
37012 /* Unread parts of the buffer must be zero-filled */
37013 memset(&((char*)pBuf)[got], 0, amt-got);
@@ -38535,11 +38556,11 @@
38535 if( bUnlock ){
38536 rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
38537 if( rc==SQLITE_OK ){
38538 memset(&aLock[ofst], 0, sizeof(int)*n);
38539 }
38540 }else if( p->sharedMask & (1<<ofst) ){
38541 assert( n==1 && aLock[ofst]>1 );
38542 aLock[ofst]--;
38543 }
38544
38545 /* Undo the local locks */
@@ -38568,11 +38589,11 @@
38568 /* Make sure no sibling connections hold locks that will block this
38569 ** lock. If any do, return SQLITE_BUSY right away. */
38570 int ii;
38571 for(ii=ofst; ii<ofst+n; ii++){
38572 assert( (p->sharedMask & mask)==0 );
38573 if( (p->exclMask & (1<<ii))==0 && aLock[ii] ){
38574 rc = SQLITE_BUSY;
38575 break;
38576 }
38577 }
38578
@@ -39964,19 +39985,39 @@
39964 }
39965 return SQLITE_OK;
39966 }
39967
39968 /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39969 **
 
 
39970 */
39971 static int mkFullPathname(
39972 const char *zPath, /* Input path */
39973 char *zOut, /* Output buffer */
39974 int nOut /* Allocated size of buffer zOut */
39975 ){
39976 int nPath = sqlite3Strlen30(zPath);
39977 int iOff = 0;
 
39978 if( zPath[0]!='/' ){
39979 if( osGetcwd(zOut, nOut-2)==0 ){
39980 return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
39981 }
39982 iOff = sqlite3Strlen30(zOut);
@@ -39987,10 +40028,45 @@
39987 ** even if it returns an error. */
39988 zOut[iOff] = '\0';
39989 return SQLITE_CANTOPEN_BKPT;
39990 }
39991 sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39992 return SQLITE_OK;
39993 }
39994
39995 /*
39996 ** Turn a relative pathname into a full pathname. The relative path
@@ -54326,10 +54402,11 @@
54326 sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
54327 char *zSuperJournal = 0; /* Contents of super-journal file */
54328 i64 nSuperJournal; /* Size of super-journal file */
54329 char *zJournal; /* Pointer to one journal within MJ file */
54330 char *zSuperPtr; /* Space to hold super-journal filename */
 
54331 int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
54332
54333 /* Allocate space for both the pJournal and pSuper file descriptors.
54334 ** If successful, open the super-journal file for reading.
54335 */
@@ -54350,15 +54427,17 @@
54350 ** files extracted from regular rollback-journals.
54351 */
54352 rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
54353 if( rc!=SQLITE_OK ) goto delsuper_out;
54354 nSuperPtr = pVfs->mxPathname+1;
54355 zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2);
54356 if( !zSuperJournal ){
54357 rc = SQLITE_NOMEM_BKPT;
54358 goto delsuper_out;
54359 }
 
 
54360 zSuperPtr = &zSuperJournal[nSuperJournal+2];
54361 rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
54362 if( rc!=SQLITE_OK ) goto delsuper_out;
54363 zSuperJournal[nSuperJournal] = 0;
54364 zSuperJournal[nSuperJournal+1] = 0;
@@ -54402,11 +54481,11 @@
54402
54403 sqlite3OsClose(pSuper);
54404 rc = sqlite3OsDelete(pVfs, zSuper, 0);
54405
54406 delsuper_out:
54407 sqlite3_free(zSuperJournal);
54408 if( pSuper ){
54409 sqlite3OsClose(pSuper);
54410 assert( !isOpen(pJournal) );
54411 sqlite3_free(pSuper);
54412 }
@@ -54740,11 +54819,15 @@
54740 ** in case this has happened, clear the changeCountDone flag now.
54741 */
54742 pPager->changeCountDone = pPager->tempFile;
54743
54744 if( rc==SQLITE_OK ){
54745 zSuper = pPager->pTmpSpace;
 
 
 
 
54746 rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
54747 testcase( rc!=SQLITE_OK );
54748 }
54749 if( rc==SQLITE_OK
54750 && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -54757,10 +54840,12 @@
54757 }
54758 if( rc==SQLITE_OK && zSuper[0] && res ){
54759 /* If there was a super-journal and this routine will return success,
54760 ** see if it is possible to delete the super-journal.
54761 */
 
 
54762 rc = pager_delsuper(pPager, zSuper);
54763 testcase( rc!=SQLITE_OK );
54764 }
54765 if( isHot && nPlayback ){
54766 sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
@@ -64746,11 +64831,11 @@
64746 #define hasReadConflicts(a, b) 0
64747 #endif
64748
64749 #ifdef SQLITE_DEBUG
64750 /*
64751 ** Return an reset the seek counter for a Btree object.
64752 */
64753 SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
64754 u64 n = pBt->nSeek;
64755 pBt->nSeek = 0;
64756 return n;
@@ -82192,13 +82277,16 @@
82192 ** equal to, or greater than the second (double).
82193 */
82194 static int sqlite3IntFloatCompare(i64 i, double r){
82195 if( sizeof(LONGDOUBLE_TYPE)>8 ){
82196 LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
 
 
 
82197 if( x<r ) return -1;
82198 if( x>r ) return +1;
82199 return 0;
82200 }else{
82201 i64 y;
82202 double s;
82203 if( r<-9223372036854775808.0 ) return +1;
82204 if( r>=9223372036854775808.0 ) return -1;
@@ -89388,11 +89476,11 @@
89388 assert( rc==SQLITE_OK );
89389 break;
89390 }
89391
89392
89393 /* Opcode: OpenEphemeral P1 P2 * P4 P5
89394 ** Synopsis: nColumn=P2
89395 **
89396 ** Open a new cursor P1 to a transient table.
89397 ** The cursor is always opened read/write even if
89398 ** the main database is read-only. The ephemeral
@@ -89408,10 +89496,14 @@
89408 **
89409 ** The P5 parameter can be a mask of the BTREE_* flags defined
89410 ** in btree.h. These flags control aspects of the operation of
89411 ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are
89412 ** added automatically.
 
 
 
 
89413 */
89414 /* Opcode: OpenAutoindex P1 P2 * P4 *
89415 ** Synopsis: nColumn=P2
89416 **
89417 ** This opcode works the same as OP_OpenEphemeral. It has a
@@ -89430,10 +89522,19 @@
89430 SQLITE_OPEN_EXCLUSIVE |
89431 SQLITE_OPEN_DELETEONCLOSE |
89432 SQLITE_OPEN_TRANSIENT_DB;
89433 assert( pOp->p1>=0 );
89434 assert( pOp->p2>=0 );
 
 
 
 
 
 
 
 
 
89435 pCx = p->apCsr[pOp->p1];
89436 if( pCx && pCx->pBtx ){
89437 /* If the ephermeral table is already open, erase all existing content
89438 ** so that the table is empty again, rather than creating a new table. */
89439 assert( pCx->isEphemeral );
@@ -90589,11 +90690,11 @@
90589 if( pOp->p5 & OPFLAG_ISNOOP ) break;
90590 #endif
90591
90592 if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
90593 if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
90594 assert( pData->flags & (MEM_Blob|MEM_Str) );
90595 x.pData = pData->z;
90596 x.nData = pData->n;
90597 seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
90598 if( pData->flags & MEM_Zero ){
90599 x.nZero = pData->u.nZero;
@@ -93644,11 +93745,15 @@
93644
93645 /* If we reach this point, it means that execution is finished with
93646 ** an error of some kind.
93647 */
93648 abort_due_to_error:
93649 if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
 
 
 
 
93650 assert( rc );
93651 if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
93652 sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
93653 }
93654 p->rc = rc;
@@ -99381,10 +99486,11 @@
99381 for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
99382 int iCol = -1;
99383 Expr *pE, *pDup;
99384 if( pItem->done ) continue;
99385 pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
 
99386 if( sqlite3ExprIsInteger(pE, &iCol) ){
99387 if( iCol<=0 || iCol>pEList->nExpr ){
99388 resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
99389 return 1;
99390 }
@@ -99560,10 +99666,11 @@
99560 nResult = pSelect->pEList->nExpr;
99561 pParse = pNC->pParse;
99562 for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
99563 Expr *pE = pItem->pExpr;
99564 Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
 
99565 if( zType[0]!='G' ){
99566 iCol = resolveAsName(pParse, pSelect->pEList, pE2);
99567 if( iCol>0 ){
99568 /* If an AS-name match is found, mark this ORDER BY column as being
99569 ** a copy of the iCol-th result-set column. The subsequent call to
@@ -103679,10 +103786,11 @@
103679 ** register iReg. The caller must ensure that iReg already contains
103680 ** the correct value for the expression.
103681 */
103682 static void exprToRegister(Expr *pExpr, int iReg){
103683 Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
 
103684 p->op2 = p->op;
103685 p->op = TK_REGISTER;
103686 p->iTable = iReg;
103687 ExprClearProperty(p, EP_Skip);
103688 }
@@ -104666,10 +104774,11 @@
104666 */
104667 SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
104668 int r2;
104669 pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
104670 if( ConstFactorOk(pParse)
 
104671 && pExpr->op!=TK_REGISTER
104672 && sqlite3ExprIsConstantNotJoin(pExpr)
104673 ){
104674 *pReg = 0;
104675 r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -119424,10 +119533,12 @@
119424 VFUNCTION(total_changes, 0, 0, 0, total_changes ),
119425 FUNCTION(replace, 3, 0, 0, replaceFunc ),
119426 FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
119427 FUNCTION(substr, 2, 0, 0, substrFunc ),
119428 FUNCTION(substr, 3, 0, 0, substrFunc ),
 
 
119429 WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
119430 WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
119431 WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
119432 WAGGREGATE(count, 0,0,0, countStep,
119433 countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
@@ -124310,10 +124421,12 @@
124310 /* Version 3.32.0 and later */
124311 char *(*create_filename)(const char*,const char*,const char*,
124312 int,const char**);
124313 void (*free_filename)(char*);
124314 sqlite3_file *(*database_file_object)(const char*);
 
 
124315 };
124316
124317 /*
124318 ** This is the function signature used for all extension entry points. It
124319 ** is also defined in the file "loadext.c".
@@ -124614,10 +124727,12 @@
124614 #define sqlite3_filename_wal sqlite3_api->filename_wal
124615 /* Version 3.32.0 and later */
124616 #define sqlite3_create_filename sqlite3_api->create_filename
124617 #define sqlite3_free_filename sqlite3_api->free_filename
124618 #define sqlite3_database_file_object sqlite3_api->database_file_object
 
 
124619 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
124620
124621 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
124622 /* This case when the file really is being compiled as a loadable
124623 ** extension */
@@ -125096,10 +125211,12 @@
125096 sqlite3_filename_wal,
125097 /* Version 3.32.0 and later */
125098 sqlite3_create_filename,
125099 sqlite3_free_filename,
125100 sqlite3_database_file_object,
 
 
125101 };
125102
125103 /* True if x is the directory separator character
125104 */
125105 #if SQLITE_OS_WIN
@@ -131654,10 +131771,11 @@
131654 Column *aCol, *pCol; /* For looping over result columns */
131655 int nCol; /* Number of columns in the result set */
131656 char *zName; /* Column name */
131657 int nName; /* Size of name in zName[] */
131658 Hash ht; /* Hash table of column names */
 
131659
131660 sqlite3HashInit(&ht);
131661 if( pEList ){
131662 nCol = pEList->nExpr;
131663 aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
@@ -131676,19 +131794,17 @@
131676 */
131677 if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
131678 /* If the column contains an "AS <name>" phrase, use <name> as the name */
131679 }else{
131680 Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
131681 while( pColExpr->op==TK_DOT ){
131682 pColExpr = pColExpr->pRight;
131683 assert( pColExpr!=0 );
131684 }
131685 if( pColExpr->op==TK_COLUMN ){
131686 /* For columns use the column name name */
131687 int iCol = pColExpr->iColumn;
131688 Table *pTab = pColExpr->y.pTab;
131689 assert( pTab!=0 );
131690 if( iCol<0 ) iCol = pTab->iPKey;
131691 zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
131692 }else if( pColExpr->op==TK_ID ){
131693 assert( !ExprHasProperty(pColExpr, EP_IntValue) );
131694 zName = pColExpr->u.zToken;
@@ -136959,26 +137075,15 @@
136959 goto trigger_cleanup;
136960 }
136961 pTab = sqlite3SrcListLookup(pParse, pTableName);
136962 if( !pTab ){
136963 /* The table does not exist. */
136964 if( db->init.iDb==1 ){
136965 /* Ticket #3810.
136966 ** Normally, whenever a table is dropped, all associated triggers are
136967 ** dropped too. But if a TEMP trigger is created on a non-TEMP table
136968 ** and the table is dropped by a different database connection, the
136969 ** trigger is not visible to the database connection that does the
136970 ** drop so the trigger cannot be dropped. This results in an
136971 ** "orphaned trigger" - a trigger whose associated table is missing.
136972 */
136973 db->init.orphanTrigger = 1;
136974 }
136975 goto trigger_cleanup;
136976 }
136977 if( IsVirtual(pTab) ){
136978 sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
136979 goto trigger_cleanup;
136980 }
136981
136982 /* Check that the trigger name is not reserved and that no trigger of the
136983 ** specified name exists */
136984 zName = sqlite3NameFromToken(db, pName);
@@ -137012,16 +137117,16 @@
137012 ** of triggers.
137013 */
137014 if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
137015 sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
137016 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
137017 goto trigger_cleanup;
137018 }
137019 if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
137020 sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
137021 " trigger on table: %S", pTableName, 0);
137022 goto trigger_cleanup;
137023 }
137024
137025 #ifndef SQLITE_OMIT_AUTHORIZATION
137026 if( !IN_RENAME_OBJECT ){
137027 int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -137077,10 +137182,27 @@
137077 if( !pParse->pNewTrigger ){
137078 sqlite3DeleteTrigger(db, pTrigger);
137079 }else{
137080 assert( pParse->pNewTrigger==pTrigger );
137081 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137082 }
137083
137084 /*
137085 ** This routine is called after all of the trigger actions have been parsed
137086 ** in order to complete the process of building the trigger.
@@ -138664,10 +138786,12 @@
138664 sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
138665 }
138666
138667 if( nChangeFrom==0 && HasRowid(pTab) ){
138668 sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
 
 
138669 }else{
138670 assert( pPk!=0 || HasRowid(pTab) );
138671 nPk = pPk ? pPk->nKeyCol : 0;
138672 iPk = pParse->nMem+1;
138673 pParse->nMem += nPk;
@@ -138755,13 +138879,14 @@
138755 /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
138756 ** mode, write the rowid into the FIFO. In either of the one-pass modes,
138757 ** leave it in register regOldRowid. */
138758 sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
138759 if( eOnePass==ONEPASS_OFF ){
138760 /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
138761 aRegIdx[nAllIdx] = ++pParse->nMem;
138762 sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
 
 
138763 }
138764 }else{
138765 /* Read the PK of the current row into an array of registers. In
138766 ** ONEPASS_OFF mode, serialize the array into a record and store it in
138767 ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
@@ -138845,12 +138970,13 @@
138845 sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
138846 sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0);
138847 VdbeCoverage(v);
138848 }
138849 }else{
138850 labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
138851 regOldRowid);
 
138852 VdbeCoverage(v);
138853 sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
138854 VdbeCoverage(v);
138855 }
138856 }
@@ -139096,15 +139222,13 @@
139096 if( eOnePass==ONEPASS_SINGLE ){
139097 /* Nothing to do at end-of-loop for a single-pass */
139098 }else if( eOnePass==ONEPASS_MULTI ){
139099 sqlite3VdbeResolveLabel(v, labelContinue);
139100 sqlite3WhereEnd(pWInfo);
139101 }else if( pPk || nChangeFrom ){
139102 sqlite3VdbeResolveLabel(v, labelContinue);
139103 sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
139104 }else{
139105 sqlite3VdbeGoto(v, labelContinue);
139106 }
139107 sqlite3VdbeResolveLabel(v, labelBreak);
139108
139109 /* Update the sqlite_sequence table by storing the content of the
139110 ** maximum rowid counter values recorded while inserting into
@@ -145894,10 +146018,11 @@
145894 ** all terms of the WHERE clause.
145895 */
145896 SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
145897 Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr);
145898 pWC->op = op;
 
145899 if( pE2==0 ) return;
145900 if( pE2->op!=op ){
145901 whereClauseInsert(pWC, pExpr, 0);
145902 }else{
145903 sqlite3WhereSplit(pWC, pE2->pLeft, op);
@@ -146292,10 +146417,20 @@
146292 */
146293 static void createMask(WhereMaskSet *pMaskSet, int iCursor){
146294 assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
146295 pMaskSet->ix[pMaskSet->n++] = iCursor;
146296 }
 
 
 
 
 
 
 
 
 
 
146297
146298 /*
146299 ** Advance to the next WhereTerm that matches according to the criteria
146300 ** established when the pScan object was initialized by whereScanInit().
146301 ** Return NULL if there are no more matching WhereTerms.
@@ -146323,12 +146458,11 @@
146323 pScan->pIdxExpr,iCur)==0)
146324 && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
146325 ){
146326 if( (pTerm->eOperator & WO_EQUIV)!=0
146327 && pScan->nEquiv<ArraySize(pScan->aiCur)
146328 && (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op
146329 ==TK_COLUMN
146330 ){
146331 int j;
146332 for(j=0; j<pScan->nEquiv; j++){
146333 if( pScan->aiCur[j]==pX->iTable
146334 && pScan->aiColumn[j]==pX->iColumn ){
@@ -146520,11 +146654,12 @@
146520 int i;
146521 const char *zColl = pIdx->azColl[iCol];
146522
146523 for(i=0; i<pList->nExpr; i++){
146524 Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr);
146525 if( p->op==TK_COLUMN
 
146526 && p->iColumn==pIdx->aiColumn[iCol]
146527 && p->iTable==iBase
146528 ){
146529 CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
146530 if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
@@ -146584,10 +146719,11 @@
146584 ** true. Note: The (p->iTable==iBase) part of this test may be false if the
146585 ** current SELECT is a correlated sub-query.
146586 */
146587 for(i=0; i<pDistinct->nExpr; i++){
146588 Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr);
 
146589 if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
146590 }
146591
146592 /* Loop through all indices on the table, checking each to see if it makes
146593 ** the DISTINCT qualifier redundant. It does so if:
@@ -148498,13 +148634,13 @@
148498 LogEst rLogSize; /* Logarithm of table size */
148499 WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
148500
148501 pNew = pBuilder->pNew;
148502 if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
148503 WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n",
148504 pProbe->pTable->zName,pProbe->zName,
148505 pNew->u.btree.nEq, pNew->nSkip));
148506
148507 assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
148508 assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
148509 if( pNew->wsFlags & WHERE_BTM_LIMIT ){
148510 opMask = WO_LT|WO_LE;
@@ -148869,10 +149005,11 @@
148869
148870 if( pIndex->bUnordered ) return 0;
148871 if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
148872 for(ii=0; ii<pOB->nExpr; ii++){
148873 Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
 
148874 if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
148875 if( pExpr->iColumn<0 ) return 1;
148876 for(jj=0; jj<pIndex->nKeyCol; jj++){
148877 if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
148878 }
@@ -149847,10 +149984,11 @@
149847 ** loops.
149848 */
149849 for(i=0; i<nOrderBy; i++){
149850 if( MASKBIT(i) & obSat ) continue;
149851 pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
 
149852 if( pOBExpr->op!=TK_COLUMN ) continue;
149853 if( pOBExpr->iTable!=iCur ) continue;
149854 pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
149855 ~ready, eqOpMask, 0);
149856 if( pTerm==0 ) continue;
@@ -149973,10 +150111,11 @@
149973 for(i=0; bOnce && i<nOrderBy; i++){
149974 if( MASKBIT(i) & obSat ) continue;
149975 pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
149976 testcase( wctrlFlags & WHERE_GROUPBY );
149977 testcase( wctrlFlags & WHERE_DISTINCTBY );
 
149978 if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
149979 if( iColumn>=XN_ROWID ){
149980 if( pOBExpr->op!=TK_COLUMN ) continue;
149981 if( pOBExpr->iTable!=iCur ) continue;
149982 if( pOBExpr->iColumn!=iColumn ) continue;
@@ -150136,11 +150275,11 @@
150136 rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
150137 rSortCost = nRow + rScale + 16;
150138
150139 /* Multiple by log(M) where M is the number of output rows.
150140 ** Use the LIMIT for M if it is smaller. Or if this sort is for
150141 ** a DISTINT operator, M will be the number of distinct output
150142 ** rows, so fudge it downwards a bit.
150143 */
150144 if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
150145 nRow = pWInfo->iLimit;
150146 }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){
@@ -194220,11 +194359,11 @@
194220 p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2];
194221 p->nEvent = p->nSegment = 0;
194222 geopolyAddSegments(p, p1, 1);
194223 geopolyAddSegments(p, p2, 2);
194224 pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
194225 rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
194226 memset(aOverlap, 0, sizeof(aOverlap));
194227 while( pThisEvent ){
194228 if( pThisEvent->x!=rX ){
194229 GeoSegment *pPrev = 0;
194230 int iMask = 0;
@@ -212129,11 +212268,11 @@
212129 Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */
212130 ){
212131 int rc = SQLITE_OK; /* Return code */
212132 Fts5Bm25Data *p; /* Object to return */
212133
212134 p = pApi->xGetAuxdata(pFts, 0);
212135 if( p==0 ){
212136 int nPhrase; /* Number of phrases in query */
212137 sqlite3_int64 nRow = 0; /* Number of rows in table */
212138 sqlite3_int64 nToken = 0; /* Number of tokens in table */
212139 sqlite3_int64 nByte; /* Bytes of space to allocate */
@@ -212203,11 +212342,11 @@
212203 int nVal, /* Number of values in apVal[] array */
212204 sqlite3_value **apVal /* Array of trailing arguments */
212205 ){
212206 const double k1 = 1.2; /* Constant "k1" from BM25 formula */
212207 const double b = 0.75; /* Constant "b" from BM25 formula */
212208 int rc = SQLITE_OK; /* Error code */
212209 double score = 0.0; /* SQL function return value */
212210 Fts5Bm25Data *pData; /* Values allocated/calculated once only */
212211 int i; /* Iterator variable */
212212 int nInst = 0; /* Value returned by xInstCount() */
212213 double D = 0.0; /* Total number of tokens in row */
@@ -212235,21 +212374,19 @@
212235 int nTok;
212236 rc = pApi->xColumnSize(pFts, -1, &nTok);
212237 D = (double)nTok;
212238 }
212239
212240 /* Determine the BM25 score for the current row. */
212241 for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
212242 score += pData->aIDF[i] * (
212243 ( aFreq[i] * (k1 + 1.0) ) /
212244 ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
212245 );
212246 }
212247
212248 /* If no error has occurred, return the calculated score. Otherwise,
212249 ** throw an SQL exception. */
212250 if( rc==SQLITE_OK ){
 
 
 
 
 
 
212251 sqlite3_result_double(pCtx, -1.0 * score);
212252 }else{
212253 sqlite3_result_error_code(pCtx, rc);
212254 }
212255 }
@@ -223384,10 +223521,11 @@
223384 cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
223385 }
223386 }else{
223387 poslist.n = 0;
223388 fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
 
223389 while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
223390 int iCol = FTS5_POS2COLUMN(iPos);
223391 int iTokOff = FTS5_POS2OFFSET(iPos);
223392 cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
223393 }
@@ -226679,11 +226817,11 @@
226679 int nArg, /* Number of args */
226680 sqlite3_value **apUnused /* Function arguments */
226681 ){
226682 assert( nArg==0 );
226683 UNUSED_PARAM2(nArg, apUnused);
226684 sqlite3_result_text(pCtx, "fts5: 2020-10-26 16:22:31 80eba105d6d1b49ba8ca2ad4e14ddec2de0bdc2f6686c2f8a1c1d24fc1fe846f", -1, SQLITE_TRANSIENT);
226685 }
226686
226687 /*
226688 ** Return true if zName is the extension on one of the shadow tables used
226689 ** by this module.
@@ -229252,17 +229390,18 @@
229252
229253 /*
229254 ** Allocate a trigram tokenizer.
229255 */
229256 static int fts5TriCreate(
229257 void *pCtx,
229258 const char **azArg,
229259 int nArg,
229260 Fts5Tokenizer **ppOut
229261 ){
229262 int rc = SQLITE_OK;
229263 TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
 
229264 if( pNew==0 ){
229265 rc = SQLITE_NOMEM;
229266 }else{
229267 int i;
229268 pNew->bFold = 1;
@@ -229291,11 +229430,11 @@
229291 ** Trigram tokenizer tokenize routine.
229292 */
229293 static int fts5TriTokenize(
229294 Fts5Tokenizer *pTok,
229295 void *pCtx,
229296 int flags,
229297 const char *pText, int nText,
229298 int (*xToken)(void*, int, const char*, int, int, int)
229299 ){
229300 TrigramTokenizer *p = (TrigramTokenizer*)pTok;
229301 int rc = SQLITE_OK;
@@ -229302,10 +229441,11 @@
229302 char aBuf[32];
229303 const unsigned char *zIn = (const unsigned char*)pText;
229304 const unsigned char *zEof = &zIn[nText];
229305 u32 iCode;
229306
 
229307 while( 1 ){
229308 char *zOut = aBuf;
229309 int iStart = zIn - (const unsigned char*)pText;
229310 const unsigned char *zNext;
229311
@@ -230164,10 +230304,11 @@
230164 }
230165 iTbl++;
230166 }
230167 aAscii[0] = 0; /* 0x00 is never a token character */
230168 }
 
230169
230170 /*
230171 ** 2015 May 30
230172 **
230173 ** The author disclaims copyright to this source code. In place of
@@ -231602,12 +231743,12 @@
231602 }
231603 #endif /* SQLITE_CORE */
231604 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
231605
231606 /************** End of stmt.c ************************************************/
231607 #if __LINE__!=231607
231608 #undef SQLITE_SOURCE_ID
231609 #define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692alt2"
231610 #endif
231611 /* Return the source-id for this library */
231612 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
231613 /************************** End of sqlite3.c ******************************/
231614
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1171,11 +1171,11 @@
1171 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1172 ** [sqlite_version()] and [sqlite_source_id()].
1173 */
1174 #define SQLITE_VERSION "3.34.0"
1175 #define SQLITE_VERSION_NUMBER 3034000
1176 #define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b"
1177
1178 /*
1179 ** CAPI3REF: Run-Time Library Version Numbers
1180 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1181 **
@@ -1550,10 +1550,11 @@
1550 #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
1551 #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
1552 #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
1553 #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
1554 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
1555 #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
1556 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
1557 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
1558 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
1559 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
1560 #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
@@ -7238,11 +7239,11 @@
7239 ** CAPI3REF: Determine the transaction state of a database
7240 ** METHOD: sqlite3
7241 **
7242 ** ^The sqlite3_txn_state(D,S) interface returns the current
7243 ** [transaction state] of schema S in database connection D. ^If S is NULL,
7244 ** then the highest transaction state of any schema on database connection D
7245 ** is returned. Transaction states are (in order of lowest to highest):
7246 ** <ol>
7247 ** <li value="0"> SQLITE_TXN_NONE
7248 ** <li value="1"> SQLITE_TXN_READ
7249 ** <li value="2"> SQLITE_TXN_WRITE
@@ -8785,11 +8786,10 @@
8786 */
8787 #define SQLITE_TESTCTRL_FIRST 5
8788 #define SQLITE_TESTCTRL_PRNG_SAVE 5
8789 #define SQLITE_TESTCTRL_PRNG_RESTORE 6
8790 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
 
8791 #define SQLITE_TESTCTRL_BITVEC_TEST 8
8792 #define SQLITE_TESTCTRL_FAULT_INSTALL 9
8793 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
8794 #define SQLITE_TESTCTRL_PENDING_BYTE 11
8795 #define SQLITE_TESTCTRL_ASSERT 12
@@ -8810,11 +8810,12 @@
8810 #define SQLITE_TESTCTRL_IMPOSTER 25
8811 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26
8812 #define SQLITE_TESTCTRL_RESULT_INTREAL 27
8813 #define SQLITE_TESTCTRL_PRNG_SEED 28
8814 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
8815 #define SQLITE_TESTCTRL_SEEK_COUNT 30
8816 #define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */
8817
8818 /*
8819 ** CAPI3REF: SQL Keyword Checking
8820 **
8821 ** These routines provide access to the set of SQL language keywords
@@ -28182,16 +28183,19 @@
28183 EnableLookaside;
28184 }
28185 }
28186
28187 /*
28188 ** Take actions at the end of an API call to deal with error codes.
28189 */
28190 static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){
28191 if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
28192 sqlite3OomClear(db);
28193 sqlite3Error(db, SQLITE_NOMEM);
28194 return SQLITE_NOMEM_BKPT;
28195 }
28196 return rc & db->errMask;
28197 }
28198
28199 /*
28200 ** This function must be called before exiting any API function (i.e.
28201 ** returning control to the user) that has called sqlite3_malloc or
@@ -28209,12 +28213,12 @@
28213 ** Otherwise the read (and possible write) of db->mallocFailed
28214 ** is unsafe, as is the call to sqlite3Error().
28215 */
28216 assert( db!=0 );
28217 assert( sqlite3_mutex_held(db->mutex) );
28218 if( db->mallocFailed || rc ){
28219 return apiHandleError(db, rc);
28220 }
28221 return rc & db->errMask;
28222 }
28223
28224 /************** End of malloc.c **********************************************/
@@ -37003,11 +37007,28 @@
37007
37008 got = seekAndRead(pFile, offset, pBuf, amt);
37009 if( got==amt ){
37010 return SQLITE_OK;
37011 }else if( got<0 ){
37012 /* pFile->lastErrno has been set by seekAndRead().
37013 ** Usually we return SQLITE_IOERR_READ here, though for some
37014 ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
37015 ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
37016 ** prior to returning to the application by the sqlite3ApiExit()
37017 ** routine.
37018 */
37019 switch( pFile->lastErrno ){
37020 case ERANGE:
37021 case EIO:
37022 #ifdef ENXIO
37023 case ENXIO:
37024 #endif
37025 #ifdef EDEVERR
37026 case EDEVERR:
37027 #endif
37028 return SQLITE_IOERR_CORRUPTFS;
37029 }
37030 return SQLITE_IOERR_READ;
37031 }else{
37032 storeLastErrno(pFile, 0); /* not a system error */
37033 /* Unread parts of the buffer must be zero-filled */
37034 memset(&((char*)pBuf)[got], 0, amt-got);
@@ -38535,11 +38556,11 @@
38556 if( bUnlock ){
38557 rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
38558 if( rc==SQLITE_OK ){
38559 memset(&aLock[ofst], 0, sizeof(int)*n);
38560 }
38561 }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
38562 assert( n==1 && aLock[ofst]>1 );
38563 aLock[ofst]--;
38564 }
38565
38566 /* Undo the local locks */
@@ -38568,11 +38589,11 @@
38589 /* Make sure no sibling connections hold locks that will block this
38590 ** lock. If any do, return SQLITE_BUSY right away. */
38591 int ii;
38592 for(ii=ofst; ii<ofst+n; ii++){
38593 assert( (p->sharedMask & mask)==0 );
38594 if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
38595 rc = SQLITE_BUSY;
38596 break;
38597 }
38598 }
38599
@@ -39964,19 +39985,39 @@
39985 }
39986 return SQLITE_OK;
39987 }
39988
39989 /*
39990 ** If the last component of the pathname in z[0]..z[j-1] is something
39991 ** other than ".." then back it out and return true. If the last
39992 ** component is empty or if it is ".." then return false.
39993 */
39994 static int unixBackupDir(const char *z, int *pJ){
39995 int j = *pJ;
39996 int i;
39997 if( j<=0 ) return 0;
39998 for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){}
39999 if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
40000 *pJ = i-1;
40001 return 1;
40002 }
40003
40004 /*
40005 ** Convert a relative pathname into a full pathname. Also
40006 ** simplify the pathname as follows:
40007 **
40008 ** Remove all instances of /./
40009 ** Remove all isntances of /X/../ for any X
40010 */
40011 static int mkFullPathname(
40012 const char *zPath, /* Input path */
40013 char *zOut, /* Output buffer */
40014 int nOut /* Allocated size of buffer zOut */
40015 ){
40016 int nPath = sqlite3Strlen30(zPath);
40017 int iOff = 0;
40018 int i, j;
40019 if( zPath[0]!='/' ){
40020 if( osGetcwd(zOut, nOut-2)==0 ){
40021 return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
40022 }
40023 iOff = sqlite3Strlen30(zOut);
@@ -39987,10 +40028,45 @@
40028 ** even if it returns an error. */
40029 zOut[iOff] = '\0';
40030 return SQLITE_CANTOPEN_BKPT;
40031 }
40032 sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
40033
40034 /* Remove duplicate '/' characters. Except, two // at the beginning
40035 ** of a pathname is allowed since this is important on windows. */
40036 for(i=j=1; zOut[i]; i++){
40037 zOut[j++] = zOut[i];
40038 while( zOut[i]=='/' && zOut[i+1]=='/' ) i++;
40039 }
40040 zOut[j] = 0;
40041
40042 assert( zOut[0]=='/' );
40043 for(i=j=0; zOut[i]; i++){
40044 if( zOut[i]=='/' ){
40045 /* Skip over internal "/." directory components */
40046 if( zOut[i+1]=='.' && zOut[i+2]=='/' ){
40047 i += 1;
40048 continue;
40049 }
40050
40051 /* If this is a "/.." directory component then back out the
40052 ** previous term of the directory if it is something other than "..".
40053 */
40054 if( zOut[i+1]=='.'
40055 && zOut[i+2]=='.'
40056 && zOut[i+3]=='/'
40057 && unixBackupDir(zOut, &j)
40058 ){
40059 i += 2;
40060 continue;
40061 }
40062 }
40063 if( ALWAYS(j>=0) ) zOut[j] = zOut[i];
40064 j++;
40065 }
40066 if( NEVER(j==0) ) zOut[j++] = '/';
40067 zOut[j] = 0;
40068 return SQLITE_OK;
40069 }
40070
40071 /*
40072 ** Turn a relative pathname into a full pathname. The relative path
@@ -54326,10 +54402,11 @@
54402 sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
54403 char *zSuperJournal = 0; /* Contents of super-journal file */
54404 i64 nSuperJournal; /* Size of super-journal file */
54405 char *zJournal; /* Pointer to one journal within MJ file */
54406 char *zSuperPtr; /* Space to hold super-journal filename */
54407 char *zFree = 0; /* Free this buffer */
54408 int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
54409
54410 /* Allocate space for both the pJournal and pSuper file descriptors.
54411 ** If successful, open the super-journal file for reading.
54412 */
@@ -54350,15 +54427,17 @@
54427 ** files extracted from regular rollback-journals.
54428 */
54429 rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
54430 if( rc!=SQLITE_OK ) goto delsuper_out;
54431 nSuperPtr = pVfs->mxPathname+1;
54432 zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
54433 if( !zFree ){
54434 rc = SQLITE_NOMEM_BKPT;
54435 goto delsuper_out;
54436 }
54437 zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
54438 zSuperJournal = &zFree[4];
54439 zSuperPtr = &zSuperJournal[nSuperJournal+2];
54440 rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
54441 if( rc!=SQLITE_OK ) goto delsuper_out;
54442 zSuperJournal[nSuperJournal] = 0;
54443 zSuperJournal[nSuperJournal+1] = 0;
@@ -54402,11 +54481,11 @@
54481
54482 sqlite3OsClose(pSuper);
54483 rc = sqlite3OsDelete(pVfs, zSuper, 0);
54484
54485 delsuper_out:
54486 sqlite3_free(zFree);
54487 if( pSuper ){
54488 sqlite3OsClose(pSuper);
54489 assert( !isOpen(pJournal) );
54490 sqlite3_free(pSuper);
54491 }
@@ -54740,11 +54819,15 @@
54819 ** in case this has happened, clear the changeCountDone flag now.
54820 */
54821 pPager->changeCountDone = pPager->tempFile;
54822
54823 if( rc==SQLITE_OK ){
54824 /* Leave 4 bytes of space before the super-journal filename in memory.
54825 ** This is because it may end up being passed to sqlite3OsOpen(), in
54826 ** which case it requires 4 0x00 bytes in memory immediately before
54827 ** the filename. */
54828 zSuper = &pPager->pTmpSpace[4];
54829 rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
54830 testcase( rc!=SQLITE_OK );
54831 }
54832 if( rc==SQLITE_OK
54833 && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -54757,10 +54840,12 @@
54840 }
54841 if( rc==SQLITE_OK && zSuper[0] && res ){
54842 /* If there was a super-journal and this routine will return success,
54843 ** see if it is possible to delete the super-journal.
54844 */
54845 assert( zSuper==&pPager->pTmpSpace[4] );
54846 memset(&zSuper[-4], 0, 4);
54847 rc = pager_delsuper(pPager, zSuper);
54848 testcase( rc!=SQLITE_OK );
54849 }
54850 if( isHot && nPlayback ){
54851 sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
@@ -64746,11 +64831,11 @@
64831 #define hasReadConflicts(a, b) 0
64832 #endif
64833
64834 #ifdef SQLITE_DEBUG
64835 /*
64836 ** Return and reset the seek counter for a Btree object.
64837 */
64838 SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
64839 u64 n = pBt->nSeek;
64840 pBt->nSeek = 0;
64841 return n;
@@ -82192,13 +82277,16 @@
82277 ** equal to, or greater than the second (double).
82278 */
82279 static int sqlite3IntFloatCompare(i64 i, double r){
82280 if( sizeof(LONGDOUBLE_TYPE)>8 ){
82281 LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
82282 testcase( x<r );
82283 testcase( x>r );
82284 testcase( x==r );
82285 if( x<r ) return -1;
82286 if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
82287 return 0; /*NO_TEST*/ /* work around bugs in gcov */
82288 }else{
82289 i64 y;
82290 double s;
82291 if( r<-9223372036854775808.0 ) return +1;
82292 if( r>=9223372036854775808.0 ) return -1;
@@ -89388,11 +89476,11 @@
89476 assert( rc==SQLITE_OK );
89477 break;
89478 }
89479
89480
89481 /* Opcode: OpenEphemeral P1 P2 P3 P4 P5
89482 ** Synopsis: nColumn=P2
89483 **
89484 ** Open a new cursor P1 to a transient table.
89485 ** The cursor is always opened read/write even if
89486 ** the main database is read-only. The ephemeral
@@ -89408,10 +89496,14 @@
89496 **
89497 ** The P5 parameter can be a mask of the BTREE_* flags defined
89498 ** in btree.h. These flags control aspects of the operation of
89499 ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are
89500 ** added automatically.
89501 **
89502 ** If P3 is positive, then reg[P3] is modified slightly so that it
89503 ** can be used as zero-length data for OP_Insert. This is an optimization
89504 ** that avoids an extra OP_Blob opcode to initialize that register.
89505 */
89506 /* Opcode: OpenAutoindex P1 P2 * P4 *
89507 ** Synopsis: nColumn=P2
89508 **
89509 ** This opcode works the same as OP_OpenEphemeral. It has a
@@ -89430,10 +89522,19 @@
89522 SQLITE_OPEN_EXCLUSIVE |
89523 SQLITE_OPEN_DELETEONCLOSE |
89524 SQLITE_OPEN_TRANSIENT_DB;
89525 assert( pOp->p1>=0 );
89526 assert( pOp->p2>=0 );
89527 if( pOp->p3>0 ){
89528 /* Make register reg[P3] into a value that can be used as the data
89529 ** form sqlite3BtreeInsert() where the length of the data is zero. */
89530 assert( pOp->p2==0 ); /* Only used when number of columns is zero */
89531 assert( pOp->opcode==OP_OpenEphemeral );
89532 assert( aMem[pOp->p3].flags & MEM_Null );
89533 aMem[pOp->p3].n = 0;
89534 aMem[pOp->p3].z = "";
89535 }
89536 pCx = p->apCsr[pOp->p1];
89537 if( pCx && pCx->pBtx ){
89538 /* If the ephermeral table is already open, erase all existing content
89539 ** so that the table is empty again, rather than creating a new table. */
89540 assert( pCx->isEphemeral );
@@ -90589,11 +90690,11 @@
90690 if( pOp->p5 & OPFLAG_ISNOOP ) break;
90691 #endif
90692
90693 if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
90694 if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
90695 assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 );
90696 x.pData = pData->z;
90697 x.nData = pData->n;
90698 seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
90699 if( pData->flags & MEM_Zero ){
90700 x.nZero = pData->u.nZero;
@@ -93644,11 +93745,15 @@
93745
93746 /* If we reach this point, it means that execution is finished with
93747 ** an error of some kind.
93748 */
93749 abort_due_to_error:
93750 if( db->mallocFailed ){
93751 rc = SQLITE_NOMEM_BKPT;
93752 }else if( rc==SQLITE_IOERR_CORRUPTFS ){
93753 rc = SQLITE_CORRUPT_BKPT;
93754 }
93755 assert( rc );
93756 if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
93757 sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
93758 }
93759 p->rc = rc;
@@ -99381,10 +99486,11 @@
99486 for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
99487 int iCol = -1;
99488 Expr *pE, *pDup;
99489 if( pItem->done ) continue;
99490 pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
99491 if( NEVER(pE==0) ) continue;
99492 if( sqlite3ExprIsInteger(pE, &iCol) ){
99493 if( iCol<=0 || iCol>pEList->nExpr ){
99494 resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
99495 return 1;
99496 }
@@ -99560,10 +99666,11 @@
99666 nResult = pSelect->pEList->nExpr;
99667 pParse = pNC->pParse;
99668 for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
99669 Expr *pE = pItem->pExpr;
99670 Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
99671 if( NEVER(pE2==0) ) continue;
99672 if( zType[0]!='G' ){
99673 iCol = resolveAsName(pParse, pSelect->pEList, pE2);
99674 if( iCol>0 ){
99675 /* If an AS-name match is found, mark this ORDER BY column as being
99676 ** a copy of the iCol-th result-set column. The subsequent call to
@@ -103679,10 +103786,11 @@
103786 ** register iReg. The caller must ensure that iReg already contains
103787 ** the correct value for the expression.
103788 */
103789 static void exprToRegister(Expr *pExpr, int iReg){
103790 Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
103791 if( NEVER(p==0) ) return;
103792 p->op2 = p->op;
103793 p->op = TK_REGISTER;
103794 p->iTable = iReg;
103795 ExprClearProperty(p, EP_Skip);
103796 }
@@ -104666,10 +104774,11 @@
104774 */
104775 SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
104776 int r2;
104777 pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
104778 if( ConstFactorOk(pParse)
104779 && ALWAYS(pExpr!=0)
104780 && pExpr->op!=TK_REGISTER
104781 && sqlite3ExprIsConstantNotJoin(pExpr)
104782 ){
104783 *pReg = 0;
104784 r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -119424,10 +119533,12 @@
119533 VFUNCTION(total_changes, 0, 0, 0, total_changes ),
119534 FUNCTION(replace, 3, 0, 0, replaceFunc ),
119535 FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
119536 FUNCTION(substr, 2, 0, 0, substrFunc ),
119537 FUNCTION(substr, 3, 0, 0, substrFunc ),
119538 FUNCTION(substring, 2, 0, 0, substrFunc ),
119539 FUNCTION(substring, 3, 0, 0, substrFunc ),
119540 WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
119541 WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
119542 WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
119543 WAGGREGATE(count, 0,0,0, countStep,
119544 countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
@@ -124310,10 +124421,12 @@
124421 /* Version 3.32.0 and later */
124422 char *(*create_filename)(const char*,const char*,const char*,
124423 int,const char**);
124424 void (*free_filename)(char*);
124425 sqlite3_file *(*database_file_object)(const char*);
124426 /* Version 3.34.0 and later */
124427 int (*txn_state)(sqlite3*,const char*);
124428 };
124429
124430 /*
124431 ** This is the function signature used for all extension entry points. It
124432 ** is also defined in the file "loadext.c".
@@ -124614,10 +124727,12 @@
124727 #define sqlite3_filename_wal sqlite3_api->filename_wal
124728 /* Version 3.32.0 and later */
124729 #define sqlite3_create_filename sqlite3_api->create_filename
124730 #define sqlite3_free_filename sqlite3_api->free_filename
124731 #define sqlite3_database_file_object sqlite3_api->database_file_object
124732 /* Version 3.34.0 and later */
124733 #define sqlite3_txn_state sqlite3_api->txn_state
124734 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
124735
124736 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
124737 /* This case when the file really is being compiled as a loadable
124738 ** extension */
@@ -125096,10 +125211,12 @@
125211 sqlite3_filename_wal,
125212 /* Version 3.32.0 and later */
125213 sqlite3_create_filename,
125214 sqlite3_free_filename,
125215 sqlite3_database_file_object,
125216 /* Version 3.34.0 and later */
125217 sqlite3_txn_state,
125218 };
125219
125220 /* True if x is the directory separator character
125221 */
125222 #if SQLITE_OS_WIN
@@ -131654,10 +131771,11 @@
131771 Column *aCol, *pCol; /* For looping over result columns */
131772 int nCol; /* Number of columns in the result set */
131773 char *zName; /* Column name */
131774 int nName; /* Size of name in zName[] */
131775 Hash ht; /* Hash table of column names */
131776 Table *pTab;
131777
131778 sqlite3HashInit(&ht);
131779 if( pEList ){
131780 nCol = pEList->nExpr;
131781 aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
@@ -131676,19 +131794,17 @@
131794 */
131795 if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
131796 /* If the column contains an "AS <name>" phrase, use <name> as the name */
131797 }else{
131798 Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
131799 while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){
131800 pColExpr = pColExpr->pRight;
131801 assert( pColExpr!=0 );
131802 }
131803 if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->y.pTab)!=0 ){
131804 /* For columns use the column name name */
131805 int iCol = pColExpr->iColumn;
 
 
131806 if( iCol<0 ) iCol = pTab->iPKey;
131807 zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
131808 }else if( pColExpr->op==TK_ID ){
131809 assert( !ExprHasProperty(pColExpr, EP_IntValue) );
131810 zName = pColExpr->u.zToken;
@@ -136959,26 +137075,15 @@
137075 goto trigger_cleanup;
137076 }
137077 pTab = sqlite3SrcListLookup(pParse, pTableName);
137078 if( !pTab ){
137079 /* The table does not exist. */
137080 goto trigger_orphan_error;
 
 
 
 
 
 
 
 
 
 
 
137081 }
137082 if( IsVirtual(pTab) ){
137083 sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
137084 goto trigger_orphan_error;
137085 }
137086
137087 /* Check that the trigger name is not reserved and that no trigger of the
137088 ** specified name exists */
137089 zName = sqlite3NameFromToken(db, pName);
@@ -137012,16 +137117,16 @@
137117 ** of triggers.
137118 */
137119 if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
137120 sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
137121 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
137122 goto trigger_orphan_error;
137123 }
137124 if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
137125 sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
137126 " trigger on table: %S", pTableName, 0);
137127 goto trigger_orphan_error;
137128 }
137129
137130 #ifndef SQLITE_OMIT_AUTHORIZATION
137131 if( !IN_RENAME_OBJECT ){
137132 int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -137077,10 +137182,27 @@
137182 if( !pParse->pNewTrigger ){
137183 sqlite3DeleteTrigger(db, pTrigger);
137184 }else{
137185 assert( pParse->pNewTrigger==pTrigger );
137186 }
137187 return;
137188
137189 trigger_orphan_error:
137190 if( db->init.iDb==1 ){
137191 /* Ticket #3810.
137192 ** Normally, whenever a table is dropped, all associated triggers are
137193 ** dropped too. But if a TEMP trigger is created on a non-TEMP table
137194 ** and the table is dropped by a different database connection, the
137195 ** trigger is not visible to the database connection that does the
137196 ** drop so the trigger cannot be dropped. This results in an
137197 ** "orphaned trigger" - a trigger whose associated table is missing.
137198 **
137199 ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df
137200 */
137201 db->init.orphanTrigger = 1;
137202 }
137203 goto trigger_cleanup;
137204 }
137205
137206 /*
137207 ** This routine is called after all of the trigger actions have been parsed
137208 ** in order to complete the process of building the trigger.
@@ -138664,10 +138786,12 @@
138786 sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
138787 }
138788
138789 if( nChangeFrom==0 && HasRowid(pTab) ){
138790 sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
138791 iEph = pParse->nTab++;
138792 addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet);
138793 }else{
138794 assert( pPk!=0 || HasRowid(pTab) );
138795 nPk = pPk ? pPk->nKeyCol : 0;
138796 iPk = pParse->nMem+1;
138797 pParse->nMem += nPk;
@@ -138755,13 +138879,14 @@
138879 /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
138880 ** mode, write the rowid into the FIFO. In either of the one-pass modes,
138881 ** leave it in register regOldRowid. */
138882 sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
138883 if( eOnePass==ONEPASS_OFF ){
 
138884 aRegIdx[nAllIdx] = ++pParse->nMem;
138885 sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid);
138886 }else{
138887 if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen);
138888 }
138889 }else{
138890 /* Read the PK of the current row into an array of registers. In
138891 ** ONEPASS_OFF mode, serialize the array into a record and store it in
138892 ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
@@ -138845,12 +138970,13 @@
138970 sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
138971 sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0);
138972 VdbeCoverage(v);
138973 }
138974 }else{
138975 sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
138976 labelContinue = sqlite3VdbeMakeLabel(pParse);
138977 addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
138978 VdbeCoverage(v);
138979 sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
138980 VdbeCoverage(v);
138981 }
138982 }
@@ -139096,15 +139222,13 @@
139222 if( eOnePass==ONEPASS_SINGLE ){
139223 /* Nothing to do at end-of-loop for a single-pass */
139224 }else if( eOnePass==ONEPASS_MULTI ){
139225 sqlite3VdbeResolveLabel(v, labelContinue);
139226 sqlite3WhereEnd(pWInfo);
139227 }else{
139228 sqlite3VdbeResolveLabel(v, labelContinue);
139229 sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
 
 
139230 }
139231 sqlite3VdbeResolveLabel(v, labelBreak);
139232
139233 /* Update the sqlite_sequence table by storing the content of the
139234 ** maximum rowid counter values recorded while inserting into
@@ -145894,10 +146018,11 @@
146018 ** all terms of the WHERE clause.
146019 */
146020 SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
146021 Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr);
146022 pWC->op = op;
146023 assert( pE2!=0 || pExpr==0 );
146024 if( pE2==0 ) return;
146025 if( pE2->op!=op ){
146026 whereClauseInsert(pWC, pExpr, 0);
146027 }else{
146028 sqlite3WhereSplit(pWC, pE2->pLeft, op);
@@ -146292,10 +146417,20 @@
146417 */
146418 static void createMask(WhereMaskSet *pMaskSet, int iCursor){
146419 assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
146420 pMaskSet->ix[pMaskSet->n++] = iCursor;
146421 }
146422
146423 /*
146424 ** If the right-hand branch of the expression is a TK_COLUMN, then return
146425 ** a pointer to the right-hand branch. Otherwise, return NULL.
146426 */
146427 static Expr *whereRightSubexprIsColumn(Expr *p){
146428 p = sqlite3ExprSkipCollateAndLikely(p->pRight);
146429 if( ALWAYS(p!=0) && p->op==TK_COLUMN ) return p;
146430 return 0;
146431 }
146432
146433 /*
146434 ** Advance to the next WhereTerm that matches according to the criteria
146435 ** established when the pScan object was initialized by whereScanInit().
146436 ** Return NULL if there are no more matching WhereTerms.
@@ -146323,12 +146458,11 @@
146458 pScan->pIdxExpr,iCur)==0)
146459 && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
146460 ){
146461 if( (pTerm->eOperator & WO_EQUIV)!=0
146462 && pScan->nEquiv<ArraySize(pScan->aiCur)
146463 && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0
 
146464 ){
146465 int j;
146466 for(j=0; j<pScan->nEquiv; j++){
146467 if( pScan->aiCur[j]==pX->iTable
146468 && pScan->aiColumn[j]==pX->iColumn ){
@@ -146520,11 +146654,12 @@
146654 int i;
146655 const char *zColl = pIdx->azColl[iCol];
146656
146657 for(i=0; i<pList->nExpr; i++){
146658 Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr);
146659 if( ALWAYS(p!=0)
146660 && p->op==TK_COLUMN
146661 && p->iColumn==pIdx->aiColumn[iCol]
146662 && p->iTable==iBase
146663 ){
146664 CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
146665 if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
@@ -146584,10 +146719,11 @@
146719 ** true. Note: The (p->iTable==iBase) part of this test may be false if the
146720 ** current SELECT is a correlated sub-query.
146721 */
146722 for(i=0; i<pDistinct->nExpr; i++){
146723 Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr);
146724 if( NEVER(p==0) ) continue;
146725 if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
146726 }
146727
146728 /* Loop through all indices on the table, checking each to see if it makes
146729 ** the DISTINCT qualifier redundant. It does so if:
@@ -148498,13 +148634,13 @@
148634 LogEst rLogSize; /* Logarithm of table size */
148635 WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
148636
148637 pNew = pBuilder->pNew;
148638 if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
148639 WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n",
148640 pProbe->pTable->zName,pProbe->zName,
148641 pNew->u.btree.nEq, pNew->nSkip, pNew->rRun));
148642
148643 assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
148644 assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
148645 if( pNew->wsFlags & WHERE_BTM_LIMIT ){
148646 opMask = WO_LT|WO_LE;
@@ -148869,10 +149005,11 @@
149005
149006 if( pIndex->bUnordered ) return 0;
149007 if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
149008 for(ii=0; ii<pOB->nExpr; ii++){
149009 Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
149010 if( NEVER(pExpr==0) ) continue;
149011 if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
149012 if( pExpr->iColumn<0 ) return 1;
149013 for(jj=0; jj<pIndex->nKeyCol; jj++){
149014 if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
149015 }
@@ -149847,10 +149984,11 @@
149984 ** loops.
149985 */
149986 for(i=0; i<nOrderBy; i++){
149987 if( MASKBIT(i) & obSat ) continue;
149988 pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
149989 if( NEVER(pOBExpr==0) ) continue;
149990 if( pOBExpr->op!=TK_COLUMN ) continue;
149991 if( pOBExpr->iTable!=iCur ) continue;
149992 pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
149993 ~ready, eqOpMask, 0);
149994 if( pTerm==0 ) continue;
@@ -149973,10 +150111,11 @@
150111 for(i=0; bOnce && i<nOrderBy; i++){
150112 if( MASKBIT(i) & obSat ) continue;
150113 pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
150114 testcase( wctrlFlags & WHERE_GROUPBY );
150115 testcase( wctrlFlags & WHERE_DISTINCTBY );
150116 if( NEVER(pOBExpr==0) ) continue;
150117 if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
150118 if( iColumn>=XN_ROWID ){
150119 if( pOBExpr->op!=TK_COLUMN ) continue;
150120 if( pOBExpr->iTable!=iCur ) continue;
150121 if( pOBExpr->iColumn!=iColumn ) continue;
@@ -150136,11 +150275,11 @@
150275 rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
150276 rSortCost = nRow + rScale + 16;
150277
150278 /* Multiple by log(M) where M is the number of output rows.
150279 ** Use the LIMIT for M if it is smaller. Or if this sort is for
150280 ** a DISTINCT operator, M will be the number of distinct output
150281 ** rows, so fudge it downwards a bit.
150282 */
150283 if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
150284 nRow = pWInfo->iLimit;
150285 }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){
@@ -194220,11 +194359,11 @@
194359 p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2];
194360 p->nEvent = p->nSegment = 0;
194361 geopolyAddSegments(p, p1, 1);
194362 geopolyAddSegments(p, p2, 2);
194363 pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
194364 rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0;
194365 memset(aOverlap, 0, sizeof(aOverlap));
194366 while( pThisEvent ){
194367 if( pThisEvent->x!=rX ){
194368 GeoSegment *pPrev = 0;
194369 int iMask = 0;
@@ -212129,11 +212268,11 @@
212268 Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */
212269 ){
212270 int rc = SQLITE_OK; /* Return code */
212271 Fts5Bm25Data *p; /* Object to return */
212272
212273 p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0);
212274 if( p==0 ){
212275 int nPhrase; /* Number of phrases in query */
212276 sqlite3_int64 nRow = 0; /* Number of rows in table */
212277 sqlite3_int64 nToken = 0; /* Number of tokens in table */
212278 sqlite3_int64 nByte; /* Bytes of space to allocate */
@@ -212203,11 +212342,11 @@
212342 int nVal, /* Number of values in apVal[] array */
212343 sqlite3_value **apVal /* Array of trailing arguments */
212344 ){
212345 const double k1 = 1.2; /* Constant "k1" from BM25 formula */
212346 const double b = 0.75; /* Constant "b" from BM25 formula */
212347 int rc; /* Error code */
212348 double score = 0.0; /* SQL function return value */
212349 Fts5Bm25Data *pData; /* Values allocated/calculated once only */
212350 int i; /* Iterator variable */
212351 int nInst = 0; /* Value returned by xInstCount() */
212352 double D = 0.0; /* Total number of tokens in row */
@@ -212235,21 +212374,19 @@
212374 int nTok;
212375 rc = pApi->xColumnSize(pFts, -1, &nTok);
212376 D = (double)nTok;
212377 }
212378
212379 /* Determine and return the BM25 score for the current row. Or, if an
212380 ** error has occurred, throw an exception. */
 
 
 
 
 
 
 
 
212381 if( rc==SQLITE_OK ){
212382 for(i=0; i<pData->nPhrase; i++){
212383 score += pData->aIDF[i] * (
212384 ( aFreq[i] * (k1 + 1.0) ) /
212385 ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
212386 );
212387 }
212388 sqlite3_result_double(pCtx, -1.0 * score);
212389 }else{
212390 sqlite3_result_error_code(pCtx, rc);
212391 }
212392 }
@@ -223384,10 +223521,11 @@
223521 cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
223522 }
223523 }else{
223524 poslist.n = 0;
223525 fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
223526 fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0");
223527 while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
223528 int iCol = FTS5_POS2COLUMN(iPos);
223529 int iTokOff = FTS5_POS2OFFSET(iPos);
223530 cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
223531 }
@@ -226679,11 +226817,11 @@
226817 int nArg, /* Number of args */
226818 sqlite3_value **apUnused /* Function arguments */
226819 ){
226820 assert( nArg==0 );
226821 UNUSED_PARAM2(nArg, apUnused);
226822 sqlite3_result_text(pCtx, "fts5: 2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b", -1, SQLITE_TRANSIENT);
226823 }
226824
226825 /*
226826 ** Return true if zName is the extension on one of the shadow tables used
226827 ** by this module.
@@ -229252,17 +229390,18 @@
229390
229391 /*
229392 ** Allocate a trigram tokenizer.
229393 */
229394 static int fts5TriCreate(
229395 void *pUnused,
229396 const char **azArg,
229397 int nArg,
229398 Fts5Tokenizer **ppOut
229399 ){
229400 int rc = SQLITE_OK;
229401 TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
229402 UNUSED_PARAM(pUnused);
229403 if( pNew==0 ){
229404 rc = SQLITE_NOMEM;
229405 }else{
229406 int i;
229407 pNew->bFold = 1;
@@ -229291,11 +229430,11 @@
229430 ** Trigram tokenizer tokenize routine.
229431 */
229432 static int fts5TriTokenize(
229433 Fts5Tokenizer *pTok,
229434 void *pCtx,
229435 int unusedFlags,
229436 const char *pText, int nText,
229437 int (*xToken)(void*, int, const char*, int, int, int)
229438 ){
229439 TrigramTokenizer *p = (TrigramTokenizer*)pTok;
229440 int rc = SQLITE_OK;
@@ -229302,10 +229441,11 @@
229441 char aBuf[32];
229442 const unsigned char *zIn = (const unsigned char*)pText;
229443 const unsigned char *zEof = &zIn[nText];
229444 u32 iCode;
229445
229446 UNUSED_PARAM(unusedFlags);
229447 while( 1 ){
229448 char *zOut = aBuf;
229449 int iStart = zIn - (const unsigned char*)pText;
229450 const unsigned char *zNext;
229451
@@ -230164,10 +230304,11 @@
230304 }
230305 iTbl++;
230306 }
230307 aAscii[0] = 0; /* 0x00 is never a token character */
230308 }
230309
230310
230311 /*
230312 ** 2015 May 30
230313 **
230314 ** The author disclaims copyright to this source code. In place of
@@ -231602,12 +231743,12 @@
231743 }
231744 #endif /* SQLITE_CORE */
231745 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
231746
231747 /************** End of stmt.c ************************************************/
231748 #if __LINE__!=231748
231749 #undef SQLITE_SOURCE_ID
231750 #define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089falt2"
231751 #endif
231752 /* Return the source-id for this library */
231753 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
231754 /************************** End of sqlite3.c ******************************/
231755
+5 -4
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123123
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124124
** [sqlite_version()] and [sqlite_source_id()].
125125
*/
126126
#define SQLITE_VERSION "3.34.0"
127127
#define SQLITE_VERSION_NUMBER 3034000
128
-#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
128
+#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b"
129129
130130
/*
131131
** CAPI3REF: Run-Time Library Version Numbers
132132
** KEYWORDS: sqlite3_version sqlite3_sourceid
133133
**
@@ -502,10 +502,11 @@
502502
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
503503
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
504504
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
505505
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
506506
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
507
+#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
507508
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
508509
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
509510
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
510511
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
511512
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
@@ -6190,11 +6191,11 @@
61906191
** CAPI3REF: Determine the transaction state of a database
61916192
** METHOD: sqlite3
61926193
**
61936194
** ^The sqlite3_txn_state(D,S) interface returns the current
61946195
** [transaction state] of schema S in database connection D. ^If S is NULL,
6195
-** then the highest transaction state of any schema on databse connection D
6196
+** then the highest transaction state of any schema on database connection D
61966197
** is returned. Transaction states are (in order of lowest to highest):
61976198
** <ol>
61986199
** <li value="0"> SQLITE_TXN_NONE
61996200
** <li value="1"> SQLITE_TXN_READ
62006201
** <li value="2"> SQLITE_TXN_WRITE
@@ -7737,11 +7738,10 @@
77377738
*/
77387739
#define SQLITE_TESTCTRL_FIRST 5
77397740
#define SQLITE_TESTCTRL_PRNG_SAVE 5
77407741
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
77417742
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
7742
-#define SQLITE_TESTCTRL_SEEK_COUNT 7
77437743
#define SQLITE_TESTCTRL_BITVEC_TEST 8
77447744
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
77457745
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
77467746
#define SQLITE_TESTCTRL_PENDING_BYTE 11
77477747
#define SQLITE_TESTCTRL_ASSERT 12
@@ -7762,11 +7762,12 @@
77627762
#define SQLITE_TESTCTRL_IMPOSTER 25
77637763
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
77647764
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
77657765
#define SQLITE_TESTCTRL_PRNG_SEED 28
77667766
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
7767
-#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
7767
+#define SQLITE_TESTCTRL_SEEK_COUNT 30
7768
+#define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */
77687769
77697770
/*
77707771
** CAPI3REF: SQL Keyword Checking
77717772
**
77727773
** These routines provide access to the set of SQL language keywords
77737774
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.34.0"
127 #define SQLITE_VERSION_NUMBER 3034000
128 #define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
@@ -502,10 +502,11 @@
502 #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
503 #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
504 #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
505 #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
506 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
 
507 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
508 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
509 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
510 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
511 #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
@@ -6190,11 +6191,11 @@
6190 ** CAPI3REF: Determine the transaction state of a database
6191 ** METHOD: sqlite3
6192 **
6193 ** ^The sqlite3_txn_state(D,S) interface returns the current
6194 ** [transaction state] of schema S in database connection D. ^If S is NULL,
6195 ** then the highest transaction state of any schema on databse connection D
6196 ** is returned. Transaction states are (in order of lowest to highest):
6197 ** <ol>
6198 ** <li value="0"> SQLITE_TXN_NONE
6199 ** <li value="1"> SQLITE_TXN_READ
6200 ** <li value="2"> SQLITE_TXN_WRITE
@@ -7737,11 +7738,10 @@
7737 */
7738 #define SQLITE_TESTCTRL_FIRST 5
7739 #define SQLITE_TESTCTRL_PRNG_SAVE 5
7740 #define SQLITE_TESTCTRL_PRNG_RESTORE 6
7741 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
7742 #define SQLITE_TESTCTRL_SEEK_COUNT 7
7743 #define SQLITE_TESTCTRL_BITVEC_TEST 8
7744 #define SQLITE_TESTCTRL_FAULT_INSTALL 9
7745 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
7746 #define SQLITE_TESTCTRL_PENDING_BYTE 11
7747 #define SQLITE_TESTCTRL_ASSERT 12
@@ -7762,11 +7762,12 @@
7762 #define SQLITE_TESTCTRL_IMPOSTER 25
7763 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26
7764 #define SQLITE_TESTCTRL_RESULT_INTREAL 27
7765 #define SQLITE_TESTCTRL_PRNG_SEED 28
7766 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
7767 #define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
 
7768
7769 /*
7770 ** CAPI3REF: SQL Keyword Checking
7771 **
7772 ** These routines provide access to the set of SQL language keywords
7773
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.34.0"
127 #define SQLITE_VERSION_NUMBER 3034000
128 #define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
@@ -502,10 +502,11 @@
502 #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
503 #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
504 #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
505 #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
506 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
507 #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
508 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
509 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
510 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
511 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
512 #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
@@ -6190,11 +6191,11 @@
6191 ** CAPI3REF: Determine the transaction state of a database
6192 ** METHOD: sqlite3
6193 **
6194 ** ^The sqlite3_txn_state(D,S) interface returns the current
6195 ** [transaction state] of schema S in database connection D. ^If S is NULL,
6196 ** then the highest transaction state of any schema on database connection D
6197 ** is returned. Transaction states are (in order of lowest to highest):
6198 ** <ol>
6199 ** <li value="0"> SQLITE_TXN_NONE
6200 ** <li value="1"> SQLITE_TXN_READ
6201 ** <li value="2"> SQLITE_TXN_WRITE
@@ -7737,11 +7738,10 @@
7738 */
7739 #define SQLITE_TESTCTRL_FIRST 5
7740 #define SQLITE_TESTCTRL_PRNG_SAVE 5
7741 #define SQLITE_TESTCTRL_PRNG_RESTORE 6
7742 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
 
7743 #define SQLITE_TESTCTRL_BITVEC_TEST 8
7744 #define SQLITE_TESTCTRL_FAULT_INSTALL 9
7745 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
7746 #define SQLITE_TESTCTRL_PENDING_BYTE 11
7747 #define SQLITE_TESTCTRL_ASSERT 12
@@ -7762,11 +7762,12 @@
7762 #define SQLITE_TESTCTRL_IMPOSTER 25
7763 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26
7764 #define SQLITE_TESTCTRL_RESULT_INTREAL 27
7765 #define SQLITE_TESTCTRL_PRNG_SEED 28
7766 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
7767 #define SQLITE_TESTCTRL_SEEK_COUNT 30
7768 #define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */
7769
7770 /*
7771 ** CAPI3REF: SQL Keyword Checking
7772 **
7773 ** These routines provide access to the set of SQL language keywords
7774
+4 -2
--- src/style.c
+++ src/style.c
@@ -1204,14 +1204,16 @@
12041204
@ <pre>
12051205
@ %h(blob_str(&g.httpHeader))
12061206
@ </pre>
12071207
}
12081208
}
1209
- style_finish_page("error");
1210
- if( zErr ){
1209
+ if( zErr && zErr[0] ){
1210
+ style_finish_page("error");
12111211
cgi_reply();
12121212
fossil_exit(1);
1213
+ }else{
1214
+ style_finish_page("test");
12131215
}
12141216
}
12151217
12161218
/*
12171219
** Generate a Not Yet Implemented error page.
12181220
--- src/style.c
+++ src/style.c
@@ -1204,14 +1204,16 @@
1204 @ <pre>
1205 @ %h(blob_str(&g.httpHeader))
1206 @ </pre>
1207 }
1208 }
1209 style_finish_page("error");
1210 if( zErr ){
1211 cgi_reply();
1212 fossil_exit(1);
 
 
1213 }
1214 }
1215
1216 /*
1217 ** Generate a Not Yet Implemented error page.
1218
--- src/style.c
+++ src/style.c
@@ -1204,14 +1204,16 @@
1204 @ <pre>
1205 @ %h(blob_str(&g.httpHeader))
1206 @ </pre>
1207 }
1208 }
1209 if( zErr && zErr[0] ){
1210 style_finish_page("error");
1211 cgi_reply();
1212 fossil_exit(1);
1213 }else{
1214 style_finish_page("test");
1215 }
1216 }
1217
1218 /*
1219 ** Generate a Not Yet Implemented error page.
1220
+126 -24
--- src/timeline.c
+++ src/timeline.c
@@ -595,25 +595,32 @@
595595
if( zType[0]!='c' ){
596596
/* Comments for anything other than a check-in are generated by
597597
** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
598598
if( zType[0]=='w' ){
599599
const char *zCom = blob_str(&comment);
600
- char *zWiki;
600
+ /* Except, the comments generated by "fossil rebuild" for a wiki
601
+ ** page edit consist of a single character '-', '+', or ':' (to
602
+ ** indicate "deleted", "added", or "edited") followed by the
603
+ ** raw wiki page name. We have to generate an appropriate
604
+ ** comment on-the-fly
605
+ */
601606
wiki_hyperlink_override(zUuid);
602
- if( (tmFlags & TIMELINE_REFS)!=0
603
- && (zWiki = strstr(zCom,"wiki"))!=0
604
- ){
605
- /* The TIMELINE_REFS flag causes timeline comments of the
606
- ** form "Changes to wiki..." or "Added wiki" to be changed
607
- ** into just "Wiki..." */
608
- Blob rcom;
609
- blob_init(&rcom, 0, 0);
610
- blob_appendf(&rcom, "W%s", zWiki+1);
611
- wiki_convert(&rcom, 0, WIKI_INLINE);
612
- blob_reset(&rcom);
607
+ if( zCom[0]=='-' ){
608
+ @ Deleted wiki page "%z(href("%R/whistory?name=%t",zCom+1))\
609
+ @ %h(zCom+1)</a>"
610
+ }else if( (tmFlags & TIMELINE_REFS)!=0
611
+ && (zCom[0]=='+' || zCom[0]==':') ){
612
+ @ Wiki page "%z(href("%R/wiki?name=%t",zCom+1))%h(zCom+1)</a>"
613
+ }else if( zCom[0]=='+' ){
614
+ @ Added wiki page "%z(href("%R/wiki?name=%t",zCom+1))%h(zCom+1)</a>"
615
+ }else if( zCom[0]==':' ){
616
+ @ Changes to wiki page "%z(href("%R/wiki?name=%t",zCom+1))\
617
+ @ %h(zCom+1)</a>"
613618
}else{
614
- wiki_convert(&comment, 0, WIKI_INLINE);
619
+ /* Legacy EVENT table entry that needs to be rebuilt */
620
+ @ Changes to a wiki page &rarr; Obsolete EVENT table information.
621
+ @ Run "fossil rebuild" on the repository.
615622
}
616623
wiki_hyperlink_override(0);
617624
}else{
618625
wiki_convert(&comment, 0, WIKI_INLINE);
619626
}
@@ -1727,19 +1734,26 @@
17271734
int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */
17281735
int pd_rid;
17291736
double rBefore, rAfter, rCirca; /* Boundary times */
17301737
const char *z;
17311738
char *zOlderButton = 0; /* URL for Older button at the bottom */
1739
+ char *zOlderButtonLabel = 0; /* Label for the Older Button */
17321740
char *zNewerButton = 0; /* URL for Newer button at the top */
1741
+ char *zNewerButtonLabel = 0; /* Label for the Newer button */
17331742
int selectedRid = 0; /* Show a highlight on this RID */
17341743
int secondaryRid = 0; /* Show secondary highlight */
17351744
int disableY = 0; /* Disable type selector on submenu */
17361745
int advancedMenu = 0; /* Use the advanced menu design */
17371746
char *zPlural; /* Ending for plural forms */
17381747
int showCherrypicks = 1; /* True to show cherrypick merges */
1748
+ int haveParameterN; /* True if n= query parameter present */
1749
+
1750
+ url_initialize(&url, "timeline");
1751
+ cgi_query_parameters_to_url(&url);
17391752
17401753
/* Set number of rows to display */
1754
+ haveParameterN = P("n")!=0;
17411755
cookie_read_parameter("n","n");
17421756
z = P("n");
17431757
if( z==0 ) z = db_get("timeline-default-length",0);
17441758
if( z ){
17451759
if( fossil_strcmp(z,"all")==0 ){
@@ -1797,12 +1811,10 @@
17971811
}
17981812
if( zType[0]=='a' || zType[0]=='c' ){
17991813
cookie_write_parameter("y","y",zType);
18001814
}
18011815
cookie_render();
1802
- url_initialize(&url, "timeline");
1803
- cgi_query_parameters_to_url(&url);
18041816
18051817
/* Convert the cf=FILEHASH query parameter into a c=CHECKINHASH value */
18061818
if( P("cf")!=0 ){
18071819
zCirca = db_text(0,
18081820
"SELECT (SELECT uuid FROM blob WHERE rid=mlink.mid)"
@@ -2064,11 +2076,10 @@
20642076
" WHERE mlink.mid=x"
20652077
" AND mlink.fnid=filename.fnid AND %s)",
20662078
glob_expr("filename.name", zChng)
20672079
);
20682080
}
2069
-// tmFlags |= TIMELINE_DISJOINT;
20702081
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
20712082
db_multi_exec("%s", blob_sql_text(&sql));
20722083
if( advancedMenu ){
20732084
style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
20742085
}
@@ -2118,10 +2129,11 @@
21182129
db_multi_exec("DELETE FROM ok");
21192130
}
21202131
if( p_rid ){
21212132
zBackTo = P("bt");
21222133
ridBackTo = zBackTo ? name_to_typed_rid(zBackTo,"ci") : 0;
2134
+ if( !haveParameterN ) nEntry = 0;
21232135
compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo);
21242136
np = db_int(0, "SELECT count(*)-1 FROM ok");
21252137
if( np>0 || nd==0 ){
21262138
if( nd>0 ) blob_appendf(&desc, " and ");
21272139
blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s");
@@ -2216,27 +2228,57 @@
22162228
}
22172229
if( bisectLocal || zBisect!=0 ){
22182230
blob_append_sql(&cond, " AND event.objid IN (SELECT rid FROM bilog) ");
22192231
}
22202232
if( zYearMonth ){
2233
+ char *zNext;
22212234
zYearMonth = timeline_expand_datetime(zYearMonth);
2235
+ if( strlen(zYearMonth)>7 ){
2236
+ zYearMonth = mprintf("%.7s", zYearMonth);
2237
+ }
2238
+ if( db_int(0,"SELECT julianday('%q-01') IS NULL", zYearMonth) ){
2239
+ zYearMonth = db_text(0, "SELECT strftime('%%Y-%%m','now');");
2240
+ }
2241
+ zNext = db_text(0, "SELECT strftime('%%Y-%%m','%q-01','+1 month');",
2242
+ zYearMonth);
2243
+ if( db_int(0,
2244
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2245
+ " WHERE blob.rid=event.objid AND mtime>=julianday('%q-01')%s)",
2246
+ zNext, blob_sql_text(&cond))
2247
+ ){
2248
+ zNewerButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0));
2249
+ zNewerButtonLabel = "Following month";
2250
+ }
2251
+ fossil_free(zNext);
2252
+ zNext = db_text(0, "SELECT strftime('%%Y-%%m','%q-01','-1 month');",
2253
+ zYearMonth);
2254
+ if( db_int(0,
2255
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2256
+ " WHERE blob.rid=event.objid AND mtime<julianday('%q-01')%s)",
2257
+ zYearMonth, blob_sql_text(&cond))
2258
+ ){
2259
+ zOlderButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0));
2260
+ zOlderButtonLabel = "Previous month";
2261
+ }
2262
+ fossil_free(zNext);
22222263
blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
22232264
zYearMonth);
2265
+ nEntry = -1;
22242266
}
22252267
else if( zYearWeek ){
2226
- char *z;
2268
+ char *z, *zNext;
22272269
zYearWeek = timeline_expand_datetime(zYearWeek);
22282270
z = db_text(0, "SELECT strftime('%%Y-%%W',%Q)", zYearWeek);
22292271
if( z && z[0] ){
22302272
zYearWeekStart = db_text(0, "SELECT date(%Q,'-6 days','weekday 1')",
22312273
zYearWeek);
22322274
zYearWeek = z;
22332275
}else{
22342276
if( strlen(zYearWeek)==7 ){
22352277
zYearWeekStart = db_text(0,
2236
- "SELECT date('%.4q-01-01','+%d days','weekday 1')",
2237
- zYearWeek, atoi(zYearWeek+5)*7);
2278
+ "SELECT date('%.4q-01-01','%+d days','weekday 1')",
2279
+ zYearWeek, atoi(zYearWeek+5)*7-6);
22382280
}else{
22392281
zYearWeekStart = 0;
22402282
}
22412283
if( zYearWeekStart==0 || zYearWeekStart[0]==0 ){
22422284
zYearWeekStart = db_text(0,
@@ -2243,20 +2285,61 @@
22432285
"SELECT date('now','-6 days','weekday 1');");
22442286
zYearWeek = db_text(0,
22452287
"SELECT strftime('%%Y-%%W','now','-6 days','weekday 1')");
22462288
}
22472289
}
2290
+ zNext = db_text(0, "SELECT date(%Q,'+7 day');", zYearWeekStart);
2291
+ if( db_int(0,
2292
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2293
+ " WHERE blob.rid=event.objid AND mtime>=julianday(%Q)%s)",
2294
+ zNext, blob_sql_text(&cond))
2295
+ ){
2296
+ zNewerButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0));
2297
+ zNewerButtonLabel = "Following week";
2298
+ }
2299
+ fossil_free(zNext);
2300
+ zNext = db_text(0, "SELECT date(%Q,'-7 days');", zYearWeekStart);
2301
+ if( db_int(0,
2302
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2303
+ " WHERE blob.rid=event.objid AND mtime<julianday(%Q)%s)",
2304
+ zYearWeekStart, blob_sql_text(&cond))
2305
+ ){
2306
+ zOlderButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0));
2307
+ zOlderButtonLabel = "Previous week";
2308
+ }
2309
+ fossil_free(zNext);
22482310
blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
22492311
zYearWeek);
22502312
nEntry = -1;
22512313
}
22522314
else if( zDay ){
2315
+ char *zNext;
22532316
zDay = timeline_expand_datetime(zDay);
22542317
zDay = db_text(0, "SELECT date(%Q)", zDay);
22552318
if( zDay==0 || zDay[0]==0 ){
22562319
zDay = db_text(0, "SELECT date('now')");
22572320
}
2321
+ zNext = db_text(0, "SELECT date(%Q,'+1 day');", zDay);
2322
+ if( db_int(0,
2323
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2324
+ " WHERE blob.rid=event.objid AND mtime>=julianday(%Q)%s)",
2325
+ zNext, blob_sql_text(&cond))
2326
+ ){
2327
+ zNewerButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2328
+ zNewerButtonLabel = "Following day";
2329
+ }
2330
+ fossil_free(zNext);
2331
+ zNext = db_text(0, "SELECT date(%Q,'-1 day');", zDay);
2332
+ if( db_int(0,
2333
+ "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2334
+ " WHERE blob.rid=event.objid AND mtime<julianday(%Q)%s)",
2335
+ zDay, blob_sql_text(&cond))
2336
+ ){
2337
+ zOlderButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2338
+ zOlderButtonLabel = "Previous day";
2339
+ }
2340
+ fossil_free(zNext);
22582341
blob_append_sql(&cond, " AND %Q=date(event.mtime) ",
22592342
zDay);
22602343
nEntry = -1;
22612344
}
22622345
else if( zNDays ){
@@ -2452,11 +2535,12 @@
24522535
db_multi_exec("%s", blob_sql_text(&sql));
24532536
24542537
n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
24552538
zPlural = n==1 ? "" : "s";
24562539
if( zYearMonth ){
2457
- blob_appendf(&desc, "%d %s%s for %h", n, zEType, zPlural, zYearMonth);
2540
+ blob_appendf(&desc, "%d %s%s for the month beginning %h-01",
2541
+ n, zEType, zPlural, zYearMonth);
24582542
}else if( zYearWeek ){
24592543
blob_appendf(&desc, "%d %s%s for week %h beginning on %h",
24602544
n, zEType, zPlural, zYearWeek, zYearWeekStart);
24612545
}else if( zDay ){
24622546
blob_appendf(&desc, "%d %s%s occurring on %h", n, zEType, zPlural, zDay);
@@ -2544,10 +2628,11 @@
25442628
"SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
25452629
" WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
25462630
rDate-ONE_SECOND, blob_sql_text(&cond))
25472631
){
25482632
zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
2633
+ zOlderButtonLabel = "More";
25492634
}
25502635
free(zDate);
25512636
}
25522637
zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
25532638
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
@@ -2559,10 +2644,11 @@
25592644
"SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
25602645
" WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
25612646
rDate+ONE_SECOND, blob_sql_text(&cond))
25622647
){
25632648
zNewerButton = fossil_strdup(url_render(&url, "a", zDate, "b", 0));
2649
+ zNewerButtonLabel = "More";
25642650
}
25652651
free(zDate);
25662652
}
25672653
if( advancedMenu ){
25682654
if( zType[0]=='a' || zType[0]=='c' ){
@@ -2628,17 +2714,19 @@
26282714
if( zError ){
26292715
@ <p class="generalError">%h(zError)</p>
26302716
}
26312717
26322718
if( zNewerButton ){
2633
- @ %z(chref("button","%z",zNewerButton))More&nbsp;&uarr;</a>
2719
+ @ %z(chref("button","%s",zNewerButton))%h(zNewerButtonLabel)\
2720
+ @ &nbsp;&uarr;</a>
26342721
}
26352722
www_print_timeline(&q, tmFlags, zThisUser, zThisTag, zBrName,
26362723
selectedRid, secondaryRid, 0);
26372724
db_finalize(&q);
26382725
if( zOlderButton ){
2639
- @ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
2726
+ @ %z(chref("button","%s",zOlderButton))%h(zOlderButtonLabel)\
2727
+ @ &nbsp;&darr;</a>
26402728
}
26412729
document_emit_js(/*handles pikchrs rendered above*/);
26422730
style_finish_page("timeline");
26432731
}
26442732
@@ -2662,10 +2750,11 @@
26622750
** 3. Comment string and user
26632751
** 4. Number of non-merge children
26642752
** 5. Number of parents
26652753
** 6. mtime
26662754
** 7. branch
2755
+** 8. event-type: 'ci', 'w', 't', 'f', and so forth.
26672756
*/
26682757
void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){
26692758
int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit;
26702759
int nLine = 0;
26712760
int nEntry = 0;
@@ -2686,10 +2775,11 @@
26862775
const char *zId = db_column_text(q, 1);
26872776
const char *zDate = db_column_text(q, 2);
26882777
const char *zCom = db_column_text(q, 3);
26892778
int nChild = db_column_int(q, 4);
26902779
int nParent = db_column_int(q, 5);
2780
+ const char *zType = db_column_text(q, 8);
26912781
char *zFree = 0;
26922782
int n = 0;
26932783
char zPrefix[80];
26942784
26952785
if( nAbsLimit!=0 ){
@@ -2729,11 +2819,22 @@
27292819
}
27302820
if( content_is_private(rid) ){
27312821
sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*UNPUBLISHED* ");
27322822
n += strlen(zPrefix+n);
27332823
}
2734
- zFree = mprintf("[%S] %s%s", zId, zPrefix, zCom);
2824
+ if( zType[0]=='w' && (zCom[0]=='+' || zCom[0]=='-' || zCom[0]==':') ){
2825
+ /* Special processing for Wiki comments */
2826
+ if( zCom[0]=='+' ){
2827
+ zFree = mprintf("[%S] Add wiki page \"%s\"", zId, zCom+1);
2828
+ }else if( zCom[0]=='-' ){
2829
+ zFree = mprintf("[%S] Delete wiki page \"%s\"", zId, zCom+1);
2830
+ }else{
2831
+ zFree = mprintf("[%S] Edit to wiki page \"%s\"", zId, zCom+1);
2832
+ }
2833
+ }else{
2834
+ zFree = mprintf("[%S] %s%s", zId, zPrefix, zCom);
2835
+ }
27352836
/* record another X lines */
27362837
nLine += comment_print(zFree, zCom, 9, width, get_comment_format());
27372838
fossil_free(zFree);
27382839
27392840
if(verboseFlag){
@@ -2799,11 +2900,12 @@
27992900
@ || ')' as comment,
28002901
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
28012902
@ AS primPlinkCount,
28022903
@ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
28032904
@ event.mtime AS mtime,
2804
- @ tagxref.value AS branch
2905
+ @ tagxref.value AS branch,
2906
+ @ event.type
28052907
@ FROM tag CROSS JOIN event CROSS JOIN blob
28062908
@ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
28072909
@ AND tagxref.tagtype>0
28082910
@ AND tagxref.rid=blob.rid
28092911
@ WHERE blob.rid=event.objid
28102912
--- src/timeline.c
+++ src/timeline.c
@@ -595,25 +595,32 @@
595 if( zType[0]!='c' ){
596 /* Comments for anything other than a check-in are generated by
597 ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
598 if( zType[0]=='w' ){
599 const char *zCom = blob_str(&comment);
600 char *zWiki;
 
 
 
 
 
601 wiki_hyperlink_override(zUuid);
602 if( (tmFlags & TIMELINE_REFS)!=0
603 && (zWiki = strstr(zCom,"wiki"))!=0
604 ){
605 /* The TIMELINE_REFS flag causes timeline comments of the
606 ** form "Changes to wiki..." or "Added wiki" to be changed
607 ** into just "Wiki..." */
608 Blob rcom;
609 blob_init(&rcom, 0, 0);
610 blob_appendf(&rcom, "W%s", zWiki+1);
611 wiki_convert(&rcom, 0, WIKI_INLINE);
612 blob_reset(&rcom);
613 }else{
614 wiki_convert(&comment, 0, WIKI_INLINE);
 
 
615 }
616 wiki_hyperlink_override(0);
617 }else{
618 wiki_convert(&comment, 0, WIKI_INLINE);
619 }
@@ -1727,19 +1734,26 @@
1727 int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */
1728 int pd_rid;
1729 double rBefore, rAfter, rCirca; /* Boundary times */
1730 const char *z;
1731 char *zOlderButton = 0; /* URL for Older button at the bottom */
 
1732 char *zNewerButton = 0; /* URL for Newer button at the top */
 
1733 int selectedRid = 0; /* Show a highlight on this RID */
1734 int secondaryRid = 0; /* Show secondary highlight */
1735 int disableY = 0; /* Disable type selector on submenu */
1736 int advancedMenu = 0; /* Use the advanced menu design */
1737 char *zPlural; /* Ending for plural forms */
1738 int showCherrypicks = 1; /* True to show cherrypick merges */
 
 
 
 
1739
1740 /* Set number of rows to display */
 
1741 cookie_read_parameter("n","n");
1742 z = P("n");
1743 if( z==0 ) z = db_get("timeline-default-length",0);
1744 if( z ){
1745 if( fossil_strcmp(z,"all")==0 ){
@@ -1797,12 +1811,10 @@
1797 }
1798 if( zType[0]=='a' || zType[0]=='c' ){
1799 cookie_write_parameter("y","y",zType);
1800 }
1801 cookie_render();
1802 url_initialize(&url, "timeline");
1803 cgi_query_parameters_to_url(&url);
1804
1805 /* Convert the cf=FILEHASH query parameter into a c=CHECKINHASH value */
1806 if( P("cf")!=0 ){
1807 zCirca = db_text(0,
1808 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.mid)"
@@ -2064,11 +2076,10 @@
2064 " WHERE mlink.mid=x"
2065 " AND mlink.fnid=filename.fnid AND %s)",
2066 glob_expr("filename.name", zChng)
2067 );
2068 }
2069 // tmFlags |= TIMELINE_DISJOINT;
2070 tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
2071 db_multi_exec("%s", blob_sql_text(&sql));
2072 if( advancedMenu ){
2073 style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
2074 }
@@ -2118,10 +2129,11 @@
2118 db_multi_exec("DELETE FROM ok");
2119 }
2120 if( p_rid ){
2121 zBackTo = P("bt");
2122 ridBackTo = zBackTo ? name_to_typed_rid(zBackTo,"ci") : 0;
 
2123 compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo);
2124 np = db_int(0, "SELECT count(*)-1 FROM ok");
2125 if( np>0 || nd==0 ){
2126 if( nd>0 ) blob_appendf(&desc, " and ");
2127 blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s");
@@ -2216,27 +2228,57 @@
2216 }
2217 if( bisectLocal || zBisect!=0 ){
2218 blob_append_sql(&cond, " AND event.objid IN (SELECT rid FROM bilog) ");
2219 }
2220 if( zYearMonth ){
 
2221 zYearMonth = timeline_expand_datetime(zYearMonth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2222 blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
2223 zYearMonth);
 
2224 }
2225 else if( zYearWeek ){
2226 char *z;
2227 zYearWeek = timeline_expand_datetime(zYearWeek);
2228 z = db_text(0, "SELECT strftime('%%Y-%%W',%Q)", zYearWeek);
2229 if( z && z[0] ){
2230 zYearWeekStart = db_text(0, "SELECT date(%Q,'-6 days','weekday 1')",
2231 zYearWeek);
2232 zYearWeek = z;
2233 }else{
2234 if( strlen(zYearWeek)==7 ){
2235 zYearWeekStart = db_text(0,
2236 "SELECT date('%.4q-01-01','+%d days','weekday 1')",
2237 zYearWeek, atoi(zYearWeek+5)*7);
2238 }else{
2239 zYearWeekStart = 0;
2240 }
2241 if( zYearWeekStart==0 || zYearWeekStart[0]==0 ){
2242 zYearWeekStart = db_text(0,
@@ -2243,20 +2285,61 @@
2243 "SELECT date('now','-6 days','weekday 1');");
2244 zYearWeek = db_text(0,
2245 "SELECT strftime('%%Y-%%W','now','-6 days','weekday 1')");
2246 }
2247 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2248 blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
2249 zYearWeek);
2250 nEntry = -1;
2251 }
2252 else if( zDay ){
 
2253 zDay = timeline_expand_datetime(zDay);
2254 zDay = db_text(0, "SELECT date(%Q)", zDay);
2255 if( zDay==0 || zDay[0]==0 ){
2256 zDay = db_text(0, "SELECT date('now')");
2257 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2258 blob_append_sql(&cond, " AND %Q=date(event.mtime) ",
2259 zDay);
2260 nEntry = -1;
2261 }
2262 else if( zNDays ){
@@ -2452,11 +2535,12 @@
2452 db_multi_exec("%s", blob_sql_text(&sql));
2453
2454 n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
2455 zPlural = n==1 ? "" : "s";
2456 if( zYearMonth ){
2457 blob_appendf(&desc, "%d %s%s for %h", n, zEType, zPlural, zYearMonth);
 
2458 }else if( zYearWeek ){
2459 blob_appendf(&desc, "%d %s%s for week %h beginning on %h",
2460 n, zEType, zPlural, zYearWeek, zYearWeekStart);
2461 }else if( zDay ){
2462 blob_appendf(&desc, "%d %s%s occurring on %h", n, zEType, zPlural, zDay);
@@ -2544,10 +2628,11 @@
2544 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2545 " WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
2546 rDate-ONE_SECOND, blob_sql_text(&cond))
2547 ){
2548 zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
 
2549 }
2550 free(zDate);
2551 }
2552 zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
2553 if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
@@ -2559,10 +2644,11 @@
2559 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2560 " WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
2561 rDate+ONE_SECOND, blob_sql_text(&cond))
2562 ){
2563 zNewerButton = fossil_strdup(url_render(&url, "a", zDate, "b", 0));
 
2564 }
2565 free(zDate);
2566 }
2567 if( advancedMenu ){
2568 if( zType[0]=='a' || zType[0]=='c' ){
@@ -2628,17 +2714,19 @@
2628 if( zError ){
2629 @ <p class="generalError">%h(zError)</p>
2630 }
2631
2632 if( zNewerButton ){
2633 @ %z(chref("button","%z",zNewerButton))More&nbsp;&uarr;</a>
 
2634 }
2635 www_print_timeline(&q, tmFlags, zThisUser, zThisTag, zBrName,
2636 selectedRid, secondaryRid, 0);
2637 db_finalize(&q);
2638 if( zOlderButton ){
2639 @ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
 
2640 }
2641 document_emit_js(/*handles pikchrs rendered above*/);
2642 style_finish_page("timeline");
2643 }
2644
@@ -2662,10 +2750,11 @@
2662 ** 3. Comment string and user
2663 ** 4. Number of non-merge children
2664 ** 5. Number of parents
2665 ** 6. mtime
2666 ** 7. branch
 
2667 */
2668 void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){
2669 int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit;
2670 int nLine = 0;
2671 int nEntry = 0;
@@ -2686,10 +2775,11 @@
2686 const char *zId = db_column_text(q, 1);
2687 const char *zDate = db_column_text(q, 2);
2688 const char *zCom = db_column_text(q, 3);
2689 int nChild = db_column_int(q, 4);
2690 int nParent = db_column_int(q, 5);
 
2691 char *zFree = 0;
2692 int n = 0;
2693 char zPrefix[80];
2694
2695 if( nAbsLimit!=0 ){
@@ -2729,11 +2819,22 @@
2729 }
2730 if( content_is_private(rid) ){
2731 sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*UNPUBLISHED* ");
2732 n += strlen(zPrefix+n);
2733 }
2734 zFree = mprintf("[%S] %s%s", zId, zPrefix, zCom);
 
 
 
 
 
 
 
 
 
 
 
2735 /* record another X lines */
2736 nLine += comment_print(zFree, zCom, 9, width, get_comment_format());
2737 fossil_free(zFree);
2738
2739 if(verboseFlag){
@@ -2799,11 +2900,12 @@
2799 @ || ')' as comment,
2800 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
2801 @ AS primPlinkCount,
2802 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
2803 @ event.mtime AS mtime,
2804 @ tagxref.value AS branch
 
2805 @ FROM tag CROSS JOIN event CROSS JOIN blob
2806 @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
2807 @ AND tagxref.tagtype>0
2808 @ AND tagxref.rid=blob.rid
2809 @ WHERE blob.rid=event.objid
2810
--- src/timeline.c
+++ src/timeline.c
@@ -595,25 +595,32 @@
595 if( zType[0]!='c' ){
596 /* Comments for anything other than a check-in are generated by
597 ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
598 if( zType[0]=='w' ){
599 const char *zCom = blob_str(&comment);
600 /* Except, the comments generated by "fossil rebuild" for a wiki
601 ** page edit consist of a single character '-', '+', or ':' (to
602 ** indicate "deleted", "added", or "edited") followed by the
603 ** raw wiki page name. We have to generate an appropriate
604 ** comment on-the-fly
605 */
606 wiki_hyperlink_override(zUuid);
607 if( zCom[0]=='-' ){
608 @ Deleted wiki page "%z(href("%R/whistory?name=%t",zCom+1))\
609 @ %h(zCom+1)</a>"
610 }else if( (tmFlags & TIMELINE_REFS)!=0
611 && (zCom[0]=='+' || zCom[0]==':') ){
612 @ Wiki page "%z(href("%R/wiki?name=%t",zCom+1))%h(zCom+1)</a>"
613 }else if( zCom[0]=='+' ){
614 @ Added wiki page "%z(href("%R/wiki?name=%t",zCom+1))%h(zCom+1)</a>"
615 }else if( zCom[0]==':' ){
616 @ Changes to wiki page "%z(href("%R/wiki?name=%t",zCom+1))\
617 @ %h(zCom+1)</a>"
618 }else{
619 /* Legacy EVENT table entry that needs to be rebuilt */
620 @ Changes to a wiki page &rarr; Obsolete EVENT table information.
621 @ Run "fossil rebuild" on the repository.
622 }
623 wiki_hyperlink_override(0);
624 }else{
625 wiki_convert(&comment, 0, WIKI_INLINE);
626 }
@@ -1727,19 +1734,26 @@
1734 int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */
1735 int pd_rid;
1736 double rBefore, rAfter, rCirca; /* Boundary times */
1737 const char *z;
1738 char *zOlderButton = 0; /* URL for Older button at the bottom */
1739 char *zOlderButtonLabel = 0; /* Label for the Older Button */
1740 char *zNewerButton = 0; /* URL for Newer button at the top */
1741 char *zNewerButtonLabel = 0; /* Label for the Newer button */
1742 int selectedRid = 0; /* Show a highlight on this RID */
1743 int secondaryRid = 0; /* Show secondary highlight */
1744 int disableY = 0; /* Disable type selector on submenu */
1745 int advancedMenu = 0; /* Use the advanced menu design */
1746 char *zPlural; /* Ending for plural forms */
1747 int showCherrypicks = 1; /* True to show cherrypick merges */
1748 int haveParameterN; /* True if n= query parameter present */
1749
1750 url_initialize(&url, "timeline");
1751 cgi_query_parameters_to_url(&url);
1752
1753 /* Set number of rows to display */
1754 haveParameterN = P("n")!=0;
1755 cookie_read_parameter("n","n");
1756 z = P("n");
1757 if( z==0 ) z = db_get("timeline-default-length",0);
1758 if( z ){
1759 if( fossil_strcmp(z,"all")==0 ){
@@ -1797,12 +1811,10 @@
1811 }
1812 if( zType[0]=='a' || zType[0]=='c' ){
1813 cookie_write_parameter("y","y",zType);
1814 }
1815 cookie_render();
 
 
1816
1817 /* Convert the cf=FILEHASH query parameter into a c=CHECKINHASH value */
1818 if( P("cf")!=0 ){
1819 zCirca = db_text(0,
1820 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.mid)"
@@ -2064,11 +2076,10 @@
2076 " WHERE mlink.mid=x"
2077 " AND mlink.fnid=filename.fnid AND %s)",
2078 glob_expr("filename.name", zChng)
2079 );
2080 }
 
2081 tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
2082 db_multi_exec("%s", blob_sql_text(&sql));
2083 if( advancedMenu ){
2084 style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
2085 }
@@ -2118,10 +2129,11 @@
2129 db_multi_exec("DELETE FROM ok");
2130 }
2131 if( p_rid ){
2132 zBackTo = P("bt");
2133 ridBackTo = zBackTo ? name_to_typed_rid(zBackTo,"ci") : 0;
2134 if( !haveParameterN ) nEntry = 0;
2135 compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo);
2136 np = db_int(0, "SELECT count(*)-1 FROM ok");
2137 if( np>0 || nd==0 ){
2138 if( nd>0 ) blob_appendf(&desc, " and ");
2139 blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s");
@@ -2216,27 +2228,57 @@
2228 }
2229 if( bisectLocal || zBisect!=0 ){
2230 blob_append_sql(&cond, " AND event.objid IN (SELECT rid FROM bilog) ");
2231 }
2232 if( zYearMonth ){
2233 char *zNext;
2234 zYearMonth = timeline_expand_datetime(zYearMonth);
2235 if( strlen(zYearMonth)>7 ){
2236 zYearMonth = mprintf("%.7s", zYearMonth);
2237 }
2238 if( db_int(0,"SELECT julianday('%q-01') IS NULL", zYearMonth) ){
2239 zYearMonth = db_text(0, "SELECT strftime('%%Y-%%m','now');");
2240 }
2241 zNext = db_text(0, "SELECT strftime('%%Y-%%m','%q-01','+1 month');",
2242 zYearMonth);
2243 if( db_int(0,
2244 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2245 " WHERE blob.rid=event.objid AND mtime>=julianday('%q-01')%s)",
2246 zNext, blob_sql_text(&cond))
2247 ){
2248 zNewerButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0));
2249 zNewerButtonLabel = "Following month";
2250 }
2251 fossil_free(zNext);
2252 zNext = db_text(0, "SELECT strftime('%%Y-%%m','%q-01','-1 month');",
2253 zYearMonth);
2254 if( db_int(0,
2255 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2256 " WHERE blob.rid=event.objid AND mtime<julianday('%q-01')%s)",
2257 zYearMonth, blob_sql_text(&cond))
2258 ){
2259 zOlderButton = fossil_strdup(url_render(&url, "ym", zNext, 0, 0));
2260 zOlderButtonLabel = "Previous month";
2261 }
2262 fossil_free(zNext);
2263 blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
2264 zYearMonth);
2265 nEntry = -1;
2266 }
2267 else if( zYearWeek ){
2268 char *z, *zNext;
2269 zYearWeek = timeline_expand_datetime(zYearWeek);
2270 z = db_text(0, "SELECT strftime('%%Y-%%W',%Q)", zYearWeek);
2271 if( z && z[0] ){
2272 zYearWeekStart = db_text(0, "SELECT date(%Q,'-6 days','weekday 1')",
2273 zYearWeek);
2274 zYearWeek = z;
2275 }else{
2276 if( strlen(zYearWeek)==7 ){
2277 zYearWeekStart = db_text(0,
2278 "SELECT date('%.4q-01-01','%+d days','weekday 1')",
2279 zYearWeek, atoi(zYearWeek+5)*7-6);
2280 }else{
2281 zYearWeekStart = 0;
2282 }
2283 if( zYearWeekStart==0 || zYearWeekStart[0]==0 ){
2284 zYearWeekStart = db_text(0,
@@ -2243,20 +2285,61 @@
2285 "SELECT date('now','-6 days','weekday 1');");
2286 zYearWeek = db_text(0,
2287 "SELECT strftime('%%Y-%%W','now','-6 days','weekday 1')");
2288 }
2289 }
2290 zNext = db_text(0, "SELECT date(%Q,'+7 day');", zYearWeekStart);
2291 if( db_int(0,
2292 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2293 " WHERE blob.rid=event.objid AND mtime>=julianday(%Q)%s)",
2294 zNext, blob_sql_text(&cond))
2295 ){
2296 zNewerButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0));
2297 zNewerButtonLabel = "Following week";
2298 }
2299 fossil_free(zNext);
2300 zNext = db_text(0, "SELECT date(%Q,'-7 days');", zYearWeekStart);
2301 if( db_int(0,
2302 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2303 " WHERE blob.rid=event.objid AND mtime<julianday(%Q)%s)",
2304 zYearWeekStart, blob_sql_text(&cond))
2305 ){
2306 zOlderButton = fossil_strdup(url_render(&url, "yw", zNext, 0, 0));
2307 zOlderButtonLabel = "Previous week";
2308 }
2309 fossil_free(zNext);
2310 blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
2311 zYearWeek);
2312 nEntry = -1;
2313 }
2314 else if( zDay ){
2315 char *zNext;
2316 zDay = timeline_expand_datetime(zDay);
2317 zDay = db_text(0, "SELECT date(%Q)", zDay);
2318 if( zDay==0 || zDay[0]==0 ){
2319 zDay = db_text(0, "SELECT date('now')");
2320 }
2321 zNext = db_text(0, "SELECT date(%Q,'+1 day');", zDay);
2322 if( db_int(0,
2323 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2324 " WHERE blob.rid=event.objid AND mtime>=julianday(%Q)%s)",
2325 zNext, blob_sql_text(&cond))
2326 ){
2327 zNewerButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2328 zNewerButtonLabel = "Following day";
2329 }
2330 fossil_free(zNext);
2331 zNext = db_text(0, "SELECT date(%Q,'-1 day');", zDay);
2332 if( db_int(0,
2333 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2334 " WHERE blob.rid=event.objid AND mtime<julianday(%Q)%s)",
2335 zDay, blob_sql_text(&cond))
2336 ){
2337 zOlderButton = fossil_strdup(url_render(&url, "ymd", zNext, 0, 0));
2338 zOlderButtonLabel = "Previous day";
2339 }
2340 fossil_free(zNext);
2341 blob_append_sql(&cond, " AND %Q=date(event.mtime) ",
2342 zDay);
2343 nEntry = -1;
2344 }
2345 else if( zNDays ){
@@ -2452,11 +2535,12 @@
2535 db_multi_exec("%s", blob_sql_text(&sql));
2536
2537 n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
2538 zPlural = n==1 ? "" : "s";
2539 if( zYearMonth ){
2540 blob_appendf(&desc, "%d %s%s for the month beginning %h-01",
2541 n, zEType, zPlural, zYearMonth);
2542 }else if( zYearWeek ){
2543 blob_appendf(&desc, "%d %s%s for week %h beginning on %h",
2544 n, zEType, zPlural, zYearWeek, zYearWeekStart);
2545 }else if( zDay ){
2546 blob_appendf(&desc, "%d %s%s occurring on %h", n, zEType, zPlural, zDay);
@@ -2544,10 +2628,11 @@
2628 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2629 " WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
2630 rDate-ONE_SECOND, blob_sql_text(&cond))
2631 ){
2632 zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
2633 zOlderButtonLabel = "More";
2634 }
2635 free(zDate);
2636 }
2637 zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
2638 if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
@@ -2559,10 +2644,11 @@
2644 "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
2645 " WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
2646 rDate+ONE_SECOND, blob_sql_text(&cond))
2647 ){
2648 zNewerButton = fossil_strdup(url_render(&url, "a", zDate, "b", 0));
2649 zNewerButtonLabel = "More";
2650 }
2651 free(zDate);
2652 }
2653 if( advancedMenu ){
2654 if( zType[0]=='a' || zType[0]=='c' ){
@@ -2628,17 +2714,19 @@
2714 if( zError ){
2715 @ <p class="generalError">%h(zError)</p>
2716 }
2717
2718 if( zNewerButton ){
2719 @ %z(chref("button","%s",zNewerButton))%h(zNewerButtonLabel)\
2720 @ &nbsp;&uarr;</a>
2721 }
2722 www_print_timeline(&q, tmFlags, zThisUser, zThisTag, zBrName,
2723 selectedRid, secondaryRid, 0);
2724 db_finalize(&q);
2725 if( zOlderButton ){
2726 @ %z(chref("button","%s",zOlderButton))%h(zOlderButtonLabel)\
2727 @ &nbsp;&darr;</a>
2728 }
2729 document_emit_js(/*handles pikchrs rendered above*/);
2730 style_finish_page("timeline");
2731 }
2732
@@ -2662,10 +2750,11 @@
2750 ** 3. Comment string and user
2751 ** 4. Number of non-merge children
2752 ** 5. Number of parents
2753 ** 6. mtime
2754 ** 7. branch
2755 ** 8. event-type: 'ci', 'w', 't', 'f', and so forth.
2756 */
2757 void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){
2758 int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit;
2759 int nLine = 0;
2760 int nEntry = 0;
@@ -2686,10 +2775,11 @@
2775 const char *zId = db_column_text(q, 1);
2776 const char *zDate = db_column_text(q, 2);
2777 const char *zCom = db_column_text(q, 3);
2778 int nChild = db_column_int(q, 4);
2779 int nParent = db_column_int(q, 5);
2780 const char *zType = db_column_text(q, 8);
2781 char *zFree = 0;
2782 int n = 0;
2783 char zPrefix[80];
2784
2785 if( nAbsLimit!=0 ){
@@ -2729,11 +2819,22 @@
2819 }
2820 if( content_is_private(rid) ){
2821 sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*UNPUBLISHED* ");
2822 n += strlen(zPrefix+n);
2823 }
2824 if( zType[0]=='w' && (zCom[0]=='+' || zCom[0]=='-' || zCom[0]==':') ){
2825 /* Special processing for Wiki comments */
2826 if( zCom[0]=='+' ){
2827 zFree = mprintf("[%S] Add wiki page \"%s\"", zId, zCom+1);
2828 }else if( zCom[0]=='-' ){
2829 zFree = mprintf("[%S] Delete wiki page \"%s\"", zId, zCom+1);
2830 }else{
2831 zFree = mprintf("[%S] Edit to wiki page \"%s\"", zId, zCom+1);
2832 }
2833 }else{
2834 zFree = mprintf("[%S] %s%s", zId, zPrefix, zCom);
2835 }
2836 /* record another X lines */
2837 nLine += comment_print(zFree, zCom, 9, width, get_comment_format());
2838 fossil_free(zFree);
2839
2840 if(verboseFlag){
@@ -2799,11 +2900,12 @@
2900 @ || ')' as comment,
2901 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
2902 @ AS primPlinkCount,
2903 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
2904 @ event.mtime AS mtime,
2905 @ tagxref.value AS branch,
2906 @ event.type
2907 @ FROM tag CROSS JOIN event CROSS JOIN blob
2908 @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
2909 @ AND tagxref.tagtype>0
2910 @ AND tagxref.rid=blob.rid
2911 @ WHERE blob.rid=event.objid
2912
+1
--- src/tkt.c
+++ src/tkt.c
@@ -446,10 +446,11 @@
446446
){
447447
goto ticket_schema_error;
448448
}
449449
break;
450450
}
451
+ case SQLITE_FUNCTION:
451452
case SQLITE_REINDEX:
452453
case SQLITE_TRANSACTION:
453454
case SQLITE_READ: {
454455
break;
455456
}
456457
--- src/tkt.c
+++ src/tkt.c
@@ -446,10 +446,11 @@
446 ){
447 goto ticket_schema_error;
448 }
449 break;
450 }
 
451 case SQLITE_REINDEX:
452 case SQLITE_TRANSACTION:
453 case SQLITE_READ: {
454 break;
455 }
456
--- src/tkt.c
+++ src/tkt.c
@@ -446,10 +446,11 @@
446 ){
447 goto ticket_schema_error;
448 }
449 break;
450 }
451 case SQLITE_FUNCTION:
452 case SQLITE_REINDEX:
453 case SQLITE_TRANSACTION:
454 case SQLITE_READ: {
455 break;
456 }
457
+1 -1
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -364,11 +364,11 @@
364364
@ <td colspan="3">
365365
@ Enter a detailed description of the problem.
366366
@ For code defects, be sure to provide details on exactly how
367367
@ the problem can be reproduced. Provide as much detail as
368368
@ possible. Format:
369
-@ <th1>combobox mutype {HTML {[links only]} Markdown {Plain Text} Wiki}} 1</th1>
369
+@ <th1>combobox mutype {HTML {[links only]} Markdown {Plain Text} Wiki} 1</th1>
370370
@ <br />
371371
@ <th1>set nline [linecount $comment 50 10]</th1>
372372
@ <textarea name="icomment" cols="80" rows="$nline"
373373
@ wrap="virtual" class="wikiedit">$<icomment></textarea><br />
374374
@ </tr>
375375
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -364,11 +364,11 @@
364 @ <td colspan="3">
365 @ Enter a detailed description of the problem.
366 @ For code defects, be sure to provide details on exactly how
367 @ the problem can be reproduced. Provide as much detail as
368 @ possible. Format:
369 @ <th1>combobox mutype {HTML {[links only]} Markdown {Plain Text} Wiki}} 1</th1>
370 @ <br />
371 @ <th1>set nline [linecount $comment 50 10]</th1>
372 @ <textarea name="icomment" cols="80" rows="$nline"
373 @ wrap="virtual" class="wikiedit">$<icomment></textarea><br />
374 @ </tr>
375
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -364,11 +364,11 @@
364 @ <td colspan="3">
365 @ Enter a detailed description of the problem.
366 @ For code defects, be sure to provide details on exactly how
367 @ the problem can be reproduced. Provide as much detail as
368 @ possible. Format:
369 @ <th1>combobox mutype {HTML {[links only]} Markdown {Plain Text} Wiki} 1</th1>
370 @ <br />
371 @ <th1>set nline [linecount $comment 50 10]</th1>
372 @ <textarea name="icomment" cols="80" rows="$nline"
373 @ wrap="virtual" class="wikiedit">$<icomment></textarea><br />
374 @ </tr>
375
+1 -1
--- src/update.c
+++ src/update.c
@@ -595,11 +595,11 @@
595595
if( dryRunFlag ){
596596
db_end_transaction(1); /* With --dry-run, rollback changes */
597597
}else{
598598
char *zPwd;
599599
ensure_empty_dirs_created(1);
600
- sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
600
+ sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
601601
file_rmdir_sql_function, 0, 0);
602602
zPwd = file_getcwd(0,0);
603603
db_multi_exec(
604604
"SELECT rmdir(%Q||name) FROM dir_to_delete"
605605
" WHERE (%Q||name)<>%Q ORDER BY name DESC",
606606
--- src/update.c
+++ src/update.c
@@ -595,11 +595,11 @@
595 if( dryRunFlag ){
596 db_end_transaction(1); /* With --dry-run, rollback changes */
597 }else{
598 char *zPwd;
599 ensure_empty_dirs_created(1);
600 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
601 file_rmdir_sql_function, 0, 0);
602 zPwd = file_getcwd(0,0);
603 db_multi_exec(
604 "SELECT rmdir(%Q||name) FROM dir_to_delete"
605 " WHERE (%Q||name)<>%Q ORDER BY name DESC",
606
--- src/update.c
+++ src/update.c
@@ -595,11 +595,11 @@
595 if( dryRunFlag ){
596 db_end_transaction(1); /* With --dry-run, rollback changes */
597 }else{
598 char *zPwd;
599 ensure_empty_dirs_created(1);
600 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
601 file_rmdir_sql_function, 0, 0);
602 zPwd = file_getcwd(0,0);
603 db_multi_exec(
604 "SELECT rmdir(%Q||name) FROM dir_to_delete"
605 " WHERE (%Q||name)<>%Q ORDER BY name DESC",
606
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -1299,11 +1299,11 @@
12991299
well_formed_wiki_name_rules();
13001300
CX("</div>"/*#wikiedit-tab-save*/);
13011301
}
13021302
builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
13031303
"storage", "popupwidget", "copybutton",
1304
- "pikchr", 0);
1304
+ "pikchr", NULL);
13051305
builtin_request_js("sbsdiff.js");
13061306
builtin_request_js("fossil.page.wikiedit.js");
13071307
builtin_fulfill_js_requests();
13081308
/* Dynamically populate the editor... */
13091309
style_script_begin(__FILE__,__LINE__);
13101310
--- src/wiki.c
+++ src/wiki.c
@@ -1299,11 +1299,11 @@
1299 well_formed_wiki_name_rules();
1300 CX("</div>"/*#wikiedit-tab-save*/);
1301 }
1302 builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
1303 "storage", "popupwidget", "copybutton",
1304 "pikchr", 0);
1305 builtin_request_js("sbsdiff.js");
1306 builtin_request_js("fossil.page.wikiedit.js");
1307 builtin_fulfill_js_requests();
1308 /* Dynamically populate the editor... */
1309 style_script_begin(__FILE__,__LINE__);
1310
--- src/wiki.c
+++ src/wiki.c
@@ -1299,11 +1299,11 @@
1299 well_formed_wiki_name_rules();
1300 CX("</div>"/*#wikiedit-tab-save*/);
1301 }
1302 builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
1303 "storage", "popupwidget", "copybutton",
1304 "pikchr", NULL);
1305 builtin_request_js("sbsdiff.js");
1306 builtin_request_js("fossil.page.wikiedit.js");
1307 builtin_fulfill_js_requests();
1308 /* Dynamically populate the editor... */
1309 style_script_begin(__FILE__,__LINE__);
1310
+2 -2
--- www/backup.md
+++ www/backup.md
@@ -248,11 +248,11 @@
248248
care of. If all variables defined in earlier scripts are available, then
249249
restoration is:
250250
251251
```
252252
openssl enc -d -aes-256-cbc -pbkdf2 -iter 52830 -pass pass:"$pass" -in "$gd" |
253
- xz -d | fossil --no-repository ~/museum/restored-repo.fossil
253
+ xz -d | fossil sql --no-repository ~/museum/restored-repo.fossil
254254
```
255255
256256
We changed the `-e` to `-d` on the `openssl` command to get decryption,
257257
and we changed the `-out` to `-in` so it reads from the encrypted backup
258258
file and writes the result to stdout.
@@ -265,11 +265,11 @@
265265
restoration:
266266
Fossil serves as a dogfooding project for SQLite,
267267
often making use of the latest features, so it is quite likely that a given
268268
random `sqlite3` binary in your `PATH` will be unable to understand the
269269
file created by “`fossil sql .dump`”! The tricky bit is, you can’t just
270
-pipe the decrpted SQL dump into `fossil sql`, because on startup, Fossil
270
+pipe the decrypted SQL dump into `fossil sql`, because on startup, Fossil
271271
normally goes looking for tables created by `fossil init`, and it won’t
272272
find them in a newly-created repo DB. We get around this by passing
273273
the `--no-repository` flag, which suppresses this behavior. Doing it
274274
this way saves you from needing to go and build a matching version of
275275
`sqlite3` just to restore the backup.
276276
--- www/backup.md
+++ www/backup.md
@@ -248,11 +248,11 @@
248 care of. If all variables defined in earlier scripts are available, then
249 restoration is:
250
251 ```
252 openssl enc -d -aes-256-cbc -pbkdf2 -iter 52830 -pass pass:"$pass" -in "$gd" |
253 xz -d | fossil --no-repository ~/museum/restored-repo.fossil
254 ```
255
256 We changed the `-e` to `-d` on the `openssl` command to get decryption,
257 and we changed the `-out` to `-in` so it reads from the encrypted backup
258 file and writes the result to stdout.
@@ -265,11 +265,11 @@
265 restoration:
266 Fossil serves as a dogfooding project for SQLite,
267 often making use of the latest features, so it is quite likely that a given
268 random `sqlite3` binary in your `PATH` will be unable to understand the
269 file created by “`fossil sql .dump`”! The tricky bit is, you can’t just
270 pipe the decrpted SQL dump into `fossil sql`, because on startup, Fossil
271 normally goes looking for tables created by `fossil init`, and it won’t
272 find them in a newly-created repo DB. We get around this by passing
273 the `--no-repository` flag, which suppresses this behavior. Doing it
274 this way saves you from needing to go and build a matching version of
275 `sqlite3` just to restore the backup.
276
--- www/backup.md
+++ www/backup.md
@@ -248,11 +248,11 @@
248 care of. If all variables defined in earlier scripts are available, then
249 restoration is:
250
251 ```
252 openssl enc -d -aes-256-cbc -pbkdf2 -iter 52830 -pass pass:"$pass" -in "$gd" |
253 xz -d | fossil sql --no-repository ~/museum/restored-repo.fossil
254 ```
255
256 We changed the `-e` to `-d` on the `openssl` command to get decryption,
257 and we changed the `-out` to `-in` so it reads from the encrypted backup
258 file and writes the result to stdout.
@@ -265,11 +265,11 @@
265 restoration:
266 Fossil serves as a dogfooding project for SQLite,
267 often making use of the latest features, so it is quite likely that a given
268 random `sqlite3` binary in your `PATH` will be unable to understand the
269 file created by “`fossil sql .dump`”! The tricky bit is, you can’t just
270 pipe the decrypted SQL dump into `fossil sql`, because on startup, Fossil
271 normally goes looking for tables created by `fossil init`, and it won’t
272 find them in a newly-created repo DB. We get around this by passing
273 the `--no-repository` flag, which suppresses this behavior. Doing it
274 this way saves you from needing to go and build a matching version of
275 `sqlite3` just to restore the backup.
276
--- www/changes.wiki
+++ www/changes.wiki
@@ -6,11 +6,29 @@
66
* The "[/help?cmd=clone|fossil clone]" command is enhanced so that
77
if the repository filename is omitted, an appropriate name is derived
88
from the remote URL and the newly cloned repo is opened. This makes
99
the clone command work more like Git, thus making it easier for
1010
people transitioning from Git.
11
+ * Changed the way that wiki edits are stored in the EVENT table of the
12
+ database, for more flexibility and better features.
13
+ <b>Run "fossil rebuild" to take advantage of this change</b>.
1114
* Add the "contact" sub-command to [/help?cmd=user|fossil user].
15
+ * Added commands "[/help?cmd=all|fossil all git export]" and
16
+ "[/help?cmd=all|fossil all git status]".
17
+ * Improvements to the "[/sitemap]" page. Add subpages
18
+ [/sitemap-timeline] and [/sitemap-test].
19
+ * Better text position in cylinder objects of Pikchr diagrams.
20
+ * New "details.txt" settings available to custom skins to better control
21
+ the rendering of Pikchr diagrams:
22
+ <ul>
23
+ <li> pikchr-foreground
24
+ <li> pikchr-scale
25
+ <li> pikchr-fontscale
26
+ </ul>
27
+ * Allow the use of SQL functions inside the ticket table definition
28
+ for custom ticket configurations.
29
+ * Countless improvements and enhancements to the documentation
1230
1331
<a name='v2_13'></a>
1432
<h2>Changes for Version 2.13 (2020-11-01)</h2>
1533
1634
* Added support for [./interwiki.md|interwiki links].
1735
--- www/changes.wiki
+++ www/changes.wiki
@@ -6,11 +6,29 @@
6 * The "[/help?cmd=clone|fossil clone]" command is enhanced so that
7 if the repository filename is omitted, an appropriate name is derived
8 from the remote URL and the newly cloned repo is opened. This makes
9 the clone command work more like Git, thus making it easier for
10 people transitioning from Git.
 
 
 
11 * Add the "contact" sub-command to [/help?cmd=user|fossil user].
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
13 <a name='v2_13'></a>
14 <h2>Changes for Version 2.13 (2020-11-01)</h2>
15
16 * Added support for [./interwiki.md|interwiki links].
17
--- www/changes.wiki
+++ www/changes.wiki
@@ -6,11 +6,29 @@
6 * The "[/help?cmd=clone|fossil clone]" command is enhanced so that
7 if the repository filename is omitted, an appropriate name is derived
8 from the remote URL and the newly cloned repo is opened. This makes
9 the clone command work more like Git, thus making it easier for
10 people transitioning from Git.
11 * Changed the way that wiki edits are stored in the EVENT table of the
12 database, for more flexibility and better features.
13 <b>Run "fossil rebuild" to take advantage of this change</b>.
14 * Add the "contact" sub-command to [/help?cmd=user|fossil user].
15 * Added commands "[/help?cmd=all|fossil all git export]" and
16 "[/help?cmd=all|fossil all git status]".
17 * Improvements to the "[/sitemap]" page. Add subpages
18 [/sitemap-timeline] and [/sitemap-test].
19 * Better text position in cylinder objects of Pikchr diagrams.
20 * New "details.txt" settings available to custom skins to better control
21 the rendering of Pikchr diagrams:
22 <ul>
23 <li> pikchr-foreground
24 <li> pikchr-scale
25 <li> pikchr-fontscale
26 </ul>
27 * Allow the use of SQL functions inside the ticket table definition
28 for custom ticket configurations.
29 * Countless improvements and enhancements to the documentation
30
31 <a name='v2_13'></a>
32 <h2>Changes for Version 2.13 (2020-11-01)</h2>
33
34 * Added support for [./interwiki.md|interwiki links].
35
--- www/ckout-workflows.md
+++ www/ckout-workflows.md
@@ -2,12 +2,11 @@
22
33
Because Fossil separates the concept of “check-out directory” from
44
“repository DB file,” it gives you the freedom to choose from several
55
working styles. Contrast Git, where the two concepts are normally
66
intermingled in a single working directory, which strongly encourages
7
-the “update in place” working style, leaving its `git-worktree` feature
8
-underutilized.
7
+the “update in place” working style.
98
109
1110
## <a id="mcw"></a> Multiple-Checkout Workflow
1211
1312
With Fossil, it is routine to have multiple check-outs from the same
@@ -48,13 +47,13 @@
4847
4948
Each check-out operates independently of the others.
5049
5150
This multiple-checkouts working style is especially useful when Fossil stores source code in programming languages
5251
where there is a “build” step that transforms source files into files
53
-you actually run or distribute. With Git’s typical switch-in-place workflow,
54
-you have to rebuild all outputs from the source files
55
-that differ between those versions whenever you switch versions. In the above Fossil working model,
52
+you actually run or distribute. Contrast a switch-in-place workflow,
53
+where you have to rebuild all outputs from the source files
54
+that differ between those versions whenever you switch versions. In the above model,
5655
you switch versions with a “`cd`” command instead, so that you only have
5756
to rebuild outputs from files you yourself change.
5857
5958
This style is also useful when a check-out directory may be tied up with
6059
some long-running process, as with the “test” example above, where you
@@ -72,13 +71,13 @@
7271
Nevertheless, it is possible to work in a more typical Git sort of
7372
style, switching between versions in a single check-out directory.
7473
7574
#### <a id="idiomatic"></a> The Idiomatic Fossil Way
7675
77
-With the clone done as in [the prior section](#mdw), the most idiomatic
78
-way is as follows:
76
+The most idiomatic way is as follows:
7977
78
+ fossil clone https://example.com/repo /path/to/repo.fossil
8079
mkdir work-dir
8180
cd work-dir
8281
fossil open /path/to/repo.fossil
8382
...work on trunk...
8483
@@ -87,56 +86,44 @@
8786
8887
Basically, you replace the `cd` commands in the multiple checkouts
8988
workflow above with `fossil up` commands.
9089
9190
92
-#### <a id="open"></a> The Clone-and-Open Way
91
+#### <a id="open"></a> Opening a Repository by URI
9392
94
-In Fossil 2.12, we added a feature that allows you to get closer to
95
-Git’s single-step clone-and-open behavior:
93
+In Fossil 2.12, we added a feature to simplify the single-worktree use
94
+case:
9695
9796
mkdir work-dir
9897
cd work-dir
9998
fossil open https://example.com/repo
10099
101100
Now you have “trunk” open in `work-dir`, with the repo file stored as
102101
`repo.fossil` in that same directory.
103102
104
-The use of [`fossil open`][open] here instead of [`fossil clone`][clone]
105
-is likely to surprise a Git user. When we were [discussing][caod]
106
-this, we considered following the Git command style, but we decided
107
-against it because it goes against this core Fossil design principle:
108
-given that the Fossil repo is separate from the check-out, why would you
109
-expect asking for a repo clone to also create a check-out directory for
110
-you? We view commingled repository + check-out as a design error in
111
-Git, so why would we repeat the error?
112
-
113
-To see why we see this behavior is error-prone, consider that
114
-`git clean` must have an exception to avoid nuking the `.git` directory.
115
-We had to add that complication to `fossil clean` when we added the
116
-`fossil open URI` feature: it won’t nuke the repo DB file.
117
-
118
-[clone]: /help?cmd=clone
119
-[open]: /help?cmd=open
120
-
121
-
122
-#### <a id="clone"></a> The Git Clone Way
123
-
124
-This feature didn’t placate many Git fans, though, so with Fossil 2.14 —
125
-currently unreleased — we now allow this:
103
+Users of Git may be surprised that it doesn’t create a directory for you
104
+and that you `cd` into it *before* the clone-and-open step, not after.
105
+This is because we’re overloading the “open” command, which already had
106
+the behavior of opening into the current working directory. Changing it
107
+to behave like `git clone` would therefore make the behavior surprising
108
+to Fossil users. (See [our discussions][caod] if you want the full
109
+details.)
110
+
111
+
112
+#### <a id="clone"></a> Git-Like Clone-and-Open
113
+
114
+With Fossil 2.14 — currently unreleased — we added a more Git-like
115
+alternative:
126116
127117
fossil clone https://fossil-scm.org/fossil
118
+ cd fossil
128119
129120
This results in a `fossil.fossil` repo DB file and a `fossil/` working
130121
directory.
131122
132123
Note that our `clone URI` behavior does not commingle the repo and
133
-check-out, solving our major problem with the Git design, though we
134
-still believe it to be confusing to have “clone” be part of “open,” and
135
-still more confusing to have “open” part of “clone.” We prefer keeping
136
-these operations entirely separate, either as at the [top of this
137
-section](#scw) or [as in the prior one](#mcw). Still, please yourself.
124
+check-out, solving our major problem with the Git design.
138125
139126
If you want the repo to be named something else, adjust the URL:
140127
141128
fossil clone https://fossil-scm.org/fossil/fsl
142129
@@ -149,8 +136,9 @@
149136
fossil clone https://dev.example.com/repo/my-project
150137
151138
The `/repo` addition is the key: whatever comes after is used as the
152139
repository name. [See the docs][clone] for more details.
153140
154
-[caod]: https://fossil-scm.org/forum/forumpost/3f143cec74
141
+[caod]: https://fossil-scm.org/forum/forumpost/3f143cec74
142
+[clone]: /help?cmd=clone
155143
156144
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
157145
--- www/ckout-workflows.md
+++ www/ckout-workflows.md
@@ -2,12 +2,11 @@
2
3 Because Fossil separates the concept of “check-out directory” from
4 “repository DB file,” it gives you the freedom to choose from several
5 working styles. Contrast Git, where the two concepts are normally
6 intermingled in a single working directory, which strongly encourages
7 the “update in place” working style, leaving its `git-worktree` feature
8 underutilized.
9
10
11 ## <a id="mcw"></a> Multiple-Checkout Workflow
12
13 With Fossil, it is routine to have multiple check-outs from the same
@@ -48,13 +47,13 @@
48
49 Each check-out operates independently of the others.
50
51 This multiple-checkouts working style is especially useful when Fossil stores source code in programming languages
52 where there is a “build” step that transforms source files into files
53 you actually run or distribute. With Git’s typical switch-in-place workflow,
54 you have to rebuild all outputs from the source files
55 that differ between those versions whenever you switch versions. In the above Fossil working model,
56 you switch versions with a “`cd`” command instead, so that you only have
57 to rebuild outputs from files you yourself change.
58
59 This style is also useful when a check-out directory may be tied up with
60 some long-running process, as with the “test” example above, where you
@@ -72,13 +71,13 @@
72 Nevertheless, it is possible to work in a more typical Git sort of
73 style, switching between versions in a single check-out directory.
74
75 #### <a id="idiomatic"></a> The Idiomatic Fossil Way
76
77 With the clone done as in [the prior section](#mdw), the most idiomatic
78 way is as follows:
79
 
80 mkdir work-dir
81 cd work-dir
82 fossil open /path/to/repo.fossil
83 ...work on trunk...
84
@@ -87,56 +86,44 @@
87
88 Basically, you replace the `cd` commands in the multiple checkouts
89 workflow above with `fossil up` commands.
90
91
92 #### <a id="open"></a> The Clone-and-Open Way
93
94 In Fossil 2.12, we added a feature that allows you to get closer to
95 Git’s single-step clone-and-open behavior:
96
97 mkdir work-dir
98 cd work-dir
99 fossil open https://example.com/repo
100
101 Now you have “trunk” open in `work-dir`, with the repo file stored as
102 `repo.fossil` in that same directory.
103
104 The use of [`fossil open`][open] here instead of [`fossil clone`][clone]
105 is likely to surprise a Git user. When we were [discussing][caod]
106 this, we considered following the Git command style, but we decided
107 against it because it goes against this core Fossil design principle:
108 given that the Fossil repo is separate from the check-out, why would you
109 expect asking for a repo clone to also create a check-out directory for
110 you? We view commingled repository + check-out as a design error in
111 Git, so why would we repeat the error?
112
113 To see why we see this behavior is error-prone, consider that
114 `git clean` must have an exception to avoid nuking the `.git` directory.
115 We had to add that complication to `fossil clean` when we added the
116 `fossil open URI` feature: it won’t nuke the repo DB file.
117
118 [clone]: /help?cmd=clone
119 [open]: /help?cmd=open
120
121
122 #### <a id="clone"></a> The Git Clone Way
123
124 This feature didn’t placate many Git fans, though, so with Fossil 2.14 —
125 currently unreleased — we now allow this:
126
127 fossil clone https://fossil-scm.org/fossil
 
128
129 This results in a `fossil.fossil` repo DB file and a `fossil/` working
130 directory.
131
132 Note that our `clone URI` behavior does not commingle the repo and
133 check-out, solving our major problem with the Git design, though we
134 still believe it to be confusing to have “clone” be part of “open,” and
135 still more confusing to have “open” part of “clone.” We prefer keeping
136 these operations entirely separate, either as at the [top of this
137 section](#scw) or [as in the prior one](#mcw). Still, please yourself.
138
139 If you want the repo to be named something else, adjust the URL:
140
141 fossil clone https://fossil-scm.org/fossil/fsl
142
@@ -149,8 +136,9 @@
149 fossil clone https://dev.example.com/repo/my-project
150
151 The `/repo` addition is the key: whatever comes after is used as the
152 repository name. [See the docs][clone] for more details.
153
154 [caod]: https://fossil-scm.org/forum/forumpost/3f143cec74
 
155
156 <div style="height:50em" id="this-space-intentionally-left-blank"></div>
157
--- www/ckout-workflows.md
+++ www/ckout-workflows.md
@@ -2,12 +2,11 @@
2
3 Because Fossil separates the concept of “check-out directory” from
4 “repository DB file,” it gives you the freedom to choose from several
5 working styles. Contrast Git, where the two concepts are normally
6 intermingled in a single working directory, which strongly encourages
7 the “update in place” working style.
 
8
9
10 ## <a id="mcw"></a> Multiple-Checkout Workflow
11
12 With Fossil, it is routine to have multiple check-outs from the same
@@ -48,13 +47,13 @@
47
48 Each check-out operates independently of the others.
49
50 This multiple-checkouts working style is especially useful when Fossil stores source code in programming languages
51 where there is a “build” step that transforms source files into files
52 you actually run or distribute. Contrast a switch-in-place workflow,
53 where you have to rebuild all outputs from the source files
54 that differ between those versions whenever you switch versions. In the above model,
55 you switch versions with a “`cd`” command instead, so that you only have
56 to rebuild outputs from files you yourself change.
57
58 This style is also useful when a check-out directory may be tied up with
59 some long-running process, as with the “test” example above, where you
@@ -72,13 +71,13 @@
71 Nevertheless, it is possible to work in a more typical Git sort of
72 style, switching between versions in a single check-out directory.
73
74 #### <a id="idiomatic"></a> The Idiomatic Fossil Way
75
76 The most idiomatic way is as follows:
 
77
78 fossil clone https://example.com/repo /path/to/repo.fossil
79 mkdir work-dir
80 cd work-dir
81 fossil open /path/to/repo.fossil
82 ...work on trunk...
83
@@ -87,56 +86,44 @@
86
87 Basically, you replace the `cd` commands in the multiple checkouts
88 workflow above with `fossil up` commands.
89
90
91 #### <a id="open"></a> Opening a Repository by URI
92
93 In Fossil 2.12, we added a feature to simplify the single-worktree use
94 case:
95
96 mkdir work-dir
97 cd work-dir
98 fossil open https://example.com/repo
99
100 Now you have “trunk” open in `work-dir`, with the repo file stored as
101 `repo.fossil` in that same directory.
102
103 Users of Git may be surprised that it doesn’t create a directory for you
104 and that you `cd` into it *before* the clone-and-open step, not after.
105 This is because we’re overloading the “open” command, which already had
106 the behavior of opening into the current working directory. Changing it
107 to behave like `git clone` would therefore make the behavior surprising
108 to Fossil users. (See [our discussions][caod] if you want the full
109 details.)
110
111
112 #### <a id="clone"></a> Git-Like Clone-and-Open
113
114 With Fossil 2.14 — currently unreleased — we added a more Git-like
115 alternative:
 
 
 
 
 
 
 
 
 
116
117 fossil clone https://fossil-scm.org/fossil
118 cd fossil
119
120 This results in a `fossil.fossil` repo DB file and a `fossil/` working
121 directory.
122
123 Note that our `clone URI` behavior does not commingle the repo and
124 check-out, solving our major problem with the Git design.
 
 
 
 
125
126 If you want the repo to be named something else, adjust the URL:
127
128 fossil clone https://fossil-scm.org/fossil/fsl
129
@@ -149,8 +136,9 @@
136 fossil clone https://dev.example.com/repo/my-project
137
138 The `/repo` addition is the key: whatever comes after is used as the
139 repository name. [See the docs][clone] for more details.
140
141 [caod]: https://fossil-scm.org/forum/forumpost/3f143cec74
142 [clone]: /help?cmd=clone
143
144 <div style="height:50em" id="this-space-intentionally-left-blank"></div>
145
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -56,11 +56,11 @@
5656
pull the documentation file from the local source tree on disk, not
5757
from the any check-in. The "<b>ckout</b>" keyword
5858
only works when you start your server using the
5959
"[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]"
6060
commands. The "/doc/ckout" URL is intended to show a preview of
61
-the documentation you are currently editing but have not yet you checked in.
61
+the documentation you are currently editing but have not yet checked in.
6262
6363
The original designed purpose of the "ckout" feature is to allow the
6464
user to preview local changes to documentation before committing the
6565
change. This is an important facility, since unlike other document
6666
languages like HTML, there is still a lot of variation among rendering
6767
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -56,11 +56,11 @@
56 pull the documentation file from the local source tree on disk, not
57 from the any check-in. The "<b>ckout</b>" keyword
58 only works when you start your server using the
59 "[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]"
60 commands. The "/doc/ckout" URL is intended to show a preview of
61 the documentation you are currently editing but have not yet you checked in.
62
63 The original designed purpose of the "ckout" feature is to allow the
64 user to preview local changes to documentation before committing the
65 change. This is an important facility, since unlike other document
66 languages like HTML, there is still a lot of variation among rendering
67
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -56,11 +56,11 @@
56 pull the documentation file from the local source tree on disk, not
57 from the any check-in. The "<b>ckout</b>" keyword
58 only works when you start your server using the
59 "[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]"
60 commands. The "/doc/ckout" URL is intended to show a preview of
61 the documentation you are currently editing but have not yet checked in.
62
63 The original designed purpose of the "ckout" feature is to allow the
64 user to preview local changes to documentation before committing the
65 change. This is an important facility, since unlike other document
66 languages like HTML, there is still a lot of variation among rendering
67
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -253,22 +253,22 @@
253253
254254
With Git, one can easily locate the ancestors of a particular check-in
255255
by following the pointers embedded in the check-in object, but it is
256256
difficult to go the other direction and locate the descendants of a
257257
check-in. It is so difficult, in fact, that neither native Git nor
258
-GitHub provide this capability short of
259
-[http://catb.org/jargon/html/G/grovel.html|groveling] the
258
+GitHub provide this capability short of crawling the
260259
[https://www.git-scm.com/docs/git-log|commit log]. With Git, if you
261260
are looking at some historical check-in then you cannot ask "What came
262261
next?" or "What are the children of this check-in?"
263262
264263
Fossil, on the other hand, parses essential information about check-ins
265264
(parents, children, committers, comments, files changed, etc.) into a
266265
relational database that can easily be queried using concise SQL
267266
statements to find both ancestors and descendants of a check-in. This is
268267
the hybrid data model mentioned above: Fossil manages your check-in and
269
-other data in a NoSQL block chain structured data store, but that's backed
268
+other data in a NoSQL [https://en.wikipedia.org/wiki/Merkle_tree |
269
+Merkle tree] structured data store, but that's backed
270270
by a set of relational lookup tables for quick indexing into that
271271
artifact store. (See "[./theory1.wiki|Thoughts On The Design Of The
272272
Fossil DVCS]" for more details.)
273273
274274
Leaf check-ins in Git that lack a "ref" become "detached," making them
@@ -276,11 +276,11 @@
276276
[http://gitfaq.org/articles/what-is-a-detached-head.html|detached head
277277
state] problem has caused untold grief for
278278
[https://www.google.com/search?q=git+detached+head+state | a huge number
279279
of Git users]. With
280280
Fossil, detached heads are simply impossible because we can always find
281
-our way back into the block chain using one or more of the relational
281
+our way back into the Merkle tree using one or more of the relational
282282
indices it automatically manages for you.
283283
284284
This design difference shows up in several other places within each
285285
tool. It is why Fossil's [/help?cmd=timeline|timeline] is generally more
286286
detailed yet more clear than those available in Git front-ends.
@@ -906,11 +906,11 @@
906906
Almost three years after Fossil solved this problem, the
907907
[https://sha-mbles.github.io/ | SHAmbles attack] was published, further
908908
weakening the case for continuing to use SHA-1.
909909
910910
The practical impact of attacks like SHAttered and SHAmbles on the
911
-Git and Fossil blockchains isn't clear, but you want to have your repositories
911
+Git and Fossil Merkle trees isn't clear, but you want to have your repositories
912912
moved over to a stronger hash algorithm before someone figures out how
913913
to make use of the weaknesses in the old one. Fossil has had this covered
914914
for years now, so that the solution is now almost universally deployed.
915915
916916
<hr/>
@@ -936,11 +936,11 @@
936936
isn't normally synchronized with a "<tt>fossil clone</tt>" command unless
937937
you add the "-u" option. (See "[./aboutdownload.wiki|How the
938938
Download Page Works]" for details.) There may also be some purely
939939
static elements of the web site served via D. Richard Hipp's own
940940
lightweight web server,
941
- <tt>[https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md|althttpd]</tt>,
941
+ <tt>[https://sqlite.org/althttpd/|althttpd]</tt>,
942942
which is configured as a front end to Fossil running in CGI mode on
943943
these sites.
944944
945945
<li><p>That estimate is based on pricing at Digital Ocean in
946946
mid-2019: Fossil will run just fine on the smallest instance they
947947
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -253,22 +253,22 @@
253
254 With Git, one can easily locate the ancestors of a particular check-in
255 by following the pointers embedded in the check-in object, but it is
256 difficult to go the other direction and locate the descendants of a
257 check-in. It is so difficult, in fact, that neither native Git nor
258 GitHub provide this capability short of
259 [http://catb.org/jargon/html/G/grovel.html|groveling] the
260 [https://www.git-scm.com/docs/git-log|commit log]. With Git, if you
261 are looking at some historical check-in then you cannot ask "What came
262 next?" or "What are the children of this check-in?"
263
264 Fossil, on the other hand, parses essential information about check-ins
265 (parents, children, committers, comments, files changed, etc.) into a
266 relational database that can easily be queried using concise SQL
267 statements to find both ancestors and descendants of a check-in. This is
268 the hybrid data model mentioned above: Fossil manages your check-in and
269 other data in a NoSQL block chain structured data store, but that's backed
 
270 by a set of relational lookup tables for quick indexing into that
271 artifact store. (See "[./theory1.wiki|Thoughts On The Design Of The
272 Fossil DVCS]" for more details.)
273
274 Leaf check-ins in Git that lack a "ref" become "detached," making them
@@ -276,11 +276,11 @@
276 [http://gitfaq.org/articles/what-is-a-detached-head.html|detached head
277 state] problem has caused untold grief for
278 [https://www.google.com/search?q=git+detached+head+state | a huge number
279 of Git users]. With
280 Fossil, detached heads are simply impossible because we can always find
281 our way back into the block chain using one or more of the relational
282 indices it automatically manages for you.
283
284 This design difference shows up in several other places within each
285 tool. It is why Fossil's [/help?cmd=timeline|timeline] is generally more
286 detailed yet more clear than those available in Git front-ends.
@@ -906,11 +906,11 @@
906 Almost three years after Fossil solved this problem, the
907 [https://sha-mbles.github.io/ | SHAmbles attack] was published, further
908 weakening the case for continuing to use SHA-1.
909
910 The practical impact of attacks like SHAttered and SHAmbles on the
911 Git and Fossil blockchains isn't clear, but you want to have your repositories
912 moved over to a stronger hash algorithm before someone figures out how
913 to make use of the weaknesses in the old one. Fossil has had this covered
914 for years now, so that the solution is now almost universally deployed.
915
916 <hr/>
@@ -936,11 +936,11 @@
936 isn't normally synchronized with a "<tt>fossil clone</tt>" command unless
937 you add the "-u" option. (See "[./aboutdownload.wiki|How the
938 Download Page Works]" for details.) There may also be some purely
939 static elements of the web site served via D. Richard Hipp's own
940 lightweight web server,
941 <tt>[https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md|althttpd]</tt>,
942 which is configured as a front end to Fossil running in CGI mode on
943 these sites.
944
945 <li><p>That estimate is based on pricing at Digital Ocean in
946 mid-2019: Fossil will run just fine on the smallest instance they
947
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -253,22 +253,22 @@
253
254 With Git, one can easily locate the ancestors of a particular check-in
255 by following the pointers embedded in the check-in object, but it is
256 difficult to go the other direction and locate the descendants of a
257 check-in. It is so difficult, in fact, that neither native Git nor
258 GitHub provide this capability short of crawling the
 
259 [https://www.git-scm.com/docs/git-log|commit log]. With Git, if you
260 are looking at some historical check-in then you cannot ask "What came
261 next?" or "What are the children of this check-in?"
262
263 Fossil, on the other hand, parses essential information about check-ins
264 (parents, children, committers, comments, files changed, etc.) into a
265 relational database that can easily be queried using concise SQL
266 statements to find both ancestors and descendants of a check-in. This is
267 the hybrid data model mentioned above: Fossil manages your check-in and
268 other data in a NoSQL [https://en.wikipedia.org/wiki/Merkle_tree |
269 Merkle tree] structured data store, but that's backed
270 by a set of relational lookup tables for quick indexing into that
271 artifact store. (See "[./theory1.wiki|Thoughts On The Design Of The
272 Fossil DVCS]" for more details.)
273
274 Leaf check-ins in Git that lack a "ref" become "detached," making them
@@ -276,11 +276,11 @@
276 [http://gitfaq.org/articles/what-is-a-detached-head.html|detached head
277 state] problem has caused untold grief for
278 [https://www.google.com/search?q=git+detached+head+state | a huge number
279 of Git users]. With
280 Fossil, detached heads are simply impossible because we can always find
281 our way back into the Merkle tree using one or more of the relational
282 indices it automatically manages for you.
283
284 This design difference shows up in several other places within each
285 tool. It is why Fossil's [/help?cmd=timeline|timeline] is generally more
286 detailed yet more clear than those available in Git front-ends.
@@ -906,11 +906,11 @@
906 Almost three years after Fossil solved this problem, the
907 [https://sha-mbles.github.io/ | SHAmbles attack] was published, further
908 weakening the case for continuing to use SHA-1.
909
910 The practical impact of attacks like SHAttered and SHAmbles on the
911 Git and Fossil Merkle trees isn't clear, but you want to have your repositories
912 moved over to a stronger hash algorithm before someone figures out how
913 to make use of the weaknesses in the old one. Fossil has had this covered
914 for years now, so that the solution is now almost universally deployed.
915
916 <hr/>
@@ -936,11 +936,11 @@
936 isn't normally synchronized with a "<tt>fossil clone</tt>" command unless
937 you add the "-u" option. (See "[./aboutdownload.wiki|How the
938 Download Page Works]" for details.) There may also be some purely
939 static elements of the web site served via D. Richard Hipp's own
940 lightweight web server,
941 <tt>[https://sqlite.org/althttpd/|althttpd]</tt>,
942 which is configured as a front end to Fossil running in CGI mode on
943 these sites.
944
945 <li><p>That estimate is based on pricing at Digital Ocean in
946 mid-2019: Fossil will run just fine on the smallest instance they
947
+18 -10
--- www/gitusers.md
+++ www/gitusers.md
@@ -687,20 +687,28 @@
687687
view][infow], though.
688688
689689
690690
#### <a name="dstat"></a> Diff Statistics
691691
692
-Fossil doesn’t have an internal equivalent to commands like
693
-`git show --stat`, but it’s easily remedied by using
694
-[the widely-available `diffstat` tool][dst]:
695
-
696
- fossil diff -i --from 2020-04-01 | diffstat
697
-
698
-We gave the `-i` flag here to force Fossil to use its internal diff
699
-implementation, bypassing [your local `diff-command` setting][dcset].
700
-If you had that set to [`colordiff`][cdiff], for example, its output
701
-would confuse `diffstat`.
692
+Fossil’s closest internal equivalent to commands like
693
+`git show --stat` is:
694
+
695
+ fossil diff -i --from 2020-04-01 --numstat
696
+
697
+The `--numstat` output is a bit cryptic, so we recommend delegating
698
+this task to [the widely-available `diffstat` tool][dst]:
699
+
700
+ fossil diff -i -N --from 2020-04-01 | diffstat
701
+
702
+We gave the `-i` flag in both cases to force Fossil to use its internal
703
+diff implementation, bypassing [your local `diff-command` setting][dcset].
704
+The `--numstat` option has no effect when you have an external diff
705
+command set, and some diff command alternatives like
706
+[`colordiff`][cdiff] produce output that confuses `diffstat`.
707
+
708
+If you leave off the `-N` flag in the second example, the `diffstat`
709
+output won’t include info about any newly-added files.
702710
703711
[cdiff]: https://www.colordiff.org/
704712
[dcset]: https://fossil-scm.org/home/help?cmd=diff-command
705713
[dst]: https://invisible-island.net/diffstat/diffstat.html
706714
707715
--- www/gitusers.md
+++ www/gitusers.md
@@ -687,20 +687,28 @@
687 view][infow], though.
688
689
690 #### <a name="dstat"></a> Diff Statistics
691
692 Fossil doesn’t have an internal equivalent to commands like
693 `git show --stat`, but it’s easily remedied by using
694 [the widely-available `diffstat` tool][dst]:
695
696 fossil diff -i --from 2020-04-01 | diffstat
697
698 We gave the `-i` flag here to force Fossil to use its internal diff
699 implementation, bypassing [your local `diff-command` setting][dcset].
700 If you had that set to [`colordiff`][cdiff], for example, its output
701 would confuse `diffstat`.
 
 
 
 
 
 
 
 
702
703 [cdiff]: https://www.colordiff.org/
704 [dcset]: https://fossil-scm.org/home/help?cmd=diff-command
705 [dst]: https://invisible-island.net/diffstat/diffstat.html
706
707
--- www/gitusers.md
+++ www/gitusers.md
@@ -687,20 +687,28 @@
687 view][infow], though.
688
689
690 #### <a name="dstat"></a> Diff Statistics
691
692 Fossil’s closest internal equivalent to commands like
693 `git show --stat` is:
694
695 fossil diff -i --from 2020-04-01 --numstat
696
697 The `--numstat` output is a bit cryptic, so we recommend delegating
698 this task to [the widely-available `diffstat` tool][dst]:
699
700 fossil diff -i -N --from 2020-04-01 | diffstat
701
702 We gave the `-i` flag in both cases to force Fossil to use its internal
703 diff implementation, bypassing [your local `diff-command` setting][dcset].
704 The `--numstat` option has no effect when you have an external diff
705 command set, and some diff command alternatives like
706 [`colordiff`][cdiff] produce output that confuses `diffstat`.
707
708 If you leave off the `-N` flag in the second example, the `diffstat`
709 output won’t include info about any newly-added files.
710
711 [cdiff]: https://www.colordiff.org/
712 [dcset]: https://fossil-scm.org/home/help?cmd=diff-command
713 [dst]: https://invisible-island.net/diffstat/diffstat.html
714
715
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -148,10 +148,11 @@
148148
<li> <a href='history.md'>Purpose and History of Fossil</a>
149149
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
150150
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
151151
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
152152
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
153
+<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
153154
<li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
154155
book</a>
155156
</ul>
156157
<a name="pindex"></a>
157158
<h2>Permuted Index:</h2>
158159
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -148,10 +148,11 @@
148 <li> <a href='history.md'>Purpose and History of Fossil</a>
149 <li> <a href='build.wiki'>Compiling and installing Fossil</a>
150 <li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
151 <li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
152 <li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
 
153 <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
154 book</a>
155 </ul>
156 <a name="pindex"></a>
157 <h2>Permuted Index:</h2>
158
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -148,10 +148,11 @@
148 <li> <a href='history.md'>Purpose and History of Fossil</a>
149 <li> <a href='build.wiki'>Compiling and installing Fossil</a>
150 <li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
151 <li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
152 <li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
153 <li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
154 <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
155 book</a>
156 </ul>
157 <a name="pindex"></a>
158 <h2>Permuted Index:</h2>
159
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -13,10 +13,11 @@
1313
<li> <a href='history.md'>Purpose and History of Fossil</a>
1414
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
1515
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
1616
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
1717
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
18
+<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
1819
<li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
1920
book</a>
2021
</ul>
2122
<a name="pindex"></a>
2223
<h2>Permuted Index:</h2>
2324
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -13,10 +13,11 @@
13 <li> <a href='history.md'>Purpose and History of Fossil</a>
14 <li> <a href='build.wiki'>Compiling and installing Fossil</a>
15 <li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
16 <li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
17 <li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
 
18 <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
19 book</a>
20 </ul>
21 <a name="pindex"></a>
22 <h2>Permuted Index:</h2>
23
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -13,10 +13,11 @@
13 <li> <a href='history.md'>Purpose and History of Fossil</a>
14 <li> <a href='build.wiki'>Compiling and installing Fossil</a>
15 <li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
16 <li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
17 <li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
18 <li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
19 <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's
20 book</a>
21 </ul>
22 <a name="pindex"></a>
23 <h2>Permuted Index:</h2>
24
+28 -45
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -297,63 +297,46 @@
297297
## <a name="lying"></a>5.0 Rebasing is lying about the project history
298298
299299
By discarding parentage information, rebase attempts to deceive the
300300
reader about how the code actually came together.
301301
302
-The [Git rebase documentation][gitrebase] admits as much. They acknowledge
303
-that when you view a repository as record of what actually happened,
304
-doing a rebase is "blasphemous" and "you're _lying_ about what
305
-actually happened", but then goes on to justify rebase as follows:
306
-
307
->
308
-_"The opposing point of view is that the commit history is the **story of
309
-how your project was made.** You wouldn't publish the first draft of a
310
-book, and the manual for how to maintain your software deserves careful
311
-editing. This is the camp that uses tools like rebase and filter-branch
312
-to tell the story in the way that's best for future readers."_
313
-
314
-This counter-argument assumes you must
315
-change history in order to enhance readability, which is not true.
316
-
317
-In fairness to the Git documentation authors, changing the
318
-project history appears to be the only way to make editorial
319
-changes in Git.
320
-But it does not have to be that way.
321
-Fossil demonstrates how "the story of your project"
322
-can be enhanced without changing the actual history
323
-by allowing users to:
302
+You may be tempted to dismiss this as an anti-Git opinion on a Fossil
303
+web site, but it’s spelled out just like that [in the Git rebase
304
+documentation][gitrebase]. It speaks of “lying,” “telling stories,”
305
+and “blasphemy.”
306
+
307
+That section of the Git docs is contrasting rebase with merge, which we
308
+cover [above](#cap-loss), but Git’s rebase feature is more than just an
309
+alternative to merging: it also provides mechanisms for changing the
310
+project history in order to make editorial changes. Fossil shows that
311
+you can get similar effects without modifying historical records,
312
+allowing users to:
324313
325314
1. Edit check-in comments to fix typos or enhance clarity
326315
2. Attach supplemental notes to check-ins or whole branches
327
- 3. Cross-reference check-ins with each other, or with
328
- wiki, tickets, forum posts, and/or embedded documentation
329
- 4. Hide ill-conceived or now-unused branches from routine display
330
- 5. Fix faulty check-in date/times resulting from misconfigured
316
+ 3. Hide ill-conceived or now-unused branches from routine display
317
+ 4. Fix faulty check-in date/times resulting from misconfigured
331318
system clocks
319
+ 5. Cross-reference check-ins with each other, or with
320
+ wiki, tickets, forum posts, and/or embedded documentation
332321
333322
…and so forth.
334323
335
-These changes are accomplished not by removing or modifying existing
324
+Fossil allows all of this not by removing or modifying existing
336325
repository entries, but rather by adding new supplemental records.
337
-The original incorrect or unclear inputs are preserved and are
338
-readily accessible. The original history is preserved.
339
-But for routine display purposes, the more
340
-readable edited presentation is provided.
341
-
342
-A repository can be a true and accurate
343
-representation of history even without getting everything perfect
344
-on the first draft. Those are not contradictory goals, at least
345
-not in theory.
346
-
347
-Unfortunately, Git does not currently provide the ability to add
348
-corrections or clarifications or supplimental notes to historical check-ins.
349
-Hence, once again,
350
-rebase can be seen as an attempt to work around limitations
351
-of Git. Git could be enhanced to support editorial changes
352
-to check-ins.
353
-Wouldn't it be better to fix the version control tool
354
-rather than requiring users to fabricate a fictitious project history?
326
+Fossil keeps the original incorrect or unclear inputs and makes them
327
+readily accessible, preserving the original historical record. Fossil
328
+doesn’t make the user tell counter-factual “stories,” it only allows the
329
+user to provide annotations to provide a more readable edited
330
+presentation for routine display purposes.
331
+
332
+Git needs rebase because it lacks these annotation facilities. Rather
333
+than consider rebase a desirable feature missing in Fossil, ask instead
334
+why Git lacks support for making editorial changes to check-ins without
335
+modifyihng history? Wouldn't it be better to fix the version control
336
+tool rather than requiring users to fabricate a fictitious project
337
+history?
355338
356339
## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information
357340
358341
One of the oft-cited advantages of rebasing in Git is that it lets you
359342
collapse multiple check-ins down to a single check-in to make the
360343
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -297,63 +297,46 @@
297 ## <a name="lying"></a>5.0 Rebasing is lying about the project history
298
299 By discarding parentage information, rebase attempts to deceive the
300 reader about how the code actually came together.
301
302 The [Git rebase documentation][gitrebase] admits as much. They acknowledge
303 that when you view a repository as record of what actually happened,
304 doing a rebase is "blasphemous" and "you're _lying_ about what
305 actually happened", but then goes on to justify rebase as follows:
306
307 >
308 _"The opposing point of view is that the commit history is the **story of
309 how your project was made.** You wouldn't publish the first draft of a
310 book, and the manual for how to maintain your software deserves careful
311 editing. This is the camp that uses tools like rebase and filter-branch
312 to tell the story in the way that's best for future readers."_
313
314 This counter-argument assumes you must
315 change history in order to enhance readability, which is not true.
316
317 In fairness to the Git documentation authors, changing the
318 project history appears to be the only way to make editorial
319 changes in Git.
320 But it does not have to be that way.
321 Fossil demonstrates how "the story of your project"
322 can be enhanced without changing the actual history
323 by allowing users to:
324
325 1. Edit check-in comments to fix typos or enhance clarity
326 2. Attach supplemental notes to check-ins or whole branches
327 3. Cross-reference check-ins with each other, or with
328 wiki, tickets, forum posts, and/or embedded documentation
329 4. Hide ill-conceived or now-unused branches from routine display
330 5. Fix faulty check-in date/times resulting from misconfigured
331 system clocks
 
 
332
333 …and so forth.
334
335 These changes are accomplished not by removing or modifying existing
336 repository entries, but rather by adding new supplemental records.
337 The original incorrect or unclear inputs are preserved and are
338 readily accessible. The original history is preserved.
339 But for routine display purposes, the more
340 readable edited presentation is provided.
341
342 A repository can be a true and accurate
343 representation of history even without getting everything perfect
344 on the first draft. Those are not contradictory goals, at least
345 not in theory.
346
347 Unfortunately, Git does not currently provide the ability to add
348 corrections or clarifications or supplimental notes to historical check-ins.
349 Hence, once again,
350 rebase can be seen as an attempt to work around limitations
351 of Git. Git could be enhanced to support editorial changes
352 to check-ins.
353 Wouldn't it be better to fix the version control tool
354 rather than requiring users to fabricate a fictitious project history?
355
356 ## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information
357
358 One of the oft-cited advantages of rebasing in Git is that it lets you
359 collapse multiple check-ins down to a single check-in to make the
360
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -297,63 +297,46 @@
297 ## <a name="lying"></a>5.0 Rebasing is lying about the project history
298
299 By discarding parentage information, rebase attempts to deceive the
300 reader about how the code actually came together.
301
302 You may be tempted to dismiss this as an anti-Git opinion on a Fossil
303 web site, but it’s spelled out just like that [in the Git rebase
304 documentation][gitrebase]. It speaks of “lying,” “telling stories,”
305 and “blasphemy.”
306
307 That section of the Git docs is contrasting rebase with merge, which we
308 cover [above](#cap-loss), but Git’s rebase feature is more than just an
309 alternative to merging: it also provides mechanisms for changing the
310 project history in order to make editorial changes. Fossil shows that
311 you can get similar effects without modifying historical records,
312 allowing users to:
 
 
 
 
 
 
 
 
 
 
 
313
314 1. Edit check-in comments to fix typos or enhance clarity
315 2. Attach supplemental notes to check-ins or whole branches
316 3. Hide ill-conceived or now-unused branches from routine display
317 4. Fix faulty check-in date/times resulting from misconfigured
 
 
318 system clocks
319 5. Cross-reference check-ins with each other, or with
320 wiki, tickets, forum posts, and/or embedded documentation
321
322 …and so forth.
323
324 Fossil allows all of this not by removing or modifying existing
325 repository entries, but rather by adding new supplemental records.
326 Fossil keeps the original incorrect or unclear inputs and makes them
327 readily accessible, preserving the original historical record. Fossil
328 doesn’t make the user tell counter-factual “stories,” it only allows the
329 user to provide annotations to provide a more readable edited
330 presentation for routine display purposes.
331
332 Git needs rebase because it lacks these annotation facilities. Rather
333 than consider rebase a desirable feature missing in Fossil, ask instead
334 why Git lacks support for making editorial changes to check-ins without
335 modifyihng history? Wouldn't it be better to fix the version control
336 tool rather than requiring users to fabricate a fictitious project
337 history?
 
 
 
 
 
 
338
339 ## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information
340
341 One of the oft-cited advantages of rebasing in Git is that it lets you
342 collapse multiple check-ins down to a single check-in to make the
343
+28 -45
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -297,63 +297,46 @@
297297
## <a name="lying"></a>5.0 Rebasing is lying about the project history
298298
299299
By discarding parentage information, rebase attempts to deceive the
300300
reader about how the code actually came together.
301301
302
-The [Git rebase documentation][gitrebase] admits as much. They acknowledge
303
-that when you view a repository as record of what actually happened,
304
-doing a rebase is "blasphemous" and "you're _lying_ about what
305
-actually happened", but then goes on to justify rebase as follows:
306
-
307
->
308
-_"The opposing point of view is that the commit history is the **story of
309
-how your project was made.** You wouldn't publish the first draft of a
310
-book, and the manual for how to maintain your software deserves careful
311
-editing. This is the camp that uses tools like rebase and filter-branch
312
-to tell the story in the way that's best for future readers."_
313
-
314
-This counter-argument assumes you must
315
-change history in order to enhance readability, which is not true.
316
-
317
-In fairness to the Git documentation authors, changing the
318
-project history appears to be the only way to make editorial
319
-changes in Git.
320
-But it does not have to be that way.
321
-Fossil demonstrates how "the story of your project"
322
-can be enhanced without changing the actual history
323
-by allowing users to:
302
+You may be tempted to dismiss this as an anti-Git opinion on a Fossil
303
+web site, but it’s spelled out just like that [in the Git rebase
304
+documentation][gitrebase]. It speaks of “lying,” “telling stories,”
305
+and “blasphemy.”
306
+
307
+That section of the Git docs is contrasting rebase with merge, which we
308
+cover [above](#cap-loss), but Git’s rebase feature is more than just an
309
+alternative to merging: it also provides mechanisms for changing the
310
+project history in order to make editorial changes. Fossil shows that
311
+you can get similar effects without modifying historical records,
312
+allowing users to:
324313
325314
1. Edit check-in comments to fix typos or enhance clarity
326315
2. Attach supplemental notes to check-ins or whole branches
327
- 3. Cross-reference check-ins with each other, or with
328
- wiki, tickets, forum posts, and/or embedded documentation
329
- 4. Hide ill-conceived or now-unused branches from routine display
330
- 5. Fix faulty check-in date/times resulting from misconfigured
316
+ 3. Hide ill-conceived or now-unused branches from routine display
317
+ 4. Fix faulty check-in date/times resulting from misconfigured
331318
system clocks
319
+ 5. Cross-reference check-ins with each other, or with
320
+ wiki, tickets, forum posts, and/or embedded documentation
332321
333322
…and so forth.
334323
335
-These changes are accomplished not by removing or modifying existing
324
+Fossil allows all of this not by removing or modifying existing
336325
repository entries, but rather by adding new supplemental records.
337
-The original incorrect or unclear inputs are preserved and are
338
-readily accessible. The original history is preserved.
339
-But for routine display purposes, the more
340
-readable edited presentation is provided.
341
-
342
-A repository can be a true and accurate
343
-representation of history even without getting everything perfect
344
-on the first draft. Those are not contradictory goals, at least
345
-not in theory.
346
-
347
-Unfortunately, Git does not currently provide the ability to add
348
-corrections or clarifications or supplimental notes to historical check-ins.
349
-Hence, once again,
350
-rebase can be seen as an attempt to work around limitations
351
-of Git. Git could be enhanced to support editorial changes
352
-to check-ins.
353
-Wouldn't it be better to fix the version control tool
354
-rather than requiring users to fabricate a fictitious project history?
326
+Fossil keeps the original incorrect or unclear inputs and makes them
327
+readily accessible, preserving the original historical record. Fossil
328
+doesn’t make the user tell counter-factual “stories,” it only allows the
329
+user to provide annotations to provide a more readable edited
330
+presentation for routine display purposes.
331
+
332
+Git needs rebase because it lacks these annotation facilities. Rather
333
+than consider rebase a desirable feature missing in Fossil, ask instead
334
+why Git lacks support for making editorial changes to check-ins without
335
+modifyihng history? Wouldn't it be better to fix the version control
336
+tool rather than requiring users to fabricate a fictitious project
337
+history?
355338
356339
## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information
357340
358341
One of the oft-cited advantages of rebasing in Git is that it lets you
359342
collapse multiple check-ins down to a single check-in to make the
360343
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -297,63 +297,46 @@
297 ## <a name="lying"></a>5.0 Rebasing is lying about the project history
298
299 By discarding parentage information, rebase attempts to deceive the
300 reader about how the code actually came together.
301
302 The [Git rebase documentation][gitrebase] admits as much. They acknowledge
303 that when you view a repository as record of what actually happened,
304 doing a rebase is "blasphemous" and "you're _lying_ about what
305 actually happened", but then goes on to justify rebase as follows:
306
307 >
308 _"The opposing point of view is that the commit history is the **story of
309 how your project was made.** You wouldn't publish the first draft of a
310 book, and the manual for how to maintain your software deserves careful
311 editing. This is the camp that uses tools like rebase and filter-branch
312 to tell the story in the way that's best for future readers."_
313
314 This counter-argument assumes you must
315 change history in order to enhance readability, which is not true.
316
317 In fairness to the Git documentation authors, changing the
318 project history appears to be the only way to make editorial
319 changes in Git.
320 But it does not have to be that way.
321 Fossil demonstrates how "the story of your project"
322 can be enhanced without changing the actual history
323 by allowing users to:
324
325 1. Edit check-in comments to fix typos or enhance clarity
326 2. Attach supplemental notes to check-ins or whole branches
327 3. Cross-reference check-ins with each other, or with
328 wiki, tickets, forum posts, and/or embedded documentation
329 4. Hide ill-conceived or now-unused branches from routine display
330 5. Fix faulty check-in date/times resulting from misconfigured
331 system clocks
 
 
332
333 …and so forth.
334
335 These changes are accomplished not by removing or modifying existing
336 repository entries, but rather by adding new supplemental records.
337 The original incorrect or unclear inputs are preserved and are
338 readily accessible. The original history is preserved.
339 But for routine display purposes, the more
340 readable edited presentation is provided.
341
342 A repository can be a true and accurate
343 representation of history even without getting everything perfect
344 on the first draft. Those are not contradictory goals, at least
345 not in theory.
346
347 Unfortunately, Git does not currently provide the ability to add
348 corrections or clarifications or supplimental notes to historical check-ins.
349 Hence, once again,
350 rebase can be seen as an attempt to work around limitations
351 of Git. Git could be enhanced to support editorial changes
352 to check-ins.
353 Wouldn't it be better to fix the version control tool
354 rather than requiring users to fabricate a fictitious project history?
355
356 ## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information
357
358 One of the oft-cited advantages of rebasing in Git is that it lets you
359 collapse multiple check-ins down to a single check-in to make the
360
--- www/rebaseharm.md
+++ www/rebaseharm.md
@@ -297,63 +297,46 @@
297 ## <a name="lying"></a>5.0 Rebasing is lying about the project history
298
299 By discarding parentage information, rebase attempts to deceive the
300 reader about how the code actually came together.
301
302 You may be tempted to dismiss this as an anti-Git opinion on a Fossil
303 web site, but it’s spelled out just like that [in the Git rebase
304 documentation][gitrebase]. It speaks of “lying,” “telling stories,”
305 and “blasphemy.”
306
307 That section of the Git docs is contrasting rebase with merge, which we
308 cover [above](#cap-loss), but Git’s rebase feature is more than just an
309 alternative to merging: it also provides mechanisms for changing the
310 project history in order to make editorial changes. Fossil shows that
311 you can get similar effects without modifying historical records,
312 allowing users to:
 
 
 
 
 
 
 
 
 
 
 
313
314 1. Edit check-in comments to fix typos or enhance clarity
315 2. Attach supplemental notes to check-ins or whole branches
316 3. Hide ill-conceived or now-unused branches from routine display
317 4. Fix faulty check-in date/times resulting from misconfigured
 
 
318 system clocks
319 5. Cross-reference check-ins with each other, or with
320 wiki, tickets, forum posts, and/or embedded documentation
321
322 …and so forth.
323
324 Fossil allows all of this not by removing or modifying existing
325 repository entries, but rather by adding new supplemental records.
326 Fossil keeps the original incorrect or unclear inputs and makes them
327 readily accessible, preserving the original historical record. Fossil
328 doesn’t make the user tell counter-factual “stories,” it only allows the
329 user to provide annotations to provide a more readable edited
330 presentation for routine display purposes.
331
332 Git needs rebase because it lacks these annotation facilities. Rather
333 than consider rebase a desirable feature missing in Fossil, ask instead
334 why Git lacks support for making editorial changes to check-ins without
335 modifyihng history? Wouldn't it be better to fix the version control
336 tool rather than requiring users to fabricate a fictitious project
337 history?
 
 
 
 
 
 
338
339 ## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information
340
341 One of the oft-cited advantages of rebasing in Git is that it lets you
342 collapse multiple check-ins down to a single check-in to make the
343
--- www/server/any/althttpd.md
+++ www/server/any/althttpd.md
@@ -36,7 +36,7 @@
3636
you created to start using your Fossil server.
3737
3838
*[Return to the top-level Fossil server article.](../)*
3939
4040
41
-[althttpd]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md
41
+[althttpd]: https://sqlite.org/althttpd/
4242
[cgi]: ../../cgi.wiki
4343
--- www/server/any/althttpd.md
+++ www/server/any/althttpd.md
@@ -36,7 +36,7 @@
36 you created to start using your Fossil server.
37
38 *[Return to the top-level Fossil server article.](../)*
39
40
41 [althttpd]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md
42 [cgi]: ../../cgi.wiki
43
--- www/server/any/althttpd.md
+++ www/server/any/althttpd.md
@@ -36,7 +36,7 @@
36 you created to start using your Fossil server.
37
38 *[Return to the top-level Fossil server article.](../)*
39
40
41 [althttpd]: https://sqlite.org/althttpd/
42 [cgi]: ../../cgi.wiki
43
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -217,25 +217,46 @@
217217
The most common thing people get wrong when hand-rolling a configuration
218218
like this is to get the slashes wrong. Fossil is sensitive to this. For
219219
instance, Fossil will not collapse double slashes down to a single
220220
slash, as some other HTTP servers will.
221221
222
+
223
+## <a name="large-uv"></a> Allowing Large Unversioned Files
224
+
225
+By default, nginx only accepts HTTP messages [up to a
226
+meg](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)
227
+in size. Fossil chunks its sync protocol such that this is not normally
228
+a problem, but when sending [unversioned content][uv], it uses a single
229
+message for the entire file. Therefore, if you will be storing files
230
+larger than this limit as unversioned content, you need to raise the
231
+limit. Within the `location` block:
232
+
233
+ # Allow large unversioned file uploads, such as PDFs
234
+ client_max_body_size 20M;
235
+
236
+[uv]: ../../unvers.wiki
237
+
222238
223239
## <a name="fail2ban"></a> Integrating `fail2ban`
224240
225
-You can have `fail2ban` recognize attacks and automatically block them,
226
-but the stock configuration doesn’t work with our Fossil setup above, so
227
-we have to do a bit of local adjustment.
241
+One of the nice things that falls out of proxying Fossil behind nginx is
242
+that it makes it easier to configure `fail2ban` to recognize attacks on
243
+Fossil and automatically block them. Fossil logs the sorts of errors we
244
+want to detect, but it does so in places like the repository’s admin
245
+log, a SQL table, which `fail2ban` doesn’t know how to query. By putting
246
+Fossil behind an nginx proxy, we convert these failures to log file
247
+form, which `fail2ban` is designed to handle.
228248
229
-First, install it:
249
+First, install `fail2ban`, if you haven’t already:
230250
231251
sudo apt install fail2ban
232252
233
-Out of the box, you get SSH monitoring only. There are nginx monitors
234
-included with the package, but they don’t look in the right places for
235
-the right things. We’d like it to react to Fossil `/login` failures, for
236
-example. Put the following into
253
+We’d like `fail2ban` to react to Fossil `/login` failures. The stock
254
+configuration of `fail2ban` only detects a few common sorts of SSH
255
+attacks by default, and its included (but disabled) nginx attack
256
+detectors don’t include one that knows how to detect an attack on
257
+Fossil. We have to teach it by putting the following into
237258
`/etc/fail2ban/filter.d/nginx-fossil-login.conf`:
238259
239260
[Definition]
240261
failregex = ^<HOST> - .*POST .*/login HTTP/..." 401
241262
242263
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -217,25 +217,46 @@
217 The most common thing people get wrong when hand-rolling a configuration
218 like this is to get the slashes wrong. Fossil is sensitive to this. For
219 instance, Fossil will not collapse double slashes down to a single
220 slash, as some other HTTP servers will.
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
223 ## <a name="fail2ban"></a> Integrating `fail2ban`
224
225 You can have `fail2ban` recognize attacks and automatically block them,
226 but the stock configuration doesn’t work with our Fossil setup above, so
227 we have to do a bit of local adjustment.
 
 
 
 
228
229 First, install it:
230
231 sudo apt install fail2ban
232
233 Out of the box, you get SSH monitoring only. There are nginx monitors
234 included with the package, but they don’t look in the right places for
235 the right things. We’d like it to react to Fossil `/login` failures, for
236 example. Put the following into
 
237 `/etc/fail2ban/filter.d/nginx-fossil-login.conf`:
238
239 [Definition]
240 failregex = ^<HOST> - .*POST .*/login HTTP/..." 401
241
242
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -217,25 +217,46 @@
217 The most common thing people get wrong when hand-rolling a configuration
218 like this is to get the slashes wrong. Fossil is sensitive to this. For
219 instance, Fossil will not collapse double slashes down to a single
220 slash, as some other HTTP servers will.
221
222
223 ## <a name="large-uv"></a> Allowing Large Unversioned Files
224
225 By default, nginx only accepts HTTP messages [up to a
226 meg](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)
227 in size. Fossil chunks its sync protocol such that this is not normally
228 a problem, but when sending [unversioned content][uv], it uses a single
229 message for the entire file. Therefore, if you will be storing files
230 larger than this limit as unversioned content, you need to raise the
231 limit. Within the `location` block:
232
233 # Allow large unversioned file uploads, such as PDFs
234 client_max_body_size 20M;
235
236 [uv]: ../../unvers.wiki
237
238
239 ## <a name="fail2ban"></a> Integrating `fail2ban`
240
241 One of the nice things that falls out of proxying Fossil behind nginx is
242 that it makes it easier to configure `fail2ban` to recognize attacks on
243 Fossil and automatically block them. Fossil logs the sorts of errors we
244 want to detect, but it does so in places like the repository’s admin
245 log, a SQL table, which `fail2ban` doesn’t know how to query. By putting
246 Fossil behind an nginx proxy, we convert these failures to log file
247 form, which `fail2ban` is designed to handle.
248
249 First, install `fail2ban`, if you haven’t already:
250
251 sudo apt install fail2ban
252
253 We’d like `fail2ban` to react to Fossil `/login` failures. The stock
254 configuration of `fail2ban` only detects a few common sorts of SSH
255 attacks by default, and its included (but disabled) nginx attack
256 detectors don’t include one that knows how to detect an attack on
257 Fossil. We have to teach it by putting the following into
258 `/etc/fail2ban/filter.d/nginx-fossil-login.conf`:
259
260 [Definition]
261 failregex = ^<HOST> - .*POST .*/login HTTP/..." 401
262
263
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -159,15 +159,27 @@
159159
root "/acme"
160160
request strip 2
161161
}
162162
}
163163
```
164
+
165
+[The default limit][dlim] for HTTP messages in OpenBSD’s `httpd` server
166
+is 1 MiB. Fossil chunks its sync protocol such that this is not
167
+normally a problem, but when sending [unversioned content][uv], it uses
168
+a single message for the entire file. Therefore, if you will be storing
169
+files larger than this limit as unversioned content, you need to raise
170
+the limit as we’ve done above with the “`connection max request body`”
171
+setting, raising the limit to 100 MiB.
172
+
173
+[dlim]: https://man.openbsd.org/httpd.conf.5#connection
174
+[uv]: ../../unvers.wiki
164175
165176
**NOTE:** If not already in possession of a HTTPS certificate, comment
166177
out the `https` server block and proceed to securing a free
167178
[Let's Encrypt Certificate](#letsencrypt); otherwise skip to
168179
[Start `httpd`](#starthttpd).
180
+
169181
170182
## <a name="letsencrypt"></a>Let's Encrypt Certificate
171183
172184
In order for `httpd` to serve HTTPS, secure a free certificate from
173185
Let's Encrypt using `acme-client`. Before issuing the request, however,
174186
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -159,15 +159,27 @@
159 root "/acme"
160 request strip 2
161 }
162 }
163 ```
 
 
 
 
 
 
 
 
 
 
 
164
165 **NOTE:** If not already in possession of a HTTPS certificate, comment
166 out the `https` server block and proceed to securing a free
167 [Let's Encrypt Certificate](#letsencrypt); otherwise skip to
168 [Start `httpd`](#starthttpd).
 
169
170 ## <a name="letsencrypt"></a>Let's Encrypt Certificate
171
172 In order for `httpd` to serve HTTPS, secure a free certificate from
173 Let's Encrypt using `acme-client`. Before issuing the request, however,
174
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -159,15 +159,27 @@
159 root "/acme"
160 request strip 2
161 }
162 }
163 ```
164
165 [The default limit][dlim] for HTTP messages in OpenBSD’s `httpd` server
166 is 1 MiB. Fossil chunks its sync protocol such that this is not
167 normally a problem, but when sending [unversioned content][uv], it uses
168 a single message for the entire file. Therefore, if you will be storing
169 files larger than this limit as unversioned content, you need to raise
170 the limit as we’ve done above with the “`connection max request body`”
171 setting, raising the limit to 100 MiB.
172
173 [dlim]: https://man.openbsd.org/httpd.conf.5#connection
174 [uv]: ../../unvers.wiki
175
176 **NOTE:** If not already in possession of a HTTPS certificate, comment
177 out the `https` server block and proceed to securing a free
178 [Let's Encrypt Certificate](#letsencrypt); otherwise skip to
179 [Start `httpd`](#starthttpd).
180
181
182 ## <a name="letsencrypt"></a>Let's Encrypt Certificate
183
184 In order for `httpd` to serve HTTPS, secure a free certificate from
185 Let's Encrypt using `acme-client`. Before issuing the request, however,
186
+1 -1
--- www/sync.wiki
+++ www/sync.wiki
@@ -12,11 +12,11 @@
1212
repositories so that all repositories have copies of all artifacts. Because
1313
artifacts are unordered, the order in which artifacts are received
1414
is unimportant. It is assumed that the hash names
1515
of artifacts are unique - that every artifact has a different hash.
1616
To a first approximation, synchronization proceeds by sharing lists
17
-hash values for available artifacts, then sharing the content of artifacts
17
+of hashes for available artifacts, then sharing the content of artifacts
1818
whose names are missing from one side or the other of the connection.
1919
In practice, a repository might contain millions of artifacts. The list of
2020
hash names for this many artifacts can be large. So optimizations are
2121
employed that usually reduce the number of hashes that need to be
2222
shared to a few hundred.</p>
2323
--- www/sync.wiki
+++ www/sync.wiki
@@ -12,11 +12,11 @@
12 repositories so that all repositories have copies of all artifacts. Because
13 artifacts are unordered, the order in which artifacts are received
14 is unimportant. It is assumed that the hash names
15 of artifacts are unique - that every artifact has a different hash.
16 To a first approximation, synchronization proceeds by sharing lists
17 hash values for available artifacts, then sharing the content of artifacts
18 whose names are missing from one side or the other of the connection.
19 In practice, a repository might contain millions of artifacts. The list of
20 hash names for this many artifacts can be large. So optimizations are
21 employed that usually reduce the number of hashes that need to be
22 shared to a few hundred.</p>
23
--- www/sync.wiki
+++ www/sync.wiki
@@ -12,11 +12,11 @@
12 repositories so that all repositories have copies of all artifacts. Because
13 artifacts are unordered, the order in which artifacts are received
14 is unimportant. It is assumed that the hash names
15 of artifacts are unique - that every artifact has a different hash.
16 To a first approximation, synchronization proceeds by sharing lists
17 of hashes for available artifacts, then sharing the content of artifacts
18 whose names are missing from one side or the other of the connection.
19 In practice, a repository might contain millions of artifacts. The list of
20 hash names for this many artifacts can be large. So optimizations are
21 employed that usually reduce the number of hashes that need to be
22 shared to a few hundred.</p>
23

Keyboard Shortcuts

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