Fossil SCM

Merge from trunk

george 2021-06-15 21:45 rptview-submenu-paralink merge
Commit f445855917422ecaef494af93c839fd6e0f8f237fc836a53b461543552828751
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.15
1
+2.16
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.15
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.16
2
--- skins/ardoise/header.txt
+++ skins/ardoise/header.txt
@@ -26,12 +26,12 @@
2626
html "<li><a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a></li>\n"
2727
builtin_request_js hbmenu.js
2828
set once 1
2929
foreach {name url expr class} $mainmenu {
3030
if {![capexpr $expr]} continue
31
- if {$once && [string match /$current_page* $url]} {
32
- lappend class active
31
+ if {$once && [string match $url\[/?#\]* /$current_page/]} {
32
+ set class "$class active"
3333
set once 0
3434
}
3535
html "<li class='$class'>"
3636
if {[string match /* $url]} {set url $home$url}
3737
html "<a href='$url'>$name</a></li>\n"
3838
--- skins/ardoise/header.txt
+++ skins/ardoise/header.txt
@@ -26,12 +26,12 @@
26 html "<li><a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a></li>\n"
27 builtin_request_js hbmenu.js
28 set once 1
29 foreach {name url expr class} $mainmenu {
30 if {![capexpr $expr]} continue
31 if {$once && [string match /$current_page* $url]} {
32 lappend class active
33 set once 0
34 }
35 html "<li class='$class'>"
36 if {[string match /* $url]} {set url $home$url}
37 html "<a href='$url'>$name</a></li>\n"
38
--- skins/ardoise/header.txt
+++ skins/ardoise/header.txt
@@ -26,12 +26,12 @@
26 html "<li><a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a></li>\n"
27 builtin_request_js hbmenu.js
28 set once 1
29 foreach {name url expr class} $mainmenu {
30 if {![capexpr $expr]} continue
31 if {$once && [string match $url\[/?#\]* /$current_page/]} {
32 set class "$class active"
33 set once 0
34 }
35 html "<li class='$class'>"
36 if {[string match /* $url]} {set url $home$url}
37 html "<a href='$url'>$name</a></li>\n"
38
--- skins/blitz/header.txt
+++ skins/blitz/header.txt
@@ -27,12 +27,12 @@
2727
html "<li><a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a></li>\n"
2828
builtin_request_js hbmenu.js
2929
set once 1
3030
foreach {name url expr class} $mainmenu {
3131
if {![capexpr $expr]} continue
32
- if {$once && [string match /$current_page* $url]} {
33
- lappend class active
32
+ if {$once && [string match $url\[/?#\]* /$current_page/]} {
33
+ set class "active $class"
3434
set once 0
3535
}
3636
html "<li class='$class'>"
3737
if {[string match /* $url]} {set url $home$url}
3838
html "<a href='$url'>$name</a></li>\n"
3939
--- skins/blitz/header.txt
+++ skins/blitz/header.txt
@@ -27,12 +27,12 @@
27 html "<li><a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a></li>\n"
28 builtin_request_js hbmenu.js
29 set once 1
30 foreach {name url expr class} $mainmenu {
31 if {![capexpr $expr]} continue
32 if {$once && [string match /$current_page* $url]} {
33 lappend class active
34 set once 0
35 }
36 html "<li class='$class'>"
37 if {[string match /* $url]} {set url $home$url}
38 html "<a href='$url'>$name</a></li>\n"
39
--- skins/blitz/header.txt
+++ skins/blitz/header.txt
@@ -27,12 +27,12 @@
27 html "<li><a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a></li>\n"
28 builtin_request_js hbmenu.js
29 set once 1
30 foreach {name url expr class} $mainmenu {
31 if {![capexpr $expr]} continue
32 if {$once && [string match $url\[/?#\]* /$current_page/]} {
33 set class "active $class"
34 set once 0
35 }
36 html "<li class='$class'>"
37 if {[string match /* $url]} {set url $home$url}
38 html "<a href='$url'>$name</a></li>\n"
39
--- skins/bootstrap/header.txt
+++ skins/bootstrap/header.txt
@@ -45,12 +45,12 @@
4545
set sitemap 0
4646
set is_index [expr [string compare [string range $current_page 0 4] "index"]==0]
4747
set is_home [expr [string compare [string range $current_page 0 [expr [string length $index_page]-1] ] $index_page]==0]
4848
foreach {name url expr class} $mainmenu {
4949
if {![capexpr $expr]} continue
50
- if {$once && [string match /$current_page* $url]} {
51
- lappend class active
50
+ if {$once && [string match $url\[/?#\]* /$current_page/]} {
51
+ set class "active $class"
5252
set once 0
5353
}
5454
html "<li class='$class'>"
5555
if {[string match /* $url]} {set url $home$url}
5656
if {[string match *sitemap* $url]} {set sitemap 1}
5757
--- skins/bootstrap/header.txt
+++ skins/bootstrap/header.txt
@@ -45,12 +45,12 @@
45 set sitemap 0
46 set is_index [expr [string compare [string range $current_page 0 4] "index"]==0]
47 set is_home [expr [string compare [string range $current_page 0 [expr [string length $index_page]-1] ] $index_page]==0]
48 foreach {name url expr class} $mainmenu {
49 if {![capexpr $expr]} continue
50 if {$once && [string match /$current_page* $url]} {
51 lappend class active
52 set once 0
53 }
54 html "<li class='$class'>"
55 if {[string match /* $url]} {set url $home$url}
56 if {[string match *sitemap* $url]} {set sitemap 1}
57
--- skins/bootstrap/header.txt
+++ skins/bootstrap/header.txt
@@ -45,12 +45,12 @@
45 set sitemap 0
46 set is_index [expr [string compare [string range $current_page 0 4] "index"]==0]
47 set is_home [expr [string compare [string range $current_page 0 [expr [string length $index_page]-1] ] $index_page]==0]
48 foreach {name url expr class} $mainmenu {
49 if {![capexpr $expr]} continue
50 if {$once && [string match $url\[/?#\]* /$current_page/]} {
51 set class "active $class"
52 set once 0
53 }
54 html "<li class='$class'>"
55 if {[string match /* $url]} {set url $home$url}
56 if {[string match *sitemap* $url]} {set sitemap 1}
57
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -85,11 +85,13 @@
8585
div.mainmenu a, div.submenu a,
8686
div.sectionmenu>a.button, div.submenu label,
8787
div.footer a {
8888
padding: 0.15em 0.5em;
8989
}
90
-/* div.mainmenu a.active, FIXME: setting of .active is broken for some URIs */
90
+div.mainmenu a.active {
91
+ border-bottom: 1px solid #FF4500f0;
92
+}
9193
a:hover,
9294
a:visited:hover {
9395
background-color: #FF4500f0;
9496
color: rgba(24,24,24,0.8);
9597
border-radius: 0.1em;
9698
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -85,11 +85,13 @@
85 div.mainmenu a, div.submenu a,
86 div.sectionmenu>a.button, div.submenu label,
87 div.footer a {
88 padding: 0.15em 0.5em;
89 }
90 /* div.mainmenu a.active, FIXME: setting of .active is broken for some URIs */
 
 
91 a:hover,
92 a:visited:hover {
93 background-color: #FF4500f0;
94 color: rgba(24,24,24,0.8);
95 border-radius: 0.1em;
96
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -85,11 +85,13 @@
85 div.mainmenu a, div.submenu a,
86 div.sectionmenu>a.button, div.submenu label,
87 div.footer a {
88 padding: 0.15em 0.5em;
89 }
90 div.mainmenu a.active {
91 border-bottom: 1px solid #FF4500f0;
92 }
93 a:hover,
94 a:visited:hover {
95 background-color: #FF4500f0;
96 color: rgba(24,24,24,0.8);
97 border-radius: 0.1em;
98
--- skins/darkmode/header.txt
+++ skins/darkmode/header.txt
@@ -17,11 +17,11 @@
1717
html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
1818
builtin_request_js hbmenu.js
1919
foreach {name url expr class} $mainmenu {
2020
if {![capexpr $expr]} continue
2121
if {[string match /* $url]} {
22
- if {[string match /$current_page* $url]} {
22
+ if {[string match $url\[/?#\]* /$current_page/]} {
2323
set class "active $class"
2424
}
2525
set url $home$url
2626
}
2727
html "<a href='$url' class='$class'>$name</a>\n"
2828
--- skins/darkmode/header.txt
+++ skins/darkmode/header.txt
@@ -17,11 +17,11 @@
17 html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
18 builtin_request_js hbmenu.js
19 foreach {name url expr class} $mainmenu {
20 if {![capexpr $expr]} continue
21 if {[string match /* $url]} {
22 if {[string match /$current_page* $url]} {
23 set class "active $class"
24 }
25 set url $home$url
26 }
27 html "<a href='$url' class='$class'>$name</a>\n"
28
--- skins/darkmode/header.txt
+++ skins/darkmode/header.txt
@@ -17,11 +17,11 @@
17 html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
18 builtin_request_js hbmenu.js
19 foreach {name url expr class} $mainmenu {
20 if {![capexpr $expr]} continue
21 if {[string match /* $url]} {
22 if {[string match $url\[/?#\]* /$current_page/]} {
23 set class "active $class"
24 }
25 set url $home$url
26 }
27 html "<a href='$url' class='$class'>$name</a>\n"
28
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -267,11 +267,11 @@
267267
padding-top: 0px;
268268
padding-bottom: 0px;
269269
}
270270
.status {padding-top: 0px;}
271271
.mainmenu a {
272
- padding: 10px 10px;
272
+ padding: 8px 10px;
273273
}
274274
.mainmenu {
275275
padding: 10px;
276276
}
277277
}
@@ -285,11 +285,11 @@
285285
padding-top: 10px;
286286
padding-bottom: 10px;
287287
}
288288
.status {padding-top: 30px;}
289289
.mainmenu a {
290
- padding: 10px 20px;
290
+ padding: 8px 20px;
291291
}
292292
.mainmenu {
293293
padding: 10px;
294294
}
295295
}
296296
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -267,11 +267,11 @@
267 padding-top: 0px;
268 padding-bottom: 0px;
269 }
270 .status {padding-top: 0px;}
271 .mainmenu a {
272 padding: 10px 10px;
273 }
274 .mainmenu {
275 padding: 10px;
276 }
277 }
@@ -285,11 +285,11 @@
285 padding-top: 10px;
286 padding-bottom: 10px;
287 }
288 .status {padding-top: 30px;}
289 .mainmenu a {
290 padding: 10px 20px;
291 }
292 .mainmenu {
293 padding: 10px;
294 }
295 }
296
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -267,11 +267,11 @@
267 padding-top: 0px;
268 padding-bottom: 0px;
269 }
270 .status {padding-top: 0px;}
271 .mainmenu a {
272 padding: 8px 10px;
273 }
274 .mainmenu {
275 padding: 10px;
276 }
277 }
@@ -285,11 +285,11 @@
285 padding-top: 10px;
286 padding-bottom: 10px;
287 }
288 .status {padding-top: 30px;}
289 .mainmenu a {
290 padding: 8px 20px;
291 }
292 .mainmenu {
293 padding: 10px;
294 }
295 }
296
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -13,11 +13,11 @@
1313
html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
1414
builtin_request_js hbmenu.js
1515
foreach {name url expr class} $mainmenu {
1616
if {![capexpr $expr]} continue
1717
if {[string match /* $url]} {
18
- if {[string match /$current_page* $url]} {
18
+ if {[string match $url\[/?#\]* /$current_page/]} {
1919
set class "active $class"
2020
}
2121
set url $home$url
2222
}
2323
html "<a href='$url' class='$class'>$name</a>\n"
2424
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -13,11 +13,11 @@
13 html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
14 builtin_request_js hbmenu.js
15 foreach {name url expr class} $mainmenu {
16 if {![capexpr $expr]} continue
17 if {[string match /* $url]} {
18 if {[string match /$current_page* $url]} {
19 set class "active $class"
20 }
21 set url $home$url
22 }
23 html "<a href='$url' class='$class'>$name</a>\n"
24
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -13,11 +13,11 @@
13 html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
14 builtin_request_js hbmenu.js
15 foreach {name url expr class} $mainmenu {
16 if {![capexpr $expr]} continue
17 if {[string match /* $url]} {
18 if {[string match $url\[/?#\]* /$current_page/]} {
19 set class "active $class"
20 }
21 set url $home$url
22 }
23 html "<a href='$url' class='$class'>$name</a>\n"
24
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -1124,11 +1124,14 @@
11241124
.fossil-PopupWidget,
11251125
.fossil-tooltip.help-buttonlet-content {
11261126
background-color: #111;
11271127
border: 1px solid rgba(255,255,255,0.5);
11281128
}
1129
-
1129
+.fossil-PopupWidget a,
1130
+.fossil-PopupWidget a:visited {
1131
+ color: white;
1132
+}
11301133
div.forumSel {
11311134
background-color: #663399;
11321135
}
11331136
div.forumPostBody blockquote {
11341137
border-width: 1pt;
11351138
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -1124,11 +1124,14 @@
1124 .fossil-PopupWidget,
1125 .fossil-tooltip.help-buttonlet-content {
1126 background-color: #111;
1127 border: 1px solid rgba(255,255,255,0.5);
1128 }
1129
 
 
 
1130 div.forumSel {
1131 background-color: #663399;
1132 }
1133 div.forumPostBody blockquote {
1134 border-width: 1pt;
1135
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -1124,11 +1124,14 @@
1124 .fossil-PopupWidget,
1125 .fossil-tooltip.help-buttonlet-content {
1126 background-color: #111;
1127 border: 1px solid rgba(255,255,255,0.5);
1128 }
1129 .fossil-PopupWidget a,
1130 .fossil-PopupWidget a:visited {
1131 color: white;
1132 }
1133 div.forumSel {
1134 background-color: #663399;
1135 }
1136 div.forumPostBody blockquote {
1137 border-width: 1pt;
1138
--- skins/xekri/header.txt
+++ skins/xekri/header.txt
@@ -94,12 +94,12 @@
9494
<div class="mainmenu"><th1>
9595
set sitemap 0
9696
foreach {name url expr class} $mainmenu {
9797
if {![capexpr $expr]} continue
9898
if {[string match /* $url]} {
99
- if {[string match /$current_page* $url]} {
100
- lappend class active
99
+ if {[string match $url\[/?#\]* /$current_page/]} {
100
+ set class "active $class"
101101
}
102102
set url $home$url
103103
}
104104
html "<a href='$url' class='$class'>$name</a>\n"
105105
if {[string match */sitemap $url]} {set sitemap 1}
106106
--- skins/xekri/header.txt
+++ skins/xekri/header.txt
@@ -94,12 +94,12 @@
94 <div class="mainmenu"><th1>
95 set sitemap 0
96 foreach {name url expr class} $mainmenu {
97 if {![capexpr $expr]} continue
98 if {[string match /* $url]} {
99 if {[string match /$current_page* $url]} {
100 lappend class active
101 }
102 set url $home$url
103 }
104 html "<a href='$url' class='$class'>$name</a>\n"
105 if {[string match */sitemap $url]} {set sitemap 1}
106
--- skins/xekri/header.txt
+++ skins/xekri/header.txt
@@ -94,12 +94,12 @@
94 <div class="mainmenu"><th1>
95 set sitemap 0
96 foreach {name url expr class} $mainmenu {
97 if {![capexpr $expr]} continue
98 if {[string match /* $url]} {
99 if {[string match $url\[/?#\]* /$current_page/]} {
100 set class "active $class"
101 }
102 set url $home$url
103 }
104 html "<a href='$url' class='$class'>$name</a>\n"
105 if {[string match */sitemap $url]} {set sitemap 1}
106
+10 -10
--- src/chat.c
+++ src/chat.c
@@ -213,18 +213,18 @@
213213
/* Definition of repository tables used by chat
214214
*/
215215
static const char zChatSchema1[] =
216216
@ CREATE TABLE repository.chat(
217217
@ msgid INTEGER PRIMARY KEY AUTOINCREMENT,
218
-@ mtime JULIANDAY, -- Time for this entry - Julianday Zulu
219
-@ lmtime TEXT, -- Localtime when message originally sent
220
-@ xfrom TEXT, -- Login of the sender
221
-@ xmsg TEXT, -- Raw, unformatted text of the message
222
-@ fname TEXT, -- Filename of the uploaded file, or NULL
223
-@ fmime TEXT, -- MIMEType of the upload file, or NULL
224
-@ mdel INT, -- msgid of another message to delete
225
-@ file BLOB -- Text of the uploaded file, or NULL
218
+@ mtime JULIANDAY, -- Time for this entry - Julianday Zulu
219
+@ lmtime TEXT, -- Client YYYY-MM-DDZHH:MM:SS when message originally sent
220
+@ xfrom TEXT, -- Login of the sender
221
+@ xmsg TEXT, -- Raw, unformatted text of the message
222
+@ fname TEXT, -- Filename of the uploaded file, or NULL
223
+@ fmime TEXT, -- MIMEType of the upload file, or NULL
224
+@ mdel INT, -- msgid of another message to delete
225
+@ file BLOB -- Text of the uploaded file, or NULL
226226
@ );
227227
;
228228
229229
230230
/*
@@ -483,12 +483,12 @@
483483
**
484484
** | {
485485
** | "msgs":[
486486
** | {
487487
** | "msgid": integer // message id
488
-** | "mtime": text // When sent: YYYY-MM-DD HH:MM:SS UTC
489
-** | "lmtime: text // Localtime where the message was sent from
488
+** | "mtime": text // When sent: YYYY-MM-DDTHH:MM:SSZ
489
+** | "lmtime: text // Sender's client-side YYYY-MM-DDTHH:MM:SS
490490
** | "xfrom": text // Login name of sender
491491
** | "uclr": text // Color string associated with the user
492492
** | "xmsg": text // HTML text of the message
493493
** | "fsize": integer // file attachment size in bytes
494494
** | "fname": text // Name of file attachment
495495
--- src/chat.c
+++ src/chat.c
@@ -213,18 +213,18 @@
213 /* Definition of repository tables used by chat
214 */
215 static const char zChatSchema1[] =
216 @ CREATE TABLE repository.chat(
217 @ msgid INTEGER PRIMARY KEY AUTOINCREMENT,
218 @ mtime JULIANDAY, -- Time for this entry - Julianday Zulu
219 @ lmtime TEXT, -- Localtime when message originally sent
220 @ xfrom TEXT, -- Login of the sender
221 @ xmsg TEXT, -- Raw, unformatted text of the message
222 @ fname TEXT, -- Filename of the uploaded file, or NULL
223 @ fmime TEXT, -- MIMEType of the upload file, or NULL
224 @ mdel INT, -- msgid of another message to delete
225 @ file BLOB -- Text of the uploaded file, or NULL
226 @ );
227 ;
228
229
230 /*
@@ -483,12 +483,12 @@
483 **
484 ** | {
485 ** | "msgs":[
486 ** | {
487 ** | "msgid": integer // message id
488 ** | "mtime": text // When sent: YYYY-MM-DD HH:MM:SS UTC
489 ** | "lmtime: text // Localtime where the message was sent from
490 ** | "xfrom": text // Login name of sender
491 ** | "uclr": text // Color string associated with the user
492 ** | "xmsg": text // HTML text of the message
493 ** | "fsize": integer // file attachment size in bytes
494 ** | "fname": text // Name of file attachment
495
--- src/chat.c
+++ src/chat.c
@@ -213,18 +213,18 @@
213 /* Definition of repository tables used by chat
214 */
215 static const char zChatSchema1[] =
216 @ CREATE TABLE repository.chat(
217 @ msgid INTEGER PRIMARY KEY AUTOINCREMENT,
218 @ mtime JULIANDAY, -- Time for this entry - Julianday Zulu
219 @ lmtime TEXT, -- Client YYYY-MM-DDZHH:MM:SS when message originally sent
220 @ xfrom TEXT, -- Login of the sender
221 @ xmsg TEXT, -- Raw, unformatted text of the message
222 @ fname TEXT, -- Filename of the uploaded file, or NULL
223 @ fmime TEXT, -- MIMEType of the upload file, or NULL
224 @ mdel INT, -- msgid of another message to delete
225 @ file BLOB -- Text of the uploaded file, or NULL
226 @ );
227 ;
228
229
230 /*
@@ -483,12 +483,12 @@
483 **
484 ** | {
485 ** | "msgs":[
486 ** | {
487 ** | "msgid": integer // message id
488 ** | "mtime": text // When sent: YYYY-MM-DDTHH:MM:SSZ
489 ** | "lmtime: text // Sender's client-side YYYY-MM-DDTHH:MM:SS
490 ** | "xfrom": text // Login name of sender
491 ** | "uclr": text // Color string associated with the user
492 ** | "xmsg": text // HTML text of the message
493 ** | "fsize": integer // file attachment size in bytes
494 ** | "fname": text // Name of file attachment
495
+19 -4
--- src/chat.js
+++ src/chat.js
@@ -94,10 +94,12 @@
9494
return resized;
9595
})();
9696
fossil.FRK = ForceResizeKludge/*for debugging*/;
9797
const Chat = (function(){
9898
const cs = {
99
+ verboseErrors: false /* if true then certain, mostly extraneous,
100
+ error messages may be sent to the console. */,
99101
e:{/*map of certain DOM elements.*/
100102
messageInjectPoint: E1('#message-inject-point'),
101103
pageTitle: E1('head title'),
102104
loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
103105
inputWrapper: E1("#chat-input-area"),
@@ -226,13 +228,13 @@
226228
}else{
227229
eMsg.scrollIntoView(false);
228230
}
229231
return this;
230232
},
231
- /* Injects element e as a new row in the chat, at the oldest end
232
- of the list if atEnd is truthy, else at the newest end of the
233
- list. */
233
+ /* Injects DOM element e as a new row in the chat, at the oldest
234
+ end of the list if atEnd is truthy, else at the newest end of
235
+ the list. */
234236
injectMessageElem: function f(e, atEnd){
235237
const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
236238
holder = this.e.messagesWrapper,
237239
prevMessage = this.e.newestMessage;
238240
if(atEnd){
@@ -736,10 +738,23 @@
736738
btnDeleteGlobal.addEventListener('click', function(){
737739
self.hide();
738740
Chat.deleteMessage(eMsg);
739741
});
740742
}
743
+ if(eMsg.dataset.xfrom){
744
+ /* Add a link to the /timeline filtered on this user. */
745
+ const toolbar2 = D.addClass(D.div(), 'toolbar');
746
+ D.append(this.e, toolbar2);
747
+ const timelineLink = D.attr(
748
+ D.a(F.repoUrl('timeline',{
749
+ u: eMsg.dataset.xfrom,
750
+ y: 'a'
751
+ }), "User's Timeline"),
752
+ 'target', '_blank'
753
+ );
754
+ D.append(toolbar2, timelineLink);
755
+ }
741756
}/*refresh()*/
742757
});
743758
f.popup.installHideHandlers();
744759
f.popup.hide = function(){
745760
delete this._eMsg;
@@ -1229,11 +1244,11 @@
12291244
// Disable the ajax start/end handling for this long-polling op:
12301245
beforesend: function(){},
12311246
aftersend: function(){},
12321247
onerror:function(err){
12331248
Chat._isBatchLoading = false;
1234
- console.error(err);
1249
+ if(Chat.verboseErrors) console.error(err);
12351250
/* ^^^ we don't use Chat.reportError() here b/c the polling
12361251
fails exepectedly when it times out, but is then immediately
12371252
resumed, and reportError() produces a loud error message. */
12381253
afterFetch();
12391254
},
12401255
--- src/chat.js
+++ src/chat.js
@@ -94,10 +94,12 @@
94 return resized;
95 })();
96 fossil.FRK = ForceResizeKludge/*for debugging*/;
97 const Chat = (function(){
98 const cs = {
 
 
99 e:{/*map of certain DOM elements.*/
100 messageInjectPoint: E1('#message-inject-point'),
101 pageTitle: E1('head title'),
102 loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
103 inputWrapper: E1("#chat-input-area"),
@@ -226,13 +228,13 @@
226 }else{
227 eMsg.scrollIntoView(false);
228 }
229 return this;
230 },
231 /* Injects element e as a new row in the chat, at the oldest end
232 of the list if atEnd is truthy, else at the newest end of the
233 list. */
234 injectMessageElem: function f(e, atEnd){
235 const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
236 holder = this.e.messagesWrapper,
237 prevMessage = this.e.newestMessage;
238 if(atEnd){
@@ -736,10 +738,23 @@
736 btnDeleteGlobal.addEventListener('click', function(){
737 self.hide();
738 Chat.deleteMessage(eMsg);
739 });
740 }
 
 
 
 
 
 
 
 
 
 
 
 
 
741 }/*refresh()*/
742 });
743 f.popup.installHideHandlers();
744 f.popup.hide = function(){
745 delete this._eMsg;
@@ -1229,11 +1244,11 @@
1229 // Disable the ajax start/end handling for this long-polling op:
1230 beforesend: function(){},
1231 aftersend: function(){},
1232 onerror:function(err){
1233 Chat._isBatchLoading = false;
1234 console.error(err);
1235 /* ^^^ we don't use Chat.reportError() here b/c the polling
1236 fails exepectedly when it times out, but is then immediately
1237 resumed, and reportError() produces a loud error message. */
1238 afterFetch();
1239 },
1240
--- src/chat.js
+++ src/chat.js
@@ -94,10 +94,12 @@
94 return resized;
95 })();
96 fossil.FRK = ForceResizeKludge/*for debugging*/;
97 const Chat = (function(){
98 const cs = {
99 verboseErrors: false /* if true then certain, mostly extraneous,
100 error messages may be sent to the console. */,
101 e:{/*map of certain DOM elements.*/
102 messageInjectPoint: E1('#message-inject-point'),
103 pageTitle: E1('head title'),
104 loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
105 inputWrapper: E1("#chat-input-area"),
@@ -226,13 +228,13 @@
228 }else{
229 eMsg.scrollIntoView(false);
230 }
231 return this;
232 },
233 /* Injects DOM element e as a new row in the chat, at the oldest
234 end of the list if atEnd is truthy, else at the newest end of
235 the list. */
236 injectMessageElem: function f(e, atEnd){
237 const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
238 holder = this.e.messagesWrapper,
239 prevMessage = this.e.newestMessage;
240 if(atEnd){
@@ -736,10 +738,23 @@
738 btnDeleteGlobal.addEventListener('click', function(){
739 self.hide();
740 Chat.deleteMessage(eMsg);
741 });
742 }
743 if(eMsg.dataset.xfrom){
744 /* Add a link to the /timeline filtered on this user. */
745 const toolbar2 = D.addClass(D.div(), 'toolbar');
746 D.append(this.e, toolbar2);
747 const timelineLink = D.attr(
748 D.a(F.repoUrl('timeline',{
749 u: eMsg.dataset.xfrom,
750 y: 'a'
751 }), "User's Timeline"),
752 'target', '_blank'
753 );
754 D.append(toolbar2, timelineLink);
755 }
756 }/*refresh()*/
757 });
758 f.popup.installHideHandlers();
759 f.popup.hide = function(){
760 delete this._eMsg;
@@ -1229,11 +1244,11 @@
1244 // Disable the ajax start/end handling for this long-polling op:
1245 beforesend: function(){},
1246 aftersend: function(){},
1247 onerror:function(err){
1248 Chat._isBatchLoading = false;
1249 if(Chat.verboseErrors) console.error(err);
1250 /* ^^^ we don't use Chat.reportError() here b/c the polling
1251 fails exepectedly when it times out, but is then immediately
1252 resumed, and reportError() produces a loud error message. */
1253 afterFetch();
1254 },
1255
+33 -1
--- src/db.c
+++ src/db.c
@@ -864,23 +864,55 @@
864864
db_exec(&err);
865865
}
866866
867867
/*
868868
** COMMAND: test-db-prepare
869
-** Usage: %fossil test-db-prepare ?OPTIONS? SQL
869
+** Usage: %fossil test-db-prepare ?OPTIONS? SQL-STATEMENT
870
+**
871
+** Options:
872
+**
873
+** --auth-report Enable the ticket report query authorizer.
874
+** --auth-ticket Enable the ticket schema query authorizer.
870875
**
871876
** Invoke db_prepare() on the SQL input. Report any errors encountered.
872877
** This command is used to verify error detection logic in the db_prepare()
873878
** utility routine.
874879
*/
875880
void db_test_db_prepare(void){
881
+ const int fAuthReport = find_option("auth-report",0,0)!=0;
882
+ const int fAuthSchema = find_option("auth-ticket",0,0)!=0;
883
+ char * zReportErr = 0; /* auth-report error string. */
884
+ int nSchemaErr = 0; /* Number of auth-ticket errors. */
876885
Stmt err;
886
+
887
+ if(fAuthReport + fAuthSchema > 1){
888
+ fossil_fatal("Only one of --auth-report or --auth-ticket "
889
+ "may be used.");
890
+ }
877891
db_find_and_open_repository(0,0);
878892
verify_all_options();
879893
if( g.argc!=3 ) usage("?OPTIONS? SQL");
894
+ if(fAuthReport){
895
+ report_restrict_sql(&zReportErr);
896
+ }else if(fAuthSchema){
897
+ ticket_restrict_sql(&nSchemaErr);
898
+ }
880899
db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
881900
db_finalize(&err);
901
+ if(fAuthReport){
902
+ report_unrestrict_sql();
903
+ if(zReportErr){
904
+ fossil_warning("Report authorizer error: %s\n", zReportErr);
905
+ fossil_free(zReportErr);
906
+ }
907
+ }else if(fAuthSchema){
908
+ ticket_unrestrict_sql();
909
+ if(nSchemaErr){
910
+ fossil_warning("Ticket schema authorizer error count: %d\n",
911
+ nSchemaErr);
912
+ }
913
+ }
882914
}
883915
884916
/*
885917
** Print the output of one or more SQL queries on standard output.
886918
** This routine is used for debugging purposes only.
887919
--- src/db.c
+++ src/db.c
@@ -864,23 +864,55 @@
864 db_exec(&err);
865 }
866
867 /*
868 ** COMMAND: test-db-prepare
869 ** Usage: %fossil test-db-prepare ?OPTIONS? SQL
 
 
 
 
 
870 **
871 ** Invoke db_prepare() on the SQL input. Report any errors encountered.
872 ** This command is used to verify error detection logic in the db_prepare()
873 ** utility routine.
874 */
875 void db_test_db_prepare(void){
 
 
 
 
876 Stmt err;
 
 
 
 
 
877 db_find_and_open_repository(0,0);
878 verify_all_options();
879 if( g.argc!=3 ) usage("?OPTIONS? SQL");
 
 
 
 
 
880 db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
881 db_finalize(&err);
 
 
 
 
 
 
 
 
 
 
 
 
 
882 }
883
884 /*
885 ** Print the output of one or more SQL queries on standard output.
886 ** This routine is used for debugging purposes only.
887
--- src/db.c
+++ src/db.c
@@ -864,23 +864,55 @@
864 db_exec(&err);
865 }
866
867 /*
868 ** COMMAND: test-db-prepare
869 ** Usage: %fossil test-db-prepare ?OPTIONS? SQL-STATEMENT
870 **
871 ** Options:
872 **
873 ** --auth-report Enable the ticket report query authorizer.
874 ** --auth-ticket Enable the ticket schema query authorizer.
875 **
876 ** Invoke db_prepare() on the SQL input. Report any errors encountered.
877 ** This command is used to verify error detection logic in the db_prepare()
878 ** utility routine.
879 */
880 void db_test_db_prepare(void){
881 const int fAuthReport = find_option("auth-report",0,0)!=0;
882 const int fAuthSchema = find_option("auth-ticket",0,0)!=0;
883 char * zReportErr = 0; /* auth-report error string. */
884 int nSchemaErr = 0; /* Number of auth-ticket errors. */
885 Stmt err;
886
887 if(fAuthReport + fAuthSchema > 1){
888 fossil_fatal("Only one of --auth-report or --auth-ticket "
889 "may be used.");
890 }
891 db_find_and_open_repository(0,0);
892 verify_all_options();
893 if( g.argc!=3 ) usage("?OPTIONS? SQL");
894 if(fAuthReport){
895 report_restrict_sql(&zReportErr);
896 }else if(fAuthSchema){
897 ticket_restrict_sql(&nSchemaErr);
898 }
899 db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
900 db_finalize(&err);
901 if(fAuthReport){
902 report_unrestrict_sql();
903 if(zReportErr){
904 fossil_warning("Report authorizer error: %s\n", zReportErr);
905 fossil_free(zReportErr);
906 }
907 }else if(fAuthSchema){
908 ticket_unrestrict_sql();
909 if(nSchemaErr){
910 fossil_warning("Ticket schema authorizer error count: %d\n",
911 nSchemaErr);
912 }
913 }
914 }
915
916 /*
917 ** Print the output of one or more SQL queries on standard output.
918 ** This routine is used for debugging purposes only.
919
--- src/default.css
+++ src/default.css
@@ -1287,10 +1287,14 @@
12871287
/* problem: if we inherit the color it may either be
12881288
transparent or inherit translucency via the
12891289
skin, leaving it unreadable. Since we set the bg
12901290
color we must also set the fg color. */;
12911291
color: rgba(235, 235, 235, 0.9);
1292
+}
1293
+.fossil-PopupWidget a,
1294
+.fossil-PopupWidget a:visited {
1295
+ color: initial;
12921296
}
12931297
.fossil-toast-message.error,
12941298
.fossil-toast-message.warning {
12951299
background: yellow;
12961300
}
12971301
--- src/default.css
+++ src/default.css
@@ -1287,10 +1287,14 @@
1287 /* problem: if we inherit the color it may either be
1288 transparent or inherit translucency via the
1289 skin, leaving it unreadable. Since we set the bg
1290 color we must also set the fg color. */;
1291 color: rgba(235, 235, 235, 0.9);
 
 
 
 
1292 }
1293 .fossil-toast-message.error,
1294 .fossil-toast-message.warning {
1295 background: yellow;
1296 }
1297
--- src/default.css
+++ src/default.css
@@ -1287,10 +1287,14 @@
1287 /* problem: if we inherit the color it may either be
1288 transparent or inherit translucency via the
1289 skin, leaving it unreadable. Since we set the bg
1290 color we must also set the fg color. */;
1291 color: rgba(235, 235, 235, 0.9);
1292 }
1293 .fossil-PopupWidget a,
1294 .fossil-PopupWidget a:visited {
1295 color: initial;
1296 }
1297 .fossil-toast-message.error,
1298 .fossil-toast-message.warning {
1299 background: yellow;
1300 }
1301
+8 -4
--- src/forum.c
+++ src/forum.c
@@ -546,16 +546,16 @@
546546
@ .%0*d(fossil_num_digits(p->nEdit))(p->pEditNext->rev)</a>
547547
}
548548
549549
/* Provide a link to select the individual post. */
550550
if( !bSelect ){
551
- @ %z(href("%R/forumpost/%S?%s",p->zUuid,zQuery))[link]</a>
551
+ @ %z(href("%R/forumpost/%!S?%s",p->zUuid,zQuery))[link]</a>
552552
}
553553
554554
/* Provide a link to the raw source code. */
555555
if( !bUnf ){
556
- @ %z(href("%R/forumpost/%S?raw",p->zUuid))[source]</a>
556
+ @ %z(href("%R/forumpost/%!S?raw",p->zUuid))[source]</a>
557557
}
558558
@ </h3>
559559
}
560560
561561
/* Check if this post is approved, also if it's by the current user. */
@@ -1173,19 +1173,20 @@
11731173
Manifest *pRootPost = 0;
11741174
const char *zMimetype = 0;
11751175
const char *zContent = 0;
11761176
const char *zTitle = 0;
11771177
char *zDate = 0;
1178
+ const char *zFpid = PD("fpid","");
11781179
int isCsrfSafe;
11791180
int isDelete = 0;
11801181
11811182
login_check_credentials();
11821183
if( !g.perm.WrForum ){
11831184
login_needed(g.anon.WrForum);
11841185
return;
11851186
}
1186
- fpid = symbolic_name_to_rid(PD("fpid",""), "f");
1187
+ fpid = symbolic_name_to_rid(zFpid, "f");
11871188
if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
11881189
webpage_error("Missing or invalid fpid query parameter");
11891190
}
11901191
froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
11911192
if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
@@ -1296,11 +1297,14 @@
12961297
zContent = PDT("content","");
12971298
style_header("Reply");
12981299
if( pRootPost->zThreadTitle ){
12991300
@ <h1>Thread: %h(pRootPost->zThreadTitle)</h1>
13001301
}
1301
- @ <h2>Replying To:</h2>
1302
+ @ <h2>Replying To:
1303
+ @ <a href="%R/forumpost/%!S(zFpid)" target="_blank">%S(zFpid)</a>
1304
+ @ <a href="%R/forumpost/%!S(zFpid)?raw" target="_blank">[source]</a>
1305
+ @ </h2>
13021306
zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", pPost->rDate);
13031307
zDisplayName = display_name_from_login(pPost->zUser);
13041308
@ <h3 class='forumPostHdr'>By %s(zDisplayName) on %h(zDate)</h3>
13051309
fossil_free(zDisplayName);
13061310
fossil_free(zDate);
13071311
--- src/forum.c
+++ src/forum.c
@@ -546,16 +546,16 @@
546 @ .%0*d(fossil_num_digits(p->nEdit))(p->pEditNext->rev)</a>
547 }
548
549 /* Provide a link to select the individual post. */
550 if( !bSelect ){
551 @ %z(href("%R/forumpost/%S?%s",p->zUuid,zQuery))[link]</a>
552 }
553
554 /* Provide a link to the raw source code. */
555 if( !bUnf ){
556 @ %z(href("%R/forumpost/%S?raw",p->zUuid))[source]</a>
557 }
558 @ </h3>
559 }
560
561 /* Check if this post is approved, also if it's by the current user. */
@@ -1173,19 +1173,20 @@
1173 Manifest *pRootPost = 0;
1174 const char *zMimetype = 0;
1175 const char *zContent = 0;
1176 const char *zTitle = 0;
1177 char *zDate = 0;
 
1178 int isCsrfSafe;
1179 int isDelete = 0;
1180
1181 login_check_credentials();
1182 if( !g.perm.WrForum ){
1183 login_needed(g.anon.WrForum);
1184 return;
1185 }
1186 fpid = symbolic_name_to_rid(PD("fpid",""), "f");
1187 if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
1188 webpage_error("Missing or invalid fpid query parameter");
1189 }
1190 froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
1191 if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
@@ -1296,11 +1297,14 @@
1296 zContent = PDT("content","");
1297 style_header("Reply");
1298 if( pRootPost->zThreadTitle ){
1299 @ <h1>Thread: %h(pRootPost->zThreadTitle)</h1>
1300 }
1301 @ <h2>Replying To:</h2>
 
 
 
1302 zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", pPost->rDate);
1303 zDisplayName = display_name_from_login(pPost->zUser);
1304 @ <h3 class='forumPostHdr'>By %s(zDisplayName) on %h(zDate)</h3>
1305 fossil_free(zDisplayName);
1306 fossil_free(zDate);
1307
--- src/forum.c
+++ src/forum.c
@@ -546,16 +546,16 @@
546 @ .%0*d(fossil_num_digits(p->nEdit))(p->pEditNext->rev)</a>
547 }
548
549 /* Provide a link to select the individual post. */
550 if( !bSelect ){
551 @ %z(href("%R/forumpost/%!S?%s",p->zUuid,zQuery))[link]</a>
552 }
553
554 /* Provide a link to the raw source code. */
555 if( !bUnf ){
556 @ %z(href("%R/forumpost/%!S?raw",p->zUuid))[source]</a>
557 }
558 @ </h3>
559 }
560
561 /* Check if this post is approved, also if it's by the current user. */
@@ -1173,19 +1173,20 @@
1173 Manifest *pRootPost = 0;
1174 const char *zMimetype = 0;
1175 const char *zContent = 0;
1176 const char *zTitle = 0;
1177 char *zDate = 0;
1178 const char *zFpid = PD("fpid","");
1179 int isCsrfSafe;
1180 int isDelete = 0;
1181
1182 login_check_credentials();
1183 if( !g.perm.WrForum ){
1184 login_needed(g.anon.WrForum);
1185 return;
1186 }
1187 fpid = symbolic_name_to_rid(zFpid, "f");
1188 if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
1189 webpage_error("Missing or invalid fpid query parameter");
1190 }
1191 froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
1192 if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
@@ -1296,11 +1297,14 @@
1297 zContent = PDT("content","");
1298 style_header("Reply");
1299 if( pRootPost->zThreadTitle ){
1300 @ <h1>Thread: %h(pRootPost->zThreadTitle)</h1>
1301 }
1302 @ <h2>Replying To:
1303 @ <a href="%R/forumpost/%!S(zFpid)" target="_blank">%S(zFpid)</a>
1304 @ <a href="%R/forumpost/%!S(zFpid)?raw" target="_blank">[source]</a>
1305 @ </h2>
1306 zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", pPost->rDate);
1307 zDisplayName = display_name_from_login(pPost->zUser);
1308 @ <h3 class='forumPostHdr'>By %s(zDisplayName) on %h(zDate)</h3>
1309 fossil_free(zDisplayName);
1310 fossil_free(zDate);
1311
+14 -3
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -252,10 +252,11 @@
252252
**
253253
** Return the number of errors.
254254
*/
255255
int ssl_open(UrlData *pUrlData){
256256
X509 *cert;
257
+ const char *zRemoteHost;
257258
258259
ssl_global_init();
259260
if( pUrlData->useProxy ){
260261
int rc;
261262
char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
@@ -276,30 +277,40 @@
276277
277278
pUrlData->path = pUrlData->proxyUrlPath;
278279
279280
iBio = BIO_new_ssl(sslCtx, 1);
280281
BIO_push(iBio, sBio);
282
+ zRemoteHost = pUrlData->hostname;
281283
}else{
282284
iBio = BIO_new_ssl_connect(sslCtx);
285
+ zRemoteHost = pUrlData->name;
283286
}
284287
if( iBio==NULL ) {
285288
ssl_set_errmsg("SSL: cannot open SSL (%s)",
286289
ERR_reason_error_string(ERR_get_error()));
287290
return 1;
288291
}
289292
BIO_get_ssl(iBio, &ssl);
290293
291294
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
292
- if( !SSL_set_tlsext_host_name(ssl,
293
- (pUrlData->useProxy?pUrlData->hostname:pUrlData->name))
294
- ){
295
+ if( !SSL_set_tlsext_host_name(ssl, zRemoteHost)){
295296
fossil_warning("WARNING: failed to set server name indication (SNI), "
296297
"continuing without it.\n");
297298
}
298299
#endif
299300
300301
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
302
+#if OPENSSL_VERSION_NUMBER >= 0x010002000
303
+ if( !sslNoCertVerify ){
304
+ X509_VERIFY_PARAM *param = 0;
305
+ param = SSL_get0_param(ssl);
306
+ if( !X509_VERIFY_PARAM_set1_host(param, zRemoteHost, strlen(zRemoteHost)) ){
307
+ fossil_fatal("failed to set hostname.");
308
+ }
309
+ /* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
310
+ }
311
+#endif
301312
302313
if( !pUrlData->useProxy ){
303314
char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
304315
BIO_set_conn_hostname(iBio, connStr);
305316
free(connStr);
306317
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -252,10 +252,11 @@
252 **
253 ** Return the number of errors.
254 */
255 int ssl_open(UrlData *pUrlData){
256 X509 *cert;
 
257
258 ssl_global_init();
259 if( pUrlData->useProxy ){
260 int rc;
261 char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
@@ -276,30 +277,40 @@
276
277 pUrlData->path = pUrlData->proxyUrlPath;
278
279 iBio = BIO_new_ssl(sslCtx, 1);
280 BIO_push(iBio, sBio);
 
281 }else{
282 iBio = BIO_new_ssl_connect(sslCtx);
 
283 }
284 if( iBio==NULL ) {
285 ssl_set_errmsg("SSL: cannot open SSL (%s)",
286 ERR_reason_error_string(ERR_get_error()));
287 return 1;
288 }
289 BIO_get_ssl(iBio, &ssl);
290
291 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
292 if( !SSL_set_tlsext_host_name(ssl,
293 (pUrlData->useProxy?pUrlData->hostname:pUrlData->name))
294 ){
295 fossil_warning("WARNING: failed to set server name indication (SNI), "
296 "continuing without it.\n");
297 }
298 #endif
299
300 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
 
 
 
 
 
 
 
 
 
 
301
302 if( !pUrlData->useProxy ){
303 char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
304 BIO_set_conn_hostname(iBio, connStr);
305 free(connStr);
306
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -252,10 +252,11 @@
252 **
253 ** Return the number of errors.
254 */
255 int ssl_open(UrlData *pUrlData){
256 X509 *cert;
257 const char *zRemoteHost;
258
259 ssl_global_init();
260 if( pUrlData->useProxy ){
261 int rc;
262 char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
@@ -276,30 +277,40 @@
277
278 pUrlData->path = pUrlData->proxyUrlPath;
279
280 iBio = BIO_new_ssl(sslCtx, 1);
281 BIO_push(iBio, sBio);
282 zRemoteHost = pUrlData->hostname;
283 }else{
284 iBio = BIO_new_ssl_connect(sslCtx);
285 zRemoteHost = pUrlData->name;
286 }
287 if( iBio==NULL ) {
288 ssl_set_errmsg("SSL: cannot open SSL (%s)",
289 ERR_reason_error_string(ERR_get_error()));
290 return 1;
291 }
292 BIO_get_ssl(iBio, &ssl);
293
294 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
295 if( !SSL_set_tlsext_host_name(ssl, zRemoteHost)){
 
 
296 fossil_warning("WARNING: failed to set server name indication (SNI), "
297 "continuing without it.\n");
298 }
299 #endif
300
301 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
302 #if OPENSSL_VERSION_NUMBER >= 0x010002000
303 if( !sslNoCertVerify ){
304 X509_VERIFY_PARAM *param = 0;
305 param = SSL_get0_param(ssl);
306 if( !X509_VERIFY_PARAM_set1_host(param, zRemoteHost, strlen(zRemoteHost)) ){
307 fossil_fatal("failed to set hostname.");
308 }
309 /* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
310 }
311 #endif
312
313 if( !pUrlData->useProxy ){
314 char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
315 BIO_set_conn_hostname(iBio, connStr);
316 free(connStr);
317
+5 -5
--- src/info.c
+++ src/info.c
@@ -2794,10 +2794,15 @@
27942794
winfo_page();
27952795
}else
27962796
if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
27972797
" WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
27982798
tinfo_page();
2799
+ }else
2800
+ if( db_table_exists("repository","forumpost")
2801
+ && db_exists("SELECT 1 FROM forumpost WHERE fpid=%d", rid)
2802
+ ){
2803
+ forumthread_page();
27992804
}else
28002805
if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
28012806
ci_page();
28022807
}else
28032808
if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
@@ -2804,15 +2809,10 @@
28042809
ci_page();
28052810
}else
28062811
if( db_exists("SELECT 1 FROM attachment WHERE attachid=%d", rid) ){
28072812
ainfo_page();
28082813
}else
2809
- if( db_table_exists("repository","forumpost")
2810
- && db_exists("SELECT 1 FROM forumpost WHERE fpid=%d", rid)
2811
- ){
2812
- forumthread_page();
2813
- }else
28142814
{
28152815
artifact_page();
28162816
}
28172817
}
28182818
28192819
--- src/info.c
+++ src/info.c
@@ -2794,10 +2794,15 @@
2794 winfo_page();
2795 }else
2796 if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
2797 " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
2798 tinfo_page();
 
 
 
 
 
2799 }else
2800 if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
2801 ci_page();
2802 }else
2803 if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
@@ -2804,15 +2809,10 @@
2804 ci_page();
2805 }else
2806 if( db_exists("SELECT 1 FROM attachment WHERE attachid=%d", rid) ){
2807 ainfo_page();
2808 }else
2809 if( db_table_exists("repository","forumpost")
2810 && db_exists("SELECT 1 FROM forumpost WHERE fpid=%d", rid)
2811 ){
2812 forumthread_page();
2813 }else
2814 {
2815 artifact_page();
2816 }
2817 }
2818
2819
--- src/info.c
+++ src/info.c
@@ -2794,10 +2794,15 @@
2794 winfo_page();
2795 }else
2796 if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
2797 " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
2798 tinfo_page();
2799 }else
2800 if( db_table_exists("repository","forumpost")
2801 && db_exists("SELECT 1 FROM forumpost WHERE fpid=%d", rid)
2802 ){
2803 forumthread_page();
2804 }else
2805 if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
2806 ci_page();
2807 }else
2808 if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
@@ -2804,15 +2809,10 @@
2809 ci_page();
2810 }else
2811 if( db_exists("SELECT 1 FROM attachment WHERE attachid=%d", rid) ){
2812 ainfo_page();
2813 }else
 
 
 
 
 
2814 {
2815 artifact_page();
2816 }
2817 }
2818
2819
+42 -1
--- src/pikchr.c
+++ src/pikchr.c
@@ -7308,10 +7308,28 @@
73087308
}else{
73097309
pToken->eType = T_LT;
73107310
return 1;
73117311
}
73127312
}
7313
+ case 0xe2: {
7314
+ if( z[1]==0x86 ){
7315
+ if( z[2]==0x90 ){
7316
+ pToken->eType = T_LARROW; /* <- */
7317
+ return 3;
7318
+ }
7319
+ if( z[2]==0x92 ){
7320
+ pToken->eType = T_RARROW; /* -> */
7321
+ return 3;
7322
+ }
7323
+ if( z[2]==0x94 ){
7324
+ pToken->eType = T_LRARROW; /* <-> */
7325
+ return 3;
7326
+ }
7327
+ }
7328
+ pToken->eType = T_ERROR;
7329
+ return 1;
7330
+ }
73137331
case '{': {
73147332
int len, depth;
73157333
i = 1;
73167334
if( bAllowCodeBlock ){
73177335
depth = 1;
@@ -7332,10 +7350,33 @@
73327350
pToken->eType = T_ERROR;
73337351
return 1;
73347352
}
73357353
pToken->eType = T_CODEBLOCK;
73367354
return i;
7355
+ }
7356
+ case '&': {
7357
+ static const struct {
7358
+ int nByte; /* Number of bytes in zEntity */
7359
+ int eCode; /* Corresponding token code */
7360
+ const char *zEntity; /* Name of the HTML entity */
7361
+ } aEntity[] = {
7362
+ /* 123456789 1234567 */
7363
+ { 6, T_RARROW, "&rarr;" }, /* Same as -> */
7364
+ { 12, T_RARROW, "&rightarrow;" }, /* Same as -> */
7365
+ { 6, T_LARROW, "&larr;" }, /* Same as <- */
7366
+ { 11, T_LARROW, "&leftarrow;" }, /* Same as <- */
7367
+ { 16, T_LRARROW, "&leftrightarrow;" }, /* Same as <-> */
7368
+ };
7369
+ unsigned int i;
7370
+ for(i=0; i<sizeof(aEntity)/sizeof(aEntity[0]); i++){
7371
+ if( strncmp((const char*)z,aEntity[i].zEntity,aEntity[i].nByte)==0 ){
7372
+ pToken->eType = aEntity[i].eCode;
7373
+ return aEntity[i].nByte;
7374
+ }
7375
+ }
7376
+ pToken->eType = T_ERROR;
7377
+ return 1;
73377378
}
73387379
default: {
73397380
c = z[0];
73407381
if( c=='.' ){
73417382
unsigned char c1 = z[1];
@@ -7960,6 +8001,6 @@
79608001
79618002
79628003
#endif /* PIKCHR_TCL */
79638004
79648005
7965
-#line 7990 "pikchr.c"
8006
+#line 8031 "pikchr.c"
79668007
--- src/pikchr.c
+++ src/pikchr.c
@@ -7308,10 +7308,28 @@
7308 }else{
7309 pToken->eType = T_LT;
7310 return 1;
7311 }
7312 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7313 case '{': {
7314 int len, depth;
7315 i = 1;
7316 if( bAllowCodeBlock ){
7317 depth = 1;
@@ -7332,10 +7350,33 @@
7332 pToken->eType = T_ERROR;
7333 return 1;
7334 }
7335 pToken->eType = T_CODEBLOCK;
7336 return i;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7337 }
7338 default: {
7339 c = z[0];
7340 if( c=='.' ){
7341 unsigned char c1 = z[1];
@@ -7960,6 +8001,6 @@
7960
7961
7962 #endif /* PIKCHR_TCL */
7963
7964
7965 #line 7990 "pikchr.c"
7966
--- src/pikchr.c
+++ src/pikchr.c
@@ -7308,10 +7308,28 @@
7308 }else{
7309 pToken->eType = T_LT;
7310 return 1;
7311 }
7312 }
7313 case 0xe2: {
7314 if( z[1]==0x86 ){
7315 if( z[2]==0x90 ){
7316 pToken->eType = T_LARROW; /* <- */
7317 return 3;
7318 }
7319 if( z[2]==0x92 ){
7320 pToken->eType = T_RARROW; /* -> */
7321 return 3;
7322 }
7323 if( z[2]==0x94 ){
7324 pToken->eType = T_LRARROW; /* <-> */
7325 return 3;
7326 }
7327 }
7328 pToken->eType = T_ERROR;
7329 return 1;
7330 }
7331 case '{': {
7332 int len, depth;
7333 i = 1;
7334 if( bAllowCodeBlock ){
7335 depth = 1;
@@ -7332,10 +7350,33 @@
7350 pToken->eType = T_ERROR;
7351 return 1;
7352 }
7353 pToken->eType = T_CODEBLOCK;
7354 return i;
7355 }
7356 case '&': {
7357 static const struct {
7358 int nByte; /* Number of bytes in zEntity */
7359 int eCode; /* Corresponding token code */
7360 const char *zEntity; /* Name of the HTML entity */
7361 } aEntity[] = {
7362 /* 123456789 1234567 */
7363 { 6, T_RARROW, "&rarr;" }, /* Same as -> */
7364 { 12, T_RARROW, "&rightarrow;" }, /* Same as -> */
7365 { 6, T_LARROW, "&larr;" }, /* Same as <- */
7366 { 11, T_LARROW, "&leftarrow;" }, /* Same as <- */
7367 { 16, T_LRARROW, "&leftrightarrow;" }, /* Same as <-> */
7368 };
7369 unsigned int i;
7370 for(i=0; i<sizeof(aEntity)/sizeof(aEntity[0]); i++){
7371 if( strncmp((const char*)z,aEntity[i].zEntity,aEntity[i].nByte)==0 ){
7372 pToken->eType = aEntity[i].eCode;
7373 return aEntity[i].nByte;
7374 }
7375 }
7376 pToken->eType = T_ERROR;
7377 return 1;
7378 }
7379 default: {
7380 c = z[0];
7381 if( c=='.' ){
7382 unsigned char c1 = z[1];
@@ -7960,6 +8001,6 @@
8001
8002
8003 #endif /* PIKCHR_TCL */
8004
8005
8006 #line 8031 "pikchr.c"
8007
+5 -1
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161161
/*
162162
** This is the SQLite authorizer callback used to make sure that the
163163
** SQL statements entered by users do not try to do anything untoward.
164164
** If anything suspicious is tried, set *(char**)pError to an error
165165
** message obtained from malloc.
166
+**
167
+** Use the "fossil test-db-prepare --auth-report SQL" command to perform
168
+** manual testing of this authorizer.
166169
*/
167170
static int report_query_authorizer(
168171
void *pError,
169172
int code,
170173
const char *zArg1,
@@ -240,11 +243,12 @@
240243
}
241244
return rc;
242245
}
243246
244247
/*
245
-** Activate the query authorizer
248
+** Activate the ticket report query authorizer. Must be followed by an
249
+** eventual call to report_unrestrict_sql().
246250
*/
247251
void report_restrict_sql(char **pzErr){
248252
db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
249253
sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
250254
}
251255
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161 /*
162 ** This is the SQLite authorizer callback used to make sure that the
163 ** SQL statements entered by users do not try to do anything untoward.
164 ** If anything suspicious is tried, set *(char**)pError to an error
165 ** message obtained from malloc.
 
 
 
166 */
167 static int report_query_authorizer(
168 void *pError,
169 int code,
170 const char *zArg1,
@@ -240,11 +243,12 @@
240 }
241 return rc;
242 }
243
244 /*
245 ** Activate the query authorizer
 
246 */
247 void report_restrict_sql(char **pzErr){
248 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
249 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
250 }
251
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161 /*
162 ** This is the SQLite authorizer callback used to make sure that the
163 ** SQL statements entered by users do not try to do anything untoward.
164 ** If anything suspicious is tried, set *(char**)pError to an error
165 ** message obtained from malloc.
166 **
167 ** Use the "fossil test-db-prepare --auth-report SQL" command to perform
168 ** manual testing of this authorizer.
169 */
170 static int report_query_authorizer(
171 void *pError,
172 int code,
173 const char *zArg1,
@@ -240,11 +243,12 @@
243 }
244 return rc;
245 }
246
247 /*
248 ** Activate the ticket report query authorizer. Must be followed by an
249 ** eventual call to report_unrestrict_sql().
250 */
251 void report_restrict_sql(char **pzErr){
252 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
253 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
254 }
255
+5 -1
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161161
/*
162162
** This is the SQLite authorizer callback used to make sure that the
163163
** SQL statements entered by users do not try to do anything untoward.
164164
** If anything suspicious is tried, set *(char**)pError to an error
165165
** message obtained from malloc.
166
+**
167
+** Use the "fossil test-db-prepare --auth-report SQL" command to perform
168
+** manual testing of this authorizer.
166169
*/
167170
static int report_query_authorizer(
168171
void *pError,
169172
int code,
170173
const char *zArg1,
@@ -240,11 +243,12 @@
240243
}
241244
return rc;
242245
}
243246
244247
/*
245
-** Activate the query authorizer
248
+** Activate the ticket report query authorizer. Must be followed by an
249
+** eventual call to report_unrestrict_sql().
246250
*/
247251
void report_restrict_sql(char **pzErr){
248252
db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
249253
sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
250254
}
251255
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161 /*
162 ** This is the SQLite authorizer callback used to make sure that the
163 ** SQL statements entered by users do not try to do anything untoward.
164 ** If anything suspicious is tried, set *(char**)pError to an error
165 ** message obtained from malloc.
 
 
 
166 */
167 static int report_query_authorizer(
168 void *pError,
169 int code,
170 const char *zArg1,
@@ -240,11 +243,12 @@
240 }
241 return rc;
242 }
243
244 /*
245 ** Activate the query authorizer
 
246 */
247 void report_restrict_sql(char **pzErr){
248 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
249 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
250 }
251
--- src/report.c
+++ src/report.c
@@ -161,10 +161,13 @@
161 /*
162 ** This is the SQLite authorizer callback used to make sure that the
163 ** SQL statements entered by users do not try to do anything untoward.
164 ** If anything suspicious is tried, set *(char**)pError to an error
165 ** message obtained from malloc.
166 **
167 ** Use the "fossil test-db-prepare --auth-report SQL" command to perform
168 ** manual testing of this authorizer.
169 */
170 static int report_query_authorizer(
171 void *pError,
172 int code,
173 const char *zArg1,
@@ -240,11 +243,12 @@
243 }
244 return rc;
245 }
246
247 /*
248 ** Activate the ticket report query authorizer. Must be followed by an
249 ** eventual call to report_unrestrict_sql().
250 */
251 void report_restrict_sql(char **pzErr){
252 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
253 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
254 }
255
+1 -1
--- src/schema.c
+++ src/schema.c
@@ -329,11 +329,11 @@
329329
@ rid INTEGER PRIMARY KEY -- Record ID of the phantom
330330
@ );
331331
@
332332
@ -- A record of orphaned delta-manifests. An orphan is a delta-manifest
333333
@ -- for which we have content, but its baseline-manifest is a phantom.
334
-@ -- We have to track all orphan maniftests so that when the baseline arrives,
334
+@ -- We have to track all orphan manifests so that when the baseline arrives,
335335
@ -- we know to process the orphaned deltas.
336336
@ CREATE TABLE orphan(
337337
@ rid INTEGER PRIMARY KEY, -- Delta manifest with a phantom baseline
338338
@ baseline INTEGER -- Phantom baseline of this orphan
339339
@ );
340340
--- src/schema.c
+++ src/schema.c
@@ -329,11 +329,11 @@
329 @ rid INTEGER PRIMARY KEY -- Record ID of the phantom
330 @ );
331 @
332 @ -- A record of orphaned delta-manifests. An orphan is a delta-manifest
333 @ -- for which we have content, but its baseline-manifest is a phantom.
334 @ -- We have to track all orphan maniftests so that when the baseline arrives,
335 @ -- we know to process the orphaned deltas.
336 @ CREATE TABLE orphan(
337 @ rid INTEGER PRIMARY KEY, -- Delta manifest with a phantom baseline
338 @ baseline INTEGER -- Phantom baseline of this orphan
339 @ );
340
--- src/schema.c
+++ src/schema.c
@@ -329,11 +329,11 @@
329 @ rid INTEGER PRIMARY KEY -- Record ID of the phantom
330 @ );
331 @
332 @ -- A record of orphaned delta-manifests. An orphan is a delta-manifest
333 @ -- for which we have content, but its baseline-manifest is a phantom.
334 @ -- We have to track all orphan manifests so that when the baseline arrives,
335 @ -- we know to process the orphaned deltas.
336 @ CREATE TABLE orphan(
337 @ rid INTEGER PRIMARY KEY, -- Delta manifest with a phantom baseline
338 @ baseline INTEGER -- Phantom baseline of this orphan
339 @ );
340
+6 -6
--- src/shell.c
+++ src/shell.c
@@ -6204,11 +6204,11 @@
62046204
}
62056205
}
62066206
}
62076207
if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
62086208
if( hit ) re_add_state(pNext, x+n);
6209
- break;
6209
+ break;
62106210
}
62116211
}
62126212
}
62136213
}
62146214
for(i=0; i<pNext->nState; i++){
@@ -6365,11 +6365,11 @@
63656365
const char *zErr;
63666366
while( (c = p->xNextChar(&p->sIn))!=0 ){
63676367
iStart = p->nState;
63686368
switch( c ){
63696369
case '|':
6370
- case '$':
6370
+ case '$':
63716371
case ')': {
63726372
p->sIn.i--;
63736373
return 0;
63746374
}
63756375
case '(': {
@@ -6381,11 +6381,11 @@
63816381
}
63826382
case '.': {
63836383
if( rePeek(p)=='*' ){
63846384
re_append(p, RE_OP_ANYSTAR, 0);
63856385
p->sIn.i++;
6386
- }else{
6386
+ }else{
63876387
re_append(p, RE_OP_ANY, 0);
63886388
}
63896389
break;
63906390
}
63916391
case '*': {
@@ -6590,12 +6590,12 @@
65906590
** A REGEXP B
65916591
**
65926592
** is implemented as regexp(B,A).
65936593
*/
65946594
static void re_sql_func(
6595
- sqlite3_context *context,
6596
- int argc,
6595
+ sqlite3_context *context,
6596
+ int argc,
65976597
sqlite3_value **argv
65986598
){
65996599
ReCompiled *pRe; /* Compiled regular expression */
66006600
const char *zPattern; /* The regular expression */
66016601
const unsigned char *zStr;/* String being searched */
@@ -14815,11 +14815,11 @@
1481514815
" Examples:",
1481614816
" .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
1481714817
" .ar -tf ARCHIVE # List members of ARCHIVE",
1481814818
" .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
1481914819
" See also:",
14820
- " http://sqlite.org/cli.html#sqlar_archive_support",
14820
+ " http://sqlite.org/cli.html#sqlite_archive_support",
1482114821
#endif
1482214822
#ifndef SQLITE_OMIT_AUTHORIZATION
1482314823
".auth ON|OFF Show authorizer callbacks",
1482414824
#endif
1482514825
".backup ?DB? FILE Backup DB (default \"main\") to FILE",
1482614826
--- src/shell.c
+++ src/shell.c
@@ -6204,11 +6204,11 @@
6204 }
6205 }
6206 }
6207 if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
6208 if( hit ) re_add_state(pNext, x+n);
6209 break;
6210 }
6211 }
6212 }
6213 }
6214 for(i=0; i<pNext->nState; i++){
@@ -6365,11 +6365,11 @@
6365 const char *zErr;
6366 while( (c = p->xNextChar(&p->sIn))!=0 ){
6367 iStart = p->nState;
6368 switch( c ){
6369 case '|':
6370 case '$':
6371 case ')': {
6372 p->sIn.i--;
6373 return 0;
6374 }
6375 case '(': {
@@ -6381,11 +6381,11 @@
6381 }
6382 case '.': {
6383 if( rePeek(p)=='*' ){
6384 re_append(p, RE_OP_ANYSTAR, 0);
6385 p->sIn.i++;
6386 }else{
6387 re_append(p, RE_OP_ANY, 0);
6388 }
6389 break;
6390 }
6391 case '*': {
@@ -6590,12 +6590,12 @@
6590 ** A REGEXP B
6591 **
6592 ** is implemented as regexp(B,A).
6593 */
6594 static void re_sql_func(
6595 sqlite3_context *context,
6596 int argc,
6597 sqlite3_value **argv
6598 ){
6599 ReCompiled *pRe; /* Compiled regular expression */
6600 const char *zPattern; /* The regular expression */
6601 const unsigned char *zStr;/* String being searched */
@@ -14815,11 +14815,11 @@
14815 " Examples:",
14816 " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
14817 " .ar -tf ARCHIVE # List members of ARCHIVE",
14818 " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
14819 " See also:",
14820 " http://sqlite.org/cli.html#sqlar_archive_support",
14821 #endif
14822 #ifndef SQLITE_OMIT_AUTHORIZATION
14823 ".auth ON|OFF Show authorizer callbacks",
14824 #endif
14825 ".backup ?DB? FILE Backup DB (default \"main\") to FILE",
14826
--- src/shell.c
+++ src/shell.c
@@ -6204,11 +6204,11 @@
6204 }
6205 }
6206 }
6207 if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
6208 if( hit ) re_add_state(pNext, x+n);
6209 break;
6210 }
6211 }
6212 }
6213 }
6214 for(i=0; i<pNext->nState; i++){
@@ -6365,11 +6365,11 @@
6365 const char *zErr;
6366 while( (c = p->xNextChar(&p->sIn))!=0 ){
6367 iStart = p->nState;
6368 switch( c ){
6369 case '|':
6370 case '$':
6371 case ')': {
6372 p->sIn.i--;
6373 return 0;
6374 }
6375 case '(': {
@@ -6381,11 +6381,11 @@
6381 }
6382 case '.': {
6383 if( rePeek(p)=='*' ){
6384 re_append(p, RE_OP_ANYSTAR, 0);
6385 p->sIn.i++;
6386 }else{
6387 re_append(p, RE_OP_ANY, 0);
6388 }
6389 break;
6390 }
6391 case '*': {
@@ -6590,12 +6590,12 @@
6590 ** A REGEXP B
6591 **
6592 ** is implemented as regexp(B,A).
6593 */
6594 static void re_sql_func(
6595 sqlite3_context *context,
6596 int argc,
6597 sqlite3_value **argv
6598 ){
6599 ReCompiled *pRe; /* Compiled regular expression */
6600 const char *zPattern; /* The regular expression */
6601 const unsigned char *zStr;/* String being searched */
@@ -14815,11 +14815,11 @@
14815 " Examples:",
14816 " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
14817 " .ar -tf ARCHIVE # List members of ARCHIVE",
14818 " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
14819 " See also:",
14820 " http://sqlite.org/cli.html#sqlite_archive_support",
14821 #endif
14822 #ifndef SQLITE_OMIT_AUTHORIZATION
14823 ".auth ON|OFF Show authorizer callbacks",
14824 #endif
14825 ".backup ?DB? FILE Backup DB (default \"main\") to FILE",
14826
+147 -80
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1205,11 +1205,11 @@
12051205
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
12061206
** [sqlite_version()] and [sqlite_source_id()].
12071207
*/
12081208
#define SQLITE_VERSION "3.36.0"
12091209
#define SQLITE_VERSION_NUMBER 3036000
1210
-#define SQLITE_SOURCE_ID "2021-06-07 00:41:18 2aa9368b63b42ac7c700516f109edcc6098c12b850eae591afed4e51a3f41819"
1210
+#define SQLITE_SOURCE_ID "2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9ef70"
12111211
12121212
/*
12131213
** CAPI3REF: Run-Time Library Version Numbers
12141214
** KEYWORDS: sqlite3_version sqlite3_sourceid
12151215
**
@@ -16558,10 +16558,16 @@
1655816558
*/
1655916559
#ifndef SET_FULLSYNC
1656016560
# define SET_FULLSYNC(x,y)
1656116561
#endif
1656216562
16563
+/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
16564
+*/
16565
+#ifndef SQLITE_MAX_PATHLEN
16566
+# define SQLITE_MAX_PATHLEN FILENAME_MAX
16567
+#endif
16568
+
1656316569
/*
1656416570
** The default size of a disk sector
1656516571
*/
1656616572
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
1656716573
# define SQLITE_DEFAULT_SECTOR_SIZE 4096
@@ -18795,10 +18801,11 @@
1879518801
#define SF_View 0x0200000 /* SELECT statement is a view */
1879618802
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
1879718803
#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
1879818804
#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
1879918805
#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
18806
+#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
1880018807
1880118808
/*
1880218809
** The results of a SELECT can be distributed in several ways, as defined
1880318810
** by one of the following macros. The "SRT" prefix means "SELECT Result
1880418811
** Type".
@@ -20158,10 +20165,11 @@
2015820165
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
2015920166
SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
2016020167
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
2016120168
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
2016220169
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
20170
+SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p);
2016320171
2016420172
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
2016520173
SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
2016620174
#endif
2016720175
@@ -20568,11 +20576,11 @@
2056820576
#ifndef SQLITE_OMIT_CTE
2056920577
SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
2057020578
SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*);
2057120579
SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*);
2057220580
SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*);
20573
-SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8);
20581
+SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8);
2057420582
#else
2057520583
# define sqlite3CteNew(P,T,E,S) ((void*)0)
2057620584
# define sqlite3CteDelete(D,C)
2057720585
# define sqlite3CteWithAdd(P,W,C) ((void*)0)
2057820586
# define sqlite3WithDelete(x,y)
@@ -21670,11 +21678,11 @@
2167021678
SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
2167121679
SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*);
2167221680
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
2167321681
SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
2167421682
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
21675
-SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
21683
+SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*));
2167621684
SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
2167721685
#ifdef SQLITE_OMIT_FLOATING_POINT
2167821686
# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
2167921687
#else
2168021688
SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
@@ -23667,10 +23675,12 @@
2366723675
zPathOut[0] = 0;
2366823676
return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
2366923677
}
2367023678
#ifndef SQLITE_OMIT_LOAD_EXTENSION
2367123679
SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
23680
+ assert( zPath!=0 );
23681
+ assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */
2367223682
return pVfs->xDlOpen(pVfs, zPath);
2367323683
}
2367423684
SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
2367523685
pVfs->xDlError(pVfs, nByte, zBufOut);
2367623686
}
@@ -66965,11 +66975,11 @@
6696566975
testcase( pc+size==usableSize );
6696666976
put2byte(pAddr, cbrk);
6696766977
if( temp==0 ){
6696866978
if( cbrk==pc ) continue;
6696966979
temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
66970
- memcpy(&temp[iCellStart], &data[iCellStart], (cbrk+size) - iCellStart);
66980
+ memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
6697166981
src = temp;
6697266982
}
6697366983
memcpy(&data[cbrk], &src[pc], size);
6697466984
}
6697566985
data[hdr+7] = 0;
@@ -78047,15 +78057,15 @@
7804778057
** either case, SQLITE_TOOBIG is returned.
7804878058
*/
7804978059
SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
7805078060
Mem *pMem, /* Memory cell to set to string value */
7805178061
const char *z, /* String pointer */
78052
- int n, /* Bytes in string, or negative */
78062
+ i64 n, /* Bytes in string, or negative */
7805378063
u8 enc, /* Encoding of z. 0 for BLOBs */
7805478064
void (*xDel)(void*) /* Destructor function */
7805578065
){
78056
- int nByte = n; /* New value for pMem->n */
78066
+ i64 nByte = n; /* New value for pMem->n */
7805778067
int iLimit; /* Maximum allowed string or blob size */
7805878068
u16 flags = 0; /* New value for pMem->flags */
7805978069
7806078070
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
7806178071
assert( !sqlite3VdbeMemIsRowSet(pMem) );
@@ -78073,11 +78083,11 @@
7807378083
}
7807478084
flags = (enc==0?MEM_Blob:MEM_Str);
7807578085
if( nByte<0 ){
7807678086
assert( enc!=0 );
7807778087
if( enc==SQLITE_UTF8 ){
78078
- nByte = 0x7fffffff & (int)strlen(z);
78088
+ nByte = strlen(z);
7807978089
}else{
7808078090
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
7808178091
}
7808278092
flags |= MEM_Term;
7808378093
}
@@ -78085,11 +78095,11 @@
7808578095
/* The following block sets the new values of Mem.z and Mem.xDel. It
7808678096
** also sets a flag in local variable "flags" to indicate the memory
7808778097
** management (one of MEM_Dyn or MEM_Static).
7808878098
*/
7808978099
if( xDel==SQLITE_TRANSIENT ){
78090
- u32 nAlloc = nByte;
78100
+ i64 nAlloc = nByte;
7809178101
if( flags&MEM_Term ){
7809278102
nAlloc += (enc==SQLITE_UTF8?1:2);
7809378103
}
7809478104
if( nByte>iLimit ){
7809578105
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
@@ -78111,11 +78121,11 @@
7811178121
pMem->xDel = xDel;
7811278122
flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
7811378123
}
7811478124
}
7811578125
78116
- pMem->n = nByte;
78126
+ pMem->n = (int)(nByte & 0x7fffffff);
7811778127
pMem->flags = flags;
7811878128
if( enc ){
7811978129
pMem->enc = enc;
7812078130
#ifdef SQLITE_ENABLE_SESSION
7812178131
}else if( pMem->db==0 ){
@@ -78131,11 +78141,11 @@
7813178141
return SQLITE_NOMEM_BKPT;
7813278142
}
7813378143
#endif
7813478144
7813578145
if( nByte>iLimit ){
78136
- return SQLITE_TOOBIG;
78146
+ return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
7813778147
}
7813878148
7813978149
return SQLITE_OK;
7814078150
}
7814178151
@@ -84527,11 +84537,11 @@
8452784537
}else if( xDel==SQLITE_TRANSIENT ){
8452884538
/* noop */
8452984539
}else{
8453084540
xDel((void*)p);
8453184541
}
84532
- if( pCtx ) sqlite3_result_error_toobig(pCtx);
84542
+ sqlite3_result_error_toobig(pCtx);
8453384543
return SQLITE_TOOBIG;
8453484544
}
8453584545
SQLITE_API void sqlite3_result_blob(
8453684546
sqlite3_context *pCtx,
8453784547
const void *z,
@@ -85509,11 +85519,11 @@
8550985519
*/
8551085520
static int bindText(
8551185521
sqlite3_stmt *pStmt, /* The statement to bind against */
8551285522
int i, /* Index of the parameter to bind */
8551385523
const void *zData, /* Pointer to the data to be bound */
85514
- int nData, /* Number of bytes of data to be bound */
85524
+ i64 nData, /* Number of bytes of data to be bound */
8551585525
void (*xDel)(void*), /* Destructor for the data */
8551685526
u8 encoding /* Encoding for the data */
8551785527
){
8551885528
Vdbe *p = (Vdbe *)pStmt;
8551985529
Mem *pVar;
@@ -85561,15 +85571,11 @@
8556185571
const void *zData,
8556285572
sqlite3_uint64 nData,
8556385573
void (*xDel)(void*)
8556485574
){
8556585575
assert( xDel!=SQLITE_DYNAMIC );
85566
- if( nData>0x7fffffff ){
85567
- return invokeValueDestructor(zData, xDel, 0);
85568
- }else{
85569
- return bindText(pStmt, i, zData, (int)nData, xDel, 0);
85570
- }
85576
+ return bindText(pStmt, i, zData, nData, xDel, 0);
8557185577
}
8557285578
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
8557385579
int rc;
8557485580
Vdbe *p = (Vdbe *)pStmt;
8557585581
rc = vdbeUnbind(p, i);
@@ -85635,16 +85641,12 @@
8563585641
sqlite3_uint64 nData,
8563685642
void (*xDel)(void*),
8563785643
unsigned char enc
8563885644
){
8563985645
assert( xDel!=SQLITE_DYNAMIC );
85640
- if( nData>0x7fffffff ){
85641
- return invokeValueDestructor(zData, xDel, 0);
85642
- }else{
85643
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
85644
- return bindText(pStmt, i, zData, (int)nData, xDel, enc);
85645
- }
85646
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
85647
+ return bindText(pStmt, i, zData, nData, xDel, enc);
8564685648
}
8564785649
#ifndef SQLITE_OMIT_UTF16
8564885650
SQLITE_API int sqlite3_bind_text16(
8564985651
sqlite3_stmt *pStmt,
8565085652
int i,
@@ -90957,11 +90959,12 @@
9095790959
assert( pOp[1].opcode==OP_SeekGE );
9095890960
9095990961
/* pOp->p2 points to the first instruction past the OP_IdxGT that
9096090962
** follows the OP_SeekGE. */
9096190963
assert( pOp->p2>=(int)(pOp-aOp)+2 );
90962
- assert( aOp[pOp->p2-1].opcode==OP_IdxGT );
90964
+ assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
90965
+ testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
9096390966
assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
9096490967
assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
9096590968
assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
9096690969
9096790970
assert( pOp->p1>0 );
@@ -92847,11 +92850,13 @@
9284792850
}
9284892851
#endif
9284992852
9285092853
iDb = pOp->p1;
9285192854
assert( iDb>=0 && iDb<db->nDb );
92852
- assert( DbHasProperty(db, iDb, DB_SchemaLoaded) || db->mallocFailed );
92855
+ assert( DbHasProperty(db, iDb, DB_SchemaLoaded)
92856
+ || db->mallocFailed
92857
+ || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) );
9285392858
9285492859
#ifndef SQLITE_OMIT_ALTERTABLE
9285592860
if( pOp->p4.z==0 ){
9285692861
sqlite3SchemaClear(db->aDb[iDb].pSchema);
9285792862
db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
@@ -102622,11 +102627,11 @@
102622102627
** Create and return a deep copy of the object passed as the second
102623102628
** argument. If an OOM condition is encountered, NULL is returned
102624102629
** and the db->mallocFailed flag set.
102625102630
*/
102626102631
#ifndef SQLITE_OMIT_CTE
102627
-static With *withDup(sqlite3 *db, With *p){
102632
+SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
102628102633
With *pRet = 0;
102629102634
if( p ){
102630102635
sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
102631102636
pRet = sqlite3DbMallocZero(db, nByte);
102632102637
if( pRet ){
@@ -102640,11 +102645,11 @@
102640102645
}
102641102646
}
102642102647
return pRet;
102643102648
}
102644102649
#else
102645
-# define withDup(x,y) 0
102650
+# define sqlite3WithDup(x,y) 0
102646102651
#endif
102647102652
102648102653
#ifndef SQLITE_OMIT_WINDOWFUNC
102649102654
/*
102650102655
** The gatherSelectWindows() procedure and its helper routine
@@ -102844,11 +102849,11 @@
102844102849
pNew->iOffset = 0;
102845102850
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
102846102851
pNew->addrOpenEphm[0] = -1;
102847102852
pNew->addrOpenEphm[1] = -1;
102848102853
pNew->nSelectRow = p->nSelectRow;
102849
- pNew->pWith = withDup(db, p->pWith);
102854
+ pNew->pWith = sqlite3WithDup(db, p->pWith);
102850102855
#ifndef SQLITE_OMIT_WINDOWFUNC
102851102856
pNew->pWin = 0;
102852102857
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
102853102858
if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
102854102859
#endif
@@ -108184,19 +108189,34 @@
108184108189
** to select statement pSelect.
108185108190
*/
108186108191
static void renameWalkWith(Walker *pWalker, Select *pSelect){
108187108192
With *pWith = pSelect->pWith;
108188108193
if( pWith ){
108194
+ Parse *pParse = pWalker->pParse;
108189108195
int i;
108196
+ With *pCopy = 0;
108197
+ assert( pWith->nCte>0 );
108198
+ if( (pWith->a[0].pSelect->selFlags & SF_Expanded)==0 ){
108199
+ /* Push a copy of the With object onto the with-stack. We use a copy
108200
+ ** here as the original will be expanded and resolved (flags SF_Expanded
108201
+ ** and SF_Resolved) below. And the parser code that uses the with-stack
108202
+ ** fails if the Select objects on it have already been expanded and
108203
+ ** resolved. */
108204
+ pCopy = sqlite3WithDup(pParse->db, pWith);
108205
+ pCopy = sqlite3WithPush(pParse, pCopy, 1);
108206
+ }
108190108207
for(i=0; i<pWith->nCte; i++){
108191108208
Select *p = pWith->a[i].pSelect;
108192108209
NameContext sNC;
108193108210
memset(&sNC, 0, sizeof(sNC));
108194
- sNC.pParse = pWalker->pParse;
108195
- sqlite3SelectPrep(sNC.pParse, p, &sNC);
108211
+ sNC.pParse = pParse;
108212
+ if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC);
108196108213
sqlite3WalkSelect(pWalker, p);
108197
- sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
108214
+ sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols);
108215
+ }
108216
+ if( pCopy && pParse->pWith==pCopy ){
108217
+ pParse->pWith = pCopy->pOuter;
108198108218
}
108199108219
}
108200108220
}
108201108221
108202108222
/*
@@ -108219,11 +108239,15 @@
108219108239
*/
108220108240
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
108221108241
Parse *pParse = pWalker->pParse;
108222108242
int i;
108223108243
if( pParse->nErr ) return WRC_Abort;
108224
- if( p->selFlags & SF_View ) return WRC_Prune;
108244
+ if( p->selFlags & (SF_View|SF_CopyCte) ){
108245
+ testcase( pSelect->selFlags & SF_View );
108246
+ testcase( pSelect->selFlags & SF_CopyCte );
108247
+ return WRC_Prune;
108248
+ }
108225108249
if( ALWAYS(p->pEList) ){
108226108250
ExprList *pList = p->pEList;
108227108251
for(i=0; i<pList->nExpr; i++){
108228108252
if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
108229108253
sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
@@ -108327,11 +108351,15 @@
108327108351
** This is a Walker select callback. It does nothing. It is only required
108328108352
** because without a dummy callback, sqlite3WalkExpr() and similar do not
108329108353
** descend into sub-select statements.
108330108354
*/
108331108355
static int renameColumnSelectCb(Walker *pWalker, Select *p){
108332
- if( p->selFlags & SF_View ) return WRC_Prune;
108356
+ if( p->selFlags & (SF_View|SF_CopyCte) ){
108357
+ testcase( pSelect->selFlags & SF_View );
108358
+ testcase( pSelect->selFlags & SF_CopyCte );
108359
+ return WRC_Prune;
108360
+ }
108333108361
renameWalkWith(pWalker, p);
108334108362
return WRC_Continue;
108335108363
}
108336108364
108337108365
/*
@@ -108963,11 +108991,15 @@
108963108991
*/
108964108992
static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
108965108993
int i;
108966108994
RenameCtx *p = pWalker->u.pRename;
108967108995
SrcList *pSrc = pSelect->pSrc;
108968
- if( pSelect->selFlags & SF_View ) return WRC_Prune;
108996
+ if( pSelect->selFlags & (SF_View|SF_CopyCte) ){
108997
+ testcase( pSelect->selFlags & SF_View );
108998
+ testcase( pSelect->selFlags & SF_CopyCte );
108999
+ return WRC_Prune;
109000
+ }
108969109001
if( NEVER(pSrc==0) ){
108970109002
assert( pWalker->pParse->db->mallocFailed );
108971109003
return WRC_Abort;
108972109004
}
108973109005
for(i=0; i<pSrc->nSrc; i++){
@@ -116705,11 +116737,11 @@
116705116737
const char *zDb = db->aDb[iDb].zDbSName;
116706116738
const char *zTab = SCHEMA_TABLE(iDb);
116707116739
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
116708116740
goto exit_drop_index;
116709116741
}
116710
- if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
116742
+ if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
116711116743
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
116712116744
goto exit_drop_index;
116713116745
}
116714116746
}
116715116747
#endif
@@ -119237,17 +119269,19 @@
119237119269
){
119238119270
/* This column was already computed by the previous index */
119239119271
continue;
119240119272
}
119241119273
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
119242
- /* If the column affinity is REAL but the number is an integer, then it
119243
- ** might be stored in the table as an integer (using a compact
119244
- ** representation) then converted to REAL by an OP_RealAffinity opcode.
119245
- ** But we are getting ready to store this value back into an index, where
119246
- ** it should be converted by to INTEGER again. So omit the OP_RealAffinity
119247
- ** opcode if it is present */
119248
- sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
119274
+ if( pIdx->aiColumn[j]>=0 ){
119275
+ /* If the column affinity is REAL but the number is an integer, then it
119276
+ ** might be stored in the table as an integer (using a compact
119277
+ ** representation) then converted to REAL by an OP_RealAffinity opcode.
119278
+ ** But we are getting ready to store this value back into an index, where
119279
+ ** it should be converted by to INTEGER again. So omit the
119280
+ ** OP_RealAffinity opcode if it is present */
119281
+ sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
119282
+ }
119249119283
}
119250119284
if( regOut ){
119251119285
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
119252119286
}
119253119287
sqlite3ReleaseTempRange(pParse, regBase, nCol);
@@ -127401,11 +127435,11 @@
127401127435
sqlite3_loadext_entry xInit;
127402127436
char *zErrmsg = 0;
127403127437
const char *zEntry;
127404127438
char *zAltEntry = 0;
127405127439
void **aHandle;
127406
- u64 nMsg = 300 + sqlite3Strlen30(zFile);
127440
+ u64 nMsg = strlen(zFile);
127407127441
int ii;
127408127442
int rc;
127409127443
127410127444
/* Shared library endings to try if zFile cannot be loaded as written */
127411127445
static const char *azEndings[] = {
@@ -127435,30 +127469,26 @@
127435127469
return SQLITE_ERROR;
127436127470
}
127437127471
127438127472
zEntry = zProc ? zProc : "sqlite3_extension_init";
127439127473
127474
+ /* tag-20210611-1. Some dlopen() implementations will segfault if given
127475
+ ** an oversize filename. Most filesystems have a pathname limit of 4K,
127476
+ ** so limit the extension filename length to about twice that.
127477
+ ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
127478
+ if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
127479
+
127440127480
handle = sqlite3OsDlOpen(pVfs, zFile);
127441127481
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
127442127482
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
127443127483
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
127444127484
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
127445127485
handle = sqlite3OsDlOpen(pVfs, zAltFile);
127446127486
sqlite3_free(zAltFile);
127447127487
}
127448127488
#endif
127449
- if( handle==0 ){
127450
- if( pzErrMsg ){
127451
- *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127452
- if( zErrmsg ){
127453
- sqlite3_snprintf(nMsg, zErrmsg,
127454
- "unable to open shared library [%s]", zFile);
127455
- sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127456
- }
127457
- }
127458
- return SQLITE_ERROR;
127459
- }
127489
+ if( handle==0 ) goto extension_not_found;
127460127490
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
127461127491
127462127492
/* If no entry point was specified and the default legacy
127463127493
** entry point name "sqlite3_extension_init" was not found, then
127464127494
** construct an entry point name "sqlite3_X_init" where the X is
@@ -127491,14 +127521,15 @@
127491127521
zEntry = zAltEntry;
127492127522
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
127493127523
}
127494127524
if( xInit==0 ){
127495127525
if( pzErrMsg ){
127496
- nMsg += sqlite3Strlen30(zEntry);
127526
+ nMsg += strlen(zEntry) + 300;
127497127527
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127498127528
if( zErrmsg ){
127499
- sqlite3_snprintf(nMsg, zErrmsg,
127529
+ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
127530
+ sqlite3_snprintf((int)nMsg, zErrmsg,
127500127531
"no entry point [%s] in shared library [%s]", zEntry, zFile);
127501127532
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127502127533
}
127503127534
}
127504127535
sqlite3OsDlClose(pVfs, handle);
@@ -127528,10 +127559,23 @@
127528127559
sqlite3DbFree(db, db->aExtension);
127529127560
db->aExtension = aHandle;
127530127561
127531127562
db->aExtension[db->nExtension++] = handle;
127532127563
return SQLITE_OK;
127564
+
127565
+extension_not_found:
127566
+ if( pzErrMsg ){
127567
+ nMsg += 300;
127568
+ *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127569
+ if( zErrmsg ){
127570
+ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
127571
+ sqlite3_snprintf((int)nMsg, zErrmsg,
127572
+ "unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile);
127573
+ sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127574
+ }
127575
+ }
127576
+ return SQLITE_ERROR;
127533127577
}
127534127578
SQLITE_API int sqlite3_load_extension(
127535127579
sqlite3 *db, /* Load the extension into this database connection */
127536127580
const char *zFile, /* Name of the shared library containing extension */
127537127581
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
@@ -131368,13 +131412,15 @@
131368131412
if( rc==SQLITE_OK ){
131369131413
sqlite3AnalysisLoad(db, iDb);
131370131414
}
131371131415
#endif
131372131416
}
131417
+ assert( pDb == &(db->aDb[iDb]) );
131373131418
if( db->mallocFailed ){
131374131419
rc = SQLITE_NOMEM_BKPT;
131375131420
sqlite3ResetAllSchemasOfConnection(db);
131421
+ pDb = &db->aDb[iDb];
131376131422
}else
131377131423
if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
131378131424
/* Hack: If the SQLITE_NoSchemaError flag is set, then consider
131379131425
** the schema loaded, even if errors (other than OOM) occurred. In
131380131426
** this situation the current sqlite3_prepare() operation will fail,
@@ -136426,10 +136472,11 @@
136426136472
** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
136427136473
*/
136428136474
typedef struct WhereConst WhereConst;
136429136475
struct WhereConst {
136430136476
Parse *pParse; /* Parsing context */
136477
+ u8 *pOomFault; /* Pointer to pParse->db->mallocFailed */
136431136478
int nConst; /* Number for COLUMN=CONSTANT terms */
136432136479
int nChng; /* Number of times a constant is propagated */
136433136480
int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */
136434136481
Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
136435136482
};
@@ -136525,10 +136572,11 @@
136525136572
WhereConst *pConst,
136526136573
Expr *pExpr,
136527136574
int bIgnoreAffBlob
136528136575
){
136529136576
int i;
136577
+ if( pConst->pOomFault[0] ) return WRC_Prune;
136530136578
if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
136531136579
if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
136532136580
testcase( ExprHasProperty(pExpr, EP_FixedCol) );
136533136581
testcase( ExprHasProperty(pExpr, EP_FromJoin) );
136534136582
return WRC_Continue;
@@ -136545,10 +136593,11 @@
136545136593
pConst->nChng++;
136546136594
ExprClearProperty(pExpr, EP_Leaf);
136547136595
ExprSetProperty(pExpr, EP_FixedCol);
136548136596
assert( pExpr->pLeft==0 );
136549136597
pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
136598
+ if( pConst->pParse->db->mallocFailed ) return WRC_Prune;
136550136599
break;
136551136600
}
136552136601
return WRC_Prune;
136553136602
}
136554136603
@@ -136577,10 +136626,11 @@
136577136626
if( pConst->bHasAffBlob ){
136578136627
if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE)
136579136628
|| pExpr->op==TK_IS
136580136629
){
136581136630
propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0);
136631
+ if( pConst->pOomFault[0] ) return WRC_Prune;
136582136632
if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){
136583136633
propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0);
136584136634
}
136585136635
}
136586136636
}
@@ -136644,10 +136694,11 @@
136644136694
){
136645136695
WhereConst x;
136646136696
Walker w;
136647136697
int nChng = 0;
136648136698
x.pParse = pParse;
136699
+ x.pOomFault = &pParse->db->mallocFailed;
136649136700
do{
136650136701
x.nConst = 0;
136651136702
x.nChng = 0;
136652136703
x.apExpr = 0;
136653136704
x.bHasAffBlob = 0;
@@ -137099,25 +137150,33 @@
137099137150
** onto the top of the stack. If argument bFree is true, then this
137100137151
** WITH clause will never be popped from the stack but should instead
137101137152
** be freed along with the Parse object. In other cases, when
137102137153
** bFree==0, the With object will be freed along with the SELECT
137103137154
** statement with which it is associated.
137155
+**
137156
+** This routine returns a copy of pWith. Or, if bFree is true and
137157
+** the pWith object is destroyed immediately due to an OOM condition,
137158
+** then this routine return NULL.
137159
+**
137160
+** If bFree is true, do not continue to use the pWith pointer after
137161
+** calling this routine, Instead, use only the return value.
137104137162
*/
137105
-SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
137163
+SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
137106137164
if( pWith ){
137165
+ if( bFree ){
137166
+ pWith = (With*)sqlite3ParserAddCleanup(pParse,
137167
+ (void(*)(sqlite3*,void*))sqlite3WithDelete,
137168
+ pWith);
137169
+ if( pWith==0 ) return 0;
137170
+ }
137107137171
if( pParse->nErr==0 ){
137108137172
assert( pParse->pWith!=pWith );
137109137173
pWith->pOuter = pParse->pWith;
137110137174
pParse->pWith = pWith;
137111137175
}
137112
- if( bFree ){
137113
- sqlite3ParserAddCleanup(pParse,
137114
- (void(*)(sqlite3*,void*))sqlite3WithDelete,
137115
- pWith);
137116
- testcase( pParse->earlyCleanup );
137117
- }
137118137176
}
137177
+ return pWith;
137119137178
}
137120137179
137121137180
/*
137122137181
** This function checks if argument pFrom refers to a CTE declared by
137123137182
** a WITH clause on the stack currently maintained by the parser (on the
@@ -137206,10 +137265,11 @@
137206137265
pTab->iPKey = -1;
137207137266
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
137208137267
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
137209137268
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
137210137269
if( db->mallocFailed ) return 2;
137270
+ pFrom->pSelect->selFlags |= SF_CopyCte;
137211137271
assert( pFrom->pSelect );
137212137272
pFrom->fg.isCte = 1;
137213137273
pFrom->u2.pCteUse = pCteUse;
137214137274
pCteUse->nUse++;
137215137275
if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
@@ -137474,10 +137534,11 @@
137474137534
){
137475137535
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
137476137536
pTab->zName);
137477137537
}
137478137538
#ifndef SQLITE_OMIT_VIRTUALTABLE
137539
+ assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 );
137479137540
if( IsVirtual(pTab)
137480137541
&& pFrom->fg.fromDDL
137481137542
&& ALWAYS(pTab->pVTable!=0)
137482137543
&& pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
137483137544
){
@@ -183221,12 +183282,12 @@
183221183282
int nPrev, /* Size of buffer zPrev in bytes */
183222183283
const char *zNext, /* Buffer containing next term */
183223183284
int nNext /* Size of buffer zNext in bytes */
183224183285
){
183225183286
int n;
183226
- UNUSED_PARAMETER(nNext);
183227
- for(n=0; n<nPrev && zPrev[n]==zNext[n]; n++);
183287
+ for(n=0; n<nPrev && n<nNext && zPrev[n]==zNext[n]; n++);
183288
+ assert_fts3_nc( n<nNext );
183228183289
return n;
183229183290
}
183230183291
183231183292
/*
183232183293
** Add term zTerm to the SegmentNode. It is guaranteed that zTerm is larger
@@ -184221,11 +184282,11 @@
184221184282
iDelta = (i64)((u64)iDocid - (u64)iPrev);
184222184283
}
184223184284
184224184285
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
184225184286
184226
- rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
184287
+ rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING);
184227184288
if( rc ) return rc;
184228184289
184229184290
if( isFirst ){
184230184291
char *a = &pCsr->aBuffer[nDoclist];
184231184292
int nWrite;
@@ -216164,10 +216225,11 @@
216164216225
return 1;
216165216226
}else{
216166216227
i64 iOff = *piOff;
216167216228
int iVal;
216168216229
fts5FastGetVarint32(a, i, iVal);
216230
+ assert( iVal>=0 );
216169216231
if( iVal<=1 ){
216170216232
if( iVal==0 ){
216171216233
*pi = i;
216172216234
return 0;
216173216235
}
@@ -216177,13 +216239,16 @@
216177216239
if( iVal<2 ){
216178216240
/* This is a corrupt record. So stop parsing it here. */
216179216241
*piOff = -1;
216180216242
return 1;
216181216243
}
216244
+ *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
216245
+ }else{
216246
+ *piOff = (iOff & (i64)0x7FFFFFFF<<32)+((iOff + (iVal-2)) & 0x7FFFFFFF);
216182216247
}
216183
- *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
216184216248
*pi = i;
216249
+ assert( *piOff>=iOff );
216185216250
return 0;
216186216251
}
216187216252
}
216188216253
216189216254
@@ -216218,18 +216283,20 @@
216218216283
static void sqlite3Fts5PoslistSafeAppend(
216219216284
Fts5Buffer *pBuf,
216220216285
i64 *piPrev,
216221216286
i64 iPos
216222216287
){
216223
- static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
216224
- if( (iPos & colmask) != (*piPrev & colmask) ){
216225
- pBuf->p[pBuf->n++] = 1;
216226
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
216227
- *piPrev = (iPos & colmask);
216228
- }
216229
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
216230
- *piPrev = iPos;
216288
+ if( iPos>=*piPrev ){
216289
+ static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
216290
+ if( (iPos & colmask) != (*piPrev & colmask) ){
216291
+ pBuf->p[pBuf->n++] = 1;
216292
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
216293
+ *piPrev = (iPos & colmask);
216294
+ }
216295
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
216296
+ *piPrev = iPos;
216297
+ }
216231216298
}
216232216299
216233216300
static int sqlite3Fts5PoslistWriterAppend(
216234216301
Fts5Buffer *pBuf,
216235216302
Fts5PoslistWriter *pWriter,
@@ -224157,11 +224224,11 @@
224157224224
pIter->base.nData = p-aCopy;
224158224225
return;
224159224226
}
224160224227
fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy);
224161224228
}
224162
- if( p==pEnd ){
224229
+ if( p>=pEnd ){
224163224230
pIter->base.pData = pIter->poslist.p;
224164224231
pIter->base.nData = pIter->poslist.n;
224165224232
return;
224166224233
}
224167224234
aCopy = p++;
@@ -225953,11 +226020,11 @@
225953226020
Fts5Buffer *p1, /* First list to merge */
225954226021
int nBuf, /* Number of buffers in array aBuf[] */
225955226022
Fts5Buffer *aBuf /* Other lists to merge in */
225956226023
){
225957226024
#define fts5PrefixMergerNextPosition(p) \
225958
- sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos);
226025
+ sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos)
225959226026
#define FTS5_MERGE_NLIST 16
225960226027
PrefixMerger aMerger[FTS5_MERGE_NLIST];
225961226028
PrefixMerger *pHead = 0;
225962226029
int i;
225963226030
int nOut = 0;
@@ -230501,11 +230568,11 @@
230501230568
int nArg, /* Number of args */
230502230569
sqlite3_value **apUnused /* Function arguments */
230503230570
){
230504230571
assert( nArg==0 );
230505230572
UNUSED_PARAM2(nArg, apUnused);
230506
- sqlite3_result_text(pCtx, "fts5: 2021-06-04 23:26:56 1c71de43dbc68002c4a6229e7efffb019655baff67a51fe922571fe420c95835", -1, SQLITE_TRANSIENT);
230573
+ sqlite3_result_text(pCtx, "fts5: 2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9ef70", -1, SQLITE_TRANSIENT);
230507230574
}
230508230575
230509230576
/*
230510230577
** Return true if zName is the extension on one of the shadow tables used
230511230578
** by this module.
@@ -235427,12 +235494,12 @@
235427235494
}
235428235495
#endif /* SQLITE_CORE */
235429235496
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
235430235497
235431235498
/************** End of stmt.c ************************************************/
235432
-#if __LINE__!=235432
235499
+#if __LINE__!=235499
235433235500
#undef SQLITE_SOURCE_ID
235434
-#define SQLITE_SOURCE_ID "2021-06-07 00:41:18 2aa9368b63b42ac7c700516f109edcc6098c12b850eae591afed4e51a3f4alt2"
235501
+#define SQLITE_SOURCE_ID "2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9alt2"
235435235502
#endif
235436235503
/* Return the source-id for this library */
235437235504
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
235438235505
/************************** End of sqlite3.c ******************************/
235439235506
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1205,11 +1205,11 @@
1205 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1206 ** [sqlite_version()] and [sqlite_source_id()].
1207 */
1208 #define SQLITE_VERSION "3.36.0"
1209 #define SQLITE_VERSION_NUMBER 3036000
1210 #define SQLITE_SOURCE_ID "2021-06-07 00:41:18 2aa9368b63b42ac7c700516f109edcc6098c12b850eae591afed4e51a3f41819"
1211
1212 /*
1213 ** CAPI3REF: Run-Time Library Version Numbers
1214 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1215 **
@@ -16558,10 +16558,16 @@
16558 */
16559 #ifndef SET_FULLSYNC
16560 # define SET_FULLSYNC(x,y)
16561 #endif
16562
 
 
 
 
 
 
16563 /*
16564 ** The default size of a disk sector
16565 */
16566 #ifndef SQLITE_DEFAULT_SECTOR_SIZE
16567 # define SQLITE_DEFAULT_SECTOR_SIZE 4096
@@ -18795,10 +18801,11 @@
18795 #define SF_View 0x0200000 /* SELECT statement is a view */
18796 #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
18797 #define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
18798 #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
18799 #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
 
