Fossil SCM

Merge current trunk.

larrybr 2021-03-25 15:43 panic-reduction merge
Commit d1adf6c40a4fec09f920cdf3df8a094507efdb6e3060f8d65c79edc91da9ea64
+1 -1
--- src/chat.c
+++ src/chat.c
@@ -186,11 +186,11 @@
186186
@ <div id='chat-messages-wrapper'>
187187
/* New chat messages get inserted immediately after this element */
188188
@ <span id='message-inject-point'></span>
189189
@ </div>
190190
191
- builtin_fossil_js_bundle_or("popupwidget", "storage", NULL);
191
+ builtin_fossil_js_bundle_or("popupwidget", "storage", "fetch", NULL);
192192
/* Always in-line the javascript for the chat page */
193193
@ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
194194
/* We need an onload handler to ensure that window.fossil is
195195
initialized before the chat init code runs. */
196196
@ window.addEventListener('load', function(){
197197
--- src/chat.c
+++ src/chat.c
@@ -186,11 +186,11 @@
186 @ <div id='chat-messages-wrapper'>
187 /* New chat messages get inserted immediately after this element */
188 @ <span id='message-inject-point'></span>
189 @ </div>
190
191 builtin_fossil_js_bundle_or("popupwidget", "storage", NULL);
192 /* Always in-line the javascript for the chat page */
193 @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
194 /* We need an onload handler to ensure that window.fossil is
195 initialized before the chat init code runs. */
196 @ window.addEventListener('load', function(){
197
--- src/chat.c
+++ src/chat.c
@@ -186,11 +186,11 @@
186 @ <div id='chat-messages-wrapper'>
187 /* New chat messages get inserted immediately after this element */
188 @ <span id='message-inject-point'></span>
189 @ </div>
190
191 builtin_fossil_js_bundle_or("popupwidget", "storage", "fetch", NULL);
192 /* Always in-line the javascript for the chat page */
193 @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
194 /* We need an onload handler to ensure that window.fossil is
195 initialized before the chat init code runs. */
196 @ window.addEventListener('load', function(){
197
+87 -66
--- src/chat.js
+++ src/chat.js
@@ -397,10 +397,12 @@
397397
this.playNewMessageSound.uri = uri;
398398
this.settings.set('audible-alert', !!uri);
399399
return this;
400400
}
401401
};
402
+ F.fetch.beforesend = ()=>cs.ajaxStart();
403
+ F.fetch.aftersend = ()=>cs.ajaxEnd();
402404
cs.e.inputCurrent = cs.e.inputSingle;
403405
/* Install default settings... */
404406
Object.keys(cs.settings.defaults).forEach(function(k){
405407
const v = cs.settings.get(k,cs);
406408
if(cs===v) cs.settings.set(k,cs.settings.defaults[k]);
@@ -538,18 +540,15 @@
538540
e = this.getMessageElemById(id);
539541
}
540542
if(!(e instanceof HTMLElement)) return;
541543
if(this.userMayDelete(e)){
542544
this.ajaxStart();
543
- fetch("chat-delete/" + id)
544
- .then(function(response){
545
- if(!response.ok) throw cs._newResponseError(response);
546
- return response;
547
- })
548
- .then(()=>this.deleteMessageElem(e))
549
- .catch(err=>this.reportErrorAsMessage(err))
550
- .finally(()=>this.ajaxEnd());
545
+ F.fetch("chat-delete/" + id, {
546
+ responseType: 'json',
547
+ onload:(r)=>this.deleteMessageElem(r),
548
+ onerror:(err)=>this.reportErrorAsMessage(err)
549
+ });
551550
}else{
552551
this.deleteMessageElem(id);
553552
}
554553
};
555554
document.addEventListener('visibilitychange', function(ev){
@@ -878,27 +877,25 @@
878877
const file = BlobXferState.blob || this.e.inputFile.files[0];
879878
if(file) fd.set("file", file);
880879
if( !msg && !file ) return;
881880
const self = this;
882881
fd.set("lmtime", localTime8601(new Date()));
883
- fetch("chat-send",{
884
- method: 'POST',
885
- body: fd
886
- }).then((x)=>{
887
- if(x.ok) return x.text();
888
- else throw Chat._newResponseError(x);
889
- }).then(function(txt){
882
+ F.fetch("chat-send",{
883
+ payload: fd,
884
+ responseType: 'text',
885
+ onerror:(err)=>this.reportErrorAsMessage(err),
886
+ onload:function(txt){
890887
if(!txt) return/*success response*/;
891888
try{
892889
const json = JSON.parse(txt);
893890
self.newContent({msgs:[json]});
894891
}catch(e){
895892
self.reportError(e);
896893
return;
897894
}
898
- })
899
- .catch((e)=>this.reportErrorAsMessage(e));
895
+ }
896
+ });
900897
BlobXferState.clear();
901898
Chat.inputValue("").inputFocus();
902899
};
903900
904901
Chat.e.inputSingle.addEventListener('keydown',function(ev){
@@ -1155,35 +1152,36 @@
11551152
D.fieldset(loadLegend), "id", "load-msg-toolbar"
11561153
);
11571154
Chat.disableDuringAjax.push(toolbar);
11581155
/* Loads the next n oldest messages, or all previous history if n is negative. */
11591156
const loadOldMessages = function(n){
1160
- Chat.ajaxStart();
11611157
Chat.e.messagesWrapper.classList.add('loading');
11621158
Chat._isBatchLoading = true;
1163
- var gotMessages = false;
11641159
const scrollHt = Chat.e.messagesWrapper.scrollHeight,
11651160
scrollTop = Chat.e.messagesWrapper.scrollTop;
1166
- fetch("chat-poll?before="+Chat.mnMsg+"&n="+n)
1167
- .then(Chat._fetchJsonOrError)
1168
- .then(function(x){
1169
- gotMessages = x.msgs.length;
1161
+ F.fetch("chat-poll",{
1162
+ urlParams:{
1163
+ before: Chat.mnMsg,
1164
+ n: n
1165
+ },
1166
+ responseType: 'json',
1167
+ onerror:function(err){
1168
+ Chat.reportErrorAsMessage(err);
1169
+ Chat._isBatchLoading = false;
1170
+ },
1171
+ onload:function(x){
1172
+ let gotMessages = x.msgs.length;
11701173
newcontent(x,true);
1171
- })
1172
- .catch(e=>Chat.reportErrorAsMessage(e))
1173
- .finally(function(){
11741174
Chat._isBatchLoading = false;
1175
- Chat.e.messagesWrapper.classList.remove('loading');
1176
- Chat.ajaxEnd();
11771175
if(Chat._gotServerError){
1178
- F.toast.error("Got an error response from the server. ",
1179
- "See message for details.");
1176
+ Chat._gotServerError = false;
11801177
return;
1181
- }else if(n<0/*we asked for all history*/
1178
+ }
1179
+ if(n<0/*we asked for all history*/
11821180
|| 0===gotMessages/*we found no history*/
11831181
|| (n>0 && gotMessages<n /*we got fewer history entries than requested*/)
1184
- || (false!==gotMessages && n===0 && gotMessages<Chat.loadMessageCount
1182
+ || (n===0 && gotMessages<Chat.loadMessageCount
11851183
/*we asked for default amount and got fewer than that.*/)){
11861184
/* We've loaded all history. Permanently disable the
11871185
history-load toolbar and keep it from being re-enabled
11881186
via the ajaxStart()/ajaxEnd() mechanism... */
11891187
const div = Chat.e.loadOlderToolbar.querySelector('div');
@@ -1199,11 +1197,16 @@
11991197
was requested, per user request */
12001198
Chat.e.messagesWrapper.scrollTo(
12011199
0, Chat.e.messagesWrapper.scrollHeight - scrollHt + scrollTop
12021200
);
12031201
}
1204
- });
1202
+ },
1203
+ aftersend:function(){
1204
+ Chat.e.messagesWrapper.classList.remove('loading');
1205
+ Chat.ajaxEnd();
1206
+ }
1207
+ });
12051208
};
12061209
const wrapper = D.div(); /* browsers don't all properly handle >1 child in a fieldset */;
12071210
D.append(toolbar, wrapper);
12081211
var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
12091212
D.append(wrapper, btn);
@@ -1213,47 +1216,65 @@
12131216
btn.addEventListener('click',()=>loadOldMessages(-1));
12141217
D.append(Chat.e.messagesWrapper, toolbar);
12151218
toolbar.disabled = true /*will be enabled when msg load finishes */;
12161219
})()/*end history loading widget setup*/;
12171220
1218
- async function poll(isFirstCall){
1219
- if(poll.running) return;
1220
- poll.running = true;
1221
- if(isFirstCall){
1221
+ const afterFetch = function f(){
1222
+ if(true===f.isFirstCall){
1223
+ f.isFirstCall = false;
1224
+ Chat.ajaxEnd();
1225
+ Chat.e.messagesWrapper.classList.remove('loading');
1226
+ setTimeout(function(){
1227
+ Chat.scrollMessagesTo(1);
1228
+ }, 250);
1229
+ }
1230
+ if(Chat._gotServerError && Chat.intervalTimer){
1231
+ clearInterval(Chat.intervalTimer);
1232
+ Chat.reportErrorAsMessage(
1233
+ "Shutting down chat poller due to server-side error. ",
1234
+ "Reload this page to reactivate it.");
1235
+ delete Chat.intervalTimer;
1236
+ }
1237
+ poll.running = false;
1238
+ };
1239
+ afterFetch.isFirstCall = true;
1240
+ const poll = async function f(){
1241
+ if(f.running) return;
1242
+ f.running = true;
1243
+ Chat._isBatchLoading = f.isFirstCall;
1244
+ if(true===f.isFirstCall){
1245
+ f.isFirstCall = false;
12221246
Chat.ajaxStart();
12231247
Chat.e.messagesWrapper.classList.add('loading');
12241248
}
1225
- Chat._isBatchLoading = isFirstCall;
1226
- var p = fetch("chat-poll?name=" + Chat.mxMsg);
1227
- p.then(Chat._fetchJsonOrError)
1228
- .then(y=>newcontent(y))
1229
- .catch(e=>console.error(e))
1230
- /* ^^^ we don't use Chat.reportError(e) here b/c the polling
1231
- fails exepectedly when it times out, but is then immediately
1232
- resumed, and reportError() produces a loud error message. */
1233
- .finally(function(){
1234
- if(isFirstCall){
1235
- Chat._isBatchLoading = false;
1236
- Chat.ajaxEnd();
1237
- Chat.e.messagesWrapper.classList.remove('loading');
1238
- setTimeout(function(){
1239
- Chat.scrollMessagesTo(1);
1240
- }, 250);
1241
- }
1242
- if(Chat._gotServerError && Chat.intervalTimer){
1243
- clearInterval(Chat.intervalTimer);
1244
- delete Chat.intervalTimer;
1245
- }
1246
- poll.running=false;
1247
- });
1248
- }
1249
+ F.fetch("chat-poll",{
1250
+ timeout: 420 * 1000/*FIXME: get the value from the server*/,
1251
+ urlParams:{
1252
+ name: Chat.mxMsg
1253
+ },
1254
+ responseType: "json",
1255
+ // Disable the ajax start/end handling for this long-polling op:
1256
+ beforesend: function(){},
1257
+ aftersend: function(){},
1258
+ onerror:function(err){
1259
+ Chat._isBatchLoading = false;
1260
+ console.error(err);
1261
+ /* ^^^ we don't use Chat.reportError() here b/c the polling
1262
+ fails exepectedly when it times out, but is then immediately
1263
+ resumed, and reportError() produces a loud error message. */
1264
+ afterFetch();
1265
+ },
1266
+ onload:function(y){
1267
+ newcontent(y);
1268
+ Chat._isBatchLoading = false;
1269
+ afterFetch();
1270
+ }
1271
+ });
1272
+ };
1273
+ poll.isFirstCall = true;
12491274
Chat._gotServerError = poll.running = false;
1250
- poll(true);
1251
- if(!Chat._gotServerError){
1252
- Chat.intervalTimer = setInterval(poll, 1000);
1253
- }
12541275
if( window.fossil.config.chat.fromcli ){
12551276
Chat.chatOnlyMode(true);
12561277
}
1257
-
1278
+ Chat.intervalTimer = setInterval(poll, 1000);
12581279
F.page.chat = Chat/* enables testing the APIs via the dev tools */;
12591280
})();
12601281
--- src/chat.js
+++ src/chat.js
@@ -397,10 +397,12 @@
397 this.playNewMessageSound.uri = uri;
398 this.settings.set('audible-alert', !!uri);
399 return this;
400 }
401 };
 
 
402 cs.e.inputCurrent = cs.e.inputSingle;
403 /* Install default settings... */
404 Object.keys(cs.settings.defaults).forEach(function(k){
405 const v = cs.settings.get(k,cs);
406 if(cs===v) cs.settings.set(k,cs.settings.defaults[k]);
@@ -538,18 +540,15 @@
538 e = this.getMessageElemById(id);
539 }
540 if(!(e instanceof HTMLElement)) return;
541 if(this.userMayDelete(e)){
542 this.ajaxStart();
543 fetch("chat-delete/" + id)
544 .then(function(response){
545 if(!response.ok) throw cs._newResponseError(response);
546 return response;
547 })
548 .then(()=>this.deleteMessageElem(e))
549 .catch(err=>this.reportErrorAsMessage(err))
550 .finally(()=>this.ajaxEnd());
551 }else{
552 this.deleteMessageElem(id);
553 }
554 };
555 document.addEventListener('visibilitychange', function(ev){
@@ -878,27 +877,25 @@
878 const file = BlobXferState.blob || this.e.inputFile.files[0];
879 if(file) fd.set("file", file);
880 if( !msg && !file ) return;
881 const self = this;
882 fd.set("lmtime", localTime8601(new Date()));
883 fetch("chat-send",{
884 method: 'POST',
885 body: fd
886 }).then((x)=>{
887 if(x.ok) return x.text();
888 else throw Chat._newResponseError(x);
889 }).then(function(txt){
890 if(!txt) return/*success response*/;
891 try{
892 const json = JSON.parse(txt);
893 self.newContent({msgs:[json]});
894 }catch(e){
895 self.reportError(e);
896 return;
897 }
898 })
899 .catch((e)=>this.reportErrorAsMessage(e));
900 BlobXferState.clear();
901 Chat.inputValue("").inputFocus();
902 };
903
904 Chat.e.inputSingle.addEventListener('keydown',function(ev){
@@ -1155,35 +1152,36 @@
1155 D.fieldset(loadLegend), "id", "load-msg-toolbar"
1156 );
1157 Chat.disableDuringAjax.push(toolbar);
1158 /* Loads the next n oldest messages, or all previous history if n is negative. */
1159 const loadOldMessages = function(n){
1160 Chat.ajaxStart();
1161 Chat.e.messagesWrapper.classList.add('loading');
1162 Chat._isBatchLoading = true;
1163 var gotMessages = false;
1164 const scrollHt = Chat.e.messagesWrapper.scrollHeight,
1165 scrollTop = Chat.e.messagesWrapper.scrollTop;
1166 fetch("chat-poll?before="+Chat.mnMsg+"&n="+n)
1167 .then(Chat._fetchJsonOrError)
1168 .then(function(x){
1169 gotMessages = x.msgs.length;
 
 
 
 
 
 
 
 
1170 newcontent(x,true);
1171 })
1172 .catch(e=>Chat.reportErrorAsMessage(e))
1173 .finally(function(){
1174 Chat._isBatchLoading = false;
1175 Chat.e.messagesWrapper.classList.remove('loading');
1176 Chat.ajaxEnd();
1177 if(Chat._gotServerError){
1178 F.toast.error("Got an error response from the server. ",
1179 "See message for details.");
1180 return;
1181 }else if(n<0/*we asked for all history*/
 
1182 || 0===gotMessages/*we found no history*/
1183 || (n>0 && gotMessages<n /*we got fewer history entries than requested*/)
1184 || (false!==gotMessages && n===0 && gotMessages<Chat.loadMessageCount
1185 /*we asked for default amount and got fewer than that.*/)){
1186 /* We've loaded all history. Permanently disable the
1187 history-load toolbar and keep it from being re-enabled
1188 via the ajaxStart()/ajaxEnd() mechanism... */
1189 const div = Chat.e.loadOlderToolbar.querySelector('div');
@@ -1199,11 +1197,16 @@
1199 was requested, per user request */
1200 Chat.e.messagesWrapper.scrollTo(
1201 0, Chat.e.messagesWrapper.scrollHeight - scrollHt + scrollTop
1202 );
1203 }
1204 });
 
 
 
 
 
1205 };
1206 const wrapper = D.div(); /* browsers don't all properly handle >1 child in a fieldset */;
1207 D.append(toolbar, wrapper);
1208 var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
1209 D.append(wrapper, btn);
@@ -1213,47 +1216,65 @@
1213 btn.addEventListener('click',()=>loadOldMessages(-1));
1214 D.append(Chat.e.messagesWrapper, toolbar);
1215 toolbar.disabled = true /*will be enabled when msg load finishes */;
1216 })()/*end history loading widget setup*/;
1217
1218 async function poll(isFirstCall){
1219 if(poll.running) return;
1220 poll.running = true;
1221 if(isFirstCall){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1222 Chat.ajaxStart();
1223 Chat.e.messagesWrapper.classList.add('loading');
1224 }
1225 Chat._isBatchLoading = isFirstCall;
1226 var p = fetch("chat-poll?name=" + Chat.mxMsg);
1227 p.then(Chat._fetchJsonOrError)
1228 .then(y=>newcontent(y))
1229 .catch(e=>console.error(e))
1230 /* ^^^ we don't use Chat.reportError(e) here b/c the polling
1231 fails exepectedly when it times out, but is then immediately
1232 resumed, and reportError() produces a loud error message. */
1233 .finally(function(){
1234 if(isFirstCall){
1235 Chat._isBatchLoading = false;
1236 Chat.ajaxEnd();
1237 Chat.e.messagesWrapper.classList.remove('loading');
1238 setTimeout(function(){
1239 Chat.scrollMessagesTo(1);
1240 }, 250);
1241 }
1242 if(Chat._gotServerError && Chat.intervalTimer){
1243 clearInterval(Chat.intervalTimer);
1244 delete Chat.intervalTimer;
1245 }
1246 poll.running=false;
1247 });
1248 }
 
1249 Chat._gotServerError = poll.running = false;
1250 poll(true);
1251 if(!Chat._gotServerError){
1252 Chat.intervalTimer = setInterval(poll, 1000);
1253 }
1254 if( window.fossil.config.chat.fromcli ){
1255 Chat.chatOnlyMode(true);
1256 }
1257
1258 F.page.chat = Chat/* enables testing the APIs via the dev tools */;
1259 })();
1260
--- src/chat.js
+++ src/chat.js
@@ -397,10 +397,12 @@
397 this.playNewMessageSound.uri = uri;
398 this.settings.set('audible-alert', !!uri);
399 return this;
400 }
401 };
402 F.fetch.beforesend = ()=>cs.ajaxStart();
403 F.fetch.aftersend = ()=>cs.ajaxEnd();
404 cs.e.inputCurrent = cs.e.inputSingle;
405 /* Install default settings... */
406 Object.keys(cs.settings.defaults).forEach(function(k){
407 const v = cs.settings.get(k,cs);
408 if(cs===v) cs.settings.set(k,cs.settings.defaults[k]);
@@ -538,18 +540,15 @@
540 e = this.getMessageElemById(id);
541 }
542 if(!(e instanceof HTMLElement)) return;
543 if(this.userMayDelete(e)){
544 this.ajaxStart();
545 F.fetch("chat-delete/" + id, {
546 responseType: 'json',
547 onload:(r)=>this.deleteMessageElem(r),
548 onerror:(err)=>this.reportErrorAsMessage(err)
549 });
 
 
 
550 }else{
551 this.deleteMessageElem(id);
552 }
553 };
554 document.addEventListener('visibilitychange', function(ev){
@@ -878,27 +877,25 @@
877 const file = BlobXferState.blob || this.e.inputFile.files[0];
878 if(file) fd.set("file", file);
879 if( !msg && !file ) return;
880 const self = this;
881 fd.set("lmtime", localTime8601(new Date()));
882 F.fetch("chat-send",{
883 payload: fd,
884 responseType: 'text',
885 onerror:(err)=>this.reportErrorAsMessage(err),
886 onload:function(txt){
 
 
887 if(!txt) return/*success response*/;
888 try{
889 const json = JSON.parse(txt);
890 self.newContent({msgs:[json]});
891 }catch(e){
892 self.reportError(e);
893 return;
894 }
895 }
896 });
897 BlobXferState.clear();
898 Chat.inputValue("").inputFocus();
899 };
900
901 Chat.e.inputSingle.addEventListener('keydown',function(ev){
@@ -1155,35 +1152,36 @@
1152 D.fieldset(loadLegend), "id", "load-msg-toolbar"
1153 );
1154 Chat.disableDuringAjax.push(toolbar);
1155 /* Loads the next n oldest messages, or all previous history if n is negative. */
1156 const loadOldMessages = function(n){
 
1157 Chat.e.messagesWrapper.classList.add('loading');
1158 Chat._isBatchLoading = true;
 
1159 const scrollHt = Chat.e.messagesWrapper.scrollHeight,
1160 scrollTop = Chat.e.messagesWrapper.scrollTop;
1161 F.fetch("chat-poll",{
1162 urlParams:{
1163 before: Chat.mnMsg,
1164 n: n
1165 },
1166 responseType: 'json',
1167 onerror:function(err){
1168 Chat.reportErrorAsMessage(err);
1169 Chat._isBatchLoading = false;
1170 },
1171 onload:function(x){
1172 let gotMessages = x.msgs.length;
1173 newcontent(x,true);
 
 
 
1174 Chat._isBatchLoading = false;
 
 
1175 if(Chat._gotServerError){
1176 Chat._gotServerError = false;
 
1177 return;
1178 }
1179 if(n<0/*we asked for all history*/
1180 || 0===gotMessages/*we found no history*/
1181 || (n>0 && gotMessages<n /*we got fewer history entries than requested*/)
1182 || (n===0 && gotMessages<Chat.loadMessageCount
1183 /*we asked for default amount and got fewer than that.*/)){
1184 /* We've loaded all history. Permanently disable the
1185 history-load toolbar and keep it from being re-enabled
1186 via the ajaxStart()/ajaxEnd() mechanism... */
1187 const div = Chat.e.loadOlderToolbar.querySelector('div');
@@ -1199,11 +1197,16 @@
1197 was requested, per user request */
1198 Chat.e.messagesWrapper.scrollTo(
1199 0, Chat.e.messagesWrapper.scrollHeight - scrollHt + scrollTop
1200 );
1201 }
1202 },
1203 aftersend:function(){
1204 Chat.e.messagesWrapper.classList.remove('loading');
1205 Chat.ajaxEnd();
1206 }
1207 });
1208 };
1209 const wrapper = D.div(); /* browsers don't all properly handle >1 child in a fieldset */;
1210 D.append(toolbar, wrapper);
1211 var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
1212 D.append(wrapper, btn);
@@ -1213,47 +1216,65 @@
1216 btn.addEventListener('click',()=>loadOldMessages(-1));
1217 D.append(Chat.e.messagesWrapper, toolbar);
1218 toolbar.disabled = true /*will be enabled when msg load finishes */;
1219 })()/*end history loading widget setup*/;
1220
1221 const afterFetch = function f(){
1222 if(true===f.isFirstCall){
1223 f.isFirstCall = false;
1224 Chat.ajaxEnd();
1225 Chat.e.messagesWrapper.classList.remove('loading');
1226 setTimeout(function(){
1227 Chat.scrollMessagesTo(1);
1228 }, 250);
1229 }
1230 if(Chat._gotServerError && Chat.intervalTimer){
1231 clearInterval(Chat.intervalTimer);
1232 Chat.reportErrorAsMessage(
1233 "Shutting down chat poller due to server-side error. ",
1234 "Reload this page to reactivate it.");
1235 delete Chat.intervalTimer;
1236 }
1237 poll.running = false;
1238 };
1239 afterFetch.isFirstCall = true;
1240 const poll = async function f(){
1241 if(f.running) return;
1242 f.running = true;
1243 Chat._isBatchLoading = f.isFirstCall;
1244 if(true===f.isFirstCall){
1245 f.isFirstCall = false;
1246 Chat.ajaxStart();
1247 Chat.e.messagesWrapper.classList.add('loading');
1248 }
1249 F.fetch("chat-poll",{
1250 timeout: 420 * 1000/*FIXME: get the value from the server*/,
1251 urlParams:{
1252 name: Chat.mxMsg
1253 },
1254 responseType: "json",
1255 // Disable the ajax start/end handling for this long-polling op:
1256 beforesend: function(){},
1257 aftersend: function(){},
1258 onerror:function(err){
1259 Chat._isBatchLoading = false;
1260 console.error(err);
1261 /* ^^^ we don't use Chat.reportError() here b/c the polling
1262 fails exepectedly when it times out, but is then immediately
1263 resumed, and reportError() produces a loud error message. */
1264 afterFetch();
1265 },
1266 onload:function(y){
1267 newcontent(y);
1268 Chat._isBatchLoading = false;
1269 afterFetch();
1270 }
1271 });
1272 };
1273 poll.isFirstCall = true;
1274 Chat._gotServerError = poll.running = false;
 
 
 
 
1275 if( window.fossil.config.chat.fromcli ){
1276 Chat.chatOnlyMode(true);
1277 }
1278 Chat.intervalTimer = setInterval(poll, 1000);
1279 F.page.chat = Chat/* enables testing the APIs via the dev tools */;
1280 })();
1281
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -86,11 +86,11 @@
8686
- timeout: integer in milliseconds specifying the XHR timeout
8787
duration. Default = fossil.fetch.timeout.
8888
8989
When an options object does not provide
9090
onload/onerror/beforesend/aftersend handlers of its own, this
91
- function falls to defaults which are member properties of this
91
+ function falls back to defaults which are member properties of this
9292
function with the same name, e.g. fossil.fetch.onload(). The
9393
default onload/onerror implementations route the data through the
9494
dev console and (for onerror()) through fossil.error(). The default
9595
beforesend/aftersend are no-ops. Individual pages may overwrite
9696
those members to provide default implementations suitable for the
@@ -166,10 +166,22 @@
166166
opt.onerror(new Error("XHR timeout of "+x.timeout+"ms expired."));
167167
};
168168
x.onreadystatechange = function(){
169169
if(XMLHttpRequest.DONE !== x.readyState) return;
170170
try{opt.aftersend()}catch(e){/*ignore*/}
171
+ if(false && 0===x.status){
172
+ /* For reasons unknown, we _sometimes_ trigger x.status==0 in FF
173
+ when the /chat page starts up, but not in Chrome nor in other
174
+ apps. Insofar as has been determined, this happens before a
175
+ request is actually sent and it appears to have no
176
+ side-effects on the app other than to generate an error
177
+ (i.e. no requests/responses are missing). This is a silly
178
+ workaround which may or may not bite us later. If so, it can
179
+ be removed at the cost of an unsightly console error message
180
+ in FF. */
181
+ return;
182
+ }
171183
if(200!==x.status){
172184
let err;
173185
try{
174186
const j = JSON.parse(x.response);
175187
if(j.error) err = new Error(j.error);
176188
177189
ADDED src/fossil.page.whistory.js
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -86,11 +86,11 @@
86 - timeout: integer in milliseconds specifying the XHR timeout
87 duration. Default = fossil.fetch.timeout.
88
89 When an options object does not provide
90 onload/onerror/beforesend/aftersend handlers of its own, this
91 function falls to defaults which are member properties of this
92 function with the same name, e.g. fossil.fetch.onload(). The
93 default onload/onerror implementations route the data through the
94 dev console and (for onerror()) through fossil.error(). The default
95 beforesend/aftersend are no-ops. Individual pages may overwrite
96 those members to provide default implementations suitable for the
@@ -166,10 +166,22 @@
166 opt.onerror(new Error("XHR timeout of "+x.timeout+"ms expired."));
167 };
168 x.onreadystatechange = function(){
169 if(XMLHttpRequest.DONE !== x.readyState) return;
170 try{opt.aftersend()}catch(e){/*ignore*/}
 
 
 
 
 
 
 
 
 
 
 
 
171 if(200!==x.status){
172 let err;
173 try{
174 const j = JSON.parse(x.response);
175 if(j.error) err = new Error(j.error);
176
177 DDED src/fossil.page.whistory.js
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -86,11 +86,11 @@
86 - timeout: integer in milliseconds specifying the XHR timeout
87 duration. Default = fossil.fetch.timeout.
88
89 When an options object does not provide
90 onload/onerror/beforesend/aftersend handlers of its own, this
91 function falls back to defaults which are member properties of this
92 function with the same name, e.g. fossil.fetch.onload(). The
93 default onload/onerror implementations route the data through the
94 dev console and (for onerror()) through fossil.error(). The default
95 beforesend/aftersend are no-ops. Individual pages may overwrite
96 those members to provide default implementations suitable for the
@@ -166,10 +166,22 @@
166 opt.onerror(new Error("XHR timeout of "+x.timeout+"ms expired."));
167 };
168 x.onreadystatechange = function(){
169 if(XMLHttpRequest.DONE !== x.readyState) return;
170 try{opt.aftersend()}catch(e){/*ignore*/}
171 if(false && 0===x.status){
172 /* For reasons unknown, we _sometimes_ trigger x.status==0 in FF
173 when the /chat page starts up, but not in Chrome nor in other
174 apps. Insofar as has been determined, this happens before a
175 request is actually sent and it appears to have no
176 side-effects on the app other than to generate an error
177 (i.e. no requests/responses are missing). This is a silly
178 workaround which may or may not bite us later. If so, it can
179 be removed at the cost of an unsightly console error message
180 in FF. */
181 return;
182 }
183 if(200!==x.status){
184 let err;
185 try{
186 const j = JSON.parse(x.response);
187 if(j.error) err = new Error(j.error);
188
189 DDED src/fossil.page.whistory.js
--- a/src/fossil.page.whistory.js
+++ b/src/fossil.page.whistory.js
@@ -0,0 +1,3 @@
1
+/* This script adds interactivity for wiki-history webpages.
2
+ *
3
+ * Th
--- a/src/fossil.page.whistory.js
+++ b/src/fossil.page.whistory.js
@@ -0,0 +1,3 @@
 
 
 
--- a/src/fossil.page.whistory.js
+++ b/src/fossil.page.whistory.js
@@ -0,0 +1,3 @@
1 /* This script adds interactivity for wiki-history webpages.
2 *
3 * Th
--- src/main.mk
+++ src/main.mk
@@ -229,10 +229,11 @@
229229
$(SRCDIR)/fossil.info-diff.js \
230230
$(SRCDIR)/fossil.numbered-lines.js \
231231
$(SRCDIR)/fossil.page.fileedit.js \
232232
$(SRCDIR)/fossil.page.forumpost.js \
233233
$(SRCDIR)/fossil.page.pikchrshow.js \
234
+ $(SRCDIR)/fossil.page.whistory.js \
234235
$(SRCDIR)/fossil.page.wikiedit.js \
235236
$(SRCDIR)/fossil.pikchr.js \
236237
$(SRCDIR)/fossil.popupwidget.js \
237238
$(SRCDIR)/fossil.storage.js \
238239
$(SRCDIR)/fossil.tabs.js \
239240
--- src/main.mk
+++ src/main.mk
@@ -229,10 +229,11 @@
229 $(SRCDIR)/fossil.info-diff.js \
230 $(SRCDIR)/fossil.numbered-lines.js \
231 $(SRCDIR)/fossil.page.fileedit.js \
232 $(SRCDIR)/fossil.page.forumpost.js \
233 $(SRCDIR)/fossil.page.pikchrshow.js \
 
234 $(SRCDIR)/fossil.page.wikiedit.js \
235 $(SRCDIR)/fossil.pikchr.js \
236 $(SRCDIR)/fossil.popupwidget.js \
237 $(SRCDIR)/fossil.storage.js \
238 $(SRCDIR)/fossil.tabs.js \
239
--- src/main.mk
+++ src/main.mk
@@ -229,10 +229,11 @@
229 $(SRCDIR)/fossil.info-diff.js \
230 $(SRCDIR)/fossil.numbered-lines.js \
231 $(SRCDIR)/fossil.page.fileedit.js \
232 $(SRCDIR)/fossil.page.forumpost.js \
233 $(SRCDIR)/fossil.page.pikchrshow.js \
234 $(SRCDIR)/fossil.page.whistory.js \
235 $(SRCDIR)/fossil.page.wikiedit.js \
236 $(SRCDIR)/fossil.pikchr.js \
237 $(SRCDIR)/fossil.popupwidget.js \
238 $(SRCDIR)/fossil.storage.js \
239 $(SRCDIR)/fossil.tabs.js \
240
+1 -1
--- src/report.c
+++ src/report.c
@@ -1032,11 +1032,11 @@
10321032
if( !tabs ){
10331033
struct GenerateHTML sState = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
10341034
10351035
db_multi_exec("PRAGMA empty_result_callbacks=ON");
10361036
style_set_current_feature("report");
1037
- style_submenu_element("Raw", "rptview?tablist=1&%h", PD("QUERY_STRING",""));
1037
+ style_submenu_element("Raw", "rptview?tablist=1&rn=%d&%h", rn, PD("QUERY_STRING","") );
10381038
if( g.perm.Admin
10391039
|| (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
10401040
style_submenu_element("Edit", "rptedit?rn=%d", rn);
10411041
}
10421042
if( g.perm.TktFmt ){
10431043
--- src/report.c
+++ src/report.c
@@ -1032,11 +1032,11 @@
1032 if( !tabs ){
1033 struct GenerateHTML sState = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1034
1035 db_multi_exec("PRAGMA empty_result_callbacks=ON");
1036 style_set_current_feature("report");
1037 style_submenu_element("Raw", "rptview?tablist=1&%h", PD("QUERY_STRING",""));
1038 if( g.perm.Admin
1039 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
1040 style_submenu_element("Edit", "rptedit?rn=%d", rn);
1041 }
1042 if( g.perm.TktFmt ){
1043
--- src/report.c
+++ src/report.c
@@ -1032,11 +1032,11 @@
1032 if( !tabs ){
1033 struct GenerateHTML sState = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1034
1035 db_multi_exec("PRAGMA empty_result_callbacks=ON");
1036 style_set_current_feature("report");
1037 style_submenu_element("Raw", "rptview?tablist=1&rn=%d&%h", rn, PD("QUERY_STRING","") );
1038 if( g.perm.Admin
1039 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
1040 style_submenu_element("Edit", "rptedit?rn=%d", rn);
1041 }
1042 if( g.perm.TktFmt ){
1043
--- src/shell.c
+++ src/shell.c
@@ -13217,10 +13217,11 @@
1321713217
1321813218
rc = sqlite3_step(pStmt);
1321913219
if( rc!=SQLITE_ROW ) return;
1322013220
nColumn = sqlite3_column_count(pStmt);
1322113221
nAlloc = nColumn*4;
13222
+ if( nAlloc<=0 ) nAlloc = 1;
1322213223
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
1322313224
if( azData==0 ) shell_out_of_memory();
1322413225
for(i=0; i<nColumn; i++){
1322513226
azData[i] = strdup(sqlite3_column_name(pStmt,i));
1322613227
}
@@ -13256,10 +13257,11 @@
1325613257
n = strlenChar(z);
1325713258
j = i%nColumn;
1325813259
if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
1325913260
}
1326013261
if( seenInterrupt ) goto columnar_end;
13262
+ if( nColumn==0 ) goto columnar_end;
1326113263
switch( p->cMode ){
1326213264
case MODE_Column: {
1326313265
colSep = " ";
1326413266
rowSep = "\n";
1326513267
if( p->showHeader ){
1326613268
--- src/shell.c
+++ src/shell.c
@@ -13217,10 +13217,11 @@
13217
13218 rc = sqlite3_step(pStmt);
13219 if( rc!=SQLITE_ROW ) return;
13220 nColumn = sqlite3_column_count(pStmt);
13221 nAlloc = nColumn*4;
 
13222 azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
13223 if( azData==0 ) shell_out_of_memory();
13224 for(i=0; i<nColumn; i++){
13225 azData[i] = strdup(sqlite3_column_name(pStmt,i));
13226 }
@@ -13256,10 +13257,11 @@
13256 n = strlenChar(z);
13257 j = i%nColumn;
13258 if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
13259 }
13260 if( seenInterrupt ) goto columnar_end;
 
13261 switch( p->cMode ){
13262 case MODE_Column: {
13263 colSep = " ";
13264 rowSep = "\n";
13265 if( p->showHeader ){
13266
--- src/shell.c
+++ src/shell.c
@@ -13217,10 +13217,11 @@
13217
13218 rc = sqlite3_step(pStmt);
13219 if( rc!=SQLITE_ROW ) return;
13220 nColumn = sqlite3_column_count(pStmt);
13221 nAlloc = nColumn*4;
13222 if( nAlloc<=0 ) nAlloc = 1;
13223 azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
13224 if( azData==0 ) shell_out_of_memory();
13225 for(i=0; i<nColumn; i++){
13226 azData[i] = strdup(sqlite3_column_name(pStmt,i));
13227 }
@@ -13256,10 +13257,11 @@
13257 n = strlenChar(z);
13258 j = i%nColumn;
13259 if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
13260 }
13261 if( seenInterrupt ) goto columnar_end;
13262 if( nColumn==0 ) goto columnar_end;
13263 switch( p->cMode ){
13264 case MODE_Column: {
13265 colSep = " ";
13266 rowSep = "\n";
13267 if( p->showHeader ){
13268
+118 -78
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
11
/******************************************************************************
22
** This file is an amalgamation of many separate C source files from SQLite
3
-** version 3.35.2. By combining all the individual C code files into this
3
+** version 3.35.3. By combining all the individual C code files into this
44
** single large file, the entire code can be compiled as a single translation
55
** unit. This allows many compilers to do optimizations that would not be
66
** possible if the files were compiled separately. Performance improvements
77
** of 5% or more are commonly seen when SQLite is compiled as a single
88
** translation unit.
@@ -1184,13 +1184,13 @@
11841184
**
11851185
** See also: [sqlite3_libversion()],
11861186
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
11871187
** [sqlite_version()] and [sqlite_source_id()].
11881188
*/
1189
-#define SQLITE_VERSION "3.35.2"
1190
-#define SQLITE_VERSION_NUMBER 3035002
1191
-#define SQLITE_SOURCE_ID "2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827"
1189
+#define SQLITE_VERSION "3.35.3"
1190
+#define SQLITE_VERSION_NUMBER 3035003
1191
+#define SQLITE_SOURCE_ID "2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c"
11921192
11931193
/*
11941194
** CAPI3REF: Run-Time Library Version Numbers
11951195
** KEYWORDS: sqlite3_version sqlite3_sourceid
11961196
**
@@ -21069,10 +21069,11 @@
2106921069
u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
2107021070
#endif
2107121071
Bool isEphemeral:1; /* True for an ephemeral table */
2107221072
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
2107321073
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
21074
+ Bool hasBeenDuped:1; /* This cursor was source or target of OP_OpenDup */
2107421075
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
2107521076
Btree *pBtx; /* Separate file holding temporary table */
2107621077
i64 seqCount; /* Sequence counter */
2107721078
u32 *aAltMap; /* Mapping from table to index column numbers */
2107821079
@@ -40218,11 +40219,12 @@
4021840219
*/
4021940220
static int unixBackupDir(const char *z, int *pJ){
4022040221
int j = *pJ;
4022140222
int i;
4022240223
if( j<=0 ) return 0;
40223
- for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){}
40224
+ for(i=j-1; i>0 && z[i-1]!='/'; i--){}
40225
+ if( i==0 ) return 0;
4022440226
if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
4022540227
*pJ = i-1;
4022640228
return 1;
4022740229
}
4022840230
@@ -64275,11 +64277,11 @@
6427564277
u8 sharable; /* True if we can share pBt with another db */
6427664278
u8 locked; /* True if db currently has pBt locked */
6427764279
u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */
6427864280
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
6427964281
int nBackup; /* Number of backup operations reading this btree */
64280
- u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
64282
+ u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */
6428164283
Btree *pNext; /* List of other sharable Btrees from the same db */
6428264284
Btree *pPrev; /* Back pointer of the same list */
6428364285
#ifdef SQLITE_DEBUG
6428464286
u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */
6428564287
#endif
@@ -67688,23 +67690,27 @@
6768867690
/*
6768967691
** Close an open database and invalidate all cursors.
6769067692
*/
6769167693
SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
6769267694
BtShared *pBt = p->pBt;
67693
- BtCursor *pCur;
6769467695
6769567696
/* Close all cursors opened via this handle. */
6769667697
assert( sqlite3_mutex_held(p->db->mutex) );
6769767698
sqlite3BtreeEnter(p);
67698
- pCur = pBt->pCursor;
67699
- while( pCur ){
67700
- BtCursor *pTmp = pCur;
67701
- pCur = pCur->pNext;
67702
- if( pTmp->pBtree==p ){
67703
- sqlite3BtreeCloseCursor(pTmp);
67699
+
67700
+ /* Verify that no other cursors have this Btree open */
67701
+#ifdef SQLITE_DEBUG
67702
+ {
67703
+ BtCursor *pCur = pBt->pCursor;
67704
+ while( pCur ){
67705
+ BtCursor *pTmp = pCur;
67706
+ pCur = pCur->pNext;
67707
+ assert( pTmp->pBtree!=p );
67708
+
6770467709
}
6770567710
}
67711
+#endif
6770667712
6770767713
/* Rollback any active transaction and free the handle structure.
6770867714
** The call to sqlite3BtreeRollback() drops any table-locks held by
6770967715
** this handle.
6771067716
*/
@@ -69082,11 +69088,11 @@
6908269088
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
6908369089
if( rc!=SQLITE_OK && bCleanup==0 ){
6908469090
sqlite3BtreeLeave(p);
6908569091
return rc;
6908669092
}
69087
- p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
69093
+ p->iBDataVersion--; /* Compensate for pPager->iDataVersion++; */
6908869094
pBt->inTransaction = TRANS_READ;
6908969095
btreeClearHasContent(pBt);
6909069096
}
6909169097
6909269098
btreeEndTransaction(p);
@@ -69492,11 +69498,18 @@
6949269498
}
6949369499
btreeReleaseAllCursorPages(pCur);
6949469500
unlockBtreeIfUnused(pBt);
6949569501
sqlite3_free(pCur->aOverflow);
6949669502
sqlite3_free(pCur->pKey);
69497
- sqlite3BtreeLeave(pBtree);
69503
+ if( (pBt->openFlags & BTREE_SINGLE) && pBt->pCursor==0 ){
69504
+ /* Since the BtShared is not sharable, there is no need to
69505
+ ** worry about the missing sqlite3BtreeLeave() call here. */
69506
+ assert( pBtree->sharable==0 );
69507
+ sqlite3BtreeClose(pBtree);
69508
+ }else{
69509
+ sqlite3BtreeLeave(pBtree);
69510
+ }
6949869511
pCur->pBtree = 0;
6949969512
}
6950069513
return SQLITE_OK;
6950169514
}
6950269515
@@ -74605,11 +74618,11 @@
7460574618
assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
7460674619
assert( pBt->pPage1 );
7460774620
assert( idx>=0 && idx<=15 );
7460874621
7460974622
if( idx==BTREE_DATA_VERSION ){
74610
- *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
74623
+ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iBDataVersion;
7461174624
}else{
7461274625
*pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
7461374626
}
7461474627
7461574628
/* If auto-vacuum is disabled in this build and this is an auto-vacuum
@@ -80833,24 +80846,19 @@
8083380846
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
8083480847
if( pCx==0 ){
8083580848
return;
8083680849
}
8083780850
assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
80851
+ assert( pCx->pBtx==0 || pCx->isEphemeral );
8083880852
switch( pCx->eCurType ){
8083980853
case CURTYPE_SORTER: {
8084080854
sqlite3VdbeSorterClose(p->db, pCx);
8084180855
break;
8084280856
}
8084380857
case CURTYPE_BTREE: {
80844
- if( pCx->isEphemeral ){
80845
- if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
80846
- /* The pCx->pCursor will be close automatically, if it exists, by
80847
- ** the call above. */
80848
- }else{
80849
- assert( pCx->uc.pCursor!=0 );
80850
- sqlite3BtreeCloseCursor(pCx->uc.pCursor);
80851
- }
80858
+ assert( pCx->uc.pCursor!=0 );
80859
+ sqlite3BtreeCloseCursor(pCx->uc.pCursor);
8085280860
break;
8085380861
}
8085480862
#ifndef SQLITE_OMIT_VIRTUALTABLE
8085580863
case CURTYPE_VTAB: {
8085680864
sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
@@ -81930,10 +81938,11 @@
8193081938
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
8193181939
VdbeCursor *p = *pp;
8193281940
assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
8193381941
if( p->deferredMoveto ){
8193481942
u32 iMap;
81943
+ assert( !p->isEphemeral );
8193581944
if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
8193681945
*pp = p->pAltCursor;
8193781946
*piCol = iMap - 1;
8193881947
return SQLITE_OK;
8193981948
}
@@ -86138,15 +86147,10 @@
8613886147
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
8613986148
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
8614086149
8614186150
assert( iCur>=0 && iCur<p->nCursor );
8614286151
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
86143
- /* Before calling sqlite3VdbeFreeCursor(), ensure the isEphemeral flag
86144
- ** is clear. Otherwise, if this is an ephemeral cursor created by
86145
- ** OP_OpenDup, the cursor will not be closed and will still be part
86146
- ** of a BtShared.pCursor list. */
86147
- if( p->apCsr[iCur]->pBtx==0 ) p->apCsr[iCur]->isEphemeral = 0;
8614886152
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
8614986153
p->apCsr[iCur] = 0;
8615086154
}
8615186155
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
8615286156
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
@@ -89828,21 +89832,24 @@
8982889832
VdbeCursor *pOrig; /* The original cursor to be duplicated */
8982989833
VdbeCursor *pCx; /* The new cursor */
8983089834
8983189835
pOrig = p->apCsr[pOp->p2];
8983289836
assert( pOrig );
89833
- assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
89837
+ assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */
8983489838
8983589839
pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
8983689840
if( pCx==0 ) goto no_mem;
8983789841
pCx->nullRow = 1;
8983889842
pCx->isEphemeral = 1;
8983989843
pCx->pKeyInfo = pOrig->pKeyInfo;
8984089844
pCx->isTable = pOrig->isTable;
8984189845
pCx->pgnoRoot = pOrig->pgnoRoot;
8984289846
pCx->isOrdered = pOrig->isOrdered;
89843
- rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
89847
+ pCx->pBtx = pOrig->pBtx;
89848
+ pCx->hasBeenDuped = 1;
89849
+ pOrig->hasBeenDuped = 1;
89850
+ rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
8984489851
pCx->pKeyInfo, pCx->uc.pCursor);
8984589852
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
8984689853
** opened for a database. Since there is already an open cursor when this
8984789854
** opcode is run, the sqlite3BtreeCursor() cannot fail */
8984889855
assert( rc==SQLITE_OK );
@@ -89904,13 +89911,14 @@
8990489911
assert( aMem[pOp->p3].flags & MEM_Null );
8990589912
aMem[pOp->p3].n = 0;
8990689913
aMem[pOp->p3].z = "";
8990789914
}
8990889915
pCx = p->apCsr[pOp->p1];
89909
- if( pCx && ALWAYS(pCx->pBtx) ){
89910
- /* If the ephermeral table is already open, erase all existing content
89911
- ** so that the table is empty again, rather than creating a new table. */
89916
+ if( pCx && !pCx->hasBeenDuped ){
89917
+ /* If the ephermeral table is already open and has no duplicates from
89918
+ ** OP_OpenDup, then erase all existing content so that the table is
89919
+ ** empty again, rather than creating a new table. */
8991289920
assert( pCx->isEphemeral );
8991389921
pCx->seqCount = 0;
8991489922
pCx->cacheStatus = CACHE_STALE;
8991589923
rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
8991689924
}else{
@@ -89920,37 +89928,40 @@
8992089928
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
8992189929
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
8992289930
vfsFlags);
8992389931
if( rc==SQLITE_OK ){
8992489932
rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
89925
- }
89926
- if( rc==SQLITE_OK ){
89927
- /* If a transient index is required, create it by calling
89928
- ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
89929
- ** opening it. If a transient table is required, just use the
89930
- ** automatically created table with root-page 1 (an BLOB_INTKEY table).
89931
- */
89932
- if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
89933
- assert( pOp->p4type==P4_KEYINFO );
89934
- rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
89935
- BTREE_BLOBKEY | pOp->p5);
89936
- if( rc==SQLITE_OK ){
89937
- assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
89938
- assert( pKeyInfo->db==db );
89939
- assert( pKeyInfo->enc==ENC(db) );
89940
- rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
89941
- pKeyInfo, pCx->uc.pCursor);
89942
- }
89943
- pCx->isTable = 0;
89944
- }else{
89945
- pCx->pgnoRoot = SCHEMA_ROOT;
89946
- rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
89947
- 0, pCx->uc.pCursor);
89948
- pCx->isTable = 1;
89949
- }
89950
- }
89951
- pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
89933
+ if( rc==SQLITE_OK ){
89934
+ /* If a transient index is required, create it by calling
89935
+ ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
89936
+ ** opening it. If a transient table is required, just use the
89937
+ ** automatically created table with root-page 1 (an BLOB_INTKEY table).
89938
+ */
89939
+ if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
89940
+ assert( pOp->p4type==P4_KEYINFO );
89941
+ rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
89942
+ BTREE_BLOBKEY | pOp->p5);
89943
+ if( rc==SQLITE_OK ){
89944
+ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
89945
+ assert( pKeyInfo->db==db );
89946
+ assert( pKeyInfo->enc==ENC(db) );
89947
+ rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
89948
+ pKeyInfo, pCx->uc.pCursor);
89949
+ }
89950
+ pCx->isTable = 0;
89951
+ }else{
89952
+ pCx->pgnoRoot = SCHEMA_ROOT;
89953
+ rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
89954
+ 0, pCx->uc.pCursor);
89955
+ pCx->isTable = 1;
89956
+ }
89957
+ }
89958
+ pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
89959
+ if( rc ){
89960
+ sqlite3BtreeClose(pCx->pBtx);
89961
+ }
89962
+ }
8995289963
}
8995389964
if( rc ) goto abort_due_to_error;
8995489965
pCx->nullRow = 1;
8995589966
break;
8995689967
}
@@ -90380,17 +90391,17 @@
9038090391
** row by, perhaps by invoking sqlite3BtreeStep() on the cursor
9038190392
** between 0 and This.P1 times.
9038290393
**
9038390394
** There are three possible outcomes from this opcode:<ol>
9038490395
**
90385
-** <li> If after This.P1 steps, the cursor is still point to a place that
90386
-** is earlier in the btree than the target row,
90387
-** then fall through into the subsquence OP_SeekGE opcode.
90396
+** <li> If after This.P1 steps, the cursor is still pointing to a place that
90397
+** is earlier in the btree than the target row, then fall through
90398
+** into the subsquence OP_SeekGE opcode.
9038890399
**
9038990400
** <li> If the cursor is successfully moved to the target row by 0 or more
9039090401
** sqlite3BtreeNext() calls, then jump to This.P2, which will land just
90391
-** past the OP_IdxGT opcode that follows the OP_SeekGE.
90402
+** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE.
9039290403
**
9039390404
** <li> If the cursor ends up past the target row (indicating the the target
9039490405
** row does not exist in the btree) then jump to SeekOP.P2.
9039590406
** </ol>
9039690407
*/
@@ -90403,11 +90414,12 @@
9040390414
assert( pOp[1].opcode==OP_SeekGE );
9040490415
9040590416
/* pOp->p2 points to the first instruction past the OP_IdxGT that
9040690417
** follows the OP_SeekGE. */
9040790418
assert( pOp->p2>=(int)(pOp-aOp)+2 );
90408
- assert( aOp[pOp->p2-1].opcode==OP_IdxGT );
90419
+ assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
90420
+ testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
9040990421
assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
9041090422
assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
9041190423
assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
9041290424
9041390425
assert( pOp->p1>0 );
@@ -91938,10 +91950,12 @@
9193891950
pTabCur->nullRow = 0;
9193991951
pTabCur->movetoTarget = rowid;
9194091952
pTabCur->deferredMoveto = 1;
9194191953
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
9194291954
pTabCur->aAltMap = pOp->p4.ai;
91955
+ assert( !pC->isEphemeral );
91956
+ assert( !pTabCur->isEphemeral );
9194391957
pTabCur->pAltCursor = pC;
9194491958
}else{
9194591959
pOut = out2Prerelease(p, pOp);
9194691960
pOut->u.i = rowid;
9194791961
}
@@ -115682,11 +115696,15 @@
115682115696
}
115683115697
115684115698
/* Clean up before exiting */
115685115699
exit_create_index:
115686115700
if( pIndex ) sqlite3FreeIndex(db, pIndex);
115687
- if( pTab ){ /* Ensure all REPLACE indexes are at the end of the list */
115701
+ if( pTab ){
115702
+ /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list.
115703
+ ** The list was already ordered when this routine was entered, so at this
115704
+ ** point at most a single index (the newly added index) will be out of
115705
+ ** order. So we have to reorder at most one index. */
115688115706
Index **ppFrom = &pTab->pIndex;
115689115707
Index *pThis;
115690115708
for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
115691115709
Index *pNext;
115692115710
if( pThis->onError!=OE_Replace ) continue;
@@ -115696,10 +115714,20 @@
115696115714
pNext->pNext = pThis;
115697115715
ppFrom = &pNext->pNext;
115698115716
}
115699115717
break;
115700115718
}
115719
+#ifdef SQLITE_DEBUG
115720
+ /* Verify that all REPLACE indexes really are now at the end
115721
+ ** of the index list. In other words, no other index type ever
115722
+ ** comes after a REPLACE index on the list. */
115723
+ for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){
115724
+ assert( pThis->onError!=OE_Replace
115725
+ || pThis->pNext==0
115726
+ || pThis->pNext->onError==OE_Replace );
115727
+ }
115728
+#endif
115701115729
}
115702115730
sqlite3ExprDelete(db, pPIWhere);
115703115731
sqlite3ExprListDelete(db, pList);
115704115732
sqlite3SrcListDelete(db, pTblName);
115705115733
sqlite3DbFree(db, zName);
@@ -123112,11 +123140,13 @@
123112123140
pNx->pUpsertSrc = pTabList;
123113123141
pNx->regData = regData;
123114123142
pNx->iDataCur = iDataCur;
123115123143
pNx->iIdxCur = iIdxCur;
123116123144
if( pNx->pUpsertTarget ){
123117
- sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx);
123145
+ if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
123146
+ goto insert_cleanup;
123147
+ }
123118123148
}
123119123149
pNx = pNx->pNextUpsert;
123120123150
}while( pNx!=0 );
123121123151
}
123122123152
#endif
@@ -124534,11 +124564,11 @@
124534124564
int regData /* Data containing new record */
124535124565
){
124536124566
Vdbe *v = pParse->pVdbe;
124537124567
int r = sqlite3GetTempReg(pParse);
124538124568
assert( !HasRowid(pTab) );
124539
- assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) );
124569
+ assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB );
124540124570
sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
124541124571
sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE);
124542124572
sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
124543124573
sqlite3ReleaseTempReg(pParse, r);
124544124574
}
@@ -133082,11 +133112,11 @@
133082133112
sqlite3HashInit(&ht);
133083133113
if( pEList ){
133084133114
nCol = pEList->nExpr;
133085133115
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
133086133116
testcase( aCol==0 );
133087
- if( nCol>32767 ) nCol = 32767;
133117
+ if( NEVER(nCol>32767) ) nCol = 32767;
133088133118
}else{
133089133119
nCol = 0;
133090133120
aCol = 0;
133091133121
}
133092133122
assert( nCol==(i16)nCol );
@@ -136156,20 +136186,28 @@
136156136186
136157136187
pCte->zCteErr = "circular reference: %s";
136158136188
pSavedWith = pParse->pWith;
136159136189
pParse->pWith = pWith;
136160136190
if( pSel->selFlags & SF_Recursive ){
136191
+ int rc;
136161136192
assert( pRecTerm!=0 );
136162136193
assert( (pRecTerm->selFlags & SF_Recursive)==0 );
136163136194
assert( pRecTerm->pNext!=0 );
136164136195
assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 );
136165136196
assert( pRecTerm->pWith==0 );
136166136197
pRecTerm->pWith = pSel->pWith;
136167
- sqlite3WalkSelect(pWalker, pRecTerm);
136198
+ rc = sqlite3WalkSelect(pWalker, pRecTerm);
136168136199
pRecTerm->pWith = 0;
136200
+ if( rc ){
136201
+ pParse->pWith = pSavedWith;
136202
+ return 2;
136203
+ }
136169136204
}else{
136170
- sqlite3WalkSelect(pWalker, pSel);
136205
+ if( sqlite3WalkSelect(pWalker, pSel) ){
136206
+ pParse->pWith = pSavedWith;
136207
+ return 2;
136208
+ }
136171136209
}
136172136210
pParse->pWith = pWith;
136173136211
136174136212
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
136175136213
pEList = pLeft->pEList;
@@ -137474,11 +137512,13 @@
137474137512
sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
137475137513
}
137476137514
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
137477137515
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
137478137516
}else{
137479
- /* Generate a subroutine that will materialize the view. */
137517
+ /* Materalize the view. If the view is not correlated, generate a
137518
+ ** subroutine to do the materialization so that subsequent uses of
137519
+ ** the same view can reuse the materialization. */
137480137520
int topAddr;
137481137521
int onceAddr = 0;
137482137522
int retAddr;
137483137523
137484137524
testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
@@ -137501,11 +137541,11 @@
137501137541
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
137502137542
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
137503137543
VdbeComment((v, "end %s", pItem->pTab->zName));
137504137544
sqlite3VdbeChangeP1(v, topAddr, retAddr);
137505137545
sqlite3ClearTempRegCache(pParse);
137506
- if( pItem->fg.isCte ){
137546
+ if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
137507137547
CteUse *pCteUse = pItem->u2.pCteUse;
137508137548
pCteUse->addrM9e = pItem->addrFillSub;
137509137549
pCteUse->regRtn = pItem->regReturn;
137510137550
pCteUse->iCur = pItem->iCursor;
137511137551
pCteUse->nRowEst = pSub->nSelectRow;
@@ -162306,11 +162346,11 @@
162306162346
/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
162307162347
#endif
162308162348
#ifdef SQLITE_EBCDIC
162309162349
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
162310162350
/* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28,
162311
-/* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162351
+/* 1x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162312162352
/* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162313162353
/* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162314162354
/* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10,
162315162355
/* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28,
162316162356
/* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6,
@@ -229211,11 +229251,11 @@
229211229251
int nArg, /* Number of args */
229212229252
sqlite3_value **apUnused /* Function arguments */
229213229253
){
229214229254
assert( nArg==0 );
229215229255
UNUSED_PARAM2(nArg, apUnused);
229216
- sqlite3_result_text(pCtx, "fts5: 2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827", -1, SQLITE_TRANSIENT);
229256
+ sqlite3_result_text(pCtx, "fts5: 2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c", -1, SQLITE_TRANSIENT);
229217229257
}
229218229258
229219229259
/*
229220229260
** Return true if zName is the extension on one of the shadow tables used
229221229261
** by this module.
@@ -234137,12 +234177,12 @@
234137234177
}
234138234178
#endif /* SQLITE_CORE */
234139234179
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
234140234180
234141234181
/************** End of stmt.c ************************************************/
234142
-#if __LINE__!=234142
234182
+#if __LINE__!=234182
234143234183
#undef SQLITE_SOURCE_ID
234144
-#define SQLITE_SOURCE_ID "2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50calt2"
234184
+#define SQLITE_SOURCE_ID "2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4alt2"
234145234185
#endif
234146234186
/* Return the source-id for this library */
234147234187
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
234148234188
/************************** End of sqlite3.c ******************************/
234149234189
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.35.2. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -1184,13 +1184,13 @@
1184 **
1185 ** See also: [sqlite3_libversion()],
1186 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1187 ** [sqlite_version()] and [sqlite_source_id()].
1188 */
1189 #define SQLITE_VERSION "3.35.2"
1190 #define SQLITE_VERSION_NUMBER 3035002
1191 #define SQLITE_SOURCE_ID "2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827"
1192
1193 /*
1194 ** CAPI3REF: Run-Time Library Version Numbers
1195 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1196 **
@@ -21069,10 +21069,11 @@
21069 u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
21070 #endif
21071 Bool isEphemeral:1; /* True for an ephemeral table */
21072 Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
21073 Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
 
21074 u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
21075 Btree *pBtx; /* Separate file holding temporary table */
21076 i64 seqCount; /* Sequence counter */
21077 u32 *aAltMap; /* Mapping from table to index column numbers */
21078
@@ -40218,11 +40219,12 @@
40218 */
40219 static int unixBackupDir(const char *z, int *pJ){
40220 int j = *pJ;
40221 int i;
40222 if( j<=0 ) return 0;
40223 for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){}
 
40224 if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
40225 *pJ = i-1;
40226 return 1;
40227 }
40228
@@ -64275,11 +64277,11 @@
64275 u8 sharable; /* True if we can share pBt with another db */
64276 u8 locked; /* True if db currently has pBt locked */
64277 u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */
64278 int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
64279 int nBackup; /* Number of backup operations reading this btree */
64280 u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
64281 Btree *pNext; /* List of other sharable Btrees from the same db */
64282 Btree *pPrev; /* Back pointer of the same list */
64283 #ifdef SQLITE_DEBUG
64284 u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */
64285 #endif
@@ -67688,23 +67690,27 @@
67688 /*
67689 ** Close an open database and invalidate all cursors.
67690 */
67691 SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
67692 BtShared *pBt = p->pBt;
67693 BtCursor *pCur;
67694
67695 /* Close all cursors opened via this handle. */
67696 assert( sqlite3_mutex_held(p->db->mutex) );
67697 sqlite3BtreeEnter(p);
67698 pCur = pBt->pCursor;
67699 while( pCur ){
67700 BtCursor *pTmp = pCur;
67701 pCur = pCur->pNext;
67702 if( pTmp->pBtree==p ){
67703 sqlite3BtreeCloseCursor(pTmp);
 
 
 
 
67704 }
67705 }
 