18800
18801 /*
18802 ** The results of a SELECT can be distributed in several ways, as defined
18803 ** by one of the following macros. The "SRT" prefix means "SELECT Result
18804 ** Type".
@@ -20158,10 +20165,11 @@
20158 SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
20159 SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
20160 SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
20161 SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
20162 SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
 
20163
20164 #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
20165 SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
20166 #endif
20167
@@ -20568,11 +20576,11 @@
20568 #ifndef SQLITE_OMIT_CTE
20569 SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
20570 SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*);
20571 SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*);
20572 SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*);
20573 SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8);
20574 #else
20575 # define sqlite3CteNew(P,T,E,S) ((void*)0)
20576 # define sqlite3CteDelete(D,C)
20577 # define sqlite3CteWithAdd(P,W,C) ((void*)0)
20578 # define sqlite3WithDelete(x,y)
@@ -21670,11 +21678,11 @@
21670 SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
21671 SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*);
21672 SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
21673 SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
21674 SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
21675 SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
21676 SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
21677 #ifdef SQLITE_OMIT_FLOATING_POINT
21678 # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
21679 #else
21680 SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
@@ -23667,10 +23675,12 @@
23667 zPathOut[0] = 0;
23668 return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
23669 }
23670 #ifndef SQLITE_OMIT_LOAD_EXTENSION
23671 SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
 
 
23672 return pVfs->xDlOpen(pVfs, zPath);
23673 }
23674 SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
23675 pVfs->xDlError(pVfs, nByte, zBufOut);
23676 }
@@ -66965,11 +66975,11 @@
66965 testcase( pc+size==usableSize );
66966 put2byte(pAddr, cbrk);
66967 if( temp==0 ){
66968 if( cbrk==pc ) continue;
66969 temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
66970 memcpy(&temp[iCellStart], &data[iCellStart], (cbrk+size) - iCellStart);
66971 src = temp;
66972 }
66973 memcpy(&data[cbrk], &src[pc], size);
66974 }
66975 data[hdr+7] = 0;
@@ -78047,15 +78057,15 @@
78047 ** either case, SQLITE_TOOBIG is returned.
78048 */
78049 SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
78050 Mem *pMem, /* Memory cell to set to string value */
78051 const char *z, /* String pointer */
78052 int n, /* Bytes in string, or negative */
78053 u8 enc, /* Encoding of z. 0 for BLOBs */
78054 void (*xDel)(void*) /* Destructor function */
78055 ){
78056 int nByte = n; /* New value for pMem->n */
78057 int iLimit; /* Maximum allowed string or blob size */
78058 u16 flags = 0; /* New value for pMem->flags */
78059
78060 assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
78061 assert( !sqlite3VdbeMemIsRowSet(pMem) );
@@ -78073,11 +78083,11 @@
78073 }
78074 flags = (enc==0?MEM_Blob:MEM_Str);
78075 if( nByte<0 ){
78076 assert( enc!=0 );
78077 if( enc==SQLITE_UTF8 ){
78078 nByte = 0x7fffffff & (int)strlen(z);
78079 }else{
78080 for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
78081 }
78082 flags |= MEM_Term;
78083 }
@@ -78085,11 +78095,11 @@
78085 /* The following block sets the new values of Mem.z and Mem.xDel. It
78086 ** also sets a flag in local variable "flags" to indicate the memory
78087 ** management (one of MEM_Dyn or MEM_Static).
78088 */
78089 if( xDel==SQLITE_TRANSIENT ){
78090 u32 nAlloc = nByte;
78091 if( flags&MEM_Term ){
78092 nAlloc += (enc==SQLITE_UTF8?1:2);
78093 }
78094 if( nByte>iLimit ){
78095 return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
@@ -78111,11 +78121,11 @@
78111 pMem->xDel = xDel;
78112 flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
78113 }
78114 }
78115
78116 pMem->n = nByte;
78117 pMem->flags = flags;
78118 if( enc ){
78119 pMem->enc = enc;
78120 #ifdef SQLITE_ENABLE_SESSION
78121 }else if( pMem->db==0 ){
@@ -78131,11 +78141,11 @@
78131 return SQLITE_NOMEM_BKPT;
78132 }
78133 #endif
78134
78135 if( nByte>iLimit ){
78136 return SQLITE_TOOBIG;
78137 }
78138
78139 return SQLITE_OK;
78140 }
78141
@@ -84527,11 +84537,11 @@
84527 }else if( xDel==SQLITE_TRANSIENT ){
84528 /* noop */
84529 }else{
84530 xDel((void*)p);
84531 }
84532 if( pCtx ) sqlite3_result_error_toobig(pCtx);
84533 return SQLITE_TOOBIG;
84534 }
84535 SQLITE_API void sqlite3_result_blob(
84536 sqlite3_context *pCtx,
84537 const void *z,
@@ -85509,11 +85519,11 @@
85509 */
85510 static int bindText(
85511 sqlite3_stmt *pStmt, /* The statement to bind against */
85512 int i, /* Index of the parameter to bind */
85513 const void *zData, /* Pointer to the data to be bound */
85514 int nData, /* Number of bytes of data to be bound */
85515 void (*xDel)(void*), /* Destructor for the data */
85516 u8 encoding /* Encoding for the data */
85517 ){
85518 Vdbe *p = (Vdbe *)pStmt;
85519 Mem *pVar;
@@ -85561,15 +85571,11 @@
85561 const void *zData,
85562 sqlite3_uint64 nData,
85563 void (*xDel)(void*)
85564 ){
85565 assert( xDel!=SQLITE_DYNAMIC );
85566 if( nData>0x7fffffff ){
85567 return invokeValueDestructor(zData, xDel, 0);
85568 }else{
85569 return bindText(pStmt, i, zData, (int)nData, xDel, 0);
85570 }
85571 }
85572 SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
85573 int rc;
85574 Vdbe *p = (Vdbe *)pStmt;
85575 rc = vdbeUnbind(p, i);
@@ -85635,16 +85641,12 @@
85635 sqlite3_uint64 nData,
85636 void (*xDel)(void*),
85637 unsigned char enc
85638 ){
85639 assert( xDel!=SQLITE_DYNAMIC );
85640 if( nData>0x7fffffff ){
85641 return invokeValueDestructor(zData, xDel, 0);
85642 }else{
85643 if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
85644 return bindText(pStmt, i, zData, (int)nData, xDel, enc);
85645 }
85646 }
85647 #ifndef SQLITE_OMIT_UTF16
85648 SQLITE_API int sqlite3_bind_text16(
85649 sqlite3_stmt *pStmt,
85650 int i,
@@ -90957,11 +90959,12 @@
90957 assert( pOp[1].opcode==OP_SeekGE );
90958
90959 /* pOp->p2 points to the first instruction past the OP_IdxGT that
90960 ** follows the OP_SeekGE. */
90961 assert( pOp->p2>=(int)(pOp-aOp)+2 );
90962 assert( aOp[pOp->p2-1].opcode==OP_IdxGT );
 
90963 assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
90964 assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
90965 assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
90966
90967 assert( pOp->p1>0 );
@@ -92847,11 +92850,13 @@
92847 }
92848 #endif
92849
92850 iDb = pOp->p1;
92851 assert( iDb>=0 && iDb<db->nDb );
92852 assert( DbHasProperty(db, iDb, DB_SchemaLoaded) || db->mallocFailed );
 
 
92853
92854 #ifndef SQLITE_OMIT_ALTERTABLE
92855 if( pOp->p4.z==0 ){
92856 sqlite3SchemaClear(db->aDb[iDb].pSchema);
92857 db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
@@ -102622,11 +102627,11 @@
102622 ** Create and return a deep copy of the object passed as the second
102623 ** argument. If an OOM condition is encountered, NULL is returned
102624 ** and the db->mallocFailed flag set.
102625 */
102626 #ifndef SQLITE_OMIT_CTE
102627 static With *withDup(sqlite3 *db, With *p){
102628 With *pRet = 0;
102629 if( p ){
102630 sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
102631 pRet = sqlite3DbMallocZero(db, nByte);
102632 if( pRet ){
@@ -102640,11 +102645,11 @@
102640 }
102641 }
102642 return pRet;
102643 }
102644 #else
102645 # define withDup(x,y) 0
102646 #endif
102647
102648 #ifndef SQLITE_OMIT_WINDOWFUNC
102649 /*
102650 ** The gatherSelectWindows() procedure and its helper routine
@@ -102844,11 +102849,11 @@
102844 pNew->iOffset = 0;
102845 pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
102846 pNew->addrOpenEphm[0] = -1;
102847 pNew->addrOpenEphm[1] = -1;
102848 pNew->nSelectRow = p->nSelectRow;
102849 pNew->pWith = withDup(db, p->pWith);
102850 #ifndef SQLITE_OMIT_WINDOWFUNC
102851 pNew->pWin = 0;
102852 pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
102853 if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
102854 #endif
@@ -108184,19 +108189,34 @@
108184 ** to select statement pSelect.
108185 */
108186 static void renameWalkWith(Walker *pWalker, Select *pSelect){
108187 With *pWith = pSelect->pWith;
108188 if( pWith ){
 
108189 int i;
 
 
 
 
 
 
 
 
 
 
 
108190 for(i=0; i<pWith->nCte; i++){
108191 Select *p = pWith->a[i].pSelect;
108192 NameContext sNC;
108193 memset(&sNC, 0, sizeof(sNC));
108194 sNC.pParse = pWalker->pParse;
108195 sqlite3SelectPrep(sNC.pParse, p, &sNC);
108196 sqlite3WalkSelect(pWalker, p);
108197 sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
 
 
 
108198 }
108199 }
108200 }
108201
108202 /*
@@ -108219,11 +108239,15 @@
108219 */
108220 static int renameUnmapSelectCb(Walker *pWalker, Select *p){
108221 Parse *pParse = pWalker->pParse;
108222 int i;
108223 if( pParse->nErr ) return WRC_Abort;
108224 if( p->selFlags & SF_View ) return WRC_Prune;
 
 
 
 
108225 if( ALWAYS(p->pEList) ){
108226 ExprList *pList = p->pEList;
108227 for(i=0; i<pList->nExpr; i++){
108228 if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
108229 sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
@@ -108327,11 +108351,15 @@
108327 ** This is a Walker select callback. It does nothing. It is only required
108328 ** because without a dummy callback, sqlite3WalkExpr() and similar do not
108329 ** descend into sub-select statements.
108330 */
108331 static int renameColumnSelectCb(Walker *pWalker, Select *p){
108332 if( p->selFlags & SF_View ) return WRC_Prune;
 
 
 
 
108333 renameWalkWith(pWalker, p);
108334 return WRC_Continue;
108335 }
108336
108337 /*
@@ -108963,11 +108991,15 @@
108963 */
108964 static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
108965 int i;
108966 RenameCtx *p = pWalker->u.pRename;
108967 SrcList *pSrc = pSelect->pSrc;
108968 if( pSelect->selFlags & SF_View ) return WRC_Prune;
 
 
 
 
108969 if( NEVER(pSrc==0) ){
108970 assert( pWalker->pParse->db->mallocFailed );
108971 return WRC_Abort;
108972 }
108973 for(i=0; i<pSrc->nSrc; i++){
@@ -116705,11 +116737,11 @@
116705 const char *zDb = db->aDb[iDb].zDbSName;
116706 const char *zTab = SCHEMA_TABLE(iDb);
116707 if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
116708 goto exit_drop_index;
116709 }
116710 if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
116711 if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
116712 goto exit_drop_index;
116713 }
116714 }
116715 #endif
@@ -119237,17 +119269,19 @@
119237 ){
119238 /* This column was already computed by the previous index */
119239 continue;
119240 }
119241 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
119242 /* If the column affinity is REAL but the number is an integer, then it
119243 ** might be stored in the table as an integer (using a compact
119244 ** representation) then converted to REAL by an OP_RealAffinity opcode.
119245 ** But we are getting ready to store this value back into an index, where
119246 ** it should be converted by to INTEGER again. So omit the OP_RealAffinity
119247 ** opcode if it is present */
119248 sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
 
 
119249 }
119250 if( regOut ){
119251 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
119252 }
119253 sqlite3ReleaseTempRange(pParse, regBase, nCol);
@@ -127401,11 +127435,11 @@
127401 sqlite3_loadext_entry xInit;
127402 char *zErrmsg = 0;
127403 const char *zEntry;
127404 char *zAltEntry = 0;
127405 void **aHandle;
127406 u64 nMsg = 300 + sqlite3Strlen30(zFile);
127407 int ii;
127408 int rc;
127409
127410 /* Shared library endings to try if zFile cannot be loaded as written */
127411 static const char *azEndings[] = {
@@ -127435,30 +127469,26 @@
127435 return SQLITE_ERROR;
127436 }
127437
127438 zEntry = zProc ? zProc : "sqlite3_extension_init";
127439
 
 
 
 
 
 
127440 handle = sqlite3OsDlOpen(pVfs, zFile);
127441 #if SQLITE_OS_UNIX || SQLITE_OS_WIN
127442 for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
127443 char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
127444 if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
127445 handle = sqlite3OsDlOpen(pVfs, zAltFile);
127446 sqlite3_free(zAltFile);
127447 }
127448 #endif
127449 if( handle==0 ){
127450 if( pzErrMsg ){
127451 *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127452 if( zErrmsg ){
127453 sqlite3_snprintf(nMsg, zErrmsg,
127454 "unable to open shared library [%s]", zFile);
127455 sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127456 }
127457 }
127458 return SQLITE_ERROR;
127459 }
127460 xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
127461
127462 /* If no entry point was specified and the default legacy
127463 ** entry point name "sqlite3_extension_init" was not found, then
127464 ** construct an entry point name "sqlite3_X_init" where the X is
@@ -127491,14 +127521,15 @@
127491 zEntry = zAltEntry;
127492 xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
127493 }
127494 if( xInit==0 ){
127495 if( pzErrMsg ){
127496 nMsg += sqlite3Strlen30(zEntry);
127497 *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127498 if( zErrmsg ){
127499 sqlite3_snprintf(nMsg, zErrmsg,
 
127500 "no entry point [%s] in shared library [%s]", zEntry, zFile);
127501 sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127502 }
127503 }
127504 sqlite3OsDlClose(pVfs, handle);
@@ -127528,10 +127559,23 @@
127528 sqlite3DbFree(db, db->aExtension);
127529 db->aExtension = aHandle;
127530
127531 db->aExtension[db->nExtension++] = handle;
127532 return SQLITE_OK;
 
 
 
 
 
 
 
 
 
 
 
 
 
127533 }
127534 SQLITE_API int sqlite3_load_extension(
127535 sqlite3 *db, /* Load the extension into this database connection */
127536 const char *zFile, /* Name of the shared library containing extension */
127537 const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
@@ -131368,13 +131412,15 @@
131368 if( rc==SQLITE_OK ){
131369 sqlite3AnalysisLoad(db, iDb);
131370 }
131371 #endif
131372 }
 
131373 if( db->mallocFailed ){
131374 rc = SQLITE_NOMEM_BKPT;
131375 sqlite3ResetAllSchemasOfConnection(db);
 
131376 }else
131377 if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
131378 /* Hack: If the SQLITE_NoSchemaError flag is set, then consider
131379 ** the schema loaded, even if errors (other than OOM) occurred. In
131380 ** this situation the current sqlite3_prepare() operation will fail,
@@ -136426,10 +136472,11 @@
136426 ** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
136427 */
136428 typedef struct WhereConst WhereConst;
136429 struct WhereConst {
136430 Parse *pParse; /* Parsing context */
 
136431 int nConst; /* Number for COLUMN=CONSTANT terms */
136432 int nChng; /* Number of times a constant is propagated */
136433 int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */
136434 Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
136435 };
@@ -136525,10 +136572,11 @@
136525 WhereConst *pConst,
136526 Expr *pExpr,
136527 int bIgnoreAffBlob
136528 ){
136529 int i;
 
136530 if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
136531 if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
136532 testcase( ExprHasProperty(pExpr, EP_FixedCol) );
136533 testcase( ExprHasProperty(pExpr, EP_FromJoin) );
136534 return WRC_Continue;
@@ -136545,10 +136593,11 @@
136545 pConst->nChng++;
136546 ExprClearProperty(pExpr, EP_Leaf);
136547 ExprSetProperty(pExpr, EP_FixedCol);
136548 assert( pExpr->pLeft==0 );
136549 pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
 
136550 break;
136551 }
136552 return WRC_Prune;
136553 }
136554
@@ -136577,10 +136626,11 @@
136577 if( pConst->bHasAffBlob ){
136578 if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE)
136579 || pExpr->op==TK_IS
136580 ){
136581 propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0);
 