67706
67707 /* Rollback any active transaction and free the handle structure.
67708 ** The call to sqlite3BtreeRollback() drops any table-locks held by
67709 ** this handle.
67710 */
@@ -69082,11 +69088,11 @@
69082 rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
69083 if( rc!=SQLITE_OK && bCleanup==0 ){
69084 sqlite3BtreeLeave(p);
69085 return rc;
69086 }
69087 p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
69088 pBt->inTransaction = TRANS_READ;
69089 btreeClearHasContent(pBt);
69090 }
69091
69092 btreeEndTransaction(p);
@@ -69492,11 +69498,18 @@
69492 }
69493 btreeReleaseAllCursorPages(pCur);
69494 unlockBtreeIfUnused(pBt);
69495 sqlite3_free(pCur->aOverflow);
69496 sqlite3_free(pCur->pKey);
69497 sqlite3BtreeLeave(pBtree);
 
 
 
 
 
 
 
69498 pCur->pBtree = 0;
69499 }
69500 return SQLITE_OK;
69501 }
69502
@@ -74605,11 +74618,11 @@
74605 assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
74606 assert( pBt->pPage1 );
74607 assert( idx>=0 && idx<=15 );
74608
74609 if( idx==BTREE_DATA_VERSION ){
74610 *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
74611 }else{
74612 *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
74613 }
74614
74615 /* If auto-vacuum is disabled in this build and this is an auto-vacuum
@@ -80833,24 +80846,19 @@
80833 SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
80834 if( pCx==0 ){
80835 return;
80836 }
80837 assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
 
80838 switch( pCx->eCurType ){
80839 case CURTYPE_SORTER: {
80840 sqlite3VdbeSorterClose(p->db, pCx);
80841 break;
80842 }
80843 case CURTYPE_BTREE: {
80844 if( pCx->isEphemeral ){
80845 if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
80846 /* The pCx->pCursor will be close automatically, if it exists, by
80847 ** the call above. */
80848 }else{
80849 assert( pCx->uc.pCursor!=0 );
80850 sqlite3BtreeCloseCursor(pCx->uc.pCursor);
80851 }
80852 break;
80853 }
80854 #ifndef SQLITE_OMIT_VIRTUALTABLE
80855 case CURTYPE_VTAB: {
80856 sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
@@ -81930,10 +81938,11 @@
81930 SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
81931 VdbeCursor *p = *pp;
81932 assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
81933 if( p->deferredMoveto ){
81934 u32 iMap;
 
81935 if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
81936 *pp = p->pAltCursor;
81937 *piCol = iMap - 1;
81938 return SQLITE_OK;
81939 }
@@ -86138,15 +86147,10 @@
86138 ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
86139 (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
86140
86141 assert( iCur>=0 && iCur<p->nCursor );
86142 if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
86143 /* Before calling sqlite3VdbeFreeCursor(), ensure the isEphemeral flag
86144 ** is clear. Otherwise, if this is an ephemeral cursor created by
86145 ** OP_OpenDup, the cursor will not be closed and will still be part
86146 ** of a BtShared.pCursor list. */
86147 if( p->apCsr[iCur]->pBtx==0 ) p->apCsr[iCur]->isEphemeral = 0;
86148 sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
86149 p->apCsr[iCur] = 0;
86150 }
86151 if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
86152 p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
@@ -89828,21 +89832,24 @@
89828 VdbeCursor *pOrig; /* The original cursor to be duplicated */
89829 VdbeCursor *pCx; /* The new cursor */
89830
89831 pOrig = p->apCsr[pOp->p2];
89832 assert( pOrig );
89833 assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
89834
89835 pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
89836 if( pCx==0 ) goto no_mem;
89837 pCx->nullRow = 1;
89838 pCx->isEphemeral = 1;
89839 pCx->pKeyInfo = pOrig->pKeyInfo;
89840 pCx->isTable = pOrig->isTable;
89841 pCx->pgnoRoot = pOrig->pgnoRoot;
89842 pCx->isOrdered = pOrig->isOrdered;
89843 rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
 
 
 
89844 pCx->pKeyInfo, pCx->uc.pCursor);
89845 /* The sqlite3BtreeCursor() routine can only fail for the first cursor
89846 ** opened for a database. Since there is already an open cursor when this
89847 ** opcode is run, the sqlite3BtreeCursor() cannot fail */
89848 assert( rc==SQLITE_OK );
@@ -89904,13 +89911,14 @@
89904 assert( aMem[pOp->p3].flags & MEM_Null );
89905 aMem[pOp->p3].n = 0;
89906 aMem[pOp->p3].z = "";
89907 }
89908 pCx = p->apCsr[pOp->p1];
89909 if( pCx && ALWAYS(pCx->pBtx) ){
89910 /* If the ephermeral table is already open, erase all existing content
89911 ** so that the table is empty again, rather than creating a new table. */
 
89912 assert( pCx->isEphemeral );
89913 pCx->seqCount = 0;
89914 pCx->cacheStatus = CACHE_STALE;
89915 rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
89916 }else{
@@ -89920,37 +89928,40 @@
89920 rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
89921 BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
89922 vfsFlags);
89923 if( rc==SQLITE_OK ){
89924 rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
89925 }
89926 if( rc==SQLITE_OK ){
89927 /* If a transient index is required, create it by calling
89928 ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
89929 ** opening it. If a transient table is required, just use the
89930 ** automatically created table with root-page 1 (an BLOB_INTKEY table).
89931 */
89932 if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
89933 assert( pOp->p4type==P4_KEYINFO );
89934 rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
89935 BTREE_BLOBKEY | pOp->p5);
89936 if( rc==SQLITE_OK ){
89937 assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
89938 assert( pKeyInfo->db==db );
89939 assert( pKeyInfo->enc==ENC(db) );
89940 rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
89941 pKeyInfo, pCx->uc.pCursor);
89942 }
89943 pCx->isTable = 0;
89944 }else{
89945 pCx->pgnoRoot = SCHEMA_ROOT;
89946 rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
89947 0, pCx->uc.pCursor);
89948 pCx->isTable = 1;
89949 }
89950 }
89951 pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
 
 
 