136582 if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){
136583 propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0);
136584 }
136585 }
136586 }
@@ -136644,10 +136694,11 @@
136644 ){
136645 WhereConst x;
136646 Walker w;
136647 int nChng = 0;
136648 x.pParse = pParse;
 
136649 do{
136650 x.nConst = 0;
136651 x.nChng = 0;
136652 x.apExpr = 0;
136653 x.bHasAffBlob = 0;
@@ -137099,25 +137150,33 @@
137099 ** onto the top of the stack. If argument bFree is true, then this
137100 ** WITH clause will never be popped from the stack but should instead
137101 ** be freed along with the Parse object. In other cases, when
137102 ** bFree==0, the With object will be freed along with the SELECT
137103 ** statement with which it is associated.
 
 
 
 
 
 
 
137104 */
137105 SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
137106 if( pWith ){
 
 
 
 
 
 
137107 if( pParse->nErr==0 ){
137108 assert( pParse->pWith!=pWith );
137109 pWith->pOuter = pParse->pWith;
137110 pParse->pWith = pWith;
137111 }
137112 if( bFree ){
137113 sqlite3ParserAddCleanup(pParse,
137114 (void(*)(sqlite3*,void*))sqlite3WithDelete,
137115 pWith);
137116 testcase( pParse->earlyCleanup );
137117 }
137118 }
 
137119 }
137120
137121 /*
137122 ** This function checks if argument pFrom refers to a CTE declared by
137123 ** a WITH clause on the stack currently maintained by the parser (on the
@@ -137206,10 +137265,11 @@
137206 pTab->iPKey = -1;
137207 pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
137208 pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
137209 pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
137210 if( db->mallocFailed ) return 2;
 
137211 assert( pFrom->pSelect );
137212 pFrom->fg.isCte = 1;
137213 pFrom->u2.pCteUse = pCteUse;
137214 pCteUse->nUse++;
137215 if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
@@ -137474,10 +137534,11 @@
137474 ){
137475 sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
137476 pTab->zName);
137477 }
137478 #ifndef SQLITE_OMIT_VIRTUALTABLE
 
137479 if( IsVirtual(pTab)
137480 && pFrom->fg.fromDDL
137481 && ALWAYS(pTab->pVTable!=0)
137482 && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
137483 ){
@@ -183221,12 +183282,12 @@
183221 int nPrev, /* Size of buffer zPrev in bytes */
183222 const char *zNext, /* Buffer containing next term */
183223 int nNext /* Size of buffer zNext in bytes */
183224 ){
183225 int n;
183226 UNUSED_PARAMETER(nNext);
183227 for(n=0; n<nPrev && zPrev[n]==zNext[n]; n++);
183228 return n;
183229 }
183230
183231 /*
183232 ** Add term zTerm to the SegmentNode. It is guaranteed that zTerm is larger
@@ -184221,11 +184282,11 @@
184221 iDelta = (i64)((u64)iDocid - (u64)iPrev);
184222 }
184223
184224 nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
184225
184226 rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
184227 if( rc ) return rc;
184228
184229 if( isFirst ){
184230 char *a = &pCsr->aBuffer[nDoclist];
184231 int nWrite;
@@ -216164,10 +216225,11 @@
216164 return 1;
216165 }else{
216166 i64 iOff = *piOff;
216167 int iVal;
216168 fts5FastGetVarint32(a, i, iVal);
 
216169 if( iVal<=1 ){
216170 if( iVal==0 ){
216171 *pi = i;
216172 return 0;
216173 }
@@ -216177,13 +216239,16 @@
216177 if( iVal<2 ){
216178 /* This is a corrupt record. So stop parsing it here. */
216179 *piOff = -1;
216180 return 1;
216181 }
 
 
 