89952 }
89953 if( rc ) goto abort_due_to_error;
89954 pCx->nullRow = 1;
89955 break;
89956 }
@@ -90380,17 +90391,17 @@
90380 ** row by, perhaps by invoking sqlite3BtreeStep() on the cursor
90381 ** between 0 and This.P1 times.
90382 **
90383 ** There are three possible outcomes from this opcode:<ol>
90384 **
90385 ** <li> If after This.P1 steps, the cursor is still point to a place that
90386 ** is earlier in the btree than the target row,
90387 ** then fall through into the subsquence OP_SeekGE opcode.
90388 **
90389 ** <li> If the cursor is successfully moved to the target row by 0 or more
90390 ** sqlite3BtreeNext() calls, then jump to This.P2, which will land just
90391 ** past the OP_IdxGT opcode that follows the OP_SeekGE.
90392 **
90393 ** <li> If the cursor ends up past the target row (indicating the the target
90394 ** row does not exist in the btree) then jump to SeekOP.P2.
90395 ** </ol>
90396 */
@@ -90403,11 +90414,12 @@
90403 assert( pOp[1].opcode==OP_SeekGE );
90404
90405 /* pOp->p2 points to the first instruction past the OP_IdxGT that
90406 ** follows the OP_SeekGE. */
90407 assert( pOp->p2>=(int)(pOp-aOp)+2 );
90408 assert( aOp[pOp->p2-1].opcode==OP_IdxGT );
 