216182 }
216183 *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
216184 *pi = i;
 
216185 return 0;
216186 }
216187 }
216188
216189
@@ -216218,18 +216283,20 @@
216218 static void sqlite3Fts5PoslistSafeAppend(
216219 Fts5Buffer *pBuf,
216220 i64 *piPrev,
216221 i64 iPos
216222 ){
216223 static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
216224 if( (iPos & colmask) != (*piPrev & colmask) ){
216225 pBuf->p[pBuf->n++] = 1;
216226 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
216227 *piPrev = (iPos & colmask);
216228 }
216229 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
216230 *piPrev = iPos;
 
 
216231 }
216232
216233 static int sqlite3Fts5PoslistWriterAppend(
216234 Fts5Buffer *pBuf,
216235 Fts5PoslistWriter *pWriter,
@@ -224157,11 +224224,11 @@
224157 pIter->base.nData = p-aCopy;
224158 return;
224159 }
224160 fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy);
224161 }
224162 if( p==pEnd ){
224163 pIter->base.pData = pIter->poslist.p;
224164 pIter->base.nData = pIter->poslist.n;
224165 return;
224166 }
224167 aCopy = p++;
@@ -225953,11 +226020,11 @@
225953 Fts5Buffer *p1, /* First list to merge */
225954 int nBuf, /* Number of buffers in array aBuf[] */
225955 Fts5Buffer *aBuf /* Other lists to merge in */
225956 ){
225957 #define fts5PrefixMergerNextPosition(p) \
225958 sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos);
225959 #define FTS5_MERGE_NLIST 16
225960 PrefixMerger aMerger[FTS5_MERGE_NLIST];
225961 PrefixMerger *pHead = 0;
225962 int i;
225963 int nOut = 0;
@@ -230501,11 +230568,11 @@
230501 int nArg, /* Number of args */
230502 sqlite3_value **apUnused /* Function arguments */
230503 ){
230504 assert( nArg==0 );
230505 UNUSED_PARAM2(nArg, apUnused);
230506 sqlite3_result_text(pCtx, "fts5: 2021-06-04 23:26:56 1c71de43dbc68002c4a6229e7efffb019655baff67a51fe922571fe420c95835", -1, SQLITE_TRANSIENT);
230507 }
230508
230509 /*
230510 ** Return true if zName is the extension on one of the shadow tables used
230511 ** by this module.
@@ -235427,12 +235494,12 @@
235427 }
235428 #endif /* SQLITE_CORE */
235429 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
235430
235431 /************** End of stmt.c ************************************************/
235432 #if __LINE__!=235432
235433 #undef SQLITE_SOURCE_ID
235434 #define SQLITE_SOURCE_ID "2021-06-07 00:41:18 2aa9368b63b42ac7c700516f109edcc6098c12b850eae591afed4e51a3f4alt2"
235435 #endif
235436 /* Return the source-id for this library */
235437 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
235438 /************************** End of sqlite3.c ******************************/
235439
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1205,11 +1205,11 @@
1205 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1206 ** [sqlite_version()] and [sqlite_source_id()].
1207 */
1208 #define SQLITE_VERSION "3.36.0"
1209 #define SQLITE_VERSION_NUMBER 3036000
1210 #define SQLITE_SOURCE_ID "2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9ef70"
1211
1212 /*
1213 ** CAPI3REF: Run-Time Library Version Numbers
1214 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1215 **
@@ -16558,10 +16558,16 @@
16558 */
16559 #ifndef SET_FULLSYNC
16560 # define SET_FULLSYNC(x,y)
16561 #endif
16562
16563 /* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
16564 */
16565 #ifndef SQLITE_MAX_PATHLEN
16566 # define SQLITE_MAX_PATHLEN FILENAME_MAX
16567 #endif
16568
16569 /*
16570 ** The default size of a disk sector
16571 */
16572 #ifndef SQLITE_DEFAULT_SECTOR_SIZE
16573 # define SQLITE_DEFAULT_SECTOR_SIZE 4096
@@ -18795,10 +18801,11 @@
18801 #define SF_View 0x0200000 /* SELECT statement is a view */
18802 #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
18803 #define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
18804 #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
18805 #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
18806 #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
18807
18808 /*
18809 ** The results of a SELECT can be distributed in several ways, as defined
18810 ** by one of the following macros. The "SRT" prefix means "SELECT Result
18811 ** Type".
@@ -20158,10 +20165,11 @@
20165 SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
20166 SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
20167 SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
20168 SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
20169 SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
20170 SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p);
20171
20172 #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
20173 SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
20174 #endif
20175
@@ -20568,11 +20576,11 @@
20576 #ifndef SQLITE_OMIT_CTE
20577 SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
20578 SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*);
20579 SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*);
20580 SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*);
20581 SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8);
20582 #else
20583 # define sqlite3CteNew(P,T,E,S) ((void*)0)
20584 # define sqlite3CteDelete(D,C)
20585 # define sqlite3CteWithAdd(P,W,C) ((void*)0)
20586 # define sqlite3WithDelete(x,y)
@@ -21670,11 +21678,11 @@
21678 SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
21679 SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*);
21680 SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
21681 SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
21682 SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
21683 SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*));
21684 SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
21685 #ifdef SQLITE_OMIT_FLOATING_POINT
21686 # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
21687 #else
21688 SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
@@ -23667,10 +23675,12 @@
23675 zPathOut[0] = 0;
23676 return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
23677 }
23678 #ifndef SQLITE_OMIT_LOAD_EXTENSION
23679 SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
23680 assert( zPath!=0 );
23681 assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */
23682 return pVfs->xDlOpen(pVfs, zPath);
23683 }
23684 SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
23685 pVfs->xDlError(pVfs, nByte, zBufOut);
23686 }
@@ -66965,11 +66975,11 @@
66975 testcase( pc+size==usableSize );
66976 put2byte(pAddr, cbrk);
66977 if( temp==0 ){
66978 if( cbrk==pc ) continue;
66979 temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
66980 memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
66981 src = temp;
66982 }
66983 memcpy(&data[cbrk], &src[pc], size);
66984 }
66985 data[hdr+7] = 0;
@@ -78047,15 +78057,15 @@
78057 ** either case, SQLITE_TOOBIG is returned.
78058 */
78059 SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
78060 Mem *pMem, /* Memory cell to set to string value */
78061 const char *z, /* String pointer */
78062 i64 n, /* Bytes in string, or negative */
78063 u8 enc, /* Encoding of z. 0 for BLOBs */
78064 void (*xDel)(void*) /* Destructor function */
78065 ){
78066 i64 nByte = n; /* New value for pMem->n */
78067 int iLimit; /* Maximum allowed string or blob size */
78068 u16 flags = 0; /* New value for pMem->flags */
78069
78070 assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
78071 assert( !sqlite3VdbeMemIsRowSet(pMem) );
@@ -78073,11 +78083,11 @@
78083 }
78084 flags = (enc==0?MEM_Blob:MEM_Str);
78085 if( nByte<0 ){
78086 assert( enc!=0 );
78087 if( enc==SQLITE_UTF8 ){
78088 nByte = strlen(z);
78089 }else{
78090 for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
78091 }
78092 flags |= MEM_Term;
78093 }
@@ -78085,11 +78095,11 @@
78095 /* The following block sets the new values of Mem.z and Mem.xDel. It
78096 ** also sets a flag in local variable "flags" to indicate the memory
78097 ** management (one of MEM_Dyn or MEM_Static).
78098 */
78099 if( xDel==SQLITE_TRANSIENT ){
78100 i64 nAlloc = nByte;
78101 if( flags&MEM_Term ){
78102 nAlloc += (enc==SQLITE_UTF8?1:2);
78103 }
78104 if( nByte>iLimit ){
78105 return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
@@ -78111,11 +78121,11 @@
78121 pMem->xDel = xDel;
78122 flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
78123 }
78124 }
78125
78126 pMem->n = (int)(nByte & 0x7fffffff);
78127 pMem->flags = flags;
78128 if( enc ){
78129 pMem->enc = enc;
78130 #ifdef SQLITE_ENABLE_SESSION
78131 }else if( pMem->db==0 ){
@@ -78131,11 +78141,11 @@
78141 return SQLITE_NOMEM_BKPT;
78142 }
78143 #endif
78144
78145 if( nByte>iLimit ){
78146 return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
78147 }
78148
78149 return SQLITE_OK;
78150 }
78151
@@ -84527,11 +84537,11 @@
84537 }else if( xDel==SQLITE_TRANSIENT ){
84538 /* noop */
84539 }else{
84540 xDel((void*)p);
84541 }
84542 sqlite3_result_error_toobig(pCtx);
84543 return SQLITE_TOOBIG;
84544 }
84545 SQLITE_API void sqlite3_result_blob(
84546 sqlite3_context *pCtx,
84547 const void *z,
@@ -85509,11 +85519,11 @@
85519 */
85520 static int bindText(
85521 sqlite3_stmt *pStmt, /* The statement to bind against */
85522 int i, /* Index of the parameter to bind */
85523 const void *zData, /* Pointer to the data to be bound */
85524 i64 nData, /* Number of bytes of data to be bound */
85525 void (*xDel)(void*), /* Destructor for the data */
85526 u8 encoding /* Encoding for the data */
85527 ){
85528 Vdbe *p = (Vdbe *)pStmt;
85529 Mem *pVar;
@@ -85561,15 +85571,11 @@
85571 const void *zData,
85572 sqlite3_uint64 nData,
85573 void (*xDel)(void*)
85574 ){
85575 assert( xDel!=SQLITE_DYNAMIC );
85576 return bindText(pStmt, i, zData, nData, xDel, 0);
 
 
 
 
85577 }
85578 SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
85579 int rc;
85580 Vdbe *p = (Vdbe *)pStmt;
85581 rc = vdbeUnbind(p, i);
@@ -85635,16 +85641,12 @@
85641 sqlite3_uint64 nData,
85642 void (*xDel)(void*),
85643 unsigned char enc
85644 ){
85645 assert( xDel!=SQLITE_DYNAMIC );
85646 if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
85647 return bindText(pStmt, i, zData, nData, xDel, enc);
 
 
 
 
85648 }
85649 #ifndef SQLITE_OMIT_UTF16
85650 SQLITE_API int sqlite3_bind_text16(
85651 sqlite3_stmt *pStmt,
85652 int i,
@@ -90957,11 +90959,12 @@
90959 assert( pOp[1].opcode==OP_SeekGE );
90960
90961 /* pOp->p2 points to the first instruction past the OP_IdxGT that
90962 ** follows the OP_SeekGE. */
90963 assert( pOp->p2>=(int)(pOp-aOp)+2 );
90964 assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
90965 testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
90966 assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
90967 assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
90968 assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
90969
90970 assert( pOp->p1>0 );
@@ -92847,11 +92850,13 @@
92850 }
92851 #endif
92852
92853 iDb = pOp->p1;
92854 assert( iDb>=0 && iDb<db->nDb );
92855 assert( DbHasProperty(db, iDb, DB_SchemaLoaded)
92856 || db->mallocFailed
92857 || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) );
92858
92859 #ifndef SQLITE_OMIT_ALTERTABLE
92860 if( pOp->p4.z==0 ){
92861 sqlite3SchemaClear(db->aDb[iDb].pSchema);
92862 db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
@@ -102622,11 +102627,11 @@
102627 ** Create and return a deep copy of the object passed as the second
102628 ** argument. If an OOM condition is encountered, NULL is returned
102629 ** and the db->mallocFailed flag set.
102630 */
102631 #ifndef SQLITE_OMIT_CTE
102632 SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
102633 With *pRet = 0;
102634 if( p ){
102635 sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
102636 pRet = sqlite3DbMallocZero(db, nByte);
102637 if( pRet ){
@@ -102640,11 +102645,11 @@
102645 }
102646 }
102647 return pRet;
102648 }
102649 #else
102650 # define sqlite3WithDup(x,y) 0
102651 #endif
102652
102653 #ifndef SQLITE_OMIT_WINDOWFUNC
102654 /*
102655 ** The gatherSelectWindows() procedure and its helper routine
@@ -102844,11 +102849,11 @@
102849 pNew->iOffset = 0;
102850 pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
102851 pNew->addrOpenEphm[0] = -1;
102852 pNew->addrOpenEphm[1] = -1;
102853 pNew->nSelectRow = p->nSelectRow;
102854 pNew->pWith = sqlite3WithDup(db, p->pWith);
102855 #ifndef SQLITE_OMIT_WINDOWFUNC
102856 pNew->pWin = 0;
102857 pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
102858 if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
102859 #endif
@@ -108184,19 +108189,34 @@
108189 ** to select statement pSelect.
108190 */
108191 static void renameWalkWith(Walker *pWalker, Select *pSelect){
108192 With *pWith = pSelect->pWith;
108193 if( pWith ){
108194 Parse *pParse = pWalker->pParse;
108195 int i;
108196 With *pCopy = 0;
108197 assert( pWith->nCte>0 );
108198 if( (pWith->a[0].pSelect->selFlags & SF_Expanded)==0 ){
108199 /* Push a copy of the With object onto the with-stack. We use a copy
108200 ** here as the original will be expanded and resolved (flags SF_Expanded
108201 ** and SF_Resolved) below. And the parser code that uses the with-stack
108202 ** fails if the Select objects on it have already been expanded and
108203 ** resolved. */
108204 pCopy = sqlite3WithDup(pParse->db, pWith);
108205 pCopy = sqlite3WithPush(pParse, pCopy, 1);
108206 }
108207 for(i=0; i<pWith->nCte; i++){
108208 Select *p = pWith->a[i].pSelect;
108209 NameContext sNC;
108210 memset(&sNC, 0, sizeof(sNC));
108211 sNC.pParse = pParse;
108212 if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC);
108213 sqlite3WalkSelect(pWalker, p);
108214 sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols);
108215 }
108216 if( pCopy && pParse->pWith==pCopy ){
108217 pParse->pWith = pCopy->pOuter;
108218 }
108219 }
108220 }
108221
108222 /*
@@ -108219,11 +108239,15 @@
108239 */
108240 static int renameUnmapSelectCb(Walker *pWalker, Select *p){
108241 Parse *pParse = pWalker->pParse;
108242 int i;
108243 if( pParse->nErr ) return WRC_Abort;
108244 if( p->selFlags & (SF_View|SF_CopyCte) ){
108245 testcase( pSelect->selFlags & SF_View );
108246 testcase( pSelect->selFlags & SF_CopyCte );
108247 return WRC_Prune;
108248 }
108249 if( ALWAYS(p->pEList) ){
108250 ExprList *pList = p->pEList;
108251 for(i=0; i<pList->nExpr; i++){
108252 if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
108253 sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
@@ -108327,11 +108351,15 @@
108351 ** This is a Walker select callback. It does nothing. It is only required
108352 ** because without a dummy callback, sqlite3WalkExpr() and similar do not
108353 ** descend into sub-select statements.
108354 */
108355 static int renameColumnSelectCb(Walker *pWalker, Select *p){
108356 if( p->selFlags & (SF_View|SF_CopyCte) ){
108357 testcase( pSelect->selFlags & SF_View );
108358 testcase( pSelect->selFlags & SF_CopyCte );
108359 return WRC_Prune;
108360 }
108361 renameWalkWith(pWalker, p);
108362 return WRC_Continue;
108363 }
108364
108365 /*
@@ -108963,11 +108991,15 @@
108991 */
108992 static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
108993 int i;
108994 RenameCtx *p = pWalker->u.pRename;
108995 SrcList *pSrc = pSelect->pSrc;
108996 if( pSelect->selFlags & (SF_View|SF_CopyCte) ){
108997 testcase( pSelect->selFlags & SF_View );
108998 testcase( pSelect->selFlags & SF_CopyCte );
108999 return WRC_Prune;
109000 }
109001 if( NEVER(pSrc==0) ){
109002 assert( pWalker->pParse->db->mallocFailed );
109003 return WRC_Abort;
109004 }
109005 for(i=0; i<pSrc->nSrc; i++){
@@ -116705,11 +116737,11 @@
116737 const char *zDb = db->aDb[iDb].zDbSName;
116738 const char *zTab = SCHEMA_TABLE(iDb);
116739 if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
116740 goto exit_drop_index;
116741 }
116742 if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
116743 if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
116744 goto exit_drop_index;
116745 }
116746 }
116747 #endif
@@ -119237,17 +119269,19 @@
119269 ){
119270 /* This column was already computed by the previous index */
119271 continue;
119272 }
119273 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
119274 if( pIdx->aiColumn[j]>=0 ){
119275 /* If the column affinity is REAL but the number is an integer, then it
119276 ** might be stored in the table as an integer (using a compact
119277 ** representation) then converted to REAL by an OP_RealAffinity opcode.
119278 ** But we are getting ready to store this value back into an index, where
119279 ** it should be converted by to INTEGER again. So omit the
119280 ** OP_RealAffinity opcode if it is present */
119281 sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
119282 }
119283 }
119284 if( regOut ){
119285 sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
119286 }
119287 sqlite3ReleaseTempRange(pParse, regBase, nCol);
@@ -127401,11 +127435,11 @@
127435 sqlite3_loadext_entry xInit;
127436 char *zErrmsg = 0;
127437 const char *zEntry;
127438 char *zAltEntry = 0;
127439 void **aHandle;
127440 u64 nMsg = strlen(zFile);
127441 int ii;
127442 int rc;
127443
127444 /* Shared library endings to try if zFile cannot be loaded as written */
127445 static const char *azEndings[] = {
@@ -127435,30 +127469,26 @@
127469 return SQLITE_ERROR;
127470 }
127471
127472 zEntry = zProc ? zProc : "sqlite3_extension_init";
127473
127474 /* tag-20210611-1. Some dlopen() implementations will segfault if given
127475 ** an oversize filename. Most filesystems have a pathname limit of 4K,
127476 ** so limit the extension filename length to about twice that.
127477 ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
127478 if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
127479
127480 handle = sqlite3OsDlOpen(pVfs, zFile);
127481 #if SQLITE_OS_UNIX || SQLITE_OS_WIN
127482 for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
127483 char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
127484 if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
127485 handle = sqlite3OsDlOpen(pVfs, zAltFile);
127486 sqlite3_free(zAltFile);
127487 }
127488 #endif
127489 if( handle==0 ) goto extension_not_found;
 
 
 
 
 
 
 
 
 
 
127490 xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
127491
127492 /* If no entry point was specified and the default legacy
127493 ** entry point name "sqlite3_extension_init" was not found, then
127494 ** construct an entry point name "sqlite3_X_init" where the X is
@@ -127491,14 +127521,15 @@
127521 zEntry = zAltEntry;
127522 xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
127523 }
127524 if( xInit==0 ){
127525 if( pzErrMsg ){
127526 nMsg += strlen(zEntry) + 300;
127527 *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127528 if( zErrmsg ){
127529 assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
127530 sqlite3_snprintf((int)nMsg, zErrmsg,
127531 "no entry point [%s] in shared library [%s]", zEntry, zFile);
127532 sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127533 }
127534 }
127535 sqlite3OsDlClose(pVfs, handle);
@@ -127528,10 +127559,23 @@
127559 sqlite3DbFree(db, db->aExtension);
127560 db->aExtension = aHandle;
127561
127562 db->aExtension[db->nExtension++] = handle;
127563 return SQLITE_OK;
127564
127565 extension_not_found:
127566 if( pzErrMsg ){
127567 nMsg += 300;
127568 *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
127569 if( zErrmsg ){
127570 assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
127571 sqlite3_snprintf((int)nMsg, zErrmsg,
127572 "unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile);
127573 sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
127574 }
127575 }
127576 return SQLITE_ERROR;
127577 }
127578 SQLITE_API int sqlite3_load_extension(
127579 sqlite3 *db, /* Load the extension into this database connection */
127580 const char *zFile, /* Name of the shared library containing extension */
127581 const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
@@ -131368,13 +131412,15 @@
131412 if( rc==SQLITE_OK ){
131413 sqlite3AnalysisLoad(db, iDb);
131414 }
131415 #endif
131416 }
131417 assert( pDb == &(db->aDb[iDb]) );
131418 if( db->mallocFailed ){
131419 rc = SQLITE_NOMEM_BKPT;
131420 sqlite3ResetAllSchemasOfConnection(db);
131421 pDb = &db->aDb[iDb];
131422 }else
131423 if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
131424 /* Hack: If the SQLITE_NoSchemaError flag is set, then consider
131425 ** the schema loaded, even if errors (other than OOM) occurred. In
131426 ** this situation the current sqlite3_prepare() operation will fail,
@@ -136426,10 +136472,11 @@
136472 ** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
136473 */
136474 typedef struct WhereConst WhereConst;
136475 struct WhereConst {
136476 Parse *pParse; /* Parsing context */
136477 u8 *pOomFault; /* Pointer to pParse->db->mallocFailed */
136478 int nConst; /* Number for COLUMN=CONSTANT terms */
136479 int nChng; /* Number of times a constant is propagated */
136480 int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */
136481 Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
136482 };
@@ -136525,10 +136572,11 @@
136572 WhereConst *pConst,
136573 Expr *pExpr,
136574 int bIgnoreAffBlob
136575 ){
136576 int i;
136577 if( pConst->pOomFault[0] ) return WRC_Prune;
136578 if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
136579 if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
136580 testcase( ExprHasProperty(pExpr, EP_FixedCol) );
136581 testcase( ExprHasProperty(pExpr, EP_FromJoin) );
136582 return WRC_Continue;
@@ -136545,10 +136593,11 @@
136593 pConst->nChng++;
136594 ExprClearProperty(pExpr, EP_Leaf);
136595 ExprSetProperty(pExpr, EP_FixedCol);
136596 assert( pExpr->pLeft==0 );
136597 pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
136598 if( pConst->pParse->db->mallocFailed ) return WRC_Prune;
136599 break;
136600 }
136601 return WRC_Prune;
136602 }
136603
@@ -136577,10 +136626,11 @@
136626 if( pConst->bHasAffBlob ){
136627 if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE)
136628 || pExpr->op==TK_IS
136629 ){
136630 propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0);
136631 if( pConst->pOomFault[0] ) return WRC_Prune;
136632 if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){
136633 propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0);
136634 }
136635 }
136636 }
@@ -136644,10 +136694,11 @@
136694 ){
136695 WhereConst x;
136696 Walker w;
136697 int nChng = 0;
136698 x.pParse = pParse;
136699 x.pOomFault = &pParse->db->mallocFailed;
136700 do{
136701 x.nConst = 0;
136702 x.nChng = 0;
136703 x.apExpr = 0;
136704 x.bHasAffBlob = 0;
@@ -137099,25 +137150,33 @@
137150 ** onto the top of the stack. If argument bFree is true, then this
137151 ** WITH clause will never be popped from the stack but should instead
137152 ** be freed along with the Parse object. In other cases, when
137153 ** bFree==0, the With object will be freed along with the SELECT
137154 ** statement with which it is associated.
137155 **
137156 ** This routine returns a copy of pWith. Or, if bFree is true and
137157 ** the pWith object is destroyed immediately due to an OOM condition,
137158 ** then this routine return NULL.
137159 **
137160 ** If bFree is true, do not continue to use the pWith pointer after
137161 ** calling this routine, Instead, use only the return value.
137162 */
137163 SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
137164 if( pWith ){
137165 if( bFree ){
137166 pWith = (With*)sqlite3ParserAddCleanup(pParse,
137167 (void(*)(sqlite3*,void*))sqlite3WithDelete,
137168 pWith);
137169 if( pWith==0 ) return 0;
137170 }
137171 if( pParse->nErr==0 ){
137172 assert( pParse->pWith!=pWith );
137173 pWith->pOuter = pParse->pWith;
137174 pParse->pWith = pWith;
137175 }
 
 
 
 
 
 
137176 }
137177 return pWith;
137178 }
137179
137180 /*
137181 ** This function checks if argument pFrom refers to a CTE declared by
137182 ** a WITH clause on the stack currently maintained by the parser (on the
@@ -137206,10 +137265,11 @@
137265 pTab->iPKey = -1;
137266 pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
137267 pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
137268 pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
137269 if( db->mallocFailed ) return 2;
137270 pFrom->pSelect->selFlags |= SF_CopyCte;
137271 assert( pFrom->pSelect );
137272 pFrom->fg.isCte = 1;
137273 pFrom->u2.pCteUse = pCteUse;
137274 pCteUse->nUse++;
137275 if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
@@ -137474,10 +137534,11 @@
137534 ){
137535 sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
137536 pTab->zName);
137537 }
137538 #ifndef SQLITE_OMIT_VIRTUALTABLE
137539 assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 );
137540 if( IsVirtual(pTab)
137541 && pFrom->fg.fromDDL
137542 && ALWAYS(pTab->pVTable!=0)
137543 && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
137544 ){
@@ -183221,12 +183282,12 @@
183282 int nPrev, /* Size of buffer zPrev in bytes */
183283 const char *zNext, /* Buffer containing next term */
183284 int nNext /* Size of buffer zNext in bytes */
183285 ){
183286 int n;
183287 for(n=0; n<nPrev && n<nNext && zPrev[n]==zNext[n]; n++);
183288 assert_fts3_nc( n<nNext );
183289 return n;
183290 }
183291
183292 /*
183293 ** Add term zTerm to the SegmentNode. It is guaranteed that zTerm is larger
@@ -184221,11 +184282,11 @@
184282 iDelta = (i64)((u64)iDocid - (u64)iPrev);
184283 }
184284
184285 nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
184286
184287 rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING);
184288 if( rc ) return rc;
184289
184290 if( isFirst ){
184291 char *a = &pCsr->aBuffer[nDoclist];
184292 int nWrite;
@@ -216164,10 +216225,11 @@
216225 return 1;
216226 }else{
216227 i64 iOff = *piOff;
216228 int iVal;
216229 fts5FastGetVarint32(a, i, iVal);
216230 assert( iVal>=0 );
216231 if( iVal<=1 ){
216232 if( iVal==0 ){
216233 *pi = i;
216234 return 0;
216235 }
@@ -216177,13 +216239,16 @@
216239 if( iVal<2 ){
216240 /* This is a corrupt record. So stop parsing it here. */
216241 *piOff = -1;
216242 return 1;
216243 }
216244 *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
216245 }else{
216246 *piOff = (iOff & (i64)0x7FFFFFFF<<32)+((iOff + (iVal-2)) & 0x7FFFFFFF);
216247 }
 
216248 *pi = i;
216249 assert( *piOff>=iOff );
216250 return 0;
216251 }
216252 }
216253
216254
@@ -216218,18 +216283,20 @@
216283 static void sqlite3Fts5PoslistSafeAppend(
216284 Fts5Buffer *pBuf,
216285 i64 *piPrev,
216286 i64 iPos
216287 ){
216288 if( iPos>=*piPrev ){
216289 static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
216290 if( (iPos & colmask) != (*piPrev & colmask) ){
216291 pBuf->p[pBuf->n++] = 1;
216292 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
216293 *piPrev = (iPos & colmask);
216294 }
216295 pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
216296 *piPrev = iPos;
216297 }
216298 }
216299
216300 static int sqlite3Fts5PoslistWriterAppend(
216301 Fts5Buffer *pBuf,
216302 Fts5PoslistWriter *pWriter,
@@ -224157,11 +224224,11 @@
224224 pIter->base.nData = p-aCopy;
224225 return;
224226 }
224227 fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy);
224228 }
224229 if( p>=pEnd ){
224230 pIter->base.pData = pIter->poslist.p;
224231 pIter->base.nData = pIter->poslist.n;
224232 return;
224233 }
224234 aCopy = p++;
@@ -225953,11 +226020,11 @@
226020 Fts5Buffer *p1, /* First list to merge */
226021 int nBuf, /* Number of buffers in array aBuf[] */
226022 Fts5Buffer *aBuf /* Other lists to merge in */
226023 ){
226024 #define fts5PrefixMergerNextPosition(p) \
226025 sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos)
226026 #define FTS5_MERGE_NLIST 16
226027 PrefixMerger aMerger[FTS5_MERGE_NLIST];
226028 PrefixMerger *pHead = 0;
226029 int i;
226030 int nOut = 0;
@@ -230501,11 +230568,11 @@
230568 int nArg, /* Number of args */
230569 sqlite3_value **apUnused /* Function arguments */
230570 ){
230571 assert( nArg==0 );
230572 UNUSED_PARAM2(nArg, apUnused);
230573 sqlite3_result_text(pCtx, "fts5: 2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9ef70", -1, SQLITE_TRANSIENT);
230574 }
230575
230576 /*
230577 ** Return true if zName is the extension on one of the shadow tables used
230578 ** by this module.
@@ -235427,12 +235494,12 @@
235494 }
235495 #endif /* SQLITE_CORE */
235496 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
235497
235498 /************** End of stmt.c ************************************************/
235499 #if __LINE__!=235499
235500 #undef SQLITE_SOURCE_ID
235501 #define SQLITE_SOURCE_ID "2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9alt2"
235502 #endif
235503 /* Return the source-id for this library */
235504 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
235505 /************************** End of sqlite3.c ******************************/
235506
+1 -1
--- 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.36.0"
127127
#define SQLITE_VERSION_NUMBER 3036000
128
-#define SQLITE_SOURCE_ID "2021-06-07 00:41:18 2aa9368b63b42ac7c700516f109edcc6098c12b850eae591afed4e51a3f41819"
128
+#define SQLITE_SOURCE_ID "2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9ef70"
129129
130130
/*
131131
** CAPI3REF: Run-Time Library Version Numbers
132132
** KEYWORDS: sqlite3_version sqlite3_sourceid
133133
**
134134
--- 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.36.0"
127 #define SQLITE_VERSION_NUMBER 3036000
128 #define SQLITE_SOURCE_ID "2021-06-07 00:41:18 2aa9368b63b42ac7c700516f109edcc6098c12b850eae591afed4e51a3f41819"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
--- 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.36.0"
127 #define SQLITE_VERSION_NUMBER 3036000
128 #define SQLITE_SOURCE_ID "2021-06-14 20:41:20 e5a5acd6006133c5da4a7dd79726dbaa41c0d60ebeda890f848a6aafe5f9ef70"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
+11
--- src/stat.c
+++ src/stat.c
@@ -60,10 +60,11 @@
6060
void stats_for_email(void){
6161
const char *zDest = db_get("email-send-method",0);
6262
int nSub, nASub, nPend, nDPend;
6363
const char *zDir, *zDb, *zCmd, *zRelay;
6464
int iCutoff;
65
+ double rDigest;
6566
@ <tr><th>Outgoing&nbsp;Email:</th><td>
6667
if( fossil_strcmp(zDest,"pipe")==0
6768
&& (zCmd = db_get("email-send-command",0))!=0
6869
){
6970
@ Piped to command "%h(zCmd)"
@@ -117,10 +118,20 @@
117118
nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
118119
" AND NOT sdonotcall AND length(ssub)>1"
119120
" AND lastContact>=%d;", iCutoff);
120121
@ %,d(nASub) active, %,d(nSub) total
121122
@ </td></tr>
123
+ rDigest = db_double(-1.0, "SELECT (julianday('now') - value)*24.0"
124
+ " FROM config WHERE name='email-last-digest'");
125
+ if( rDigest>0.0 ){
126
+ @ <tr><th>Last Digest:</th><td>Approximately \
127
+ if( rDigest>48.0 ){
128
+ @ %.1f(rDigest/24.0) days ago</td>
129
+ }else{
130
+ @ %.1f(rDigest) hours ago</td>
131
+ }
132
+ }
122133
}
123134
124135
/*
125136
** WEBPAGE: stat
126137
**
127138
--- src/stat.c
+++ src/stat.c
@@ -60,10 +60,11 @@
60 void stats_for_email(void){
61 const char *zDest = db_get("email-send-method",0);
62 int nSub, nASub, nPend, nDPend;
63 const char *zDir, *zDb, *zCmd, *zRelay;
64 int iCutoff;
 
65 @ <tr><th>Outgoing&nbsp;Email:</th><td>
66 if( fossil_strcmp(zDest,"pipe")==0
67 && (zCmd = db_get("email-send-command",0))!=0
68 ){
69 @ Piped to command "%h(zCmd)"
@@ -117,10 +118,20 @@
117 nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
118 " AND NOT sdonotcall AND length(ssub)>1"
119 " AND lastContact>=%d;", iCutoff);
120 @ %,d(nASub) active, %,d(nSub) total
121 @ </td></tr>
 
 
 
 
 
 
 
 
 
 
122 }
123
124 /*
125 ** WEBPAGE: stat
126 **
127
--- src/stat.c
+++ src/stat.c
@@ -60,10 +60,11 @@
60 void stats_for_email(void){
61 const char *zDest = db_get("email-send-method",0);
62 int nSub, nASub, nPend, nDPend;
63 const char *zDir, *zDb, *zCmd, *zRelay;
64 int iCutoff;
65 double rDigest;
66 @ <tr><th>Outgoing&nbsp;Email:</th><td>
67 if( fossil_strcmp(zDest,"pipe")==0
68 && (zCmd = db_get("email-send-command",0))!=0
69 ){
70 @ Piped to command "%h(zCmd)"
@@ -117,10 +118,20 @@
118 nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
119 " AND NOT sdonotcall AND length(ssub)>1"
120 " AND lastContact>=%d;", iCutoff);
121 @ %,d(nASub) active, %,d(nSub) total
122 @ </td></tr>
123 rDigest = db_double(-1.0, "SELECT (julianday('now') - value)*24.0"
124 " FROM config WHERE name='email-last-digest'");
125 if( rDigest>0.0 ){
126 @ <tr><th>Last Digest:</th><td>Approximately \
127 if( rDigest>48.0 ){
128 @ %.1f(rDigest/24.0) days ago</td>
129 }else{
130 @ %.1f(rDigest) hours ago</td>
131 }
132 }
133 }
134
135 /*
136 ** WEBPAGE: stat
137 **
138
+3 -3
--- src/sync.c
+++ src/sync.c
@@ -192,11 +192,11 @@
192192
**
193193
** Usage: %fossil pull ?URL? ?options?
194194
**
195195
** Pull all sharable changes from a remote repository into the local
196196
** repository. Sharable changes include public check-ins, edits to
197
-** wiki pages, tickets, and tech-notes, as well as forum content. Add
197
+** wiki pages, tickets, tech-notes, and forum posts. Add
198198
** the --private option to pull private branches. Use the
199199
** "configuration pull" command to pull website configuration details.
200200
**
201201
** If URL is not specified, then the URL from the most recent clone, push,
202202
** pull, remote, or sync command is used. See "fossil help clone" for
@@ -243,11 +243,11 @@
243243
**
244244
** Usage: %fossil push ?URL? ?options?
245245
**
246246
** Push all sharable changes from the local repository to a remote
247247
** repository. Sharable changes include public check-ins, edits to
248
-** wiki pages, tickets, and tech-notes, as well as forum content. Use
248
+** wiki pages, tickets, tech-notes, and forum posts. Use
249249
** --private to also push private branches. Use the "configuration
250250
** push" command to push website configuration details.
251251
**
252252
** If URL is not specified, then the URL from the most recent clone, push,
253253
** pull, remote, or sync command is used. See "fossil help clone" for
@@ -290,11 +290,11 @@
290290
**
291291
** Usage: %fossil sync ?URL? ?options?
292292
**
293293
** Synchronize all sharable changes between the local repository and a
294294
** remote repository. Sharable changes include public check-ins and
295
-** edits to wiki pages, tickets, and technical notes.
295
+** edits to wiki pages, tickets, forum posts, and technical notes.
296296
**
297297
** If URL is not specified, then the URL from the most recent clone, push,
298298
** pull, remote, or sync command is used. See "fossil help clone" for
299299
** details on the URL formats.
300300
**
301301
--- src/sync.c
+++ src/sync.c
@@ -192,11 +192,11 @@
192 **
193 ** Usage: %fossil pull ?URL? ?options?
194 **
195 ** Pull all sharable changes from a remote repository into the local
196 ** repository. Sharable changes include public check-ins, edits to
197 ** wiki pages, tickets, and tech-notes, as well as forum content. Add
198 ** the --private option to pull private branches. Use the
199 ** "configuration pull" command to pull website configuration details.
200 **
201 ** If URL is not specified, then the URL from the most recent clone, push,
202 ** pull, remote, or sync command is used. See "fossil help clone" for
@@ -243,11 +243,11 @@
243 **
244 ** Usage: %fossil push ?URL? ?options?
245 **
246 ** Push all sharable changes from the local repository to a remote
247 ** repository. Sharable changes include public check-ins, edits to
248 ** wiki pages, tickets, and tech-notes, as well as forum content. Use
249 ** --private to also push private branches. Use the "configuration
250 ** push" command to push website configuration details.
251 **
252 ** If URL is not specified, then the URL from the most recent clone, push,
253 ** pull, remote, or sync command is used. See "fossil help clone" for
@@ -290,11 +290,11 @@
290 **
291 ** Usage: %fossil sync ?URL? ?options?
292 **
293 ** Synchronize all sharable changes between the local repository and a
294 ** remote repository. Sharable changes include public check-ins and
295 ** edits to wiki pages, tickets, and technical notes.
296 **
297 ** If URL is not specified, then the URL from the most recent clone, push,
298 ** pull, remote, or sync command is used. See "fossil help clone" for
299 ** details on the URL formats.
300 **
301
--- src/sync.c
+++ src/sync.c
@@ -192,11 +192,11 @@
192 **
193 ** Usage: %fossil pull ?URL? ?options?
194 **
195 ** Pull all sharable changes from a remote repository into the local
196 ** repository. Sharable changes include public check-ins, edits to
197 ** wiki pages, tickets, tech-notes, and forum posts. Add
198 ** the --private option to pull private branches. Use the
199 ** "configuration pull" command to pull website configuration details.
200 **
201 ** If URL is not specified, then the URL from the most recent clone, push,
202 ** pull, remote, or sync command is used. See "fossil help clone" for
@@ -243,11 +243,11 @@
243 **
244 ** Usage: %fossil push ?URL? ?options?
245 **
246 ** Push all sharable changes from the local repository to a remote
247 ** repository. Sharable changes include public check-ins, edits to
248 ** wiki pages, tickets, tech-notes, and forum posts. Use
249 ** --private to also push private branches. Use the "configuration
250 ** push" command to push website configuration details.
251 **
252 ** If URL is not specified, then the URL from the most recent clone, push,
253 ** pull, remote, or sync command is used. See "fossil help clone" for
@@ -290,11 +290,11 @@
290 **
291 ** Usage: %fossil sync ?URL? ?options?
292 **
293 ** Synchronize all sharable changes between the local repository and a
294 ** remote repository. Sharable changes include public check-ins and
295 ** edits to wiki pages, tickets, forum posts, and technical notes.
296 **
297 ** If URL is not specified, then the URL from the most recent clone, push,
298 ** pull, remote, or sync command is used. See "fossil help clone" for
299 ** details on the URL formats.
300 **
301
+12 -2
--- src/th_main.c
+++ src/th_main.c
@@ -2976,11 +2976,12 @@
29762976
** COMMAND: test-th-eval
29772977
**
29782978
** Usage: %fossil test-th-eval SCRIPT
29792979
**
29802980
** Evaluate SCRIPT as if it were a header or footer or ticket rendering
2981
-** script and show the results on standard output.
2981
+** script and show the results on standard output. SCRIPT may be either
2982
+** a filename or a string of th1 script code.
29822983
**
29832984
** Options:
29842985
**
29852986
** --cgi Include a CGI response header in the output
29862987
** --http Include an HTTP response header in the output
@@ -2990,11 +2991,13 @@
29902991
** --th-trace Trace TH1 execution (for debugging purposes)
29912992
*/
29922993
void test_th_eval(void){
29932994
int rc;
29942995
const char *zRc;
2996
+ const char *zCode = 0;
29952997
int forceCgi, fullHttpReply;
2998
+ Blob code = empty_blob;
29962999
Th_InitTraceLog();
29973000
forceCgi = find_option("cgi", 0, 0)!=0;
29983001
fullHttpReply = find_option("http", 0, 0)!=0;
29993002
if( fullHttpReply ) forceCgi = 1;
30003003
if( forceCgi ) Th_ForceCgi(fullHttpReply);
@@ -3012,16 +3015,23 @@
30123015
g.useLocalauth = 1;
30133016
}
30143017
verify_all_options();
30153018
if( g.argc!=3 ){
30163019
usage("script");
3020
+ }
3021
+ if(file_isfile(g.argv[2], ExtFILE)){
3022
+ blob_read_from_file(&code, g.argv[2], ExtFILE);
3023
+ zCode = blob_str(&code);
3024
+ }else{
3025
+ zCode = g.argv[2];
30173026
}
30183027
Th_FossilInit(TH_INIT_DEFAULT);
3019
- rc = Th_Eval(g.interp, 0, g.argv[2], -1);
3028
+ rc = Th_Eval(g.interp, 0, zCode, -1);
30203029
zRc = Th_ReturnCodeName(rc, 1);
30213030
fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
30223031
Th_PrintTraceLog();
3032
+ blob_reset(&code);
30233033
if( forceCgi ) cgi_reply();
30243034
}
30253035
30263036
/*
30273037
** COMMAND: test-th-source
30283038
--- src/th_main.c
+++ src/th_main.c
@@ -2976,11 +2976,12 @@
2976 ** COMMAND: test-th-eval
2977 **
2978 ** Usage: %fossil test-th-eval SCRIPT
2979 **
2980 ** Evaluate SCRIPT as if it were a header or footer or ticket rendering
2981 ** script and show the results on standard output.
 
2982 **
2983 ** Options:
2984 **
2985 ** --cgi Include a CGI response header in the output
2986 ** --http Include an HTTP response header in the output
@@ -2990,11 +2991,13 @@
2990 ** --th-trace Trace TH1 execution (for debugging purposes)
2991 */
2992 void test_th_eval(void){
2993 int rc;
2994 const char *zRc;
 
2995 int forceCgi, fullHttpReply;
 
2996 Th_InitTraceLog();
2997 forceCgi = find_option("cgi", 0, 0)!=0;
2998 fullHttpReply = find_option("http", 0, 0)!=0;
2999 if( fullHttpReply ) forceCgi = 1;
3000 if( forceCgi ) Th_ForceCgi(fullHttpReply);
@@ -3012,16 +3015,23 @@
3012 g.useLocalauth = 1;
3013 }
3014 verify_all_options();
3015 if( g.argc!=3 ){
3016 usage("script");
 
 
 
 
 
 
3017 }
3018 Th_FossilInit(TH_INIT_DEFAULT);
3019 rc = Th_Eval(g.interp, 0, g.argv[2], -1);
3020 zRc = Th_ReturnCodeName(rc, 1);
3021 fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
3022 Th_PrintTraceLog();
 