90409 assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
90410 assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
90411 assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
90412
90413 assert( pOp->p1>0 );
@@ -91938,10 +91950,12 @@
91938 pTabCur->nullRow = 0;
91939 pTabCur->movetoTarget = rowid;
91940 pTabCur->deferredMoveto = 1;
91941 assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
91942 pTabCur->aAltMap = pOp->p4.ai;
 
 
91943 pTabCur->pAltCursor = pC;
91944 }else{
91945 pOut = out2Prerelease(p, pOp);
91946 pOut->u.i = rowid;
91947 }
@@ -115682,11 +115696,15 @@
115682 }
115683
115684 /* Clean up before exiting */
115685 exit_create_index:
115686 if( pIndex ) sqlite3FreeIndex(db, pIndex);
115687 if( pTab ){ /* Ensure all REPLACE indexes are at the end of the list */
 
 
 
 
115688 Index **ppFrom = &pTab->pIndex;
115689 Index *pThis;
115690 for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
115691 Index *pNext;
115692 if( pThis->onError!=OE_Replace ) continue;
@@ -115696,10 +115714,20 @@
115696 pNext->pNext = pThis;
115697 ppFrom = &pNext->pNext;
115698 }
115699 break;
115700 }
 
 
 
 
 
 
 
 
 
 
115701 }
115702 sqlite3ExprDelete(db, pPIWhere);
115703 sqlite3ExprListDelete(db, pList);
115704 sqlite3SrcListDelete(db, pTblName);
115705 sqlite3DbFree(db, zName);
@@ -123112,11 +123140,13 @@
123112 pNx->pUpsertSrc = pTabList;
123113 pNx->regData = regData;
123114 pNx->iDataCur = iDataCur;
123115 pNx->iIdxCur = iIdxCur;
123116 if( pNx->pUpsertTarget ){
123117 sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx);
 
 
123118 }
123119 pNx = pNx->pNextUpsert;
123120 }while( pNx!=0 );
123121 }
123122 #endif
@@ -124534,11 +124564,11 @@
124534 int regData /* Data containing new record */
124535 ){
124536 Vdbe *v = pParse->pVdbe;
124537 int r = sqlite3GetTempReg(pParse);
124538 assert( !HasRowid(pTab) );
124539 assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) );
124540 sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
124541 sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE);
124542 sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
124543 sqlite3ReleaseTempReg(pParse, r);
124544 }
@@ -133082,11 +133112,11 @@
133082 sqlite3HashInit(&ht);
133083 if( pEList ){
133084 nCol = pEList->nExpr;
133085 aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
133086 testcase( aCol==0 );
133087 if( nCol>32767 ) nCol = 32767;
133088 }else{
133089 nCol = 0;
133090 aCol = 0;
133091 }
133092 assert( nCol==(i16)nCol );
@@ -136156,20 +136186,28 @@
136156
136157 pCte->zCteErr = "circular reference: %s";
136158 pSavedWith = pParse->pWith;
136159 pParse->pWith = pWith;
136160 if( pSel->selFlags & SF_Recursive ){
 
136161 assert( pRecTerm!=0 );
136162 assert( (pRecTerm->selFlags & SF_Recursive)==0 );
136163 assert( pRecTerm->pNext!=0 );
136164 assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 );
136165 assert( pRecTerm->pWith==0 );
136166 pRecTerm->pWith = pSel->pWith;
136167 sqlite3WalkSelect(pWalker, pRecTerm);
136168 pRecTerm->pWith = 0;
 
 
 
 
136169 }else{
136170 sqlite3WalkSelect(pWalker, pSel);
 
 
 
136171 }
136172 pParse->pWith = pWith;
136173
136174 for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
136175 pEList = pLeft->pEList;
@@ -137474,11 +137512,13 @@
137474 sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
137475 }
137476 sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
137477 pSub->nSelectRow = pPrior->pSelect->nSelectRow;
137478 }else{
137479 /* Generate a subroutine that will materialize the view. */
 
 
137480 int topAddr;
137481 int onceAddr = 0;
137482 int retAddr;
137483
137484 testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
@@ -137501,11 +137541,11 @@
137501 if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
137502 retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
137503 VdbeComment((v, "end %s", pItem->pTab->zName));
137504 sqlite3VdbeChangeP1(v, topAddr, retAddr);
137505 sqlite3ClearTempRegCache(pParse);
137506 if( pItem->fg.isCte ){
137507 CteUse *pCteUse = pItem->u2.pCteUse;
137508 pCteUse->addrM9e = pItem->addrFillSub;
137509 pCteUse->regRtn = pItem->regReturn;
137510 pCteUse->iCur = pItem->iCursor;
137511 pCteUse->nRowEst = pSub->nSelectRow;
@@ -162306,11 +162346,11 @@
162306 /* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
162307 #endif
162308 #ifdef SQLITE_EBCDIC
162309 /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
162310 /* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28,
162311 /* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162312 /* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162313 /* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162314 /* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10,
162315 /* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28,
162316 /* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6,
@@ -229211,11 +229251,11 @@
229211 int nArg, /* Number of args */
229212 sqlite3_value **apUnused /* Function arguments */
229213 ){
229214 assert( nArg==0 );
229215 UNUSED_PARAM2(nArg, apUnused);
229216 sqlite3_result_text(pCtx, "fts5: 2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827", -1, SQLITE_TRANSIENT);
229217 }
229218
229219 /*
229220 ** Return true if zName is the extension on one of the shadow tables used
229221 ** by this module.
@@ -234137,12 +234177,12 @@
234137 }
234138 #endif /* SQLITE_CORE */
234139 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
234140
234141 /************** End of stmt.c ************************************************/
234142 #if __LINE__!=234142
234143 #undef SQLITE_SOURCE_ID
234144 #define SQLITE_SOURCE_ID "2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50calt2"
234145 #endif
234146 /* Return the source-id for this library */
234147 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
234148 /************************** End of sqlite3.c ******************************/
234149
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.35.3. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -1184,13 +1184,13 @@
1184 **
1185 ** See also: [sqlite3_libversion()],
1186 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1187 ** [sqlite_version()] and [sqlite_source_id()].
1188 */
1189 #define SQLITE_VERSION "3.35.3"
1190 #define SQLITE_VERSION_NUMBER 3035003
1191 #define SQLITE_SOURCE_ID "2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c"
1192
1193 /*
1194 ** CAPI3REF: Run-Time Library Version Numbers
1195 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1196 **
@@ -21069,10 +21069,11 @@
21069 u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
21070 #endif
21071 Bool isEphemeral:1; /* True for an ephemeral table */
21072 Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
21073 Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
21074 Bool hasBeenDuped:1; /* This cursor was source or target of OP_OpenDup */
21075 u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
21076 Btree *pBtx; /* Separate file holding temporary table */
21077 i64 seqCount; /* Sequence counter */
21078 u32 *aAltMap; /* Mapping from table to index column numbers */
21079
@@ -40218,11 +40219,12 @@
40219 */
40220 static int unixBackupDir(const char *z, int *pJ){
40221 int j = *pJ;
40222 int i;
40223 if( j<=0 ) return 0;
40224 for(i=j-1; i>0 && z[i-1]!='/'; i--){}
40225 if( i==0 ) return 0;
40226 if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
40227 *pJ = i-1;
40228 return 1;
40229 }
40230
@@ -64275,11 +64277,11 @@
64277 u8 sharable; /* True if we can share pBt with another db */
64278 u8 locked; /* True if db currently has pBt locked */
64279 u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */
64280 int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
64281 int nBackup; /* Number of backup operations reading this btree */
64282 u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */
64283 Btree *pNext; /* List of other sharable Btrees from the same db */
64284 Btree *pPrev; /* Back pointer of the same list */
64285 #ifdef SQLITE_DEBUG
64286 u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */
64287 #endif
@@ -67688,23 +67690,27 @@
67690 /*
67691 ** Close an open database and invalidate all cursors.
67692 */
67693 SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
67694 BtShared *pBt = p->pBt;
 
67695
67696 /* Close all cursors opened via this handle. */
67697 assert( sqlite3_mutex_held(p->db->mutex) );
67698 sqlite3BtreeEnter(p);
67699
67700 /* Verify that no other cursors have this Btree open */
67701 #ifdef SQLITE_DEBUG
67702 {
67703 BtCursor *pCur = pBt->pCursor;
67704 while( pCur ){
67705 BtCursor *pTmp = pCur;
67706 pCur = pCur->pNext;
67707 assert( pTmp->pBtree!=p );
67708
67709 }
67710 }
67711 #endif
67712
67713 /* Rollback any active transaction and free the handle structure.
67714 ** The call to sqlite3BtreeRollback() drops any table-locks held by
67715 ** this handle.
67716 */
@@ -69082,11 +69088,11 @@
69088 rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
69089 if( rc!=SQLITE_OK && bCleanup==0 ){
69090 sqlite3BtreeLeave(p);
69091 return rc;
69092 }
69093 p->iBDataVersion--; /* Compensate for pPager->iDataVersion++; */
69094 pBt->inTransaction = TRANS_READ;
69095 btreeClearHasContent(pBt);
69096 }
69097
69098 btreeEndTransaction(p);
@@ -69492,11 +69498,18 @@
69498 }
69499 btreeReleaseAllCursorPages(pCur);
69500 unlockBtreeIfUnused(pBt);
69501 sqlite3_free(pCur->aOverflow);
69502 sqlite3_free(pCur->pKey);
69503 if( (pBt->openFlags & BTREE_SINGLE) && pBt->pCursor==0 ){
69504 /* Since the BtShared is not sharable, there is no need to
69505 ** worry about the missing sqlite3BtreeLeave() call here. */
69506 assert( pBtree->sharable==0 );
69507 sqlite3BtreeClose(pBtree);
69508 }else{
69509 sqlite3BtreeLeave(pBtree);
69510 }
69511 pCur->pBtree = 0;
69512 }
69513 return SQLITE_OK;
69514 }
69515
@@ -74605,11 +74618,11 @@
74618 assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
74619 assert( pBt->pPage1 );
74620 assert( idx>=0 && idx<=15 );
74621
74622 if( idx==BTREE_DATA_VERSION ){
74623 *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iBDataVersion;
74624 }else{
74625 *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
74626 }
74627
74628 /* If auto-vacuum is disabled in this build and this is an auto-vacuum
@@ -80833,24 +80846,19 @@
80846 SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
80847 if( pCx==0 ){
80848 return;
80849 }
80850 assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
80851 assert( pCx->pBtx==0 || pCx->isEphemeral );
80852 switch( pCx->eCurType ){
80853 case CURTYPE_SORTER: {
80854 sqlite3VdbeSorterClose(p->db, pCx);
80855 break;
80856 }
80857 case CURTYPE_BTREE: {
80858 assert( pCx->uc.pCursor!=0 );
80859 sqlite3BtreeCloseCursor(pCx->uc.pCursor);
 
 
 
 
 
 
80860 break;
80861 }
80862 #ifndef SQLITE_OMIT_VIRTUALTABLE
80863 case CURTYPE_VTAB: {
80864 sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
@@ -81930,10 +81938,11 @@
81938 SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
81939 VdbeCursor *p = *pp;
81940 assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
81941 if( p->deferredMoveto ){
81942 u32 iMap;
81943 assert( !p->isEphemeral );
81944 if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
81945 *pp = p->pAltCursor;
81946 *piCol = iMap - 1;
81947 return SQLITE_OK;
81948 }
@@ -86138,15 +86147,10 @@
86147 ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
86148 (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
86149
86150 assert( iCur>=0 && iCur<p->nCursor );
86151 if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
 
 
 
 
 
86152 sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
86153 p->apCsr[iCur] = 0;
86154 }
86155 if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
86156 p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
@@ -89828,21 +89832,24 @@
89832 VdbeCursor *pOrig; /* The original cursor to be duplicated */
89833 VdbeCursor *pCx; /* The new cursor */
89834
89835 pOrig = p->apCsr[pOp->p2];
89836 assert( pOrig );
89837 assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */
89838
89839 pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
89840 if( pCx==0 ) goto no_mem;
89841 pCx->nullRow = 1;
89842 pCx->isEphemeral = 1;
89843 pCx->pKeyInfo = pOrig->pKeyInfo;
89844 pCx->isTable = pOrig->isTable;
89845 pCx->pgnoRoot = pOrig->pgnoRoot;
89846 pCx->isOrdered = pOrig->isOrdered;
89847 pCx->pBtx = pOrig->pBtx;
89848 pCx->hasBeenDuped = 1;
89849 pOrig->hasBeenDuped = 1;
89850 rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
89851 pCx->pKeyInfo, pCx->uc.pCursor);
89852 /* The sqlite3BtreeCursor() routine can only fail for the first cursor
89853 ** opened for a database. Since there is already an open cursor when this
89854 ** opcode is run, the sqlite3BtreeCursor() cannot fail */
89855 assert( rc==SQLITE_OK );
@@ -89904,13 +89911,14 @@
89911 assert( aMem[pOp->p3].flags & MEM_Null );
89912 aMem[pOp->p3].n = 0;
89913 aMem[pOp->p3].z = "";
89914 }
89915 pCx = p->apCsr[pOp->p1];
89916 if( pCx && !pCx->hasBeenDuped ){
89917 /* If the ephermeral table is already open and has no duplicates from
89918 ** OP_OpenDup, then erase all existing content so that the table is
89919 ** empty again, rather than creating a new table. */
89920 assert( pCx->isEphemeral );
89921 pCx->seqCount = 0;
89922 pCx->cacheStatus = CACHE_STALE;
89923 rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
89924 }else{
@@ -89920,37 +89928,40 @@
89928 rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
89929 BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
89930 vfsFlags);
89931 if( rc==SQLITE_OK ){
89932 rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
89933 if( rc==SQLITE_OK ){
89934 /* If a transient index is required, create it by calling
89935 ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
89936 ** opening it. If a transient table is required, just use the
89937 ** automatically created table with root-page 1 (an BLOB_INTKEY table).
89938 */
89939 if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
89940 assert( pOp->p4type==P4_KEYINFO );
89941 rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
89942 BTREE_BLOBKEY | pOp->p5);
89943 if( rc==SQLITE_OK ){
89944 assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
89945 assert( pKeyInfo->db==db );
89946 assert( pKeyInfo->enc==ENC(db) );
89947 rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
89948 pKeyInfo, pCx->uc.pCursor);
89949 }
89950 pCx->isTable = 0;
89951 }else{
89952 pCx->pgnoRoot = SCHEMA_ROOT;
89953 rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
89954 0, pCx->uc.pCursor);
89955 pCx->isTable = 1;
89956 }
89957 }
89958 pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
89959 if( rc ){
89960 sqlite3BtreeClose(pCx->pBtx);
89961 }
89962 }
89963 }
89964 if( rc ) goto abort_due_to_error;
89965 pCx->nullRow = 1;
89966 break;
89967 }
@@ -90380,17 +90391,17 @@
90391 ** row by, perhaps by invoking sqlite3BtreeStep() on the cursor
90392 ** between 0 and This.P1 times.
90393 **
90394 ** There are three possible outcomes from this opcode:<ol>
90395 **
90396 ** <li> If after This.P1 steps, the cursor is still pointing to a place that
90397 ** is earlier in the btree than the target row, then fall through
90398 ** into the subsquence OP_SeekGE opcode.
90399 **
90400 ** <li> If the cursor is successfully moved to the target row by 0 or more
90401 ** sqlite3BtreeNext() calls, then jump to This.P2, which will land just
90402 ** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE.
90403 **
90404 ** <li> If the cursor ends up past the target row (indicating the the target
90405 ** row does not exist in the btree) then jump to SeekOP.P2.
90406 ** </ol>
90407 */
@@ -90403,11 +90414,12 @@
90414 assert( pOp[1].opcode==OP_SeekGE );
90415
90416 /* pOp->p2 points to the first instruction past the OP_IdxGT that
90417 ** follows the OP_SeekGE. */
90418 assert( pOp->p2>=(int)(pOp-aOp)+2 );
90419 assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
90420 testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
90421 assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
90422 assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
90423 assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
90424
90425 assert( pOp->p1>0 );
@@ -91938,10 +91950,12 @@
91950 pTabCur->nullRow = 0;
91951 pTabCur->movetoTarget = rowid;
91952 pTabCur->deferredMoveto = 1;
91953 assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
91954 pTabCur->aAltMap = pOp->p4.ai;
91955 assert( !pC->isEphemeral );
91956 assert( !pTabCur->isEphemeral );
91957 pTabCur->pAltCursor = pC;
91958 }else{
91959 pOut = out2Prerelease(p, pOp);
91960 pOut->u.i = rowid;
91961 }
@@ -115682,11 +115696,15 @@
115696 }
115697
115698 /* Clean up before exiting */
115699 exit_create_index:
115700 if( pIndex ) sqlite3FreeIndex(db, pIndex);
115701 if( pTab ){
115702 /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list.
115703 ** The list was already ordered when this routine was entered, so at this
115704 ** point at most a single index (the newly added index) will be out of
115705 ** order. So we have to reorder at most one index. */
115706 Index **ppFrom = &pTab->pIndex;
115707 Index *pThis;
115708 for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
115709 Index *pNext;
115710 if( pThis->onError!=OE_Replace ) continue;
@@ -115696,10 +115714,20 @@
115714 pNext->pNext = pThis;
115715 ppFrom = &pNext->pNext;
115716 }
115717 break;
115718 }
115719 #ifdef SQLITE_DEBUG
115720 /* Verify that all REPLACE indexes really are now at the end
115721 ** of the index list. In other words, no other index type ever
115722 ** comes after a REPLACE index on the list. */
115723 for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){
115724 assert( pThis->onError!=OE_Replace
115725 || pThis->pNext==0
115726 || pThis->pNext->onError==OE_Replace );
115727 }
115728 #endif
115729 }
115730 sqlite3ExprDelete(db, pPIWhere);
115731 sqlite3ExprListDelete(db, pList);
115732 sqlite3SrcListDelete(db, pTblName);
115733 sqlite3DbFree(db, zName);
@@ -123112,11 +123140,13 @@
123140 pNx->pUpsertSrc = pTabList;
123141 pNx->regData = regData;
123142 pNx->iDataCur = iDataCur;
123143 pNx->iIdxCur = iIdxCur;
123144 if( pNx->pUpsertTarget ){
123145 if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
123146 goto insert_cleanup;
123147 }
123148 }
123149 pNx = pNx->pNextUpsert;
123150 }while( pNx!=0 );
123151 }
123152 #endif
@@ -124534,11 +124564,11 @@
124564 int regData /* Data containing new record */
124565 ){
124566 Vdbe *v = pParse->pVdbe;
124567 int r = sqlite3GetTempReg(pParse);
124568 assert( !HasRowid(pTab) );
124569 assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB );
124570 sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
124571 sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE);
124572 sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
124573 sqlite3ReleaseTempReg(pParse, r);
124574 }
@@ -133082,11 +133112,11 @@
133112 sqlite3HashInit(&ht);
133113 if( pEList ){
133114 nCol = pEList->nExpr;
133115 aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
133116 testcase( aCol==0 );
133117 if( NEVER(nCol>32767) ) nCol = 32767;
133118 }else{
133119 nCol = 0;
133120 aCol = 0;
133121 }
133122 assert( nCol==(i16)nCol );
@@ -136156,20 +136186,28 @@
136186
136187 pCte->zCteErr = "circular reference: %s";
136188 pSavedWith = pParse->pWith;
136189 pParse->pWith = pWith;
136190 if( pSel->selFlags & SF_Recursive ){
136191 int rc;
136192 assert( pRecTerm!=0 );
136193 assert( (pRecTerm->selFlags & SF_Recursive)==0 );
136194 assert( pRecTerm->pNext!=0 );
136195 assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 );
136196 assert( pRecTerm->pWith==0 );
136197 pRecTerm->pWith = pSel->pWith;
136198 rc = sqlite3WalkSelect(pWalker, pRecTerm);
136199 pRecTerm->pWith = 0;
136200 if( rc ){
136201 pParse->pWith = pSavedWith;
136202 return 2;
136203 }
136204 }else{
136205 if( sqlite3WalkSelect(pWalker, pSel) ){
136206 pParse->pWith = pSavedWith;
136207 return 2;
136208 }
136209 }
136210 pParse->pWith = pWith;
136211
136212 for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
136213 pEList = pLeft->pEList;
@@ -137474,11 +137512,13 @@
137512 sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
137513 }
137514 sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
137515 pSub->nSelectRow = pPrior->pSelect->nSelectRow;
137516 }else{
137517 /* Materalize the view. If the view is not correlated, generate a
137518 ** subroutine to do the materialization so that subsequent uses of
137519 ** the same view can reuse the materialization. */
137520 int topAddr;
137521 int onceAddr = 0;
137522 int retAddr;
137523
137524 testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
@@ -137501,11 +137541,11 @@
137541 if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
137542 retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
137543 VdbeComment((v, "end %s", pItem->pTab->zName));
137544 sqlite3VdbeChangeP1(v, topAddr, retAddr);
137545 sqlite3ClearTempRegCache(pParse);
137546 if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
137547 CteUse *pCteUse = pItem->u2.pCteUse;
137548 pCteUse->addrM9e = pItem->addrFillSub;
137549 pCteUse->regRtn = pItem->regReturn;
137550 pCteUse->iCur = pItem->iCursor;
137551 pCteUse->nRowEst = pSub->nSelectRow;
@@ -162306,11 +162346,11 @@
162346 /* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
162347 #endif
162348 #ifdef SQLITE_EBCDIC
162349 /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
162350 /* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28,
162351 /* 1x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162352 /* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162353 /* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
162354 /* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10,
162355 /* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28,
162356 /* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6,
@@ -229211,11 +229251,11 @@
229251 int nArg, /* Number of args */
229252 sqlite3_value **apUnused /* Function arguments */
229253 ){
229254 assert( nArg==0 );
229255 UNUSED_PARAM2(nArg, apUnused);
229256 sqlite3_result_text(pCtx, "fts5: 2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c", -1, SQLITE_TRANSIENT);
229257 }
229258
229259 /*
229260 ** Return true if zName is the extension on one of the shadow tables used
229261 ** by this module.
@@ -234137,12 +234177,12 @@
234177 }
234178 #endif /* SQLITE_CORE */
234179 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
234180
234181 /************** End of stmt.c ************************************************/
234182 #if __LINE__!=234182
234183 #undef SQLITE_SOURCE_ID
234184 #define SQLITE_SOURCE_ID "2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4alt2"
234185 #endif
234186 /* Return the source-id for this library */
234187 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
234188 /************************** End of sqlite3.c ******************************/
234189
+3 -3
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -121,13 +121,13 @@
121121
**
122122
** See also: [sqlite3_libversion()],
123123
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124124
** [sqlite_version()] and [sqlite_source_id()].
125125
*/
126
-#define SQLITE_VERSION "3.35.2"
127
-#define SQLITE_VERSION_NUMBER 3035002
128
-#define SQLITE_SOURCE_ID "2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827"
126
+#define SQLITE_VERSION "3.35.3"
127
+#define SQLITE_VERSION_NUMBER 3035003
128
+#define SQLITE_SOURCE_ID "2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c"
129129
130130
/*
131131
** CAPI3REF: Run-Time Library Version Numbers
132132
** KEYWORDS: sqlite3_version sqlite3_sourceid
133133
**
134134
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -121,13 +121,13 @@
121 **
122 ** See also: [sqlite3_libversion()],
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.35.2"
127 #define SQLITE_VERSION_NUMBER 3035002
128 #define SQLITE_SOURCE_ID "2021-03-17 19:07:21 ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -121,13 +121,13 @@
121 **
122 ** See also: [sqlite3_libversion()],
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.35.3"
127 #define SQLITE_VERSION_NUMBER 3035003
128 #define SQLITE_SOURCE_ID "2021-03-21 18:23:48 6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
+3 -1
--- src/style.c
+++ src/style.c
@@ -212,11 +212,13 @@
212212
va_list ap;
213213
if( zOtherArgs==0 ) zOtherArgs = "";
214214
va_start(ap, zAction);
215215
zLink = vmprintf(zAction, ap);
216216
va_end(ap);
217
- if( g.perm.Hyperlink && !g.javascriptHyperlink ){
217
+ if( fossil_strcmp(zLink,"/register")==0
218
+ || (g.perm.Hyperlink && !g.javascriptHyperlink)
219
+ ){
218220
@ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
219221
}else{
220222
needHrefJs = 1;
221223
@ <form method="POST" data-action='%s(zLink)' action='%R/login' \
222224
@ %s(zOtherArgs)>
223225
--- src/style.c
+++ src/style.c
@@ -212,11 +212,13 @@
212 va_list ap;
213 if( zOtherArgs==0 ) zOtherArgs = "";
214 va_start(ap, zAction);
215 zLink = vmprintf(zAction, ap);
216 va_end(ap);
217 if( g.perm.Hyperlink && !g.javascriptHyperlink ){
 
 
218 @ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
219 }else{
220 needHrefJs = 1;
221 @ <form method="POST" data-action='%s(zLink)' action='%R/login' \
222 @ %s(zOtherArgs)>
223
--- src/style.c
+++ src/style.c
@@ -212,11 +212,13 @@
212 va_list ap;
213 if( zOtherArgs==0 ) zOtherArgs = "";
214 va_start(ap, zAction);
215 zLink = vmprintf(zAction, ap);
216 va_end(ap);
217 if( fossil_strcmp(zLink,"/register")==0
218 || (g.perm.Hyperlink && !g.javascriptHyperlink)
219 ){
220 @ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
221 }else{
222 needHrefJs = 1;
223 @ <form method="POST" data-action='%s(zLink)' action='%R/login' \
224 @ %s(zOtherArgs)>
225
+23 -21
--- src/timeline.c
+++ src/timeline.c
@@ -3037,30 +3037,10 @@
30373037
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
30383038
** means UTC.
30393039
**
30403040
**
30413041
** Options:
3042
-** -n|--limit N If N is positive, output the first N entries. If
3043
-** N is negative, output the first -N lines. If N is
3044
-** zero, no limit. Default is -20 meaning 20 lines.
3045
-** -p|--path PATH Output items affecting PATH only.
3046
-** PATH can be a file or a sub directory.
3047
-** --offset P skip P changes
3048
-** --sql Show the SQL used to generate the timeline
3049
-** -t|--type TYPE Output items from the given types only, such as:
3050
-** ci = file commits only
3051
-** e = technical notes only
3052
-** f = forum posts only
3053
-** t = tickets only
3054
-** w = wiki commits only
3055
-** -v|--verbose Output the list of files changed by each commit
3056
-** and the type of each change (edited, deleted,
3057
-** etc.) after the check-in comment.
3058
-** -W|--width N Width of lines (default is to auto-detect). N must be
3059
-** either greater than 20 or it ust be zero 0 to
3060
-** indicate no limit, resulting in a single line per
3061
-** entry.
30623042
** -F|--format Entry format. Values "oneline", "medium", and "full"
30633043
** get mapped to the full options below. Otherwise a
30643044
** string which can contain these placeholders:
30653045
** %n newline
30663046
** %% a raw %
@@ -3074,12 +3054,34 @@
30743054
** %p phase: zero or more of *CURRENT*, *MERGE*,
30753055
** *FORK*, *UNPUBLISHED*, *LEAF*, *BRANCH*
30763056
** --oneline Show only short hash and comment for each entry
30773057
** --medium Medium-verbose entry formatting
30783058
** --full Extra verbose entry formatting
3059
+**
3060
+** -n|--limit N If N is positive, output the first N entries. If
3061
+** N is negative, output the first -N lines. If N is
3062
+** zero, no limit. Default is -20 meaning 20 lines.
3063
+** --offset P skip P changes
3064
+** -p|--path PATH Output items affecting PATH only.
3065
+** PATH can be a file or a sub directory.
30793066
** -R REPO_FILE Specifies the repository db to use. Default is
30803067
** the current checkout's repository.
3068
+
3069
+** --sql Show the SQL used to generate the timeline
3070
+** -t|--type TYPE Output items from the given types only, such as:
3071
+** ci = file commits only
3072
+** e = technical notes only
3073
+** f = forum posts only
3074
+** t = tickets only
3075
+** w = wiki commits only
3076
+** -v|--verbose Output the list of files changed by each commit
3077
+** and the type of each change (edited, deleted,
3078
+** etc.) after the check-in comment.
3079
+** -W|--width N Width of lines (default is to auto-detect). N must be
3080
+** either greater than 20 or it ust be zero 0 to
3081
+** indicate no limit, resulting in a single line per
3082
+** entry.
30813083
*/
30823084
void timeline_cmd(void){
30833085
Stmt q;
30843086
int n, k, width;
30853087
const char *zLimit;
@@ -3154,11 +3156,11 @@
31543156
mode = TIMELINE_MODE_PARENTS;
31553157
}else if( strncmp(g.argv[2],"parents",k)==0 ){
31563158
mode = TIMELINE_MODE_PARENTS;
31573159
}else if(!zType && !zLimit){
31583160
usage("?WHEN? ?CHECKIN|DATETIME? ?-n|--limit #? ?-t|--type TYPE? "
3159
- "?-W|--width WIDTH? ?-p|--path PATH");
3161
+ "?-W|--width WIDTH? ?-p|--path PATH?");
31603162
}
31613163
if( '-' != *g.argv[3] ){
31623164
zOrigin = g.argv[3];
31633165
}else{
31643166
zOrigin = "now";
31653167
--- src/timeline.c
+++ src/timeline.c
@@ -3037,30 +3037,10 @@
3037 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
3038 ** means UTC.
3039 **
3040 **
3041 ** Options:
3042 ** -n|--limit N If N is positive, output the first N entries. If
3043 ** N is negative, output the first -N lines. If N is
3044 ** zero, no limit. Default is -20 meaning 20 lines.
3045 ** -p|--path PATH Output items affecting PATH only.
3046 ** PATH can be a file or a sub directory.
3047 ** --offset P skip P changes
3048 ** --sql Show the SQL used to generate the timeline
3049 ** -t|--type TYPE Output items from the given types only, such as:
3050 ** ci = file commits only
3051 ** e = technical notes only
3052 ** f = forum posts only
3053 ** t = tickets only
3054 ** w = wiki commits only
3055 ** -v|--verbose Output the list of files changed by each commit
3056 ** and the type of each change (edited, deleted,
3057 ** etc.) after the check-in comment.
3058 ** -W|--width N Width of lines (default is to auto-detect). N must be
3059 ** either greater than 20 or it ust be zero 0 to
3060 ** indicate no limit, resulting in a single line per
3061 ** entry.
3062 ** -F|--format Entry format. Values "oneline", "medium", and "full"
3063 ** get mapped to the full options below. Otherwise a
3064 ** string which can contain these placeholders:
3065 ** %n newline
3066 ** %% a raw %
@@ -3074,12 +3054,34 @@
3074 ** %p phase: zero or more of *CURRENT*, *MERGE*,
3075 ** *FORK*, *UNPUBLISHED*, *LEAF*, *BRANCH*
3076 ** --oneline Show only short hash and comment for each entry
3077 ** --medium Medium-verbose entry formatting
3078 ** --full Extra verbose entry formatting
 
 
 
 
 
 
 
3079 ** -R REPO_FILE Specifies the repository db to use. Default is
3080 ** the current checkout's repository.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3081 */
3082 void timeline_cmd(void){
3083 Stmt q;
3084 int n, k, width;
3085 const char *zLimit;
@@ -3154,11 +3156,11 @@
3154 mode = TIMELINE_MODE_PARENTS;
3155 }else if( strncmp(g.argv[2],"parents",k)==0 ){
3156 mode = TIMELINE_MODE_PARENTS;
3157 }else if(!zType && !zLimit){
3158 usage("?WHEN? ?CHECKIN|DATETIME? ?-n|--limit #? ?-t|--type TYPE? "
3159 "?-W|--width WIDTH? ?-p|--path PATH");
3160 }
3161 if( '-' != *g.argv[3] ){
3162 zOrigin = g.argv[3];
3163 }else{
3164 zOrigin = "now";
3165
--- src/timeline.c
+++ src/timeline.c
@@ -3037,30 +3037,10 @@
3037 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
3038 ** means UTC.
3039 **
3040 **
3041 ** Options:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3042 ** -F|--format Entry format. Values "oneline", "medium", and "full"
3043 ** get mapped to the full options below. Otherwise a
3044 ** string which can contain these placeholders:
3045 ** %n newline
3046 ** %% a raw %
@@ -3074,12 +3054,34 @@
3054 ** %p phase: zero or more of *CURRENT*, *MERGE*,
3055 ** *FORK*, *UNPUBLISHED*, *LEAF*, *BRANCH*
3056 ** --oneline Show only short hash and comment for each entry
3057 ** --medium Medium-verbose entry formatting
3058 ** --full Extra verbose entry formatting
3059 **
3060 ** -n|--limit N If N is positive, output the first N entries. If
3061 ** N is negative, output the first -N lines. If N is
3062 ** zero, no limit. Default is -20 meaning 20 lines.
3063 ** --offset P skip P changes
3064 ** -p|--path PATH Output items affecting PATH only.
3065 ** PATH can be a file or a sub directory.
3066 ** -R REPO_FILE Specifies the repository db to use. Default is
3067 ** the current checkout's repository.
3068
3069 ** --sql Show the SQL used to generate the timeline
3070 ** -t|--type TYPE Output items from the given types only, such as:
3071 ** ci = file commits only
3072 ** e = technical notes only
3073 ** f = forum posts only
3074 ** t = tickets only
3075 ** w = wiki commits only
3076 ** -v|--verbose Output the list of files changed by each commit
3077 ** and the type of each change (edited, deleted,
3078 ** etc.) after the check-in comment.
3079 ** -W|--width N Width of lines (default is to auto-detect). N must be
3080 ** either greater than 20 or it ust be zero 0 to
3081 ** indicate no limit, resulting in a single line per
3082 ** entry.
3083 */
3084 void timeline_cmd(void){
3085 Stmt q;
3086 int n, k, width;
3087 const char *zLimit;
@@ -3154,11 +3156,11 @@
3156 mode = TIMELINE_MODE_PARENTS;
3157 }else if( strncmp(g.argv[2],"parents",k)==0 ){
3158 mode = TIMELINE_MODE_PARENTS;
3159 }else if(!zType && !zLimit){
3160 usage("?WHEN? ?CHECKIN|DATETIME? ?-n|--limit #? ?-t|--type TYPE? "
3161 "?-W|--width WIDTH? ?-p|--path PATH?");
3162 }
3163 if( '-' != *g.argv[3] ){
3164 zOrigin = g.argv[3];
3165 }else{
3166 zOrigin = "now";
3167
+71 -19
--- src/wiki.c
+++ src/wiki.c
@@ -1579,35 +1579,87 @@
15791579
** showid Show RID values
15801580
**
15811581
** Show the complete change history for a single wiki page.
15821582
*/
15831583
void whistory_page(void){
1584
+ Stmt q;
15841585
const char *zPageName;
1585
- Blob sql;
1586
- Stmt q;
1586
+ double rNow;
1587
+ int showRid;
15871588
login_check_credentials();
15881589
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
15891590
zPageName = PD("name","");
15901591
style_set_current_feature("wiki");
15911592
style_header("History Of %s", zPageName);
1592
- blob_init(&sql, 0, 0);
1593
- blob_append(&sql, timeline_query_for_www(), -1);
1594
- blob_append_sql(&sql,
1595
- "AND event.objid IN ("
1596
- " SELECT tagxref.srcid"
1597
- " FROM tagxref, tag"
1598
- " WHERE tagxref.tagid=tag.tagid"
1599
- " AND tag.tagname='wiki-%q')"
1600
- " ORDER BY mtime DESC",
1601
- zPageName
1593
+ showRid = P("showid")!=0;
1594
+ db_prepare(&q,
1595
+ "SELECT"
1596
+ " event.mtime,"
1597
+ " blob.uuid,"
1598
+ " coalesce(event.euser,event.user),"
1599
+ " event.objid,"
1600
+ " datetime(event.mtime)"
1601
+ " FROM event, blob, tag, tagxref"
1602
+ " WHERE event.type='w' AND blob.rid=event.objid"
1603
+ " AND tag.tagname='wiki-%q'"
1604
+ " AND tagxref.tagid=tag.tagid AND tagxref.srcid=event.objid"
1605
+ " ORDER BY event.mtime DESC",
1606
+ zPageName
16021607
);
1603
- db_prepare(&q, "%s", blob_sql_text(&sql));
1604
- www_print_timeline(&q,
1605
- TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_REFS,
1606
- 0, 0, 0, 0, 0, 0);
1608
+ @ <h2>History of <a href="%R/wiki?name=%T(zPageName)">%h(zPageName)</a></h2>
1609
+ form_begin( "id='wh-form'", "%R/wdiff" );
1610
+ @ <input id="wh-pid" name="pid" type="radio" hidden />
1611
+ @ <input id="wh-id" name="id" type="hidden" />
1612
+ @ </form>
1613
+ @ <style> .wh-clickable { cursor: pointer; } </style>
1614
+ @ <div class="brlist">
1615
+ @ <table>
1616
+ @ <thead><tr>
1617
+ @ <th>Age</th>
1618
+ @ <th>Hash</th>
1619
+ @ <th><span title="Baseline from which diffs are computed (click to unset)"
1620
+ @ id="wh-cleaner" class="wh-clickable">&#9875;</span></th>
1621
+ @ <th>User<span hidden class="wh-clickable"
1622
+ @ id="wh-collapser">&emsp;&#9842;</span></th>
1623
+ if( showRid ){
1624
+ @ <th>RID</th>
1625
+ }
1626
+ @ <th>&nbsp;</th>
1627
+ @ </tr></thead><tbody>
1628
+ rNow = db_double(0.0, "SELECT julianday('now')");
1629
+ char zAuthor[64]; memset( zAuthor, 0, sizeof(zAuthor) );
1630
+ while( db_step(&q)==SQLITE_ROW ){
1631
+ double rMtime = db_column_double(&q, 0);
1632
+ const char *zUuid = db_column_text(&q, 1);
1633
+ const char *zUser = db_column_text(&q, 2);
1634
+ int wrid = db_column_int(&q, 3);
1635
+ const char *zWhen = db_column_text(&q, 4);
1636
+ /* sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0); */
1637
+ char *zAge = human_readable_age(rNow - rMtime);
1638
+ if( strncmp( zAuthor, zUser, sizeof(zAuthor) - 1 ) == 0 ) {
1639
+ @ <tr class="wh-intermediate" title="%s(zWhen)">
1640
+ }
1641
+ else {
1642
+ strncpy( zAuthor, zUser, sizeof(zAuthor) - 1 );
1643
+ @ <tr class="wh-major" title="%s(zWhen)">
1644
+ }
1645
+ /* @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td> */
1646
+ @ <td>%s(zAge)</td>
1647
+ fossil_free(zAge);
1648
+ @ <td>%z(href("%R/info/%s",zUuid))%S(zUuid)</a></td>
1649
+ @ <td><input disabled type="radio" name="baseline" value="%S(zUuid)"/></td>
1650
+ @ <td>%h(zUser)<span class="wh-iterations" hidden /></td>
1651
+ if( showRid ){
1652
+ @ <td>%z(href("%R/artifact/%S",zUuid))%d(wrid)</a></td>
1653
+ }
1654
+ @ <td>%z(chref("wh-difflink","%R/wdiff?id=%S",zUuid))diff</a></td>
1655
+ @ </tr>
1656
+ }
1657
+ @ </tbody></table></div>
16071658
db_finalize(&q);
1608
- blob_reset(&sql);
1659
+ builtin_request_js("fossil.page.whistory.js");
1660
+ /* style_table_sorter(); */
16091661
style_finish_page();
16101662
}
16111663
16121664
/*
16131665
** WEBPAGE: wdiff
@@ -1642,14 +1694,14 @@
16421694
zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid1);
16431695
pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
16441696
if( pW1==0 ) fossil_redirect_home();
16451697
blob_init(&w1, pW1->zWiki, -1);
16461698
zPid = P("pid");
1647
- if( zPid==0 && pW1->nParent ){
1699
+ if( ( zPid==0 || zPid[0] == 0 ) && pW1->nParent ){
16481700
zPid = pW1->azParent[0];
16491701
}
1650
- if( zPid ){
1702
+ if( zPid && zPid[0] != 0 ){
16511703
char *zDate;
16521704
rid2 = name_to_typed_rid(zPid, "w");
16531705
pW2 = manifest_get(rid2, CFTYPE_WIKI, 0);
16541706
blob_init(&w2, pW2->zWiki, -1);
16551707
@ <h2>Changes to \
16561708
--- src/wiki.c
+++ src/wiki.c
@@ -1579,35 +1579,87 @@
1579 ** showid Show RID values
1580 **
1581 ** Show the complete change history for a single wiki page.
1582 */
1583 void whistory_page(void){
 
1584 const char *zPageName;
1585 Blob sql;
1586 Stmt q;
1587 login_check_credentials();
1588 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1589 zPageName = PD("name","");
1590 style_set_current_feature("wiki");
1591 style_header("History Of %s", zPageName);
1592 blob_init(&sql, 0, 0);
1593 blob_append(&sql, timeline_query_for_www(), -1);
1594 blob_append_sql(&sql,
1595 "AND event.objid IN ("
1596 " SELECT tagxref.srcid"
1597 " FROM tagxref, tag"
1598 " WHERE tagxref.tagid=tag.tagid"
1599 " AND tag.tagname='wiki-%q')"
1600 " ORDER BY mtime DESC",
1601 zPageName
 
 
 
 
1602 );
1603 db_prepare(&q, "%s", blob_sql_text(&sql));
1604 www_print_timeline(&q,
1605 TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_REFS,
1606 0, 0, 0, 0, 0, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1607 db_finalize(&q);
1608 blob_reset(&sql);
 
1609 style_finish_page();
1610 }
1611
1612 /*
1613 ** WEBPAGE: wdiff
@@ -1642,14 +1694,14 @@
1642 zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid1);
1643 pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
1644 if( pW1==0 ) fossil_redirect_home();
1645 blob_init(&w1, pW1->zWiki, -1);
1646 zPid = P("pid");
1647 if( zPid==0 && pW1->nParent ){
1648 zPid = pW1->azParent[0];
1649 }
1650 if( zPid ){
1651 char *zDate;
1652 rid2 = name_to_typed_rid(zPid, "w");
1653 pW2 = manifest_get(rid2, CFTYPE_WIKI, 0);
1654 blob_init(&w2, pW2->zWiki, -1);
1655 @ <h2>Changes to \
1656
--- src/wiki.c
+++ src/wiki.c
@@ -1579,35 +1579,87 @@
1579 ** showid Show RID values
1580 **
1581 ** Show the complete change history for a single wiki page.
1582 */
1583 void whistory_page(void){
1584 Stmt q;
1585 const char *zPageName;
1586 double rNow;
1587 int showRid;
1588 login_check_credentials();
1589 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1590 zPageName = PD("name","");
1591 style_set_current_feature("wiki");
1592 style_header("History Of %s", zPageName);
1593 showRid = P("showid")!=0;
1594 db_prepare(&q,
1595 "SELECT"
1596 " event.mtime,"
1597 " blob.uuid,"
1598 " coalesce(event.euser,event.user),"
1599 " event.objid,"
1600 " datetime(event.mtime)"
1601 " FROM event, blob, tag, tagxref"
1602 " WHERE event.type='w' AND blob.rid=event.objid"
1603 " AND tag.tagname='wiki-%q'"
1604 " AND tagxref.tagid=tag.tagid AND tagxref.srcid=event.objid"
1605 " ORDER BY event.mtime DESC",
1606 zPageName
1607 );
1608 @ <h2>History of <a href="%R/wiki?name=%T(zPageName)">%h(zPageName)</a></h2>
1609 form_begin( "id='wh-form'", "%R/wdiff" );
1610 @ <input id="wh-pid" name="pid" type="radio" hidden />
1611 @ <input id="wh-id" name="id" type="hidden" />
1612 @ </form>
1613 @ <style> .wh-clickable { cursor: pointer; } </style>
1614 @ <div class="brlist">
1615 @ <table>
1616 @ <thead><tr>
1617 @ <th>Age</th>
1618 @ <th>Hash</th>
1619 @ <th><span title="Baseline from which diffs are computed (click to unset)"
1620 @ id="wh-cleaner" class="wh-clickable">&#9875;</span></th>
1621 @ <th>User<span hidden class="wh-clickable"
1622 @ id="wh-collapser">&emsp;&#9842;</span></th>
1623 if( showRid ){
1624 @ <th>RID</th>
1625 }
1626 @ <th>&nbsp;</th>
1627 @ </tr></thead><tbody>
1628 rNow = db_double(0.0, "SELECT julianday('now')");
1629 char zAuthor[64]; memset( zAuthor, 0, sizeof(zAuthor) );
1630 while( db_step(&q)==SQLITE_ROW ){
1631 double rMtime = db_column_double(&q, 0);
1632 const char *zUuid = db_column_text(&q, 1);
1633 const char *zUser = db_column_text(&q, 2);
1634 int wrid = db_column_int(&q, 3);
1635 const char *zWhen = db_column_text(&q, 4);
1636 /* sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0); */
1637 char *zAge = human_readable_age(rNow - rMtime);
1638 if( strncmp( zAuthor, zUser, sizeof(zAuthor) - 1 ) == 0 ) {
1639 @ <tr class="wh-intermediate" title="%s(zWhen)">
1640 }
1641 else {
1642 strncpy( zAuthor, zUser, sizeof(zAuthor) - 1 );
1643 @ <tr class="wh-major" title="%s(zWhen)">
1644 }
1645 /* @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td> */
1646 @ <td>%s(zAge)</td>
1647 fossil_free(zAge);
1648 @ <td>%z(href("%R/info/%s",zUuid))%S(zUuid)</a></td>
1649 @ <td><input disabled type="radio" name="baseline" value="%S(zUuid)"/></td>
1650 @ <td>%h(zUser)<span class="wh-iterations" hidden /></td>
1651 if( showRid ){
1652 @ <td>%z(href("%R/artifact/%S",zUuid))%d(wrid)</a></td>
1653 }
1654 @ <td>%z(chref("wh-difflink","%R/wdiff?id=%S",zUuid))diff</a></td>
1655 @ </tr>
1656 }
1657 @ </tbody></table></div>
1658 db_finalize(&q);
1659 builtin_request_js("fossil.page.whistory.js");
1660 /* style_table_sorter(); */
1661 style_finish_page();
1662 }
1663
1664 /*
1665 ** WEBPAGE: wdiff
@@ -1642,14 +1694,14 @@
1694 zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid1);
1695 pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
1696 if( pW1==0 ) fossil_redirect_home();
1697 blob_init(&w1, pW1->zWiki, -1);
1698 zPid = P("pid");
1699 if( ( zPid==0 || zPid[0] == 0 ) && pW1->nParent ){
1700 zPid = pW1->azParent[0];
1701 }
1702 if( zPid && zPid[0] != 0 ){
1703 char *zDate;
1704 rid2 = name_to_typed_rid(zPid, "w");
1705 pW2 = manifest_get(rid2, CFTYPE_WIKI, 0);
1706 blob_init(&w2, pW2->zWiki, -1);
1707 @ <h2>Changes to \
1708

Keyboard Shortcuts

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