3023 if( forceCgi ) cgi_reply();
3024 }
3025
3026 /*
3027 ** COMMAND: test-th-source
3028
--- src/th_main.c
+++ src/th_main.c
@@ -2976,11 +2976,12 @@
2976 ** COMMAND: test-th-eval
2977 **
2978 ** Usage: %fossil test-th-eval SCRIPT
2979 **
2980 ** Evaluate SCRIPT as if it were a header or footer or ticket rendering
2981 ** script and show the results on standard output. SCRIPT may be either
2982 ** a filename or a string of th1 script code.
2983 **
2984 ** Options:
2985 **
2986 ** --cgi Include a CGI response header in the output
2987 ** --http Include an HTTP response header in the output
@@ -2990,11 +2991,13 @@
2991 ** --th-trace Trace TH1 execution (for debugging purposes)
2992 */
2993 void test_th_eval(void){
2994 int rc;
2995 const char *zRc;
2996 const char *zCode = 0;
2997 int forceCgi, fullHttpReply;
2998 Blob code = empty_blob;
2999 Th_InitTraceLog();
3000 forceCgi = find_option("cgi", 0, 0)!=0;
3001 fullHttpReply = find_option("http", 0, 0)!=0;
3002 if( fullHttpReply ) forceCgi = 1;
3003 if( forceCgi ) Th_ForceCgi(fullHttpReply);
@@ -3012,16 +3015,23 @@
3015 g.useLocalauth = 1;
3016 }
3017 verify_all_options();
3018 if( g.argc!=3 ){
3019 usage("script");
3020 }
3021 if(file_isfile(g.argv[2], ExtFILE)){
3022 blob_read_from_file(&code, g.argv[2], ExtFILE);
3023 zCode = blob_str(&code);
3024 }else{
3025 zCode = g.argv[2];
3026 }
3027 Th_FossilInit(TH_INIT_DEFAULT);
3028 rc = Th_Eval(g.interp, 0, zCode, -1);
3029 zRc = Th_ReturnCodeName(rc, 1);
3030 fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
3031 Th_PrintTraceLog();
3032 blob_reset(&code);
3033 if( forceCgi ) cgi_reply();
3034 }
3035
3036 /*
3037 ** COMMAND: test-th-source
3038
+23 -2
--- src/tkt.c
+++ src/tkt.c
@@ -378,10 +378,12 @@
378378
** schema for the ticketing system. Only allow
379379
**
380380
** CREATE TABLE
381381
** CREATE INDEX
382382
** CREATE VIEW
383
+** DROP INDEX
384
+** DROP VIEW
383385
**
384386
** And for objects in "main" or "repository" whose names
385387
** begin with "ticket" or "fx_". Also allow
386388
**
387389
** INSERT
@@ -393,10 +395,13 @@
393395
**
394396
** Of particular importance for security is that this routine
395397
** disallows data changes on the "config" table, as that could
396398
** allow a malicious server to modify settings in such a way as
397399
** to cause a remote code execution.
400
+**
401
+** Use the "fossil test-db-prepare --auth-ticket SQL" command to perform
402
+** manual testing of this authorizer.
398403
*/
399404
static int ticket_schema_auth(
400405
void *pNErr,
401406
int eCode,
402407
const char *z0,
@@ -403,10 +408,11 @@
403408
const char *z1,
404409
const char *z2,
405410
const char *z3
406411
){
407412
switch( eCode ){
413
+ case SQLITE_DROP_VIEW:
408414
case SQLITE_CREATE_VIEW:
409415
case SQLITE_CREATE_TABLE: {
410416
if( sqlite3_stricmp(z2,"main")!=0
411417
&& sqlite3_stricmp(z2,"repository")!=0
412418
){
@@ -417,10 +423,11 @@
417423
){
418424
goto ticket_schema_error;
419425
}
420426
break;
421427
}
428
+ case SQLITE_DROP_INDEX:
422429
case SQLITE_CREATE_INDEX: {
423430
if( sqlite3_stricmp(z2,"main")!=0
424431
&& sqlite3_stricmp(z2,"repository")!=0
425432
){
426433
goto ticket_schema_error;
@@ -463,10 +470,24 @@
463470
ticket_schema_error:
464471
if( pNErr ) *(int*)pNErr = 1;
465472
return SQLITE_DENY;
466473
}
467474
475
+/*
476
+** Activate the ticket schema authorizer. Must be followed by
477
+** an eventual call to ticket_unrestrict_sql().
478
+*/
479
+void ticket_restrict_sql(int * pNErr){
480
+ db_set_authorizer(ticket_schema_auth,(void*)pNErr,"Ticket-Schema");
481
+}
482
+/*
483
+** Deactivate the ticket schema authorizer.
484
+*/
485
+void ticket_unrestrict_sql(void){
486
+ db_clear_authorizer();
487
+}
488
+
468489
469490
/*
470491
** Recreate the TICKET and TICKETCHNG tables.
471492
*/
472493
void ticket_create_table(int separateConnection){
@@ -475,18 +496,18 @@
475496
db_multi_exec(
476497
"DROP TABLE IF EXISTS ticket;"
477498
"DROP TABLE IF EXISTS ticketchng;"
478499
);
479500
zSql = ticket_table_schema();
480
- db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
501
+ ticket_restrict_sql(0);
481502
if( separateConnection ){
482503
if( db_transaction_nesting_depth() ) db_end_transaction(0);
483504
db_init_database(g.zRepositoryName, zSql, 0);
484505
}else{
485506
db_multi_exec("%s", zSql/*safe-for-%s*/);
486507
}
487
- db_clear_authorizer();
508
+ ticket_unrestrict_sql();
488509
fossil_free(zSql);
489510
}
490511
491512
/*
492513
** Repopulate the TICKET and TICKETCHNG tables from scratch using all
493514
--- src/tkt.c
+++ src/tkt.c
@@ -378,10 +378,12 @@
378 ** schema for the ticketing system. Only allow
379 **
380 ** CREATE TABLE
381 ** CREATE INDEX
382 ** CREATE VIEW
 
 
383 **
384 ** And for objects in "main" or "repository" whose names
385 ** begin with "ticket" or "fx_". Also allow
386 **
387 ** INSERT
@@ -393,10 +395,13 @@
393 **
394 ** Of particular importance for security is that this routine
395 ** disallows data changes on the "config" table, as that could
396 ** allow a malicious server to modify settings in such a way as
397 ** to cause a remote code execution.
 
 
 
398 */
399 static int ticket_schema_auth(
400 void *pNErr,
401 int eCode,
402 const char *z0,
@@ -403,10 +408,11 @@
403 const char *z1,
404 const char *z2,
405 const char *z3
406 ){
407 switch( eCode ){
 
408 case SQLITE_CREATE_VIEW:
409 case SQLITE_CREATE_TABLE: {
410 if( sqlite3_stricmp(z2,"main")!=0
411 && sqlite3_stricmp(z2,"repository")!=0
412 ){
@@ -417,10 +423,11 @@
417 ){
418 goto ticket_schema_error;
419 }
420 break;
421 }
 
422 case SQLITE_CREATE_INDEX: {
423 if( sqlite3_stricmp(z2,"main")!=0
424 && sqlite3_stricmp(z2,"repository")!=0
425 ){
426 goto ticket_schema_error;
@@ -463,10 +470,24 @@
463 ticket_schema_error:
464 if( pNErr ) *(int*)pNErr = 1;
465 return SQLITE_DENY;
466 }
467
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
469 /*
470 ** Recreate the TICKET and TICKETCHNG tables.
471 */
472 void ticket_create_table(int separateConnection){
@@ -475,18 +496,18 @@
475 db_multi_exec(
476 "DROP TABLE IF EXISTS ticket;"
477 "DROP TABLE IF EXISTS ticketchng;"
478 );
479 zSql = ticket_table_schema();
480 db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
481 if( separateConnection ){
482 if( db_transaction_nesting_depth() ) db_end_transaction(0);
483 db_init_database(g.zRepositoryName, zSql, 0);
484 }else{
485 db_multi_exec("%s", zSql/*safe-for-%s*/);
486 }
487 db_clear_authorizer();
488 fossil_free(zSql);
489 }
490
491 /*
492 ** Repopulate the TICKET and TICKETCHNG tables from scratch using all
493
--- src/tkt.c
+++ src/tkt.c
@@ -378,10 +378,12 @@
378 ** schema for the ticketing system. Only allow
379 **
380 ** CREATE TABLE
381 ** CREATE INDEX
382 ** CREATE VIEW
383 ** DROP INDEX
384 ** DROP VIEW
385 **
386 ** And for objects in "main" or "repository" whose names
387 ** begin with "ticket" or "fx_". Also allow
388 **
389 ** INSERT
@@ -393,10 +395,13 @@
395 **
396 ** Of particular importance for security is that this routine
397 ** disallows data changes on the "config" table, as that could
398 ** allow a malicious server to modify settings in such a way as
399 ** to cause a remote code execution.
400 **
401 ** Use the "fossil test-db-prepare --auth-ticket SQL" command to perform
402 ** manual testing of this authorizer.
403 */
404 static int ticket_schema_auth(
405 void *pNErr,
406 int eCode,
407 const char *z0,
@@ -403,10 +408,11 @@
408 const char *z1,
409 const char *z2,
410 const char *z3
411 ){
412 switch( eCode ){
413 case SQLITE_DROP_VIEW:
414 case SQLITE_CREATE_VIEW:
415 case SQLITE_CREATE_TABLE: {
416 if( sqlite3_stricmp(z2,"main")!=0
417 && sqlite3_stricmp(z2,"repository")!=0
418 ){
@@ -417,10 +423,11 @@
423 ){
424 goto ticket_schema_error;
425 }
426 break;
427 }
428 case SQLITE_DROP_INDEX:
429 case SQLITE_CREATE_INDEX: {
430 if( sqlite3_stricmp(z2,"main")!=0
431 && sqlite3_stricmp(z2,"repository")!=0
432 ){
433 goto ticket_schema_error;
@@ -463,10 +470,24 @@
470 ticket_schema_error:
471 if( pNErr ) *(int*)pNErr = 1;
472 return SQLITE_DENY;
473 }
474
475 /*
476 ** Activate the ticket schema authorizer. Must be followed by
477 ** an eventual call to ticket_unrestrict_sql().
478 */
479 void ticket_restrict_sql(int * pNErr){
480 db_set_authorizer(ticket_schema_auth,(void*)pNErr,"Ticket-Schema");
481 }
482 /*
483 ** Deactivate the ticket schema authorizer.
484 */
485 void ticket_unrestrict_sql(void){
486 db_clear_authorizer();
487 }
488
489
490 /*
491 ** Recreate the TICKET and TICKETCHNG tables.
492 */
493 void ticket_create_table(int separateConnection){
@@ -475,18 +496,18 @@
496 db_multi_exec(
497 "DROP TABLE IF EXISTS ticket;"
498 "DROP TABLE IF EXISTS ticketchng;"
499 );
500 zSql = ticket_table_schema();
501 ticket_restrict_sql(0);
502 if( separateConnection ){
503 if( db_transaction_nesting_depth() ) db_end_transaction(0);
504 db_init_database(g.zRepositoryName, zSql, 0);
505 }else{
506 db_multi_exec("%s", zSql/*safe-for-%s*/);
507 }
508 ticket_unrestrict_sql();
509 fossil_free(zSql);
510 }
511
512 /*
513 ** Repopulate the TICKET and TICKETCHNG tables from scratch using all
514
+21 -4
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,12 @@
11
<title>Change Log</title>
22
33
<a name='v2_16'></a>
44
<h2>Changes for Version 2.16 (pending)</h2>
5
+ * <b>Security:</b> Fix the client-side TLS so that it verifies that the
6
+ server hostname matches its certificate. <b>Upgrading to
7
+ the patch is recommended.</b>
58
* The [/brlist|/brlist web page] allows the user to
69
select multiple branches to be displayed together in a single
710
timeline.
811
* The [./forum.wiki|Forum] provides a hyperlink on the author of each
912
post that goes to a timeline of recent posts by that same author.
@@ -16,18 +19,28 @@
1619
pages now default to markdown format.
1720
* The [/help?cmd=/login|/login] page now links to a user's forum post
1821
timeline if the repository has forum posts.
1922
* Tags may now be propagated for forum posts, wiki pages, and technotes.
2023
The [/help?cmd=tag|tag command] can now manipulate and list such tags.
24
+ * [./caps/login-groups.md|Login-Groups] are now show on the repository
25
+ list of the "[/help?cmd=all|fossil all ui]" command.
26
+ * Administrators can configure [./alerts|email alerts] to expire
27
+ a specific number of days (ex: 365) after the last user contact with
28
+ the Fossil server. This can prevents alert emails being sent to
29
+ abandoned email accounts forever.
2130
* Submenu of the [/help?cmd=/rptview|/rptview] and
2231
[/help?cmd=/wiki|/wiki] pages may be
2332
[branch/rptview-submenu-paralink|extended with auxiliary hyperlinks].
2433
2534
<a name='v2_15'></a>
26
-<h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)</h2>
35
+<h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)
36
+ and 2.15.2 on (2021-06-15)</h2>
37
+ * <b>Patch 2.15.2:</b> Fix the client-side TLS so that it verifies that the
38
+ server hostname matches its certificate. <b>Upgrading to
39
+ the patch is recommended.</b>
2740
* <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
28
- the patch is recommended.</b><p>
41
+ the patch is recommended.</b>
2942
* The [./defcsp.md|default CSP] has been relaxed slightly to allow
3043
images to be loaded from any URL. All other resources are still
3144
locked down by default.
3245
* The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
3346
setting to determine the content of the main menu.
@@ -102,13 +115,17 @@
102115
versions of a wiki (by the means of anchoring a "baseline" version)
103116
and the ability to squeeze several sequential edits made by the same
104117
user into a single "recycled" row (the latest edit in that sequence).
105118
106119
<a name='v2_14'></a>
107
-<h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)</h2>
120
+<h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
121
+ and 2.14.2 on (2021-06-15)</h2>
122
+ * <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
123
+ server hostname matches its certificate. <b>Upgrading to
124
+ the patch is recommended.</b><
108125
* <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
109
- <b>Upgrading to the patch is recommended.</b><p>
126
+ <b>Upgrading to the patch is recommended.</b>
110127
* <b>Schema Update Notice #1:</b>
111128
This release drops a trigger from the database schema (replacing
112129
it with a TEMP trigger that is created as needed). This
113130
change happens automatically the first time you
114131
add content to a repository using Fossil 2.14 or later. No
115132
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,12 @@
1 <title>Change Log</title>
2
3 <a name='v2_16'></a>
4 <h2>Changes for Version 2.16 (pending)</h2>
 
 
 
5 * The [/brlist|/brlist web page] allows the user to
6 select multiple branches to be displayed together in a single
7 timeline.
8 * The [./forum.wiki|Forum] provides a hyperlink on the author of each
9 post that goes to a timeline of recent posts by that same author.
@@ -16,18 +19,28 @@
16 pages now default to markdown format.
17 * The [/help?cmd=/login|/login] page now links to a user's forum post
18 timeline if the repository has forum posts.
19 * Tags may now be propagated for forum posts, wiki pages, and technotes.
20 The [/help?cmd=tag|tag command] can now manipulate and list such tags.
 
 
 
 
 
 
21 * Submenu of the [/help?cmd=/rptview|/rptview] and
22 [/help?cmd=/wiki|/wiki] pages may be
23 [branch/rptview-submenu-paralink|extended with auxiliary hyperlinks].
24
25 <a name='v2_15'></a>
26 <h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)</h2>
 
 
 
 
27 * <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
28 the patch is recommended.</b><p>
29 * The [./defcsp.md|default CSP] has been relaxed slightly to allow
30 images to be loaded from any URL. All other resources are still
31 locked down by default.
32 * The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
33 setting to determine the content of the main menu.
@@ -102,13 +115,17 @@
102 versions of a wiki (by the means of anchoring a "baseline" version)
103 and the ability to squeeze several sequential edits made by the same
104 user into a single "recycled" row (the latest edit in that sequence).
105
106 <a name='v2_14'></a>
107 <h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)</h2>
 
 
 
 
108 * <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
109 <b>Upgrading to the patch is recommended.</b><p>
110 * <b>Schema Update Notice #1:</b>
111 This release drops a trigger from the database schema (replacing
112 it with a TEMP trigger that is created as needed). This
113 change happens automatically the first time you
114 add content to a repository using Fossil 2.14 or later. No
115
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,12 @@
1 <title>Change Log</title>
2
3 <a name='v2_16'></a>
4 <h2>Changes for Version 2.16 (pending)</h2>
5 * <b>Security:</b> Fix the client-side TLS so that it verifies that the
6 server hostname matches its certificate. <b>Upgrading to
7 the patch is recommended.</b>
8 * The [/brlist|/brlist web page] allows the user to
9 select multiple branches to be displayed together in a single
10 timeline.
11 * The [./forum.wiki|Forum] provides a hyperlink on the author of each
12 post that goes to a timeline of recent posts by that same author.
@@ -16,18 +19,28 @@
19 pages now default to markdown format.
20 * The [/help?cmd=/login|/login] page now links to a user's forum post
21 timeline if the repository has forum posts.
22 * Tags may now be propagated for forum posts, wiki pages, and technotes.
23 The [/help?cmd=tag|tag command] can now manipulate and list such tags.
24 * [./caps/login-groups.md|Login-Groups] are now show on the repository
25 list of the "[/help?cmd=all|fossil all ui]" command.
26 * Administrators can configure [./alerts|email alerts] to expire
27 a specific number of days (ex: 365) after the last user contact with
28 the Fossil server. This can prevents alert emails being sent to
29 abandoned email accounts forever.
30 * Submenu of the [/help?cmd=/rptview|/rptview] and
31 [/help?cmd=/wiki|/wiki] pages may be
32 [branch/rptview-submenu-paralink|extended with auxiliary hyperlinks].
33
34 <a name='v2_15'></a>
35 <h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)
36 and 2.15.2 on (2021-06-15)</h2>
37 * <b>Patch 2.15.2:</b> Fix the client-side TLS so that it verifies that the
38 server hostname matches its certificate. <b>Upgrading to
39 the patch is recommended.</b>
40 * <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
41 the patch is recommended.</b>
42 * The [./defcsp.md|default CSP] has been relaxed slightly to allow
43 images to be loaded from any URL. All other resources are still
44 locked down by default.
45 * The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
46 setting to determine the content of the main menu.
@@ -102,13 +115,17 @@
115 versions of a wiki (by the means of anchoring a "baseline" version)
116 and the ability to squeeze several sequential edits made by the same
117 user into a single "recycled" row (the latest edit in that sequence).
118
119 <a name='v2_14'></a>
120 <h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
121 and 2.14.2 on (2021-06-15)</h2>
122 * <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
123 server hostname matches its certificate. <b>Upgrading to
124 the patch is recommended.</b><
125 * <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
126 <b>Upgrading to the patch is recommended.</b>
127 * <b>Schema Update Notice #1:</b>
128 This release drops a trigger from the database schema (replacing
129 it with a TEMP trigger that is created as needed). This
130 change happens automatically the first time you
131 add content to a repository using Fossil 2.14 or later. No
132
+21 -4
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,12 @@
11
<title>Change Log</title>
22
33
<a name='v2_16'></a>
44
<h2>Changes for Version 2.16 (pending)</h2>
5
+ * <b>Security:</b> Fix the client-side TLS so that it verifies that the
6
+ server hostname matches its certificate. <b>Upgrading to
7
+ the patch is recommended.</b>
58
* The [/brlist|/brlist web page] allows the user to
69
select multiple branches to be displayed together in a single
710
timeline.
811
* The [./forum.wiki|Forum] provides a hyperlink on the author of each
912
post that goes to a timeline of recent posts by that same author.
@@ -16,18 +19,28 @@
1619
pages now default to markdown format.
1720
* The [/help?cmd=/login|/login] page now links to a user's forum post
1821
timeline if the repository has forum posts.
1922
* Tags may now be propagated for forum posts, wiki pages, and technotes.
2023
The [/help?cmd=tag|tag command] can now manipulate and list such tags.
24
+ * [./caps/login-groups.md|Login-Groups] are now show on the repository
25
+ list of the "[/help?cmd=all|fossil all ui]" command.
26
+ * Administrators can configure [./alerts|email alerts] to expire
27
+ a specific number of days (ex: 365) after the last user contact with
28
+ the Fossil server. This can prevents alert emails being sent to
29
+ abandoned email accounts forever.
2130
* Submenu of the [/help?cmd=/rptview|/rptview] and
2231
[/help?cmd=/wiki|/wiki] pages may be
2332
[branch/rptview-submenu-paralink|extended with auxiliary hyperlinks].
2433
2534
<a name='v2_15'></a>
26
-<h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)</h2>
35
+<h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)
36
+ and 2.15.2 on (2021-06-15)</h2>
37
+ * <b>Patch 2.15.2:</b> Fix the client-side TLS so that it verifies that the
38
+ server hostname matches its certificate. <b>Upgrading to
39
+ the patch is recommended.</b>
2740
* <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
28
- the patch is recommended.</b><p>
41
+ the patch is recommended.</b>
2942
* The [./defcsp.md|default CSP] has been relaxed slightly to allow
3043
images to be loaded from any URL. All other resources are still
3144
locked down by default.
3245
* The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
3346
setting to determine the content of the main menu.
@@ -102,13 +115,17 @@
102115
versions of a wiki (by the means of anchoring a "baseline" version)
103116
and the ability to squeeze several sequential edits made by the same
104117
user into a single "recycled" row (the latest edit in that sequence).
105118
106119
<a name='v2_14'></a>
107
-<h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)</h2>
120
+<h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
121
+ and 2.14.2 on (2021-06-15)</h2>
122
+ * <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
123
+ server hostname matches its certificate. <b>Upgrading to
124
+ the patch is recommended.</b><
108125
* <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
109
- <b>Upgrading to the patch is recommended.</b><p>
126
+ <b>Upgrading to the patch is recommended.</b>
110127
* <b>Schema Update Notice #1:</b>
111128
This release drops a trigger from the database schema (replacing
112129
it with a TEMP trigger that is created as needed). This
113130
change happens automatically the first time you
114131
add content to a repository using Fossil 2.14 or later. No
115132
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,12 @@
1 <title>Change Log</title>
2
3 <a name='v2_16'></a>
4 <h2>Changes for Version 2.16 (pending)</h2>
 
 
 
5 * The [/brlist|/brlist web page] allows the user to
6 select multiple branches to be displayed together in a single
7 timeline.
8 * The [./forum.wiki|Forum] provides a hyperlink on the author of each
9 post that goes to a timeline of recent posts by that same author.
@@ -16,18 +19,28 @@
16 pages now default to markdown format.
17 * The [/help?cmd=/login|/login] page now links to a user's forum post
18 timeline if the repository has forum posts.
19 * Tags may now be propagated for forum posts, wiki pages, and technotes.
20 The [/help?cmd=tag|tag command] can now manipulate and list such tags.
 
 
 
 
 
 
21 * Submenu of the [/help?cmd=/rptview|/rptview] and
22 [/help?cmd=/wiki|/wiki] pages may be
23 [branch/rptview-submenu-paralink|extended with auxiliary hyperlinks].
24
25 <a name='v2_15'></a>
26 <h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)</h2>
 
 
 
 
27 * <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
28 the patch is recommended.</b><p>
29 * The [./defcsp.md|default CSP] has been relaxed slightly to allow
30 images to be loaded from any URL. All other resources are still
31 locked down by default.
32 * The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
33 setting to determine the content of the main menu.
@@ -102,13 +115,17 @@
102 versions of a wiki (by the means of anchoring a "baseline" version)
103 and the ability to squeeze several sequential edits made by the same
104 user into a single "recycled" row (the latest edit in that sequence).
105
106 <a name='v2_14'></a>
107 <h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)</h2>
 
 
 
 
108 * <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
109 <b>Upgrading to the patch is recommended.</b><p>
110 * <b>Schema Update Notice #1:</b>
111 This release drops a trigger from the database schema (replacing
112 it with a TEMP trigger that is created as needed). This
113 change happens automatically the first time you
114 add content to a repository using Fossil 2.14 or later. No
115
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,12 @@
1 <title>Change Log</title>
2
3 <a name='v2_16'></a>
4 <h2>Changes for Version 2.16 (pending)</h2>
5 * <b>Security:</b> Fix the client-side TLS so that it verifies that the
6 server hostname matches its certificate. <b>Upgrading to
7 the patch is recommended.</b>
8 * The [/brlist|/brlist web page] allows the user to
9 select multiple branches to be displayed together in a single
10 timeline.
11 * The [./forum.wiki|Forum] provides a hyperlink on the author of each
12 post that goes to a timeline of recent posts by that same author.
@@ -16,18 +19,28 @@
19 pages now default to markdown format.
20 * The [/help?cmd=/login|/login] page now links to a user's forum post
21 timeline if the repository has forum posts.
22 * Tags may now be propagated for forum posts, wiki pages, and technotes.
23 The [/help?cmd=tag|tag command] can now manipulate and list such tags.
24 * [./caps/login-groups.md|Login-Groups] are now show on the repository
25 list of the "[/help?cmd=all|fossil all ui]" command.
26 * Administrators can configure [./alerts|email alerts] to expire
27 a specific number of days (ex: 365) after the last user contact with
28 the Fossil server. This can prevents alert emails being sent to
29 abandoned email accounts forever.
30 * Submenu of the [/help?cmd=/rptview|/rptview] and
31 [/help?cmd=/wiki|/wiki] pages may be
32 [branch/rptview-submenu-paralink|extended with auxiliary hyperlinks].
33
34 <a name='v2_15'></a>
35 <h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)
36 and 2.15.2 on (2021-06-15)</h2>
37 * <b>Patch 2.15.2:</b> Fix the client-side TLS so that it verifies that the
38 server hostname matches its certificate. <b>Upgrading to
39 the patch is recommended.</b>
40 * <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
41 the patch is recommended.</b>
42 * The [./defcsp.md|default CSP] has been relaxed slightly to allow
43 images to be loaded from any URL. All other resources are still
44 locked down by default.
45 * The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
46 setting to determine the content of the main menu.
@@ -102,13 +115,17 @@
115 versions of a wiki (by the means of anchoring a "baseline" version)
116 and the ability to squeeze several sequential edits made by the same
117 user into a single "recycled" row (the latest edit in that sequence).
118
119 <a name='v2_14'></a>
120 <h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
121 and 2.14.2 on (2021-06-15)</h2>
122 * <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
123 server hostname matches its certificate. <b>Upgrading to
124 the patch is recommended.</b><
125 * <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
126 <b>Upgrading to the patch is recommended.</b>
127 * <b>Schema Update Notice #1:</b>
128 This release drops a trigger from the database schema (replacing
129 it with a TEMP trigger that is created as needed). This
130 change happens automatically the first time you
131 add content to a repository using Fossil 2.14 or later. No
132
+2 -2
--- www/index.wiki
+++ www/index.wiki
@@ -82,15 +82,15 @@
8282
the repository are consistent prior to each commit.
8383
8484
8. <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].
8585
8686
<hr>
87
-<h3>Latest Release: 2.15 ([/timeline?c=version-2.15|2021-03-26])</h3>
87
+<h3>Latest Release: 2.15.2 ([/timeline?c=version-2.15.2|2021-06-15])</h3>
8888
8989
* [/uv/download.html|Download]
9090
* [./changes.wiki#v2_15|Change Summary]
91
- * [/timeline?p=version-2.15&bt=version-2.14&y=ci|Check-ins in version 2.15]
91
+ * [/timeline?p=version-2.15.2&bt=version-2.14&y=ci|Check-ins in version 2.15.2]
9292
* [/timeline?df=version-2.15&y=ci|Check-ins derived from the 2.15 release]
9393
* [/timeline?t=release|Timeline of all past releases]
9494
9595
<hr>
9696
<h3>Quick Start</h3>
9797
--- www/index.wiki
+++ www/index.wiki
@@ -82,15 +82,15 @@
82 the repository are consistent prior to each commit.
83
84 8. <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].
85
86 <hr>
87 <h3>Latest Release: 2.15 ([/timeline?c=version-2.15|2021-03-26])</h3>
88
89 * [/uv/download.html|Download]
90 * [./changes.wiki#v2_15|Change Summary]
91 * [/timeline?p=version-2.15&bt=version-2.14&y=ci|Check-ins in version 2.15]
92 * [/timeline?df=version-2.15&y=ci|Check-ins derived from the 2.15 release]
93 * [/timeline?t=release|Timeline of all past releases]
94
95 <hr>
96 <h3>Quick Start</h3>
97
--- www/index.wiki
+++ www/index.wiki
@@ -82,15 +82,15 @@
82 the repository are consistent prior to each commit.
83
84 8. <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].
85
86 <hr>
87 <h3>Latest Release: 2.15.2 ([/timeline?c=version-2.15.2|2021-06-15])</h3>
88
89 * [/uv/download.html|Download]
90 * [./changes.wiki#v2_15|Change Summary]
91 * [/timeline?p=version-2.15.2&bt=version-2.14&y=ci|Check-ins in version 2.15.2]
92 * [/timeline?df=version-2.15&y=ci|Check-ins derived from the 2.15 release]
93 * [/timeline?t=release|Timeline of all past releases]
94
95 <hr>
96 <h3>Quick Start</h3>
97
--- www/javascript.md
+++ www/javascript.md
@@ -572,11 +572,11 @@
572572
gateway bidirectional should be possible as well, as long as it properly
573573
uses SQLite transactions.
574574
575575
### <a id="brlist"></a>List of branches
576576
577
-Since Fossil 2.16 [`/brlist`](/brlist) page uses JavaScript to enable
577
+Since Fossil 2.16 the [`/brlist`](/brlist) page uses JavaScript to enable
578578
selection of several branches for further study via `/timeline`.
579579
Client-side script interactively responds to checkboxes' events
580580
and constructs a special hyperlink in the submenu.
581581
Clicking this hyperlink loads a `/timeline` page that shows
582582
only these selected branches (and the related check-ins).
@@ -619,12 +619,12 @@
619619
2) Features end users request which catch the interest of one or more
620620
developers, provided the developer(s) in question are in a position to
621621
expend the effort.
622622
623623
3) Features end users and co-contributors can convince a developer into
624
-coding even when they really don't want to. 𘘉
624
+coding even when they really don't want to.
625625
626626
In all of this, Fossil's project lead understandably has the final
627627
say-so in whether any given feature indeed gets merged into the mainline
628628
trunk. Development of any given feature, no matter how much effort was
629629
involved, does not guarantee its eventual inclusion into the public
630630
releases.
631631
--- www/javascript.md
+++ www/javascript.md
@@ -572,11 +572,11 @@
572 gateway bidirectional should be possible as well, as long as it properly
573 uses SQLite transactions.
574
575 ### <a id="brlist"></a>List of branches
576
577 Since Fossil 2.16 [`/brlist`](/brlist) page uses JavaScript to enable
578 selection of several branches for further study via `/timeline`.
579 Client-side script interactively responds to checkboxes' events
580 and constructs a special hyperlink in the submenu.
581 Clicking this hyperlink loads a `/timeline` page that shows
582 only these selected branches (and the related check-ins).
@@ -619,12 +619,12 @@
619 2) Features end users request which catch the interest of one or more
620 developers, provided the developer(s) in question are in a position to
621 expend the effort.
622
623 3) Features end users and co-contributors can convince a developer into
624 coding even when they really don't want to. 𘘉
625
626 In all of this, Fossil's project lead understandably has the final
627 say-so in whether any given feature indeed gets merged into the mainline
628 trunk. Development of any given feature, no matter how much effort was
629 involved, does not guarantee its eventual inclusion into the public
630 releases.
631
--- www/javascript.md
+++ www/javascript.md
@@ -572,11 +572,11 @@
572 gateway bidirectional should be possible as well, as long as it properly
573 uses SQLite transactions.
574
575 ### <a id="brlist"></a>List of branches
576
577 Since Fossil 2.16 the [`/brlist`](/brlist) page uses JavaScript to enable
578 selection of several branches for further study via `/timeline`.
579 Client-side script interactively responds to checkboxes' events
580 and constructs a special hyperlink in the submenu.
581 Clicking this hyperlink loads a `/timeline` page that shows
582 only these selected branches (and the related check-ins).
@@ -619,12 +619,12 @@
619 2) Features end users request which catch the interest of one or more
620 developers, provided the developer(s) in question are in a position to
621 expend the effort.
622
623 3) Features end users and co-contributors can convince a developer into
624 coding even when they really don't want to.
625
626 In all of this, Fossil's project lead understandably has the final
627 say-so in whether any given feature indeed gets merged into the mainline
628 trunk. Development of any given feature, no matter how much effort was
629 involved, does not guarantee its eventual inclusion into the public
630 releases.
631
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -115,10 +115,11 @@
115115
theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
116116
tickets.wiki {The Fossil Ticket System}
117117
unvers.wiki {Unversioned Files}
118118
webpage-ex.md {Webpage Examples}
119119
webui.wiki {The Fossil Web Interface}
120
+ whyallinone.md {Why Bundle Forum, Wiki, and other Web Software With Your DVCS?}
120121
whyusefossil.wiki {Why You Should Use Fossil}
121122
whyusefossil.wiki {Benefits Of Version Control}
122123
wikitheory.wiki {Wiki In Fossil}
123124
/wiki_rules {Wiki Formatting Rules}
124125
}
125126
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -115,10 +115,11 @@
115 theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
116 tickets.wiki {The Fossil Ticket System}
117 unvers.wiki {Unversioned Files}
118 webpage-ex.md {Webpage Examples}
119 webui.wiki {The Fossil Web Interface}
 
120 whyusefossil.wiki {Why You Should Use Fossil}
121 whyusefossil.wiki {Benefits Of Version Control}
122 wikitheory.wiki {Wiki In Fossil}
123 /wiki_rules {Wiki Formatting Rules}
124 }
125
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -115,10 +115,11 @@
115 theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
116 tickets.wiki {The Fossil Ticket System}
117 unvers.wiki {Unversioned Files}
118 webpage-ex.md {Webpage Examples}
119 webui.wiki {The Fossil Web Interface}
120 whyallinone.md {Why Bundle Forum, Wiki, and other Web Software With Your DVCS?}
121 whyusefossil.wiki {Why You Should Use Fossil}
122 whyusefossil.wiki {Benefits Of Version Control}
123 wikitheory.wiki {Wiki In Fossil}
124 /wiki_rules {Wiki Formatting Rules}
125 }
126
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -125,9 +125,10 @@
125125
<li><a href="fiveminutes.wiki">Up and Running in 5 Minutes as a Single User</a></li>
126126
<li><a href="javascript.md">Use of JavaScript in Fossil</a></li>
127127
<li><a href="caps/ref.html">User Capability Reference</a></li>
128128
<li><a href="ssl.wiki">Using SSL with Fossil</a></li>
129129
<li><a href="webpage-ex.md">Webpage Examples</a></li>
130
+<li><a href="whyallinone.md">Why Bundle Forum, Wiki, and other Web Software With Your DVCS?</a></li>
130131
<li><a href="whyusefossil.wiki">Why You Should Use Fossil</a></li>
131132
<li><a href="../../../wiki_rules">Wiki Formatting Rules</a></li>
132133
<li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
133134
</ul></div>
134135
135136
ADDED www/whyallinone.md
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -125,9 +125,10 @@
125 <li><a href="fiveminutes.wiki">Up and Running in 5 Minutes as a Single User</a></li>
126 <li><a href="javascript.md">Use of JavaScript in Fossil</a></li>
127 <li><a href="caps/ref.html">User Capability Reference</a></li>
128 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
129 <li><a href="webpage-ex.md">Webpage Examples</a></li>
 
130 <li><a href="whyusefossil.wiki">Why You Should Use Fossil</a></li>
131 <li><a href="../../../wiki_rules">Wiki Formatting Rules</a></li>
132 <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
133 </ul></div>
134
135 DDED www/whyallinone.md
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -125,9 +125,10 @@
125 <li><a href="fiveminutes.wiki">Up and Running in 5 Minutes as a Single User</a></li>
126 <li><a href="javascript.md">Use of JavaScript in Fossil</a></li>
127 <li><a href="caps/ref.html">User Capability Reference</a></li>
128 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
129 <li><a href="webpage-ex.md">Webpage Examples</a></li>
130 <li><a href="whyallinone.md">Why Bundle Forum, Wiki, and other Web Software With Your DVCS?</a></li>
131 <li><a href="whyusefossil.wiki">Why You Should Use Fossil</a></li>
132 <li><a href="../../../wiki_rules">Wiki Formatting Rules</a></li>
133 <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
134 </ul></div>
135
136 DDED www/whyallinone.md
--- a/www/whyallinone.md
+++ b/www/whyallinone.md
@@ -0,0 +1,231 @@
1
+# Why Add Forum, Wiki, and Web Software To Your DVCS?
2
+
3
+One notable feature of Fossil is that it bundles
4
+[bug tracking](./bugtheory.wiki),
5
+[wiki](./wikitheory.wiki),
6
+[forum](./forum.wiki),
7
+[chat](./chat.md), and
8
+[technotes](./event.wiki)
9
+with distributed version control to give you an
10
+all-in-one software project management system.
11
+
12
+A commenter on [Hacker News](https://news.ycombinator.com/item?id=27437895)
13
+takes exception to this idea, writing:
14
+
15
+> *I don't want forum/web software built into my dvcs.*
16
+> *I don't see how this improves over git.*
17
+
18
+This commenter may hold whatever opinions he wishes, of course.
19
+However, there are many good reasons why bundling other project management
20
+features with the DVCS might be useful for a given project:
21
+
22
+ 1. There is a single software package to install and manage for the
23
+ project website.
24
+ The alternative is to select, install, configure, learn about,
25
+ manage, and maintain separate DVCS, wiki,
26
+ ticketing, forum,
27
+ chat, documentation, and whatever other software packages your project needs.
28
+ Less time spent on project administration details means more
29
+ time available to spend on the project itself.
30
+
31
+ 2. Fossil’s autosync feature gives you an implicit backup of the
32
+ wiki, tickets, forum, and so forth simply by cloning the
33
+ repository to another machine and using that clone regularly.
34
+ Since the typical Fossil usage pattern is to stand the repo up on a
35
+ central server and have the developers clone that repository down
36
+ to their personal machines, if the server falls over, the last
37
+ developer to do anything that resulted in an autosync has a
38
+ functional and up-to-date backup.
39
+
40
+ There are [limitations to relying on Fossil’s autosync feature for
41
+ backup purposes](./backup.md), but that document gives two methods
42
+ for more complete backups, both of which are easily automated. The
43
+ Fossil project itself is distributed across three data centers in
44
+ this manner via cron.
45
+
46
+ 3. Remote workers get more than just the source code:
47
+ they get the entire website including versioned documentation,
48
+ wiki articles, tickets, forum posts, and so forth. This supports
49
+ off-network development when traveling, when riding out Internet
50
+ service failures, and when workers must sync with multiple remote
51
+ servers, as when working alternately from home and in some central
52
+ office.
53
+
54
+ Feature-competitive Fossil alternatives typically solve this same
55
+ problem with centralization, which generally means that only the
56
+ DVCS piece still works in these situations where the developer is
57
+ unable to contact the central server. Why accept the limitation of
58
+ having a distributed clone of the code repo alone?
59
+
60
+ Centralization doesn’t work for every project. If you enjoy the
61
+ benefits of truly distributed (read: non-centralized) version
62
+ control, you may also benefit from distributed forums, distributed
63
+ ticket tracking, distributed wiki article publishing, and so
64
+ forth.
65
+
66
+ 4. Integration of all of these features allows easy hyperlinks between
67
+ check-in comments, wiki pages, forum posts, and tickets. More,
68
+ because the software sees both sides of the link, referrer and
69
+ referent, it can provide automatic back-references.
70
+
71
+ A common situation in a Fossil project is that:
72
+
73
+ * a forum post refers to a versioned project document that shows
74
+ that the software isn’t behaving as documented;
75
+ * a developer triages that forum report as a verified bug, filing
76
+ a ticket to prioritize and track the resolution;
77
+ * developers chat about the problem, referring to the ticket and
78
+ thereby indirectly referring to the forum post, plus perhaps to
79
+ other Fossil-managed resources such as a wiki document giving
80
+ design principles that guide the proper fix; and finally
81
+ * the commit message resolving the ticket includes a reference to
82
+ the ticket it resolves.
83
+
84
+ Since Fossil sees that the commit refers to a ticket, the ticket
85
+ page automatically also refers back to the commit, closing the
86
+ loop. A latecomer may arrive at the ticket via a web search, and
87
+ from that see that it was closed following a commit. They can
88
+ follow the link from the initial ticket message to the forum
89
+ thread to catch up on the discussion leading to the fix and likely
90
+ find a follow-up post from the initial reporting user saying
91
+ whether the fix worked for them. If further work was needed, the
92
+ latecomer can likely find it from that forum thread.
93
+
94
+ This works even in a remote off-network clone: the developer can
95
+ pull up the project web site via an `http://localhost` link and
96
+ follow these links around the loop.
97
+
98
+ Fossil allows breaking some of these project facilities out into
99
+ separate repositories, as when the public forum is kept separate
100
+ from the actual software development repository for administration
101
+ reasons. By using Fossil’s [interwiki link
102
+ feature](./interwiki.md), you can get this same internal linking
103
+ from ticket to commit to forum to wiki even across these
104
+ administrative boundaries, even with remote off-network clones,
105
+ simply by adjusting the interwiki map to match the remote clone’s
106
+ network configuration.
107
+
108
+ 5. Bundling all of these services gives [single sign-on][SSO] (SSO) for all
109
+ aspects of the project. The same username/password works for code,
110
+ wiki, forum, tickets, and chat.
111
+
112
+ If you choose to administratively separate some of these features
113
+ by setting up multiple cooperating Fossil repositories, its skinning groups feature](./caps/login-groups.md) allows asymmetric SSO
114
+ across these administrative boundaries so that, for example, users
115
+ allowed to commit to the code repository also get a forum
116
+ repository login, but self-registered forum users don’t
117
+ automatically get the ability to commit to the code repo.
118
+
119
+ 6. Bundling all of these features reduces the number of external
120
+ dependencies for the project.
121
+
122
+ Take the first two points above: standing up a Fossil repo backup
123
+ on a new server may be as simple as copying the backup to the new
124
+ server and [configuring its stock HTTP server to point at the
125
+ backup repository via CGI](./server/any/cgi.md).
126
+
127
+ Consider: If you had good backups for all of the elements in a
128
+ Git + [Jira] + [Discord] + [MediaWiki] + [Sphinx] lash-up, how long
129
+ would it take you to stand up a replacement? That lash-up
130
+ certainly has more features combined than Fossil alone, but are
131
+ they worth the administration and hosting costs they impose?
132
+ Fossil’s feature set suffices for the SQLite project it was
133
+ created to serve, as well as for many others; is your project
134
+ sufficiently more complex, such that it *needs* all of those extra
135
+ features and their concomitant complexity?
136
+
137
+ Considerations such as these push many into centralized hosting
138
+ services such as GitHub, GitLab, Bitbucket, and so forth, but that
139
+ just takes you back to point 3 above.
140
+
141
+ 7. Hosting all of these elements within a single service gives a
142
+ consistent look-and-feel across all aspects of the project.
143
+
144
+ Skinning independent software packages’ web interfaces to make
145
+ them appear unified is more work than [skinning] everything once, as
146
+ in Fossil, and even then, you can’t make independently-developed
147
+ software look like it was produced by a single entity without
148
+ resorting to heroic levels of customization. If you use a separate
149
+ DVCS web front end, chat system, forum manager, documentation
150
+ system, ticket tracker, and so on, you are likely to be relegated
151
+ to simply matching colors and fonts; you *might* also get the
152
+ ability to add a common logo to the header of all of these
153
+ independent pieces. The pieces won’t look unified, because they
154
+ weren’t developed that way.
155
+
156
+ The Fossil project’s
157
+ skinning system lets you affect all of its elements globally from the
158
+ single skin editor.
159
+
160
+ Or not: there’s a feature in Fossil that lets skin customizations
161
+ apply to only *some* Fossil features. The initial impetus behind
162
+ this feature was that one of our users wanted Markdown to be
163
+ rendered with different indentation in forum posts than in
164
+ [embedded documentation][edoc] owing to the inherent differences between
165
+ the two presentation modalities.
166
+
167
+ A user taking advantage of this per-feature CSS capability who
168
+ wishes to change a UI element common to all Fossil features — say,
169
+ to change the font for literal code blocks — may still make such a
170
+ change globally. Opting into this per-feature CSS doesn’t fork all
171
+ skinning efforts: UI elements not explicitly reskinned on a
172
+ per-feature basis inherit the global skinning.
173
+
174
+ But it goes futher. Fossil has a feature for [project-specific
175
+ extensions](./serverext.wiki), which backs the [SQLite Release
176
+ Checklist][srckl], for instance. You wouldn’t know by looking at
177
+ that page that it’s produced by software that isn’t actually part
178
+ of Fossil: the extension only delivers the core of the page,
179
+ and Fossil’s skining wraps it in a way that lets it inherit all of
180
+ the project-level skinning customizations.
181
+
182
+ 8. Unifying all of these features within Fossil
183
+ means we have a single Markdown interpreter common to all
184
+ elements. If you lash multiple software systems together, even if
185
+ they can all agree on Markdown as a common document markup
186
+ language — hardly a given, as shown by the MediaWiki and Sphinx
187
+ elements in point 6’s example above — they’re likely to render your text
188
+ using different — possibly even incompatibly-different — Markdown
189
+ dialects.
190
+
191
+ This costs you Fossil
192
+can link out to these systems, and they back into Fossil, letting you
193
+use Fossiln-controlled
194
+ project document. A developer on a Fossil-backed project may simply copy-paste the forum post
195
+ text into the new document and save it, not needing to carefully
196
+ check that it still renders properly under the second Markdown
197
+ rendering engine. Similarly, if a user reports a potential bug via
198
+ the forum, the developer can copy interesting pieces of the
199
+ Markdown from the post into a ticket comment, again without
200
+ needing to fiddle with dialect incompatibilities.
201
+
202
+ 9. Fossil is [free, open-source software](../COPYRIGHT-BSD2.txt),
203
+ through and through. Git-backed lash-ups tend to incorporate
204
+ either proprietary add-ons or proprietary hosting systems that
205
+ produce vendor lock-in. Fossil gives you the freedom to take your
206
+ complete backup (point 2) of the project including its
207
+ idiosyncratic customizations and stand it up elsewhere on
208
+ commodity hardware and software stacks.
209
+
210
+All of this having been said, the non-DVCS features of Fossil are
211
+optional. Its forum and chat features are disabled by default, and you
212
+can disable the ticket-tracking and wiki features with a quick
213
+configuration change to its [role-based access control system](./caps/).
214
+When you’re ready to turn these additional features on, you can do so
215
+with a few mouse clicks.
216
+
217
+Because Fossil is web-native out of the box, if you’ve delegated these
218
+features to outside systems to flesh out Git’s DVCS-only nature, you are
219
+free to do the same with Fossil. One of the many things the [skinning]
220
+facility allows is replacing the built-in links to the wiki, forum,
221
+ticket system, etc. with links to external systems. How easy those
222
+systems make it to link back into Fossil is up to their developers.
223
+
224
+[Discord]: https://discord.com/
225
+[edoc]: ./embeddeddoc.wiki
226
+[Jira]: https://www.atlassian.com/software/jira
227
+[MediaWiki]: https://www.mediawiki.org/
228
+[skinning]: ./customskin.md
229
+[Sphinx]: https://www.sphinx-doc.org/en/master/
230
+[SSO]: https://en.wikipedia.org/wiki/Single_sign-on
231
+[srckl]: https://www.sqlite.org/src/ext/checklist/top/inde
--- a/www/whyallinone.md
+++ b/www/whyallinone.md
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/whyallinone.md
+++ b/www/whyallinone.md
@@ -0,0 +1,231 @@
1 # Why Add Forum, Wiki, and Web Software To Your DVCS?
2
3 One notable feature of Fossil is that it bundles
4 [bug tracking](./bugtheory.wiki),
5 [wiki](./wikitheory.wiki),
6 [forum](./forum.wiki),
7 [chat](./chat.md), and
8 [technotes](./event.wiki)
9 with distributed version control to give you an
10 all-in-one software project management system.
11
12 A commenter on [Hacker News](https://news.ycombinator.com/item?id=27437895)
13 takes exception to this idea, writing:
14
15 > *I don't want forum/web software built into my dvcs.*
16 > *I don't see how this improves over git.*
17
18 This commenter may hold whatever opinions he wishes, of course.
19 However, there are many good reasons why bundling other project management
20 features with the DVCS might be useful for a given project:
21
22 1. There is a single software package to install and manage for the
23 project website.
24 The alternative is to select, install, configure, learn about,
25 manage, and maintain separate DVCS, wiki,
26 ticketing, forum,
27 chat, documentation, and whatever other software packages your project needs.
28 Less time spent on project administration details means more
29 time available to spend on the project itself.
30
31 2. Fossil’s autosync feature gives you an implicit backup of the
32 wiki, tickets, forum, and so forth simply by cloning the
33 repository to another machine and using that clone regularly.
34 Since the typical Fossil usage pattern is to stand the repo up on a
35 central server and have the developers clone that repository down
36 to their personal machines, if the server falls over, the last
37 developer to do anything that resulted in an autosync has a
38 functional and up-to-date backup.
39
40 There are [limitations to relying on Fossil’s autosync feature for
41 backup purposes](./backup.md), but that document gives two methods
42 for more complete backups, both of which are easily automated. The
43 Fossil project itself is distributed across three data centers in
44 this manner via cron.
45
46 3. Remote workers get more than just the source code:
47 they get the entire website including versioned documentation,
48 wiki articles, tickets, forum posts, and so forth. This supports
49 off-network development when traveling, when riding out Internet
50 service failures, and when workers must sync with multiple remote
51 servers, as when working alternately from home and in some central
52 office.
53
54 Feature-competitive Fossil alternatives typically solve this same
55 problem with centralization, which generally means that only the
56 DVCS piece still works in these situations where the developer is
57 unable to contact the central server. Why accept the limitation of
58 having a distributed clone of the code repo alone?
59
60 Centralization doesn’t work for every project. If you enjoy the
61 benefits of truly distributed (read: non-centralized) version
62 control, you may also benefit from distributed forums, distributed
63 ticket tracking, distributed wiki article publishing, and so
64 forth.
65
66 4. Integration of all of these features allows easy hyperlinks between
67 check-in comments, wiki pages, forum posts, and tickets. More,
68 because the software sees both sides of the link, referrer and
69 referent, it can provide automatic back-references.
70
71 A common situation in a Fossil project is that:
72
73 * a forum post refers to a versioned project document that shows
74 that the software isn’t behaving as documented;
75 * a developer triages that forum report as a verified bug, filing
76 a ticket to prioritize and track the resolution;
77 * developers chat about the problem, referring to the ticket and
78 thereby indirectly referring to the forum post, plus perhaps to
79 other Fossil-managed resources such as a wiki document giving
80 design principles that guide the proper fix; and finally
81 * the commit message resolving the ticket includes a reference to
82 the ticket it resolves.
83
84 Since Fossil sees that the commit refers to a ticket, the ticket
85 page automatically also refers back to the commit, closing the
86 loop. A latecomer may arrive at the ticket via a web search, and
87 from that see that it was closed following a commit. They can
88 follow the link from the initial ticket message to the forum
89 thread to catch up on the discussion leading to the fix and likely
90 find a follow-up post from the initial reporting user saying
91 whether the fix worked for them. If further work was needed, the
92 latecomer can likely find it from that forum thread.
93
94 This works even in a remote off-network clone: the developer can
95 pull up the project web site via an `http://localhost` link and
96 follow these links around the loop.
97
98 Fossil allows breaking some of these project facilities out into
99 separate repositories, as when the public forum is kept separate
100 from the actual software development repository for administration
101 reasons. By using Fossil’s [interwiki link
102 feature](./interwiki.md), you can get this same internal linking
103 from ticket to commit to forum to wiki even across these
104 administrative boundaries, even with remote off-network clones,
105 simply by adjusting the interwiki map to match the remote clone’s
106 network configuration.
107
108 5. Bundling all of these services gives [single sign-on][SSO] (SSO) for all
109 aspects of the project. The same username/password works for code,
110 wiki, forum, tickets, and chat.
111
112 If you choose to administratively separate some of these features
113 by setting up multiple cooperating Fossil repositories, its skinning groups feature](./caps/login-groups.md) allows asymmetric SSO
114 across these administrative boundaries so that, for example, users
115 allowed to commit to the code repository also get a forum
116 repository login, but self-registered forum users don’t
117 automatically get the ability to commit to the code repo.
118
119 6. Bundling all of these features reduces the number of external
120 dependencies for the project.
121
122 Take the first two points above: standing up a Fossil repo backup
123 on a new server may be as simple as copying the backup to the new
124 server and [configuring its stock HTTP server to point at the
125 backup repository via CGI](./server/any/cgi.md).
126
127 Consider: If you had good backups for all of the elements in a
128 Git + [Jira] + [Discord] + [MediaWiki] + [Sphinx] lash-up, how long
129 would it take you to stand up a replacement? That lash-up
130 certainly has more features combined than Fossil alone, but are
131 they worth the administration and hosting costs they impose?
132 Fossil’s feature set suffices for the SQLite project it was
133 created to serve, as well as for many others; is your project
134 sufficiently more complex, such that it *needs* all of those extra
135 features and their concomitant complexity?
136
137 Considerations such as these push many into centralized hosting
138 services such as GitHub, GitLab, Bitbucket, and so forth, but that
139 just takes you back to point 3 above.
140
141 7. Hosting all of these elements within a single service gives a
142 consistent look-and-feel across all aspects of the project.
143
144 Skinning independent software packages’ web interfaces to make
145 them appear unified is more work than [skinning] everything once, as
146 in Fossil, and even then, you can’t make independently-developed
147 software look like it was produced by a single entity without
148 resorting to heroic levels of customization. If you use a separate
149 DVCS web front end, chat system, forum manager, documentation
150 system, ticket tracker, and so on, you are likely to be relegated
151 to simply matching colors and fonts; you *might* also get the
152 ability to add a common logo to the header of all of these
153 independent pieces. The pieces won’t look unified, because they
154 weren’t developed that way.
155
156 The Fossil project’s
157 skinning system lets you affect all of its elements globally from the
158 single skin editor.
159
160 Or not: there’s a feature in Fossil that lets skin customizations
161 apply to only *some* Fossil features. The initial impetus behind
162 this feature was that one of our users wanted Markdown to be
163 rendered with different indentation in forum posts than in
164 [embedded documentation][edoc] owing to the inherent differences between
165 the two presentation modalities.
166
167 A user taking advantage of this per-feature CSS capability who
168 wishes to change a UI element common to all Fossil features — say,
169 to change the font for literal code blocks — may still make such a
170 change globally. Opting into this per-feature CSS doesn’t fork all
171 skinning efforts: UI elements not explicitly reskinned on a
172 per-feature basis inherit the global skinning.
173
174 But it goes futher. Fossil has a feature for [project-specific
175 extensions](./serverext.wiki), which backs the [SQLite Release
176 Checklist][srckl], for instance. You wouldn’t know by looking at
177 that page that it’s produced by software that isn’t actually part
178 of Fossil: the extension only delivers the core of the page,
179 and Fossil’s skining wraps it in a way that lets it inherit all of
180 the project-level skinning customizations.
181
182 8. Unifying all of these features within Fossil
183 means we have a single Markdown interpreter common to all
184 elements. If you lash multiple software systems together, even if
185 they can all agree on Markdown as a common document markup
186 language — hardly a given, as shown by the MediaWiki and Sphinx
187 elements in point 6’s example above — they’re likely to render your text
188 using different — possibly even incompatibly-different — Markdown
189 dialects.
190
191 This costs you Fossil
192 can link out to these systems, and they back into Fossil, letting you
193 use Fossiln-controlled
194 project document. A developer on a Fossil-backed project may simply copy-paste the forum post
195 text into the new document and save it, not needing to carefully
196 check that it still renders properly under the second Markdown
197 rendering engine. Similarly, if a user reports a potential bug via
198 the forum, the developer can copy interesting pieces of the
199 Markdown from the post into a ticket comment, again without
200 needing to fiddle with dialect incompatibilities.
201
202 9. Fossil is [free, open-source software](../COPYRIGHT-BSD2.txt),
203 through and through. Git-backed lash-ups tend to incorporate
204 either proprietary add-ons or proprietary hosting systems that
205 produce vendor lock-in. Fossil gives you the freedom to take your
206 complete backup (point 2) of the project including its
207 idiosyncratic customizations and stand it up elsewhere on
208 commodity hardware and software stacks.
209
210 All of this having been said, the non-DVCS features of Fossil are
211 optional. Its forum and chat features are disabled by default, and you
212 can disable the ticket-tracking and wiki features with a quick
213 configuration change to its [role-based access control system](./caps/).
214 When you’re ready to turn these additional features on, you can do so
215 with a few mouse clicks.
216
217 Because Fossil is web-native out of the box, if you’ve delegated these
218 features to outside systems to flesh out Git’s DVCS-only nature, you are
219 free to do the same with Fossil. One of the many things the [skinning]
220 facility allows is replacing the built-in links to the wiki, forum,
221 ticket system, etc. with links to external systems. How easy those
222 systems make it to link back into Fossil is up to their developers.
223
224 [Discord]: https://discord.com/
225 [edoc]: ./embeddeddoc.wiki
226 [Jira]: https://www.atlassian.com/software/jira
227 [MediaWiki]: https://www.mediawiki.org/
228 [skinning]: ./customskin.md
229 [Sphinx]: https://www.sphinx-doc.org/en/master/
230 [SSO]: https://en.wikipedia.org/wiki/Single_sign-on
231 [srckl]: https://www.sqlite.org/src/ext/checklist/top/inde

Keyboard Shortcuts

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