Fossil SCM

Merged trunk changes in

wyoung 2020-05-27 16:02 artifact-view-links merge
Commit 32f391f65530a4f96da8f42c4d1740e2558d3ce959f9770f33630a4346ce1aa3
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.11
1
+2.12
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.11
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.12
2
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -17,17 +17,18 @@
1717
html "<a href='$home$url' class='active $cls'>$name</a>\n"
1818
} else {
1919
html "<a href='$home$url' class='$cls'>$name</a>\n"
2020
}
2121
}
22
-html "<a id='hbbtn' href='$home/sitemap'>&#9776;</a>"
22
+html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
2323
menulink $index_page Home {}
2424
if {[anycap jor]} {
2525
menulink /timeline Timeline {}
2626
}
2727
if {[hascap oh]} {
28
- menulink /dir?ci=tip Files desktoponly
28
+ if {![info exists current_checkin]} {set current_checkin tip}
29
+ menulink /dir?ci=$current_checkin Files desktoponly
2930
}
3031
if {[hascap o]} {
3132
menulink /brlist Branches desktoponly
3233
menulink /taglist Tags wideonly
3334
}
3435
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -17,17 +17,18 @@
17 html "<a href='$home$url' class='active $cls'>$name</a>\n"
18 } else {
19 html "<a href='$home$url' class='$cls'>$name</a>\n"
20 }
21 }
22 html "<a id='hbbtn' href='$home/sitemap'>&#9776;</a>"
23 menulink $index_page Home {}
24 if {[anycap jor]} {
25 menulink /timeline Timeline {}
26 }
27 if {[hascap oh]} {
28 menulink /dir?ci=tip Files desktoponly
 
29 }
30 if {[hascap o]} {
31 menulink /brlist Branches desktoponly
32 menulink /taglist Tags wideonly
33 }
34
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -17,17 +17,18 @@
17 html "<a href='$home$url' class='active $cls'>$name</a>\n"
18 } else {
19 html "<a href='$home$url' class='$cls'>$name</a>\n"
20 }
21 }
22 html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>"
23 menulink $index_page Home {}
24 if {[anycap jor]} {
25 menulink /timeline Timeline {}
26 }
27 if {[hascap oh]} {
28 if {![info exists current_checkin]} {set current_checkin tip}
29 menulink /dir?ci=$current_checkin Files desktoponly
30 }
31 if {[hascap o]} {
32 menulink /brlist Branches desktoponly
33 menulink /taglist Tags wideonly
34 }
35
--- src/allrepo.c
+++ src/allrepo.c
@@ -283,11 +283,13 @@
283283
}else if( strncmp(zCmd, "sync", n)==0 ){
284284
zCmd = "sync -autourl -R";
285285
collect_argument(&extra, "verbose","v");
286286
collect_argument(&extra, "unversioned","u");
287287
}else if( strncmp(zCmd, "test-integrity", n)==0 ){
288
+ collect_argument(&extra, "db-only", "d");
288289
collect_argument(&extra, "parse", 0);
290
+ collect_argument(&extra, "quick", "q");
289291
zCmd = "test-integrity";
290292
}else if( strncmp(zCmd, "test-orphans", n)==0 ){
291293
zCmd = "test-orphans -R";
292294
}else if( strncmp(zCmd, "test-missing", n)==0 ){
293295
zCmd = "test-missing -q -R";
294296
--- src/allrepo.c
+++ src/allrepo.c
@@ -283,11 +283,13 @@
283 }else if( strncmp(zCmd, "sync", n)==0 ){
284 zCmd = "sync -autourl -R";
285 collect_argument(&extra, "verbose","v");
286 collect_argument(&extra, "unversioned","u");
287 }else if( strncmp(zCmd, "test-integrity", n)==0 ){
 
288 collect_argument(&extra, "parse", 0);
 
289 zCmd = "test-integrity";
290 }else if( strncmp(zCmd, "test-orphans", n)==0 ){
291 zCmd = "test-orphans -R";
292 }else if( strncmp(zCmd, "test-missing", n)==0 ){
293 zCmd = "test-missing -q -R";
294
--- src/allrepo.c
+++ src/allrepo.c
@@ -283,11 +283,13 @@
283 }else if( strncmp(zCmd, "sync", n)==0 ){
284 zCmd = "sync -autourl -R";
285 collect_argument(&extra, "verbose","v");
286 collect_argument(&extra, "unversioned","u");
287 }else if( strncmp(zCmd, "test-integrity", n)==0 ){
288 collect_argument(&extra, "db-only", "d");
289 collect_argument(&extra, "parse", 0);
290 collect_argument(&extra, "quick", "q");
291 zCmd = "test-integrity";
292 }else if( strncmp(zCmd, "test-orphans", n)==0 ){
293 zCmd = "test-orphans -R";
294 }else if( strncmp(zCmd, "test-missing", n)==0 ){
295 zCmd = "test-missing -q -R";
296
+14
--- src/branch.c
+++ src/branch.c
@@ -18,10 +18,24 @@
1818
** This file contains code used to create new branches within a repository.
1919
*/
2020
#include "config.h"
2121
#include "branch.h"
2222
#include <assert.h>
23
+
24
+/*
25
+** Return true if zBr is the branch name associated with check-in with
26
+** blob.uuid value of zUuid
27
+*/
28
+int branch_includes_uuid(const char *zBr, const char *zUuid){
29
+ return db_exists(
30
+ "SELECT 1 FROM tagxref, blob"
31
+ " WHERE blob.uuid=%Q AND tagxref.rid=blob.rid"
32
+ " AND tagxref.value=%Q AND tagxref.tagtype>0"
33
+ " AND tagxref.tagid=%d",
34
+ zUuid, zBr, TAG_BRANCH
35
+ );
36
+}
2337
2438
/*
2539
** If RID refers to a check-in, return the name of the branch for that
2640
** check-in.
2741
**
2842
--- src/branch.c
+++ src/branch.c
@@ -18,10 +18,24 @@
18 ** This file contains code used to create new branches within a repository.
19 */
20 #include "config.h"
21 #include "branch.h"
22 #include <assert.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
24 /*
25 ** If RID refers to a check-in, return the name of the branch for that
26 ** check-in.
27 **
28
--- src/branch.c
+++ src/branch.c
@@ -18,10 +18,24 @@
18 ** This file contains code used to create new branches within a repository.
19 */
20 #include "config.h"
21 #include "branch.h"
22 #include <assert.h>
23
24 /*
25 ** Return true if zBr is the branch name associated with check-in with
26 ** blob.uuid value of zUuid
27 */
28 int branch_includes_uuid(const char *zBr, const char *zUuid){
29 return db_exists(
30 "SELECT 1 FROM tagxref, blob"
31 " WHERE blob.uuid=%Q AND tagxref.rid=blob.rid"
32 " AND tagxref.value=%Q AND tagxref.tagtype>0"
33 " AND tagxref.tagid=%d",
34 zUuid, zBr, TAG_BRANCH
35 );
36 }
37
38 /*
39 ** If RID refers to a check-in, return the name of the branch for that
40 ** check-in.
41 **
42
+14
--- src/branch.c
+++ src/branch.c
@@ -18,10 +18,24 @@
1818
** This file contains code used to create new branches within a repository.
1919
*/
2020
#include "config.h"
2121
#include "branch.h"
2222
#include <assert.h>
23
+
24
+/*
25
+** Return true if zBr is the branch name associated with check-in with
26
+** blob.uuid value of zUuid
27
+*/
28
+int branch_includes_uuid(const char *zBr, const char *zUuid){
29
+ return db_exists(
30
+ "SELECT 1 FROM tagxref, blob"
31
+ " WHERE blob.uuid=%Q AND tagxref.rid=blob.rid"
32
+ " AND tagxref.value=%Q AND tagxref.tagtype>0"
33
+ " AND tagxref.tagid=%d",
34
+ zUuid, zBr, TAG_BRANCH
35
+ );
36
+}
2337
2438
/*
2539
** If RID refers to a check-in, return the name of the branch for that
2640
** check-in.
2741
**
2842
--- src/branch.c
+++ src/branch.c
@@ -18,10 +18,24 @@
18 ** This file contains code used to create new branches within a repository.
19 */
20 #include "config.h"
21 #include "branch.h"
22 #include <assert.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
24 /*
25 ** If RID refers to a check-in, return the name of the branch for that
26 ** check-in.
27 **
28
--- src/branch.c
+++ src/branch.c
@@ -18,10 +18,24 @@
18 ** This file contains code used to create new branches within a repository.
19 */
20 #include "config.h"
21 #include "branch.h"
22 #include <assert.h>
23
24 /*
25 ** Return true if zBr is the branch name associated with check-in with
26 ** blob.uuid value of zUuid
27 */
28 int branch_includes_uuid(const char *zBr, const char *zUuid){
29 return db_exists(
30 "SELECT 1 FROM tagxref, blob"
31 " WHERE blob.uuid=%Q AND tagxref.rid=blob.rid"
32 " AND tagxref.value=%Q AND tagxref.tagtype>0"
33 " AND tagxref.tagid=%d",
34 zUuid, zBr, TAG_BRANCH
35 );
36 }
37
38 /*
39 ** If RID refers to a check-in, return the name of the branch for that
40 ** check-in.
41 **
42
+146 -75
--- src/browse.c
+++ src/browse.c
@@ -59,10 +59,18 @@
5959
zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]);
6060
sqlite3_result_text(context, zOut, i-n+1, sqlite3_free);
6161
}
6262
}
6363
64
+/*
65
+** Flag arguments for hyperlinked_path()
66
+*/
67
+#if INTERFACE
68
+# define LINKPATH_FINFO 0x0001 /* Link final term to /finfo */
69
+# define LINKPATH_FILE 0x0002 /* Link final term to /file */
70
+#endif
71
+
6472
/*
6573
** Given a pathname which is a relative path from the root of
6674
** the repository to a file or directory, compute a string which
6775
** is an HTML rendering of that path with hyperlinks on each
6876
** directory component of the path where the hyperlink redirects
@@ -76,29 +84,36 @@
7684
void hyperlinked_path(
7785
const char *zPath, /* Path to render */
7886
Blob *pOut, /* Write into this blob */
7987
const char *zCI, /* check-in name, or NULL */
8088
const char *zURI, /* "dir" or "tree" */
81
- const char *zREx /* Extra query parameters */
89
+ const char *zREx, /* Extra query parameters */
90
+ unsigned int mFlags /* Extra flags */
8291
){
8392
int i, j;
8493
char *zSep = "";
8594
8695
for(i=0; zPath[i]; i=j){
8796
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
88
- if( zPath[j] && g.perm.Hyperlink ){
89
- if( zCI ){
90
- char *zLink = href("%R/%s?name=%#T%s&ci=%!S", zURI, j, zPath, zREx,zCI);
91
- blob_appendf(pOut, "%s%z%#h</a>",
92
- zSep, zLink, j-i, &zPath[i]);
93
- }else{
94
- char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
95
- blob_appendf(pOut, "%s%z%#h</a>",
96
- zSep, zLink, j-i, &zPath[i]);
97
- }
98
- }else{
99
- blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
97
+ if( zPath[j]==0 ){
98
+ if( mFlags & LINKPATH_FILE ){
99
+ zURI = "file";
100
+ }else if( mFlags & LINKPATH_FINFO ){
101
+ zURI = "finfo";
102
+ }else{
103
+ blob_appendf(pOut, "/%h", zPath+i);
104
+ break;
105
+ }
106
+ }
107
+ if( zCI ){
108
+ char *zLink = href("%R/%s?name=%#T%s&ci=%T", zURI, j, zPath, zREx,zCI);
109
+ blob_appendf(pOut, "%s%z%#h</a>",
110
+ zSep, zLink, j-i, &zPath[i]);
111
+ }else{
112
+ char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
113
+ blob_appendf(pOut, "%s%z%#h</a>",
114
+ zSep, zLink, j-i, &zPath[i]);
100115
}
101116
zSep = "/";
102117
while( zPath[j]=='/' ){ j++; }
103118
}
104119
}
@@ -127,27 +142,24 @@
127142
char *zPrefix;
128143
Stmt q;
129144
const char *zCI = P("ci");
130145
int rid = 0;
131146
char *zUuid = 0;
132
- Blob dirname;
133147
Manifest *pM = 0;
134148
const char *zSubdirLink;
135149
int linkTrunk = 1;
136150
int linkTip = 1;
137151
HQuery sURI;
152
+ int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */
153
+ int isBranchCI = 0; /* True if ci= refers to a branch name */
154
+ char *zHeader = 0;
138155
156
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
139157
if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
140158
login_check_credentials();
141159
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
142160
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
143
- style_header("File List");
144
- style_adunit_config(ADUNIT_RIGHT_OK);
145
- sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
146
- pathelementFunc, 0, 0);
147
- url_initialize(&sURI, "dir");
148
- cgi_query_parameters_to_url(&sURI);
149161
150162
/* If the name= parameter is an empty string, make it a NULL pointer */
151163
if( zD && strlen(zD)==0 ){ zD = 0; }
152164
153165
/* If a specific check-in is requested, fetch and parse it. If the
@@ -159,53 +171,80 @@
159171
if( pM ){
160172
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
161173
linkTrunk = trunkRid && rid != trunkRid;
162174
linkTip = rid != symbolic_name_to_rid("tip", "ci");
163175
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
176
+ isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
177
+ isBranchCI = branch_includes_uuid(zCI, zUuid);
178
+ Th_Store("current_checkin", zCI);
164179
}else{
165180
zCI = 0;
166181
}
167182
}
168183
184
+ assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
185
+ if( zD==0 ){
186
+ if( zCI ){
187
+ zHeader = mprintf("Top-level Files of %s", zCI);
188
+ }else{
189
+ zHeader = mprintf("All Top-level Files");
190
+ }
191
+ }else{
192
+ if( zCI ){
193
+ zHeader = mprintf("Files in %s/ of %s", zD, zCI);
194
+ }else{
195
+ zHeader = mprintf("All File in %s/", zD);
196
+ }
197
+ }
198
+ style_header("%s", zHeader);
199
+ fossil_free(zHeader);
200
+ style_adunit_config(ADUNIT_RIGHT_OK);
201
+ sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
202
+ pathelementFunc, 0, 0);
203
+ url_initialize(&sURI, "dir");
204
+ cgi_query_parameters_to_url(&sURI);
205
+
169206
/* Compute the title of the page */
170
- blob_zero(&dirname);
171207
if( zD ){
172
- blob_append(&dirname, "in directory ", -1);
173
- hyperlinked_path(zD, &dirname, zCI, "dir", "");
208
+ Blob dirname;
209
+ blob_init(&dirname, 0, 0);
210
+ hyperlinked_path(zD, &dirname, zCI, "dir", "", 0);
211
+ @ <h2>Files in directory %s(blob_str(&dirname)) \
212
+ blob_reset(&dirname);
174213
zPrefix = mprintf("%s/", zD);
175214
style_submenu_element("Top-Level", "%s",
176215
url_render(&sURI, "name", 0, 0, 0));
177216
}else{
178
- blob_append(&dirname, "in the top-level directory", -1);
217
+ @ <h2>Files in the top-level directory \
179218
zPrefix = "";
180219
}
220
+ if( zCI ){
221
+ if( fossil_strcmp(zCI,"tip")==0 ){
222
+ @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a></h2>
223
+ }else if( isBranchCI ){
224
+ @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a> \
225
+ @ of branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
226
+ }else {
227
+ @ of check-in %z(href("%R/info?name=%T",zCI))%h(zCI)</a></h2>
228
+ }
229
+ zSubdirLink = mprintf("%R/dir?ci=%T&name=%T", zCI, zPrefix);
230
+ if( nD==0 ){
231
+ style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
232
+ }
233
+ }else{
234
+ @ in any check-in</h2>
235
+ zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
236
+ }
181237
if( linkTrunk ){
182238
style_submenu_element("Trunk", "%s",
183239
url_render(&sURI, "ci", "trunk", 0, 0));
184240
}
185241
if( linkTip ){
186242
style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0));
187243
}
188
- if( zCI ){
189
- @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>]
190
- @ %s(blob_str(&dirname))
191
- if( zD ){
192
- @ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
193
- }
194
- @ </h2>
195
- zSubdirLink = mprintf("%R/dir?ci=%!S&name=%T", zUuid, zPrefix);
196
- if( nD==0 ){
197
- style_submenu_element("File Ages", "%R/fileage?name=%!S", zUuid);
198
- }
199
- }else{
200
- @ <h2>The union of all files from all check-ins
201
- @ %s(blob_str(&dirname))
202
- if( zD ){
203
- @ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
204
- }
205
- @ </h2>
206
- zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
244
+ if( zD ){
245
+ style_submenu_element("History","%R/timeline?chng=%T/*", zD);
207246
}
208247
style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
209248
style_submenu_element("Tree-View", "%s",
210249
url_render(&sURI, "type", "tree", 0, 0));
211250
@@ -282,12 +321,11 @@
282321
zFN++;
283322
@ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
284323
}else{
285324
const char *zLink;
286325
if( zCI ){
287
- const char *zUuid = db_column_text(&q, 1);
288
- zLink = href("%R/artifact/%!S",zUuid);
326
+ zLink = href("%R/file?name=%T%T&ci=%T",zPrefix,zFN,zCI);
289327
}else{
290328
zLink = href("%R/finfo?name=%T%T",zPrefix,zFN);
291329
}
292330
@ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li>
293331
}
@@ -612,11 +650,15 @@
612650
HQuery sURI; /* Hyperlink */
613651
int startExpanded; /* True to start out with the tree expanded */
614652
int showDirOnly; /* Show directories only. Omit files */
615653
int nDir = 0; /* Number of directories. Used for ID attributes */
616654
char *zProjectName = db_get("project-name", 0);
655
+ int isSymbolicCI = 0; /* ci= is a symbolic name, not a hash prefix */
656
+ int isBranchCI = 0; /* ci= refers to a branch name */
657
+ char *zHeader = 0;
617658
659
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
618660
if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; }
619661
memset(&sTree, 0, sizeof(sTree));
620662
login_check_credentials();
621663
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
622664
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
@@ -624,14 +666,12 @@
624666
pathelementFunc, 0, 0);
625667
url_initialize(&sURI, "tree");
626668
cgi_query_parameters_to_url(&sURI);
627669
if( PB("nofiles") ){
628670
showDirOnly = 1;
629
- style_header("Folder Hierarchy");
630671
}else{
631672
showDirOnly = 0;
632
- style_header("File Tree");
633673
}
634674
style_adunit_config(ADUNIT_RIGHT_OK);
635675
if( PB("expand") ){
636676
startExpanded = 1;
637677
}else{
@@ -660,37 +700,55 @@
660700
linkTip = rid != symbolic_name_to_rid("tip", "ci");
661701
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
662702
rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
663703
zNow = db_text("", "SELECT datetime(mtime,toLocal())"
664704
" FROM event WHERE objid=%d", rid);
705
+ isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI)) != 0);
706
+ isBranchCI = branch_includes_uuid(zCI, zUuid);
707
+ Th_Store("current_checkin", zCI);
665708
}else{
666709
zCI = 0;
667710
}
668711
}
669712
if( zCI==0 ){
670713
rNow = db_double(0.0, "SELECT max(mtime) FROM event");
671714
zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event");
672715
}
716
+
717
+ assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
718
+ if( zD==0 ){
719
+ if( zCI ){
720
+ zHeader = mprintf("Top-level Files of %s", zCI);
721
+ }else{
722
+ zHeader = mprintf("All Top-level Files");
723
+ }
724
+ }else{
725
+ if( zCI ){
726
+ zHeader = mprintf("Files in %s/ of %s", zD, zCI);
727
+ }else{
728
+ zHeader = mprintf("All File in %s/", zD);
729
+ }
730
+ }
731
+ style_header("%s", zHeader);
732
+ fossil_free(zHeader);
673733
674734
/* Compute the title of the page */
675735
blob_zero(&dirname);
676736
if( zD ){
677737
blob_append(&dirname, "within directory ", -1);
678
- hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
738
+ hyperlinked_path(zD, &dirname, zCI, "tree", zREx, 0);
679739
if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
680740
style_submenu_element("Top-Level", "%s",
681741
url_render(&sURI, "name", 0, 0, 0));
682
- }else{
683
- if( zRE ){
684
- blob_appendf(&dirname, "matching \"%s\"", zRE);
685
- }
742
+ }else if( zRE ){
743
+ blob_appendf(&dirname, "matching \"%s\"", zRE);
686744
}
687745
style_submenu_binary("mtime","Sort By Time","Sort By Filename", 0);
688746
if( zCI ){
689747
style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
690748
if( nD==0 && !showDirOnly ){
691
- style_submenu_element("File Ages", "%R/fileage?name=%s", zUuid);
749
+ style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
692750
}
693751
}
694752
if( linkTrunk ){
695753
style_submenu_element("Trunk", "%s",
696754
url_render(&sURI, "ci", "trunk", 0, 0));
@@ -745,10 +803,11 @@
745803
tree_add_node(&sTree, zName, zUuid, mtime);
746804
nFile++;
747805
}
748806
db_finalize(&q);
749807
}
808
+ style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
750809
751810
if( showDirOnly ){
752811
for(nFile=0, p=sTree.pFirst; p; p=p->pNext){
753812
if( p->pChild!=0 && p->nFullName>nD ) nFile++;
754813
}
@@ -755,18 +814,24 @@
755814
zObjType = "Folders";
756815
}else{
757816
zObjType = "Files";
758817
}
759818
760
- style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
761
-
762
- if( zCI ){
763
- @ <h2>%s(zObjType) from
764
- if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
765
- @ "%h(zCI)"
766
- }
767
- @ [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))
819
+ if( zCI && strcmp(zCI,"tip")==0 ){
820
+ @ <h2>%s(zObjType) in the %z(href("%R/info?name=tip"))latest check-in</a>
821
+ }else if( isBranchCI ){
822
+ @ <h2>%s(zObjType) in the %z(href("%R/info?name=%T",zCI))latest check-in\
823
+ @ </a> for branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a>
824
+ if( blob_size(&dirname) ){
825
+ @ and %s(blob_str(&dirname))</h2>
826
+ }
827
+ }else if( zCI ){
828
+ @ <h2>%s(zObjType) for check-in \
829
+ @ %z(href("%R/info?name=%T",zCI))%h(zCI)</a></h2>
830
+ if( blob_size(&dirname) ){
831
+ @ and %s(blob_str(&dirname))</h2>
832
+ }
768833
}else{
769834
int n = db_int(0, "SELECT count(*) FROM plink");
770835
@ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname))
771836
}
772837
if( useMtime ){
@@ -824,11 +889,11 @@
824889
nDir++;
825890
}else if( !showDirOnly ){
826891
const char *zFileClass = fileext_class(p->zName);
827892
char *zLink;
828893
if( zCI ){
829
- zLink = href("%R/artifact/%!S",p->zUuid);
894
+ zLink = href("%R/file?name=%T&ci=%T",p->zFullName,zCI);
830895
}else{
831896
zLink = href("%R/finfo?name=%T",p->zFullName);
832897
}
833898
@ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline">
834899
@ %z(zLink)%h(p->zName)</a>
@@ -1001,10 +1066,11 @@
10011066
int rid;
10021067
const char *zName;
10031068
const char *zGlob;
10041069
const char *zUuid;
10051070
const char *zNow; /* Time of check-in */
1071
+ int isBranchCI; /* name= is a branch name */
10061072
int showId = PB("showid");
10071073
Stmt q1, q2;
10081074
double baseTime;
10091075
login_check_credentials();
10101076
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
@@ -1014,28 +1080,34 @@
10141080
rid = symbolic_name_to_rid(zName, "ci");
10151081
if( rid==0 ){
10161082
fossil_fatal("not a valid check-in: %s", zName);
10171083
}
10181084
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1085
+ isBranchCI = branch_includes_uuid(zName,zUuid);
10191086
baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid);
10201087
zNow = db_text("", "SELECT datetime(mtime,toLocal()) FROM event"
10211088
" WHERE objid=%d", rid);
10221089
style_submenu_element("Tree-View", "%R/tree?ci=%T&mtime=1&type=tree", zName);
10231090
style_header("File Ages");
10241091
zGlob = P("glob");
10251092
compute_fileage(rid,zGlob);
10261093
db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
10271094
1028
- @ <h1>Files in
1029
- @ %z(href("%R/info/%!S",zUuid))[%S(zUuid)]</a>
1095
+ if( fossil_strcmp(zName,"tip")==0 ){
1096
+ @ <h1>Files in the %z(href("%R/info?name=tip"))latest check-in</a>
1097
+ }else if( isBranchCI ){
1098
+ @ <h1>Files in the %z(href("%R/info?name=%T",zName))latest check-in</a>
1099
+ @ of branch %z(href("%R/timeline?r=%T",zName))%h(zName)</a>
1100
+ }else{
1101
+ @ <h1>Files in check-in %z(href("%R/info?name=%T",zName))%h(zName)</a>
1102
+ }
10301103
if( zGlob && zGlob[0] ){
10311104
@ that match "%h(zGlob)"
10321105
}
10331106
@ ordered by age</h1>
10341107
@
1035
- @ <p>File ages are expressed relative to the
1036
- @ %z(href("%R/ci/%!S",zUuid))[%S(zUuid)]</a> check-in time of
1108
+ @ <p>File ages are expressed relative to the check-in time of
10371109
@ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p>
10381110
@
10391111
@ <div class='fileage'><table>
10401112
@ <tr><th>Age</th><th>Files</th><th>Check-in</th></tr>
10411113
db_prepare(&q1,
@@ -1050,14 +1122,13 @@
10501122
" AND blob.rid=event.objid\n"
10511123
" ORDER BY event.mtime DESC;",
10521124
TAG_BRANCH
10531125
);
10541126
db_prepare(&q2,
1055
- "SELECT blob.uuid, filename.name, fileage.fid\n"
1056
- " FROM fileage, blob, filename\n"
1127
+ "SELECT filename.name, fileage.fid\n"
1128
+ " FROM fileage, filename\n"
10571129
" WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid"
1058
- " AND blob.rid=fileage.fid;"
10591130
);
10601131
while( db_step(&q1)==SQLITE_ROW ){
10611132
double age = baseTime - db_column_double(&q1, 0);
10621133
int mid = db_column_int(&q1, 1);
10631134
const char *zUuid = db_column_text(&q1, 2);
@@ -1067,24 +1138,24 @@
10671138
char *zAge = human_readable_age(age);
10681139
@ <tr><td>%s(zAge)</td>
10691140
@ <td>
10701141
db_bind_int(&q2, ":mid", mid);
10711142
while( db_step(&q2)==SQLITE_ROW ){
1072
- const char *zFUuid = db_column_text(&q2,0);
1073
- const char *zFile = db_column_text(&q2,1);
1074
- int fid = db_column_int(&q2,2);
1143
+ const char *zFile = db_column_text(&q2,0);
1144
+ @ %z(href("%R/file?name=%T&ci=%!S",zFile,zUuid))%h(zFile)</a> \
10751145
if( showId ){
1076
- @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a> (%d(fid))<br />
1146
+ int fid = db_column_int(&q2,1);
1147
+ @ (%d(fid))<br />
10771148
}else{
1078
- @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a><br />
1149
+ @ </a><br />
10791150
}
10801151
}
10811152
db_reset(&q2);
10821153
@ </td>
10831154
@ <td>
10841155
@ %W(zComment)
1085
- @ (check-in:&nbsp;%z(href("%R/ci/%!S",zUuid))%S(zUuid)</a>,
1156
+ @ (check-in:&nbsp;%z(href("%R/info/%!S",zUuid))%S(zUuid)</a>,
10861157
if( showId ){
10871158
@ id: %d(mid)
10881159
}
10891160
@ user:&nbsp;%z(href("%R/timeline?u=%t&c=%!S&nd",zUser,zUuid))%h(zUser)</a>,
10901161
@ branch:&nbsp;\
10911162
--- src/browse.c
+++ src/browse.c
@@ -59,10 +59,18 @@
59 zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]);
60 sqlite3_result_text(context, zOut, i-n+1, sqlite3_free);
61 }
62 }
63
 
 
 
 
 
 
 
 
64 /*
65 ** Given a pathname which is a relative path from the root of
66 ** the repository to a file or directory, compute a string which
67 ** is an HTML rendering of that path with hyperlinks on each
68 ** directory component of the path where the hyperlink redirects
@@ -76,29 +84,36 @@
76 void hyperlinked_path(
77 const char *zPath, /* Path to render */
78 Blob *pOut, /* Write into this blob */
79 const char *zCI, /* check-in name, or NULL */
80 const char *zURI, /* "dir" or "tree" */
81 const char *zREx /* Extra query parameters */
 
82 ){
83 int i, j;
84 char *zSep = "";
85
86 for(i=0; zPath[i]; i=j){
87 for(j=i; zPath[j] && zPath[j]!='/'; j++){}
88 if( zPath[j] && g.perm.Hyperlink ){
89 if( zCI ){
90 char *zLink = href("%R/%s?name=%#T%s&ci=%!S", zURI, j, zPath, zREx,zCI);
91 blob_appendf(pOut, "%s%z%#h</a>",
92 zSep, zLink, j-i, &zPath[i]);
93 }else{
94 char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
95 blob_appendf(pOut, "%s%z%#h</a>",
96 zSep, zLink, j-i, &zPath[i]);
97 }
98 }else{
99 blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
 
 
 
 
 
 
100 }
101 zSep = "/";
102 while( zPath[j]=='/' ){ j++; }
103 }
104 }
@@ -127,27 +142,24 @@
127 char *zPrefix;
128 Stmt q;
129 const char *zCI = P("ci");
130 int rid = 0;
131 char *zUuid = 0;
132 Blob dirname;
133 Manifest *pM = 0;
134 const char *zSubdirLink;
135 int linkTrunk = 1;
136 int linkTip = 1;
137 HQuery sURI;
 
 
 
138
 
139 if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
140 login_check_credentials();
141 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
142 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
143 style_header("File List");
144 style_adunit_config(ADUNIT_RIGHT_OK);
145 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
146 pathelementFunc, 0, 0);
147 url_initialize(&sURI, "dir");
148 cgi_query_parameters_to_url(&sURI);
149
150 /* If the name= parameter is an empty string, make it a NULL pointer */
151 if( zD && strlen(zD)==0 ){ zD = 0; }
152
153 /* If a specific check-in is requested, fetch and parse it. If the
@@ -159,53 +171,80 @@
159 if( pM ){
160 int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
161 linkTrunk = trunkRid && rid != trunkRid;
162 linkTip = rid != symbolic_name_to_rid("tip", "ci");
163 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
 
 
 
164 }else{
165 zCI = 0;
166 }
167 }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169 /* Compute the title of the page */
170 blob_zero(&dirname);
171 if( zD ){
172 blob_append(&dirname, "in directory ", -1);
173 hyperlinked_path(zD, &dirname, zCI, "dir", "");
 
 
 
174 zPrefix = mprintf("%s/", zD);
175 style_submenu_element("Top-Level", "%s",
176 url_render(&sURI, "name", 0, 0, 0));
177 }else{
178 blob_append(&dirname, "in the top-level directory", -1);
179 zPrefix = "";
180 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181 if( linkTrunk ){
182 style_submenu_element("Trunk", "%s",
183 url_render(&sURI, "ci", "trunk", 0, 0));
184 }
185 if( linkTip ){
186 style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0));
187 }
188 if( zCI ){
189 @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>]
190 @ %s(blob_str(&dirname))
191 if( zD ){
192 @ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
193 }
194 @ </h2>
195 zSubdirLink = mprintf("%R/dir?ci=%!S&name=%T", zUuid, zPrefix);
196 if( nD==0 ){
197 style_submenu_element("File Ages", "%R/fileage?name=%!S", zUuid);
198 }
199 }else{
200 @ <h2>The union of all files from all check-ins
201 @ %s(blob_str(&dirname))
202 if( zD ){
203 @ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
204 }
205 @ </h2>
206 zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
207 }
208 style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
209 style_submenu_element("Tree-View", "%s",
210 url_render(&sURI, "type", "tree", 0, 0));
211
@@ -282,12 +321,11 @@
282 zFN++;
283 @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
284 }else{
285 const char *zLink;
286 if( zCI ){
287 const char *zUuid = db_column_text(&q, 1);
288 zLink = href("%R/artifact/%!S",zUuid);
289 }else{
290 zLink = href("%R/finfo?name=%T%T",zPrefix,zFN);
291 }
292 @ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li>
293 }
@@ -612,11 +650,15 @@
612 HQuery sURI; /* Hyperlink */
613 int startExpanded; /* True to start out with the tree expanded */
614 int showDirOnly; /* Show directories only. Omit files */
615 int nDir = 0; /* Number of directories. Used for ID attributes */
616 char *zProjectName = db_get("project-name", 0);
 
 
 
617
 
618 if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; }
619 memset(&sTree, 0, sizeof(sTree));
620 login_check_credentials();
621 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
622 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
@@ -624,14 +666,12 @@
624 pathelementFunc, 0, 0);
625 url_initialize(&sURI, "tree");
626 cgi_query_parameters_to_url(&sURI);
627 if( PB("nofiles") ){
628 showDirOnly = 1;
629 style_header("Folder Hierarchy");
630 }else{
631 showDirOnly = 0;
632 style_header("File Tree");
633 }
634 style_adunit_config(ADUNIT_RIGHT_OK);
635 if( PB("expand") ){
636 startExpanded = 1;
637 }else{
@@ -660,37 +700,55 @@
660 linkTip = rid != symbolic_name_to_rid("tip", "ci");
661 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
662 rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
663 zNow = db_text("", "SELECT datetime(mtime,toLocal())"
664 " FROM event WHERE objid=%d", rid);
 
 
 
665 }else{
666 zCI = 0;
667 }
668 }
669 if( zCI==0 ){
670 rNow = db_double(0.0, "SELECT max(mtime) FROM event");
671 zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event");
672 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
674 /* Compute the title of the page */
675 blob_zero(&dirname);
676 if( zD ){
677 blob_append(&dirname, "within directory ", -1);
678 hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
679 if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
680 style_submenu_element("Top-Level", "%s",
681 url_render(&sURI, "name", 0, 0, 0));
682 }else{
683 if( zRE ){
684 blob_appendf(&dirname, "matching \"%s\"", zRE);
685 }
686 }
687 style_submenu_binary("mtime","Sort By Time","Sort By Filename", 0);
688 if( zCI ){
689 style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
690 if( nD==0 && !showDirOnly ){
691 style_submenu_element("File Ages", "%R/fileage?name=%s", zUuid);
692 }
693 }
694 if( linkTrunk ){
695 style_submenu_element("Trunk", "%s",
696 url_render(&sURI, "ci", "trunk", 0, 0));
@@ -745,10 +803,11 @@
745 tree_add_node(&sTree, zName, zUuid, mtime);
746 nFile++;
747 }
748 db_finalize(&q);
749 }
 
750
751 if( showDirOnly ){
752 for(nFile=0, p=sTree.pFirst; p; p=p->pNext){
753 if( p->pChild!=0 && p->nFullName>nD ) nFile++;
754 }
@@ -755,18 +814,24 @@
755 zObjType = "Folders";
756 }else{
757 zObjType = "Files";
758 }
759
760 style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
761
762 if( zCI ){
763 @ <h2>%s(zObjType) from
764 if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
765 @ "%h(zCI)"
766 }
767 @ [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))
 
 
 
 
 
 
768 }else{
769 int n = db_int(0, "SELECT count(*) FROM plink");
770 @ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname))
771 }
772 if( useMtime ){
@@ -824,11 +889,11 @@
824 nDir++;
825 }else if( !showDirOnly ){
826 const char *zFileClass = fileext_class(p->zName);
827 char *zLink;
828 if( zCI ){
829 zLink = href("%R/artifact/%!S",p->zUuid);
830 }else{
831 zLink = href("%R/finfo?name=%T",p->zFullName);
832 }
833 @ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline">
834 @ %z(zLink)%h(p->zName)</a>
@@ -1001,10 +1066,11 @@
1001 int rid;
1002 const char *zName;
1003 const char *zGlob;
1004 const char *zUuid;
1005 const char *zNow; /* Time of check-in */
 
1006 int showId = PB("showid");
1007 Stmt q1, q2;
1008 double baseTime;
1009 login_check_credentials();
1010 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
@@ -1014,28 +1080,34 @@
1014 rid = symbolic_name_to_rid(zName, "ci");
1015 if( rid==0 ){
1016 fossil_fatal("not a valid check-in: %s", zName);
1017 }
1018 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
 
1019 baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid);
1020 zNow = db_text("", "SELECT datetime(mtime,toLocal()) FROM event"
1021 " WHERE objid=%d", rid);
1022 style_submenu_element("Tree-View", "%R/tree?ci=%T&mtime=1&type=tree", zName);
1023 style_header("File Ages");
1024 zGlob = P("glob");
1025 compute_fileage(rid,zGlob);
1026 db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
1027
1028 @ <h1>Files in
1029 @ %z(href("%R/info/%!S",zUuid))[%S(zUuid)]</a>
 
 
 
 
 
 
1030 if( zGlob && zGlob[0] ){
1031 @ that match "%h(zGlob)"
1032 }
1033 @ ordered by age</h1>
1034 @
1035 @ <p>File ages are expressed relative to the
1036 @ %z(href("%R/ci/%!S",zUuid))[%S(zUuid)]</a> check-in time of
1037 @ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p>
1038 @
1039 @ <div class='fileage'><table>
1040 @ <tr><th>Age</th><th>Files</th><th>Check-in</th></tr>
1041 db_prepare(&q1,
@@ -1050,14 +1122,13 @@
1050 " AND blob.rid=event.objid\n"
1051 " ORDER BY event.mtime DESC;",
1052 TAG_BRANCH
1053 );
1054 db_prepare(&q2,
1055 "SELECT blob.uuid, filename.name, fileage.fid\n"
1056 " FROM fileage, blob, filename\n"
1057 " WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid"
1058 " AND blob.rid=fileage.fid;"
1059 );
1060 while( db_step(&q1)==SQLITE_ROW ){
1061 double age = baseTime - db_column_double(&q1, 0);
1062 int mid = db_column_int(&q1, 1);
1063 const char *zUuid = db_column_text(&q1, 2);
@@ -1067,24 +1138,24 @@
1067 char *zAge = human_readable_age(age);
1068 @ <tr><td>%s(zAge)</td>
1069 @ <td>
1070 db_bind_int(&q2, ":mid", mid);
1071 while( db_step(&q2)==SQLITE_ROW ){
1072 const char *zFUuid = db_column_text(&q2,0);
1073 const char *zFile = db_column_text(&q2,1);
1074 int fid = db_column_int(&q2,2);
1075 if( showId ){
1076 @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a> (%d(fid))<br />
 
1077 }else{
1078 @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a><br />
1079 }
1080 }
1081 db_reset(&q2);
1082 @ </td>
1083 @ <td>
1084 @ %W(zComment)
1085 @ (check-in:&nbsp;%z(href("%R/ci/%!S",zUuid))%S(zUuid)</a>,
1086 if( showId ){
1087 @ id: %d(mid)
1088 }
1089 @ user:&nbsp;%z(href("%R/timeline?u=%t&c=%!S&nd",zUser,zUuid))%h(zUser)</a>,
1090 @ branch:&nbsp;\
1091
--- src/browse.c
+++ src/browse.c
@@ -59,10 +59,18 @@
59 zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]);
60 sqlite3_result_text(context, zOut, i-n+1, sqlite3_free);
61 }
62 }
63
64 /*
65 ** Flag arguments for hyperlinked_path()
66 */
67 #if INTERFACE
68 # define LINKPATH_FINFO 0x0001 /* Link final term to /finfo */
69 # define LINKPATH_FILE 0x0002 /* Link final term to /file */
70 #endif
71
72 /*
73 ** Given a pathname which is a relative path from the root of
74 ** the repository to a file or directory, compute a string which
75 ** is an HTML rendering of that path with hyperlinks on each
76 ** directory component of the path where the hyperlink redirects
@@ -76,29 +84,36 @@
84 void hyperlinked_path(
85 const char *zPath, /* Path to render */
86 Blob *pOut, /* Write into this blob */
87 const char *zCI, /* check-in name, or NULL */
88 const char *zURI, /* "dir" or "tree" */
89 const char *zREx, /* Extra query parameters */
90 unsigned int mFlags /* Extra flags */
91 ){
92 int i, j;
93 char *zSep = "";
94
95 for(i=0; zPath[i]; i=j){
96 for(j=i; zPath[j] && zPath[j]!='/'; j++){}
97 if( zPath[j]==0 ){
98 if( mFlags & LINKPATH_FILE ){
99 zURI = "file";
100 }else if( mFlags & LINKPATH_FINFO ){
101 zURI = "finfo";
102 }else{
103 blob_appendf(pOut, "/%h", zPath+i);
104 break;
105 }
106 }
107 if( zCI ){
108 char *zLink = href("%R/%s?name=%#T%s&ci=%T", zURI, j, zPath, zREx,zCI);
109 blob_appendf(pOut, "%s%z%#h</a>",
110 zSep, zLink, j-i, &zPath[i]);
111 }else{
112 char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
113 blob_appendf(pOut, "%s%z%#h</a>",
114 zSep, zLink, j-i, &zPath[i]);
115 }
116 zSep = "/";
117 while( zPath[j]=='/' ){ j++; }
118 }
119 }
@@ -127,27 +142,24 @@
142 char *zPrefix;
143 Stmt q;
144 const char *zCI = P("ci");
145 int rid = 0;
146 char *zUuid = 0;
 
147 Manifest *pM = 0;
148 const char *zSubdirLink;
149 int linkTrunk = 1;
150 int linkTip = 1;
151 HQuery sURI;
152 int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */
153 int isBranchCI = 0; /* True if ci= refers to a branch name */
154 char *zHeader = 0;
155
156 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
157 if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
158 login_check_credentials();
159 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
160 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
 
 
 
 
 
 
161
162 /* If the name= parameter is an empty string, make it a NULL pointer */
163 if( zD && strlen(zD)==0 ){ zD = 0; }
164
165 /* If a specific check-in is requested, fetch and parse it. If the
@@ -159,53 +171,80 @@
171 if( pM ){
172 int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
173 linkTrunk = trunkRid && rid != trunkRid;
174 linkTip = rid != symbolic_name_to_rid("tip", "ci");
175 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
176 isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
177 isBranchCI = branch_includes_uuid(zCI, zUuid);
178 Th_Store("current_checkin", zCI);
179 }else{
180 zCI = 0;
181 }
182 }
183
184 assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
185 if( zD==0 ){
186 if( zCI ){
187 zHeader = mprintf("Top-level Files of %s", zCI);
188 }else{
189 zHeader = mprintf("All Top-level Files");
190 }
191 }else{
192 if( zCI ){
193 zHeader = mprintf("Files in %s/ of %s", zD, zCI);
194 }else{
195 zHeader = mprintf("All File in %s/", zD);
196 }
197 }
198 style_header("%s", zHeader);
199 fossil_free(zHeader);
200 style_adunit_config(ADUNIT_RIGHT_OK);
201 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
202 pathelementFunc, 0, 0);
203 url_initialize(&sURI, "dir");
204 cgi_query_parameters_to_url(&sURI);
205
206 /* Compute the title of the page */
 
207 if( zD ){
208 Blob dirname;
209 blob_init(&dirname, 0, 0);
210 hyperlinked_path(zD, &dirname, zCI, "dir", "", 0);
211 @ <h2>Files in directory %s(blob_str(&dirname)) \
212 blob_reset(&dirname);
213 zPrefix = mprintf("%s/", zD);
214 style_submenu_element("Top-Level", "%s",
215 url_render(&sURI, "name", 0, 0, 0));
216 }else{
217 @ <h2>Files in the top-level directory \
218 zPrefix = "";
219 }
220 if( zCI ){
221 if( fossil_strcmp(zCI,"tip")==0 ){
222 @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a></h2>
223 }else if( isBranchCI ){
224 @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a> \
225 @ of branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
226 }else {
227 @ of check-in %z(href("%R/info?name=%T",zCI))%h(zCI)</a></h2>
228 }
229 zSubdirLink = mprintf("%R/dir?ci=%T&name=%T", zCI, zPrefix);
230 if( nD==0 ){
231 style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
232 }
233 }else{
234 @ in any check-in</h2>
235 zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
236 }
237 if( linkTrunk ){
238 style_submenu_element("Trunk", "%s",
239 url_render(&sURI, "ci", "trunk", 0, 0));
240 }
241 if( linkTip ){
242 style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0));
243 }
244 if( zD ){
245 style_submenu_element("History","%R/timeline?chng=%T/*", zD);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246 }
247 style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
248 style_submenu_element("Tree-View", "%s",
249 url_render(&sURI, "type", "tree", 0, 0));
250
@@ -282,12 +321,11 @@
321 zFN++;
322 @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
323 }else{
324 const char *zLink;
325 if( zCI ){
326 zLink = href("%R/file?name=%T%T&ci=%T",zPrefix,zFN,zCI);
 
327 }else{
328 zLink = href("%R/finfo?name=%T%T",zPrefix,zFN);
329 }
330 @ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li>
331 }
@@ -612,11 +650,15 @@
650 HQuery sURI; /* Hyperlink */
651 int startExpanded; /* True to start out with the tree expanded */
652 int showDirOnly; /* Show directories only. Omit files */
653 int nDir = 0; /* Number of directories. Used for ID attributes */
654 char *zProjectName = db_get("project-name", 0);
655 int isSymbolicCI = 0; /* ci= is a symbolic name, not a hash prefix */
656 int isBranchCI = 0; /* ci= refers to a branch name */
657 char *zHeader = 0;
658
659 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
660 if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; }
661 memset(&sTree, 0, sizeof(sTree));
662 login_check_credentials();
663 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
664 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
@@ -624,14 +666,12 @@
666 pathelementFunc, 0, 0);
667 url_initialize(&sURI, "tree");
668 cgi_query_parameters_to_url(&sURI);
669 if( PB("nofiles") ){
670 showDirOnly = 1;
 
671 }else{
672 showDirOnly = 0;
 
673 }
674 style_adunit_config(ADUNIT_RIGHT_OK);
675 if( PB("expand") ){
676 startExpanded = 1;
677 }else{
@@ -660,37 +700,55 @@
700 linkTip = rid != symbolic_name_to_rid("tip", "ci");
701 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
702 rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
703 zNow = db_text("", "SELECT datetime(mtime,toLocal())"
704 " FROM event WHERE objid=%d", rid);
705 isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI)) != 0);
706 isBranchCI = branch_includes_uuid(zCI, zUuid);
707 Th_Store("current_checkin", zCI);
708 }else{
709 zCI = 0;
710 }
711 }
712 if( zCI==0 ){
713 rNow = db_double(0.0, "SELECT max(mtime) FROM event");
714 zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event");
715 }
716
717 assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
718 if( zD==0 ){
719 if( zCI ){
720 zHeader = mprintf("Top-level Files of %s", zCI);
721 }else{
722 zHeader = mprintf("All Top-level Files");
723 }
724 }else{
725 if( zCI ){
726 zHeader = mprintf("Files in %s/ of %s", zD, zCI);
727 }else{
728 zHeader = mprintf("All File in %s/", zD);
729 }
730 }
731 style_header("%s", zHeader);
732 fossil_free(zHeader);
733
734 /* Compute the title of the page */
735 blob_zero(&dirname);
736 if( zD ){
737 blob_append(&dirname, "within directory ", -1);
738 hyperlinked_path(zD, &dirname, zCI, "tree", zREx, 0);
739 if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
740 style_submenu_element("Top-Level", "%s",
741 url_render(&sURI, "name", 0, 0, 0));
742 }else if( zRE ){
743 blob_appendf(&dirname, "matching \"%s\"", zRE);
 
 
744 }
745 style_submenu_binary("mtime","Sort By Time","Sort By Filename", 0);
746 if( zCI ){
747 style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
748 if( nD==0 && !showDirOnly ){
749 style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
750 }
751 }
752 if( linkTrunk ){
753 style_submenu_element("Trunk", "%s",
754 url_render(&sURI, "ci", "trunk", 0, 0));
@@ -745,10 +803,11 @@
803 tree_add_node(&sTree, zName, zUuid, mtime);
804 nFile++;
805 }
806 db_finalize(&q);
807 }
808 style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
809
810 if( showDirOnly ){
811 for(nFile=0, p=sTree.pFirst; p; p=p->pNext){
812 if( p->pChild!=0 && p->nFullName>nD ) nFile++;
813 }
@@ -755,18 +814,24 @@
814 zObjType = "Folders";
815 }else{
816 zObjType = "Files";
817 }
818
819 if( zCI && strcmp(zCI,"tip")==0 ){
820 @ <h2>%s(zObjType) in the %z(href("%R/info?name=tip"))latest check-in</a>
821 }else if( isBranchCI ){
822 @ <h2>%s(zObjType) in the %z(href("%R/info?name=%T",zCI))latest check-in\
823 @ </a> for branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a>
824 if( blob_size(&dirname) ){
825 @ and %s(blob_str(&dirname))</h2>
826 }
827 }else if( zCI ){
828 @ <h2>%s(zObjType) for check-in \
829 @ %z(href("%R/info?name=%T",zCI))%h(zCI)</a></h2>
830 if( blob_size(&dirname) ){
831 @ and %s(blob_str(&dirname))</h2>
832 }
833 }else{
834 int n = db_int(0, "SELECT count(*) FROM plink");
835 @ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname))
836 }
837 if( useMtime ){
@@ -824,11 +889,11 @@
889 nDir++;
890 }else if( !showDirOnly ){
891 const char *zFileClass = fileext_class(p->zName);
892 char *zLink;
893 if( zCI ){
894 zLink = href("%R/file?name=%T&ci=%T",p->zFullName,zCI);
895 }else{
896 zLink = href("%R/finfo?name=%T",p->zFullName);
897 }
898 @ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline">
899 @ %z(zLink)%h(p->zName)</a>
@@ -1001,10 +1066,11 @@
1066 int rid;
1067 const char *zName;
1068 const char *zGlob;
1069 const char *zUuid;
1070 const char *zNow; /* Time of check-in */
1071 int isBranchCI; /* name= is a branch name */
1072 int showId = PB("showid");
1073 Stmt q1, q2;
1074 double baseTime;
1075 login_check_credentials();
1076 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
@@ -1014,28 +1080,34 @@
1080 rid = symbolic_name_to_rid(zName, "ci");
1081 if( rid==0 ){
1082 fossil_fatal("not a valid check-in: %s", zName);
1083 }
1084 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1085 isBranchCI = branch_includes_uuid(zName,zUuid);
1086 baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid);
1087 zNow = db_text("", "SELECT datetime(mtime,toLocal()) FROM event"
1088 " WHERE objid=%d", rid);
1089 style_submenu_element("Tree-View", "%R/tree?ci=%T&mtime=1&type=tree", zName);
1090 style_header("File Ages");
1091 zGlob = P("glob");
1092 compute_fileage(rid,zGlob);
1093 db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
1094
1095 if( fossil_strcmp(zName,"tip")==0 ){
1096 @ <h1>Files in the %z(href("%R/info?name=tip"))latest check-in</a>
1097 }else if( isBranchCI ){
1098 @ <h1>Files in the %z(href("%R/info?name=%T",zName))latest check-in</a>
1099 @ of branch %z(href("%R/timeline?r=%T",zName))%h(zName)</a>
1100 }else{
1101 @ <h1>Files in check-in %z(href("%R/info?name=%T",zName))%h(zName)</a>
1102 }
1103 if( zGlob && zGlob[0] ){
1104 @ that match "%h(zGlob)"
1105 }
1106 @ ordered by age</h1>
1107 @
1108 @ <p>File ages are expressed relative to the check-in time of
 
1109 @ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p>
1110 @
1111 @ <div class='fileage'><table>
1112 @ <tr><th>Age</th><th>Files</th><th>Check-in</th></tr>
1113 db_prepare(&q1,
@@ -1050,14 +1122,13 @@
1122 " AND blob.rid=event.objid\n"
1123 " ORDER BY event.mtime DESC;",
1124 TAG_BRANCH
1125 );
1126 db_prepare(&q2,
1127 "SELECT filename.name, fileage.fid\n"
1128 " FROM fileage, filename\n"
1129 " WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid"
 
1130 );
1131 while( db_step(&q1)==SQLITE_ROW ){
1132 double age = baseTime - db_column_double(&q1, 0);
1133 int mid = db_column_int(&q1, 1);
1134 const char *zUuid = db_column_text(&q1, 2);
@@ -1067,24 +1138,24 @@
1138 char *zAge = human_readable_age(age);
1139 @ <tr><td>%s(zAge)</td>
1140 @ <td>
1141 db_bind_int(&q2, ":mid", mid);
1142 while( db_step(&q2)==SQLITE_ROW ){
1143 const char *zFile = db_column_text(&q2,0);
1144 @ %z(href("%R/file?name=%T&ci=%!S",zFile,zUuid))%h(zFile)</a> \
 
1145 if( showId ){
1146 int fid = db_column_int(&q2,1);
1147 @ (%d(fid))<br />
1148 }else{
1149 @ </a><br />
1150 }
1151 }
1152 db_reset(&q2);
1153 @ </td>
1154 @ <td>
1155 @ %W(zComment)
1156 @ (check-in:&nbsp;%z(href("%R/info/%!S",zUuid))%S(zUuid)</a>,
1157 if( showId ){
1158 @ id: %d(mid)
1159 }
1160 @ user:&nbsp;%z(href("%R/timeline?u=%t&c=%!S&nd",zUser,zUuid))%h(zUser)</a>,
1161 @ branch:&nbsp;\
1162
+10 -2
--- src/builtin.c
+++ src/builtin.c
@@ -55,17 +55,25 @@
5555
return (char*)builtin_file(zFilename, 0);
5656
}
5757
5858
/*
5959
** COMMAND: test-builtin-list
60
+**
61
+** If -verbose is used, it outputs a line at the end
62
+** with the total item count and size.
6063
**
6164
** List the names and sizes of all built-in resources.
6265
*/
6366
void test_builtin_list(void){
64
- int i;
67
+ int i, size = 0;;
6568
for(i=0; i<count(aBuiltinFiles); i++){
66
- fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,aBuiltinFiles[i].nByte);
69
+ const int n = aBuiltinFiles[i].nByte;
70
+ fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,n);
71
+ size += n;
72
+ }
73
+ if(find_option("verbose","v",0)!=0){
74
+ fossil_print("%d entries totaling %d bytes\n", i, size);
6775
}
6876
}
6977
7078
/*
7179
** WEBPAGE: test-builtin-files
7280
--- src/builtin.c
+++ src/builtin.c
@@ -55,17 +55,25 @@
55 return (char*)builtin_file(zFilename, 0);
56 }
57
58 /*
59 ** COMMAND: test-builtin-list
 
 
 
60 **
61 ** List the names and sizes of all built-in resources.
62 */
63 void test_builtin_list(void){
64 int i;
65 for(i=0; i<count(aBuiltinFiles); i++){
66 fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,aBuiltinFiles[i].nByte);
 
 
 
 
 
67 }
68 }
69
70 /*
71 ** WEBPAGE: test-builtin-files
72
--- src/builtin.c
+++ src/builtin.c
@@ -55,17 +55,25 @@
55 return (char*)builtin_file(zFilename, 0);
56 }
57
58 /*
59 ** COMMAND: test-builtin-list
60 **
61 ** If -verbose is used, it outputs a line at the end
62 ** with the total item count and size.
63 **
64 ** List the names and sizes of all built-in resources.
65 */
66 void test_builtin_list(void){
67 int i, size = 0;;
68 for(i=0; i<count(aBuiltinFiles); i++){
69 const int n = aBuiltinFiles[i].nByte;
70 fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,n);
71 size += n;
72 }
73 if(find_option("verbose","v",0)!=0){
74 fossil_print("%d entries totaling %d bytes\n", i, size);
75 }
76 }
77
78 /*
79 ** WEBPAGE: test-builtin-files
80
--- src/capabilities.c
+++ src/capabilities.c
@@ -239,11 +239,11 @@
239239
char *zOneLiner; /* One-line summary */
240240
} aCap[] = {
241241
{ 'a', CAPCLASS_SUPER, 0,
242242
"Admin", "Create and delete users" },
243243
{ 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0,
244
- "Attach", "Add attchments to wiki or tickets" },
244
+ "Attach", "Add attachments to wiki or tickets" },
245245
{ 'c', CAPCLASS_TKT, 0,
246246
"Append-Tkt", "Append to existing tickets" },
247247
/*
248248
** d unused since fork from CVSTrac;
249249
** see https://fossil-scm.org/forum/forumpost/43c78f4bef
250250
--- src/capabilities.c
+++ src/capabilities.c
@@ -239,11 +239,11 @@
239 char *zOneLiner; /* One-line summary */
240 } aCap[] = {
241 { 'a', CAPCLASS_SUPER, 0,
242 "Admin", "Create and delete users" },
243 { 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0,
244 "Attach", "Add attchments to wiki or tickets" },
245 { 'c', CAPCLASS_TKT, 0,
246 "Append-Tkt", "Append to existing tickets" },
247 /*
248 ** d unused since fork from CVSTrac;
249 ** see https://fossil-scm.org/forum/forumpost/43c78f4bef
250
--- src/capabilities.c
+++ src/capabilities.c
@@ -239,11 +239,11 @@
239 char *zOneLiner; /* One-line summary */
240 } aCap[] = {
241 { 'a', CAPCLASS_SUPER, 0,
242 "Admin", "Create and delete users" },
243 { 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0,
244 "Attach", "Add attachments to wiki or tickets" },
245 { 'c', CAPCLASS_TKT, 0,
246 "Append-Tkt", "Append to existing tickets" },
247 /*
248 ** d unused since fork from CVSTrac;
249 ** see https://fossil-scm.org/forum/forumpost/43c78f4bef
250
+2 -1
--- src/captcha.c
+++ src/captcha.c
@@ -558,11 +558,12 @@
558558
/*
559559
** Add a "Speak the captcha" button.
560560
*/
561561
void captcha_speakit_button(unsigned int uSeed, const char *zMsg){
562562
if( zMsg==0 ) zMsg = "Speak the text";
563
- @ <input type="button" value="%h(zMsg)" id="speakthetext">
563
+ @ <input aria-label="%h(zMsg)" type="button" value="%h(zMsg)" \
564
+ @ id="speakthetext">
564565
@ <script nonce="%h(style_nonce())">
565566
@ document.getElementById("speakthetext").onclick = function(){
566567
@ var audio = window.fossilAudioCaptcha \
567568
@ || new Audio("%R/captcha-audio/%u(uSeed)");
568569
@ window.fossilAudioCaptcha = audio;
569570
--- src/captcha.c
+++ src/captcha.c
@@ -558,11 +558,12 @@
558 /*
559 ** Add a "Speak the captcha" button.
560 */
561 void captcha_speakit_button(unsigned int uSeed, const char *zMsg){
562 if( zMsg==0 ) zMsg = "Speak the text";
563 @ <input type="button" value="%h(zMsg)" id="speakthetext">
 
564 @ <script nonce="%h(style_nonce())">
565 @ document.getElementById("speakthetext").onclick = function(){
566 @ var audio = window.fossilAudioCaptcha \
567 @ || new Audio("%R/captcha-audio/%u(uSeed)");
568 @ window.fossilAudioCaptcha = audio;
569
--- src/captcha.c
+++ src/captcha.c
@@ -558,11 +558,12 @@
558 /*
559 ** Add a "Speak the captcha" button.
560 */
561 void captcha_speakit_button(unsigned int uSeed, const char *zMsg){
562 if( zMsg==0 ) zMsg = "Speak the text";
563 @ <input aria-label="%h(zMsg)" type="button" value="%h(zMsg)" \
564 @ id="speakthetext">
565 @ <script nonce="%h(style_nonce())">
566 @ document.getElementById("speakthetext").onclick = function(){
567 @ var audio = window.fossilAudioCaptcha \
568 @ || new Audio("%R/captcha-audio/%u(uSeed)");
569 @ window.fossilAudioCaptcha = audio;
570
+32 -10
--- src/cgi.c
+++ src/cgi.c
@@ -174,12 +174,12 @@
174174
}
175175
176176
/*
177177
** Additional information used to form the HTTP reply
178178
*/
179
-static const char *zContentType = "text/html"; /* Content type of the reply */
180
-static const char *zReplyStatus = "OK"; /* Reply status description */
179
+static const char *zContentType = "text/html"; /* Content type of the reply */
180
+static const char *zReplyStatus = "OK"; /* Reply status description */
181181
static int iReplyStatus = 200; /* Reply status code */
182182
static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
183183
static int rangeStart = 0; /* Start of Range: */
184184
static int rangeEnd = 0; /* End of Range: plus 1 */
185185
@@ -293,11 +293,11 @@
293293
}
294294
if( g.isConst ){
295295
/* isConst means that the reply is guaranteed to be invariant, even
296296
** after configuration changes and/or Fossil binary recompiles. */
297297
fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
298
- }else if( etag_tag()!=0 ){
298
+ }else if( etag_tag()[0]!=0 ){
299299
fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
300300
fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
301301
}else{
302302
fprintf(g.httpOut, "Cache-control: no-cache\r\n");
303303
}
@@ -329,17 +329,17 @@
329329
*/
330330
331331
/* Content intended for logged in users should only be cached in
332332
** the browser, not some shared location.
333333
*/
334
- fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
335
- if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
336
- cgi_combine_header_and_body();
337
- blob_compress(&cgiContent[0], &cgiContent[0]);
338
- }
339
-
340334
if( iReplyStatus!=304 ) {
335
+ fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
336
+ if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
337
+ cgi_combine_header_and_body();
338
+ blob_compress(&cgiContent[0], &cgiContent[0]);
339
+ }
340
+
341341
if( is_gzippable() && iReplyStatus!=206 ){
342342
int i;
343343
gzip_begin(0);
344344
for( i=0; i<2; i++ ){
345345
int size = blob_size(&cgiContent[i]);
@@ -359,11 +359,12 @@
359359
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
360360
}else{
361361
total_size = 0;
362362
}
363363
fprintf(g.httpOut, "\r\n");
364
- if( total_size>0 && iReplyStatus != 304
364
+ if( total_size>0
365
+ && iReplyStatus!=304
365366
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
366367
){
367368
int i, size;
368369
for(i=0; i<2; i++){
369370
size = blob_size(&cgiContent[i]);
@@ -432,10 +433,31 @@
432433
va_list ap;
433434
va_start(ap, zFormat);
434435
cgi_redirect(vmprintf(zFormat, ap));
435436
va_end(ap);
436437
}
438
+
439
+/*
440
+** Add a "Content-disposition: attachment; filename=%s" header to the reply.
441
+*/
442
+void cgi_content_disposition_filename(const char *zFilename){
443
+ char *z;
444
+ int i, n;
445
+
446
+ /* 0123456789 123456789 123456789 123456789 123456*/
447
+ z = mprintf("Content-Disposition: attachment; filename=\"%s\";\r\n",
448
+ file_tail(zFilename));
449
+ n = (int)strlen(z);
450
+ for(i=43; i<n-4; i++){
451
+ char c = z[i];
452
+ if( fossil_isalnum(c) ) continue;
453
+ if( c=='.' || c=='-' || c=='/' ) continue;
454
+ z[i] = '_';
455
+ }
456
+ cgi_append_header(z);
457
+ fossil_free(z);
458
+}
437459
438460
/*
439461
** Return the URL for the caller. This is obtained from either the
440462
** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter.
441463
** If neither exist, return zDefault.
442464
--- src/cgi.c
+++ src/cgi.c
@@ -174,12 +174,12 @@
174 }
175
176 /*
177 ** Additional information used to form the HTTP reply
178 */
179 static const char *zContentType = "text/html"; /* Content type of the reply */
180 static const char *zReplyStatus = "OK"; /* Reply status description */
181 static int iReplyStatus = 200; /* Reply status code */
182 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
183 static int rangeStart = 0; /* Start of Range: */
184 static int rangeEnd = 0; /* End of Range: plus 1 */
185
@@ -293,11 +293,11 @@
293 }
294 if( g.isConst ){
295 /* isConst means that the reply is guaranteed to be invariant, even
296 ** after configuration changes and/or Fossil binary recompiles. */
297 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
298 }else if( etag_tag()!=0 ){
299 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
300 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
301 }else{
302 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
303 }
@@ -329,17 +329,17 @@
329 */
330
331 /* Content intended for logged in users should only be cached in
332 ** the browser, not some shared location.
333 */
334 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
335 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
336 cgi_combine_header_and_body();
337 blob_compress(&cgiContent[0], &cgiContent[0]);
338 }
339
340 if( iReplyStatus!=304 ) {
 
 
 
 
 
 
341 if( is_gzippable() && iReplyStatus!=206 ){
342 int i;
343 gzip_begin(0);
344 for( i=0; i<2; i++ ){
345 int size = blob_size(&cgiContent[i]);
@@ -359,11 +359,12 @@
359 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
360 }else{
361 total_size = 0;
362 }
363 fprintf(g.httpOut, "\r\n");
364 if( total_size>0 && iReplyStatus != 304
 
365 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
366 ){
367 int i, size;
368 for(i=0; i<2; i++){
369 size = blob_size(&cgiContent[i]);
@@ -432,10 +433,31 @@
432 va_list ap;
433 va_start(ap, zFormat);
434 cgi_redirect(vmprintf(zFormat, ap));
435 va_end(ap);
436 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
438 /*
439 ** Return the URL for the caller. This is obtained from either the
440 ** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter.
441 ** If neither exist, return zDefault.
442
--- src/cgi.c
+++ src/cgi.c
@@ -174,12 +174,12 @@
174 }
175
176 /*
177 ** Additional information used to form the HTTP reply
178 */
179 static const char *zContentType = "text/html"; /* Content type of the reply */
180 static const char *zReplyStatus = "OK"; /* Reply status description */
181 static int iReplyStatus = 200; /* Reply status code */
182 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
183 static int rangeStart = 0; /* Start of Range: */
184 static int rangeEnd = 0; /* End of Range: plus 1 */
185
@@ -293,11 +293,11 @@
293 }
294 if( g.isConst ){
295 /* isConst means that the reply is guaranteed to be invariant, even
296 ** after configuration changes and/or Fossil binary recompiles. */
297 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
298 }else if( etag_tag()[0]!=0 ){
299 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
300 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
301 }else{
302 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
303 }
@@ -329,17 +329,17 @@
329 */
330
331 /* Content intended for logged in users should only be cached in
332 ** the browser, not some shared location.
333 */
 
 
 
 
 
 
334 if( iReplyStatus!=304 ) {
335 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
336 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
337 cgi_combine_header_and_body();
338 blob_compress(&cgiContent[0], &cgiContent[0]);
339 }
340
341 if( is_gzippable() && iReplyStatus!=206 ){
342 int i;
343 gzip_begin(0);
344 for( i=0; i<2; i++ ){
345 int size = blob_size(&cgiContent[i]);
@@ -359,11 +359,12 @@
359 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
360 }else{
361 total_size = 0;
362 }
363 fprintf(g.httpOut, "\r\n");
364 if( total_size>0
365 && iReplyStatus!=304
366 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
367 ){
368 int i, size;
369 for(i=0; i<2; i++){
370 size = blob_size(&cgiContent[i]);
@@ -432,10 +433,31 @@
433 va_list ap;
434 va_start(ap, zFormat);
435 cgi_redirect(vmprintf(zFormat, ap));
436 va_end(ap);
437 }
438
439 /*
440 ** Add a "Content-disposition: attachment; filename=%s" header to the reply.
441 */
442 void cgi_content_disposition_filename(const char *zFilename){
443 char *z;
444 int i, n;
445
446 /* 0123456789 123456789 123456789 123456789 123456*/
447 z = mprintf("Content-Disposition: attachment; filename=\"%s\";\r\n",
448 file_tail(zFilename));
449 n = (int)strlen(z);
450 for(i=43; i<n-4; i++){
451 char c = z[i];
452 if( fossil_isalnum(c) ) continue;
453 if( c=='.' || c=='-' || c=='/' ) continue;
454 z[i] = '_';
455 }
456 cgi_append_header(z);
457 fossil_free(z);
458 }
459
460 /*
461 ** Return the URL for the caller. This is obtained from either the
462 ** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter.
463 ** If neither exist, return zDefault.
464
--- src/content.c
+++ src/content.c
@@ -944,13 +944,19 @@
944944
** Verify that all content can be extracted from the BLOB table correctly.
945945
** If the BLOB table is correct, then the repository can always be
946946
** successfully reconstructed using "fossil rebuild".
947947
**
948948
** Options:
949
+**
950
+** -d|--db-only Run "PRAGMA integrity_check" on the database only.
951
+** No other validation is performed.
949952
**
950953
** --parse Parse all manifests, wikis, tickets, events, and
951954
** so forth, reporting any errors found.
955
+**
956
+** -q|--quick Run "PRAGMA quick_check" on the database only.
957
+** No other validation is performed.
952958
*/
953959
void test_integrity(void){
954960
Stmt q;
955961
Blob content;
956962
int n1 = 0;
@@ -958,11 +964,25 @@
958964
int nErr = 0;
959965
int total;
960966
int nCA = 0;
961967
int anCA[10];
962968
int bParse = find_option("parse",0,0)!=0;
969
+ int bDbOnly = find_option("db-only","d",0)!=0;
970
+ int bQuick = find_option("quick","q",0)!=0;
963971
db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
972
+ if( bDbOnly || bQuick ){
973
+ const char *zType = bQuick ? "quick" : "integrity";
974
+ char *zRes;
975
+ zRes = db_text(0,"PRAGMA repository.%s_check", zType/*safe-for-%s*/);
976
+ if( fossil_strcmp(zRes,"ok")!=0 ){
977
+ fossil_print("%s_check failed!\n", zType);
978
+ exit(1);
979
+ }else{
980
+ fossil_print("ok\n");
981
+ }
982
+ return;
983
+ }
964984
memset(anCA, 0, sizeof(anCA));
965985
966986
/* Make sure no public artifact is a delta from a private artifact */
967987
db_prepare(&q,
968988
"SELECT "
969989
--- src/content.c
+++ src/content.c
@@ -944,13 +944,19 @@
944 ** Verify that all content can be extracted from the BLOB table correctly.
945 ** If the BLOB table is correct, then the repository can always be
946 ** successfully reconstructed using "fossil rebuild".
947 **
948 ** Options:
 
 
 
949 **
950 ** --parse Parse all manifests, wikis, tickets, events, and
951 ** so forth, reporting any errors found.
 
 
 
952 */
953 void test_integrity(void){
954 Stmt q;
955 Blob content;
956 int n1 = 0;
@@ -958,11 +964,25 @@
958 int nErr = 0;
959 int total;
960 int nCA = 0;
961 int anCA[10];
962 int bParse = find_option("parse",0,0)!=0;
 
 
963 db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
 
 
 
 
 
 
 
 
 
 
 
 
964 memset(anCA, 0, sizeof(anCA));
965
966 /* Make sure no public artifact is a delta from a private artifact */
967 db_prepare(&q,
968 "SELECT "
969
--- src/content.c
+++ src/content.c
@@ -944,13 +944,19 @@
944 ** Verify that all content can be extracted from the BLOB table correctly.
945 ** If the BLOB table is correct, then the repository can always be
946 ** successfully reconstructed using "fossil rebuild".
947 **
948 ** Options:
949 **
950 ** -d|--db-only Run "PRAGMA integrity_check" on the database only.
951 ** No other validation is performed.
952 **
953 ** --parse Parse all manifests, wikis, tickets, events, and
954 ** so forth, reporting any errors found.
955 **
956 ** -q|--quick Run "PRAGMA quick_check" on the database only.
957 ** No other validation is performed.
958 */
959 void test_integrity(void){
960 Stmt q;
961 Blob content;
962 int n1 = 0;
@@ -958,11 +964,25 @@
964 int nErr = 0;
965 int total;
966 int nCA = 0;
967 int anCA[10];
968 int bParse = find_option("parse",0,0)!=0;
969 int bDbOnly = find_option("db-only","d",0)!=0;
970 int bQuick = find_option("quick","q",0)!=0;
971 db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
972 if( bDbOnly || bQuick ){
973 const char *zType = bQuick ? "quick" : "integrity";
974 char *zRes;
975 zRes = db_text(0,"PRAGMA repository.%s_check", zType/*safe-for-%s*/);
976 if( fossil_strcmp(zRes,"ok")!=0 ){
977 fossil_print("%s_check failed!\n", zType);
978 exit(1);
979 }else{
980 fossil_print("ok\n");
981 }
982 return;
983 }
984 memset(anCA, 0, sizeof(anCA));
985
986 /* Make sure no public artifact is a delta from a private artifact */
987 db_prepare(&q,
988 "SELECT "
989
+13 -1
--- src/db.c
+++ src/db.c
@@ -2381,16 +2381,28 @@
23812381
char c = i==argc-1 ? '\n' : ' ';
23822382
fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
23832383
}
23842384
}
23852385
}
2386
-LOCAL int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){
2386
+
2387
+/*
2388
+** Callback for sqlite3_trace_v2();
2389
+*/
2390
+int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){
23872391
sqlite3_stmt *pStmt = (sqlite3_stmt*)pP;
23882392
char *zSql;
23892393
int n;
23902394
const char *zArg = (const char*)pX;
23912395
char zEnd[40];
2396
+ if( m & SQLITE_TRACE_CLOSE ){
2397
+ /* If we are tracking closes, that means we want to clean up static
2398
+ ** prepared statements. */
2399
+ while( db.pAllStmt ){
2400
+ db_finalize(db.pAllStmt);
2401
+ }
2402
+ return 0;
2403
+ }
23922404
if( zArg[0]=='-' ) return 0;
23932405
if( m & SQLITE_TRACE_PROFILE ){
23942406
sqlite3_int64 nNano = *(sqlite3_int64*)pX;
23952407
double rMillisec = 0.000001 * nNano;
23962408
sqlite3_snprintf(sizeof(zEnd),zEnd," /* %.3fms */\n", rMillisec);
23972409
--- src/db.c
+++ src/db.c
@@ -2381,16 +2381,28 @@
2381 char c = i==argc-1 ? '\n' : ' ';
2382 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
2383 }
2384 }
2385 }
2386 LOCAL int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){
 
 
 
 
2387 sqlite3_stmt *pStmt = (sqlite3_stmt*)pP;
2388 char *zSql;
2389 int n;
2390 const char *zArg = (const char*)pX;
2391 char zEnd[40];
 
 
 
 
 
 
 
 
2392 if( zArg[0]=='-' ) return 0;
2393 if( m & SQLITE_TRACE_PROFILE ){
2394 sqlite3_int64 nNano = *(sqlite3_int64*)pX;
2395 double rMillisec = 0.000001 * nNano;
2396 sqlite3_snprintf(sizeof(zEnd),zEnd," /* %.3fms */\n", rMillisec);
2397
--- src/db.c
+++ src/db.c
@@ -2381,16 +2381,28 @@
2381 char c = i==argc-1 ? '\n' : ' ';
2382 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
2383 }
2384 }
2385 }
2386
2387 /*
2388 ** Callback for sqlite3_trace_v2();
2389 */
2390 int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){
2391 sqlite3_stmt *pStmt = (sqlite3_stmt*)pP;
2392 char *zSql;
2393 int n;
2394 const char *zArg = (const char*)pX;
2395 char zEnd[40];
2396 if( m & SQLITE_TRACE_CLOSE ){
2397 /* If we are tracking closes, that means we want to clean up static
2398 ** prepared statements. */
2399 while( db.pAllStmt ){
2400 db_finalize(db.pAllStmt);
2401 }
2402 return 0;
2403 }
2404 if( zArg[0]=='-' ) return 0;
2405 if( m & SQLITE_TRACE_PROFILE ){
2406 sqlite3_int64 nNano = *(sqlite3_int64*)pX;
2407 double rMillisec = 0.000001 * nNano;
2408 sqlite3_snprintf(sizeof(zEnd),zEnd," /* %.3fms */\n", rMillisec);
2409
--- src/default_css.txt
+++ src/default_css.txt
@@ -860,5 +860,11 @@
860860
// }
861861
// #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div {
862862
// max-width: 30em;
863863
// overflow: auto;
864864
// }
865
+input {
866
+ max-width: 95%;
867
+}
868
+textarea {
869
+ max-width: 95%;
870
+}
865871
--- src/default_css.txt
+++ src/default_css.txt
@@ -860,5 +860,11 @@
860 // }
861 // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div {
862 // max-width: 30em;
863 // overflow: auto;
864 // }
 
 
 
 
 
 
865
--- src/default_css.txt
+++ src/default_css.txt
@@ -860,5 +860,11 @@
860 // }
861 // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div {
862 // max-width: 30em;
863 // overflow: auto;
864 // }
865 input {
866 max-width: 95%;
867 }
868 textarea {
869 max-width: 95%;
870 }
871
+19 -14
--- src/doc.c
+++ src/doc.c
@@ -810,11 +810,11 @@
810810
** WEBPAGE: doc
811811
** URL: /uv/FILE
812812
** URL: /doc/CHECKIN/FILE
813813
**
814814
** CHECKIN can be either tag or hash prefix or timestamp identifying a
815
-** particular check, or the name of a branch (meaning the most recent
815
+** particular check-in, or the name of a branch (meaning the most recent
816816
** check-in on that branch) or one of various magic words:
817817
**
818818
** "tip" means the most recent check-in
819819
**
820820
** "ckout" means the current check-out, if the server is run from
@@ -824,11 +824,12 @@
824824
** regardless of what branch it occurs on.
825825
**
826826
** FILE is the name of a file to delivered up as a webpage. FILE is relative
827827
** to the root of the source tree of the repository. The FILE must
828828
** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
829
-** directly from disk and need not be a managed file.
829
+** directly from disk and need not be a managed file. For /uv, FILE
830
+** can also be the hash of the unversioned file.
830831
**
831832
** The "ckout" CHECKIN is intended for development - to provide a mechanism
832833
** for looking at what a file will look like using the /doc webpage after
833834
** it gets checked in.
834835
**
@@ -931,22 +932,26 @@
931932
goto doc_not_found;
932933
}
933934
}
934935
if( isUV ){
935936
if( db_table_exists("repository","unversioned") ){
936
- Stmt q;
937
- db_prepare(&q, "SELECT hash, mtime FROM unversioned"
938
- " WHERE name=%Q", zName);
939
- if( db_step(&q)==SQLITE_ROW ){
940
- etag_check(ETAG_HASH, db_column_text(&q,0));
941
- etag_last_modified(db_column_int64(&q,1));
942
- }
943
- db_finalize(&q);
944
- if( unversioned_content(zName, &filebody)==0 ){
945
- rid = 1;
946
- zDfltTitle = zName;
947
- }
937
+ rid = unversioned_content(zName, &filebody);
938
+ if( rid==1 ){
939
+ Stmt q;
940
+ db_prepare(&q, "SELECT hash, mtime FROM unversioned"
941
+ " WHERE name=%Q", zName);
942
+ if( db_step(&q)==SQLITE_ROW ){
943
+ etag_check(ETAG_HASH, db_column_text(&q,0));
944
+ etag_last_modified(db_column_int64(&q,1));
945
+ }
946
+ db_finalize(&q);
947
+ }else if( rid==2 ){
948
+ zName = db_text(zName,
949
+ "SELECT name FROM unversioned WHERE hash=%Q", zName);
950
+ g.isConst = 1;
951
+ }
952
+ zDfltTitle = zName;
948953
}
949954
}else if( fossil_strcmp(zCheckin,"ckout")==0 ){
950955
/* Read from the local checkout */
951956
char *zFullpath;
952957
db_must_be_within_tree();
953958
--- src/doc.c
+++ src/doc.c
@@ -810,11 +810,11 @@
810 ** WEBPAGE: doc
811 ** URL: /uv/FILE
812 ** URL: /doc/CHECKIN/FILE
813 **
814 ** CHECKIN can be either tag or hash prefix or timestamp identifying a
815 ** particular check, or the name of a branch (meaning the most recent
816 ** check-in on that branch) or one of various magic words:
817 **
818 ** "tip" means the most recent check-in
819 **
820 ** "ckout" means the current check-out, if the server is run from
@@ -824,11 +824,12 @@
824 ** regardless of what branch it occurs on.
825 **
826 ** FILE is the name of a file to delivered up as a webpage. FILE is relative
827 ** to the root of the source tree of the repository. The FILE must
828 ** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
829 ** directly from disk and need not be a managed file.
 
830 **
831 ** The "ckout" CHECKIN is intended for development - to provide a mechanism
832 ** for looking at what a file will look like using the /doc webpage after
833 ** it gets checked in.
834 **
@@ -931,22 +932,26 @@
931 goto doc_not_found;
932 }
933 }
934 if( isUV ){
935 if( db_table_exists("repository","unversioned") ){
936 Stmt q;
937 db_prepare(&q, "SELECT hash, mtime FROM unversioned"
938 " WHERE name=%Q", zName);
939 if( db_step(&q)==SQLITE_ROW ){
940 etag_check(ETAG_HASH, db_column_text(&q,0));
941 etag_last_modified(db_column_int64(&q,1));
942 }
943 db_finalize(&q);
944 if( unversioned_content(zName, &filebody)==0 ){
945 rid = 1;
946 zDfltTitle = zName;
947 }
 
 
 
 
948 }
949 }else if( fossil_strcmp(zCheckin,"ckout")==0 ){
950 /* Read from the local checkout */
951 char *zFullpath;
952 db_must_be_within_tree();
953
--- src/doc.c
+++ src/doc.c
@@ -810,11 +810,11 @@
810 ** WEBPAGE: doc
811 ** URL: /uv/FILE
812 ** URL: /doc/CHECKIN/FILE
813 **
814 ** CHECKIN can be either tag or hash prefix or timestamp identifying a
815 ** particular check-in, or the name of a branch (meaning the most recent
816 ** check-in on that branch) or one of various magic words:
817 **
818 ** "tip" means the most recent check-in
819 **
820 ** "ckout" means the current check-out, if the server is run from
@@ -824,11 +824,12 @@
824 ** regardless of what branch it occurs on.
825 **
826 ** FILE is the name of a file to delivered up as a webpage. FILE is relative
827 ** to the root of the source tree of the repository. The FILE must
828 ** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
829 ** directly from disk and need not be a managed file. For /uv, FILE
830 ** can also be the hash of the unversioned file.
831 **
832 ** The "ckout" CHECKIN is intended for development - to provide a mechanism
833 ** for looking at what a file will look like using the /doc webpage after
834 ** it gets checked in.
835 **
@@ -931,22 +932,26 @@
932 goto doc_not_found;
933 }
934 }
935 if( isUV ){
936 if( db_table_exists("repository","unversioned") ){
937 rid = unversioned_content(zName, &filebody);
938 if( rid==1 ){
939 Stmt q;
940 db_prepare(&q, "SELECT hash, mtime FROM unversioned"
941 " WHERE name=%Q", zName);
942 if( db_step(&q)==SQLITE_ROW ){
943 etag_check(ETAG_HASH, db_column_text(&q,0));
944 etag_last_modified(db_column_int64(&q,1));
945 }
946 db_finalize(&q);
947 }else if( rid==2 ){
948 zName = db_text(zName,
949 "SELECT name FROM unversioned WHERE hash=%Q", zName);
950 g.isConst = 1;
951 }
952 zDfltTitle = zName;
953 }
954 }else if( fossil_strcmp(zCheckin,"ckout")==0 ){
955 /* Read from the local checkout */
956 char *zFullpath;
957 db_must_be_within_tree();
958
+43 -6
--- src/etag.c
+++ src/etag.c
@@ -24,10 +24,12 @@
2424
** (1) The mtime on the Fossil executable
2525
** (2) The last change to the CONFIG table
2626
** (3) The last change to the EVENT table
2727
** (4) The value of the display cookie
2828
** (5) A hash value supplied by the page generator
29
+** (6) The details of the request URI
30
+** (7) The name user as determined by the login cookie
2931
**
3032
** Item (1) is always included in the ETag. The other elements are
3133
** optional. Because (1) is always included as part of the ETag, all
3234
** outstanding ETags can be invalidated by touching the fossil executable.
3335
**
@@ -60,32 +62,50 @@
6062
*/
6163
#define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */
6264
#define ETAG_DATA 0x02 /* Output depends on the EVENT table */
6365
#define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */
6466
#define ETAG_HASH 0x08 /* Output depends on a hash */
67
+#define ETAG_QUERY 0x10 /* Output depends on PATH_INFO and QUERY_STRING */
68
+ /* and the g.zLogin value */
6569
#endif
6670
6771
static char zETag[33]; /* The generated ETag */
6872
static int iMaxAge = 0; /* The max-age parameter in the reply */
6973
static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */
74
+
75
+/*
76
+** Return a hash that changes every time the Fossil source code is
77
+** rebuilt.
78
+**
79
+** The FOSSIL_BUILD_HASH string that is returned here gets computed by
80
+** the mkversion utility program. The result is a hash of MANIFEST_UUID
81
+** and the unix timestamp for when the mkversion utility program is run.
82
+**
83
+** During development rebuilds, if you need the source code id to change
84
+** in order to invalidate caches, simply "touch" the "manifest" file in
85
+** the top of the source directory prior to running "make" and a new
86
+** FOSSIL_BUILD_HASH will be generated automatically.
87
+*/
88
+const char *fossil_exe_id(void){
89
+ return FOSSIL_BUILD_HASH;
90
+}
7091
7192
/*
7293
** Generate an ETag
7394
*/
7495
void etag_check(unsigned eFlags, const char *zHash){
75
- sqlite3_int64 mtime;
7696
const char *zIfNoneMatch;
7797
char zBuf[50];
7898
assert( zETag[0]==0 ); /* Only call this routine once! */
7999
80100
iMaxAge = 86400;
81101
md5sum_init();
82102
83
- /* Always include the mtime of the executable as part of the hash */
84
- mtime = file_mtime(g.nameOfExe, ExtFILE);
85
- sqlite3_snprintf(sizeof(zBuf),zBuf,"mtime: %lld\n", mtime);
86
- md5sum_step_text(zBuf, -1);
103
+ /* Always include the executable ID as part of the hash */
104
+ md5sum_step_text("exe-id: ", -1);
105
+ md5sum_step_text(fossil_exe_id(), -1);
106
+ md5sum_step_text("\n", 1);
87107
88108
if( (eFlags & ETAG_HASH)!=0 && zHash ){
89109
md5sum_step_text("hash: ", -1);
90110
md5sum_step_text(zHash, -1);
91111
md5sum_step_text("\n", 1);
@@ -98,11 +118,11 @@
98118
md5sum_step_text("\n", 1);
99119
iMaxAge = 60;
100120
}else if( eFlags & ETAG_CONFIG ){
101121
int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'");
102122
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
103
- md5sum_step_text("data: ", -1);
123
+ md5sum_step_text("config: ", -1);
104124
md5sum_step_text(zBuf, -1);
105125
md5sum_step_text("\n", 1);
106126
iMaxAge = 3600;
107127
}
108128
@@ -111,10 +131,27 @@
111131
md5sum_step_text("display-cookie: ", -1);
112132
md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1);
113133
md5sum_step_text("\n", 1);
114134
iMaxAge = 0;
115135
}
136
+
137
+ /* Output depends on PATH_INFO and QUERY_STRING */
138
+ if( eFlags & ETAG_QUERY ){
139
+ const char *zQS = P("QUERY_STRING");
140
+ md5sum_step_text("query: ", -1);
141
+ md5sum_step_text(PD("PATH_INFO",""), -1);
142
+ if( zQS ){
143
+ md5sum_step_text("?", 1);
144
+ md5sum_step_text(zQS, -1);
145
+ }
146
+ md5sum_step_text("\n",1);
147
+ if( g.zLogin ){
148
+ md5sum_step_text("login: ", -1);
149
+ md5sum_step_text(g.zLogin, -1);
150
+ md5sum_step_text("\n", 1);
151
+ }
152
+ }
116153
117154
/* Generate the ETag */
118155
memcpy(zETag, md5sum_finish(0), 33);
119156
120157
/* Check to see if the generated ETag matches If-None-Match and
121158
--- src/etag.c
+++ src/etag.c
@@ -24,10 +24,12 @@
24 ** (1) The mtime on the Fossil executable
25 ** (2) The last change to the CONFIG table
26 ** (3) The last change to the EVENT table
27 ** (4) The value of the display cookie
28 ** (5) A hash value supplied by the page generator
 
 
29 **
30 ** Item (1) is always included in the ETag. The other elements are
31 ** optional. Because (1) is always included as part of the ETag, all
32 ** outstanding ETags can be invalidated by touching the fossil executable.
33 **
@@ -60,32 +62,50 @@
60 */
61 #define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */
62 #define ETAG_DATA 0x02 /* Output depends on the EVENT table */
63 #define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */
64 #define ETAG_HASH 0x08 /* Output depends on a hash */
 
 
65 #endif
66
67 static char zETag[33]; /* The generated ETag */
68 static int iMaxAge = 0; /* The max-age parameter in the reply */
69 static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
71 /*
72 ** Generate an ETag
73 */
74 void etag_check(unsigned eFlags, const char *zHash){
75 sqlite3_int64 mtime;
76 const char *zIfNoneMatch;
77 char zBuf[50];
78 assert( zETag[0]==0 ); /* Only call this routine once! */
79
80 iMaxAge = 86400;
81 md5sum_init();
82
83 /* Always include the mtime of the executable as part of the hash */
84 mtime = file_mtime(g.nameOfExe, ExtFILE);
85 sqlite3_snprintf(sizeof(zBuf),zBuf,"mtime: %lld\n", mtime);
86 md5sum_step_text(zBuf, -1);
87
88 if( (eFlags & ETAG_HASH)!=0 && zHash ){
89 md5sum_step_text("hash: ", -1);
90 md5sum_step_text(zHash, -1);
91 md5sum_step_text("\n", 1);
@@ -98,11 +118,11 @@
98 md5sum_step_text("\n", 1);
99 iMaxAge = 60;
100 }else if( eFlags & ETAG_CONFIG ){
101 int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'");
102 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
103 md5sum_step_text("data: ", -1);
104 md5sum_step_text(zBuf, -1);
105 md5sum_step_text("\n", 1);
106 iMaxAge = 3600;
107 }
108
@@ -111,10 +131,27 @@
111 md5sum_step_text("display-cookie: ", -1);
112 md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1);
113 md5sum_step_text("\n", 1);
114 iMaxAge = 0;
115 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
117 /* Generate the ETag */
118 memcpy(zETag, md5sum_finish(0), 33);
119
120 /* Check to see if the generated ETag matches If-None-Match and
121
--- src/etag.c
+++ src/etag.c
@@ -24,10 +24,12 @@
24 ** (1) The mtime on the Fossil executable
25 ** (2) The last change to the CONFIG table
26 ** (3) The last change to the EVENT table
27 ** (4) The value of the display cookie
28 ** (5) A hash value supplied by the page generator
29 ** (6) The details of the request URI
30 ** (7) The name user as determined by the login cookie
31 **
32 ** Item (1) is always included in the ETag. The other elements are
33 ** optional. Because (1) is always included as part of the ETag, all
34 ** outstanding ETags can be invalidated by touching the fossil executable.
35 **
@@ -60,32 +62,50 @@
62 */
63 #define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */
64 #define ETAG_DATA 0x02 /* Output depends on the EVENT table */
65 #define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */
66 #define ETAG_HASH 0x08 /* Output depends on a hash */
67 #define ETAG_QUERY 0x10 /* Output depends on PATH_INFO and QUERY_STRING */
68 /* and the g.zLogin value */
69 #endif
70
71 static char zETag[33]; /* The generated ETag */
72 static int iMaxAge = 0; /* The max-age parameter in the reply */
73 static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */
74
75 /*
76 ** Return a hash that changes every time the Fossil source code is
77 ** rebuilt.
78 **
79 ** The FOSSIL_BUILD_HASH string that is returned here gets computed by
80 ** the mkversion utility program. The result is a hash of MANIFEST_UUID
81 ** and the unix timestamp for when the mkversion utility program is run.
82 **
83 ** During development rebuilds, if you need the source code id to change
84 ** in order to invalidate caches, simply "touch" the "manifest" file in
85 ** the top of the source directory prior to running "make" and a new
86 ** FOSSIL_BUILD_HASH will be generated automatically.
87 */
88 const char *fossil_exe_id(void){
89 return FOSSIL_BUILD_HASH;
90 }
91
92 /*
93 ** Generate an ETag
94 */
95 void etag_check(unsigned eFlags, const char *zHash){
 
96 const char *zIfNoneMatch;
97 char zBuf[50];
98 assert( zETag[0]==0 ); /* Only call this routine once! */
99
100 iMaxAge = 86400;
101 md5sum_init();
102
103 /* Always include the executable ID as part of the hash */
104 md5sum_step_text("exe-id: ", -1);
105 md5sum_step_text(fossil_exe_id(), -1);
106 md5sum_step_text("\n", 1);
107
108 if( (eFlags & ETAG_HASH)!=0 && zHash ){
109 md5sum_step_text("hash: ", -1);
110 md5sum_step_text(zHash, -1);
111 md5sum_step_text("\n", 1);
@@ -98,11 +118,11 @@
118 md5sum_step_text("\n", 1);
119 iMaxAge = 60;
120 }else if( eFlags & ETAG_CONFIG ){
121 int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'");
122 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
123 md5sum_step_text("config: ", -1);
124 md5sum_step_text(zBuf, -1);
125 md5sum_step_text("\n", 1);
126 iMaxAge = 3600;
127 }
128
@@ -111,10 +131,27 @@
131 md5sum_step_text("display-cookie: ", -1);
132 md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1);
133 md5sum_step_text("\n", 1);
134 iMaxAge = 0;
135 }
136
137 /* Output depends on PATH_INFO and QUERY_STRING */
138 if( eFlags & ETAG_QUERY ){
139 const char *zQS = P("QUERY_STRING");
140 md5sum_step_text("query: ", -1);
141 md5sum_step_text(PD("PATH_INFO",""), -1);
142 if( zQS ){
143 md5sum_step_text("?", 1);
144 md5sum_step_text(zQS, -1);
145 }
146 md5sum_step_text("\n",1);
147 if( g.zLogin ){
148 md5sum_step_text("login: ", -1);
149 md5sum_step_text(g.zLogin, -1);
150 md5sum_step_text("\n", 1);
151 }
152 }
153
154 /* Generate the ETag */
155 memcpy(zETag, md5sum_finish(0), 33);
156
157 /* Check to see if the generated ETag matches If-None-Match and
158
+15 -11
--- src/finfo.c
+++ src/finfo.c
@@ -199,11 +199,11 @@
199199
TAG_BRANCH, zFilename, filename_collation(),
200200
iLimit, iOffset
201201
);
202202
blob_zero(&line);
203203
if( iBrief ){
204
- fossil_print("History of %s\n", blob_str(&fname));
204
+ fossil_print("History for %s\n", blob_str(&fname));
205205
}
206206
while( db_step(&q)==SQLITE_ROW ){
207207
const char *zFileUuid = db_column_text(&q, 0);
208208
const char *zCiUuid = db_column_text(&q,1);
209209
const char *zDate = db_column_text(&q, 2);
@@ -296,11 +296,11 @@
296296
** timezone offset from UTC as "-HH:MM" (westward) or "+HH:MM"
297297
** (eastward). Either no timezone suffix or "Z" means UTC.
298298
*/
299299
void finfo_page(void){
300300
Stmt q;
301
- const char *zFilename;
301
+ const char *zFilename = PD("name","");
302302
char zPrevDate[20];
303303
const char *zA;
304304
const char *zB;
305305
int n;
306306
int baseCheckin;
@@ -321,11 +321,16 @@
321321
const char *zMark; /* Mark this version of the file */
322322
int selRid = 0; /* RID of the marked file version */
323323
324324
login_check_credentials();
325325
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
326
- style_header("File History");
326
+ fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
327
+ if( fnid==0 ){
328
+ style_header("No such file");
329
+ }else{
330
+ style_header("History for %s", zFilename);
331
+ }
327332
login_anonymous_available();
328333
tmFlags = timeline_ss_submenu();
329334
if( tmFlags & TIMELINE_COLUMNAR ){
330335
zStyle = "Columnar";
331336
}else if( tmFlags & TIMELINE_COMPACT ){
@@ -340,13 +345,11 @@
340345
url_initialize(&url, "finfo");
341346
if( brBg ) url_add_parameter(&url, "brbg", 0);
342347
if( uBg ) url_add_parameter(&url, "ubg", 0);
343348
baseCheckin = name_to_rid_www("ci");
344349
zPrevDate[0] = 0;
345
- zFilename = PD("name","");
346350
cookie_render();
347
- fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
348351
if( fnid==0 ){
349352
@ No such file: %h(zFilename)
350353
style_footer();
351354
return;
352355
}
@@ -435,12 +438,13 @@
435438
}else if( n>0 ){
436439
blob_appendf(&title, "First %d ancestors of file ", n);
437440
}else{
438441
blob_appendf(&title, "Ancestors of file ");
439442
}
440
- blob_appendf(&title,"<a href='%R/finfo?name=%T'>%h</a>",
441
- zFilename, zFilename);
443
+ blob_appendf(&title,"%z%h</a>",
444
+ href("%R/file?name=%T&ci=%!S", zFilename, zUuid),
445
+ zFilename);
442446
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
443447
blob_append(&title, origCheckin ? " between " : " from ", -1);
444448
blob_appendf(&title, "check-in %z%S</a>", zLink, zUuid);
445449
if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
446450
fossil_free(zUuid);
@@ -449,12 +453,12 @@
449453
zLink = href("%R/info/%!S", zUuid);
450454
blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
451455
fossil_free(zUuid);
452456
}
453457
}else{
454
- blob_appendf(&title, "History of ");
455
- hyperlinked_path(zFilename, &title, 0, "tree", "");
458
+ blob_appendf(&title, "History for ");
459
+ hyperlinked_path(zFilename, &title, 0, "tree", "", LINKPATH_FILE);
456460
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
457461
}
458462
if( uBg ){
459463
blob_append(&title, " (color-coded by user)", -1);
460464
}
@@ -524,11 +528,11 @@
524528
@ <tr class='timelineSelected'>
525529
}else{
526530
@ <tr>
527531
}
528532
@ <td class="timelineTime">\
529
- @ %z(href("%R/artifact/%!S",zUuid))%s(zTime)</a></td>
533
+ @ %z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))%s(zTime)</a></td>
530534
@ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
531535
@ </td>
532536
if( zBgClr && zBgClr[0] ){
533537
@ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
534538
}else{
@@ -561,11 +565,11 @@
561565
cgi_printf("<span class='clutter' id='detail-%d'>",frid);
562566
}
563567
cgi_printf("<span class='timeline%sDetail'>", zStyle);
564568
if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
565569
if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
566
- @ file:&nbsp;%z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
570
+ @ file:&nbsp;%z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))[%S(zUuid)]</a>
567571
if( fShowId ){
568572
int srcId = delta_source_rid(frid);
569573
if( srcId>0 ){
570574
@ id:&nbsp;%d(frid)&larr;%d(srcId)
571575
}else{
572576
--- src/finfo.c
+++ src/finfo.c
@@ -199,11 +199,11 @@
199 TAG_BRANCH, zFilename, filename_collation(),
200 iLimit, iOffset
201 );
202 blob_zero(&line);
203 if( iBrief ){
204 fossil_print("History of %s\n", blob_str(&fname));
205 }
206 while( db_step(&q)==SQLITE_ROW ){
207 const char *zFileUuid = db_column_text(&q, 0);
208 const char *zCiUuid = db_column_text(&q,1);
209 const char *zDate = db_column_text(&q, 2);
@@ -296,11 +296,11 @@
296 ** timezone offset from UTC as "-HH:MM" (westward) or "+HH:MM"
297 ** (eastward). Either no timezone suffix or "Z" means UTC.
298 */
299 void finfo_page(void){
300 Stmt q;
301 const char *zFilename;
302 char zPrevDate[20];
303 const char *zA;
304 const char *zB;
305 int n;
306 int baseCheckin;
@@ -321,11 +321,16 @@
321 const char *zMark; /* Mark this version of the file */
322 int selRid = 0; /* RID of the marked file version */
323
324 login_check_credentials();
325 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
326 style_header("File History");
 
 
 
 
 
327 login_anonymous_available();
328 tmFlags = timeline_ss_submenu();
329 if( tmFlags & TIMELINE_COLUMNAR ){
330 zStyle = "Columnar";
331 }else if( tmFlags & TIMELINE_COMPACT ){
@@ -340,13 +345,11 @@
340 url_initialize(&url, "finfo");
341 if( brBg ) url_add_parameter(&url, "brbg", 0);
342 if( uBg ) url_add_parameter(&url, "ubg", 0);
343 baseCheckin = name_to_rid_www("ci");
344 zPrevDate[0] = 0;
345 zFilename = PD("name","");
346 cookie_render();
347 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
348 if( fnid==0 ){
349 @ No such file: %h(zFilename)
350 style_footer();
351 return;
352 }
@@ -435,12 +438,13 @@
435 }else if( n>0 ){
436 blob_appendf(&title, "First %d ancestors of file ", n);
437 }else{
438 blob_appendf(&title, "Ancestors of file ");
439 }
440 blob_appendf(&title,"<a href='%R/finfo?name=%T'>%h</a>",
441 zFilename, zFilename);
 
442 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
443 blob_append(&title, origCheckin ? " between " : " from ", -1);
444 blob_appendf(&title, "check-in %z%S</a>", zLink, zUuid);
445 if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
446 fossil_free(zUuid);
@@ -449,12 +453,12 @@
449 zLink = href("%R/info/%!S", zUuid);
450 blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
451 fossil_free(zUuid);
452 }
453 }else{
454 blob_appendf(&title, "History of ");
455 hyperlinked_path(zFilename, &title, 0, "tree", "");
456 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
457 }
458 if( uBg ){
459 blob_append(&title, " (color-coded by user)", -1);
460 }
@@ -524,11 +528,11 @@
524 @ <tr class='timelineSelected'>
525 }else{
526 @ <tr>
527 }
528 @ <td class="timelineTime">\
529 @ %z(href("%R/artifact/%!S",zUuid))%s(zTime)</a></td>
530 @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
531 @ </td>
532 if( zBgClr && zBgClr[0] ){
533 @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
534 }else{
@@ -561,11 +565,11 @@
561 cgi_printf("<span class='clutter' id='detail-%d'>",frid);
562 }
563 cgi_printf("<span class='timeline%sDetail'>", zStyle);
564 if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
565 if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
566 @ file:&nbsp;%z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
567 if( fShowId ){
568 int srcId = delta_source_rid(frid);
569 if( srcId>0 ){
570 @ id:&nbsp;%d(frid)&larr;%d(srcId)
571 }else{
572
--- src/finfo.c
+++ src/finfo.c
@@ -199,11 +199,11 @@
199 TAG_BRANCH, zFilename, filename_collation(),
200 iLimit, iOffset
201 );
202 blob_zero(&line);
203 if( iBrief ){
204 fossil_print("History for %s\n", blob_str(&fname));
205 }
206 while( db_step(&q)==SQLITE_ROW ){
207 const char *zFileUuid = db_column_text(&q, 0);
208 const char *zCiUuid = db_column_text(&q,1);
209 const char *zDate = db_column_text(&q, 2);
@@ -296,11 +296,11 @@
296 ** timezone offset from UTC as "-HH:MM" (westward) or "+HH:MM"
297 ** (eastward). Either no timezone suffix or "Z" means UTC.
298 */
299 void finfo_page(void){
300 Stmt q;
301 const char *zFilename = PD("name","");
302 char zPrevDate[20];
303 const char *zA;
304 const char *zB;
305 int n;
306 int baseCheckin;
@@ -321,11 +321,16 @@
321 const char *zMark; /* Mark this version of the file */
322 int selRid = 0; /* RID of the marked file version */
323
324 login_check_credentials();
325 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
326 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
327 if( fnid==0 ){
328 style_header("No such file");
329 }else{
330 style_header("History for %s", zFilename);
331 }
332 login_anonymous_available();
333 tmFlags = timeline_ss_submenu();
334 if( tmFlags & TIMELINE_COLUMNAR ){
335 zStyle = "Columnar";
336 }else if( tmFlags & TIMELINE_COMPACT ){
@@ -340,13 +345,11 @@
345 url_initialize(&url, "finfo");
346 if( brBg ) url_add_parameter(&url, "brbg", 0);
347 if( uBg ) url_add_parameter(&url, "ubg", 0);
348 baseCheckin = name_to_rid_www("ci");
349 zPrevDate[0] = 0;
 
350 cookie_render();
 
351 if( fnid==0 ){
352 @ No such file: %h(zFilename)
353 style_footer();
354 return;
355 }
@@ -435,12 +438,13 @@
438 }else if( n>0 ){
439 blob_appendf(&title, "First %d ancestors of file ", n);
440 }else{
441 blob_appendf(&title, "Ancestors of file ");
442 }
443 blob_appendf(&title,"%z%h</a>",
444 href("%R/file?name=%T&ci=%!S", zFilename, zUuid),
445 zFilename);
446 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
447 blob_append(&title, origCheckin ? " between " : " from ", -1);
448 blob_appendf(&title, "check-in %z%S</a>", zLink, zUuid);
449 if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
450 fossil_free(zUuid);
@@ -449,12 +453,12 @@
453 zLink = href("%R/info/%!S", zUuid);
454 blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
455 fossil_free(zUuid);
456 }
457 }else{
458 blob_appendf(&title, "History for ");
459 hyperlinked_path(zFilename, &title, 0, "tree", "", LINKPATH_FILE);
460 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
461 }
462 if( uBg ){
463 blob_append(&title, " (color-coded by user)", -1);
464 }
@@ -524,11 +528,11 @@
528 @ <tr class='timelineSelected'>
529 }else{
530 @ <tr>
531 }
532 @ <td class="timelineTime">\
533 @ %z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))%s(zTime)</a></td>
534 @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
535 @ </td>
536 if( zBgClr && zBgClr[0] ){
537 @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
538 }else{
@@ -561,11 +565,11 @@
565 cgi_printf("<span class='clutter' id='detail-%d'>",frid);
566 }
567 cgi_printf("<span class='timeline%sDetail'>", zStyle);
568 if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
569 if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
570 @ file:&nbsp;%z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))[%S(zUuid)]</a>
571 if( fShowId ){
572 int srcId = delta_source_rid(frid);
573 if( srcId>0 ){
574 @ id:&nbsp;%d(frid)&larr;%d(srcId)
575 }else{
576
+5 -4
--- src/forum.c
+++ src/forum.c
@@ -1013,12 +1013,12 @@
10131013
@ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
10141014
@ maxlength="125"><br>
10151015
}
10161016
@ %z(href("%R/markup_help"))Markup style</a>:
10171017
mimetype_option_menu(zMimetype);
1018
- @ <br><textarea name="content" class="wikiedit" cols="80" \
1019
- @ rows="25" wrap="virtual">%h(zContent)</textarea><br>
1018
+ @ <br><textarea aria-label="Content:" name="content" class="wikiedit" \
1019
+ @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea><br>
10201020
}
10211021
10221022
/*
10231023
** WEBPAGE: forumnew
10241024
** WEBPAGE: forumedit
@@ -1119,11 +1119,12 @@
11191119
@ <input type="submit" name="submit" value="Submit">
11201120
}else{
11211121
@ <input type="submit" name="submit" value="Submit" disabled>
11221122
}
11231123
if( g.perm.Debug ){
1124
- /* For the test-forumnew page add these extra debugging controls */
1124
+ /* Give extra control over the post to users with the special
1125
+ * Debug capability, which includes Admin and Setup users */
11251126
@ <div class="debug">
11261127
@ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
11271128
@ Dry run</label>
11281129
@ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
11291130
@ Require moderator approval</label>
@@ -1235,11 +1236,11 @@
12351236
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
12361237
@ <input type="hidden" name="nullout" value="1">
12371238
@ <input type="hidden" name="mimetype" value="%h(zMimetype)">
12381239
@ <input type="hidden" name="content" value="%h(zContent)">
12391240
if( zTitle ){
1240
- @ <input type="hidden" name="title" value="%h(zTitle)">
1241
+ @ <input aria-label="Title" type="hidden" name="title" value="%h(zTitle)">
12411242
}
12421243
}else if( P("edit") ){
12431244
/* Provide an edit to the fpid post */
12441245
zMimetype = P("mimetype");
12451246
zContent = PT("content");
12461247
--- src/forum.c
+++ src/forum.c
@@ -1013,12 +1013,12 @@
1013 @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
1014 @ maxlength="125"><br>
1015 }
1016 @ %z(href("%R/markup_help"))Markup style</a>:
1017 mimetype_option_menu(zMimetype);
1018 @ <br><textarea name="content" class="wikiedit" cols="80" \
1019 @ rows="25" wrap="virtual">%h(zContent)</textarea><br>
1020 }
1021
1022 /*
1023 ** WEBPAGE: forumnew
1024 ** WEBPAGE: forumedit
@@ -1119,11 +1119,12 @@
1119 @ <input type="submit" name="submit" value="Submit">
1120 }else{
1121 @ <input type="submit" name="submit" value="Submit" disabled>
1122 }
1123 if( g.perm.Debug ){
1124 /* For the test-forumnew page add these extra debugging controls */
 
1125 @ <div class="debug">
1126 @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
1127 @ Dry run</label>
1128 @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
1129 @ Require moderator approval</label>
@@ -1235,11 +1236,11 @@
1235 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
1236 @ <input type="hidden" name="nullout" value="1">
1237 @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
1238 @ <input type="hidden" name="content" value="%h(zContent)">
1239 if( zTitle ){
1240 @ <input type="hidden" name="title" value="%h(zTitle)">
1241 }
1242 }else if( P("edit") ){
1243 /* Provide an edit to the fpid post */
1244 zMimetype = P("mimetype");
1245 zContent = PT("content");
1246
--- src/forum.c
+++ src/forum.c
@@ -1013,12 +1013,12 @@
1013 @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
1014 @ maxlength="125"><br>
1015 }
1016 @ %z(href("%R/markup_help"))Markup style</a>:
1017 mimetype_option_menu(zMimetype);
1018 @ <br><textarea aria-label="Content:" name="content" class="wikiedit" \
1019 @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea><br>
1020 }
1021
1022 /*
1023 ** WEBPAGE: forumnew
1024 ** WEBPAGE: forumedit
@@ -1119,11 +1119,12 @@
1119 @ <input type="submit" name="submit" value="Submit">
1120 }else{
1121 @ <input type="submit" name="submit" value="Submit" disabled>
1122 }
1123 if( g.perm.Debug ){
1124 /* Give extra control over the post to users with the special
1125 * Debug capability, which includes Admin and Setup users */
1126 @ <div class="debug">
1127 @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
1128 @ Dry run</label>
1129 @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
1130 @ Require moderator approval</label>
@@ -1235,11 +1236,11 @@
1236 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
1237 @ <input type="hidden" name="nullout" value="1">
1238 @ <input type="hidden" name="mimetype" value="%h(zMimetype)">
1239 @ <input type="hidden" name="content" value="%h(zContent)">
1240 if( zTitle ){
1241 @ <input aria-label="Title" type="hidden" name="title" value="%h(zTitle)">
1242 }
1243 }else if( P("edit") ){
1244 /* Provide an edit to the fpid post */
1245 zMimetype = P("mimetype");
1246 zContent = PT("content");
1247
+14 -6
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -24,19 +24,19 @@
2424
** SSL support is abstracted out into this module because Fossil can
2525
** be compiled without SSL support (which requires OpenSSL library)
2626
*/
2727
2828
#include "config.h"
29
+#include "http_ssl.h"
2930
3031
#ifdef FOSSIL_ENABLE_SSL
3132
3233
#include <openssl/bio.h>
3334
#include <openssl/ssl.h>
3435
#include <openssl/err.h>
3536
#include <openssl/x509.h>
3637
37
-#include "http_ssl.h"
3838
#include <assert.h>
3939
#include <sys/types.h>
4040
4141
/*
4242
** There can only be a single OpenSSL IO connection open at a time.
@@ -328,10 +328,11 @@
328328
ssl_close();
329329
return 1;
330330
}
331331
332332
if( !sslNoCertVerify && SSL_get_verify_result(ssl)!=X509_V_OK ){
333
+ int x;
333334
char *desc, *prompt;
334335
Blob ans;
335336
char cReply;
336337
BIO *mem;
337338
unsigned char md[32];
@@ -338,11 +339,17 @@
338339
char zHash[32*2+1];
339340
unsigned int mdLength = (int)sizeof(md);
340341
341342
memset(md, 0, sizeof(md));
342343
zHash[0] = 0;
343
- if( X509_digest(cert, EVP_sha256(), md, &mdLength) ){
344
+ /* MMNNFFPPS */
345
+#if OPENSSL_VERSION_NUMBER >= 0x010000000
346
+ x = X509_digest(cert, EVP_sha256(), md, &mdLength);
347
+#else
348
+ x = X509_digest(cert, EVP_sha1(), md, &mdLength);
349
+#endif
350
+ if( x ){
344351
int j;
345352
for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
346353
zHash[j*2] = "0123456789abcdef"[md[j]>>4];
347354
zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
348355
}
@@ -518,25 +525,26 @@
518525
** for the domains listed. Or if
519526
** the --all option is specified,
520527
** remove all TLS cert exceptions.
521528
*/
522529
void test_tlsconfig_info(void){
523
- const char *zCmd;
524
- size_t nCmd;
525
- int nHit = 0;
526530
#if !defined(FOSSIL_ENABLE_SSL)
527531
fossil_print("TLS disabled in this build\n");
528532
#else
533
+ const char *zCmd;
534
+ size_t nCmd;
535
+ int nHit = 0;
529536
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
530537
db_open_config(1,0);
531538
zCmd = g.argc>=3 ? g.argv[2] : "show";
532539
nCmd = strlen(zCmd);
533540
if( strncmp("show",zCmd,nCmd)==0 ){
534541
const char *zName, *zValue;
535542
size_t nName;
536543
Stmt q;
537
- fossil_print("OpenSSL-version: %s\n", SSLeay_version(SSLEAY_VERSION));
544
+ fossil_print("OpenSSL-version: %s (0x%09x)\n",
545
+ SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_NUMBER);
538546
fossil_print("OpenSSL-cert-file: %s\n", X509_get_default_cert_file());
539547
fossil_print("OpenSSL-cert-dir: %s\n", X509_get_default_cert_dir());
540548
zName = X509_get_default_cert_file_env();
541549
zValue = fossil_getenv(zName);
542550
if( zValue==0 ) zValue = "";
543551
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -24,19 +24,19 @@
24 ** SSL support is abstracted out into this module because Fossil can
25 ** be compiled without SSL support (which requires OpenSSL library)
26 */
27
28 #include "config.h"
 
29
30 #ifdef FOSSIL_ENABLE_SSL
31
32 #include <openssl/bio.h>
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35 #include <openssl/x509.h>
36
37 #include "http_ssl.h"
38 #include <assert.h>
39 #include <sys/types.h>
40
41 /*
42 ** There can only be a single OpenSSL IO connection open at a time.
@@ -328,10 +328,11 @@
328 ssl_close();
329 return 1;
330 }
331
332 if( !sslNoCertVerify && SSL_get_verify_result(ssl)!=X509_V_OK ){
 
333 char *desc, *prompt;
334 Blob ans;
335 char cReply;
336 BIO *mem;
337 unsigned char md[32];
@@ -338,11 +339,17 @@
338 char zHash[32*2+1];
339 unsigned int mdLength = (int)sizeof(md);
340
341 memset(md, 0, sizeof(md));
342 zHash[0] = 0;
343 if( X509_digest(cert, EVP_sha256(), md, &mdLength) ){
 
 
 
 
 
 
344 int j;
345 for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
346 zHash[j*2] = "0123456789abcdef"[md[j]>>4];
347 zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
348 }
@@ -518,25 +525,26 @@
518 ** for the domains listed. Or if
519 ** the --all option is specified,
520 ** remove all TLS cert exceptions.
521 */
522 void test_tlsconfig_info(void){
523 const char *zCmd;
524 size_t nCmd;
525 int nHit = 0;
526 #if !defined(FOSSIL_ENABLE_SSL)
527 fossil_print("TLS disabled in this build\n");
528 #else
 
 
 
529 db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
530 db_open_config(1,0);
531 zCmd = g.argc>=3 ? g.argv[2] : "show";
532 nCmd = strlen(zCmd);
533 if( strncmp("show",zCmd,nCmd)==0 ){
534 const char *zName, *zValue;
535 size_t nName;
536 Stmt q;
537 fossil_print("OpenSSL-version: %s\n", SSLeay_version(SSLEAY_VERSION));
 
538 fossil_print("OpenSSL-cert-file: %s\n", X509_get_default_cert_file());
539 fossil_print("OpenSSL-cert-dir: %s\n", X509_get_default_cert_dir());
540 zName = X509_get_default_cert_file_env();
541 zValue = fossil_getenv(zName);
542 if( zValue==0 ) zValue = "";
543
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -24,19 +24,19 @@
24 ** SSL support is abstracted out into this module because Fossil can
25 ** be compiled without SSL support (which requires OpenSSL library)
26 */
27
28 #include "config.h"
29 #include "http_ssl.h"
30
31 #ifdef FOSSIL_ENABLE_SSL
32
33 #include <openssl/bio.h>
34 #include <openssl/ssl.h>
35 #include <openssl/err.h>
36 #include <openssl/x509.h>
37
 
38 #include <assert.h>
39 #include <sys/types.h>
40
41 /*
42 ** There can only be a single OpenSSL IO connection open at a time.
@@ -328,10 +328,11 @@
328 ssl_close();
329 return 1;
330 }
331
332 if( !sslNoCertVerify && SSL_get_verify_result(ssl)!=X509_V_OK ){
333 int x;
334 char *desc, *prompt;
335 Blob ans;
336 char cReply;
337 BIO *mem;
338 unsigned char md[32];
@@ -338,11 +339,17 @@
339 char zHash[32*2+1];
340 unsigned int mdLength = (int)sizeof(md);
341
342 memset(md, 0, sizeof(md));
343 zHash[0] = 0;
344 /* MMNNFFPPS */
345 #if OPENSSL_VERSION_NUMBER >= 0x010000000
346 x = X509_digest(cert, EVP_sha256(), md, &mdLength);
347 #else
348 x = X509_digest(cert, EVP_sha1(), md, &mdLength);
349 #endif
350 if( x ){
351 int j;
352 for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
353 zHash[j*2] = "0123456789abcdef"[md[j]>>4];
354 zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
355 }
@@ -518,25 +525,26 @@
525 ** for the domains listed. Or if
526 ** the --all option is specified,
527 ** remove all TLS cert exceptions.
528 */
529 void test_tlsconfig_info(void){
 
 
 
530 #if !defined(FOSSIL_ENABLE_SSL)
531 fossil_print("TLS disabled in this build\n");
532 #else
533 const char *zCmd;
534 size_t nCmd;
535 int nHit = 0;
536 db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
537 db_open_config(1,0);
538 zCmd = g.argc>=3 ? g.argv[2] : "show";
539 nCmd = strlen(zCmd);
540 if( strncmp("show",zCmd,nCmd)==0 ){
541 const char *zName, *zValue;
542 size_t nName;
543 Stmt q;
544 fossil_print("OpenSSL-version: %s (0x%09x)\n",
545 SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_NUMBER);
546 fossil_print("OpenSSL-cert-file: %s\n", X509_get_default_cert_file());
547 fossil_print("OpenSSL-cert-dir: %s\n", X509_get_default_cert_dir());
548 zName = X509_get_default_cert_file_env();
549 zValue = fossil_getenv(zName);
550 if( zValue==0 ) zValue = "";
551
+217 -140
--- src/info.c
+++ src/info.c
@@ -666,10 +666,11 @@
666666
const char *zOrigDate;
667667
int okWiki = 0;
668668
Blob wiki_read_links = BLOB_INITIALIZER;
669669
Blob wiki_add_links = BLOB_INITIALIZER;
670670
671
+ Th_Store("current_checkin", zName);
671672
style_header("Check-in [%S]", zUuid);
672673
login_anonymous_available();
673674
zEUser = db_text(0,
674675
"SELECT value FROM tagxref"
675676
" WHERE tagid=%d AND rid=%d AND tagtype>0",
@@ -1340,33 +1341,22 @@
13401341
13411342
/*
13421343
** Possible flags for the second parameter to
13431344
** object_description()
13441345
*/
1345
-#define OBJDESC_DETAIL 0x0001 /* more detail */
1346
+#define OBJDESC_DETAIL 0x0001 /* Show more detail */
13461347
#define OBJDESC_BASE 0x0002 /* Set <base> using this object */
13471348
#endif
13481349
13491350
/*
13501351
** Write a description of an object to the www reply.
1351
-**
1352
-** If the object is a file then mention:
1353
-**
1354
-** * It's artifact ID
1355
-** * All its filenames
1356
-** * The check-in it was part of, with times and users
1357
-**
1358
-** If the object is a manifest, then mention:
1359
-**
1360
-** * It's artifact ID
1361
-** * date of check-in
1362
-** * Comment & user
13631352
*/
13641353
int object_description(
1365
- int rid, /* The artifact ID */
1354
+ int rid, /* The artifact ID for the object to describe */
13661355
u32 objdescFlags, /* Flags to control display */
1367
- Blob *pDownloadName /* Fill with an appropriate download name */
1356
+ const char *zFileName, /* For file objects, use this name. Can be NULL */
1357
+ Blob *pDownloadName /* Fill with a good download name. Can be NULL */
13681358
){
13691359
Stmt q;
13701360
int cnt = 0;
13711361
int nWiki = 0;
13721362
int objType = 0;
@@ -1401,10 +1391,11 @@
14011391
const char *zVers = db_column_text(&q, 4);
14021392
int mPerm = db_column_int(&q, 5);
14031393
const char *zBr = db_column_text(&q, 6);
14041394
int szFile = db_column_int(&q,7);
14051395
int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1396
+ if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
14061397
if( sameFilename && !showDetail ){
14071398
if( cnt==1 ){
14081399
@ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
14091400
}
14101401
cnt++;
@@ -1671,12 +1662,12 @@
16711662
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
16721663
cookie_link_parameter("diff","diff","2");
16731664
diffType = atoi(PD("diff","2"));
16741665
cookie_render();
16751666
if( P("from") && P("to") ){
1676
- v1 = artifact_from_ci_and_filename(0, "from");
1677
- v2 = artifact_from_ci_and_filename(0, "to");
1667
+ v1 = artifact_from_ci_and_filename("from");
1668
+ v2 = artifact_from_ci_and_filename("to");
16781669
}else{
16791670
Stmt q;
16801671
v1 = name_to_rid_www("v1");
16811672
v2 = name_to_rid_www("v2");
16821673
@@ -1747,13 +1738,13 @@
17471738
@ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
17481739
@ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
17491740
}else{
17501741
@ <h2>Differences From
17511742
@ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1752
- object_description(v1, objdescFlags, 0);
1743
+ object_description(v1, objdescFlags,0, 0);
17531744
@ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1754
- object_description(v2, objdescFlags, 0);
1745
+ object_description(v2, objdescFlags,0, 0);
17551746
}
17561747
if( pRe ){
17571748
@ <b>Only differences that match regular expression "%h(zRe)"
17581749
@ are shown.</b>
17591750
}
@@ -1763,22 +1754,27 @@
17631754
style_footer();
17641755
}
17651756
17661757
/*
17671758
** WEBPAGE: raw
1768
-** URL: /raw?name=ARTIFACTID&m=TYPE
1759
+** URL: /raw/ARTIFACTID
17691760
** URL: /raw?ci=BRANCH&filename=NAME
17701761
**
1762
+** Additional query parameters:
1763
+**
1764
+** m=MIMETYPE The mimetype is MIMETYPE
1765
+** at=FILENAME Content-disposition; attachment; filename=FILENAME;
1766
+**
17711767
** Return the uninterpreted content of an artifact. Used primarily
17721768
** to view artifacts that are images.
17731769
*/
17741770
void rawartifact_page(void){
17751771
int rid = 0;
17761772
char *zUuid;
17771773
1778
- if( P("ci") && P("filename") ){
1779
- rid = artifact_from_ci_and_filename(0, 0);
1774
+ if( P("ci") ){
1775
+ rid = artifact_from_ci_and_filename(0);
17801776
}
17811777
if( rid==0 ){
17821778
rid = name_to_rid_www("name");
17831779
}
17841780
login_check_credentials();
@@ -1825,26 +1821,37 @@
18251821
** NULL, guess at the MIME-type based on the filename
18261822
** associated with the artifact.
18271823
*/
18281824
void deliver_artifact(int rid, const char *zMime){
18291825
Blob content;
1826
+ const char *zAttachName = P("at");
18301827
if( zMime==0 ){
1831
- char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1832
- " WHERE mlink.fid=%d"
1833
- " AND filename.fnid=mlink.fnid", rid);
1834
- if( !zFName ){
1828
+ char *zFN = (char*)zAttachName;
1829
+ if( zFN==0 ){
1830
+ zFN = db_text(0, "SELECT filename.name FROM mlink, filename"
1831
+ " WHERE mlink.fid=%d"
1832
+ " AND filename.fnid=mlink.fnid", rid);
1833
+ }
1834
+ if( zFN==0 ){
18351835
/* Look also at the attachment table */
1836
- zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837
- " WHERE blob.rid=%d"
1838
- " AND attachment.src=blob.uuid", rid);
1836
+ zFN = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837
+ " WHERE blob.rid=%d"
1838
+ " AND attachment.src=blob.uuid", rid);
1839
+ }
1840
+ if( zFN ){
1841
+ zMime = mimetype_from_name(zFN);
18391842
}
1840
- if( zFName ) zMime = mimetype_from_name(zFName);
1841
- if( zMime==0 ) zMime = "application/x-fossil-artifact";
1843
+ if( zMime==0 ){
1844
+ zMime = "application/x-fossil-artifact";
1845
+ }
18421846
}
18431847
content_get(rid, &content);
18441848
fossil_free(style_csp(1));
18451849
cgi_set_content_type(zMime);
1850
+ if( zAttachName ){
1851
+ cgi_content_disposition_filename(zAttachName);
1852
+ }
18461853
cgi_set_content(&content);
18471854
}
18481855
18491856
/*
18501857
** Render a hex dump of a file.
@@ -1937,13 +1944,13 @@
19371944
}else{
19381945
@ :</h2>
19391946
}
19401947
blob_zero(&downloadName);
19411948
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1942
- object_description(rid, objdescFlags, &downloadName);
1943
- style_submenu_element("Download", "%s/raw/%T?name=%s",
1944
- g.zTop, blob_str(&downloadName), zUuid);
1949
+ object_description(rid, objdescFlags, 0, &downloadName);
1950
+ style_submenu_element("Download", "%R/raw/%s?at=%T",
1951
+ zUuid, file_tail(blob_str(&downloadName)));
19451952
@ <hr />
19461953
content_get(rid, &content);
19471954
@ <blockquote><pre>
19481955
hexdump(&content);
19491956
@ </pre></blockquote>
@@ -1952,59 +1959,53 @@
19521959
19531960
/*
19541961
** Look for "ci" and "filename" query parameters. If found, try to
19551962
** use them to extract the record ID of an artifact for the file.
19561963
**
1957
-** Also look for "fn" as an alias for "filename". If either "filename"
1958
-** or "fn" is present but "ci" is missing, use "tip" as a default value
1959
-** for "ci".
1960
-**
1961
-** If zNameParam is not NULL, this use that parameter as the filename
1962
-** rather than "fn" or "filename".
1963
-**
1964
-** If pUrl is not NULL, then record the "ci" and "filename" values in
1965
-** pUrl.
1966
-**
1967
-** At least one of pUrl or zNameParam must be NULL.
1964
+** Also look for "fn" and "name" as an aliases for "filename". If any
1965
+** "filename" or "fn" or "name" are present but "ci" is missing, then
1966
+** use "tip" as the default value for "ci".
1967
+**
1968
+** If zNameParam is not NULL, then use that parameter as the filename
1969
+** rather than "fn" or "filename" or "name". the zNameParam is used
1970
+** for the from= and to= query parameters of /fdiff.
19681971
*/
1969
-int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){
1972
+int artifact_from_ci_and_filename(const char *zNameParam){
19701973
const char *zFilename;
19711974
const char *zCI;
19721975
int cirid;
19731976
Manifest *pManifest;
19741977
ManifestFile *pFile;
1978
+ int rid = 0;
19751979
19761980
if( zNameParam ){
19771981
zFilename = P(zNameParam);
19781982
}else{
19791983
zFilename = P("filename");
19801984
if( zFilename==0 ){
19811985
zFilename = P("fn");
19821986
}
1987
+ if( zFilename==0 ){
1988
+ zFilename = P("name");
1989
+ }
19831990
}
19841991
if( zFilename==0 ) return 0;
19851992
1986
- zCI = P("ci");
1987
- cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci");
1993
+ zCI = PD("ci", "tip");
1994
+ cirid = name_to_typed_rid(zCI, "ci");
19881995
if( cirid<=0 ) return 0;
19891996
pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
19901997
if( pManifest==0 ) return 0;
19911998
manifest_file_rewind(pManifest);
19921999
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
19932000
if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1994
- int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1995
- manifest_destroy(pManifest);
1996
- if( pUrl ){
1997
- assert( zNameParam==0 );
1998
- url_add_parameter(pUrl, "fn", zFilename);
1999
- if( zCI ) url_add_parameter(pUrl, "ci", zCI);
2000
- }
2001
- return rid;
2001
+ rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
2002
+ break;
20022003
}
20032004
}
20042005
manifest_destroy(pManifest);
2005
- return 0;
2006
+ return rid;
20062007
}
20072008
20082009
/*
20092010
** The "z" argument is a string that contains the text of a source code
20102011
** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2106,21 +2107,31 @@
21062107
** ln=N - highlight line number N
21072108
** ln=M-N - highlight lines M through N inclusive
21082109
** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
21092110
** verbose - show more detail in the description
21102111
** download - redirect to the download (artifact page only)
2111
-** name=SHA1HASH - Provide the SHA1HASH as a query parameter
2112
-** filename=NAME - Show information for content file NAME
2113
-** fn=NAME - "fn" is shorthand for "filename"
2114
-** ci=VERSION - The specific check-in to use for "filename=".
2112
+** name=NAME - filename or hash as a query parameter
2113
+** filename=NAME - alternative spelling for "name="
2114
+** fn=NAME - alternative spelling for "name="
2115
+** ci=VERSION - The specific check-in to use with "name=" to
2116
+** identify the file.
21152117
**
21162118
** The /artifact page show the complete content of a file
2117
-** identified by HASH as preformatted text. The
2118
-** /whatis page shows only a description of the file. The /file
2119
-** page shows the most recent version of the file or directory
2120
-** called NAME, or a list of the top-level directory if NAME is
2121
-** omitted.
2119
+** identified by HASH. The /whatis page shows only a description
2120
+** of how the artifact is used. The /file page shows the most recent
2121
+** version of the file or directory called NAME, or a list of the
2122
+** top-level directory if NAME is omitted.
2123
+**
2124
+** For /artifact and /whatis, the name= query parameter can refer to
2125
+** either the name of a file, or an artifact hash. If the ci= query
2126
+** parameter is also present, then name= must refer to a file name.
2127
+** If ci= is omitted, then the hash interpretation is preferred but
2128
+** if name= cannot be understood as a hash, a default "tip" value is
2129
+** used for ci=.
2130
+**
2131
+** For /file, name= can only be interpreted as a filename. As before,
2132
+** a default value of "tip" is used for ci= if ci= is omitted.
21222133
*/
21232134
void artifact_page(void){
21242135
int rid = 0;
21252136
Blob content;
21262137
const char *zMime;
@@ -2127,99 +2138,151 @@
21272138
Blob downloadName;
21282139
int renderAsWiki = 0;
21292140
int renderAsHtml = 0;
21302141
int objType;
21312142
int asText;
2132
- const char *zUuid;
2143
+ const char *zUuid = 0;
21332144
const char *zBr;
21342145
u32 objdescFlags = OBJDESC_BASE;
21352146
int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
21362147
int isFile = fossil_strcmp(g.zPath,"file")==0;
21372148
const char *zLn = P("ln");
21382149
const char *zName = P("name");
2139
- HQuery url;
2140
-
2141
- url_initialize(&url, g.zPath);
2142
- rid = artifact_from_ci_and_filename(&url, 0);
2143
- if( rid==0 ){
2144
- url_add_parameter(&url, "name", zName);
2145
- if( isFile ){
2146
- /* Do a top-level directory listing in /file mode if no argument
2147
- ** specified */
2148
- if( zName==0 || zName[0]==0 ){
2149
- if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2150
- page_tree();
2151
- return;
2152
- }
2153
- /* Look for a single file with the given name */
2154
- rid = db_int(0,
2155
- "SELECT fid FROM filename, mlink, event"
2156
- " WHERE name=%Q"
2157
- " AND mlink.fnid=filename.fnid"
2158
- " AND event.objid=mlink.mid"
2159
- " ORDER BY event.mtime DESC LIMIT 1",
2160
- zName
2161
- );
2162
- /* If no file called NAME exists, instead look for a directory
2163
- ** with that name, and do a directory listing */
2164
- if( rid==0 ){
2165
- int nName = (int)strlen(zName);
2166
- if( nName && zName[nName-1]=='/' ) nName--;
2167
- if( db_exists(
2168
- "SELECT 1 FROM filename"
2169
- " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2170
- nName, zName, nName+1, nName, zName
2171
- ) ){
2172
- if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2173
- page_tree();
2174
- return;
2175
- }
2176
- }
2177
- /* If no file or directory called NAME: issue an error */
2178
- if( rid==0 ){
2179
- style_header("No such file");
2180
- @ File '%h(zName)' does not exist in this repository.
2181
- style_footer();
2182
- return;
2183
- }
2184
- }else{
2185
- rid = name_to_rid_www("name");
2186
- }
2187
- }
2188
-
2189
- login_check_credentials();
2190
- if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2191
- if( rid==0 ){
2192
- style_header("No such artifact");
2193
- @ Artifact '%h(zName)' does not exist in this repository.
2194
- style_footer();
2195
- return;
2196
- }
2150
+ const char *zCI = P("ci");
2151
+ HQuery url;
2152
+ char *zCIUuid = 0;
2153
+ int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2154
+ int isBranchCI = 0; /* ci= refers to a branch name */
2155
+ char *zHeader = 0;
2156
+
2157
+ login_check_credentials();
2158
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2159
+
2160
+ /* Capture and normalize the name= and ci= query parameters */
2161
+ if( zName==0 ){
2162
+ zName = P("filename");
2163
+ if( zName==0 ){
2164
+ zName = P("fn");
2165
+ }
2166
+ }
2167
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2168
+ if( zCI
2169
+ && name_to_uuid2(zCI, "ci", &zCIUuid)
2170
+ && sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI))!=0
2171
+ ){
2172
+ isSymbolicCI = 1;
2173
+ isBranchCI = branch_includes_uuid(zCI, zCIUuid);
2174
+ }
2175
+
2176
+ /* The name= query parameter (or at least one of its alternative
2177
+ ** spellings) is required. Except for /file, show a top-level
2178
+ ** directory listing if name= is omitted.
2179
+ */
2180
+ if( zName==0 ){
2181
+ if( isFile ){
2182
+ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2183
+ page_tree();
2184
+ return;
2185
+ }
2186
+ style_header("Missing name= query parameter");
2187
+ @ The name= query parameter is missing
2188
+ style_footer();
2189
+ return;
2190
+ }
2191
+
2192
+ url_initialize(&url, g.zPath);
2193
+ url_add_parameter(&url, "name", zName);
2194
+ url_add_parameter(&url, "ci", zCI);
2195
+
2196
+ if( zCI==0 && !isFile ){
2197
+ /* If there is no ci= query parameter, then prefer to interpret
2198
+ ** name= as a hash for /artifact and /whatis. But for not for /file.
2199
+ ** For /file, a name= without a ci= while prefer to use the default
2200
+ ** "tip" value for ci=. */
2201
+ rid = name_to_rid(zName);
2202
+ }
2203
+ if( rid==0 ){
2204
+ rid = artifact_from_ci_and_filename(0);
2205
+ }
2206
+
2207
+ if( rid==0 ){ /* Artifact not found */
2208
+ if( isFile ){
2209
+ /* For /file, also check to see if name= refers to a directory,
2210
+ ** and if so, do a listing for that directory */
2211
+ int nName = (int)strlen(zName);
2212
+ if( nName && zName[nName-1]=='/' ) nName--;
2213
+ if( db_exists(
2214
+ "SELECT 1 FROM filename"
2215
+ " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2216
+ nName, zName, nName+1, nName, zName
2217
+ ) ){
2218
+ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2219
+ page_tree();
2220
+ return;
2221
+ }
2222
+ style_header("No such file");
2223
+ @ File '%h(zName)' does not exist in this repository.
2224
+ }else{
2225
+ style_header("No such artifact");
2226
+ @ Artifact '%h(zName)' does not exist in this repository.
2227
+ }
2228
+ style_footer();
2229
+ return;
2230
+ }
2231
+
21972232
if( descOnly || P("verbose")!=0 ){
21982233
url_add_parameter(&url, "verbose", "1");
21992234
objdescFlags |= OBJDESC_DETAIL;
22002235
}
22012236
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2237
+
2238
+ asText = P("txt")!=0;
22022239
if( isFile ){
2203
- @ <h2>Latest version of file '%h(zName)':</h2>
2240
+ if( zCI==0 || fossil_strcmp(zCI,"tip")==0 ){
2241
+ zCI = "tip";
2242
+ @ <h2>File %z(href("%R/finfo?name=%T&m=tip",zName))%h(zName)</a>
2243
+ @ from the %z(href("%R/info/tip"))latest check-in</a></h2>
2244
+ }else{
2245
+ const char *zPath;
2246
+ Blob path;
2247
+ blob_zero(&path);
2248
+ hyperlinked_path(zName, &path, zCI, "dir", "", LINKPATH_FINFO);
2249
+ zPath = blob_str(&path);
2250
+ @ <h2>File %s(zPath) \
2251
+ if( isBranchCI ){
2252
+ @ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
2253
+ }else if( isSymbolicCI ){
2254
+ @ as of check-in %z(href("%R/info/%!S",zCIUuid))%s(zCI)</a></h2>
2255
+ }else{
2256
+ @ as of check-in [%z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
2257
+ }
2258
+ blob_reset(&path);
2259
+ }
22042260
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2261
+ style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T",
2262
+ zName, zCI);
2263
+ style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T",
2264
+ zName, zCI);
2265
+ blob_init(&downloadName, zName, -1);
2266
+ objType = OBJTYPE_CONTENT;
22052267
}else{
22062268
@ <h2>Artifact
22072269
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
22082270
if( g.perm.Setup ){
22092271
@ (%d(rid)):</h2>
22102272
}else{
22112273
@ :</h2>
22122274
}
2275
+ blob_zero(&downloadName);
2276
+ if( asText ) objdescFlags &= ~OBJDESC_BASE;
2277
+ objType = object_description(rid, objdescFlags,
2278
+ (isFile?zName:0), &downloadName);
22132279
}
2214
- blob_zero(&downloadName);
2215
- asText = P("txt")!=0;
2216
- if( asText ) objdescFlags &= ~OBJDESC_BASE;
2217
- objType = object_description(rid, objdescFlags, &downloadName);
22182280
if( !descOnly && P("download")!=0 ){
2219
- cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2220
- db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2281
+ cgi_redirectf("%R/raw/%s?at=%T",
2282
+ db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
2283
+ file_tail(blob_str(&downloadName)));
22212284
/*NOTREACHED*/
22222285
}
22232286
if( g.perm.Admin ){
22242287
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
22252288
if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2227,13 +2290,28 @@
22272290
g.zTop, zUuid);
22282291
}else{
22292292
style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
22302293
}
22312294
}
2232
- style_header("%s", isFile ? "File Content" :
2233
- descOnly ? "Artifact Description" : "Artifact Content");
2234
- if( g.perm.Admin ){
2295
+
2296
+ if( isFile ){
2297
+ if( isSymbolicCI ){
2298
+ zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2299
+ }else if( zCI ){
2300
+ zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2301
+ }else{
2302
+ zHeader = mprintf("%s", file_tail(zName));
2303
+ }
2304
+ }else if( descOnly ){
2305
+ zHeader = mprintf("Artifact Description [%S]", zUuid);
2306
+ }else{
2307
+ zHeader = mprintf("Artifact [%S]", zUuid);
2308
+ }
2309
+ style_header("%s", zHeader);
2310
+ fossil_free(zCIUuid);
2311
+ fossil_free(zHeader);
2312
+ if( !isFile && g.perm.Admin ){
22352313
Stmt q;
22362314
db_prepare(&q,
22372315
"SELECT coalesce(user.login,rcvfrom.uid),"
22382316
" datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
22392317
" FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
@@ -2253,12 +2331,11 @@
22532331
zBr, blob_str(&downloadName));
22542332
style_submenu_element("Tip", "%R/file/%T?ci=%T",
22552333
blob_str(&downloadName), zBr);
22562334
fossil_free((void *)zBr);
22572335
}
2258
- style_submenu_element("Download", "%R/raw/%T?name=%s",
2259
- blob_str(&downloadName), zUuid);
2336
+ style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName));
22602337
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
22612338
style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
22622339
}
22632340
zMime = mimetype_from_name(blob_str(&downloadName));
22642341
if( zMime ){
@@ -2288,11 +2365,11 @@
22882365
@ <hr />
22892366
content_get(rid, &content);
22902367
if( renderAsWiki ){
22912368
wiki_render_by_mimetype(&content, zMime);
22922369
}else if( renderAsHtml ){
2293
- @ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)"
2370
+ @ <iframe src="%R/raw/%s(zUuid)"
22942371
@ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
22952372
@ sandbox="allow-same-origin" id="ifm1">
22962373
@ </iframe>
22972374
@ <script nonce="%h(style_nonce())">
22982375
@ document.getElementById("ifm1").addEventListener("load",
@@ -2717,15 +2794,15 @@
27172794
**
27182795
** Edit a check-in. (Check-ins are immutable and do not really change.
27192796
** This page really creates supplemental tags that affect the display
27202797
** of the check-in.)
27212798
**
2722
-** Query parmeters:
2799
+** Query parameters:
27232800
**
27242801
** rid=INTEGER Record ID of the check-in to edit (REQUIRED)
27252802
**
2726
-** POST parameters after pressing "Perview", "Cancel", or "Apply":
2803
+** POST parameters after pressing "Preview", "Cancel", or "Apply":
27272804
**
27282805
** c=TEXT New check-in comment
27292806
** u=TEXT New user name
27302807
** newclr Apply a background color
27312808
** clr=TEXT New background color (only if newclr)
27322809
--- src/info.c
+++ src/info.c
@@ -666,10 +666,11 @@
666 const char *zOrigDate;
667 int okWiki = 0;
668 Blob wiki_read_links = BLOB_INITIALIZER;
669 Blob wiki_add_links = BLOB_INITIALIZER;
670
 
671 style_header("Check-in [%S]", zUuid);
672 login_anonymous_available();
673 zEUser = db_text(0,
674 "SELECT value FROM tagxref"
675 " WHERE tagid=%d AND rid=%d AND tagtype>0",
@@ -1340,33 +1341,22 @@
1340
1341 /*
1342 ** Possible flags for the second parameter to
1343 ** object_description()
1344 */
1345 #define OBJDESC_DETAIL 0x0001 /* more detail */
1346 #define OBJDESC_BASE 0x0002 /* Set <base> using this object */
1347 #endif
1348
1349 /*
1350 ** Write a description of an object to the www reply.
1351 **
1352 ** If the object is a file then mention:
1353 **
1354 ** * It's artifact ID
1355 ** * All its filenames
1356 ** * The check-in it was part of, with times and users
1357 **
1358 ** If the object is a manifest, then mention:
1359 **
1360 ** * It's artifact ID
1361 ** * date of check-in
1362 ** * Comment & user
1363 */
1364 int object_description(
1365 int rid, /* The artifact ID */
1366 u32 objdescFlags, /* Flags to control display */
1367 Blob *pDownloadName /* Fill with an appropriate download name */
 
1368 ){
1369 Stmt q;
1370 int cnt = 0;
1371 int nWiki = 0;
1372 int objType = 0;
@@ -1401,10 +1391,11 @@
1401 const char *zVers = db_column_text(&q, 4);
1402 int mPerm = db_column_int(&q, 5);
1403 const char *zBr = db_column_text(&q, 6);
1404 int szFile = db_column_int(&q,7);
1405 int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
 
1406 if( sameFilename && !showDetail ){
1407 if( cnt==1 ){
1408 @ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
1409 }
1410 cnt++;
@@ -1671,12 +1662,12 @@
1671 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1672 cookie_link_parameter("diff","diff","2");
1673 diffType = atoi(PD("diff","2"));
1674 cookie_render();
1675 if( P("from") && P("to") ){
1676 v1 = artifact_from_ci_and_filename(0, "from");
1677 v2 = artifact_from_ci_and_filename(0, "to");
1678 }else{
1679 Stmt q;
1680 v1 = name_to_rid_www("v1");
1681 v2 = name_to_rid_www("v2");
1682
@@ -1747,13 +1738,13 @@
1747 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1748 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1749 }else{
1750 @ <h2>Differences From
1751 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1752 object_description(v1, objdescFlags, 0);
1753 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1754 object_description(v2, objdescFlags, 0);
1755 }
1756 if( pRe ){
1757 @ <b>Only differences that match regular expression "%h(zRe)"
1758 @ are shown.</b>
1759 }
@@ -1763,22 +1754,27 @@
1763 style_footer();
1764 }
1765
1766 /*
1767 ** WEBPAGE: raw
1768 ** URL: /raw?name=ARTIFACTID&m=TYPE
1769 ** URL: /raw?ci=BRANCH&filename=NAME
1770 **
 
 
 
 
 
1771 ** Return the uninterpreted content of an artifact. Used primarily
1772 ** to view artifacts that are images.
1773 */
1774 void rawartifact_page(void){
1775 int rid = 0;
1776 char *zUuid;
1777
1778 if( P("ci") && P("filename") ){
1779 rid = artifact_from_ci_and_filename(0, 0);
1780 }
1781 if( rid==0 ){
1782 rid = name_to_rid_www("name");
1783 }
1784 login_check_credentials();
@@ -1825,26 +1821,37 @@
1825 ** NULL, guess at the MIME-type based on the filename
1826 ** associated with the artifact.
1827 */
1828 void deliver_artifact(int rid, const char *zMime){
1829 Blob content;
 
1830 if( zMime==0 ){
1831 char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1832 " WHERE mlink.fid=%d"
1833 " AND filename.fnid=mlink.fnid", rid);
1834 if( !zFName ){
 
 
 
1835 /* Look also at the attachment table */
1836 zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837 " WHERE blob.rid=%d"
1838 " AND attachment.src=blob.uuid", rid);
 
 
 
1839 }
1840 if( zFName ) zMime = mimetype_from_name(zFName);
1841 if( zMime==0 ) zMime = "application/x-fossil-artifact";
 
1842 }
1843 content_get(rid, &content);
1844 fossil_free(style_csp(1));
1845 cgi_set_content_type(zMime);
 
 
 
1846 cgi_set_content(&content);
1847 }
1848
1849 /*
1850 ** Render a hex dump of a file.
@@ -1937,13 +1944,13 @@
1937 }else{
1938 @ :</h2>
1939 }
1940 blob_zero(&downloadName);
1941 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1942 object_description(rid, objdescFlags, &downloadName);
1943 style_submenu_element("Download", "%s/raw/%T?name=%s",
1944 g.zTop, blob_str(&downloadName), zUuid);
1945 @ <hr />
1946 content_get(rid, &content);
1947 @ <blockquote><pre>
1948 hexdump(&content);
1949 @ </pre></blockquote>
@@ -1952,59 +1959,53 @@
1952
1953 /*
1954 ** Look for "ci" and "filename" query parameters. If found, try to
1955 ** use them to extract the record ID of an artifact for the file.
1956 **
1957 ** Also look for "fn" as an alias for "filename". If either "filename"
1958 ** or "fn" is present but "ci" is missing, use "tip" as a default value
1959 ** for "ci".
1960 **
1961 ** If zNameParam is not NULL, this use that parameter as the filename
1962 ** rather than "fn" or "filename".
1963 **
1964 ** If pUrl is not NULL, then record the "ci" and "filename" values in
1965 ** pUrl.
1966 **
1967 ** At least one of pUrl or zNameParam must be NULL.
1968 */
1969 int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){
1970 const char *zFilename;
1971 const char *zCI;
1972 int cirid;
1973 Manifest *pManifest;
1974 ManifestFile *pFile;
 
1975
1976 if( zNameParam ){
1977 zFilename = P(zNameParam);
1978 }else{
1979 zFilename = P("filename");
1980 if( zFilename==0 ){
1981 zFilename = P("fn");
1982 }
 
 
 
1983 }
1984 if( zFilename==0 ) return 0;
1985
1986 zCI = P("ci");
1987 cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci");
1988 if( cirid<=0 ) return 0;
1989 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1990 if( pManifest==0 ) return 0;
1991 manifest_file_rewind(pManifest);
1992 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1993 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1994 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1995 manifest_destroy(pManifest);
1996 if( pUrl ){
1997 assert( zNameParam==0 );
1998 url_add_parameter(pUrl, "fn", zFilename);
1999 if( zCI ) url_add_parameter(pUrl, "ci", zCI);
2000 }
2001 return rid;
2002 }
2003 }
2004 manifest_destroy(pManifest);
2005 return 0;
2006 }
2007
2008 /*
2009 ** The "z" argument is a string that contains the text of a source code
2010 ** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2106,21 +2107,31 @@
2106 ** ln=N - highlight line number N
2107 ** ln=M-N - highlight lines M through N inclusive
2108 ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
2109 ** verbose - show more detail in the description
2110 ** download - redirect to the download (artifact page only)
2111 ** name=SHA1HASH - Provide the SHA1HASH as a query parameter
2112 ** filename=NAME - Show information for content file NAME
2113 ** fn=NAME - "fn" is shorthand for "filename"
2114 ** ci=VERSION - The specific check-in to use for "filename=".
 
2115 **
2116 ** The /artifact page show the complete content of a file
2117 ** identified by HASH as preformatted text. The
2118 ** /whatis page shows only a description of the file. The /file
2119 ** page shows the most recent version of the file or directory
2120 ** called NAME, or a list of the top-level directory if NAME is
2121 ** omitted.
 
 
 
 
 
 
 
 
 
2122 */
2123 void artifact_page(void){
2124 int rid = 0;
2125 Blob content;
2126 const char *zMime;
@@ -2127,99 +2138,151 @@
2127 Blob downloadName;
2128 int renderAsWiki = 0;
2129 int renderAsHtml = 0;
2130 int objType;
2131 int asText;
2132 const char *zUuid;
2133 const char *zBr;
2134 u32 objdescFlags = OBJDESC_BASE;
2135 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2136 int isFile = fossil_strcmp(g.zPath,"file")==0;
2137 const char *zLn = P("ln");
2138 const char *zName = P("name");
2139 HQuery url;
2140
2141 url_initialize(&url, g.zPath);
2142 rid = artifact_from_ci_and_filename(&url, 0);
2143 if( rid==0 ){
2144 url_add_parameter(&url, "name", zName);
2145 if( isFile ){
2146 /* Do a top-level directory listing in /file mode if no argument
2147 ** specified */
2148 if( zName==0 || zName[0]==0 ){
2149 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2150 page_tree();
2151 return;
2152 }
2153 /* Look for a single file with the given name */
2154 rid = db_int(0,
2155 "SELECT fid FROM filename, mlink, event"
2156 " WHERE name=%Q"
2157 " AND mlink.fnid=filename.fnid"
2158 " AND event.objid=mlink.mid"
2159 " ORDER BY event.mtime DESC LIMIT 1",
2160 zName
2161 );
2162 /* If no file called NAME exists, instead look for a directory
2163 ** with that name, and do a directory listing */
2164 if( rid==0 ){
2165 int nName = (int)strlen(zName);
2166 if( nName && zName[nName-1]=='/' ) nName--;
2167 if( db_exists(
2168 "SELECT 1 FROM filename"
2169 " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2170 nName, zName, nName+1, nName, zName
2171 ) ){
2172 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2173 page_tree();
2174 return;
2175 }
2176 }
2177 /* If no file or directory called NAME: issue an error */
2178 if( rid==0 ){
2179 style_header("No such file");
2180 @ File '%h(zName)' does not exist in this repository.
2181 style_footer();
2182 return;
2183 }
2184 }else{
2185 rid = name_to_rid_www("name");
2186 }
2187 }
2188
2189 login_check_credentials();
2190 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2191 if( rid==0 ){
2192 style_header("No such artifact");
2193 @ Artifact '%h(zName)' does not exist in this repository.
2194 style_footer();
2195 return;
2196 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2197 if( descOnly || P("verbose")!=0 ){
2198 url_add_parameter(&url, "verbose", "1");
2199 objdescFlags |= OBJDESC_DETAIL;
2200 }
2201 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
 
 
2202 if( isFile ){
2203 @ <h2>Latest version of file '%h(zName)':</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2204 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
 
 
 
 
 
 
2205 }else{
2206 @ <h2>Artifact
2207 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2208 if( g.perm.Setup ){
2209 @ (%d(rid)):</h2>
2210 }else{
2211 @ :</h2>
2212 }
 
 
 
 
2213 }
2214 blob_zero(&downloadName);
2215 asText = P("txt")!=0;
2216 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2217 objType = object_description(rid, objdescFlags, &downloadName);
2218 if( !descOnly && P("download")!=0 ){
2219 cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2220 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
 
2221 /*NOTREACHED*/
2222 }
2223 if( g.perm.Admin ){
2224 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
2225 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2227,13 +2290,28 @@
2227 g.zTop, zUuid);
2228 }else{
2229 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2230 }
2231 }
2232 style_header("%s", isFile ? "File Content" :
2233 descOnly ? "Artifact Description" : "Artifact Content");
2234 if( g.perm.Admin ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2235 Stmt q;
2236 db_prepare(&q,
2237 "SELECT coalesce(user.login,rcvfrom.uid),"
2238 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2239 " FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
@@ -2253,12 +2331,11 @@
2253 zBr, blob_str(&downloadName));
2254 style_submenu_element("Tip", "%R/file/%T?ci=%T",
2255 blob_str(&downloadName), zBr);
2256 fossil_free((void *)zBr);
2257 }
2258 style_submenu_element("Download", "%R/raw/%T?name=%s",
2259 blob_str(&downloadName), zUuid);
2260 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
2261 style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
2262 }
2263 zMime = mimetype_from_name(blob_str(&downloadName));
2264 if( zMime ){
@@ -2288,11 +2365,11 @@
2288 @ <hr />
2289 content_get(rid, &content);
2290 if( renderAsWiki ){
2291 wiki_render_by_mimetype(&content, zMime);
2292 }else if( renderAsHtml ){
2293 @ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)"
2294 @ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
2295 @ sandbox="allow-same-origin" id="ifm1">
2296 @ </iframe>
2297 @ <script nonce="%h(style_nonce())">
2298 @ document.getElementById("ifm1").addEventListener("load",
@@ -2717,15 +2794,15 @@
2717 **
2718 ** Edit a check-in. (Check-ins are immutable and do not really change.
2719 ** This page really creates supplemental tags that affect the display
2720 ** of the check-in.)
2721 **
2722 ** Query parmeters:
2723 **
2724 ** rid=INTEGER Record ID of the check-in to edit (REQUIRED)
2725 **
2726 ** POST parameters after pressing "Perview", "Cancel", or "Apply":
2727 **
2728 ** c=TEXT New check-in comment
2729 ** u=TEXT New user name
2730 ** newclr Apply a background color
2731 ** clr=TEXT New background color (only if newclr)
2732
--- src/info.c
+++ src/info.c
@@ -666,10 +666,11 @@
666 const char *zOrigDate;
667 int okWiki = 0;
668 Blob wiki_read_links = BLOB_INITIALIZER;
669 Blob wiki_add_links = BLOB_INITIALIZER;
670
671 Th_Store("current_checkin", zName);
672 style_header("Check-in [%S]", zUuid);
673 login_anonymous_available();
674 zEUser = db_text(0,
675 "SELECT value FROM tagxref"
676 " WHERE tagid=%d AND rid=%d AND tagtype>0",
@@ -1340,33 +1341,22 @@
1341
1342 /*
1343 ** Possible flags for the second parameter to
1344 ** object_description()
1345 */
1346 #define OBJDESC_DETAIL 0x0001 /* Show more detail */
1347 #define OBJDESC_BASE 0x0002 /* Set <base> using this object */
1348 #endif
1349
1350 /*
1351 ** Write a description of an object to the www reply.
 
 
 
 
 
 
 
 
 
 
 
 
1352 */
1353 int object_description(
1354 int rid, /* The artifact ID for the object to describe */
1355 u32 objdescFlags, /* Flags to control display */
1356 const char *zFileName, /* For file objects, use this name. Can be NULL */
1357 Blob *pDownloadName /* Fill with a good download name. Can be NULL */
1358 ){
1359 Stmt q;
1360 int cnt = 0;
1361 int nWiki = 0;
1362 int objType = 0;
@@ -1401,10 +1391,11 @@
1391 const char *zVers = db_column_text(&q, 4);
1392 int mPerm = db_column_int(&q, 5);
1393 const char *zBr = db_column_text(&q, 6);
1394 int szFile = db_column_int(&q,7);
1395 int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1396 if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
1397 if( sameFilename && !showDetail ){
1398 if( cnt==1 ){
1399 @ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
1400 }
1401 cnt++;
@@ -1671,12 +1662,12 @@
1662 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1663 cookie_link_parameter("diff","diff","2");
1664 diffType = atoi(PD("diff","2"));
1665 cookie_render();
1666 if( P("from") && P("to") ){
1667 v1 = artifact_from_ci_and_filename("from");
1668 v2 = artifact_from_ci_and_filename("to");
1669 }else{
1670 Stmt q;
1671 v1 = name_to_rid_www("v1");
1672 v2 = name_to_rid_www("v2");
1673
@@ -1747,13 +1738,13 @@
1738 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1739 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1740 }else{
1741 @ <h2>Differences From
1742 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1743 object_description(v1, objdescFlags,0, 0);
1744 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1745 object_description(v2, objdescFlags,0, 0);
1746 }
1747 if( pRe ){
1748 @ <b>Only differences that match regular expression "%h(zRe)"
1749 @ are shown.</b>
1750 }
@@ -1763,22 +1754,27 @@
1754 style_footer();
1755 }
1756
1757 /*
1758 ** WEBPAGE: raw
1759 ** URL: /raw/ARTIFACTID
1760 ** URL: /raw?ci=BRANCH&filename=NAME
1761 **
1762 ** Additional query parameters:
1763 **
1764 ** m=MIMETYPE The mimetype is MIMETYPE
1765 ** at=FILENAME Content-disposition; attachment; filename=FILENAME;
1766 **
1767 ** Return the uninterpreted content of an artifact. Used primarily
1768 ** to view artifacts that are images.
1769 */
1770 void rawartifact_page(void){
1771 int rid = 0;
1772 char *zUuid;
1773
1774 if( P("ci") ){
1775 rid = artifact_from_ci_and_filename(0);
1776 }
1777 if( rid==0 ){
1778 rid = name_to_rid_www("name");
1779 }
1780 login_check_credentials();
@@ -1825,26 +1821,37 @@
1821 ** NULL, guess at the MIME-type based on the filename
1822 ** associated with the artifact.
1823 */
1824 void deliver_artifact(int rid, const char *zMime){
1825 Blob content;
1826 const char *zAttachName = P("at");
1827 if( zMime==0 ){
1828 char *zFN = (char*)zAttachName;
1829 if( zFN==0 ){
1830 zFN = db_text(0, "SELECT filename.name FROM mlink, filename"
1831 " WHERE mlink.fid=%d"
1832 " AND filename.fnid=mlink.fnid", rid);
1833 }
1834 if( zFN==0 ){
1835 /* Look also at the attachment table */
1836 zFN = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837 " WHERE blob.rid=%d"
1838 " AND attachment.src=blob.uuid", rid);
1839 }
1840 if( zFN ){
1841 zMime = mimetype_from_name(zFN);
1842 }
1843 if( zMime==0 ){
1844 zMime = "application/x-fossil-artifact";
1845 }
1846 }
1847 content_get(rid, &content);
1848 fossil_free(style_csp(1));
1849 cgi_set_content_type(zMime);
1850 if( zAttachName ){
1851 cgi_content_disposition_filename(zAttachName);
1852 }
1853 cgi_set_content(&content);
1854 }
1855
1856 /*
1857 ** Render a hex dump of a file.
@@ -1937,13 +1944,13 @@
1944 }else{
1945 @ :</h2>
1946 }
1947 blob_zero(&downloadName);
1948 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1949 object_description(rid, objdescFlags, 0, &downloadName);
1950 style_submenu_element("Download", "%R/raw/%s?at=%T",
1951 zUuid, file_tail(blob_str(&downloadName)));
1952 @ <hr />
1953 content_get(rid, &content);
1954 @ <blockquote><pre>
1955 hexdump(&content);
1956 @ </pre></blockquote>
@@ -1952,59 +1959,53 @@
1959
1960 /*
1961 ** Look for "ci" and "filename" query parameters. If found, try to
1962 ** use them to extract the record ID of an artifact for the file.
1963 **
1964 ** Also look for "fn" and "name" as an aliases for "filename". If any
1965 ** "filename" or "fn" or "name" are present but "ci" is missing, then
1966 ** use "tip" as the default value for "ci".
1967 **
1968 ** If zNameParam is not NULL, then use that parameter as the filename
1969 ** rather than "fn" or "filename" or "name". the zNameParam is used
1970 ** for the from= and to= query parameters of /fdiff.
 
 
 
 
1971 */
1972 int artifact_from_ci_and_filename(const char *zNameParam){
1973 const char *zFilename;
1974 const char *zCI;
1975 int cirid;
1976 Manifest *pManifest;
1977 ManifestFile *pFile;
1978 int rid = 0;
1979
1980 if( zNameParam ){
1981 zFilename = P(zNameParam);
1982 }else{
1983 zFilename = P("filename");
1984 if( zFilename==0 ){
1985 zFilename = P("fn");
1986 }
1987 if( zFilename==0 ){
1988 zFilename = P("name");
1989 }
1990 }
1991 if( zFilename==0 ) return 0;
1992
1993 zCI = PD("ci", "tip");
1994 cirid = name_to_typed_rid(zCI, "ci");
1995 if( cirid<=0 ) return 0;
1996 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1997 if( pManifest==0 ) return 0;
1998 manifest_file_rewind(pManifest);
1999 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
2000 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
2001 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
2002 break;
 
 
 
 
 
 
2003 }
2004 }
2005 manifest_destroy(pManifest);
2006 return rid;
2007 }
2008
2009 /*
2010 ** The "z" argument is a string that contains the text of a source code
2011 ** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2106,21 +2107,31 @@
2107 ** ln=N - highlight line number N
2108 ** ln=M-N - highlight lines M through N inclusive
2109 ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
2110 ** verbose - show more detail in the description
2111 ** download - redirect to the download (artifact page only)
2112 ** name=NAME - filename or hash as a query parameter
2113 ** filename=NAME - alternative spelling for "name="
2114 ** fn=NAME - alternative spelling for "name="
2115 ** ci=VERSION - The specific check-in to use with "name=" to
2116 ** identify the file.
2117 **
2118 ** The /artifact page show the complete content of a file
2119 ** identified by HASH. The /whatis page shows only a description
2120 ** of how the artifact is used. The /file page shows the most recent
2121 ** version of the file or directory called NAME, or a list of the
2122 ** top-level directory if NAME is omitted.
2123 **
2124 ** For /artifact and /whatis, the name= query parameter can refer to
2125 ** either the name of a file, or an artifact hash. If the ci= query
2126 ** parameter is also present, then name= must refer to a file name.
2127 ** If ci= is omitted, then the hash interpretation is preferred but
2128 ** if name= cannot be understood as a hash, a default "tip" value is
2129 ** used for ci=.
2130 **
2131 ** For /file, name= can only be interpreted as a filename. As before,
2132 ** a default value of "tip" is used for ci= if ci= is omitted.
2133 */
2134 void artifact_page(void){
2135 int rid = 0;
2136 Blob content;
2137 const char *zMime;
@@ -2127,99 +2138,151 @@
2138 Blob downloadName;
2139 int renderAsWiki = 0;
2140 int renderAsHtml = 0;
2141 int objType;
2142 int asText;
2143 const char *zUuid = 0;
2144 const char *zBr;
2145 u32 objdescFlags = OBJDESC_BASE;
2146 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2147 int isFile = fossil_strcmp(g.zPath,"file")==0;
2148 const char *zLn = P("ln");
2149 const char *zName = P("name");
2150 const char *zCI = P("ci");
2151 HQuery url;
2152 char *zCIUuid = 0;
2153 int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2154 int isBranchCI = 0; /* ci= refers to a branch name */
2155 char *zHeader = 0;
2156
2157 login_check_credentials();
2158 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2159
2160 /* Capture and normalize the name= and ci= query parameters */
2161 if( zName==0 ){
2162 zName = P("filename");
2163 if( zName==0 ){
2164 zName = P("fn");
2165 }
2166 }
2167 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2168 if( zCI
2169 && name_to_uuid2(zCI, "ci", &zCIUuid)
2170 && sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI))!=0
2171 ){
2172 isSymbolicCI = 1;
2173 isBranchCI = branch_includes_uuid(zCI, zCIUuid);
2174 }
2175
2176 /* The name= query parameter (or at least one of its alternative
2177 ** spellings) is required. Except for /file, show a top-level
2178 ** directory listing if name= is omitted.
2179 */
2180 if( zName==0 ){
2181 if( isFile ){
2182 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2183 page_tree();
2184 return;
2185 }
2186 style_header("Missing name= query parameter");
2187 @ The name= query parameter is missing
2188 style_footer();
2189 return;
2190 }
2191
2192 url_initialize(&url, g.zPath);
2193 url_add_parameter(&url, "name", zName);
2194 url_add_parameter(&url, "ci", zCI);
2195
2196 if( zCI==0 && !isFile ){
2197 /* If there is no ci= query parameter, then prefer to interpret
2198 ** name= as a hash for /artifact and /whatis. But for not for /file.
2199 ** For /file, a name= without a ci= while prefer to use the default
2200 ** "tip" value for ci=. */
2201 rid = name_to_rid(zName);
2202 }
2203 if( rid==0 ){
2204 rid = artifact_from_ci_and_filename(0);
2205 }
2206
2207 if( rid==0 ){ /* Artifact not found */
2208 if( isFile ){
2209 /* For /file, also check to see if name= refers to a directory,
2210 ** and if so, do a listing for that directory */
2211 int nName = (int)strlen(zName);
2212 if( nName && zName[nName-1]=='/' ) nName--;
2213 if( db_exists(
2214 "SELECT 1 FROM filename"
2215 " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2216 nName, zName, nName+1, nName, zName
2217 ) ){
2218 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2219 page_tree();
2220 return;
2221 }
2222 style_header("No such file");
2223 @ File '%h(zName)' does not exist in this repository.
2224 }else{
2225 style_header("No such artifact");
2226 @ Artifact '%h(zName)' does not exist in this repository.
2227 }
2228 style_footer();
2229 return;
2230 }
2231
2232 if( descOnly || P("verbose")!=0 ){
2233 url_add_parameter(&url, "verbose", "1");
2234 objdescFlags |= OBJDESC_DETAIL;
2235 }
2236 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2237
2238 asText = P("txt")!=0;
2239 if( isFile ){
2240 if( zCI==0 || fossil_strcmp(zCI,"tip")==0 ){
2241 zCI = "tip";
2242 @ <h2>File %z(href("%R/finfo?name=%T&m=tip",zName))%h(zName)</a>
2243 @ from the %z(href("%R/info/tip"))latest check-in</a></h2>
2244 }else{
2245 const char *zPath;
2246 Blob path;
2247 blob_zero(&path);
2248 hyperlinked_path(zName, &path, zCI, "dir", "", LINKPATH_FINFO);
2249 zPath = blob_str(&path);
2250 @ <h2>File %s(zPath) \
2251 if( isBranchCI ){
2252 @ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
2253 }else if( isSymbolicCI ){
2254 @ as of check-in %z(href("%R/info/%!S",zCIUuid))%s(zCI)</a></h2>
2255 }else{
2256 @ as of check-in [%z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
2257 }
2258 blob_reset(&path);
2259 }
2260 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2261 style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T",
2262 zName, zCI);
2263 style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T",
2264 zName, zCI);
2265 blob_init(&downloadName, zName, -1);
2266 objType = OBJTYPE_CONTENT;
2267 }else{
2268 @ <h2>Artifact
2269 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2270 if( g.perm.Setup ){
2271 @ (%d(rid)):</h2>
2272 }else{
2273 @ :</h2>
2274 }
2275 blob_zero(&downloadName);
2276 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2277 objType = object_description(rid, objdescFlags,
2278 (isFile?zName:0), &downloadName);
2279 }
 
 
 
 
2280 if( !descOnly && P("download")!=0 ){
2281 cgi_redirectf("%R/raw/%s?at=%T",
2282 db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
2283 file_tail(blob_str(&downloadName)));
2284 /*NOTREACHED*/
2285 }
2286 if( g.perm.Admin ){
2287 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
2288 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2227,13 +2290,28 @@
2290 g.zTop, zUuid);
2291 }else{
2292 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2293 }
2294 }
2295
2296 if( isFile ){
2297 if( isSymbolicCI ){
2298 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2299 }else if( zCI ){
2300 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2301 }else{
2302 zHeader = mprintf("%s", file_tail(zName));
2303 }
2304 }else if( descOnly ){
2305 zHeader = mprintf("Artifact Description [%S]", zUuid);
2306 }else{
2307 zHeader = mprintf("Artifact [%S]", zUuid);
2308 }
2309 style_header("%s", zHeader);
2310 fossil_free(zCIUuid);
2311 fossil_free(zHeader);
2312 if( !isFile && g.perm.Admin ){
2313 Stmt q;
2314 db_prepare(&q,
2315 "SELECT coalesce(user.login,rcvfrom.uid),"
2316 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2317 " FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
@@ -2253,12 +2331,11 @@
2331 zBr, blob_str(&downloadName));
2332 style_submenu_element("Tip", "%R/file/%T?ci=%T",
2333 blob_str(&downloadName), zBr);
2334 fossil_free((void *)zBr);
2335 }
2336 style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName));
 
2337 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
2338 style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
2339 }
2340 zMime = mimetype_from_name(blob_str(&downloadName));
2341 if( zMime ){
@@ -2288,11 +2365,11 @@
2365 @ <hr />
2366 content_get(rid, &content);
2367 if( renderAsWiki ){
2368 wiki_render_by_mimetype(&content, zMime);
2369 }else if( renderAsHtml ){
2370 @ <iframe src="%R/raw/%s(zUuid)"
2371 @ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
2372 @ sandbox="allow-same-origin" id="ifm1">
2373 @ </iframe>
2374 @ <script nonce="%h(style_nonce())">
2375 @ document.getElementById("ifm1").addEventListener("load",
@@ -2717,15 +2794,15 @@
2794 **
2795 ** Edit a check-in. (Check-ins are immutable and do not really change.
2796 ** This page really creates supplemental tags that affect the display
2797 ** of the check-in.)
2798 **
2799 ** Query parameters:
2800 **
2801 ** rid=INTEGER Record ID of the check-in to edit (REQUIRED)
2802 **
2803 ** POST parameters after pressing "Preview", "Cancel", or "Apply":
2804 **
2805 ** c=TEXT New check-in comment
2806 ** u=TEXT New user name
2807 ** newclr Apply a background color
2808 ** clr=TEXT New background color (only if newclr)
2809
+217 -140
--- src/info.c
+++ src/info.c
@@ -666,10 +666,11 @@
666666
const char *zOrigDate;
667667
int okWiki = 0;
668668
Blob wiki_read_links = BLOB_INITIALIZER;
669669
Blob wiki_add_links = BLOB_INITIALIZER;
670670
671
+ Th_Store("current_checkin", zName);
671672
style_header("Check-in [%S]", zUuid);
672673
login_anonymous_available();
673674
zEUser = db_text(0,
674675
"SELECT value FROM tagxref"
675676
" WHERE tagid=%d AND rid=%d AND tagtype>0",
@@ -1340,33 +1341,22 @@
13401341
13411342
/*
13421343
** Possible flags for the second parameter to
13431344
** object_description()
13441345
*/
1345
-#define OBJDESC_DETAIL 0x0001 /* more detail */
1346
+#define OBJDESC_DETAIL 0x0001 /* Show more detail */
13461347
#define OBJDESC_BASE 0x0002 /* Set <base> using this object */
13471348
#endif
13481349
13491350
/*
13501351
** Write a description of an object to the www reply.
1351
-**
1352
-** If the object is a file then mention:
1353
-**
1354
-** * It's artifact ID
1355
-** * All its filenames
1356
-** * The check-in it was part of, with times and users
1357
-**
1358
-** If the object is a manifest, then mention:
1359
-**
1360
-** * It's artifact ID
1361
-** * date of check-in
1362
-** * Comment & user
13631352
*/
13641353
int object_description(
1365
- int rid, /* The artifact ID */
1354
+ int rid, /* The artifact ID for the object to describe */
13661355
u32 objdescFlags, /* Flags to control display */
1367
- Blob *pDownloadName /* Fill with an appropriate download name */
1356
+ const char *zFileName, /* For file objects, use this name. Can be NULL */
1357
+ Blob *pDownloadName /* Fill with a good download name. Can be NULL */
13681358
){
13691359
Stmt q;
13701360
int cnt = 0;
13711361
int nWiki = 0;
13721362
int objType = 0;
@@ -1401,10 +1391,11 @@
14011391
const char *zVers = db_column_text(&q, 4);
14021392
int mPerm = db_column_int(&q, 5);
14031393
const char *zBr = db_column_text(&q, 6);
14041394
int szFile = db_column_int(&q,7);
14051395
int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1396
+ if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
14061397
if( sameFilename && !showDetail ){
14071398
if( cnt==1 ){
14081399
@ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
14091400
}
14101401
cnt++;
@@ -1671,12 +1662,12 @@
16711662
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
16721663
cookie_link_parameter("diff","diff","2");
16731664
diffType = atoi(PD("diff","2"));
16741665
cookie_render();
16751666
if( P("from") && P("to") ){
1676
- v1 = artifact_from_ci_and_filename(0, "from");
1677
- v2 = artifact_from_ci_and_filename(0, "to");
1667
+ v1 = artifact_from_ci_and_filename("from");
1668
+ v2 = artifact_from_ci_and_filename("to");
16781669
}else{
16791670
Stmt q;
16801671
v1 = name_to_rid_www("v1");
16811672
v2 = name_to_rid_www("v2");
16821673
@@ -1747,13 +1738,13 @@
17471738
@ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
17481739
@ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
17491740
}else{
17501741
@ <h2>Differences From
17511742
@ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1752
- object_description(v1, objdescFlags, 0);
1743
+ object_description(v1, objdescFlags,0, 0);
17531744
@ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1754
- object_description(v2, objdescFlags, 0);
1745
+ object_description(v2, objdescFlags,0, 0);
17551746
}
17561747
if( pRe ){
17571748
@ <b>Only differences that match regular expression "%h(zRe)"
17581749
@ are shown.</b>
17591750
}
@@ -1763,22 +1754,27 @@
17631754
style_footer();
17641755
}
17651756
17661757
/*
17671758
** WEBPAGE: raw
1768
-** URL: /raw?name=ARTIFACTID&m=TYPE
1759
+** URL: /raw/ARTIFACTID
17691760
** URL: /raw?ci=BRANCH&filename=NAME
17701761
**
1762
+** Additional query parameters:
1763
+**
1764
+** m=MIMETYPE The mimetype is MIMETYPE
1765
+** at=FILENAME Content-disposition; attachment; filename=FILENAME;
1766
+**
17711767
** Return the uninterpreted content of an artifact. Used primarily
17721768
** to view artifacts that are images.
17731769
*/
17741770
void rawartifact_page(void){
17751771
int rid = 0;
17761772
char *zUuid;
17771773
1778
- if( P("ci") && P("filename") ){
1779
- rid = artifact_from_ci_and_filename(0, 0);
1774
+ if( P("ci") ){
1775
+ rid = artifact_from_ci_and_filename(0);
17801776
}
17811777
if( rid==0 ){
17821778
rid = name_to_rid_www("name");
17831779
}
17841780
login_check_credentials();
@@ -1825,26 +1821,37 @@
18251821
** NULL, guess at the MIME-type based on the filename
18261822
** associated with the artifact.
18271823
*/
18281824
void deliver_artifact(int rid, const char *zMime){
18291825
Blob content;
1826
+ const char *zAttachName = P("at");
18301827
if( zMime==0 ){
1831
- char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1832
- " WHERE mlink.fid=%d"
1833
- " AND filename.fnid=mlink.fnid", rid);
1834
- if( !zFName ){
1828
+ char *zFN = (char*)zAttachName;
1829
+ if( zFN==0 ){
1830
+ zFN = db_text(0, "SELECT filename.name FROM mlink, filename"
1831
+ " WHERE mlink.fid=%d"
1832
+ " AND filename.fnid=mlink.fnid", rid);
1833
+ }
1834
+ if( zFN==0 ){
18351835
/* Look also at the attachment table */
1836
- zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837
- " WHERE blob.rid=%d"
1838
- " AND attachment.src=blob.uuid", rid);
1836
+ zFN = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837
+ " WHERE blob.rid=%d"
1838
+ " AND attachment.src=blob.uuid", rid);
1839
+ }
1840
+ if( zFN ){
1841
+ zMime = mimetype_from_name(zFN);
18391842
}
1840
- if( zFName ) zMime = mimetype_from_name(zFName);
1841
- if( zMime==0 ) zMime = "application/x-fossil-artifact";
1843
+ if( zMime==0 ){
1844
+ zMime = "application/x-fossil-artifact";
1845
+ }
18421846
}
18431847
content_get(rid, &content);
18441848
fossil_free(style_csp(1));
18451849
cgi_set_content_type(zMime);
1850
+ if( zAttachName ){
1851
+ cgi_content_disposition_filename(zAttachName);
1852
+ }
18461853
cgi_set_content(&content);
18471854
}
18481855
18491856
/*
18501857
** Render a hex dump of a file.
@@ -1937,13 +1944,13 @@
19371944
}else{
19381945
@ :</h2>
19391946
}
19401947
blob_zero(&downloadName);
19411948
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1942
- object_description(rid, objdescFlags, &downloadName);
1943
- style_submenu_element("Download", "%s/raw/%T?name=%s",
1944
- g.zTop, blob_str(&downloadName), zUuid);
1949
+ object_description(rid, objdescFlags, 0, &downloadName);
1950
+ style_submenu_element("Download", "%R/raw/%s?at=%T",
1951
+ zUuid, file_tail(blob_str(&downloadName)));
19451952
@ <hr />
19461953
content_get(rid, &content);
19471954
@ <blockquote><pre>
19481955
hexdump(&content);
19491956
@ </pre></blockquote>
@@ -1952,59 +1959,53 @@
19521959
19531960
/*
19541961
** Look for "ci" and "filename" query parameters. If found, try to
19551962
** use them to extract the record ID of an artifact for the file.
19561963
**
1957
-** Also look for "fn" as an alias for "filename". If either "filename"
1958
-** or "fn" is present but "ci" is missing, use "tip" as a default value
1959
-** for "ci".
1960
-**
1961
-** If zNameParam is not NULL, this use that parameter as the filename
1962
-** rather than "fn" or "filename".
1963
-**
1964
-** If pUrl is not NULL, then record the "ci" and "filename" values in
1965
-** pUrl.
1966
-**
1967
-** At least one of pUrl or zNameParam must be NULL.
1964
+** Also look for "fn" and "name" as an aliases for "filename". If any
1965
+** "filename" or "fn" or "name" are present but "ci" is missing, then
1966
+** use "tip" as the default value for "ci".
1967
+**
1968
+** If zNameParam is not NULL, then use that parameter as the filename
1969
+** rather than "fn" or "filename" or "name". the zNameParam is used
1970
+** for the from= and to= query parameters of /fdiff.
19681971
*/
1969
-int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){
1972
+int artifact_from_ci_and_filename(const char *zNameParam){
19701973
const char *zFilename;
19711974
const char *zCI;
19721975
int cirid;
19731976
Manifest *pManifest;
19741977
ManifestFile *pFile;
1978
+ int rid = 0;
19751979
19761980
if( zNameParam ){
19771981
zFilename = P(zNameParam);
19781982
}else{
19791983
zFilename = P("filename");
19801984
if( zFilename==0 ){
19811985
zFilename = P("fn");
19821986
}
1987
+ if( zFilename==0 ){
1988
+ zFilename = P("name");
1989
+ }
19831990
}
19841991
if( zFilename==0 ) return 0;
19851992
1986
- zCI = P("ci");
1987
- cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci");
1993
+ zCI = PD("ci", "tip");
1994
+ cirid = name_to_typed_rid(zCI, "ci");
19881995
if( cirid<=0 ) return 0;
19891996
pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
19901997
if( pManifest==0 ) return 0;
19911998
manifest_file_rewind(pManifest);
19921999
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
19932000
if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1994
- int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1995
- manifest_destroy(pManifest);
1996
- if( pUrl ){
1997
- assert( zNameParam==0 );
1998
- url_add_parameter(pUrl, "fn", zFilename);
1999
- if( zCI ) url_add_parameter(pUrl, "ci", zCI);
2000
- }
2001
- return rid;
2001
+ rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
2002
+ break;
20022003
}
20032004
}
20042005
manifest_destroy(pManifest);
2005
- return 0;
2006
+ return rid;
20062007
}
20072008
20082009
/*
20092010
** The "z" argument is a string that contains the text of a source code
20102011
** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2106,21 +2107,31 @@
21062107
** ln=N - highlight line number N
21072108
** ln=M-N - highlight lines M through N inclusive
21082109
** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
21092110
** verbose - show more detail in the description
21102111
** download - redirect to the download (artifact page only)
2111
-** name=SHA1HASH - Provide the SHA1HASH as a query parameter
2112
-** filename=NAME - Show information for content file NAME
2113
-** fn=NAME - "fn" is shorthand for "filename"
2114
-** ci=VERSION - The specific check-in to use for "filename=".
2112
+** name=NAME - filename or hash as a query parameter
2113
+** filename=NAME - alternative spelling for "name="
2114
+** fn=NAME - alternative spelling for "name="
2115
+** ci=VERSION - The specific check-in to use with "name=" to
2116
+** identify the file.
21152117
**
21162118
** The /artifact page show the complete content of a file
2117
-** identified by HASH as preformatted text. The
2118
-** /whatis page shows only a description of the file. The /file
2119
-** page shows the most recent version of the file or directory
2120
-** called NAME, or a list of the top-level directory if NAME is
2121
-** omitted.
2119
+** identified by HASH. The /whatis page shows only a description
2120
+** of how the artifact is used. The /file page shows the most recent
2121
+** version of the file or directory called NAME, or a list of the
2122
+** top-level directory if NAME is omitted.
2123
+**
2124
+** For /artifact and /whatis, the name= query parameter can refer to
2125
+** either the name of a file, or an artifact hash. If the ci= query
2126
+** parameter is also present, then name= must refer to a file name.
2127
+** If ci= is omitted, then the hash interpretation is preferred but
2128
+** if name= cannot be understood as a hash, a default "tip" value is
2129
+** used for ci=.
2130
+**
2131
+** For /file, name= can only be interpreted as a filename. As before,
2132
+** a default value of "tip" is used for ci= if ci= is omitted.
21222133
*/
21232134
void artifact_page(void){
21242135
int rid = 0;
21252136
Blob content;
21262137
const char *zMime;
@@ -2127,99 +2138,151 @@
21272138
Blob downloadName;
21282139
int renderAsWiki = 0;
21292140
int renderAsHtml = 0;
21302141
int objType;
21312142
int asText;
2132
- const char *zUuid;
2143
+ const char *zUuid = 0;
21332144
const char *zBr;
21342145
u32 objdescFlags = OBJDESC_BASE;
21352146
int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
21362147
int isFile = fossil_strcmp(g.zPath,"file")==0;
21372148
const char *zLn = P("ln");
21382149
const char *zName = P("name");
2139
- HQuery url;
2140
-
2141
- url_initialize(&url, g.zPath);
2142
- rid = artifact_from_ci_and_filename(&url, 0);
2143
- if( rid==0 ){
2144
- url_add_parameter(&url, "name", zName);
2145
- if( isFile ){
2146
- /* Do a top-level directory listing in /file mode if no argument
2147
- ** specified */
2148
- if( zName==0 || zName[0]==0 ){
2149
- if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2150
- page_tree();
2151
- return;
2152
- }
2153
- /* Look for a single file with the given name */
2154
- rid = db_int(0,
2155
- "SELECT fid FROM filename, mlink, event"
2156
- " WHERE name=%Q"
2157
- " AND mlink.fnid=filename.fnid"
2158
- " AND event.objid=mlink.mid"
2159
- " ORDER BY event.mtime DESC LIMIT 1",
2160
- zName
2161
- );
2162
- /* If no file called NAME exists, instead look for a directory
2163
- ** with that name, and do a directory listing */
2164
- if( rid==0 ){
2165
- int nName = (int)strlen(zName);
2166
- if( nName && zName[nName-1]=='/' ) nName--;
2167
- if( db_exists(
2168
- "SELECT 1 FROM filename"
2169
- " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2170
- nName, zName, nName+1, nName, zName
2171
- ) ){
2172
- if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2173
- page_tree();
2174
- return;
2175
- }
2176
- }
2177
- /* If no file or directory called NAME: issue an error */
2178
- if( rid==0 ){
2179
- style_header("No such file");
2180
- @ File '%h(zName)' does not exist in this repository.
2181
- style_footer();
2182
- return;
2183
- }
2184
- }else{
2185
- rid = name_to_rid_www("name");
2186
- }
2187
- }
2188
-
2189
- login_check_credentials();
2190
- if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2191
- if( rid==0 ){
2192
- style_header("No such artifact");
2193
- @ Artifact '%h(zName)' does not exist in this repository.
2194
- style_footer();
2195
- return;
2196
- }
2150
+ const char *zCI = P("ci");
2151
+ HQuery url;
2152
+ char *zCIUuid = 0;
2153
+ int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2154
+ int isBranchCI = 0; /* ci= refers to a branch name */
2155
+ char *zHeader = 0;
2156
+
2157
+ login_check_credentials();
2158
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2159
+
2160
+ /* Capture and normalize the name= and ci= query parameters */
2161
+ if( zName==0 ){
2162
+ zName = P("filename");
2163
+ if( zName==0 ){
2164
+ zName = P("fn");
2165
+ }
2166
+ }
2167
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2168
+ if( zCI
2169
+ && name_to_uuid2(zCI, "ci", &zCIUuid)
2170
+ && sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI))!=0
2171
+ ){
2172
+ isSymbolicCI = 1;
2173
+ isBranchCI = branch_includes_uuid(zCI, zCIUuid);
2174
+ }
2175
+
2176
+ /* The name= query parameter (or at least one of its alternative
2177
+ ** spellings) is required. Except for /file, show a top-level
2178
+ ** directory listing if name= is omitted.
2179
+ */
2180
+ if( zName==0 ){
2181
+ if( isFile ){
2182
+ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2183
+ page_tree();
2184
+ return;
2185
+ }
2186
+ style_header("Missing name= query parameter");
2187
+ @ The name= query parameter is missing
2188
+ style_footer();
2189
+ return;
2190
+ }
2191
+
2192
+ url_initialize(&url, g.zPath);
2193
+ url_add_parameter(&url, "name", zName);
2194
+ url_add_parameter(&url, "ci", zCI);
2195
+
2196
+ if( zCI==0 && !isFile ){
2197
+ /* If there is no ci= query parameter, then prefer to interpret
2198
+ ** name= as a hash for /artifact and /whatis. But for not for /file.
2199
+ ** For /file, a name= without a ci= while prefer to use the default
2200
+ ** "tip" value for ci=. */
2201
+ rid = name_to_rid(zName);
2202
+ }
2203
+ if( rid==0 ){
2204
+ rid = artifact_from_ci_and_filename(0);
2205
+ }
2206
+
2207
+ if( rid==0 ){ /* Artifact not found */
2208
+ if( isFile ){
2209
+ /* For /file, also check to see if name= refers to a directory,
2210
+ ** and if so, do a listing for that directory */
2211
+ int nName = (int)strlen(zName);
2212
+ if( nName && zName[nName-1]=='/' ) nName--;
2213
+ if( db_exists(
2214
+ "SELECT 1 FROM filename"
2215
+ " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2216
+ nName, zName, nName+1, nName, zName
2217
+ ) ){
2218
+ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2219
+ page_tree();
2220
+ return;
2221
+ }
2222
+ style_header("No such file");
2223
+ @ File '%h(zName)' does not exist in this repository.
2224
+ }else{
2225
+ style_header("No such artifact");
2226
+ @ Artifact '%h(zName)' does not exist in this repository.
2227
+ }
2228
+ style_footer();
2229
+ return;
2230
+ }
2231
+
21972232
if( descOnly || P("verbose")!=0 ){
21982233
url_add_parameter(&url, "verbose", "1");
21992234
objdescFlags |= OBJDESC_DETAIL;
22002235
}
22012236
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2237
+
2238
+ asText = P("txt")!=0;
22022239
if( isFile ){
2203
- @ <h2>Latest version of file '%h(zName)':</h2>
2240
+ if( zCI==0 || fossil_strcmp(zCI,"tip")==0 ){
2241
+ zCI = "tip";
2242
+ @ <h2>File %z(href("%R/finfo?name=%T&m=tip",zName))%h(zName)</a>
2243
+ @ from the %z(href("%R/info/tip"))latest check-in</a></h2>
2244
+ }else{
2245
+ const char *zPath;
2246
+ Blob path;
2247
+ blob_zero(&path);
2248
+ hyperlinked_path(zName, &path, zCI, "dir", "", LINKPATH_FINFO);
2249
+ zPath = blob_str(&path);
2250
+ @ <h2>File %s(zPath) \
2251
+ if( isBranchCI ){
2252
+ @ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
2253
+ }else if( isSymbolicCI ){
2254
+ @ as of check-in %z(href("%R/info/%!S",zCIUuid))%s(zCI)</a></h2>
2255
+ }else{
2256
+ @ as of check-in [%z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
2257
+ }
2258
+ blob_reset(&path);
2259
+ }
22042260
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2261
+ style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T",
2262
+ zName, zCI);
2263
+ style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T",
2264
+ zName, zCI);
2265
+ blob_init(&downloadName, zName, -1);
2266
+ objType = OBJTYPE_CONTENT;
22052267
}else{
22062268
@ <h2>Artifact
22072269
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
22082270
if( g.perm.Setup ){
22092271
@ (%d(rid)):</h2>
22102272
}else{
22112273
@ :</h2>
22122274
}
2275
+ blob_zero(&downloadName);
2276
+ if( asText ) objdescFlags &= ~OBJDESC_BASE;
2277
+ objType = object_description(rid, objdescFlags,
2278
+ (isFile?zName:0), &downloadName);
22132279
}
2214
- blob_zero(&downloadName);
2215
- asText = P("txt")!=0;
2216
- if( asText ) objdescFlags &= ~OBJDESC_BASE;
2217
- objType = object_description(rid, objdescFlags, &downloadName);
22182280
if( !descOnly && P("download")!=0 ){
2219
- cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2220
- db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2281
+ cgi_redirectf("%R/raw/%s?at=%T",
2282
+ db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
2283
+ file_tail(blob_str(&downloadName)));
22212284
/*NOTREACHED*/
22222285
}
22232286
if( g.perm.Admin ){
22242287
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
22252288
if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2227,13 +2290,28 @@
22272290
g.zTop, zUuid);
22282291
}else{
22292292
style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
22302293
}
22312294
}
2232
- style_header("%s", isFile ? "File Content" :
2233
- descOnly ? "Artifact Description" : "Artifact Content");
2234
- if( g.perm.Admin ){
2295
+
2296
+ if( isFile ){
2297
+ if( isSymbolicCI ){
2298
+ zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2299
+ }else if( zCI ){
2300
+ zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2301
+ }else{
2302
+ zHeader = mprintf("%s", file_tail(zName));
2303
+ }
2304
+ }else if( descOnly ){
2305
+ zHeader = mprintf("Artifact Description [%S]", zUuid);
2306
+ }else{
2307
+ zHeader = mprintf("Artifact [%S]", zUuid);
2308
+ }
2309
+ style_header("%s", zHeader);
2310
+ fossil_free(zCIUuid);
2311
+ fossil_free(zHeader);
2312
+ if( !isFile && g.perm.Admin ){
22352313
Stmt q;
22362314
db_prepare(&q,
22372315
"SELECT coalesce(user.login,rcvfrom.uid),"
22382316
" datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
22392317
" FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
@@ -2253,12 +2331,11 @@
22532331
zBr, blob_str(&downloadName));
22542332
style_submenu_element("Tip", "%R/file/%T?ci=%T",
22552333
blob_str(&downloadName), zBr);
22562334
fossil_free((void *)zBr);
22572335
}
2258
- style_submenu_element("Download", "%R/raw/%T?name=%s",
2259
- blob_str(&downloadName), zUuid);
2336
+ style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName));
22602337
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
22612338
style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
22622339
}
22632340
zMime = mimetype_from_name(blob_str(&downloadName));
22642341
if( zMime ){
@@ -2288,11 +2365,11 @@
22882365
@ <hr />
22892366
content_get(rid, &content);
22902367
if( renderAsWiki ){
22912368
wiki_render_by_mimetype(&content, zMime);
22922369
}else if( renderAsHtml ){
2293
- @ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)"
2370
+ @ <iframe src="%R/raw/%s(zUuid)"
22942371
@ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
22952372
@ sandbox="allow-same-origin" id="ifm1">
22962373
@ </iframe>
22972374
@ <script nonce="%h(style_nonce())">
22982375
@ document.getElementById("ifm1").addEventListener("load",
@@ -2717,15 +2794,15 @@
27172794
**
27182795
** Edit a check-in. (Check-ins are immutable and do not really change.
27192796
** This page really creates supplemental tags that affect the display
27202797
** of the check-in.)
27212798
**
2722
-** Query parmeters:
2799
+** Query parameters:
27232800
**
27242801
** rid=INTEGER Record ID of the check-in to edit (REQUIRED)
27252802
**
2726
-** POST parameters after pressing "Perview", "Cancel", or "Apply":
2803
+** POST parameters after pressing "Preview", "Cancel", or "Apply":
27272804
**
27282805
** c=TEXT New check-in comment
27292806
** u=TEXT New user name
27302807
** newclr Apply a background color
27312808
** clr=TEXT New background color (only if newclr)
27322809
--- src/info.c
+++ src/info.c
@@ -666,10 +666,11 @@
666 const char *zOrigDate;
667 int okWiki = 0;
668 Blob wiki_read_links = BLOB_INITIALIZER;
669 Blob wiki_add_links = BLOB_INITIALIZER;
670
 
671 style_header("Check-in [%S]", zUuid);
672 login_anonymous_available();
673 zEUser = db_text(0,
674 "SELECT value FROM tagxref"
675 " WHERE tagid=%d AND rid=%d AND tagtype>0",
@@ -1340,33 +1341,22 @@
1340
1341 /*
1342 ** Possible flags for the second parameter to
1343 ** object_description()
1344 */
1345 #define OBJDESC_DETAIL 0x0001 /* more detail */
1346 #define OBJDESC_BASE 0x0002 /* Set <base> using this object */
1347 #endif
1348
1349 /*
1350 ** Write a description of an object to the www reply.
1351 **
1352 ** If the object is a file then mention:
1353 **
1354 ** * It's artifact ID
1355 ** * All its filenames
1356 ** * The check-in it was part of, with times and users
1357 **
1358 ** If the object is a manifest, then mention:
1359 **
1360 ** * It's artifact ID
1361 ** * date of check-in
1362 ** * Comment & user
1363 */
1364 int object_description(
1365 int rid, /* The artifact ID */
1366 u32 objdescFlags, /* Flags to control display */
1367 Blob *pDownloadName /* Fill with an appropriate download name */
 
1368 ){
1369 Stmt q;
1370 int cnt = 0;
1371 int nWiki = 0;
1372 int objType = 0;
@@ -1401,10 +1391,11 @@
1401 const char *zVers = db_column_text(&q, 4);
1402 int mPerm = db_column_int(&q, 5);
1403 const char *zBr = db_column_text(&q, 6);
1404 int szFile = db_column_int(&q,7);
1405 int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
 
1406 if( sameFilename && !showDetail ){
1407 if( cnt==1 ){
1408 @ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
1409 }
1410 cnt++;
@@ -1671,12 +1662,12 @@
1671 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1672 cookie_link_parameter("diff","diff","2");
1673 diffType = atoi(PD("diff","2"));
1674 cookie_render();
1675 if( P("from") && P("to") ){
1676 v1 = artifact_from_ci_and_filename(0, "from");
1677 v2 = artifact_from_ci_and_filename(0, "to");
1678 }else{
1679 Stmt q;
1680 v1 = name_to_rid_www("v1");
1681 v2 = name_to_rid_www("v2");
1682
@@ -1747,13 +1738,13 @@
1747 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1748 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1749 }else{
1750 @ <h2>Differences From
1751 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1752 object_description(v1, objdescFlags, 0);
1753 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1754 object_description(v2, objdescFlags, 0);
1755 }
1756 if( pRe ){
1757 @ <b>Only differences that match regular expression "%h(zRe)"
1758 @ are shown.</b>
1759 }
@@ -1763,22 +1754,27 @@
1763 style_footer();
1764 }
1765
1766 /*
1767 ** WEBPAGE: raw
1768 ** URL: /raw?name=ARTIFACTID&m=TYPE
1769 ** URL: /raw?ci=BRANCH&filename=NAME
1770 **
 
 
 
 
 
1771 ** Return the uninterpreted content of an artifact. Used primarily
1772 ** to view artifacts that are images.
1773 */
1774 void rawartifact_page(void){
1775 int rid = 0;
1776 char *zUuid;
1777
1778 if( P("ci") && P("filename") ){
1779 rid = artifact_from_ci_and_filename(0, 0);
1780 }
1781 if( rid==0 ){
1782 rid = name_to_rid_www("name");
1783 }
1784 login_check_credentials();
@@ -1825,26 +1821,37 @@
1825 ** NULL, guess at the MIME-type based on the filename
1826 ** associated with the artifact.
1827 */
1828 void deliver_artifact(int rid, const char *zMime){
1829 Blob content;
 
1830 if( zMime==0 ){
1831 char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1832 " WHERE mlink.fid=%d"
1833 " AND filename.fnid=mlink.fnid", rid);
1834 if( !zFName ){
 
 
 
1835 /* Look also at the attachment table */
1836 zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837 " WHERE blob.rid=%d"
1838 " AND attachment.src=blob.uuid", rid);
 
 
 
1839 }
1840 if( zFName ) zMime = mimetype_from_name(zFName);
1841 if( zMime==0 ) zMime = "application/x-fossil-artifact";
 
1842 }
1843 content_get(rid, &content);
1844 fossil_free(style_csp(1));
1845 cgi_set_content_type(zMime);
 
 
 
1846 cgi_set_content(&content);
1847 }
1848
1849 /*
1850 ** Render a hex dump of a file.
@@ -1937,13 +1944,13 @@
1937 }else{
1938 @ :</h2>
1939 }
1940 blob_zero(&downloadName);
1941 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1942 object_description(rid, objdescFlags, &downloadName);
1943 style_submenu_element("Download", "%s/raw/%T?name=%s",
1944 g.zTop, blob_str(&downloadName), zUuid);
1945 @ <hr />
1946 content_get(rid, &content);
1947 @ <blockquote><pre>
1948 hexdump(&content);
1949 @ </pre></blockquote>
@@ -1952,59 +1959,53 @@
1952
1953 /*
1954 ** Look for "ci" and "filename" query parameters. If found, try to
1955 ** use them to extract the record ID of an artifact for the file.
1956 **
1957 ** Also look for "fn" as an alias for "filename". If either "filename"
1958 ** or "fn" is present but "ci" is missing, use "tip" as a default value
1959 ** for "ci".
1960 **
1961 ** If zNameParam is not NULL, this use that parameter as the filename
1962 ** rather than "fn" or "filename".
1963 **
1964 ** If pUrl is not NULL, then record the "ci" and "filename" values in
1965 ** pUrl.
1966 **
1967 ** At least one of pUrl or zNameParam must be NULL.
1968 */
1969 int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){
1970 const char *zFilename;
1971 const char *zCI;
1972 int cirid;
1973 Manifest *pManifest;
1974 ManifestFile *pFile;
 
1975
1976 if( zNameParam ){
1977 zFilename = P(zNameParam);
1978 }else{
1979 zFilename = P("filename");
1980 if( zFilename==0 ){
1981 zFilename = P("fn");
1982 }
 
 
 
1983 }
1984 if( zFilename==0 ) return 0;
1985
1986 zCI = P("ci");
1987 cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci");
1988 if( cirid<=0 ) return 0;
1989 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1990 if( pManifest==0 ) return 0;
1991 manifest_file_rewind(pManifest);
1992 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1993 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1994 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1995 manifest_destroy(pManifest);
1996 if( pUrl ){
1997 assert( zNameParam==0 );
1998 url_add_parameter(pUrl, "fn", zFilename);
1999 if( zCI ) url_add_parameter(pUrl, "ci", zCI);
2000 }
2001 return rid;
2002 }
2003 }
2004 manifest_destroy(pManifest);
2005 return 0;
2006 }
2007
2008 /*
2009 ** The "z" argument is a string that contains the text of a source code
2010 ** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2106,21 +2107,31 @@
2106 ** ln=N - highlight line number N
2107 ** ln=M-N - highlight lines M through N inclusive
2108 ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
2109 ** verbose - show more detail in the description
2110 ** download - redirect to the download (artifact page only)
2111 ** name=SHA1HASH - Provide the SHA1HASH as a query parameter
2112 ** filename=NAME - Show information for content file NAME
2113 ** fn=NAME - "fn" is shorthand for "filename"
2114 ** ci=VERSION - The specific check-in to use for "filename=".
 
2115 **
2116 ** The /artifact page show the complete content of a file
2117 ** identified by HASH as preformatted text. The
2118 ** /whatis page shows only a description of the file. The /file
2119 ** page shows the most recent version of the file or directory
2120 ** called NAME, or a list of the top-level directory if NAME is
2121 ** omitted.
 
 
 
 
 
 
 
 
 
2122 */
2123 void artifact_page(void){
2124 int rid = 0;
2125 Blob content;
2126 const char *zMime;
@@ -2127,99 +2138,151 @@
2127 Blob downloadName;
2128 int renderAsWiki = 0;
2129 int renderAsHtml = 0;
2130 int objType;
2131 int asText;
2132 const char *zUuid;
2133 const char *zBr;
2134 u32 objdescFlags = OBJDESC_BASE;
2135 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2136 int isFile = fossil_strcmp(g.zPath,"file")==0;
2137 const char *zLn = P("ln");
2138 const char *zName = P("name");
2139 HQuery url;
2140
2141 url_initialize(&url, g.zPath);
2142 rid = artifact_from_ci_and_filename(&url, 0);
2143 if( rid==0 ){
2144 url_add_parameter(&url, "name", zName);
2145 if( isFile ){
2146 /* Do a top-level directory listing in /file mode if no argument
2147 ** specified */
2148 if( zName==0 || zName[0]==0 ){
2149 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2150 page_tree();
2151 return;
2152 }
2153 /* Look for a single file with the given name */
2154 rid = db_int(0,
2155 "SELECT fid FROM filename, mlink, event"
2156 " WHERE name=%Q"
2157 " AND mlink.fnid=filename.fnid"
2158 " AND event.objid=mlink.mid"
2159 " ORDER BY event.mtime DESC LIMIT 1",
2160 zName
2161 );
2162 /* If no file called NAME exists, instead look for a directory
2163 ** with that name, and do a directory listing */
2164 if( rid==0 ){
2165 int nName = (int)strlen(zName);
2166 if( nName && zName[nName-1]=='/' ) nName--;
2167 if( db_exists(
2168 "SELECT 1 FROM filename"
2169 " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2170 nName, zName, nName+1, nName, zName
2171 ) ){
2172 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2173 page_tree();
2174 return;
2175 }
2176 }
2177 /* If no file or directory called NAME: issue an error */
2178 if( rid==0 ){
2179 style_header("No such file");
2180 @ File '%h(zName)' does not exist in this repository.
2181 style_footer();
2182 return;
2183 }
2184 }else{
2185 rid = name_to_rid_www("name");
2186 }
2187 }
2188
2189 login_check_credentials();
2190 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2191 if( rid==0 ){
2192 style_header("No such artifact");
2193 @ Artifact '%h(zName)' does not exist in this repository.
2194 style_footer();
2195 return;
2196 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2197 if( descOnly || P("verbose")!=0 ){
2198 url_add_parameter(&url, "verbose", "1");
2199 objdescFlags |= OBJDESC_DETAIL;
2200 }
2201 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
 
 
2202 if( isFile ){
2203 @ <h2>Latest version of file '%h(zName)':</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2204 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
 
 
 
 
 
 
2205 }else{
2206 @ <h2>Artifact
2207 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2208 if( g.perm.Setup ){
2209 @ (%d(rid)):</h2>
2210 }else{
2211 @ :</h2>
2212 }
 
 
 
 
2213 }
2214 blob_zero(&downloadName);
2215 asText = P("txt")!=0;
2216 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2217 objType = object_description(rid, objdescFlags, &downloadName);
2218 if( !descOnly && P("download")!=0 ){
2219 cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2220 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
 
2221 /*NOTREACHED*/
2222 }
2223 if( g.perm.Admin ){
2224 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
2225 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2227,13 +2290,28 @@
2227 g.zTop, zUuid);
2228 }else{
2229 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2230 }
2231 }
2232 style_header("%s", isFile ? "File Content" :
2233 descOnly ? "Artifact Description" : "Artifact Content");
2234 if( g.perm.Admin ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2235 Stmt q;
2236 db_prepare(&q,
2237 "SELECT coalesce(user.login,rcvfrom.uid),"
2238 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2239 " FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
@@ -2253,12 +2331,11 @@
2253 zBr, blob_str(&downloadName));
2254 style_submenu_element("Tip", "%R/file/%T?ci=%T",
2255 blob_str(&downloadName), zBr);
2256 fossil_free((void *)zBr);
2257 }
2258 style_submenu_element("Download", "%R/raw/%T?name=%s",
2259 blob_str(&downloadName), zUuid);
2260 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
2261 style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
2262 }
2263 zMime = mimetype_from_name(blob_str(&downloadName));
2264 if( zMime ){
@@ -2288,11 +2365,11 @@
2288 @ <hr />
2289 content_get(rid, &content);
2290 if( renderAsWiki ){
2291 wiki_render_by_mimetype(&content, zMime);
2292 }else if( renderAsHtml ){
2293 @ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)"
2294 @ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
2295 @ sandbox="allow-same-origin" id="ifm1">
2296 @ </iframe>
2297 @ <script nonce="%h(style_nonce())">
2298 @ document.getElementById("ifm1").addEventListener("load",
@@ -2717,15 +2794,15 @@
2717 **
2718 ** Edit a check-in. (Check-ins are immutable and do not really change.
2719 ** This page really creates supplemental tags that affect the display
2720 ** of the check-in.)
2721 **
2722 ** Query parmeters:
2723 **
2724 ** rid=INTEGER Record ID of the check-in to edit (REQUIRED)
2725 **
2726 ** POST parameters after pressing "Perview", "Cancel", or "Apply":
2727 **
2728 ** c=TEXT New check-in comment
2729 ** u=TEXT New user name
2730 ** newclr Apply a background color
2731 ** clr=TEXT New background color (only if newclr)
2732
--- src/info.c
+++ src/info.c
@@ -666,10 +666,11 @@
666 const char *zOrigDate;
667 int okWiki = 0;
668 Blob wiki_read_links = BLOB_INITIALIZER;
669 Blob wiki_add_links = BLOB_INITIALIZER;
670
671 Th_Store("current_checkin", zName);
672 style_header("Check-in [%S]", zUuid);
673 login_anonymous_available();
674 zEUser = db_text(0,
675 "SELECT value FROM tagxref"
676 " WHERE tagid=%d AND rid=%d AND tagtype>0",
@@ -1340,33 +1341,22 @@
1341
1342 /*
1343 ** Possible flags for the second parameter to
1344 ** object_description()
1345 */
1346 #define OBJDESC_DETAIL 0x0001 /* Show more detail */
1347 #define OBJDESC_BASE 0x0002 /* Set <base> using this object */
1348 #endif
1349
1350 /*
1351 ** Write a description of an object to the www reply.
 
 
 
 
 
 
 
 
 
 
 
 
1352 */
1353 int object_description(
1354 int rid, /* The artifact ID for the object to describe */
1355 u32 objdescFlags, /* Flags to control display */
1356 const char *zFileName, /* For file objects, use this name. Can be NULL */
1357 Blob *pDownloadName /* Fill with a good download name. Can be NULL */
1358 ){
1359 Stmt q;
1360 int cnt = 0;
1361 int nWiki = 0;
1362 int objType = 0;
@@ -1401,10 +1391,11 @@
1391 const char *zVers = db_column_text(&q, 4);
1392 int mPerm = db_column_int(&q, 5);
1393 const char *zBr = db_column_text(&q, 6);
1394 int szFile = db_column_int(&q,7);
1395 int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1396 if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
1397 if( sameFilename && !showDetail ){
1398 if( cnt==1 ){
1399 @ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
1400 }
1401 cnt++;
@@ -1671,12 +1662,12 @@
1662 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1663 cookie_link_parameter("diff","diff","2");
1664 diffType = atoi(PD("diff","2"));
1665 cookie_render();
1666 if( P("from") && P("to") ){
1667 v1 = artifact_from_ci_and_filename("from");
1668 v2 = artifact_from_ci_and_filename("to");
1669 }else{
1670 Stmt q;
1671 v1 = name_to_rid_www("v1");
1672 v2 = name_to_rid_www("v2");
1673
@@ -1747,13 +1738,13 @@
1738 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1739 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1740 }else{
1741 @ <h2>Differences From
1742 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1743 object_description(v1, objdescFlags,0, 0);
1744 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1745 object_description(v2, objdescFlags,0, 0);
1746 }
1747 if( pRe ){
1748 @ <b>Only differences that match regular expression "%h(zRe)"
1749 @ are shown.</b>
1750 }
@@ -1763,22 +1754,27 @@
1754 style_footer();
1755 }
1756
1757 /*
1758 ** WEBPAGE: raw
1759 ** URL: /raw/ARTIFACTID
1760 ** URL: /raw?ci=BRANCH&filename=NAME
1761 **
1762 ** Additional query parameters:
1763 **
1764 ** m=MIMETYPE The mimetype is MIMETYPE
1765 ** at=FILENAME Content-disposition; attachment; filename=FILENAME;
1766 **
1767 ** Return the uninterpreted content of an artifact. Used primarily
1768 ** to view artifacts that are images.
1769 */
1770 void rawartifact_page(void){
1771 int rid = 0;
1772 char *zUuid;
1773
1774 if( P("ci") ){
1775 rid = artifact_from_ci_and_filename(0);
1776 }
1777 if( rid==0 ){
1778 rid = name_to_rid_www("name");
1779 }
1780 login_check_credentials();
@@ -1825,26 +1821,37 @@
1821 ** NULL, guess at the MIME-type based on the filename
1822 ** associated with the artifact.
1823 */
1824 void deliver_artifact(int rid, const char *zMime){
1825 Blob content;
1826 const char *zAttachName = P("at");
1827 if( zMime==0 ){
1828 char *zFN = (char*)zAttachName;
1829 if( zFN==0 ){
1830 zFN = db_text(0, "SELECT filename.name FROM mlink, filename"
1831 " WHERE mlink.fid=%d"
1832 " AND filename.fnid=mlink.fnid", rid);
1833 }
1834 if( zFN==0 ){
1835 /* Look also at the attachment table */
1836 zFN = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837 " WHERE blob.rid=%d"
1838 " AND attachment.src=blob.uuid", rid);
1839 }
1840 if( zFN ){
1841 zMime = mimetype_from_name(zFN);
1842 }
1843 if( zMime==0 ){
1844 zMime = "application/x-fossil-artifact";
1845 }
1846 }
1847 content_get(rid, &content);
1848 fossil_free(style_csp(1));
1849 cgi_set_content_type(zMime);
1850 if( zAttachName ){
1851 cgi_content_disposition_filename(zAttachName);
1852 }
1853 cgi_set_content(&content);
1854 }
1855
1856 /*
1857 ** Render a hex dump of a file.
@@ -1937,13 +1944,13 @@
1944 }else{
1945 @ :</h2>
1946 }
1947 blob_zero(&downloadName);
1948 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1949 object_description(rid, objdescFlags, 0, &downloadName);
1950 style_submenu_element("Download", "%R/raw/%s?at=%T",
1951 zUuid, file_tail(blob_str(&downloadName)));
1952 @ <hr />
1953 content_get(rid, &content);
1954 @ <blockquote><pre>
1955 hexdump(&content);
1956 @ </pre></blockquote>
@@ -1952,59 +1959,53 @@
1959
1960 /*
1961 ** Look for "ci" and "filename" query parameters. If found, try to
1962 ** use them to extract the record ID of an artifact for the file.
1963 **
1964 ** Also look for "fn" and "name" as an aliases for "filename". If any
1965 ** "filename" or "fn" or "name" are present but "ci" is missing, then
1966 ** use "tip" as the default value for "ci".
1967 **
1968 ** If zNameParam is not NULL, then use that parameter as the filename
1969 ** rather than "fn" or "filename" or "name". the zNameParam is used
1970 ** for the from= and to= query parameters of /fdiff.
 
 
 
 
1971 */
1972 int artifact_from_ci_and_filename(const char *zNameParam){
1973 const char *zFilename;
1974 const char *zCI;
1975 int cirid;
1976 Manifest *pManifest;
1977 ManifestFile *pFile;
1978 int rid = 0;
1979
1980 if( zNameParam ){
1981 zFilename = P(zNameParam);
1982 }else{
1983 zFilename = P("filename");
1984 if( zFilename==0 ){
1985 zFilename = P("fn");
1986 }
1987 if( zFilename==0 ){
1988 zFilename = P("name");
1989 }
1990 }
1991 if( zFilename==0 ) return 0;
1992
1993 zCI = PD("ci", "tip");
1994 cirid = name_to_typed_rid(zCI, "ci");
1995 if( cirid<=0 ) return 0;
1996 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1997 if( pManifest==0 ) return 0;
1998 manifest_file_rewind(pManifest);
1999 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
2000 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
2001 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
2002 break;
 
 
 
 
 
 
2003 }
2004 }
2005 manifest_destroy(pManifest);
2006 return rid;
2007 }
2008
2009 /*
2010 ** The "z" argument is a string that contains the text of a source code
2011 ** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2106,21 +2107,31 @@
2107 ** ln=N - highlight line number N
2108 ** ln=M-N - highlight lines M through N inclusive
2109 ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
2110 ** verbose - show more detail in the description
2111 ** download - redirect to the download (artifact page only)
2112 ** name=NAME - filename or hash as a query parameter
2113 ** filename=NAME - alternative spelling for "name="
2114 ** fn=NAME - alternative spelling for "name="
2115 ** ci=VERSION - The specific check-in to use with "name=" to
2116 ** identify the file.
2117 **
2118 ** The /artifact page show the complete content of a file
2119 ** identified by HASH. The /whatis page shows only a description
2120 ** of how the artifact is used. The /file page shows the most recent
2121 ** version of the file or directory called NAME, or a list of the
2122 ** top-level directory if NAME is omitted.
2123 **
2124 ** For /artifact and /whatis, the name= query parameter can refer to
2125 ** either the name of a file, or an artifact hash. If the ci= query
2126 ** parameter is also present, then name= must refer to a file name.
2127 ** If ci= is omitted, then the hash interpretation is preferred but
2128 ** if name= cannot be understood as a hash, a default "tip" value is
2129 ** used for ci=.
2130 **
2131 ** For /file, name= can only be interpreted as a filename. As before,
2132 ** a default value of "tip" is used for ci= if ci= is omitted.
2133 */
2134 void artifact_page(void){
2135 int rid = 0;
2136 Blob content;
2137 const char *zMime;
@@ -2127,99 +2138,151 @@
2138 Blob downloadName;
2139 int renderAsWiki = 0;
2140 int renderAsHtml = 0;
2141 int objType;
2142 int asText;
2143 const char *zUuid = 0;
2144 const char *zBr;
2145 u32 objdescFlags = OBJDESC_BASE;
2146 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2147 int isFile = fossil_strcmp(g.zPath,"file")==0;
2148 const char *zLn = P("ln");
2149 const char *zName = P("name");
2150 const char *zCI = P("ci");
2151 HQuery url;
2152 char *zCIUuid = 0;
2153 int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2154 int isBranchCI = 0; /* ci= refers to a branch name */
2155 char *zHeader = 0;
2156
2157 login_check_credentials();
2158 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2159
2160 /* Capture and normalize the name= and ci= query parameters */
2161 if( zName==0 ){
2162 zName = P("filename");
2163 if( zName==0 ){
2164 zName = P("fn");
2165 }
2166 }
2167 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2168 if( zCI
2169 && name_to_uuid2(zCI, "ci", &zCIUuid)
2170 && sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI))!=0
2171 ){
2172 isSymbolicCI = 1;
2173 isBranchCI = branch_includes_uuid(zCI, zCIUuid);
2174 }
2175
2176 /* The name= query parameter (or at least one of its alternative
2177 ** spellings) is required. Except for /file, show a top-level
2178 ** directory listing if name= is omitted.
2179 */
2180 if( zName==0 ){
2181 if( isFile ){
2182 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2183 page_tree();
2184 return;
2185 }
2186 style_header("Missing name= query parameter");
2187 @ The name= query parameter is missing
2188 style_footer();
2189 return;
2190 }
2191
2192 url_initialize(&url, g.zPath);
2193 url_add_parameter(&url, "name", zName);
2194 url_add_parameter(&url, "ci", zCI);
2195
2196 if( zCI==0 && !isFile ){
2197 /* If there is no ci= query parameter, then prefer to interpret
2198 ** name= as a hash for /artifact and /whatis. But for not for /file.
2199 ** For /file, a name= without a ci= while prefer to use the default
2200 ** "tip" value for ci=. */
2201 rid = name_to_rid(zName);
2202 }
2203 if( rid==0 ){
2204 rid = artifact_from_ci_and_filename(0);
2205 }
2206
2207 if( rid==0 ){ /* Artifact not found */
2208 if( isFile ){
2209 /* For /file, also check to see if name= refers to a directory,
2210 ** and if so, do a listing for that directory */
2211 int nName = (int)strlen(zName);
2212 if( nName && zName[nName-1]=='/' ) nName--;
2213 if( db_exists(
2214 "SELECT 1 FROM filename"
2215 " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2216 nName, zName, nName+1, nName, zName
2217 ) ){
2218 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2219 page_tree();
2220 return;
2221 }
2222 style_header("No such file");
2223 @ File '%h(zName)' does not exist in this repository.
2224 }else{
2225 style_header("No such artifact");
2226 @ Artifact '%h(zName)' does not exist in this repository.
2227 }
2228 style_footer();
2229 return;
2230 }
2231
2232 if( descOnly || P("verbose")!=0 ){
2233 url_add_parameter(&url, "verbose", "1");
2234 objdescFlags |= OBJDESC_DETAIL;
2235 }
2236 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2237
2238 asText = P("txt")!=0;
2239 if( isFile ){
2240 if( zCI==0 || fossil_strcmp(zCI,"tip")==0 ){
2241 zCI = "tip";
2242 @ <h2>File %z(href("%R/finfo?name=%T&m=tip",zName))%h(zName)</a>
2243 @ from the %z(href("%R/info/tip"))latest check-in</a></h2>
2244 }else{
2245 const char *zPath;
2246 Blob path;
2247 blob_zero(&path);
2248 hyperlinked_path(zName, &path, zCI, "dir", "", LINKPATH_FINFO);
2249 zPath = blob_str(&path);
2250 @ <h2>File %s(zPath) \
2251 if( isBranchCI ){
2252 @ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
2253 }else if( isSymbolicCI ){
2254 @ as of check-in %z(href("%R/info/%!S",zCIUuid))%s(zCI)</a></h2>
2255 }else{
2256 @ as of check-in [%z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
2257 }
2258 blob_reset(&path);
2259 }
2260 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2261 style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T",
2262 zName, zCI);
2263 style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T",
2264 zName, zCI);
2265 blob_init(&downloadName, zName, -1);
2266 objType = OBJTYPE_CONTENT;
2267 }else{
2268 @ <h2>Artifact
2269 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2270 if( g.perm.Setup ){
2271 @ (%d(rid)):</h2>
2272 }else{
2273 @ :</h2>
2274 }
2275 blob_zero(&downloadName);
2276 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2277 objType = object_description(rid, objdescFlags,
2278 (isFile?zName:0), &downloadName);
2279 }
 
 
 
 
2280 if( !descOnly && P("download")!=0 ){
2281 cgi_redirectf("%R/raw/%s?at=%T",
2282 db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
2283 file_tail(blob_str(&downloadName)));
2284 /*NOTREACHED*/
2285 }
2286 if( g.perm.Admin ){
2287 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
2288 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2227,13 +2290,28 @@
2290 g.zTop, zUuid);
2291 }else{
2292 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2293 }
2294 }
2295
2296 if( isFile ){
2297 if( isSymbolicCI ){
2298 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2299 }else if( zCI ){
2300 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2301 }else{
2302 zHeader = mprintf("%s", file_tail(zName));
2303 }
2304 }else if( descOnly ){
2305 zHeader = mprintf("Artifact Description [%S]", zUuid);
2306 }else{
2307 zHeader = mprintf("Artifact [%S]", zUuid);
2308 }
2309 style_header("%s", zHeader);
2310 fossil_free(zCIUuid);
2311 fossil_free(zHeader);
2312 if( !isFile && g.perm.Admin ){
2313 Stmt q;
2314 db_prepare(&q,
2315 "SELECT coalesce(user.login,rcvfrom.uid),"
2316 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2317 " FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
@@ -2253,12 +2331,11 @@
2331 zBr, blob_str(&downloadName));
2332 style_submenu_element("Tip", "%R/file/%T?ci=%T",
2333 blob_str(&downloadName), zBr);
2334 fossil_free((void *)zBr);
2335 }
2336 style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName));
 
2337 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
2338 style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
2339 }
2340 zMime = mimetype_from_name(blob_str(&downloadName));
2341 if( zMime ){
@@ -2288,11 +2365,11 @@
2365 @ <hr />
2366 content_get(rid, &content);
2367 if( renderAsWiki ){
2368 wiki_render_by_mimetype(&content, zMime);
2369 }else if( renderAsHtml ){
2370 @ <iframe src="%R/raw/%s(zUuid)"
2371 @ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
2372 @ sandbox="allow-same-origin" id="ifm1">
2373 @ </iframe>
2374 @ <script nonce="%h(style_nonce())">
2375 @ document.getElementById("ifm1").addEventListener("load",
@@ -2717,15 +2794,15 @@
2794 **
2795 ** Edit a check-in. (Check-ins are immutable and do not really change.
2796 ** This page really creates supplemental tags that affect the display
2797 ** of the check-in.)
2798 **
2799 ** Query parameters:
2800 **
2801 ** rid=INTEGER Record ID of the check-in to edit (REQUIRED)
2802 **
2803 ** POST parameters after pressing "Preview", "Cancel", or "Apply":
2804 **
2805 ** c=TEXT New check-in comment
2806 ** u=TEXT New user name
2807 ** newclr Apply a background color
2808 ** clr=TEXT New background color (only if newclr)
2809
+34 -28
--- src/login.c
+++ src/login.c
@@ -678,20 +678,18 @@
678678
}else{
679679
zAnonPw = 0;
680680
}
681681
@ <table class="login_out">
682682
@ <tr>
683
- @ <td class="form_label">User ID:</td>
684
- if( anonFlag ){
685
- @ <td><input type="text" id="u" name="u" value="anonymous" size="30"></td>
686
- }else{
687
- @ <td><input type="text" id="u" name="u" value="" size="30" /></td>
688
- }
683
+ @ <td class="form_label" id="userlabel1">User ID:</td>
684
+ @ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
685
+ @ size="30" value="%s(anonFlag?"anonymous":"")"></td>
689686
@ </tr>
690687
@ <tr>
691
- @ <td class="form_label">Password:</td>
692
- @ <td><input type="password" id="p" name="p" value="" size="30" />\
688
+ @ <td class="form_label" id="pswdlabel">Password:</td>
689
+ @ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
690
+ @ name="p" value="" size="30" />\
693691
if( zAnonPw && !noAnon ){
694692
captcha_speakit_button(uSeed, "Speak password for \"anonymous\"");
695693
}
696694
@ </td>
697695
@ </tr>
@@ -750,16 +748,19 @@
750748
if( g.perm.Password ){
751749
@ <hr>
752750
@ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
753751
form_begin(0, "%R/login");
754752
@ <table>
755
- @ <tr><td class="form_label">Old Password:</td>
756
- @ <td><input type="password" name="p" size="30" /></td></tr>
757
- @ <tr><td class="form_label">New Password:</td>
758
- @ <td><input type="password" name="n1" size="30" /></td></tr>
759
- @ <tr><td class="form_label">Repeat New Password:</td>
760
- @ <td><input type="password" name="n2" size="30" /></td></tr>
753
+ @ <tr><td class="form_label" id="oldpw">Old Password:</td>
754
+ @ <td><input aria-labelledby="oldpw" type="password" name="p" \
755
+ @ size="30"/></td></tr>
756
+ @ <tr><td class="form_label" id="newpw">New Password:</td>
757
+ @ <td><input aria-labelledby="newpw" type="password" name="n1" \
758
+ @ size="30" /></td></tr>
759
+ @ <tr><td class="form_label" id="reppw">Repeat New Password:</td>
760
+ @ <td><input aria-labledby="reppw" type="password" name="n2" \
761
+ @ size="30" /></td></tr>
761762
@ <tr><td></td>
762763
@ <td><input type="submit" value="Change Password" /></td></tr>
763764
@ </table>
764765
@ </form>
765766
}
@@ -1690,57 +1691,62 @@
16901691
@ <input type="hidden" name="g" value="%h(P("g"))" />
16911692
}
16921693
@ <p><input type="hidden" name="captchaseed" value="%u(uSeed)" />
16931694
@ <table class="login_out">
16941695
@ <tr>
1695
- @ <td class="form_label" align="right">User ID:</td>
1696
- @ <td><input type="text" name="u" value="%h(zUserID)" size="30"></td>
1696
+ @ <td class="form_label" align="right" id="uid">User ID:</td>
1697
+ @ <td><input aria-labelledby="uid" type="text" name="u" \
1698
+ @ value="%h(zUserID)" size="30"></td>
16971699
@
16981700
if( iErrLine==1 ){
16991701
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17001702
}
17011703
@ <tr>
1702
- @ <td class="form_label" align="right">Display Name:</td>
1703
- @ <td><input type="text" name="dn" value="%h(zDName)" size="30"></td>
1704
+ @ <td class="form_label" align="right" id="dpyname">Display Name:</td>
1705
+ @ <td><input aria-labelledby="dpyname" type="text" name="dn" \
1706
+ @ value="%h(zDName)" size="30"></td>
17041707
@ </tr>
17051708
if( iErrLine==2 ){
17061709
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17071710
}
17081711
@ </tr>
17091712
@ <tr>
1710
- @ <td class="form_label" align="right">Email Address:</td>
1711
- @ <td><input type="text" name="ea" value="%h(zEAddr)" size="30"></td>
1713
+ @ <td class="form_label" align="right" id="emaddr">Email Address:</td>
1714
+ @ <td><input aria-labelledby="emaddr" type="text" name="ea" \
1715
+ @ value="%h(zEAddr)" size="30"></td>
17121716
@ </tr>
17131717
if( iErrLine==3 ){
17141718
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17151719
}
17161720
if( canDoAlerts ){
17171721
int a = atoi(PD("alerts","1"));
17181722
@ <tr>
1719
- @ <td class="form_label" align="right">Email&nbsp;Alerts?</td>
1720
- @ <td><select size='1' name='alerts'>
1723
+ @ <td class="form_label" align="right" id="emalrt">Email&nbsp;Alerts?</td>
1724
+ @ <td><select aria-labelledby="emalrt" size='1' name='alerts'>
17211725
@ <option value="1" %s(a?"selected":"")>Yes</option>
17221726
@ <option value="0" %s(!a?"selected":"")>No</option>
17231727
@ </select></td></tr>
17241728
}
17251729
@ <tr>
1726
- @ <td class="form_label" align="right">Password:</td>
1727
- @ <td><input type="password" name="p" value="%h(zPasswd)" size="30"></td>
1730
+ @ <td class="form_label" align="right" id="pswd">Password:</td>
1731
+ @ <td><input aria-labelledby="pswd" type="password" name="p" \
1732
+ @ value="%h(zPasswd)" size="30"></td>
17281733
@ <tr>
17291734
if( iErrLine==4 ){
17301735
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17311736
}
17321737
@ <tr>
1733
- @ <td class="form_label" align="right">Confirm:</td>
1734
- @ <td><input type="password" name="cp" value="%h(zConfirm)" size="30"></td>
1738
+ @ <td class="form_label" align="right" id="pwcfrm">Confirm:</td>
1739
+ @ <td><input aria-labelledby="pwcfrm" type="password" name="cp" \
1740
+ @ value="%h(zConfirm)" size="30"></td>
17351741
@ </tr>
17361742
if( iErrLine==5 ){
17371743
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17381744
}
17391745
@ <tr>
1740
- @ <td class="form_label" align="right">Captcha:</td>
1741
- @ <td><input type="text" name="captcha" size="30"\
1746
+ @ <td class="form_label" align="right" id="cptcha">Captcha:</td>
1747
+ @ <td><input type="text" name="captcha" aria-labelledby="cptcha" \
17421748
@ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
17431749
captcha_speakit_button(uSeed, "Speak the captcha text");
17441750
@ </td>
17451751
@ </tr>
17461752
if( iErrLine==6 ){
17471753
--- src/login.c
+++ src/login.c
@@ -678,20 +678,18 @@
678 }else{
679 zAnonPw = 0;
680 }
681 @ <table class="login_out">
682 @ <tr>
683 @ <td class="form_label">User ID:</td>
684 if( anonFlag ){
685 @ <td><input type="text" id="u" name="u" value="anonymous" size="30"></td>
686 }else{
687 @ <td><input type="text" id="u" name="u" value="" size="30" /></td>
688 }
689 @ </tr>
690 @ <tr>
691 @ <td class="form_label">Password:</td>
692 @ <td><input type="password" id="p" name="p" value="" size="30" />\
 
693 if( zAnonPw && !noAnon ){
694 captcha_speakit_button(uSeed, "Speak password for \"anonymous\"");
695 }
696 @ </td>
697 @ </tr>
@@ -750,16 +748,19 @@
750 if( g.perm.Password ){
751 @ <hr>
752 @ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
753 form_begin(0, "%R/login");
754 @ <table>
755 @ <tr><td class="form_label">Old Password:</td>
756 @ <td><input type="password" name="p" size="30" /></td></tr>
757 @ <tr><td class="form_label">New Password:</td>
758 @ <td><input type="password" name="n1" size="30" /></td></tr>
759 @ <tr><td class="form_label">Repeat New Password:</td>
760 @ <td><input type="password" name="n2" size="30" /></td></tr>
 
 
 
761 @ <tr><td></td>
762 @ <td><input type="submit" value="Change Password" /></td></tr>
763 @ </table>
764 @ </form>
765 }
@@ -1690,57 +1691,62 @@
1690 @ <input type="hidden" name="g" value="%h(P("g"))" />
1691 }
1692 @ <p><input type="hidden" name="captchaseed" value="%u(uSeed)" />
1693 @ <table class="login_out">
1694 @ <tr>
1695 @ <td class="form_label" align="right">User ID:</td>
1696 @ <td><input type="text" name="u" value="%h(zUserID)" size="30"></td>
 
1697 @
1698 if( iErrLine==1 ){
1699 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1700 }
1701 @ <tr>
1702 @ <td class="form_label" align="right">Display Name:</td>
1703 @ <td><input type="text" name="dn" value="%h(zDName)" size="30"></td>
 
1704 @ </tr>
1705 if( iErrLine==2 ){
1706 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1707 }
1708 @ </tr>
1709 @ <tr>
1710 @ <td class="form_label" align="right">Email Address:</td>
1711 @ <td><input type="text" name="ea" value="%h(zEAddr)" size="30"></td>
 
1712 @ </tr>
1713 if( iErrLine==3 ){
1714 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1715 }
1716 if( canDoAlerts ){
1717 int a = atoi(PD("alerts","1"));
1718 @ <tr>
1719 @ <td class="form_label" align="right">Email&nbsp;Alerts?</td>
1720 @ <td><select size='1' name='alerts'>
1721 @ <option value="1" %s(a?"selected":"")>Yes</option>
1722 @ <option value="0" %s(!a?"selected":"")>No</option>
1723 @ </select></td></tr>
1724 }
1725 @ <tr>
1726 @ <td class="form_label" align="right">Password:</td>
1727 @ <td><input type="password" name="p" value="%h(zPasswd)" size="30"></td>
 
1728 @ <tr>
1729 if( iErrLine==4 ){
1730 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1731 }
1732 @ <tr>
1733 @ <td class="form_label" align="right">Confirm:</td>
1734 @ <td><input type="password" name="cp" value="%h(zConfirm)" size="30"></td>
 
1735 @ </tr>
1736 if( iErrLine==5 ){
1737 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1738 }
1739 @ <tr>
1740 @ <td class="form_label" align="right">Captcha:</td>
1741 @ <td><input type="text" name="captcha" size="30"\
1742 @ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
1743 captcha_speakit_button(uSeed, "Speak the captcha text");
1744 @ </td>
1745 @ </tr>
1746 if( iErrLine==6 ){
1747
--- src/login.c
+++ src/login.c
@@ -678,20 +678,18 @@
678 }else{
679 zAnonPw = 0;
680 }
681 @ <table class="login_out">
682 @ <tr>
683 @ <td class="form_label" id="userlabel1">User ID:</td>
684 @ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
685 @ size="30" value="%s(anonFlag?"anonymous":"")"></td>
 
 
 
686 @ </tr>
687 @ <tr>
688 @ <td class="form_label" id="pswdlabel">Password:</td>
689 @ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
690 @ name="p" value="" size="30" />\
691 if( zAnonPw && !noAnon ){
692 captcha_speakit_button(uSeed, "Speak password for \"anonymous\"");
693 }
694 @ </td>
695 @ </tr>
@@ -750,16 +748,19 @@
748 if( g.perm.Password ){
749 @ <hr>
750 @ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
751 form_begin(0, "%R/login");
752 @ <table>
753 @ <tr><td class="form_label" id="oldpw">Old Password:</td>
754 @ <td><input aria-labelledby="oldpw" type="password" name="p" \
755 @ size="30"/></td></tr>
756 @ <tr><td class="form_label" id="newpw">New Password:</td>
757 @ <td><input aria-labelledby="newpw" type="password" name="n1" \
758 @ size="30" /></td></tr>
759 @ <tr><td class="form_label" id="reppw">Repeat New Password:</td>
760 @ <td><input aria-labledby="reppw" type="password" name="n2" \
761 @ size="30" /></td></tr>
762 @ <tr><td></td>
763 @ <td><input type="submit" value="Change Password" /></td></tr>
764 @ </table>
765 @ </form>
766 }
@@ -1690,57 +1691,62 @@
1691 @ <input type="hidden" name="g" value="%h(P("g"))" />
1692 }
1693 @ <p><input type="hidden" name="captchaseed" value="%u(uSeed)" />
1694 @ <table class="login_out">
1695 @ <tr>
1696 @ <td class="form_label" align="right" id="uid">User ID:</td>
1697 @ <td><input aria-labelledby="uid" type="text" name="u" \
1698 @ value="%h(zUserID)" size="30"></td>
1699 @
1700 if( iErrLine==1 ){
1701 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1702 }
1703 @ <tr>
1704 @ <td class="form_label" align="right" id="dpyname">Display Name:</td>
1705 @ <td><input aria-labelledby="dpyname" type="text" name="dn" \
1706 @ value="%h(zDName)" size="30"></td>
1707 @ </tr>
1708 if( iErrLine==2 ){
1709 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1710 }
1711 @ </tr>
1712 @ <tr>
1713 @ <td class="form_label" align="right" id="emaddr">Email Address:</td>
1714 @ <td><input aria-labelledby="emaddr" type="text" name="ea" \
1715 @ value="%h(zEAddr)" size="30"></td>
1716 @ </tr>
1717 if( iErrLine==3 ){
1718 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1719 }
1720 if( canDoAlerts ){
1721 int a = atoi(PD("alerts","1"));
1722 @ <tr>
1723 @ <td class="form_label" align="right" id="emalrt">Email&nbsp;Alerts?</td>
1724 @ <td><select aria-labelledby="emalrt" size='1' name='alerts'>
1725 @ <option value="1" %s(a?"selected":"")>Yes</option>
1726 @ <option value="0" %s(!a?"selected":"")>No</option>
1727 @ </select></td></tr>
1728 }
1729 @ <tr>
1730 @ <td class="form_label" align="right" id="pswd">Password:</td>
1731 @ <td><input aria-labelledby="pswd" type="password" name="p" \
1732 @ value="%h(zPasswd)" size="30"></td>
1733 @ <tr>
1734 if( iErrLine==4 ){
1735 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1736 }
1737 @ <tr>
1738 @ <td class="form_label" align="right" id="pwcfrm">Confirm:</td>
1739 @ <td><input aria-labelledby="pwcfrm" type="password" name="cp" \
1740 @ value="%h(zConfirm)" size="30"></td>
1741 @ </tr>
1742 if( iErrLine==5 ){
1743 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1744 }
1745 @ <tr>
1746 @ <td class="form_label" align="right" id="cptcha">Captcha:</td>
1747 @ <td><input type="text" name="captcha" aria-labelledby="cptcha" \
1748 @ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
1749 captcha_speakit_button(uSeed, "Speak the captcha text");
1750 @ </td>
1751 @ </tr>
1752 if( iErrLine==6 ){
1753
+55 -25
--- src/markdown.c
+++ src/markdown.c
@@ -466,10 +466,51 @@
466466
end = i;
467467
}
468468
}
469469
}
470470
471
+/*
472
+** data[*pI] should be a "`" character that introduces a code-span.
473
+** The code-span boundry mark can be any number of one or more "`"
474
+** characters. We do not know the size of the boundry marker, only
475
+** that there is at least one "`" at data[*pI].
476
+**
477
+** This routine increases *pI to move it past the code-span, including
478
+** the closing boundary mark. Or, if the code-span is unterminated,
479
+** this routine moves *pI past the opening boundary mark only.
480
+*/
481
+static void skip_codespan(const char *data, size_t size, size_t *pI){
482
+ size_t i = *pI;
483
+ size_t span_nb; /* Number of "`" characters in the boundary mark */
484
+ size_t bt;
485
+
486
+ assert( i<size );
487
+ assert( data[i]=='`' );
488
+ data += i;
489
+ size -= i;
490
+
491
+ /* counting the number of opening backticks */
492
+ i = 0;
493
+ span_nb = 0;
494
+ while( i<size && data[i]=='`' ){
495
+ i++;
496
+ span_nb++;
497
+ }
498
+ if( i>=size ){
499
+ *pI += span_nb;
500
+ return;
501
+ }
502
+
503
+ /* finding the matching closing sequence */
504
+ bt = 0;
505
+ while( i<size && bt<span_nb ){
506
+ if( data[i]=='`' ) bt += 1; else bt = 0;
507
+ i++;
508
+ }
509
+ *pI += (bt == span_nb) ? i : span_nb;
510
+}
511
+
471512
472513
/* find_emph_char -- looks for the next emph char, skipping other constructs */
473514
static size_t find_emph_char(char *data, size_t size, char c){
474515
size_t i = 1;
475516
@@ -483,34 +524,13 @@
483524
continue;
484525
}
485526
486527
if( data[i]==c ) return i;
487528
488
- /* skipping a code span */
489
- if( data[i]=='`' ){
490
- size_t span_nb = 0, bt;
491
- size_t tmp_i = 0;
492
-
493
- /* counting the number of opening backticks */
494
- while( i<size && data[i]=='`' ){
495
- i++;
496
- span_nb++;
497
- }
498
- if( i>=size ) return 0;
499
-
500
- /* finding the matching closing sequence */
501
- bt = 0;
502
- while( i<size && bt<span_nb ){
503
- if( !tmp_i && data[i]==c ) tmp_i = i;
504
- if( data[i]=='`' ) bt += 1; else bt = 0;
505
- i++;
506
- }
507
- if( i>=size ) return tmp_i;
508
- i++;
509
-
510
- /* skipping a link */
511
- }else if( data[i]=='[' ){
529
+ if( data[i]=='`' ){ /* skip a code span */
530
+ skip_codespan(data, size, &i);
531
+ }else if( data[i]=='[' ){ /* skip a link */
512532
size_t tmp_i = 0;
513533
char cc;
514534
i++;
515535
while( i<size && data[i]!=']' ){
516536
if( !tmp_i && data[i]==c ) tmp_i = i;
@@ -1174,10 +1194,14 @@
11741194
if( i<size && data[i]=='|') outer_sep++;
11751195
11761196
/* count the number of pipes in the line */
11771197
for(n_sep=0; i<size && data[i]!='\n'; i++){
11781198
if( is_table_sep(data, i) ) n_sep++;
1199
+ if( data[i]=='`' ){
1200
+ skip_codespan(data, size, &i);
1201
+ i--;
1202
+ }
11791203
}
11801204
11811205
/* march back to check for optional last '|' before blanks and EOL */
11821206
while( i && (data[i-1]==' ' || data[i-1]=='\t' || data[i-1]=='\n') ){ i--; }
11831207
if( i && is_table_sep(data, i-1) ) outer_sep += 1;
@@ -1834,11 +1858,17 @@
18341858
/* skip blanks */
18351859
while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
18361860
beg = i;
18371861
18381862
/* forward to the next separator or EOL */
1839
- while( i<size && !is_table_sep(data, i) && data[i]!='\n' ){ i++; }
1863
+ while( i<size && !is_table_sep(data, i) && data[i]!='\n' ){
1864
+ if( data[i]=='`' ){
1865
+ skip_codespan(data, size, &i);
1866
+ }else{
1867
+ i++;
1868
+ }
1869
+ }
18401870
end = i;
18411871
if( i<size ){
18421872
i++;
18431873
if( data[i-1]=='\n' ) total = i;
18441874
}
18451875
--- src/markdown.c
+++ src/markdown.c
@@ -466,10 +466,51 @@
466 end = i;
467 }
468 }
469 }
470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
472 /* find_emph_char -- looks for the next emph char, skipping other constructs */
473 static size_t find_emph_char(char *data, size_t size, char c){
474 size_t i = 1;
475
@@ -483,34 +524,13 @@
483 continue;
484 }
485
486 if( data[i]==c ) return i;
487
488 /* skipping a code span */
489 if( data[i]=='`' ){
490 size_t span_nb = 0, bt;
491 size_t tmp_i = 0;
492
493 /* counting the number of opening backticks */
494 while( i<size && data[i]=='`' ){
495 i++;
496 span_nb++;
497 }
498 if( i>=size ) return 0;
499
500 /* finding the matching closing sequence */
501 bt = 0;
502 while( i<size && bt<span_nb ){
503 if( !tmp_i && data[i]==c ) tmp_i = i;
504 if( data[i]=='`' ) bt += 1; else bt = 0;
505 i++;
506 }
507 if( i>=size ) return tmp_i;
508 i++;
509
510 /* skipping a link */
511 }else if( data[i]=='[' ){
512 size_t tmp_i = 0;
513 char cc;
514 i++;
515 while( i<size && data[i]!=']' ){
516 if( !tmp_i && data[i]==c ) tmp_i = i;
@@ -1174,10 +1194,14 @@
1174 if( i<size && data[i]=='|') outer_sep++;
1175
1176 /* count the number of pipes in the line */
1177 for(n_sep=0; i<size && data[i]!='\n'; i++){
1178 if( is_table_sep(data, i) ) n_sep++;
 
 
 
 
1179 }
1180
1181 /* march back to check for optional last '|' before blanks and EOL */
1182 while( i && (data[i-1]==' ' || data[i-1]=='\t' || data[i-1]=='\n') ){ i--; }
1183 if( i && is_table_sep(data, i-1) ) outer_sep += 1;
@@ -1834,11 +1858,17 @@
1834 /* skip blanks */
1835 while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
1836 beg = i;
1837
1838 /* forward to the next separator or EOL */
1839 while( i<size && !is_table_sep(data, i) && data[i]!='\n' ){ i++; }
 
 
 
 
 
 
1840 end = i;
1841 if( i<size ){
1842 i++;
1843 if( data[i-1]=='\n' ) total = i;
1844 }
1845
--- src/markdown.c
+++ src/markdown.c
@@ -466,10 +466,51 @@
466 end = i;
467 }
468 }
469 }
470
471 /*
472 ** data[*pI] should be a "`" character that introduces a code-span.
473 ** The code-span boundry mark can be any number of one or more "`"
474 ** characters. We do not know the size of the boundry marker, only
475 ** that there is at least one "`" at data[*pI].
476 **
477 ** This routine increases *pI to move it past the code-span, including
478 ** the closing boundary mark. Or, if the code-span is unterminated,
479 ** this routine moves *pI past the opening boundary mark only.
480 */
481 static void skip_codespan(const char *data, size_t size, size_t *pI){
482 size_t i = *pI;
483 size_t span_nb; /* Number of "`" characters in the boundary mark */
484 size_t bt;
485
486 assert( i<size );
487 assert( data[i]=='`' );
488 data += i;
489 size -= i;
490
491 /* counting the number of opening backticks */
492 i = 0;
493 span_nb = 0;
494 while( i<size && data[i]=='`' ){
495 i++;
496 span_nb++;
497 }
498 if( i>=size ){
499 *pI += span_nb;
500 return;
501 }
502
503 /* finding the matching closing sequence */
504 bt = 0;
505 while( i<size && bt<span_nb ){
506 if( data[i]=='`' ) bt += 1; else bt = 0;
507 i++;
508 }
509 *pI += (bt == span_nb) ? i : span_nb;
510 }
511
512
513 /* find_emph_char -- looks for the next emph char, skipping other constructs */
514 static size_t find_emph_char(char *data, size_t size, char c){
515 size_t i = 1;
516
@@ -483,34 +524,13 @@
524 continue;
525 }
526
527 if( data[i]==c ) return i;
528
529 if( data[i]=='`' ){ /* skip a code span */
530 skip_codespan(data, size, &i);
531 }else if( data[i]=='[' ){ /* skip a link */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532 size_t tmp_i = 0;
533 char cc;
534 i++;
535 while( i<size && data[i]!=']' ){
536 if( !tmp_i && data[i]==c ) tmp_i = i;
@@ -1174,10 +1194,14 @@
1194 if( i<size && data[i]=='|') outer_sep++;
1195
1196 /* count the number of pipes in the line */
1197 for(n_sep=0; i<size && data[i]!='\n'; i++){
1198 if( is_table_sep(data, i) ) n_sep++;
1199 if( data[i]=='`' ){
1200 skip_codespan(data, size, &i);
1201 i--;
1202 }
1203 }
1204
1205 /* march back to check for optional last '|' before blanks and EOL */
1206 while( i && (data[i-1]==' ' || data[i-1]=='\t' || data[i-1]=='\n') ){ i--; }
1207 if( i && is_table_sep(data, i-1) ) outer_sep += 1;
@@ -1834,11 +1858,17 @@
1858 /* skip blanks */
1859 while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
1860 beg = i;
1861
1862 /* forward to the next separator or EOL */
1863 while( i<size && !is_table_sep(data, i) && data[i]!='\n' ){
1864 if( data[i]=='`' ){
1865 skip_codespan(data, size, &i);
1866 }else{
1867 i++;
1868 }
1869 }
1870 end = i;
1871 if( i<size ){
1872 i++;
1873 if( data[i-1]=='\n' ) total = i;
1874 }
1875
+1 -1
--- src/merge3.c
+++ src/merge3.c
@@ -139,11 +139,11 @@
139139
** Text of boundary markers for merge conflicts.
140140
*/
141141
static const char *const mergeMarker[] = {
142142
/*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
143143
"<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n",
144
- "======= COMMON ANCESTOR content follows ============================\n",
144
+ "||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||\n",
145145
"======= MERGED IN content follows ==================================\n",
146146
">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
147147
};
148148
149149
150150
--- src/merge3.c
+++ src/merge3.c
@@ -139,11 +139,11 @@
139 ** Text of boundary markers for merge conflicts.
140 */
141 static const char *const mergeMarker[] = {
142 /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
143 "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n",
144 "======= COMMON ANCESTOR content follows ============================\n",
145 "======= MERGED IN content follows ==================================\n",
146 ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
147 };
148
149
150
--- src/merge3.c
+++ src/merge3.c
@@ -139,11 +139,11 @@
139 ** Text of boundary markers for merge conflicts.
140 */
141 static const char *const mergeMarker[] = {
142 /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
143 "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n",
144 "||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||\n",
145 "======= MERGED IN content follows ==================================\n",
146 ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
147 };
148
149
150
--- src/mkversion.c
+++ src/mkversion.c
@@ -9,27 +9,59 @@
99
*/
1010
#include <stdio.h>
1111
#include <string.h>
1212
#include <stdlib.h>
1313
#include <ctype.h>
14
+#include <time.h>
1415
1516
static FILE *open_for_reading(const char *zFilename){
1617
FILE *f = fopen(zFilename, "r");
1718
if( f==0 ){
1819
fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
1920
exit(1);
2021
}
2122
return f;
2223
}
24
+
25
+/*
26
+** Given an arbitrary-length input string key zIn, generate
27
+** an N-byte hexadecimal hash of that string into zOut.
28
+*/
29
+static void hash(const char *zIn, int N, char *zOut){
30
+ unsigned char i, j, t;
31
+ int m, n;
32
+ unsigned char s[256];
33
+ for(m=0; m<256; m++){ s[m] = m; }
34
+ for(j=0, m=n=0; m<256; m++, n++){
35
+ j += s[m] + zIn[n];
36
+ if( zIn[n]==0 ){ n = -1; }
37
+ t = s[j];
38
+ s[j] = s[m];
39
+ s[m] = t;
40
+ }
41
+ i = j = 0;
42
+ for(n=0; n<N-2; n+=2){
43
+ i++;
44
+ t = s[i];
45
+ j += t;
46
+ s[i] = s[j];
47
+ s[j] = t;
48
+ t += s[i];
49
+ zOut[n] = "0123456789abcdef"[(t>>4)&0xf];
50
+ zOut[n+1] = "0123456789abcdef"[t&0xf];
51
+ }
52
+ zOut[n] = 0;
53
+}
2354
2455
int main(int argc, char *argv[]){
2556
FILE *m,*u,*v;
2657
char *z;
2758
#if defined(__DMC__) /* e.g. 0x857 */
2859
int i = 0;
2960
#endif
3061
int j = 0, x = 0, d = 0;
62
+ size_t n;
3163
int vn[3];
3264
char b[1000];
3365
char vx[1000];
3466
if( argc!=4 ){
3567
fprintf(stderr, "Usage: %s manifest.uuid manifest VERSION\n", argv[0]);
@@ -45,10 +77,16 @@
4577
fclose(u);
4678
for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
4779
*z = 0;
4880
printf("#define MANIFEST_UUID \"%s\"\n",b);
4981
printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
82
+ n = strlen(b);
83
+ if( n + 50 < sizeof(b) ){
84
+ sprintf(b+n, "%d", (int)time(0));
85
+ hash(b,33,vx);
86
+ printf("#define FOSSIL_BUILD_HASH \"%s\"\n", vx);
87
+ }
5088
m = open_for_reading(argv[2]);
5189
while(b == fgets(b, sizeof(b)-1,m)){
5290
if(0 == strncmp("D ",b,2)){
5391
int k, n;
5492
char zDateNum[30];
5593
--- src/mkversion.c
+++ src/mkversion.c
@@ -9,27 +9,59 @@
9 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <ctype.h>
 
14
15 static FILE *open_for_reading(const char *zFilename){
16 FILE *f = fopen(zFilename, "r");
17 if( f==0 ){
18 fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
19 exit(1);
20 }
21 return f;
22 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
24 int main(int argc, char *argv[]){
25 FILE *m,*u,*v;
26 char *z;
27 #if defined(__DMC__) /* e.g. 0x857 */
28 int i = 0;
29 #endif
30 int j = 0, x = 0, d = 0;
 
31 int vn[3];
32 char b[1000];
33 char vx[1000];
34 if( argc!=4 ){
35 fprintf(stderr, "Usage: %s manifest.uuid manifest VERSION\n", argv[0]);
@@ -45,10 +77,16 @@
45 fclose(u);
46 for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
47 *z = 0;
48 printf("#define MANIFEST_UUID \"%s\"\n",b);
49 printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
 
 
 
 
 
 
50 m = open_for_reading(argv[2]);
51 while(b == fgets(b, sizeof(b)-1,m)){
52 if(0 == strncmp("D ",b,2)){
53 int k, n;
54 char zDateNum[30];
55
--- src/mkversion.c
+++ src/mkversion.c
@@ -9,27 +9,59 @@
9 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <time.h>
15
16 static FILE *open_for_reading(const char *zFilename){
17 FILE *f = fopen(zFilename, "r");
18 if( f==0 ){
19 fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
20 exit(1);
21 }
22 return f;
23 }
24
25 /*
26 ** Given an arbitrary-length input string key zIn, generate
27 ** an N-byte hexadecimal hash of that string into zOut.
28 */
29 static void hash(const char *zIn, int N, char *zOut){
30 unsigned char i, j, t;
31 int m, n;
32 unsigned char s[256];
33 for(m=0; m<256; m++){ s[m] = m; }
34 for(j=0, m=n=0; m<256; m++, n++){
35 j += s[m] + zIn[n];
36 if( zIn[n]==0 ){ n = -1; }
37 t = s[j];
38 s[j] = s[m];
39 s[m] = t;
40 }
41 i = j = 0;
42 for(n=0; n<N-2; n+=2){
43 i++;
44 t = s[i];
45 j += t;
46 s[i] = s[j];
47 s[j] = t;
48 t += s[i];
49 zOut[n] = "0123456789abcdef"[(t>>4)&0xf];
50 zOut[n+1] = "0123456789abcdef"[t&0xf];
51 }
52 zOut[n] = 0;
53 }
54
55 int main(int argc, char *argv[]){
56 FILE *m,*u,*v;
57 char *z;
58 #if defined(__DMC__) /* e.g. 0x857 */
59 int i = 0;
60 #endif
61 int j = 0, x = 0, d = 0;
62 size_t n;
63 int vn[3];
64 char b[1000];
65 char vx[1000];
66 if( argc!=4 ){
67 fprintf(stderr, "Usage: %s manifest.uuid manifest VERSION\n", argv[0]);
@@ -45,10 +77,16 @@
77 fclose(u);
78 for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
79 *z = 0;
80 printf("#define MANIFEST_UUID \"%s\"\n",b);
81 printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
82 n = strlen(b);
83 if( n + 50 < sizeof(b) ){
84 sprintf(b+n, "%d", (int)time(0));
85 hash(b,33,vx);
86 printf("#define FOSSIL_BUILD_HASH \"%s\"\n", vx);
87 }
88 m = open_for_reading(argv[2]);
89 while(b == fgets(b, sizeof(b)-1,m)){
90 if(0 == strncmp("D ",b,2)){
91 int k, n;
92 char zDateNum[30];
93
+3 -3
--- src/name.c
+++ src/name.c
@@ -614,11 +614,11 @@
614614
while( db_step(&q)==SQLITE_ROW ){
615615
const char *zUuid = db_column_text(&q, 0);
616616
int rid = db_column_int(&q, 1);
617617
@ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
618618
@ %s(zUuid)</a> -
619
- object_description(rid, 0, 0);
619
+ object_description(rid, 0, 0, 0);
620620
@ </p></li>
621621
}
622622
db_finalize(&q);
623623
db_prepare(&q,
624624
" SELECT tkt_rid, tkt_uuid, title"
@@ -636,11 +636,11 @@
636636
@ <ul></ul>
637637
@ Ticket
638638
hyperlink_to_uuid(zUuid);
639639
@ - %h(zTitle).
640640
@ <ul><li>
641
- object_description(rid, 0, 0);
641
+ object_description(rid, 0, 0, 0);
642642
@ </li></ul>
643643
@ </p></li>
644644
}
645645
db_finalize(&q);
646646
db_prepare(&q,
@@ -652,11 +652,11 @@
652652
int rid = db_column_int(&q, 0);
653653
const char* zUuid = db_column_text(&q, 1);
654654
@ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
655655
@ %s(zUuid)</a> -
656656
@ <ul><li>
657
- object_description(rid, 0, 0);
657
+ object_description(rid, 0, 0, 0);
658658
@ </li></ul>
659659
@ </p></li>
660660
}
661661
@ </ol>
662662
db_finalize(&q);
663663
--- src/name.c
+++ src/name.c
@@ -614,11 +614,11 @@
614 while( db_step(&q)==SQLITE_ROW ){
615 const char *zUuid = db_column_text(&q, 0);
616 int rid = db_column_int(&q, 1);
617 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
618 @ %s(zUuid)</a> -
619 object_description(rid, 0, 0);
620 @ </p></li>
621 }
622 db_finalize(&q);
623 db_prepare(&q,
624 " SELECT tkt_rid, tkt_uuid, title"
@@ -636,11 +636,11 @@
636 @ <ul></ul>
637 @ Ticket
638 hyperlink_to_uuid(zUuid);
639 @ - %h(zTitle).
640 @ <ul><li>
641 object_description(rid, 0, 0);
642 @ </li></ul>
643 @ </p></li>
644 }
645 db_finalize(&q);
646 db_prepare(&q,
@@ -652,11 +652,11 @@
652 int rid = db_column_int(&q, 0);
653 const char* zUuid = db_column_text(&q, 1);
654 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
655 @ %s(zUuid)</a> -
656 @ <ul><li>
657 object_description(rid, 0, 0);
658 @ </li></ul>
659 @ </p></li>
660 }
661 @ </ol>
662 db_finalize(&q);
663
--- src/name.c
+++ src/name.c
@@ -614,11 +614,11 @@
614 while( db_step(&q)==SQLITE_ROW ){
615 const char *zUuid = db_column_text(&q, 0);
616 int rid = db_column_int(&q, 1);
617 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
618 @ %s(zUuid)</a> -
619 object_description(rid, 0, 0, 0);
620 @ </p></li>
621 }
622 db_finalize(&q);
623 db_prepare(&q,
624 " SELECT tkt_rid, tkt_uuid, title"
@@ -636,11 +636,11 @@
636 @ <ul></ul>
637 @ Ticket
638 hyperlink_to_uuid(zUuid);
639 @ - %h(zTitle).
640 @ <ul><li>
641 object_description(rid, 0, 0, 0);
642 @ </li></ul>
643 @ </p></li>
644 }
645 db_finalize(&q);
646 db_prepare(&q,
@@ -652,11 +652,11 @@
652 int rid = db_column_int(&q, 0);
653 const char* zUuid = db_column_text(&q, 1);
654 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
655 @ %s(zUuid)</a> -
656 @ <ul><li>
657 object_description(rid, 0, 0, 0);
658 @ </li></ul>
659 @ </p></li>
660 }
661 @ </ol>
662 db_finalize(&q);
663
+3 -3
--- src/name.c
+++ src/name.c
@@ -614,11 +614,11 @@
614614
while( db_step(&q)==SQLITE_ROW ){
615615
const char *zUuid = db_column_text(&q, 0);
616616
int rid = db_column_int(&q, 1);
617617
@ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
618618
@ %s(zUuid)</a> -
619
- object_description(rid, 0, 0);
619
+ object_description(rid, 0, 0, 0);
620620
@ </p></li>
621621
}
622622
db_finalize(&q);
623623
db_prepare(&q,
624624
" SELECT tkt_rid, tkt_uuid, title"
@@ -636,11 +636,11 @@
636636
@ <ul></ul>
637637
@ Ticket
638638
hyperlink_to_uuid(zUuid);
639639
@ - %h(zTitle).
640640
@ <ul><li>
641
- object_description(rid, 0, 0);
641
+ object_description(rid, 0, 0, 0);
642642
@ </li></ul>
643643
@ </p></li>
644644
}
645645
db_finalize(&q);
646646
db_prepare(&q,
@@ -652,11 +652,11 @@
652652
int rid = db_column_int(&q, 0);
653653
const char* zUuid = db_column_text(&q, 1);
654654
@ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
655655
@ %s(zUuid)</a> -
656656
@ <ul><li>
657
- object_description(rid, 0, 0);
657
+ object_description(rid, 0, 0, 0);
658658
@ </li></ul>
659659
@ </p></li>
660660
}
661661
@ </ol>
662662
db_finalize(&q);
663663
--- src/name.c
+++ src/name.c
@@ -614,11 +614,11 @@
614 while( db_step(&q)==SQLITE_ROW ){
615 const char *zUuid = db_column_text(&q, 0);
616 int rid = db_column_int(&q, 1);
617 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
618 @ %s(zUuid)</a> -
619 object_description(rid, 0, 0);
620 @ </p></li>
621 }
622 db_finalize(&q);
623 db_prepare(&q,
624 " SELECT tkt_rid, tkt_uuid, title"
@@ -636,11 +636,11 @@
636 @ <ul></ul>
637 @ Ticket
638 hyperlink_to_uuid(zUuid);
639 @ - %h(zTitle).
640 @ <ul><li>
641 object_description(rid, 0, 0);
642 @ </li></ul>
643 @ </p></li>
644 }
645 db_finalize(&q);
646 db_prepare(&q,
@@ -652,11 +652,11 @@
652 int rid = db_column_int(&q, 0);
653 const char* zUuid = db_column_text(&q, 1);
654 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
655 @ %s(zUuid)</a> -
656 @ <ul><li>
657 object_description(rid, 0, 0);
658 @ </li></ul>
659 @ </p></li>
660 }
661 @ </ol>
662 db_finalize(&q);
663
--- src/name.c
+++ src/name.c
@@ -614,11 +614,11 @@
614 while( db_step(&q)==SQLITE_ROW ){
615 const char *zUuid = db_column_text(&q, 0);
616 int rid = db_column_int(&q, 1);
617 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
618 @ %s(zUuid)</a> -
619 object_description(rid, 0, 0, 0);
620 @ </p></li>
621 }
622 db_finalize(&q);
623 db_prepare(&q,
624 " SELECT tkt_rid, tkt_uuid, title"
@@ -636,11 +636,11 @@
636 @ <ul></ul>
637 @ Ticket
638 hyperlink_to_uuid(zUuid);
639 @ - %h(zTitle).
640 @ <ul><li>
641 object_description(rid, 0, 0, 0);
642 @ </li></ul>
643 @ </p></li>
644 }
645 db_finalize(&q);
646 db_prepare(&q,
@@ -652,11 +652,11 @@
652 int rid = db_column_int(&q, 0);
653 const char* zUuid = db_column_text(&q, 1);
654 @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
655 @ %s(zUuid)</a> -
656 @ <ul><li>
657 object_description(rid, 0, 0, 0);
658 @ </li></ul>
659 @ </p></li>
660 }
661 @ </ol>
662 db_finalize(&q);
663
+3 -3
--- src/printf.c
+++ src/printf.c
@@ -34,11 +34,11 @@
3434
** The following macros help determine those lengths. FOSSIL_HASH_DIGITS
3535
** is the default number of digits to display to humans. This value can
3636
** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL
3737
** is the minimum number of digits to be used in URLs. The number used
3838
** will always be at least 6 more than the number used for human output,
39
-** or 40 if the number of digits in human output is 34 or more.
39
+** or HNAME_MAX, whichever is least.
4040
*/
4141
#ifndef FOSSIL_HASH_DIGITS
4242
# define FOSSIL_HASH_DIGITS 10 /* For %S (human display) */
4343
#endif
4444
#ifndef FOSSIL_HASH_DIGITS_URL
@@ -54,14 +54,14 @@
5454
static int nDigitHuman = 0;
5555
static int nDigitUrl = 0;
5656
if( nDigitHuman==0 ){
5757
nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS);
5858
if( nDigitHuman < 6 ) nDigitHuman = 6;
59
- if( nDigitHuman > 40 ) nDigitHuman = 40;
59
+ if( nDigitHuman > HNAME_MAX ) nDigitHuman = HNAME_MAX;
6060
nDigitUrl = nDigitHuman + 6;
6161
if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL;
62
- if( nDigitUrl > 40 ) nDigitUrl = 40;
62
+ if( nDigitUrl > HNAME_MAX ) nDigitUrl = HNAME_MAX;
6363
}
6464
return bForUrl ? nDigitUrl : nDigitHuman;
6565
}
6666
6767
/*
6868
--- src/printf.c
+++ src/printf.c
@@ -34,11 +34,11 @@
34 ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS
35 ** is the default number of digits to display to humans. This value can
36 ** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL
37 ** is the minimum number of digits to be used in URLs. The number used
38 ** will always be at least 6 more than the number used for human output,
39 ** or 40 if the number of digits in human output is 34 or more.
40 */
41 #ifndef FOSSIL_HASH_DIGITS
42 # define FOSSIL_HASH_DIGITS 10 /* For %S (human display) */
43 #endif
44 #ifndef FOSSIL_HASH_DIGITS_URL
@@ -54,14 +54,14 @@
54 static int nDigitHuman = 0;
55 static int nDigitUrl = 0;
56 if( nDigitHuman==0 ){
57 nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS);
58 if( nDigitHuman < 6 ) nDigitHuman = 6;
59 if( nDigitHuman > 40 ) nDigitHuman = 40;
60 nDigitUrl = nDigitHuman + 6;
61 if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL;
62 if( nDigitUrl > 40 ) nDigitUrl = 40;
63 }
64 return bForUrl ? nDigitUrl : nDigitHuman;
65 }
66
67 /*
68
--- src/printf.c
+++ src/printf.c
@@ -34,11 +34,11 @@
34 ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS
35 ** is the default number of digits to display to humans. This value can
36 ** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL
37 ** is the minimum number of digits to be used in URLs. The number used
38 ** will always be at least 6 more than the number used for human output,
39 ** or HNAME_MAX, whichever is least.
40 */
41 #ifndef FOSSIL_HASH_DIGITS
42 # define FOSSIL_HASH_DIGITS 10 /* For %S (human display) */
43 #endif
44 #ifndef FOSSIL_HASH_DIGITS_URL
@@ -54,14 +54,14 @@
54 static int nDigitHuman = 0;
55 static int nDigitUrl = 0;
56 if( nDigitHuman==0 ){
57 nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS);
58 if( nDigitHuman < 6 ) nDigitHuman = 6;
59 if( nDigitHuman > HNAME_MAX ) nDigitHuman = HNAME_MAX;
60 nDigitUrl = nDigitHuman + 6;
61 if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL;
62 if( nDigitUrl > HNAME_MAX ) nDigitUrl = HNAME_MAX;
63 }
64 return bForUrl ? nDigitUrl : nDigitHuman;
65 }
66
67 /*
68
+33 -25
--- src/setup.c
+++ src/setup.c
@@ -201,16 +201,17 @@
201201
admin_log("Set option [%q] to [%q].",
202202
zVar, iQ ? "on" : "off");
203203
iVal = iQ;
204204
}
205205
}
206
- @ <label><input type="checkbox" name="%s(zQParm)"
206
+ @ <label><input type="checkbox" name="%s(zQParm)" \
207
+ @ aria-label="%s(zLabel[0]?zLabel:zQParm)" \
207208
if( iVal ){
208
- @ checked="checked"
209
+ @ checked="checked" \
209210
}
210211
if( disabled ){
211
- @ disabled="disabled"
212
+ @ disabled="disabled" \
212213
}
213214
@ /> <b>%s(zLabel)</b></label>
214215
}
215216
216217
/*
@@ -232,12 +233,12 @@
232233
db_set(zVar, zQ, 0);
233234
admin_log("Set entry_attribute %Q to: %.*s%s",
234235
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
235236
zVal = zQ;
236237
}
237
- @ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" \
238
- @ size="%d(width)" \
238
+ @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
239
+ @ id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)" \
239240
if( disabled ){
240241
@ disabled="disabled" \
241242
}
242243
@ /> <b>%s(zLabel)</b>
243244
}
@@ -263,16 +264,17 @@
263264
admin_log("Set textarea_attribute %Q to: %.*s%s",
264265
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
265266
z = zQ;
266267
}
267268
if( rows>0 && cols>0 ){
268
- @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)"
269
+ @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" \
270
+ @ aria-label="%h(zLabel[0]?zLabel:zQP)" \
269271
if( disabled ){
270
- @ disabled="disabled"
272
+ @ disabled="disabled" \
271273
}
272274
@ cols="%d(cols)">%h(z)</textarea>
273
- if( zLabel && *zLabel ){
275
+ if( *zLabel ){
274276
@ <span class="textareaLabel">%s(zLabel)</span>
275277
}
276278
}
277279
return z;
278280
}
@@ -297,11 +299,11 @@
297299
db_set(zVar, zQ, 0);
298300
admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
299301
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
300302
z = zQ;
301303
}
302
- @ <select size="1" name="%s(zQP)" id="id%s(zQP)">
304
+ @ <select aria-label="%h(zLabel)" size="1" name="%s(zQP)" id="id%s(zQP)">
303305
for(i=0; i<nChoice*2; i+=2){
304306
const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : "";
305307
@ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option>
306308
}
307309
@ </select> <b>%h(zLabel)</b>
@@ -398,11 +400,11 @@
398400
@ <hr />
399401
onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
400402
"http_authentication_ok", "http_authentication_ok", 0, 0);
401403
@ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
402404
@ variable or the "Authentication:" HTTP header to find the username and
403
- @ password. This is another way of supporting Basic Authenitication.
405
+ @ password. This is another way of supporting Basic Authentication.
404406
@ (Property: "http_authentication_ok")
405407
@ </p>
406408
@
407409
@ <hr />
408410
entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
@@ -606,25 +608,30 @@
606608
@
607609
@ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
608610
login_insert_csrf_secret();
609611
@ <blockquote><table border="0">
610612
@
611
- @ <tr><th align="right">Repository filename in group to join:</th>
612
- @ <td width="5"></td><td>
613
- @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
614
- @
615
- @ <tr><th align="right">Login on the above repo:</th>
616
- @ <td width="5"></td><td>
617
- @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
618
- @
619
- @ <tr><th align="right">Password:</th>
620
- @ <td width="5"></td><td>
621
- @ <input type="password" size="20" name="pw"></td></tr>
622
- @
623
- @ <tr><th align="right">Name of login-group:</th>
624
- @ <td width="5"></td><td>
625
- @ <input type="text" size="30" value="%h(zNewName)" name="newname">
613
+ @ <tr><th align="right" id="rfigtj">Repository filename \
614
+ @ in group to join:</th>
615
+ @ <td width="5"></td><td>
616
+ @ <input aria-labelledby="rfigtj" type="text" size="50" \
617
+ @ value="%h(zRepo)" name="repo"></td></tr>
618
+ @
619
+ @ <tr><th align="right" id="lotar">Login on the above repo:</th>
620
+ @ <td width="5"></td><td>
621
+ @ <input aria-labelledby="lotar" type="text" size="20" \
622
+ @ value="%h(zLogin)" name="login"></td></tr>
623
+ @
624
+ @ <tr><th align="right" id="lgpw">Password:</th>
625
+ @ <td width="5"></td><td>
626
+ @ <input aria-labelledby="lgpw" type="password" size="20" name="pw">\
627
+ @ </td></tr>
628
+ @
629
+ @ <tr><th align="right" id="nolg">Name of login-group:</th>
630
+ @ <td width="5"></td><td>
631
+ @ <input aria-labelledby="nolg" type="text" size="30" \
632
+ @ value="%h(zNewName)" name="newname">
626633
@ (only used if creating a new login-group).</td></tr>
627634
@
628635
@ <tr><td colspan="3" align="center">
629636
@ <input type="submit" value="Join" name="join"></td></tr>
630637
@ </table></blockquote></div></form>
@@ -1137,10 +1144,11 @@
11371144
}
11381145
db_begin_transaction();
11391146
if( P("clear")!=0 && cgi_csrf_safe(1) ){
11401147
db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
11411148
cgi_replace_parameter("adunit","");
1149
+ cgi_replace_parameter("adright","");
11421150
}
11431151
11441152
style_header("Edit Ad Unit");
11451153
@ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
11461154
login_insert_csrf_secret();
11471155
--- src/setup.c
+++ src/setup.c
@@ -201,16 +201,17 @@
201 admin_log("Set option [%q] to [%q].",
202 zVar, iQ ? "on" : "off");
203 iVal = iQ;
204 }
205 }
206 @ <label><input type="checkbox" name="%s(zQParm)"
 
207 if( iVal ){
208 @ checked="checked"
209 }
210 if( disabled ){
211 @ disabled="disabled"
212 }
213 @ /> <b>%s(zLabel)</b></label>
214 }
215
216 /*
@@ -232,12 +233,12 @@
232 db_set(zVar, zQ, 0);
233 admin_log("Set entry_attribute %Q to: %.*s%s",
234 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
235 zVal = zQ;
236 }
237 @ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" \
238 @ size="%d(width)" \
239 if( disabled ){
240 @ disabled="disabled" \
241 }
242 @ /> <b>%s(zLabel)</b>
243 }
@@ -263,16 +264,17 @@
263 admin_log("Set textarea_attribute %Q to: %.*s%s",
264 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
265 z = zQ;
266 }
267 if( rows>0 && cols>0 ){
268 @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)"
 
269 if( disabled ){
270 @ disabled="disabled"
271 }
272 @ cols="%d(cols)">%h(z)</textarea>
273 if( zLabel && *zLabel ){
274 @ <span class="textareaLabel">%s(zLabel)</span>
275 }
276 }
277 return z;
278 }
@@ -297,11 +299,11 @@
297 db_set(zVar, zQ, 0);
298 admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
299 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
300 z = zQ;
301 }
302 @ <select size="1" name="%s(zQP)" id="id%s(zQP)">
303 for(i=0; i<nChoice*2; i+=2){
304 const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : "";
305 @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option>
306 }
307 @ </select> <b>%h(zLabel)</b>
@@ -398,11 +400,11 @@
398 @ <hr />
399 onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
400 "http_authentication_ok", "http_authentication_ok", 0, 0);
401 @ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
402 @ variable or the "Authentication:" HTTP header to find the username and
403 @ password. This is another way of supporting Basic Authenitication.
404 @ (Property: "http_authentication_ok")
405 @ </p>
406 @
407 @ <hr />
408 entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
@@ -606,25 +608,30 @@
606 @
607 @ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
608 login_insert_csrf_secret();
609 @ <blockquote><table border="0">
610 @
611 @ <tr><th align="right">Repository filename in group to join:</th>
612 @ <td width="5"></td><td>
613 @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
614 @
615 @ <tr><th align="right">Login on the above repo:</th>
616 @ <td width="5"></td><td>
617 @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
618 @
619 @ <tr><th align="right">Password:</th>
620 @ <td width="5"></td><td>
621 @ <input type="password" size="20" name="pw"></td></tr>
622 @
623 @ <tr><th align="right">Name of login-group:</th>
624 @ <td width="5"></td><td>
625 @ <input type="text" size="30" value="%h(zNewName)" name="newname">
 
 
 
 
 
626 @ (only used if creating a new login-group).</td></tr>
627 @
628 @ <tr><td colspan="3" align="center">
629 @ <input type="submit" value="Join" name="join"></td></tr>
630 @ </table></blockquote></div></form>
@@ -1137,10 +1144,11 @@
1137 }
1138 db_begin_transaction();
1139 if( P("clear")!=0 && cgi_csrf_safe(1) ){
1140 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
1141 cgi_replace_parameter("adunit","");
 
1142 }
1143
1144 style_header("Edit Ad Unit");
1145 @ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
1146 login_insert_csrf_secret();
1147
--- src/setup.c
+++ src/setup.c
@@ -201,16 +201,17 @@
201 admin_log("Set option [%q] to [%q].",
202 zVar, iQ ? "on" : "off");
203 iVal = iQ;
204 }
205 }
206 @ <label><input type="checkbox" name="%s(zQParm)" \
207 @ aria-label="%s(zLabel[0]?zLabel:zQParm)" \
208 if( iVal ){
209 @ checked="checked" \
210 }
211 if( disabled ){
212 @ disabled="disabled" \
213 }
214 @ /> <b>%s(zLabel)</b></label>
215 }
216
217 /*
@@ -232,12 +233,12 @@
233 db_set(zVar, zQ, 0);
234 admin_log("Set entry_attribute %Q to: %.*s%s",
235 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
236 zVal = zQ;
237 }
238 @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
239 @ id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)" \
240 if( disabled ){
241 @ disabled="disabled" \
242 }
243 @ /> <b>%s(zLabel)</b>
244 }
@@ -263,16 +264,17 @@
264 admin_log("Set textarea_attribute %Q to: %.*s%s",
265 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
266 z = zQ;
267 }
268 if( rows>0 && cols>0 ){
269 @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" \
270 @ aria-label="%h(zLabel[0]?zLabel:zQP)" \
271 if( disabled ){
272 @ disabled="disabled" \
273 }
274 @ cols="%d(cols)">%h(z)</textarea>
275 if( *zLabel ){
276 @ <span class="textareaLabel">%s(zLabel)</span>
277 }
278 }
279 return z;
280 }
@@ -297,11 +299,11 @@
299 db_set(zVar, zQ, 0);
300 admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
301 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
302 z = zQ;
303 }
304 @ <select aria-label="%h(zLabel)" size="1" name="%s(zQP)" id="id%s(zQP)">
305 for(i=0; i<nChoice*2; i+=2){
306 const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : "";
307 @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option>
308 }
309 @ </select> <b>%h(zLabel)</b>
@@ -398,11 +400,11 @@
400 @ <hr />
401 onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
402 "http_authentication_ok", "http_authentication_ok", 0, 0);
403 @ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
404 @ variable or the "Authentication:" HTTP header to find the username and
405 @ password. This is another way of supporting Basic Authentication.
406 @ (Property: "http_authentication_ok")
407 @ </p>
408 @
409 @ <hr />
410 entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
@@ -606,25 +608,30 @@
608 @
609 @ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
610 login_insert_csrf_secret();
611 @ <blockquote><table border="0">
612 @
613 @ <tr><th align="right" id="rfigtj">Repository filename \
614 @ in group to join:</th>
615 @ <td width="5"></td><td>
616 @ <input aria-labelledby="rfigtj" type="text" size="50" \
617 @ value="%h(zRepo)" name="repo"></td></tr>
618 @
619 @ <tr><th align="right" id="lotar">Login on the above repo:</th>
620 @ <td width="5"></td><td>
621 @ <input aria-labelledby="lotar" type="text" size="20" \
622 @ value="%h(zLogin)" name="login"></td></tr>
623 @
624 @ <tr><th align="right" id="lgpw">Password:</th>
625 @ <td width="5"></td><td>
626 @ <input aria-labelledby="lgpw" type="password" size="20" name="pw">\
627 @ </td></tr>
628 @
629 @ <tr><th align="right" id="nolg">Name of login-group:</th>
630 @ <td width="5"></td><td>
631 @ <input aria-labelledby="nolg" type="text" size="30" \
632 @ value="%h(zNewName)" name="newname">
633 @ (only used if creating a new login-group).</td></tr>
634 @
635 @ <tr><td colspan="3" align="center">
636 @ <input type="submit" value="Join" name="join"></td></tr>
637 @ </table></blockquote></div></form>
@@ -1137,10 +1144,11 @@
1144 }
1145 db_begin_transaction();
1146 if( P("clear")!=0 && cgi_csrf_safe(1) ){
1147 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
1148 cgi_replace_parameter("adunit","");
1149 cgi_replace_parameter("adright","");
1150 }
1151
1152 style_header("Edit Ad Unit");
1153 @ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
1154 login_insert_csrf_secret();
1155
+16 -12
--- src/setupuser.c
+++ src/setupuser.c
@@ -534,24 +534,27 @@
534534
@ <input type="hidden" name="pw" value="*">
535535
}
536536
@ <input type="hidden" name="referer" value="%h(cgi_referer("setup_ulist"))">
537537
@ <table width="100%%">
538538
@ <tr>
539
- @ <td class="usetupEditLabel">User ID:</td>
539
+ @ <td class="usetupEditLabel" id="suuid">User ID:</td>
540540
if( uid ){
541
- @ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" />\
541
+ @ <td>%d(uid) <input aria-labelledby="suuid" type="hidden" \
542
+ @ name="id" value="%d(uid)"/>\
542543
@ </td>
543544
}else{
544
- @ <td>(new user)<input type="hidden" name="id" value="0" /></td>
545
+ @ <td>(new user)<input aria-labelledby="suuid" type="hidden" name="id" \
546
+ @ value="0" /></td>
545547
}
546548
@ </tr>
547549
@ <tr>
548
- @ <td class="usetupEditLabel">Login:</td>
550
+ @ <td class="usetupEditLabel" id="sulgn">Login:</td>
549551
if( login_is_special(zLogin) ){
550552
@ <td><b>%h(zLogin)</b></td>
551553
}else{
552
- @ <td><input type="text" name="login" value="%h(zLogin)" />\
554
+ @ <td><input aria-labelledby="sulgn" type="text" name="login" \
555
+ @ value="%h(zLogin)" />
553556
if( alert_tables_exist() ){
554557
int sid;
555558
sid = db_int(0, "SELECT subscriberId FROM subscriber"
556559
" WHERE suname=%Q", zLogin);
557560
if( sid>0 ){
@@ -559,12 +562,13 @@
559562
@ (subscription info for %h(zLogin))</a>\
560563
}
561564
}
562565
@ </td></tr>
563566
@ <tr>
564
- @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
565
- @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
567
+ @ <td class="usetupEditLabel" id="sucnfo">Contact&nbsp;Info:</td>
568
+ @ <td><textarea aria-labelledby="sucnfo" name="info" cols="40" \
569
+ @ rows="2">%h(zInfo)</textarea></td>
566570
}
567571
@ </tr>
568572
@ <tr>
569573
@ <td class="usetupEditLabel">Capabilities:</td>
570574
@ <td width="100%%">
@@ -653,19 +657,19 @@
653657
@ <a href="%R/setup_ucap_list">(key)</a>
654658
@ </td>
655659
@ </tr>
656660
if( !login_is_special(zLogin) ){
657661
@ <tr>
658
- @ <td align="right">Password:</td>
662
+ @ <td align="right" id="supw">Password:</td>
659663
if( zPw[0] ){
660664
/* Obscure the password for all users */
661
- @ <td><input type="password" autocomplete="off" name="pw"\
662
- @ value="**********" /></td>
665
+ @ <td><input aria-labelledby="supw" type="password" autocomplete="off" \
666
+ @ name="pw" value="**********" /></td>
663667
}else{
664668
/* Show an empty password as an empty input field */
665
- @ <td><input type="password" autocomplete="off" name="pw"\
666
- @ value="" /></td>
669
+ @ <td><input aria-labelledby="supw" type="password" name="pw" \
670
+ @ autocomplete="off" value="" /></td>
667671
}
668672
@ </tr>
669673
}
670674
zGroup = login_group_name();
671675
if( zGroup ){
672676
--- src/setupuser.c
+++ src/setupuser.c
@@ -534,24 +534,27 @@
534 @ <input type="hidden" name="pw" value="*">
535 }
536 @ <input type="hidden" name="referer" value="%h(cgi_referer("setup_ulist"))">
537 @ <table width="100%%">
538 @ <tr>
539 @ <td class="usetupEditLabel">User ID:</td>
540 if( uid ){
541 @ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" />\
 
542 @ </td>
543 }else{
544 @ <td>(new user)<input type="hidden" name="id" value="0" /></td>
 
545 }
546 @ </tr>
547 @ <tr>
548 @ <td class="usetupEditLabel">Login:</td>
549 if( login_is_special(zLogin) ){
550 @ <td><b>%h(zLogin)</b></td>
551 }else{
552 @ <td><input type="text" name="login" value="%h(zLogin)" />\
 
553 if( alert_tables_exist() ){
554 int sid;
555 sid = db_int(0, "SELECT subscriberId FROM subscriber"
556 " WHERE suname=%Q", zLogin);
557 if( sid>0 ){
@@ -559,12 +562,13 @@
559 @ (subscription info for %h(zLogin))</a>\
560 }
561 }
562 @ </td></tr>
563 @ <tr>
564 @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
565 @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
 
566 }
567 @ </tr>
568 @ <tr>
569 @ <td class="usetupEditLabel">Capabilities:</td>
570 @ <td width="100%%">
@@ -653,19 +657,19 @@
653 @ <a href="%R/setup_ucap_list">(key)</a>
654 @ </td>
655 @ </tr>
656 if( !login_is_special(zLogin) ){
657 @ <tr>
658 @ <td align="right">Password:</td>
659 if( zPw[0] ){
660 /* Obscure the password for all users */
661 @ <td><input type="password" autocomplete="off" name="pw"\
662 @ value="**********" /></td>
663 }else{
664 /* Show an empty password as an empty input field */
665 @ <td><input type="password" autocomplete="off" name="pw"\
666 @ value="" /></td>
667 }
668 @ </tr>
669 }
670 zGroup = login_group_name();
671 if( zGroup ){
672
--- src/setupuser.c
+++ src/setupuser.c
@@ -534,24 +534,27 @@
534 @ <input type="hidden" name="pw" value="*">
535 }
536 @ <input type="hidden" name="referer" value="%h(cgi_referer("setup_ulist"))">
537 @ <table width="100%%">
538 @ <tr>
539 @ <td class="usetupEditLabel" id="suuid">User ID:</td>
540 if( uid ){
541 @ <td>%d(uid) <input aria-labelledby="suuid" type="hidden" \
542 @ name="id" value="%d(uid)"/>\
543 @ </td>
544 }else{
545 @ <td>(new user)<input aria-labelledby="suuid" type="hidden" name="id" \
546 @ value="0" /></td>
547 }
548 @ </tr>
549 @ <tr>
550 @ <td class="usetupEditLabel" id="sulgn">Login:</td>
551 if( login_is_special(zLogin) ){
552 @ <td><b>%h(zLogin)</b></td>
553 }else{
554 @ <td><input aria-labelledby="sulgn" type="text" name="login" \
555 @ value="%h(zLogin)" />
556 if( alert_tables_exist() ){
557 int sid;
558 sid = db_int(0, "SELECT subscriberId FROM subscriber"
559 " WHERE suname=%Q", zLogin);
560 if( sid>0 ){
@@ -559,12 +562,13 @@
562 @ (subscription info for %h(zLogin))</a>\
563 }
564 }
565 @ </td></tr>
566 @ <tr>
567 @ <td class="usetupEditLabel" id="sucnfo">Contact&nbsp;Info:</td>
568 @ <td><textarea aria-labelledby="sucnfo" name="info" cols="40" \
569 @ rows="2">%h(zInfo)</textarea></td>
570 }
571 @ </tr>
572 @ <tr>
573 @ <td class="usetupEditLabel">Capabilities:</td>
574 @ <td width="100%%">
@@ -653,19 +657,19 @@
657 @ <a href="%R/setup_ucap_list">(key)</a>
658 @ </td>
659 @ </tr>
660 if( !login_is_special(zLogin) ){
661 @ <tr>
662 @ <td align="right" id="supw">Password:</td>
663 if( zPw[0] ){
664 /* Obscure the password for all users */
665 @ <td><input aria-labelledby="supw" type="password" autocomplete="off" \
666 @ name="pw" value="**********" /></td>
667 }else{
668 /* Show an empty password as an empty input field */
669 @ <td><input aria-labelledby="supw" type="password" name="pw" \
670 @ autocomplete="off" value="" /></td>
671 }
672 @ </tr>
673 }
674 zGroup = login_group_name();
675 if( zGroup ){
676
+10 -4
--- src/shell.c
+++ src/shell.c
@@ -6589,10 +6589,11 @@
65896589
** sqlar support.
65906590
*/
65916591
/* #include "sqlite3ext.h" */
65926592
SQLITE_EXTENSION_INIT1
65936593
#include <zlib.h>
6594
+#include <assert.h>
65946595
65956596
/*
65966597
** Implementation of the "sqlar_compress(X)" SQL function.
65976598
**
65986599
** If the type of X is SQLITE_BLOB, and compressing that blob using
@@ -7998,18 +7999,23 @@
79987999
while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
79998000
/* int iId = sqlite3_column_int(pExplain, 0); */
80008001
/* int iParent = sqlite3_column_int(pExplain, 1); */
80018002
/* int iNotUsed = sqlite3_column_int(pExplain, 2); */
80028003
const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
8003
- int nDetail = STRLEN(zDetail);
8004
+ int nDetail;
80048005
int i;
80058006
8007
+ if( !zDetail ) continue;
8008
+ nDetail = STRLEN(zDetail);
8009
+
80068010
for(i=0; i<nDetail; i++){
80078011
const char *zIdx = 0;
8008
- if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
8012
+ if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
80098013
zIdx = &zDetail[i+13];
8010
- }else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
8014
+ }else if( i+22<nDetail
8015
+ && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
8016
+ ){
80118017
zIdx = &zDetail[i+22];
80128018
}
80138019
if( zIdx ){
80148020
const char *zSql;
80158021
int nIdx = 0;
@@ -8820,11 +8826,11 @@
88208826
sqlite3_free(p->zCandidates);
88218827
sqlite3_free(p);
88228828
}
88238829
}
88248830
8825
-#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
8831
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
88268832
88278833
/************************* End ../ext/expert/sqlite3expert.c ********************/
88288834
88298835
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
88308836
/************************* Begin ../ext/misc/dbdata.c ******************/
88318837
--- src/shell.c
+++ src/shell.c
@@ -6589,10 +6589,11 @@
6589 ** sqlar support.
6590 */
6591 /* #include "sqlite3ext.h" */
6592 SQLITE_EXTENSION_INIT1
6593 #include <zlib.h>
 
6594
6595 /*
6596 ** Implementation of the "sqlar_compress(X)" SQL function.
6597 **
6598 ** If the type of X is SQLITE_BLOB, and compressing that blob using
@@ -7998,18 +7999,23 @@
7998 while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
7999 /* int iId = sqlite3_column_int(pExplain, 0); */
8000 /* int iParent = sqlite3_column_int(pExplain, 1); */
8001 /* int iNotUsed = sqlite3_column_int(pExplain, 2); */
8002 const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
8003 int nDetail = STRLEN(zDetail);
8004 int i;
8005
 
 
 
8006 for(i=0; i<nDetail; i++){
8007 const char *zIdx = 0;
8008 if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
8009 zIdx = &zDetail[i+13];
8010 }else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
 
 
8011 zIdx = &zDetail[i+22];
8012 }
8013 if( zIdx ){
8014 const char *zSql;
8015 int nIdx = 0;
@@ -8820,11 +8826,11 @@
8820 sqlite3_free(p->zCandidates);
8821 sqlite3_free(p);
8822 }
8823 }
8824
8825 #endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
8826
8827 /************************* End ../ext/expert/sqlite3expert.c ********************/
8828
8829 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
8830 /************************* Begin ../ext/misc/dbdata.c ******************/
8831
--- src/shell.c
+++ src/shell.c
@@ -6589,10 +6589,11 @@
6589 ** sqlar support.
6590 */
6591 /* #include "sqlite3ext.h" */
6592 SQLITE_EXTENSION_INIT1
6593 #include <zlib.h>
6594 #include <assert.h>
6595
6596 /*
6597 ** Implementation of the "sqlar_compress(X)" SQL function.
6598 **
6599 ** If the type of X is SQLITE_BLOB, and compressing that blob using
@@ -7998,18 +7999,23 @@
7999 while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
8000 /* int iId = sqlite3_column_int(pExplain, 0); */
8001 /* int iParent = sqlite3_column_int(pExplain, 1); */
8002 /* int iNotUsed = sqlite3_column_int(pExplain, 2); */
8003 const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
8004 int nDetail;
8005 int i;
8006
8007 if( !zDetail ) continue;
8008 nDetail = STRLEN(zDetail);
8009
8010 for(i=0; i<nDetail; i++){
8011 const char *zIdx = 0;
8012 if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
8013 zIdx = &zDetail[i+13];
8014 }else if( i+22<nDetail
8015 && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
8016 ){
8017 zIdx = &zDetail[i+22];
8018 }
8019 if( zIdx ){
8020 const char *zSql;
8021 int nIdx = 0;
@@ -8820,11 +8826,11 @@
8826 sqlite3_free(p->zCandidates);
8827 sqlite3_free(p);
8828 }
8829 }
8830
8831 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
8832
8833 /************************* End ../ext/expert/sqlite3expert.c ********************/
8834
8835 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
8836 /************************* Begin ../ext/misc/dbdata.c ******************/
8837
+2 -2
--- src/shun.c
+++ src/shun.c
@@ -187,11 +187,11 @@
187187
@ sight - set the "hidden" tag on such artifacts instead.</p>
188188
@
189189
@ <blockquote>
190190
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
191191
login_insert_csrf_secret();
192
- @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid">
192
+ @ <textarea class="fullsize-text" cols="70" rows="%d(numRows)" name="uuid">
193193
if( zShun ){
194194
if( strlen(zShun) ){
195195
@ %h(zShun)
196196
}else if( nRcvid ){
197197
db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
@@ -214,11 +214,11 @@
214214
@ operations.</p>
215215
@
216216
@ <blockquote>
217217
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
218218
login_insert_csrf_secret();
219
- @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid">
219
+ @ <textarea class="fullsize-text" cols="70" rows="%d(numRows)" name="uuid">
220220
if( zAccept ){
221221
if( strlen(zAccept) ){
222222
@ %h(zAccept)
223223
}else if( nRcvid ){
224224
db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
225225
--- src/shun.c
+++ src/shun.c
@@ -187,11 +187,11 @@
187 @ sight - set the "hidden" tag on such artifacts instead.</p>
188 @
189 @ <blockquote>
190 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
191 login_insert_csrf_secret();
192 @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid">
193 if( zShun ){
194 if( strlen(zShun) ){
195 @ %h(zShun)
196 }else if( nRcvid ){
197 db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
@@ -214,11 +214,11 @@
214 @ operations.</p>
215 @
216 @ <blockquote>
217 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
218 login_insert_csrf_secret();
219 @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid">
220 if( zAccept ){
221 if( strlen(zAccept) ){
222 @ %h(zAccept)
223 }else if( nRcvid ){
224 db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
225
--- src/shun.c
+++ src/shun.c
@@ -187,11 +187,11 @@
187 @ sight - set the "hidden" tag on such artifacts instead.</p>
188 @
189 @ <blockquote>
190 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
191 login_insert_csrf_secret();
192 @ <textarea class="fullsize-text" cols="70" rows="%d(numRows)" name="uuid">
193 if( zShun ){
194 if( strlen(zShun) ){
195 @ %h(zShun)
196 }else if( nRcvid ){
197 db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
@@ -214,11 +214,11 @@
214 @ operations.</p>
215 @
216 @ <blockquote>
217 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
218 login_insert_csrf_secret();
219 @ <textarea class="fullsize-text" cols="70" rows="%d(numRows)" name="uuid">
220 if( zAccept ){
221 if( strlen(zAccept) ){
222 @ %h(zAccept)
223 }else if( nRcvid ){
224 db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
225
+7 -2
--- src/skins.c
+++ src/skins.c
@@ -281,10 +281,13 @@
281281
** Return an identifier that is (probably) different for every skin
282282
** but that is (probably) the same if the skin is unchanged. This
283283
** identifier can be attached to resource URLs to force reloading when
284284
** the resources change but allow the resources to be read from cache
285285
** as long as they are unchanged.
286
+**
287
+** The zResource argument is the name of a CONFIG setting that
288
+** defines the resource. Examples: "css", "logo-image".
286289
*/
287290
unsigned int skin_id(const char *zResource){
288291
unsigned int h = 0;
289292
if( zAltSkinDir ){
290293
h = skin_hash(0, zAltSkinDir);
@@ -293,11 +296,13 @@
293296
}else{
294297
char *zMTime = db_get_mtime(zResource, 0, 0);
295298
h = skin_hash(0, zMTime);
296299
fossil_free(zMTime);
297300
}
298
- h = skin_hash(h, MANIFEST_UUID);
301
+
302
+ /* Change the ID every time Fossil is recompiled */
303
+ h = skin_hash(h, fossil_exe_id());
299304
return h;
300305
}
301306
302307
/*
303308
** For a skin named zSkinName, compute the name of the CONFIG table
@@ -1117,11 +1122,11 @@
11171122
if( !g.perm.Admin ){
11181123
@ <p>Only administrators are allowed to publish draft skins. Contact
11191124
@ an administrator to get this "draft%d(iSkin)" skin published.</p>
11201125
}else{
11211126
@ <p>When the draft%d(iSkin) skin is ready for production use,
1122
- @ make it the default scan by clicking the acknowledgements and
1127
+ @ make it the default skin by clicking the acknowledgements and
11231128
@ pressing the button below:</p>
11241129
@
11251130
@ <form method='POST' action='%R/setup_skin#step7'>
11261131
@ <p class='skinInput'>
11271132
@ <input type='hidden' name='sk' value='%d(iSkin)'>
11281133
--- src/skins.c
+++ src/skins.c
@@ -281,10 +281,13 @@
281 ** Return an identifier that is (probably) different for every skin
282 ** but that is (probably) the same if the skin is unchanged. This
283 ** identifier can be attached to resource URLs to force reloading when
284 ** the resources change but allow the resources to be read from cache
285 ** as long as they are unchanged.
 
 
 
286 */
287 unsigned int skin_id(const char *zResource){
288 unsigned int h = 0;
289 if( zAltSkinDir ){
290 h = skin_hash(0, zAltSkinDir);
@@ -293,11 +296,13 @@
293 }else{
294 char *zMTime = db_get_mtime(zResource, 0, 0);
295 h = skin_hash(0, zMTime);
296 fossil_free(zMTime);
297 }
298 h = skin_hash(h, MANIFEST_UUID);
 
 
299 return h;
300 }
301
302 /*
303 ** For a skin named zSkinName, compute the name of the CONFIG table
@@ -1117,11 +1122,11 @@
1117 if( !g.perm.Admin ){
1118 @ <p>Only administrators are allowed to publish draft skins. Contact
1119 @ an administrator to get this "draft%d(iSkin)" skin published.</p>
1120 }else{
1121 @ <p>When the draft%d(iSkin) skin is ready for production use,
1122 @ make it the default scan by clicking the acknowledgements and
1123 @ pressing the button below:</p>
1124 @
1125 @ <form method='POST' action='%R/setup_skin#step7'>
1126 @ <p class='skinInput'>
1127 @ <input type='hidden' name='sk' value='%d(iSkin)'>
1128
--- src/skins.c
+++ src/skins.c
@@ -281,10 +281,13 @@
281 ** Return an identifier that is (probably) different for every skin
282 ** but that is (probably) the same if the skin is unchanged. This
283 ** identifier can be attached to resource URLs to force reloading when
284 ** the resources change but allow the resources to be read from cache
285 ** as long as they are unchanged.
286 **
287 ** The zResource argument is the name of a CONFIG setting that
288 ** defines the resource. Examples: "css", "logo-image".
289 */
290 unsigned int skin_id(const char *zResource){
291 unsigned int h = 0;
292 if( zAltSkinDir ){
293 h = skin_hash(0, zAltSkinDir);
@@ -293,11 +296,13 @@
296 }else{
297 char *zMTime = db_get_mtime(zResource, 0, 0);
298 h = skin_hash(0, zMTime);
299 fossil_free(zMTime);
300 }
301
302 /* Change the ID every time Fossil is recompiled */
303 h = skin_hash(h, fossil_exe_id());
304 return h;
305 }
306
307 /*
308 ** For a skin named zSkinName, compute the name of the CONFIG table
@@ -1117,11 +1122,11 @@
1122 if( !g.perm.Admin ){
1123 @ <p>Only administrators are allowed to publish draft skins. Contact
1124 @ an administrator to get this "draft%d(iSkin)" skin published.</p>
1125 }else{
1126 @ <p>When the draft%d(iSkin) skin is ready for production use,
1127 @ make it the default skin by clicking the acknowledgements and
1128 @ pressing the button below:</p>
1129 @
1130 @ <form method='POST' action='%R/setup_skin#step7'>
1131 @ <p class='skinInput'>
1132 @ <input type='hidden' name='sk' value='%d(iSkin)'>
1133
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -164,10 +164,11 @@
164164
static int sqlcmd_autoinit(
165165
sqlite3 *db,
166166
const char **pzErrMsg,
167167
const void *notUsed
168168
){
169
+ int mTrace = SQLITE_TRACE_CLOSE;
169170
add_content_sql_commands(db);
170171
db_add_aux_functions(db);
171172
re_add_sql_func(db);
172173
search_sql_setup(db);
173174
foci_register(db);
@@ -186,10 +187,14 @@
186187
char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
187188
g.zConfigDbName);
188189
sqlite3_exec(db, zSql, 0, 0, 0);
189190
sqlite3_free(zSql);
190191
}
192
+ /* Arrange to trace close operations so that static prepared statements
193
+ ** will get cleaned up when the shell closes the database connection */
194
+ if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
195
+ sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
191196
return SQLITE_OK;
192197
}
193198
194199
/*
195200
** atexit() handler that cleans up global state modified by this module.
196201
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -164,10 +164,11 @@
164 static int sqlcmd_autoinit(
165 sqlite3 *db,
166 const char **pzErrMsg,
167 const void *notUsed
168 ){
 
169 add_content_sql_commands(db);
170 db_add_aux_functions(db);
171 re_add_sql_func(db);
172 search_sql_setup(db);
173 foci_register(db);
@@ -186,10 +187,14 @@
186 char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
187 g.zConfigDbName);
188 sqlite3_exec(db, zSql, 0, 0, 0);
189 sqlite3_free(zSql);
190 }
 
 
 
 
191 return SQLITE_OK;
192 }
193
194 /*
195 ** atexit() handler that cleans up global state modified by this module.
196
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -164,10 +164,11 @@
164 static int sqlcmd_autoinit(
165 sqlite3 *db,
166 const char **pzErrMsg,
167 const void *notUsed
168 ){
169 int mTrace = SQLITE_TRACE_CLOSE;
170 add_content_sql_commands(db);
171 db_add_aux_functions(db);
172 re_add_sql_func(db);
173 search_sql_setup(db);
174 foci_register(db);
@@ -186,10 +187,14 @@
187 char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
188 g.zConfigDbName);
189 sqlite3_exec(db, zSql, 0, 0, 0);
190 sqlite3_free(zSql);
191 }
192 /* Arrange to trace close operations so that static prepared statements
193 ** will get cleaned up when the shell closes the database connection */
194 if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
195 sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
196 return SQLITE_OK;
197 }
198
199 /*
200 ** atexit() handler that cleans up global state modified by this module.
201
+694 -379
--- 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.32.0. By combining all the individual C code files into this
3
+** version 3.32.1. 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.
@@ -1160,13 +1160,13 @@
11601160
**
11611161
** See also: [sqlite3_libversion()],
11621162
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
11631163
** [sqlite_version()] and [sqlite_source_id()].
11641164
*/
1165
-#define SQLITE_VERSION "3.32.0"
1166
-#define SQLITE_VERSION_NUMBER 3032000
1167
-#define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda"
1165
+#define SQLITE_VERSION "3.32.1"
1166
+#define SQLITE_VERSION_NUMBER 3032001
1167
+#define SQLITE_SOURCE_ID "2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350"
11681168
11691169
/*
11701170
** CAPI3REF: Run-Time Library Version Numbers
11711171
** KEYWORDS: sqlite3_version sqlite3_sourceid
11721172
**
@@ -1545,18 +1545,20 @@
15451545
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
15461546
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
15471547
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
15481548
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
15491549
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
1550
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
15501551
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
15511552
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
15521553
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
15531554
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
15541555
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
15551556
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
15561557
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
15571558
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
1559
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
15581560
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
15591561
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
15601562
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
15611563
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
15621564
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
@@ -6530,11 +6532,11 @@
65306532
** when first called if N is less than or equal to zero or if a memory
65316533
** allocate error occurs.
65326534
**
65336535
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
65346536
** determined by the N parameter on first successful call. Changing the
6535
-** value of N in any subsequents call to sqlite3_aggregate_context() within
6537
+** value of N in any subsequent call to sqlite3_aggregate_context() within
65366538
** the same aggregate function instance will not resize the memory
65376539
** allocation.)^ Within the xFinal callback, it is customary to set
65386540
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
65396541
** pointless memory allocations occur.
65406542
**
@@ -14535,11 +14537,10 @@
1453514537
typedef struct BusyHandler BusyHandler;
1453614538
struct BusyHandler {
1453714539
int (*xBusyHandler)(void *,int); /* The busy callback */
1453814540
void *pBusyArg; /* First arg to busy callback */
1453914541
int nBusy; /* Incremented with each busy call */
14540
- u8 bExtraFileArg; /* Include sqlite3_file as callback arg */
1454114542
};
1454214543
1454314544
/*
1454414545
** Name of the master database table. The master database table
1454514546
** is a special table that holds the names and attributes of all
@@ -15918,17 +15919,25 @@
1591815919
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
1591915920
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
1592015921
SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
1592115922
SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
1592215923
# ifdef SQLITE_ENABLE_SNAPSHOT
15923
-SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
15924
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
15924
+SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
15925
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
1592515926
SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
1592615927
SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
1592715928
SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
1592815929
# endif
1592915930
#endif
15931
+
15932
+#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
15933
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
15934
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
15935
+#else
15936
+# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
15937
+# define sqlite3PagerWalDb(x,y)
15938
+#endif
1593015939
1593115940
#ifdef SQLITE_DIRECT_OVERFLOW_READ
1593215941
SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
1593315942
#endif
1593415943
@@ -15951,15 +15960,10 @@
1595115960
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
1595215961
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
1595315962
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
1595415963
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
1595515964
SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
15956
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
15957
-SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager);
15958
-#else
15959
-# define sqlite3PagerResetLockTimeout(X)
15960
-#endif
1596115965
1596215966
/* Functions used to truncate the database file. */
1596315967
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
1596415968
1596515969
SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
@@ -17115,11 +17119,11 @@
1711517119
#define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */
1711617120
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
1711717121
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
1711817122
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
1711917123
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
17120
-#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
17124
+/* 0x0200 -- available for reuse */
1712117125
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
1712217126
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
1712317127
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
1712417128
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
1712517129
** single query - might change over time */
@@ -17136,10 +17140,11 @@
1713617140
#define INLINEFUNC_coalesce 0
1713717141
#define INLINEFUNC_implies_nonnull_row 1
1713817142
#define INLINEFUNC_expr_implies_expr 2
1713917143
#define INLINEFUNC_expr_compare 3
1714017144
#define INLINEFUNC_affinity 4
17145
+#define INLINEFUNC_iif 5
1714117146
#define INLINEFUNC_unlikely 99 /* Default case */
1714217147
1714317148
/*
1714417149
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
1714517150
** used to create the initializers for the FuncDef structures.
@@ -17836,11 +17841,11 @@
1783617841
/*
1783717842
** An instance of this structure contains information needed to generate
1783817843
** code for a SELECT that contains aggregate functions.
1783917844
**
1784017845
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
17841
-** pointer to this structure. The Expr.iColumn field is the index in
17846
+** pointer to this structure. The Expr.iAgg field is the index in
1784217847
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
1784317848
** code for that node.
1784417849
**
1784517850
** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the
1784617851
** original Select structure that describes the SELECT statement. These
@@ -19075,10 +19080,13 @@
1907519080
SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
1907619081
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
1907719082
SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
1907819083
SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
1907919084
SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
19085
+SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker*,Select*);
19086
+SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker*,Select*);
19087
+
1908019088
#ifdef SQLITE_DEBUG
1908119089
SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
1908219090
#endif
1908319091
1908419092
/*
@@ -19935,11 +19943,11 @@
1993519943
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
1993619944
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
1993719945
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
1993819946
SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
1993919947
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
19940
-SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
19948
+SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
1994119949
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
1994219950
SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
1994319951
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
1994419952
SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
1994519953
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
@@ -20060,12 +20068,14 @@
2006020068
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
2006120069
#endif
2006220070
SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db);
2006320071
#ifndef SQLITE_OMIT_VIRTUALTABLE
2006420072
SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
20073
+SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
2006520074
#else
2006620075
# define sqlite3ShadowTableName(A,B) 0
20076
+# define sqlite3IsShadowTableOf(A,B,C) 0
2006720077
#endif
2006820078
SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
2006920079
SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
2007020080
SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
2007120081
SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
@@ -27730,14 +27740,16 @@
2773027740
if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
2773127741
mem0.alarmThreshold-nDiff ){
2773227742
sqlite3MallocAlarm(nDiff);
2773327743
}
2773427744
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27745
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
2773527746
if( pNew==0 && mem0.alarmThreshold>0 ){
2773627747
sqlite3MallocAlarm((int)nBytes);
2773727748
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
2773827749
}
27750
+#endif
2773927751
if( pNew ){
2774027752
nNew = sqlite3MallocSize(pNew);
2774127753
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
2774227754
}
2774327755
sqlite3_mutex_leave(mem0.mutex);
@@ -27918,11 +27930,11 @@
2791827930
}
2791927931
}else{
2792027932
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
2792127933
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
2792227934
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
27923
- pNew = sqlite3_realloc64(p, n);
27935
+ pNew = sqlite3Realloc(p, n);
2792427936
if( !pNew ){
2792527937
sqlite3OomFault(db);
2792627938
}
2792727939
sqlite3MemdebugSetType(pNew,
2792827940
(db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
@@ -28265,10 +28277,17 @@
2826528277
#ifndef SQLITE_PRINT_BUF_SIZE
2826628278
# define SQLITE_PRINT_BUF_SIZE 70
2826728279
#endif
2826828280
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
2826928281
28282
+/*
28283
+** Hard limit on the precision of floating-point conversions.
28284
+*/
28285
+#ifndef SQLITE_PRINTF_PRECISION_LIMIT
28286
+# define SQLITE_FP_PRECISION_LIMIT 100000000
28287
+#endif
28288
+
2827028289
/*
2827128290
** Render a string given by "fmt" into the StrAccum object.
2827228291
*/
2827328292
SQLITE_API void sqlite3_str_vappendf(
2827428293
sqlite3_str *pAccum, /* Accumulate results here */
@@ -28465,10 +28484,12 @@
2846528484
** precision The specified precision. The default
2846628485
** is -1.
2846728486
** xtype The class of the conversion.
2846828487
** infop Pointer to the appropriate info struct.
2846928488
*/
28489
+ assert( width>=0 );
28490
+ assert( precision>=(-1) );
2847028491
switch( xtype ){
2847128492
case etPOINTER:
2847228493
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
2847328494
sizeof(char*)==sizeof(long int) ? 1 : 0;
2847428495
/* Fall through into the next case */
@@ -28586,10 +28607,15 @@
2858628607
}
2858728608
#ifdef SQLITE_OMIT_FLOATING_POINT
2858828609
length = 0;
2858928610
#else
2859028611
if( precision<0 ) precision = 6; /* Set default precision */
28612
+#ifdef SQLITE_FP_PRECISION_LIMIT
28613
+ if( precision>SQLITE_FP_PRECISION_LIMIT ){
28614
+ precision = SQLITE_FP_PRECISION_LIMIT;
28615
+ }
28616
+#endif
2859128617
if( realvalue<0.0 ){
2859228618
realvalue = -realvalue;
2859328619
prefix = '-';
2859428620
}else{
2859528621
prefix = flag_prefix;
@@ -28868,11 +28894,11 @@
2886828894
}else{
2886928895
escarg = va_arg(ap,char*);
2887028896
}
2887128897
isnull = escarg==0;
2887228898
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
28873
- /* For %q, %Q, and %w, the precision is the number of byte (or
28899
+ /* For %q, %Q, and %w, the precision is the number of bytes (or
2887428900
** characters if the ! flags is present) to use from the input.
2887528901
** Because of the extra quoting characters inserted, the number
2887628902
** of output characters may be larger than the precision.
2887728903
*/
2887828904
k = precision;
@@ -28995,11 +29021,11 @@
2899529021
p->nAlloc = (int)szNew;
2899629022
}
2899729023
if( p->db ){
2899829024
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
2899929025
}else{
29000
- zNew = sqlite3_realloc64(zOld, p->nAlloc);
29026
+ zNew = sqlite3Realloc(zOld, p->nAlloc);
2900129027
}
2900229028
if( zNew ){
2900329029
assert( p->zText!=0 || p->nChar==0 );
2900429030
if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
2900529031
p->zText = zNew;
@@ -29337,11 +29363,11 @@
2933729363
** and segfaults if you give it a long long int.
2933829364
*/
2933929365
SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
2934029366
va_list ap;
2934129367
StrAccum acc;
29342
- char zBuf[500];
29368
+ char zBuf[SQLITE_PRINT_BUF_SIZE*10];
2934329369
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
2934429370
va_start(ap,zFormat);
2934529371
sqlite3_str_vappendf(&acc, zFormat, ap);
2934629372
va_end(ap);
2934729373
sqlite3StrAccumFinish(&acc);
@@ -29953,12 +29979,13 @@
2995329979
#else
2995429980
pWin = 0;
2995529981
#endif
2995629982
}
2995729983
if( pExpr->op==TK_AGG_FUNCTION ){
29958
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
29959
- pExpr->op2, pExpr->u.zToken, zFlgs);
29984
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s iAgg=%d agg=%p",
29985
+ pExpr->op2, pExpr->u.zToken, zFlgs,
29986
+ pExpr->iAgg, pExpr->pAggInfo);
2996029987
}else if( pExpr->op2!=0 ){
2996129988
const char *zOp2;
2996229989
char zBuf[8];
2996329990
sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2);
2996429991
zOp2 = zBuf;
@@ -30847,10 +30874,11 @@
3084730874
/* UTF-16 Little-endian -> UTF-8 */
3084830875
while( zIn<zTerm ){
3084930876
c = *(zIn++);
3085030877
c += (*(zIn++))<<8;
3085130878
if( c>=0xd800 && c<0xe000 ){
30879
+#ifdef SQLITE_REPLACE_INVALID_UTF
3085230880
if( c>=0xdc00 || zIn>=zTerm ){
3085330881
c = 0xfffd;
3085430882
}else{
3085530883
int c2 = *(zIn++);
3085630884
c2 += (*(zIn++))<<8;
@@ -30859,19 +30887,27 @@
3085930887
c = 0xfffd;
3086030888
}else{
3086130889
c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
3086230890
}
3086330891
}
30892
+#else
30893
+ if( zIn<zTerm ){
30894
+ int c2 = (*zIn++);
30895
+ c2 += ((*zIn++)<<8);
30896
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
30897
+ }
30898
+#endif
3086430899
}
3086530900
WRITE_UTF8(z, c);
3086630901
}
3086730902
}else{
3086830903
/* UTF-16 Big-endian -> UTF-8 */
3086930904
while( zIn<zTerm ){
3087030905
c = (*(zIn++))<<8;
3087130906
c += *(zIn++);
3087230907
if( c>=0xd800 && c<0xe000 ){
30908
+#ifdef SQLITE_REPLACE_INVALID_UTF
3087330909
if( c>=0xdc00 || zIn>=zTerm ){
3087430910
c = 0xfffd;
3087530911
}else{
3087630912
int c2 = (*(zIn++))<<8;
3087730913
c2 += *(zIn++);
@@ -30880,10 +30916,17 @@
3088030916
c = 0xfffd;
3088130917
}else{
3088230918
c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
3088330919
}
3088430920
}
30921
+#else
30922
+ if( zIn<zTerm ){
30923
+ int c2 = ((*zIn++)<<8);
30924
+ c2 += (*zIn++);
30925
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
30926
+ }
30927
+#endif
3088530928
}
3088630929
WRITE_UTF8(z, c);
3088730930
}
3088830931
}
3088930932
pMem->n = (int)(z - zOut);
@@ -34971,20 +35014,21 @@
3497135014
static int osSetPosixAdvisoryLock(
3497235015
int h, /* The file descriptor on which to take the lock */
3497335016
struct flock *pLock, /* The description of the lock */
3497435017
unixFile *pFile /* Structure holding timeout value */
3497535018
){
35019
+ int tm = pFile->iBusyTimeout;
3497635020
int rc = osFcntl(h,F_SETLK,pLock);
34977
- while( rc<0 && pFile->iBusyTimeout>0 ){
35021
+ while( rc<0 && tm>0 ){
3497835022
/* On systems that support some kind of blocking file lock with a timeout,
3497935023
** make appropriate changes here to invoke that blocking file lock. On
3498035024
** generic posix, however, there is no such API. So we simply try the
3498135025
** lock once every millisecond until either the timeout expires, or until
3498235026
** the lock is obtained. */
3498335027
usleep(1000);
3498435028
rc = osFcntl(h,F_SETLK,pLock);
34985
- pFile->iBusyTimeout--;
35029
+ tm--;
3498635030
}
3498735031
return rc;
3498835032
}
3498935033
#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
3499035034
@@ -37722,17 +37766,24 @@
3772237766
3772337767
/* Locks are within range */
3772437768
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
3772537769
3772637770
if( pShmNode->hShm>=0 ){
37771
+ int res;
3772737772
/* Initialize the locking parameters */
3772837773
f.l_type = lockType;
3772937774
f.l_whence = SEEK_SET;
3773037775
f.l_start = ofst;
3773137776
f.l_len = n;
37732
- rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37733
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
37777
+ res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37778
+ if( res==-1 ){
37779
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
37780
+ rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
37781
+#else
37782
+ rc = SQLITE_BUSY;
37783
+#endif
37784
+ }
3773437785
}
3773537786
3773637787
/* Update the global lock state and do debug tracing */
3773737788
#ifdef SQLITE_DEBUG
3773837789
{ u16 mask;
@@ -38225,26 +38276,27 @@
3822538276
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
3822638277
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
3822738278
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
3822838279
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
3822938280
38230
- /* Check that, if this to be a blocking lock, that locks have been
38231
- ** obtained in the following order.
38281
+ /* Check that, if this to be a blocking lock, no locks that occur later
38282
+ ** in the following list than the lock being obtained are already held:
3823238283
**
3823338284
** 1. Checkpointer lock (ofst==1).
38234
- ** 2. Recover lock (ofst==2).
38285
+ ** 2. Write lock (ofst==0).
3823538286
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
38236
- ** 4. Write lock (ofst==0).
3823738287
**
3823838288
** In other words, if this is a blocking lock, none of the locks that
3823938289
** occur later in the above list than the lock being obtained may be
3824038290
** held. */
3824138291
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
38242
- assert( pDbFd->iBusyTimeout==0
38243
- || (flags & SQLITE_SHM_UNLOCK) || ofst==0
38244
- || ((p->exclMask|p->sharedMask)&~((1<<ofst)-2))==0
38245
- );
38292
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
38293
+ (ofst!=2) /* not RECOVER */
38294
+ && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
38295
+ && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
38296
+ && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
38297
+ ));
3824638298
#endif
3824738299
3824838300
mask = (1<<(ofst+n)) - (1<<ofst);
3824938301
assert( n>1 || mask==(1<<ofst) );
3825038302
sqlite3_mutex_enter(pShmNode->pShmMutex);
@@ -45033,10 +45085,11 @@
4503345085
}
4503445086
4503545087
/* Forward references to VFS helper methods used for temporary files */
4503645088
static int winGetTempname(sqlite3_vfs *, char **);
4503745089
static int winIsDir(const void *);
45090
+static BOOL winIsLongPathPrefix(const char *);
4503845091
static BOOL winIsDriveLetterAndColon(const char *);
4503945092
4504045093
/*
4504145094
** Control and query of the open file handle.
4504245095
*/
@@ -46802,11 +46855,13 @@
4680246855
pFile->pVfs = pVfs;
4680346856
pFile->h = h;
4680446857
if( isReadonly ){
4680546858
pFile->ctrlFlags |= WINFILE_RDONLY;
4680646859
}
46807
- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
46860
+ if( (flags & SQLITE_OPEN_MAIN_DB)
46861
+ && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
46862
+ ){
4680846863
pFile->ctrlFlags |= WINFILE_PSOW;
4680946864
}
4681046865
pFile->lastErrno = NO_ERROR;
4681146866
pFile->zPath = zName;
4681246867
#if SQLITE_MAX_MMAP_SIZE>0
@@ -47011,10 +47066,21 @@
4701147066
*pResOut = rc;
4701247067
OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
4701347068
zFilename, pResOut, *pResOut));
4701447069
return SQLITE_OK;
4701547070
}
47071
+
47072
+/*
47073
+** Returns non-zero if the specified path name starts with the "long path"
47074
+** prefix.
47075
+*/
47076
+static BOOL winIsLongPathPrefix(
47077
+ const char *zPathname
47078
+){
47079
+ return ( zPathname[0]=='\\' && zPathname[1]=='\\'
47080
+ && zPathname[2]=='?' && zPathname[3]=='\\' );
47081
+}
4701647082
4701747083
/*
4701847084
** Returns non-zero if the specified path name starts with a drive letter
4701947085
** followed by a colon character.
4702047086
*/
@@ -47076,14 +47142,15 @@
4707647142
DWORD nByte;
4707747143
void *zConverted;
4707847144
char *zOut;
4707947145
#endif
4708047146
47081
- /* If this path name begins with "/X:", where "X" is any alphabetic
47082
- ** character, discard the initial "/" from the pathname.
47147
+ /* If this path name begins with "/X:" or "\\?\", where "X" is any
47148
+ ** alphabetic character, discard the initial "/" from the pathname.
4708347149
*/
47084
- if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
47150
+ if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
47151
+ || winIsLongPathPrefix(zRelative+1)) ){
4708547152
zRelative++;
4708647153
}
4708747154
4708847155
#if defined(__CYGWIN__)
4708947156
SimulateIOError( return SQLITE_ERROR );
@@ -47835,11 +47902,11 @@
4783547902
if( newSz>p->szMax ){
4783647903
return SQLITE_FULL;
4783747904
}
4783847905
newSz *= 2;
4783947906
if( newSz>p->szMax ) newSz = p->szMax;
47840
- pNew = sqlite3_realloc64(p->aData, newSz);
47907
+ pNew = sqlite3Realloc(p->aData, newSz);
4784147908
if( pNew==0 ) return SQLITE_NOMEM;
4784247909
p->aData = pNew;
4784347910
p->szAlloc = newSz;
4784447911
return SQLITE_OK;
4784547912
}
@@ -48282,14 +48349,15 @@
4828248349
*/
4828348350
SQLITE_PRIVATE int sqlite3MemdbInit(void){
4828448351
sqlite3_vfs *pLower = sqlite3_vfs_find(0);
4828548352
int sz = pLower->szOsFile;
4828648353
memdb_vfs.pAppData = pLower;
48287
- /* In all known configurations of SQLite, the size of a default
48288
- ** sqlite3_file is greater than the size of a memdb sqlite3_file.
48289
- ** Should that ever change, remove the following NEVER() */
48290
- if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
48354
+ /* The following conditional can only be true when compiled for
48355
+ ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
48356
+ ** it in, to be safe, but it is marked as NO_TEST since there
48357
+ ** is no way to reach it under most builds. */
48358
+ if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
4829148359
memdb_vfs.szOsFile = sz;
4829248360
return sqlite3_vfs_register(&memdb_vfs, 0);
4829348361
}
4829448362
#endif /* SQLITE_ENABLE_DESERIALIZE */
4829548363
@@ -51548,10 +51616,15 @@
5154851616
SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
5154951617
#endif
5155051618
5155151619
/* Return the sqlite3_file object for the WAL file */
5155251620
SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
51621
+
51622
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
51623
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
51624
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
51625
+#endif
5155351626
5155451627
#endif /* ifndef SQLITE_OMIT_WAL */
5155551628
#endif /* SQLITE_WAL_H */
5155651629
5155751630
/************** End of wal.h *************************************************/
@@ -57238,11 +57311,10 @@
5723857311
Pager *pPager;
5723957312
assert( pPg!=0 );
5724057313
assert( pPg->pgno==1 );
5724157314
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
5724257315
pPager = pPg->pPager;
57243
- sqlite3PagerResetLockTimeout(pPager);
5724457316
sqlite3PcacheRelease(pPg);
5724557317
pagerUnlockIfUnused(pPager);
5724657318
}
5724757319
5724857320
/*
@@ -58531,20 +58603,10 @@
5853158603
*/
5853258604
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
5853358605
return pPager->fd;
5853458606
}
5853558607
58536
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
58537
-/*
58538
-** Reset the lock timeout for pager.
58539
-*/
58540
-SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager){
58541
- int x = 0;
58542
- sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
58543
-}
58544
-#endif
58545
-
5854658608
/*
5854758609
** Return the file handle for the journal file (if it exists).
5854858610
** This will be either the rollback journal or the WAL file.
5854958611
*/
5855058612
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
@@ -58954,11 +59016,10 @@
5895459016
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
5895559017
pPager->pBusyHandlerArg,
5895659018
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
5895759019
pnLog, pnCkpt
5895859020
);
58959
- sqlite3PagerResetLockTimeout(pPager);
5896059021
}
5896159022
return rc;
5896259023
}
5896359024
5896459025
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
@@ -59119,11 +59180,35 @@
5911959180
}
5912059181
}
5912159182
return rc;
5912259183
}
5912359184
59185
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59186
+/*
59187
+** If pager pPager is a wal-mode database not in exclusive locking mode,
59188
+** invoke the sqlite3WalWriteLock() function on the associated Wal object
59189
+** with the same db and bLock parameters as were passed to this function.
59190
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
59191
+*/
59192
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
59193
+ int rc = SQLITE_OK;
59194
+ if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
59195
+ rc = sqlite3WalWriteLock(pPager->pWal, bLock);
59196
+ }
59197
+ return rc;
59198
+}
5912459199
59200
+/*
59201
+** Set the database handle used by the wal layer to determine if
59202
+** blocking locks are required.
59203
+*/
59204
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
59205
+ if( pagerUseWal(pPager) ){
59206
+ sqlite3WalDb(pPager->pWal, db);
59207
+ }
59208
+}
59209
+#endif
5912559210
5912659211
#ifdef SQLITE_ENABLE_SNAPSHOT
5912759212
/*
5912859213
** If this is a WAL database, obtain a snapshot handle for the snapshot
5912959214
** currently open. Otherwise, return an error.
@@ -59139,11 +59224,14 @@
5913959224
/*
5914059225
** If this is a WAL database, store a pointer to pSnapshot. Next time a
5914159226
** read transaction is opened, attempt to read from the snapshot it
5914259227
** identifies. If this is not a WAL database, return an error.
5914359228
*/
59144
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
59229
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
59230
+ Pager *pPager,
59231
+ sqlite3_snapshot *pSnapshot
59232
+){
5914559233
int rc = SQLITE_OK;
5914659234
if( pPager->pWal ){
5914759235
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
5914859236
}else{
5914959237
rc = SQLITE_ERROR;
@@ -59684,10 +59772,13 @@
5968459772
u8 lockError; /* True if a locking error has occurred */
5968559773
#endif
5968659774
#ifdef SQLITE_ENABLE_SNAPSHOT
5968759775
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
5968859776
#endif
59777
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59778
+ sqlite3 *db;
59779
+#endif
5968959780
};
5969059781
5969159782
/*
5969259783
** Candidate values for Wal.exclusiveMode.
5969359784
*/
@@ -59782,11 +59873,11 @@
5978259873
5978359874
/* Enlarge the pWal->apWiData[] array if required */
5978459875
if( pWal->nWiData<=iPage ){
5978559876
sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
5978659877
volatile u32 **apNew;
59787
- apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
59878
+ apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
5978859879
if( !apNew ){
5978959880
*ppPage = 0;
5979059881
return SQLITE_NOMEM_BKPT;
5979159882
}
5979259883
memset((void*)&apNew[pWal->nWiData], 0,
@@ -59903,29 +59994,47 @@
5990359994
5990459995
aOut[0] = s1;
5990559996
aOut[1] = s2;
5990659997
}
5990759998
59999
+/*
60000
+** If there is the possibility of concurrent access to the SHM file
60001
+** from multiple threads and/or processes, then do a memory barrier.
60002
+*/
5990860003
static void walShmBarrier(Wal *pWal){
5990960004
if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
5991060005
sqlite3OsShmBarrier(pWal->pDbFd);
5991160006
}
5991260007
}
5991360008
60009
+/*
60010
+** Add the SQLITE_NO_TSAN as part of the return-type of a function
60011
+** definition as a hint that the function contains constructs that
60012
+** might give false-positive TSAN warnings.
60013
+**
60014
+** See tag-20200519-1.
60015
+*/
60016
+#if defined(__clang__) && !defined(SQLITE_NO_TSAN)
60017
+# define SQLITE_NO_TSAN __attribute__((no_sanitize_thread))
60018
+#else
60019
+# define SQLITE_NO_TSAN
60020
+#endif
60021
+
5991460022
/*
5991560023
** Write the header information in pWal->hdr into the wal-index.
5991660024
**
5991760025
** The checksum on pWal->hdr is updated before it is written.
5991860026
*/
59919
-static void walIndexWriteHdr(Wal *pWal){
60027
+static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){
5992060028
volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
5992160029
const int nCksum = offsetof(WalIndexHdr, aCksum);
5992260030
5992360031
assert( pWal->writeLock );
5992460032
pWal->hdr.isInit = 1;
5992560033
pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
5992660034
walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
60035
+ /* Possible TSAN false-positive. See tag-20200519-1 */
5992760036
memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
5992860037
walShmBarrier(pWal);
5992960038
memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
5993060039
}
5993160040
@@ -60057,11 +60166,11 @@
6005760166
if( pWal->exclusiveMode ) return SQLITE_OK;
6005860167
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
6005960168
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
6006060169
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
6006160170
walLockName(lockIdx), rc ? "failed" : "ok"));
60062
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
60171
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
6006360172
return rc;
6006460173
}
6006560174
static void walUnlockShared(Wal *pWal, int lockIdx){
6006660175
if( pWal->exclusiveMode ) return;
6006760176
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
@@ -60073,11 +60182,11 @@
6007360182
if( pWal->exclusiveMode ) return SQLITE_OK;
6007460183
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
6007560184
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
6007660185
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
6007760186
walLockName(lockIdx), n, rc ? "failed" : "ok"));
60078
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
60187
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
6007960188
return rc;
6008060189
}
6008160190
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
6008260191
if( pWal->exclusiveMode ) return;
6008360192
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
@@ -60345,15 +60454,10 @@
6034560454
int rc; /* Return Code */
6034660455
i64 nSize; /* Size of log file */
6034760456
u32 aFrameCksum[2] = {0, 0};
6034860457
int iLock; /* Lock offset to lock for checkpoint */
6034960458
60350
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
60351
- int tmout = 0;
60352
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
60353
-#endif
60354
-
6035560459
/* Obtain an exclusive lock on all byte in the locking range not already
6035660460
** locked by the caller. The caller is guaranteed to have locked the
6035760461
** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
6035860462
** If successful, the same bytes that are locked here are unlocked before
6035960463
** this function returns.
@@ -60897,10 +61001,93 @@
6089761001
p = 0;
6089861002
}
6089961003
*pp = p;
6090061004
return rc;
6090161005
}
61006
+
61007
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61008
+/*
61009
+** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
61010
+** they are supported by the VFS, and (b) the database handle is configured
61011
+** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
61012
+** or 0 otherwise.
61013
+*/
61014
+static int walEnableBlocking(Wal *pWal){
61015
+ int res = 0;
61016
+ if( pWal->db ){
61017
+ int tmout = pWal->db->busyTimeout;
61018
+ if( tmout ){
61019
+ int rc;
61020
+ rc = sqlite3OsFileControl(
61021
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
61022
+ );
61023
+ res = (rc==SQLITE_OK);
61024
+ }
61025
+ }
61026
+ return res;
61027
+}
61028
+
61029
+/*
61030
+** Disable blocking locks.
61031
+*/
61032
+static void walDisableBlocking(Wal *pWal){
61033
+ int tmout = 0;
61034
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
61035
+}
61036
+
61037
+/*
61038
+** If parameter bLock is true, attempt to enable blocking locks, take
61039
+** the WRITER lock, and then disable blocking locks. If blocking locks
61040
+** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
61041
+** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
61042
+** an error if blocking locks can not be enabled.
61043
+**
61044
+** If the bLock parameter is false and the WRITER lock is held, release it.
61045
+*/
61046
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){
61047
+ int rc = SQLITE_OK;
61048
+ assert( pWal->readLock<0 || bLock==0 );
61049
+ if( bLock ){
61050
+ assert( pWal->db );
61051
+ if( walEnableBlocking(pWal) ){
61052
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
61053
+ if( rc==SQLITE_OK ){
61054
+ pWal->writeLock = 1;
61055
+ }
61056
+ walDisableBlocking(pWal);
61057
+ }
61058
+ }else if( pWal->writeLock ){
61059
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61060
+ pWal->writeLock = 0;
61061
+ }
61062
+ return rc;
61063
+}
61064
+
61065
+/*
61066
+** Set the database handle used to determine if blocking locks are required.
61067
+*/
61068
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
61069
+ pWal->db = db;
61070
+}
61071
+
61072
+/*
61073
+** Take an exclusive WRITE lock. Blocking if so configured.
61074
+*/
61075
+static int walLockWriter(Wal *pWal){
61076
+ int rc;
61077
+ walEnableBlocking(pWal);
61078
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
61079
+ walDisableBlocking(pWal);
61080
+ return rc;
61081
+}
61082
+#else
61083
+# define walEnableBlocking(x) 0
61084
+# define walDisableBlocking(x)
61085
+# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
61086
+# define sqlite3WalDb(pWal, db)
61087
+#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
61088
+
6090261089
6090361090
/*
6090461091
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
6090561092
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
6090661093
** busy-handler function. Invoke it and retry the lock until either the
@@ -60915,10 +61102,16 @@
6091561102
){
6091661103
int rc;
6091761104
do {
6091861105
rc = walLockExclusive(pWal, lockIdx, n);
6091961106
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
61107
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61108
+ if( rc==SQLITE_BUSY_TIMEOUT ){
61109
+ walDisableBlocking(pWal);
61110
+ rc = SQLITE_BUSY;
61111
+ }
61112
+#endif
6092061113
return rc;
6092161114
}
6092261115
6092361116
/*
6092461117
** The cache of the wal-index header must be valid to call this function.
@@ -60952,11 +61145,11 @@
6095261145
pWal->nCkpt++;
6095361146
pWal->hdr.mxFrame = 0;
6095461147
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
6095561148
memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
6095661149
walIndexWriteHdr(pWal);
60957
- pInfo->nBackfill = 0;
61150
+ AtomicStore(&pInfo->nBackfill, 0);
6095861151
pInfo->nBackfillAttempted = 0;
6095961152
pInfo->aReadMark[1] = 0;
6096061153
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
6096161154
assert( pInfo->aReadMark[0]==0 );
6096261155
}
@@ -61027,36 +61220,17 @@
6102761220
** cannot be backfilled from the WAL.
6102861221
*/
6102961222
mxSafeFrame = pWal->hdr.mxFrame;
6103061223
mxPage = pWal->hdr.nPage;
6103161224
for(i=1; i<WAL_NREADER; i++){
61032
- /* Thread-sanitizer reports that the following is an unsafe read,
61033
- ** as some other thread may be in the process of updating the value
61034
- ** of the aReadMark[] slot. The assumption here is that if that is
61035
- ** happening, the other client may only be increasing the value,
61036
- ** not decreasing it. So assuming either that either the "old" or
61037
- ** "new" version of the value is read, and not some arbitrary value
61038
- ** that would never be written by a real client, things are still
61039
- ** safe.
61040
- **
61041
- ** Astute readers have pointed out that the assumption stated in the
61042
- ** last sentence of the previous paragraph is not guaranteed to be
61043
- ** true for all conforming systems. However, the assumption is true
61044
- ** for all compilers and architectures in common use today (circa
61045
- ** 2019-11-27) and the alternatives are both slow and complex, and
61046
- ** so we will continue to go with the current design for now. If this
61047
- ** bothers you, or if you really are running on a system where aligned
61048
- ** 32-bit reads and writes are not atomic, then you can simply avoid
61049
- ** the use of WAL mode, or only use WAL mode together with
61050
- ** PRAGMA locking_mode=EXCLUSIVE and all will be well.
61051
- */
61052
- u32 y = pInfo->aReadMark[i];
61225
+ u32 y = AtomicLoad(pInfo->aReadMark+i);
6105361226
if( mxSafeFrame>y ){
6105461227
assert( y<=pWal->hdr.mxFrame );
6105561228
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
6105661229
if( rc==SQLITE_OK ){
61057
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
61230
+ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
61231
+ AtomicStore(pInfo->aReadMark+i, iMark);
6105861232
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
6105961233
}else if( rc==SQLITE_BUSY ){
6106061234
mxSafeFrame = y;
6106161235
xBusy = 0;
6106261236
}else{
@@ -61070,11 +61244,11 @@
6107061244
rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter);
6107161245
assert( rc==SQLITE_OK || pIter==0 );
6107261246
}
6107361247
6107461248
if( pIter
61075
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
61249
+ && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
6107661250
){
6107761251
u32 nBackfill = pInfo->nBackfill;
6107861252
6107961253
pInfo->nBackfillAttempted = mxSafeFrame;
6108061254
@@ -61126,11 +61300,11 @@
6112661300
if( rc==SQLITE_OK ){
6112761301
rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
6112861302
}
6112961303
}
6113061304
if( rc==SQLITE_OK ){
61131
- pInfo->nBackfill = mxSafeFrame;
61305
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame);
6113261306
}
6113361307
}
6113461308
6113561309
/* Release the reader lock held while backfilling */
6113661310
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
@@ -61285,11 +61459,11 @@
6128561459
** and *pChanged is set to 1.
6128661460
**
6128761461
** If the checksum cannot be verified return non-zero. If the header
6128861462
** is read successfully and the checksum verified, return zero.
6128961463
*/
61290
-static int walIndexTryHdr(Wal *pWal, int *pChanged){
61464
+static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
6129161465
u32 aCksum[2]; /* Checksum on the header content */
6129261466
WalIndexHdr h1, h2; /* Two copies of the header content */
6129361467
WalIndexHdr volatile *aHdr; /* Header in shared memory */
6129461468
6129561469
/* The first page of the wal-index must be mapped at this point. */
@@ -61298,17 +61472,23 @@
6129861472
/* Read the header. This might happen concurrently with a write to the
6129961473
** same area of shared memory on a different CPU in a SMP,
6130061474
** meaning it is possible that an inconsistent snapshot is read
6130161475
** from the file. If this happens, return non-zero.
6130261476
**
61477
+ ** tag-20200519-1:
6130361478
** There are two copies of the header at the beginning of the wal-index.
6130461479
** When reading, read [0] first then [1]. Writes are in the reverse order.
6130561480
** Memory barriers are used to prevent the compiler or the hardware from
61306
- ** reordering the reads and writes.
61481
+ ** reordering the reads and writes. TSAN and similar tools can sometimes
61482
+ ** give false-positive warnings about these accesses because the tools do not
61483
+ ** account for the double-read and the memory barrier. The use of mutexes
61484
+ ** here would be problematic as the memory being accessed is potentially
61485
+ ** shared among multiple processes and not all mutex implementions work
61486
+ ** reliably in that environment.
6130761487
*/
6130861488
aHdr = walIndexHdr(pWal);
61309
- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
61489
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */
6131061490
walShmBarrier(pWal);
6131161491
memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
6131261492
6131361493
if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
6131461494
return 1; /* Dirty read */
@@ -61394,32 +61574,36 @@
6139461574
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
6139561575
6139661576
/* If the first attempt failed, it might have been due to a race
6139761577
** with a writer. So get a WRITE lock and try again.
6139861578
*/
61399
- assert( badHdr==0 || pWal->writeLock==0 );
6140061579
if( badHdr ){
6140161580
if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
6140261581
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
6140361582
walUnlockShared(pWal, WAL_WRITE_LOCK);
6140461583
rc = SQLITE_READONLY_RECOVERY;
6140561584
}
61406
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
61407
- pWal->writeLock = 1;
61408
- if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
61409
- badHdr = walIndexTryHdr(pWal, pChanged);
61410
- if( badHdr ){
61411
- /* If the wal-index header is still malformed even while holding
61412
- ** a WRITE lock, it can only mean that the header is corrupted and
61413
- ** needs to be reconstructed. So run recovery to do exactly that.
61414
- */
61415
- rc = walIndexRecover(pWal);
61416
- *pChanged = 1;
61417
- }
61418
- }
61419
- pWal->writeLock = 0;
61420
- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61585
+ }else{
61586
+ int bWriteLock = pWal->writeLock;
61587
+ if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
61588
+ pWal->writeLock = 1;
61589
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
61590
+ badHdr = walIndexTryHdr(pWal, pChanged);
61591
+ if( badHdr ){
61592
+ /* If the wal-index header is still malformed even while holding
61593
+ ** a WRITE lock, it can only mean that the header is corrupted and
61594
+ ** needs to be reconstructed. So run recovery to do exactly that.
61595
+ */
61596
+ rc = walIndexRecover(pWal);
61597
+ *pChanged = 1;
61598
+ }
61599
+ }
61600
+ if( bWriteLock==0 ){
61601
+ pWal->writeLock = 0;
61602
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61603
+ }
61604
+ }
6142161605
}
6142261606
}
6142361607
6142461608
/* If the header is read successfully, check the version number to make
6142561609
** sure the wal-index was not constructed with some future format that
@@ -61745,11 +61929,11 @@
6174561929
}
6174661930
6174761931
assert( pWal->nWiData>0 );
6174861932
assert( pWal->apWiData[0]!=0 );
6174961933
pInfo = walCkptInfo(pWal);
61750
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
61934
+ if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
6175161935
#ifdef SQLITE_ENABLE_SNAPSHOT
6175261936
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
6175361937
#endif
6175461938
){
6175561939
/* The WAL has been completely backfilled (or it is empty).
@@ -61912,11 +62096,11 @@
6191262096
void *pBuf2 = sqlite3_malloc(szPage);
6191362097
if( pBuf1==0 || pBuf2==0 ){
6191462098
rc = SQLITE_NOMEM;
6191562099
}else{
6191662100
u32 i = pInfo->nBackfillAttempted;
61917
- for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
62101
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
6191862102
WalHashLoc sLoc; /* Hash table location */
6191962103
u32 pgno; /* Page number in db file */
6192062104
i64 iDbOff; /* Offset of db file entry */
6192162105
i64 iWalOff; /* Offset of wal file entry */
6192262106
@@ -61967,26 +62151,40 @@
6196762151
** needs to be flushed.
6196862152
*/
6196962153
SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
6197062154
int rc; /* Return code */
6197162155
int cnt = 0; /* Number of TryBeginRead attempts */
61972
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61973
- int tmout = 0;
61974
-#endif
61975
-
6197662156
#ifdef SQLITE_ENABLE_SNAPSHOT
6197762157
int bChanged = 0;
6197862158
WalIndexHdr *pSnapshot = pWal->pSnapshot;
61979
- if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
61980
- bChanged = 1;
61981
- }
6198262159
#endif
6198362160
61984
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61985
- /* Disable blocking locks. They are not useful when trying to open a
61986
- ** read-transaction, and blocking may cause deadlock anyway. */
61987
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
62161
+ assert( pWal->ckptLock==0 );
62162
+
62163
+#ifdef SQLITE_ENABLE_SNAPSHOT
62164
+ if( pSnapshot ){
62165
+ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62166
+ bChanged = 1;
62167
+ }
62168
+
62169
+ /* It is possible that there is a checkpointer thread running
62170
+ ** concurrent with this code. If this is the case, it may be that the
62171
+ ** checkpointer has already determined that it will checkpoint
62172
+ ** snapshot X, where X is later in the wal file than pSnapshot, but
62173
+ ** has not yet set the pInfo->nBackfillAttempted variable to indicate
62174
+ ** its intent. To avoid the race condition this leads to, ensure that
62175
+ ** there is no checkpointer process by taking a shared CKPT lock
62176
+ ** before checking pInfo->nBackfillAttempted. */
62177
+ (void)walEnableBlocking(pWal);
62178
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
62179
+ walDisableBlocking(pWal);
62180
+
62181
+ if( rc!=SQLITE_OK ){
62182
+ return rc;
62183
+ }
62184
+ pWal->ckptLock = 1;
62185
+ }
6198862186
#endif
6198962187
6199062188
do{
6199162189
rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
6199262190
}while( rc==WAL_RETRY );
@@ -61993,20 +62191,10 @@
6199362191
testcase( (rc&0xff)==SQLITE_BUSY );
6199462192
testcase( (rc&0xff)==SQLITE_IOERR );
6199562193
testcase( rc==SQLITE_PROTOCOL );
6199662194
testcase( rc==SQLITE_OK );
6199762195
61998
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61999
- /* If they were disabled earlier and the read-transaction has been
62000
- ** successfully opened, re-enable blocking locks. This is because the
62001
- ** connection may attempt to upgrade to a write-transaction, which does
62002
- ** benefit from using blocking locks. */
62003
- if( rc==SQLITE_OK ){
62004
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
62005
- }
62006
-#endif
62007
-
6200862196
#ifdef SQLITE_ENABLE_SNAPSHOT
6200962197
if( rc==SQLITE_OK ){
6201062198
if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
6201162199
/* At this point the client has a lock on an aReadMark[] slot holding
6201262200
** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
@@ -62024,52 +62212,46 @@
6202462212
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
6202562213
6202662214
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
6202762215
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
6202862216
62029
- /* It is possible that there is a checkpointer thread running
62030
- ** concurrent with this code. If this is the case, it may be that the
62031
- ** checkpointer has already determined that it will checkpoint
62032
- ** snapshot X, where X is later in the wal file than pSnapshot, but
62033
- ** has not yet set the pInfo->nBackfillAttempted variable to indicate
62034
- ** its intent. To avoid the race condition this leads to, ensure that
62035
- ** there is no checkpointer process by taking a shared CKPT lock
62036
- ** before checking pInfo->nBackfillAttempted.
62037
- **
62038
- ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
62039
- ** this already?
62040
- */
62041
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
62042
-
62043
- if( rc==SQLITE_OK ){
62044
- /* Check that the wal file has not been wrapped. Assuming that it has
62045
- ** not, also check that no checkpointer has attempted to checkpoint any
62046
- ** frames beyond pSnapshot->mxFrame. If either of these conditions are
62047
- ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
62048
- ** with *pSnapshot and set *pChanged as appropriate for opening the
62049
- ** snapshot. */
62050
- if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
62051
- && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
62052
- ){
62053
- assert( pWal->readLock>0 );
62054
- memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
62055
- *pChanged = bChanged;
62056
- }else{
62057
- rc = SQLITE_ERROR_SNAPSHOT;
62058
- }
62059
-
62060
- /* Release the shared CKPT lock obtained above. */
62061
- walUnlockShared(pWal, WAL_CKPT_LOCK);
62062
- pWal->minFrame = 1;
62063
- }
62064
-
62217
+ /* Check that the wal file has not been wrapped. Assuming that it has
62218
+ ** not, also check that no checkpointer has attempted to checkpoint any
62219
+ ** frames beyond pSnapshot->mxFrame. If either of these conditions are
62220
+ ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
62221
+ ** with *pSnapshot and set *pChanged as appropriate for opening the
62222
+ ** snapshot. */
62223
+ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
62224
+ && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
62225
+ ){
62226
+ assert( pWal->readLock>0 );
62227
+ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
62228
+ *pChanged = bChanged;
62229
+ }else{
62230
+ rc = SQLITE_ERROR_SNAPSHOT;
62231
+ }
62232
+
62233
+ /* A client using a non-current snapshot may not ignore any frames
62234
+ ** from the start of the wal file. This is because, for a system
62235
+ ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
62236
+ ** have omitted to checkpoint a frame earlier than minFrame in
62237
+ ** the file because there exists a frame after iSnapshot that
62238
+ ** is the same database page. */
62239
+ pWal->minFrame = 1;
6206562240
6206662241
if( rc!=SQLITE_OK ){
6206762242
sqlite3WalEndReadTransaction(pWal);
6206862243
}
6206962244
}
6207062245
}
62246
+
62247
+ /* Release the shared CKPT lock obtained above. */
62248
+ if( pWal->ckptLock ){
62249
+ assert( pSnapshot );
62250
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
62251
+ pWal->ckptLock = 0;
62252
+ }
6207162253
#endif
6207262254
return rc;
6207362255
}
6207462256
6207562257
/*
@@ -62145,26 +62327,28 @@
6214562327
for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){
6214662328
WalHashLoc sLoc; /* Hash table location */
6214762329
int iKey; /* Hash slot index */
6214862330
int nCollide; /* Number of hash collisions remaining */
6214962331
int rc; /* Error code */
62332
+ u32 iH;
6215062333
6215162334
rc = walHashGet(pWal, iHash, &sLoc);
6215262335
if( rc!=SQLITE_OK ){
6215362336
return rc;
6215462337
}
6215562338
nCollide = HASHTABLE_NSLOT;
62156
- for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
62157
- u32 iH = sLoc.aHash[iKey];
62339
+ iKey = walHash(pgno);
62340
+ while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
6215862341
u32 iFrame = iH + sLoc.iZero;
6215962342
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){
6216062343
assert( iFrame>iRead || CORRUPT_DB );
6216162344
iRead = iFrame;
6216262345
}
6216362346
if( (nCollide--)==0 ){
6216462347
return SQLITE_CORRUPT_BKPT;
6216562348
}
62349
+ iKey = walNextHash(iKey);
6216662350
}
6216762351
if( iRead ) break;
6216862352
}
6216962353
6217062354
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
@@ -62235,10 +62419,20 @@
6223562419
**
6223662420
** There can only be a single writer active at a time.
6223762421
*/
6223862422
SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
6223962423
int rc;
62424
+
62425
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
62426
+ /* If the write-lock is already held, then it was obtained before the
62427
+ ** read-transaction was even opened, making this call a no-op.
62428
+ ** Return early. */
62429
+ if( pWal->writeLock ){
62430
+ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
62431
+ return SQLITE_OK;
62432
+ }
62433
+#endif
6224062434
6224162435
/* Cannot start a write transaction without first holding a read
6224262436
** transaction. */
6224362437
assert( pWal->readLock>=0 );
6224462438
assert( pWal->writeLock==0 && pWal->iReCksum==0 );
@@ -62811,50 +63005,57 @@
6281163005
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
6281263006
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
6281363007
6281463008
if( pWal->readOnly ) return SQLITE_READONLY;
6281563009
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
63010
+
63011
+ /* Enable blocking locks, if possible. If blocking locks are successfully
63012
+ ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
63013
+ sqlite3WalDb(pWal, db);
63014
+ (void)walEnableBlocking(pWal);
6281663015
6281763016
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
62818
- ** "checkpoint" lock on the database file. */
63017
+ ** "checkpoint" lock on the database file.
63018
+ ** EVIDENCE-OF: R-10421-19736 If any other process is running a
63019
+ ** checkpoint operation at the same time, the lock cannot be obtained and
63020
+ ** SQLITE_BUSY is returned.
63021
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
63022
+ ** it will not be invoked in this case.
63023
+ */
6281963024
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
62820
- if( rc ){
62821
- /* EVIDENCE-OF: R-10421-19736 If any other process is running a
62822
- ** checkpoint operation at the same time, the lock cannot be obtained and
62823
- ** SQLITE_BUSY is returned.
62824
- ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
62825
- ** it will not be invoked in this case.
62826
- */
62827
- testcase( rc==SQLITE_BUSY );
62828
- testcase( xBusy!=0 );
62829
- return rc;
62830
- }
62831
- pWal->ckptLock = 1;
62832
-
62833
- /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
62834
- ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
62835
- ** file.
62836
- **
62837
- ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
62838
- ** immediately, and a busy-handler is configured, it is invoked and the
62839
- ** writer lock retried until either the busy-handler returns 0 or the
62840
- ** lock is successfully obtained.
62841
- */
62842
- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
62843
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
62844
- if( rc==SQLITE_OK ){
62845
- pWal->writeLock = 1;
62846
- }else if( rc==SQLITE_BUSY ){
62847
- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
62848
- xBusy2 = 0;
62849
- rc = SQLITE_OK;
62850
- }
62851
- }
63025
+ testcase( rc==SQLITE_BUSY );
63026
+ testcase( rc!=SQLITE_OK && xBusy2!=0 );
63027
+ if( rc==SQLITE_OK ){
63028
+ pWal->ckptLock = 1;
63029
+
63030
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
63031
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
63032
+ ** file.
63033
+ **
63034
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
63035
+ ** immediately, and a busy-handler is configured, it is invoked and the
63036
+ ** writer lock retried until either the busy-handler returns 0 or the
63037
+ ** lock is successfully obtained.
63038
+ */
63039
+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
63040
+ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
63041
+ if( rc==SQLITE_OK ){
63042
+ pWal->writeLock = 1;
63043
+ }else if( rc==SQLITE_BUSY ){
63044
+ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
63045
+ xBusy2 = 0;
63046
+ rc = SQLITE_OK;
63047
+ }
63048
+ }
63049
+ }
63050
+
6285263051
6285363052
/* Read the wal-index header. */
6285463053
if( rc==SQLITE_OK ){
63054
+ walDisableBlocking(pWal);
6285563055
rc = walIndexReadHdr(pWal, &isChanged);
63056
+ (void)walEnableBlocking(pWal);
6285663057
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
6285763058
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
6285863059
}
6285963060
}
6286063061
@@ -62881,16 +63082,24 @@
6288163082
** next time the pager opens a snapshot on this database it knows that
6288263083
** the cache needs to be reset.
6288363084
*/
6288463085
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
6288563086
}
63087
+
63088
+ walDisableBlocking(pWal);
63089
+ sqlite3WalDb(pWal, 0);
6288663090
6288763091
/* Release the locks. */
6288863092
sqlite3WalEndWriteTransaction(pWal);
62889
- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
62890
- pWal->ckptLock = 0;
63093
+ if( pWal->ckptLock ){
63094
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
63095
+ pWal->ckptLock = 0;
63096
+ }
6289163097
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
63098
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
63099
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
63100
+#endif
6289263101
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
6289363102
}
6289463103
6289563104
/* Return the value to pass to a sqlite3_wal_hook callback, the
6289663105
** number of frames in the WAL at the point of the last commit since
@@ -63003,11 +63212,14 @@
6300363212
return rc;
6300463213
}
6300563214
6300663215
/* Try to open on pSnapshot when the next read-transaction starts
6300763216
*/
63008
-SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
63217
+SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
63218
+ Wal *pWal,
63219
+ sqlite3_snapshot *pSnapshot
63220
+){
6300963221
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
6301063222
}
6301163223
6301263224
/*
6301363225
** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
@@ -63522,11 +63734,11 @@
6352263734
u8 incrVacuum; /* True if incr-vacuum is enabled */
6352363735
u8 bDoTruncate; /* True to truncate db on commit */
6352463736
#endif
6352563737
u8 inTransaction; /* Transaction state */
6352663738
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
63527
- u8 nReserveWanted; /* 1 more than desired number of extra bytes per page */
63739
+ u8 nReserveWanted; /* Desired number of extra bytes per page */
6352863740
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
6352963741
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
6353063742
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
6353163743
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
6353263744
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
@@ -66416,12 +66628,11 @@
6641666628
*/
6641766629
static int btreeInvokeBusyHandler(void *pArg){
6641866630
BtShared *pBt = (BtShared*)pArg;
6641966631
assert( pBt->db );
6642066632
assert( sqlite3_mutex_held(pBt->db->mutex) );
66421
- return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
66422
- sqlite3PagerFile(pBt->pPager));
66633
+ return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
6642366634
}
6642466635
6642566636
/*
6642666637
** Open a database file.
6642766638
**
@@ -66968,23 +67179,21 @@
6696867179
** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
6696967180
** and autovacuum mode can no longer be changed.
6697067181
*/
6697167182
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
6697267183
int rc = SQLITE_OK;
67184
+ int x;
6697367185
BtShared *pBt = p->pBt;
66974
- assert( nReserve>=-1 && nReserve<=254 );
67186
+ assert( nReserve>=0 && nReserve<=255 );
6697567187
sqlite3BtreeEnter(p);
66976
- if( nReserve>=0 ){
66977
- pBt->nReserveWanted = nReserve + 1;
66978
- }
67188
+ pBt->nReserveWanted = nReserve;
67189
+ x = pBt->pageSize - pBt->usableSize;
67190
+ if( nReserve<x ) nReserve = x;
6697967191
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
6698067192
sqlite3BtreeLeave(p);
6698167193
return SQLITE_READONLY;
6698267194
}
66983
- if( nReserve<0 ){
66984
- nReserve = pBt->pageSize - pBt->usableSize;
66985
- }
6698667195
assert( nReserve>=0 && nReserve<=255 );
6698767196
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
6698867197
((pageSize-1)&pageSize)==0 ){
6698967198
assert( (pageSize & 7)==0 );
6699067199
assert( !pBt->pCursor );
@@ -67031,16 +67240,16 @@
6703167240
** The value returned is the larger of the current reserve size and
6703267241
** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
6703367242
** The amount of reserve can only grow - never shrink.
6703467243
*/
6703567244
SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
67036
- int n;
67245
+ int n1, n2;
6703767246
sqlite3BtreeEnter(p);
67038
- n = ((int)p->pBt->nReserveWanted) - 1;
67039
- if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
67247
+ n1 = (int)p->pBt->nReserveWanted;
67248
+ n2 = sqlite3BtreeGetReserveNoMutex(p);
6704067249
sqlite3BtreeLeave(p);
67041
- return n;
67250
+ return n1>n2 ? n1 : n2;
6704267251
}
6704367252
6704467253
6704567254
/*
6704667255
** Set the maximum page count for a database if mxPage is positive.
@@ -67486,10 +67695,11 @@
6748667695
** when A already has a read lock, we encourage A to give up and let B
6748767696
** proceed.
6748867697
*/
6748967698
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
6749067699
BtShared *pBt = p->pBt;
67700
+ Pager *pPager = pBt->pPager;
6749167701
int rc = SQLITE_OK;
6749267702
6749367703
sqlite3BtreeEnter(p);
6749467704
btreeIntegrity(p);
6749567705
@@ -67501,11 +67711,11 @@
6750167711
goto trans_begun;
6750267712
}
6750367713
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
6750467714
6750567715
if( (p->db->flags & SQLITE_ResetDatabase)
67506
- && sqlite3PagerIsreadonly(pBt->pPager)==0
67716
+ && sqlite3PagerIsreadonly(pPager)==0
6750767717
){
6750867718
pBt->btsFlags &= ~BTS_READ_ONLY;
6750967719
}
6751067720
6751167721
/* Write transactions are not possible on a read-only database */
@@ -67549,10 +67759,22 @@
6754967759
if( SQLITE_OK!=rc ) goto trans_begun;
6755067760
6755167761
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
6755267762
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
6755367763
do {
67764
+ sqlite3PagerWalDb(pPager, p->db);
67765
+
67766
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67767
+ /* If transitioning from no transaction directly to a write transaction,
67768
+ ** block for the WRITER lock first if possible. */
67769
+ if( pBt->pPage1==0 && wrflag ){
67770
+ assert( pBt->inTransaction==TRANS_NONE );
67771
+ rc = sqlite3PagerWalWriteLock(pPager, 1);
67772
+ if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
67773
+ }
67774
+#endif
67775
+
6755467776
/* Call lockBtree() until either pBt->pPage1 is populated or
6755567777
** lockBtree() returns something other than SQLITE_OK. lockBtree()
6755667778
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
6755767779
** reading page 1 it discovers that the page-size of the database
6755867780
** file is not pBt->pageSize. In this case lockBtree() will update
@@ -67562,11 +67784,11 @@
6756267784
6756367785
if( rc==SQLITE_OK && wrflag ){
6756467786
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
6756567787
rc = SQLITE_READONLY;
6756667788
}else{
67567
- rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
67789
+ rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
6756867790
if( rc==SQLITE_OK ){
6756967791
rc = newDatabase(pBt);
6757067792
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
6757167793
/* if there was no transaction opened when this function was
6757267794
** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
@@ -67575,15 +67797,19 @@
6757567797
}
6757667798
}
6757767799
}
6757867800
6757967801
if( rc!=SQLITE_OK ){
67802
+ (void)sqlite3PagerWalWriteLock(pPager, 0);
6758067803
unlockBtreeIfUnused(pBt);
6758167804
}
6758267805
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
6758367806
btreeInvokeBusyHandler(pBt) );
67584
- sqlite3PagerResetLockTimeout(pBt->pPager);
67807
+ sqlite3PagerWalDb(pPager, 0);
67808
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67809
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
67810
+#endif
6758567811
6758667812
if( rc==SQLITE_OK ){
6758767813
if( p->inTrans==TRANS_NONE ){
6758867814
pBt->nTransaction++;
6758967815
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -67631,11 +67857,11 @@
6763167857
if( wrflag ){
6763267858
/* This call makes sure that the pager has the correct number of
6763367859
** open savepoints. If the second parameter is greater than 0 and
6763467860
** the sub-journal is not already open, then it will be opened here.
6763567861
*/
67636
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
67862
+ rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
6763767863
}
6763867864
}
6763967865
6764067866
btreeIntegrity(p);
6764167867
sqlite3BtreeLeave(p);
@@ -71267,11 +71493,11 @@
7126771493
7126871494
/* Remove cells from the start and end of the page */
7126971495
assert( nCell>=0 );
7127071496
if( iOld<iNew ){
7127171497
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
71272
- if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
71498
+ if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
7127371499
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
7127471500
nCell -= nShift;
7127571501
}
7127671502
if( iNewEnd < iOldEnd ){
7127771503
int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
@@ -74746,11 +74972,11 @@
7474674972
** Attempt to set the page size of the destination to match the page size
7474774973
** of the source.
7474874974
*/
7474974975
static int setDestPgsz(sqlite3_backup *p){
7475074976
int rc;
74751
- rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
74977
+ rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
7475274978
return rc;
7475374979
}
7475474980
7475574981
/*
7475674982
** Check that there is no open read-transaction on the b-tree passed as the
@@ -79143,10 +79369,11 @@
7914379369
char *zP4;
7914479370
char *zCom;
7914579371
sqlite3 dummyDb;
7914679372
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
7914779373
if( pOut==0 ) pOut = stdout;
79374
+ sqlite3BeginBenignMalloc();
7914879375
dummyDb.mallocFailed = 1;
7914979376
zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
7915079377
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
7915179378
zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
7915279379
#else
@@ -79161,10 +79388,11 @@
7916179388
zCom ? zCom : ""
7916279389
);
7916379390
fflush(pOut);
7916479391
sqlite3_free(zP4);
7916579392
sqlite3_free(zCom);
79393
+ sqlite3EndBenignMalloc();
7916679394
}
7916779395
#endif
7916879396
7916979397
/*
7917079398
** Initialize an array of N Mem element.
@@ -83902,11 +84130,11 @@
8390284130
p->db->errCode = SQLITE_OK;
8390384131
8390484132
/* If the bit corresponding to this variable in Vdbe.expmask is set, then
8390584133
** binding a new value to this variable invalidates the current query plan.
8390684134
**
83907
- ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
84135
+ ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host
8390884136
** parameter in the WHERE clause might influence the choice of query plan
8390984137
** for a statement, then the statement will be automatically recompiled,
8391084138
** as if there had been a schema change, on the first sqlite3_step() call
8391184139
** following any change to the bindings of that parameter.
8391284140
*/
@@ -90540,16 +90768,23 @@
9054090768
rc = sqlite3VdbeSorterWrite(pC, pIn2);
9054190769
if( rc) goto abort_due_to_error;
9054290770
break;
9054390771
}
9054490772
90545
-/* Opcode: IdxDelete P1 P2 P3 * *
90773
+/* Opcode: IdxDelete P1 P2 P3 * P5
9054690774
** Synopsis: key=r[P2@P3]
9054790775
**
9054890776
** The content of P3 registers starting at register P2 form
9054990777
** an unpacked index key. This opcode removes that entry from the
9055090778
** index opened by cursor P1.
90779
+**
90780
+** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
90781
+** if no matching index entry is found. This happens when running
90782
+** an UPDATE or DELETE statement and the index entry to be updated
90783
+** or deleted is not found. For some uses of IdxDelete
90784
+** (example: the EXCEPT operator) it does not matter that no matching
90785
+** entry is found. For those cases, P5 is zero.
9055190786
*/
9055290787
case OP_IdxDelete: {
9055390788
VdbeCursor *pC;
9055490789
BtCursor *pCrsr;
9055590790
int res;
@@ -90562,20 +90797,22 @@
9056290797
assert( pC!=0 );
9056390798
assert( pC->eCurType==CURTYPE_BTREE );
9056490799
sqlite3VdbeIncrWriteCounter(p, pC);
9056590800
pCrsr = pC->uc.pCursor;
9056690801
assert( pCrsr!=0 );
90567
- assert( pOp->p5==0 );
9056890802
r.pKeyInfo = pC->pKeyInfo;
9056990803
r.nField = (u16)pOp->p3;
9057090804
r.default_rc = 0;
9057190805
r.aMem = &aMem[pOp->p2];
9057290806
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
9057390807
if( rc ) goto abort_due_to_error;
9057490808
if( res==0 ){
9057590809
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
9057690810
if( rc ) goto abort_due_to_error;
90811
+ }else if( pOp->p5 ){
90812
+ rc = SQLITE_CORRUPT_INDEX;
90813
+ goto abort_due_to_error;
9057790814
}
9057890815
assert( pC->deferredMoveto==0 );
9057990816
pC->cacheStatus = CACHE_STALE;
9058090817
pC->seekResult = 0;
9058190818
break;
@@ -96192,12 +96429,12 @@
9619296429
*************************************************************************
9619396430
**
9619496431
** This file implements virtual-tables for examining the bytecode content
9619596432
** of a prepared statement.
9619696433
*/
96197
-#ifdef SQLITE_ENABLE_BYTECODE_VTAB
9619896434
/* #include "sqliteInt.h" */
96435
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
9619996436
/* #include "vdbeInt.h" */
9620096437
9620196438
/* An instance of the bytecode() table-valued function.
9620296439
*/
9620396440
typedef struct bytecodevtab bytecodevtab;
@@ -96598,10 +96835,12 @@
9659896835
if( rc==SQLITE_OK ){
9659996836
rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
9660096837
}
9660196838
return rc;
9660296839
}
96840
+#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
96841
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
9660396842
#endif /* SQLITE_ENABLE_BYTECODE_VTAB */
9660496843
9660596844
/************** End of vdbevtab.c ********************************************/
9660696845
/************** Begin file memjournal.c **************************************/
9660796846
/*
@@ -97243,10 +97482,47 @@
9724397482
}
9724497483
p = p->pPrior;
9724597484
}while( p!=0 );
9724697485
return WRC_Continue;
9724797486
}
97487
+
97488
+/* Increase the walkerDepth when entering a subquery, and
97489
+** descrease when leaving the subquery.
97490
+*/
97491
+SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
97492
+ UNUSED_PARAMETER(pSelect);
97493
+ pWalker->walkerDepth++;
97494
+ return WRC_Continue;
97495
+}
97496
+SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){
97497
+ UNUSED_PARAMETER(pSelect);
97498
+ pWalker->walkerDepth--;
97499
+}
97500
+
97501
+
97502
+/*
97503
+** No-op routine for the parse-tree walker.
97504
+**
97505
+** When this routine is the Walker.xExprCallback then expression trees
97506
+** are walked without any actions being taken at each node. Presumably,
97507
+** when this routine is used for Walker.xExprCallback then
97508
+** Walker.xSelectCallback is set to do something useful for every
97509
+** subquery in the parser tree.
97510
+*/
97511
+SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
97512
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
97513
+ return WRC_Continue;
97514
+}
97515
+
97516
+/*
97517
+** No-op routine for the parse-tree walker for SELECT statements.
97518
+** subquery in the parser tree.
97519
+*/
97520
+SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
97521
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
97522
+ return WRC_Continue;
97523
+}
9724897524
9724997525
/************** End of walker.c **********************************************/
9725097526
/************** Begin file resolve.c *****************************************/
9725197527
/*
9725297528
** 2008 August 18
@@ -97272,10 +97548,12 @@
9727297548
** This needs to occur when copying a TK_AGG_FUNCTION node from an
9727397549
** outer query into an inner subquery.
9727497550
**
9727597551
** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
9727697552
** is a helper function - a callback for the tree walker.
97553
+**
97554
+** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
9727797555
*/
9727897556
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
9727997557
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
9728097558
return WRC_Continue;
9728197559
}
@@ -102902,10 +103180,17 @@
102902103180
}
102903103181
setDoNotMergeFlagOnCopy(v);
102904103182
sqlite3VdbeResolveLabel(v, endCoalesce);
102905103183
break;
102906103184
}
103185
+ case INLINEFUNC_iif: {
103186
+ Expr caseExpr;
103187
+ memset(&caseExpr, 0, sizeof(caseExpr));
103188
+ caseExpr.op = TK_CASE;
103189
+ caseExpr.x.pList = pFarg;
103190
+ return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
103191
+ }
102907103192
102908103193
default: {
102909103194
/* The UNLIKELY() function is a no-op. The result is the value
102910103195
** of the first argument.
102911103196
*/
@@ -103006,11 +103291,14 @@
103006103291
op = pExpr->op;
103007103292
}
103008103293
switch( op ){
103009103294
case TK_AGG_COLUMN: {
103010103295
AggInfo *pAggInfo = pExpr->pAggInfo;
103011
- struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
103296
+ struct AggInfo_col *pCol;
103297
+ assert( pAggInfo!=0 );
103298
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
103299
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
103012103300
if( !pAggInfo->directMode ){
103013103301
assert( pCol->iMem>0 );
103014103302
return pCol->iMem;
103015103303
}else if( pAggInfo->useSortingIdx ){
103016103304
Table *pTab = pCol->pTab;
@@ -103306,11 +103594,14 @@
103306103594
sqlite3VdbeJumpHere(v, addr);
103307103595
break;
103308103596
}
103309103597
case TK_AGG_FUNCTION: {
103310103598
AggInfo *pInfo = pExpr->pAggInfo;
103311
- if( pInfo==0 ){
103599
+ if( pInfo==0
103600
+ || NEVER(pExpr->iAgg<0)
103601
+ || NEVER(pExpr->iAgg>=pInfo->nFunc)
103602
+ ){
103312103603
assert( !ExprHasProperty(pExpr, EP_IntValue) );
103313103604
sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
103314103605
}else{
103315103606
return pInfo->aFunc[pExpr->iAgg].iMem;
103316103607
}
@@ -103684,11 +103975,11 @@
103684103975
assert( pExpr->affExpr==OE_Rollback
103685103976
|| pExpr->affExpr==OE_Abort
103686103977
|| pExpr->affExpr==OE_Fail
103687103978
|| pExpr->affExpr==OE_Ignore
103688103979
);
103689
- if( !pParse->pTriggerTab ){
103980
+ if( !pParse->pTriggerTab && !pParse->nested ){
103690103981
sqlite3ErrorMsg(pParse,
103691103982
"RAISE() may only be used within a trigger-program");
103692103983
return 0;
103693103984
}
103694103985
if( pExpr->affExpr==OE_Abort ){
@@ -103698,12 +103989,13 @@
103698103989
if( pExpr->affExpr==OE_Ignore ){
103699103990
sqlite3VdbeAddOp4(
103700103991
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
103701103992
VdbeCoverage(v);
103702103993
}else{
103703
- sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
103704
- pExpr->affExpr, pExpr->u.zToken, 0, 0);
103994
+ sqlite3HaltConstraint(pParse,
103995
+ pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
103996
+ pExpr->affExpr, pExpr->u.zToken, 0, 0);
103705103997
}
103706103998
103707103999
break;
103708104000
}
103709104001
#endif
@@ -105061,19 +105353,10 @@
105061105353
}
105062105354
}
105063105355
}
105064105356
return WRC_Continue;
105065105357
}
105066
-static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
105067
- UNUSED_PARAMETER(pSelect);
105068
- pWalker->walkerDepth++;
105069
- return WRC_Continue;
105070
-}
105071
-static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
105072
- UNUSED_PARAMETER(pSelect);
105073
- pWalker->walkerDepth--;
105074
-}
105075105358
105076105359
/*
105077105360
** Analyze the pExpr expression looking for aggregate functions and
105078105361
** for variables that need to be added to AggInfo object that pNC->pAggInfo
105079105362
** points to. Additional entries are made on the AggInfo object as
@@ -105083,12 +105366,12 @@
105083105366
** analyzed by sqlite3ResolveExprNames().
105084105367
*/
105085105368
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
105086105369
Walker w;
105087105370
w.xExprCallback = analyzeAggregate;
105088
- w.xSelectCallback = analyzeAggregatesInSelect;
105089
- w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
105371
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
105372
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
105090105373
w.walkerDepth = 0;
105091105374
w.u.pNC = pNC;
105092105375
w.pParse = 0;
105093105376
assert( pNC->pSrcList!=0 );
105094105377
sqlite3WalkExpr(&w, pExpr);
@@ -105323,11 +105606,14 @@
105323105606
if( !zName ) goto exit_rename_table;
105324105607
105325105608
/* Check that a table or index named 'zName' does not already exist
105326105609
** in database iDb. If so, this is an error.
105327105610
*/
105328
- if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
105611
+ if( sqlite3FindTable(db, zName, zDb)
105612
+ || sqlite3FindIndex(db, zName, zDb)
105613
+ || sqlite3IsShadowTableOf(db, pTab, zName)
105614
+ ){
105329105615
sqlite3ErrorMsg(pParse,
105330105616
"there is already another table or index with this name: %s", zName);
105331105617
goto exit_rename_table;
105332105618
}
105333105619
@@ -105454,10 +105740,26 @@
105454105740
exit_rename_table:
105455105741
sqlite3SrcListDelete(db, pSrc);
105456105742
sqlite3DbFree(db, zName);
105457105743
db->mDbFlags = savedDbFlags;
105458105744
}
105745
+
105746
+/*
105747
+** Write code that will raise an error if the table described by
105748
+** zDb and zTab is not empty.
105749
+*/
105750
+static void sqlite3ErrorIfNotEmpty(
105751
+ Parse *pParse, /* Parsing context */
105752
+ const char *zDb, /* Schema holding the table */
105753
+ const char *zTab, /* Table to check for empty */
105754
+ const char *zErr /* Error message text */
105755
+){
105756
+ sqlite3NestedParse(pParse,
105757
+ "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
105758
+ zErr, zDb, zTab
105759
+ );
105760
+}
105459105761
105460105762
/*
105461105763
** This function is called after an "ALTER TABLE ... ADD" statement
105462105764
** has been parsed. Argument pColDef contains the text of the new
105463105765
** column definition.
@@ -105507,11 +105809,12 @@
105507105809
if( pCol->colFlags & COLFLAG_PRIMKEY ){
105508105810
sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
105509105811
return;
105510105812
}
105511105813
if( pNew->pIndex ){
105512
- sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
105814
+ sqlite3ErrorMsg(pParse,
105815
+ "Cannot add a UNIQUE column");
105513105816
return;
105514105817
}
105515105818
if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
105516105819
/* If the default value for the new column was specified with a
105517105820
** literal NULL, then set pDflt to 0. This simplifies checking
@@ -105520,19 +105823,18 @@
105520105823
assert( pDflt==0 || pDflt->op==TK_SPAN );
105521105824
if( pDflt && pDflt->pLeft->op==TK_NULL ){
105522105825
pDflt = 0;
105523105826
}
105524105827
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
105525
- sqlite3ErrorMsg(pParse,
105828
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105526105829
"Cannot add a REFERENCES column with non-NULL default value");
105527
- return;
105528105830
}
105529105831
if( pCol->notNull && !pDflt ){
105530
- sqlite3ErrorMsg(pParse,
105832
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105531105833
"Cannot add a NOT NULL column with default value NULL");
105532
- return;
105533105834
}
105835
+
105534105836
105535105837
/* Ensure the default expression is something that sqlite3ValueFromExpr()
105536105838
** can handle (i.e. not CURRENT_TIME etc.)
105537105839
*/
105538105840
if( pDflt ){
@@ -105543,18 +105845,17 @@
105543105845
if( rc!=SQLITE_OK ){
105544105846
assert( db->mallocFailed == 1 );
105545105847
return;
105546105848
}
105547105849
if( !pVal ){
105548
- sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
105549
- return;
105850
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105851
+ "Cannot add a column with non-constant default");
105550105852
}
105551105853
sqlite3ValueFree(pVal);
105552105854
}
105553105855
}else if( pCol->colFlags & COLFLAG_STORED ){
105554
- sqlite3ErrorMsg(pParse, "cannot add a STORED column");
105555
- return;
105856
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
105556105857
}
105557105858
105558105859
105559105860
/* Modify the CREATE TABLE statement. */
105560105861
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
@@ -110055,26 +110356,43 @@
110055110356
** exists */
110056110357
if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
110057110358
return 0;
110058110359
}
110059110360
#endif
110060
- while(1){
110061
- for(i=OMIT_TEMPDB; i<db->nDb; i++){
110062
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
110063
- if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
110064
- assert( sqlite3SchemaMutexHeld(db, j, 0) );
110065
- p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
110066
- if( p ) return p;
110067
- }
110068
- }
110069
- /* Not found. If the name we were looking for was temp.sqlite_master
110070
- ** then change the name to sqlite_temp_master and try again. */
110071
- if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
110072
- if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
110073
- zName = TEMP_MASTER_NAME;
110074
- }
110075
- return 0;
110361
+ if( zDatabase ){
110362
+ for(i=0; i<db->nDb; i++){
110363
+ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
110364
+ }
110365
+ if( i>=db->nDb ){
110366
+ /* No match against the official names. But always match "main"
110367
+ ** to schema 0 as a legacy fallback. */
110368
+ if( sqlite3StrICmp(zDatabase,"main")==0 ){
110369
+ i = 0;
110370
+ }else{
110371
+ return 0;
110372
+ }
110373
+ }
110374
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
110375
+ if( p==0 && i==1 && sqlite3StrICmp(zName, MASTER_NAME)==0 ){
110376
+ /* All temp.sqlite_master to be an alias for sqlite_temp_master */
110377
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, TEMP_MASTER_NAME);
110378
+ }
110379
+ }else{
110380
+ /* Match against TEMP first */
110381
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
110382
+ if( p ) return p;
110383
+ /* The main database is second */
110384
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
110385
+ if( p ) return p;
110386
+ /* Attached databases are in order of attachment */
110387
+ for(i=2; i<db->nDb; i++){
110388
+ assert( sqlite3SchemaMutexHeld(db, i, 0) );
110389
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
110390
+ if( p ) break;
110391
+ }
110392
+ }
110393
+ return p;
110076110394
}
110077110395
110078110396
/*
110079110397
** Locate the in-memory structure that describes a particular database
110080110398
** table given the name of that table and (optionally) the name of the
@@ -111874,10 +112192,32 @@
111874112192
assert( pPk->nColumn==j );
111875112193
assert( pTab->nNVCol<=j );
111876112194
recomputeColumnsNotIndexed(pPk);
111877112195
}
111878112196
112197
+
112198
+#ifndef SQLITE_OMIT_VIRTUALTABLE
112199
+/*
112200
+** Return true if pTab is a virtual table and zName is a shadow table name
112201
+** for that virtual table.
112202
+*/
112203
+SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
112204
+ int nName; /* Length of zName */
112205
+ Module *pMod; /* Module for the virtual table */
112206
+
112207
+ if( !IsVirtual(pTab) ) return 0;
112208
+ nName = sqlite3Strlen30(pTab->zName);
112209
+ if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
112210
+ if( zName[nName]!='_' ) return 0;
112211
+ pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
112212
+ if( pMod==0 ) return 0;
112213
+ if( pMod->pModule->iVersion<3 ) return 0;
112214
+ if( pMod->pModule->xShadowName==0 ) return 0;
112215
+ return pMod->pModule->xShadowName(zName+nName+1);
112216
+}
112217
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
112218
+
111879112219
#ifndef SQLITE_OMIT_VIRTUALTABLE
111880112220
/*
111881112221
** Return true if zName is a shadow table name in the current database
111882112222
** connection.
111883112223
**
@@ -111885,26 +112225,21 @@
111885112225
** restored to its original value prior to this routine returning.
111886112226
*/
111887112227
SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
111888112228
char *zTail; /* Pointer to the last "_" in zName */
111889112229
Table *pTab; /* Table that zName is a shadow of */
111890
- Module *pMod; /* Module for the virtual table */
111891
-
111892112230
zTail = strrchr(zName, '_');
111893112231
if( zTail==0 ) return 0;
111894112232
*zTail = 0;
111895112233
pTab = sqlite3FindTable(db, zName, 0);
111896112234
*zTail = '_';
111897112235
if( pTab==0 ) return 0;
111898112236
if( !IsVirtual(pTab) ) return 0;
111899
- pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
111900
- if( pMod==0 ) return 0;
111901
- if( pMod->pModule->iVersion<3 ) return 0;
111902
- if( pMod->pModule->xShadowName==0 ) return 0;
111903
- return pMod->pModule->xShadowName(zTail+1);
112237
+ return sqlite3IsShadowTableOf(db, pTab, zName);
111904112238
}
111905112239
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
112240
+
111906112241
111907112242
#ifdef SQLITE_DEBUG
111908112243
/*
111909112244
** Mark all nodes of an expression as EP_Immutable, indicating that
111910112245
** they should not be changed. Expressions attached to a table or
@@ -114373,11 +114708,11 @@
114373114708
pParse->rc = rc;
114374114709
return 1;
114375114710
}
114376114711
db->aDb[1].pBt = pBt;
114377114712
assert( db->aDb[1].pSchema );
114378
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
114713
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
114379114714
sqlite3OomFault(db);
114380114715
return 1;
114381114716
}
114382114717
}
114383114718
return 0;
@@ -114484,11 +114819,11 @@
114484114819
char *p4, /* Error message */
114485114820
i8 p4type, /* P4_STATIC or P4_TRANSIENT */
114486114821
u8 p5Errmsg /* P5_ErrMsg type */
114487114822
){
114488114823
Vdbe *v = sqlite3GetVdbe(pParse);
114489
- assert( (errCode&0xff)==SQLITE_CONSTRAINT );
114824
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
114490114825
if( onError==OE_Abort ){
114491114826
sqlite3MayAbort(pParse);
114492114827
}
114493114828
sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
114494114829
sqlite3VdbeChangeP5(v, p5Errmsg);
@@ -116197,10 +116532,11 @@
116197116532
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
116198116533
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
116199116534
&iPartIdxLabel, pPrior, r1);
116200116535
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
116201116536
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
116537
+ sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
116202116538
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
116203116539
pPrior = pIdx;
116204116540
}
116205116541
}
116206116542
@@ -117590,11 +117926,11 @@
117590117926
if( (cntExpand&(cntExpand-1))==0 ){
117591117927
/* Grow the size of the output buffer only on substitutions
117592117928
** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
117593117929
u8 *zOld;
117594117930
zOld = zOut;
117595
- zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
117931
+ zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
117596117932
if( zOut==0 ){
117597117933
sqlite3_result_error_nomem(context);
117598117934
sqlite3_free(zOld);
117599117935
return;
117600117936
}
@@ -118287,11 +118623,11 @@
118287118623
FUNCTION(round, 2, 0, 0, roundFunc ),
118288118624
#endif
118289118625
FUNCTION(upper, 1, 0, 0, upperFunc ),
118290118626
FUNCTION(lower, 1, 0, 0, lowerFunc ),
118291118627
FUNCTION(hex, 1, 0, 0, hexFunc ),
118292
- INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
118628
+ INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
118293118629
VFUNCTION(random, 0, 0, 0, randomFunc ),
118294118630
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
118295118631
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
118296118632
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
118297118633
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
@@ -118327,11 +118663,12 @@
118327118663
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
118328118664
FUNCTION(unknown, -1, 0, 0, unknownFunc ),
118329118665
#endif
118330118666
FUNCTION(coalesce, 1, 0, 0, 0 ),
118331118667
FUNCTION(coalesce, 0, 0, 0, 0 ),
118332
- INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
118668
+ INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
118669
+ INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
118333118670
};
118334118671
#ifndef SQLITE_OMIT_ALTERTABLE
118335118672
sqlite3AlterFunctions();
118336118673
#endif
118337118674
sqlite3WindowFunctions();
@@ -121752,11 +122089,11 @@
121752122089
}
121753122090
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
121754122091
sqlite3TableAffinity(v, pTab, regNewData+1);
121755122092
bAffinityDone = 1;
121756122093
}
121757
- VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
122094
+ VdbeNoopComment((v, "prep index %s", pIdx->zName));
121758122095
iThisCur = iIdxCur+ix;
121759122096
121760122097
121761122098
/* Skip partial indices for which the WHERE clause is not true */
121762122099
if( pIdx->pPartIdxWhere ){
@@ -125555,11 +125892,11 @@
125555125892
}else{
125556125893
/* Malloc may fail when setting the page-size, as there is an internal
125557125894
** buffer that the pager module resizes using sqlite3_realloc().
125558125895
*/
125559125896
db->nextPagesize = sqlite3Atoi(zRight);
125560
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
125897
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
125561125898
sqlite3OomFault(db);
125562125899
}
125563125900
}
125564125901
break;
125565125902
}
@@ -133724,33 +134061,10 @@
133724134061
}
133725134062
}
133726134063
return WRC_Continue;
133727134064
}
133728134065
133729
-/*
133730
-** No-op routine for the parse-tree walker.
133731
-**
133732
-** When this routine is the Walker.xExprCallback then expression trees
133733
-** are walked without any actions being taken at each node. Presumably,
133734
-** when this routine is used for Walker.xExprCallback then
133735
-** Walker.xSelectCallback is set to do something useful for every
133736
-** subquery in the parser tree.
133737
-*/
133738
-SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
133739
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
133740
- return WRC_Continue;
133741
-}
133742
-
133743
-/*
133744
-** No-op routine for the parse-tree walker for SELECT statements.
133745
-** subquery in the parser tree.
133746
-*/
133747
-SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
133748
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
133749
- return WRC_Continue;
133750
-}
133751
-
133752134066
#if SQLITE_DEBUG
133753134067
/*
133754134068
** Always assert. This xSelectCallback2 implementation proves that the
133755134069
** xSelectCallback2 is never invoked.
133756134070
*/
@@ -134917,11 +135231,11 @@
134917135231
sAggInfo.mxReg = pParse->nMem;
134918135232
if( db->mallocFailed ) goto select_end;
134919135233
#if SELECTTRACE_ENABLED
134920135234
if( sqlite3SelectTrace & 0x400 ){
134921135235
int ii;
134922
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
135236
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", &sAggInfo));
134923135237
sqlite3TreeViewSelect(0, p, 0);
134924135238
for(ii=0; ii<sAggInfo.nColumn; ii++){
134925135239
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
134926135240
ii, sAggInfo.aCol[ii].iMem);
134927135241
sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
@@ -135193,17 +135507,19 @@
135193135507
**
135194135508
** In practice the KeyInfo structure will not be used. It is only
135195135509
** passed to keep OP_OpenRead happy.
135196135510
*/
135197135511
if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
135198
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
135199
- if( pIdx->bUnordered==0
135200
- && pIdx->szIdxRow<pTab->szTabRow
135201
- && pIdx->pPartIdxWhere==0
135202
- && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
135203
- ){
135204
- pBest = pIdx;
135512
+ if( !p->pSrc->a[0].fg.notIndexed ){
135513
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
135514
+ if( pIdx->bUnordered==0
135515
+ && pIdx->szIdxRow<pTab->szTabRow
135516
+ && pIdx->pPartIdxWhere==0
135517
+ && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
135518
+ ){
135519
+ pBest = pIdx;
135520
+ }
135205135521
}
135206135522
}
135207135523
if( pBest ){
135208135524
iRoot = pBest->tnum;
135209135525
pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
@@ -135378,11 +135694,11 @@
135378135694
need = nCol;
135379135695
}
135380135696
if( p->nData + need > p->nAlloc ){
135381135697
char **azNew;
135382135698
p->nAlloc = p->nAlloc*2 + need;
135383
- azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
135699
+ azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
135384135700
if( azNew==0 ) goto malloc_failed;
135385135701
p->azResult = azNew;
135386135702
}
135387135703
135388135704
/* If this is the first row, then generate an extra row containing
@@ -135487,11 +135803,11 @@
135487135803
sqlite3_free_table(&res.azResult[1]);
135488135804
return rc;
135489135805
}
135490135806
if( res.nAlloc>res.nData ){
135491135807
char **azNew;
135492
- azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
135808
+ azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
135493135809
if( azNew==0 ){
135494135810
sqlite3_free_table(&res.azResult[1]);
135495135811
db->errCode = SQLITE_NOMEM;
135496135812
return SQLITE_NOMEM_BKPT;
135497135813
}
@@ -136777,14 +137093,14 @@
136777137093
** Therefore, the P4 parameter is only required if the default value for
136778137094
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
136779137095
** function is capable of transforming these types of expressions into
136780137096
** sqlite3_value objects.
136781137097
**
136782
-** If parameter iReg is not negative, code an OP_RealAffinity instruction
136783
-** on register iReg. This is used when an equivalent integer value is
136784
-** stored in place of an 8-byte floating point value in order to save
136785
-** space.
137098
+** If column as REAL affinity and the table is an ordinary b-tree table
137099
+** (not a virtual table) then the value might have been stored as an
137100
+** integer. In that case, add an OP_RealAffinity opcode to make sure
137101
+** it has been converted into REAL.
136786137102
*/
136787137103
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
136788137104
assert( pTab!=0 );
136789137105
if( !pTab->pSelect ){
136790137106
sqlite3_value *pValue = 0;
@@ -136797,11 +137113,11 @@
136797137113
if( pValue ){
136798137114
sqlite3VdbeAppendP4(v, pValue, P4_MEM);
136799137115
}
136800137116
}
136801137117
#ifndef SQLITE_OMIT_FLOATING_POINT
136802
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
137118
+ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
136803137119
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
136804137120
}
136805137121
#endif
136806137122
}
136807137123
@@ -138439,11 +138755,11 @@
138439138755
db->mDbFlags = saved_mDbFlags;
138440138756
db->flags = saved_flags;
138441138757
db->nChange = saved_nChange;
138442138758
db->nTotalChange = saved_nTotalChange;
138443138759
db->mTrace = saved_mTrace;
138444
- sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
138760
+ sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
138445138761
138446138762
/* Currently there is an SQL level transaction open on the vacuum
138447138763
** database. No locks are held on any other files (since the main file
138448138764
** was committed at the btree level). So it safe to end the transaction
138449138765
** by manually setting the autoCommit flag to true and detaching the
@@ -139646,11 +139962,11 @@
139646139962
assert( IsVirtual(pTab) );
139647139963
for(i=0; i<pToplevel->nVtabLock; i++){
139648139964
if( pTab==pToplevel->apVtabLock[i] ) return;
139649139965
}
139650139966
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
139651
- apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
139967
+ apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n);
139652139968
if( apVtabLock ){
139653139969
pToplevel->apVtabLock = apVtabLock;
139654139970
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
139655139971
}else{
139656139972
sqlite3OomFault(pToplevel->db);
@@ -150938,24 +151254,47 @@
150938151254
){
150939151255
if( pAppend ){
150940151256
int i;
150941151257
int nInit = pList ? pList->nExpr : 0;
150942151258
for(i=0; i<pAppend->nExpr; i++){
150943
- int iDummy;
150944151259
Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
150945151260
assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
150946
- if( bIntToNull && pDup && sqlite3ExprIsInteger(pDup, &iDummy) ){
150947
- pDup->op = TK_NULL;
150948
- pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
150949
- pDup->u.zToken = 0;
151261
+ if( bIntToNull && pDup ){
151262
+ int iDummy;
151263
+ Expr *pSub;
151264
+ for(pSub=pDup; ExprHasProperty(pSub, EP_Skip); pSub=pSub->pLeft){
151265
+ assert( pSub );
151266
+ }
151267
+ if( sqlite3ExprIsInteger(pSub, &iDummy) ){
151268
+ pSub->op = TK_NULL;
151269
+ pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
151270
+ pSub->u.zToken = 0;
151271
+ }
150950151272
}
150951151273
pList = sqlite3ExprListAppend(pParse, pList, pDup);
150952151274
if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
150953151275
}
150954151276
}
150955151277
return pList;
150956151278
}
151279
+
151280
+/*
151281
+** When rewriting a query, if the new subquery in the FROM clause
151282
+** contains TK_AGG_FUNCTION nodes that refer to an outer query,
151283
+** then we have to increase the Expr->op2 values of those nodes
151284
+** due to the extra subquery layer that was added.
151285
+**
151286
+** See also the incrAggDepth() routine in resolve.c
151287
+*/
151288
+static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){
151289
+ if( pExpr->op==TK_AGG_FUNCTION
151290
+ && pExpr->op2>=pWalker->walkerDepth
151291
+ ){
151292
+ pExpr->op2++;
151293
+ }
151294
+ return WRC_Continue;
151295
+}
150957151296
150958151297
/*
150959151298
** If the SELECT statement passed as the second argument does not invoke
150960151299
** any SQL window functions, this function is a no-op. Otherwise, it
150961151300
** rewrites the SELECT statement so that window function xStep functions
@@ -151062,10 +151401,11 @@
151062151401
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
151063151402
);
151064151403
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
151065151404
if( p->pSrc ){
151066151405
Table *pTab2;
151406
+ Walker w;
151067151407
p->pSrc->a[0].pSelect = pSub;
151068151408
sqlite3SrcListAssignCursors(pParse, p->pSrc);
151069151409
pSub->selFlags |= SF_Expanded;
151070151410
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
151071151411
pSub->selFlags |= (selFlags & SF_Aggregate);
@@ -151077,10 +151417,15 @@
151077151417
}else{
151078151418
memcpy(pTab, pTab2, sizeof(Table));
151079151419
pTab->tabFlags |= TF_Ephemeral;
151080151420
p->pSrc->a[0].pTab = pTab;
151081151421
pTab = pTab2;
151422
+ memset(&w, 0, sizeof(w));
151423
+ w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
151424
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
151425
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
151426
+ sqlite3WalkSelect(&w, pSub);
151082151427
}
151083151428
}else{
151084151429
sqlite3SelectDelete(db, pSub);
151085151430
}
151086151431
if( db->mallocFailed ) rc = SQLITE_NOMEM;
@@ -160130,10 +160475,11 @@
160130160475
}
160131160476
#endif
160132160477
if( rc==SQLITE_OK ){
160133160478
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
160134160479
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
160480
+ sqlite3MemoryBarrier();
160135160481
sqlite3GlobalConfig.isInit = 1;
160136160482
#ifdef SQLITE_EXTRA_INIT
160137160483
bRunExtraInit = 1;
160138160484
#endif
160139160485
}
@@ -161431,12 +161777,11 @@
161431161777
** Return non-zero to retry the lock. Return zero to stop trying
161432161778
** and cause SQLite to return SQLITE_BUSY.
161433161779
*/
161434161780
static int sqliteDefaultBusyCallback(
161435161781
void *ptr, /* Database connection */
161436
- int count, /* Number of times table has been busy */
161437
- sqlite3_file *pFile /* The file on which the lock occurred */
161782
+ int count /* Number of times table has been busy */
161438161783
){
161439161784
#if SQLITE_OS_WIN || HAVE_USLEEP
161440161785
/* This case is for systems that have support for sleeping for fractions of
161441161786
** a second. Examples: All windows systems, unix systems with usleep() */
161442161787
static const u8 delays[] =
@@ -161446,35 +161791,10 @@
161446161791
# define NDELAY ArraySize(delays)
161447161792
sqlite3 *db = (sqlite3 *)ptr;
161448161793
int tmout = db->busyTimeout;
161449161794
int delay, prior;
161450161795
161451
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
161452
- if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
161453
- if( count ){
161454
- /* If this is the second or later invocation of the busy-handler,
161455
- ** but tmout==0, then code in wal.c must have disabled the blocking
161456
- ** lock before the SQLITE_BUSY error was hit. In this case, no delay
161457
- ** occurred while waiting for the lock, so fall through to the xSleep()
161458
- ** code below to delay a while before retrying the lock.
161459
- **
161460
- ** Alternatively, if tmout!=0, then SQLite has already waited
161461
- ** sqlite3.busyTimeout ms for a lock. In this case, return 0 to
161462
- ** indicate that the lock should not be retried and the SQLITE_BUSY
161463
- ** error returned to the application. */
161464
- if( tmout ){
161465
- tmout = 0;
161466
- sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
161467
- return 0;
161468
- }
161469
- }else{
161470
- return 1;
161471
- }
161472
- }
161473
-#else
161474
- UNUSED_PARAMETER(pFile);
161475
-#endif
161476161796
assert( count>=0 );
161477161797
if( count < NDELAY ){
161478161798
delay = delays[count];
161479161799
prior = totals[count];
161480161800
}else{
@@ -161490,11 +161810,10 @@
161490161810
#else
161491161811
/* This case for unix systems that lack usleep() support. Sleeping
161492161812
** must be done in increments of whole seconds */
161493161813
sqlite3 *db = (sqlite3 *)ptr;
161494161814
int tmout = ((sqlite3 *)ptr)->busyTimeout;
161495
- UNUSED_PARAMETER(pFile);
161496161815
if( (count+1)*1000 > tmout ){
161497161816
return 0;
161498161817
}
161499161818
sqlite3OsSleep(db->pVfs, 1000000);
161500161819
return 1;
@@ -161508,23 +161827,14 @@
161508161827
** lock on VFS file pFile.
161509161828
**
161510161829
** If this routine returns non-zero, the lock is retried. If it
161511161830
** returns 0, the operation aborts with an SQLITE_BUSY error.
161512161831
*/
161513
-SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
161832
+SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
161514161833
int rc;
161515161834
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
161516
- if( p->bExtraFileArg ){
161517
- /* Add an extra parameter with the pFile pointer to the end of the
161518
- ** callback argument list */
161519
- int (*xTra)(void*,int,sqlite3_file*);
161520
- xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
161521
- rc = xTra(p->pBusyArg, p->nBusy, pFile);
161522
- }else{
161523
- /* Legacy style busy handler callback */
161524
- rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
161525
- }
161835
+ rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
161526161836
if( rc==0 ){
161527161837
p->nBusy = -1;
161528161838
}else{
161529161839
p->nBusy++;
161530161840
}
@@ -161545,11 +161855,10 @@
161545161855
#endif
161546161856
sqlite3_mutex_enter(db->mutex);
161547161857
db->busyHandler.xBusyHandler = xBusy;
161548161858
db->busyHandler.pBusyArg = pArg;
161549161859
db->busyHandler.nBusy = 0;
161550
- db->busyHandler.bExtraFileArg = 0;
161551161860
db->busyTimeout = 0;
161552161861
sqlite3_mutex_leave(db->mutex);
161553161862
return SQLITE_OK;
161554161863
}
161555161864
@@ -161596,11 +161905,10 @@
161596161905
#endif
161597161906
if( ms>0 ){
161598161907
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
161599161908
(void*)db);
161600161909
db->busyTimeout = ms;
161601
- db->busyHandler.bExtraFileArg = 1;
161602161910
}else{
161603161911
sqlite3_busy_handler(db, 0, 0);
161604161912
}
161605161913
return SQLITE_OK;
161606161914
}
@@ -163071,10 +163379,13 @@
163071163379
| SQLITE_EnableQPSG
163072163380
#endif
163073163381
#if defined(SQLITE_DEFAULT_DEFENSIVE)
163074163382
| SQLITE_Defensive
163075163383
#endif
163384
+#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
163385
+ | SQLITE_LegacyAlter
163386
+#endif
163076163387
;
163077163388
sqlite3HashInit(&db->aCollSeq);
163078163389
#ifndef SQLITE_OMIT_VIRTUALTABLE
163079163390
sqlite3HashInit(&db->aModule);
163080163391
#endif
@@ -163113,11 +163424,11 @@
163113163424
assert( SQLITE_OPEN_CREATE == 0x04 );
163114163425
testcase( (1<<(flags&7))==0x02 ); /* READONLY */
163115163426
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
163116163427
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
163117163428
if( ((1<<(flags&7)) & 0x46)==0 ){
163118
- rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
163429
+ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
163119163430
}else{
163120163431
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
163121163432
}
163122163433
if( rc!=SQLITE_OK ){
163123163434
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
@@ -163668,11 +163979,11 @@
163668163979
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
163669163980
rc = SQLITE_OK;
163670163981
}else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
163671163982
int iNew = *(int*)pArg;
163672163983
*(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
163673
- if( iNew>=0 && iNew<=254 ){
163984
+ if( iNew>=0 && iNew<=255 ){
163674163985
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
163675163986
}
163676163987
rc = SQLITE_OK;
163677163988
}else{
163678163989
rc = sqlite3OsFileControl(fd, op, pArg);
@@ -167905,11 +168216,13 @@
167905168216
static void fts3ReadNextPos(
167906168217
char **pp, /* IN/OUT: Pointer into position-list buffer */
167907168218
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
167908168219
){
167909168220
if( (**pp)&0xFE ){
167910
- fts3GetDeltaVarint(pp, pi);
168221
+ int iVal;
168222
+ *pp += fts3GetVarint32((*pp), &iVal);
168223
+ *pi += iVal;
167911168224
*pi -= 2;
167912168225
}else{
167913168226
*pi = POSITION_LIST_END;
167914168227
}
167915168228
}
@@ -171035,10 +171348,11 @@
171035171348
while( *pRc==SQLITE_OK && pLeft->bEof==0 ){
171036171349
memset(pDl->pList, 0, pDl->nList);
171037171350
fts3EvalNextRow(pCsr, pLeft, pRc);
171038171351
}
171039171352
}
171353
+ pRight->bEof = pLeft->bEof = 1;
171040171354
}
171041171355
}
171042171356
break;
171043171357
}
171044171358
@@ -182580,11 +182894,11 @@
182580182894
iStart = pExpr->iPhrase * p->nCol;
182581182895
}else{
182582182896
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
182583182897
}
182584182898
182585
- while( 1 ){
182899
+ if( pIter ) while( 1 ){
182586182900
int nHit = fts3ColumnlistCount(&pIter);
182587182901
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
182588182902
if( p->flag==FTS3_MATCHINFO_LHITS ){
182589182903
p->aMatchinfo[iStart + iCol] = (u32)nHit;
182590182904
}else if( nHit ){
@@ -184494,10 +184808,11 @@
184494184808
}
184495184809
184496184810
/* Append N bytes from zIn onto the end of the JsonString string.
184497184811
*/
184498184812
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
184813
+ if( N==0 ) return;
184499184814
if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
184500184815
memcpy(p->zBuf+p->nUsed, zIn, N);
184501184816
p->nUsed += N;
184502184817
}
184503184818
@@ -224505,11 +224820,11 @@
224505224820
int nArg, /* Number of args */
224506224821
sqlite3_value **apUnused /* Function arguments */
224507224822
){
224508224823
assert( nArg==0 );
224509224824
UNUSED_PARAM2(nArg, apUnused);
224510
- sqlite3_result_text(pCtx, "fts5: 2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda", -1, SQLITE_TRANSIENT);
224825
+ sqlite3_result_text(pCtx, "fts5: 2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350", -1, SQLITE_TRANSIENT);
224511224826
}
224512224827
224513224828
/*
224514224829
** Return true if zName is the extension on one of the shadow tables used
224515224830
** by this module.
@@ -229288,12 +229603,12 @@
229288229603
}
229289229604
#endif /* SQLITE_CORE */
229290229605
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
229291229606
229292229607
/************** End of stmt.c ************************************************/
229293
-#if __LINE__!=229293
229608
+#if __LINE__!=229608
229294229609
#undef SQLITE_SOURCE_ID
229295
-#define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb21alt2"
229610
+#define SQLITE_SOURCE_ID "2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba8alt2"
229296229611
#endif
229297229612
/* Return the source-id for this library */
229298229613
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
229299229614
/************************** End of sqlite3.c ******************************/
229300229615
--- 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.32.0. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -1160,13 +1160,13 @@
1160 **
1161 ** See also: [sqlite3_libversion()],
1162 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1163 ** [sqlite_version()] and [sqlite_source_id()].
1164 */
1165 #define SQLITE_VERSION "3.32.0"
1166 #define SQLITE_VERSION_NUMBER 3032000
1167 #define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda"
1168
1169 /*
1170 ** CAPI3REF: Run-Time Library Version Numbers
1171 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1172 **
@@ -1545,18 +1545,20 @@
1545 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
1546 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
1547 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
1548 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
1549 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
 
1550 #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
1551 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
1552 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
1553 #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
1554 #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
1555 #define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
1556 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
1557 #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
 
1558 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
1559 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
1560 #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
1561 #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
1562 #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
@@ -6530,11 +6532,11 @@
6530 ** when first called if N is less than or equal to zero or if a memory
6531 ** allocate error occurs.
6532 **
6533 ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
6534 ** determined by the N parameter on first successful call. Changing the
6535 ** value of N in any subsequents call to sqlite3_aggregate_context() within
6536 ** the same aggregate function instance will not resize the memory
6537 ** allocation.)^ Within the xFinal callback, it is customary to set
6538 ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
6539 ** pointless memory allocations occur.
6540 **
@@ -14535,11 +14537,10 @@
14535 typedef struct BusyHandler BusyHandler;
14536 struct BusyHandler {
14537 int (*xBusyHandler)(void *,int); /* The busy callback */
14538 void *pBusyArg; /* First arg to busy callback */
14539 int nBusy; /* Incremented with each busy call */
14540 u8 bExtraFileArg; /* Include sqlite3_file as callback arg */
14541 };
14542
14543 /*
14544 ** Name of the master database table. The master database table
14545 ** is a special table that holds the names and attributes of all
@@ -15918,17 +15919,25 @@
15918 SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
15919 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
15920 SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
15921 SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
15922 # ifdef SQLITE_ENABLE_SNAPSHOT
15923 SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
15924 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
15925 SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
15926 SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
15927 SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
15928 # endif
15929 #endif
 
 
 
 
 
 
 
 
15930
15931 #ifdef SQLITE_DIRECT_OVERFLOW_READ
15932 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
15933 #endif
15934
@@ -15951,15 +15960,10 @@
15951 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
15952 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
15953 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
15954 SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
15955 SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
15956 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
15957 SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager);
15958 #else
15959 # define sqlite3PagerResetLockTimeout(X)
15960 #endif
15961
15962 /* Functions used to truncate the database file. */
15963 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
15964
15965 SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
@@ -17115,11 +17119,11 @@
17115 #define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */
17116 #define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
17117 #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
17118 #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
17119 #define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
17120 #define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
17121 #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
17122 #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
17123 #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
17124 #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
17125 ** single query - might change over time */
@@ -17136,10 +17140,11 @@
17136 #define INLINEFUNC_coalesce 0
17137 #define INLINEFUNC_implies_nonnull_row 1
17138 #define INLINEFUNC_expr_implies_expr 2
17139 #define INLINEFUNC_expr_compare 3
17140 #define INLINEFUNC_affinity 4
 
17141 #define INLINEFUNC_unlikely 99 /* Default case */
17142
17143 /*
17144 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
17145 ** used to create the initializers for the FuncDef structures.
@@ -17836,11 +17841,11 @@
17836 /*
17837 ** An instance of this structure contains information needed to generate
17838 ** code for a SELECT that contains aggregate functions.
17839 **
17840 ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
17841 ** pointer to this structure. The Expr.iColumn field is the index in
17842 ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
17843 ** code for that node.
17844 **
17845 ** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the
17846 ** original Select structure that describes the SELECT statement. These
@@ -19075,10 +19080,13 @@
19075 SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
19076 SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
19077 SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
19078 SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
19079 SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
 
 
 
19080 #ifdef SQLITE_DEBUG
19081 SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
19082 #endif
19083
19084 /*
@@ -19935,11 +19943,11 @@
19935 SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
19936 SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
19937 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
19938 SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
19939 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
19940 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
19941 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
19942 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
19943 SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
19944 SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
19945 SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
@@ -20060,12 +20068,14 @@
20060 # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
20061 #endif
20062 SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db);
20063 #ifndef SQLITE_OMIT_VIRTUALTABLE
20064 SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
 
20065 #else
20066 # define sqlite3ShadowTableName(A,B) 0
 
20067 #endif
20068 SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
20069 SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
20070 SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
20071 SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
@@ -27730,14 +27740,16 @@
27730 if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
27731 mem0.alarmThreshold-nDiff ){
27732 sqlite3MallocAlarm(nDiff);
27733 }
27734 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
 
27735 if( pNew==0 && mem0.alarmThreshold>0 ){
27736 sqlite3MallocAlarm((int)nBytes);
27737 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27738 }
 
27739 if( pNew ){
27740 nNew = sqlite3MallocSize(pNew);
27741 sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
27742 }
27743 sqlite3_mutex_leave(mem0.mutex);
@@ -27918,11 +27930,11 @@
27918 }
27919 }else{
27920 assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
27921 assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
27922 sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
27923 pNew = sqlite3_realloc64(p, n);
27924 if( !pNew ){
27925 sqlite3OomFault(db);
27926 }
27927 sqlite3MemdebugSetType(pNew,
27928 (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
@@ -28265,10 +28277,17 @@
28265 #ifndef SQLITE_PRINT_BUF_SIZE
28266 # define SQLITE_PRINT_BUF_SIZE 70
28267 #endif
28268 #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
28269
 
 
 
 
 
 
 
28270 /*
28271 ** Render a string given by "fmt" into the StrAccum object.
28272 */
28273 SQLITE_API void sqlite3_str_vappendf(
28274 sqlite3_str *pAccum, /* Accumulate results here */
@@ -28465,10 +28484,12 @@
28465 ** precision The specified precision. The default
28466 ** is -1.
28467 ** xtype The class of the conversion.
28468 ** infop Pointer to the appropriate info struct.
28469 */
 
 
28470 switch( xtype ){
28471 case etPOINTER:
28472 flag_long = sizeof(char*)==sizeof(i64) ? 2 :
28473 sizeof(char*)==sizeof(long int) ? 1 : 0;
28474 /* Fall through into the next case */
@@ -28586,10 +28607,15 @@
28586 }
28587 #ifdef SQLITE_OMIT_FLOATING_POINT
28588 length = 0;
28589 #else
28590 if( precision<0 ) precision = 6; /* Set default precision */
 
 
 
 
 
28591 if( realvalue<0.0 ){
28592 realvalue = -realvalue;
28593 prefix = '-';
28594 }else{
28595 prefix = flag_prefix;
@@ -28868,11 +28894,11 @@
28868 }else{
28869 escarg = va_arg(ap,char*);
28870 }
28871 isnull = escarg==0;
28872 if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
28873 /* For %q, %Q, and %w, the precision is the number of byte (or
28874 ** characters if the ! flags is present) to use from the input.
28875 ** Because of the extra quoting characters inserted, the number
28876 ** of output characters may be larger than the precision.
28877 */
28878 k = precision;
@@ -28995,11 +29021,11 @@
28995 p->nAlloc = (int)szNew;
28996 }
28997 if( p->db ){
28998 zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
28999 }else{
29000 zNew = sqlite3_realloc64(zOld, p->nAlloc);
29001 }
29002 if( zNew ){
29003 assert( p->zText!=0 || p->nChar==0 );
29004 if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
29005 p->zText = zNew;
@@ -29337,11 +29363,11 @@
29337 ** and segfaults if you give it a long long int.
29338 */
29339 SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
29340 va_list ap;
29341 StrAccum acc;
29342 char zBuf[500];
29343 sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
29344 va_start(ap,zFormat);
29345 sqlite3_str_vappendf(&acc, zFormat, ap);
29346 va_end(ap);
29347 sqlite3StrAccumFinish(&acc);
@@ -29953,12 +29979,13 @@
29953 #else
29954 pWin = 0;
29955 #endif
29956 }
29957 if( pExpr->op==TK_AGG_FUNCTION ){
29958 sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
29959 pExpr->op2, pExpr->u.zToken, zFlgs);
 
29960 }else if( pExpr->op2!=0 ){
29961 const char *zOp2;
29962 char zBuf[8];
29963 sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2);
29964 zOp2 = zBuf;
@@ -30847,10 +30874,11 @@
30847 /* UTF-16 Little-endian -> UTF-8 */
30848 while( zIn<zTerm ){
30849 c = *(zIn++);
30850 c += (*(zIn++))<<8;
30851 if( c>=0xd800 && c<0xe000 ){
 
30852 if( c>=0xdc00 || zIn>=zTerm ){
30853 c = 0xfffd;
30854 }else{
30855 int c2 = *(zIn++);
30856 c2 += (*(zIn++))<<8;
@@ -30859,19 +30887,27 @@
30859 c = 0xfffd;
30860 }else{
30861 c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
30862 }
30863 }
 
 
 
 
 
 
 
30864 }
30865 WRITE_UTF8(z, c);
30866 }
30867 }else{
30868 /* UTF-16 Big-endian -> UTF-8 */
30869 while( zIn<zTerm ){
30870 c = (*(zIn++))<<8;
30871 c += *(zIn++);
30872 if( c>=0xd800 && c<0xe000 ){
 
30873 if( c>=0xdc00 || zIn>=zTerm ){
30874 c = 0xfffd;
30875 }else{
30876 int c2 = (*(zIn++))<<8;
30877 c2 += *(zIn++);
@@ -30880,10 +30916,17 @@
30880 c = 0xfffd;
30881 }else{
30882 c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
30883 }
30884 }
 
 
 
 
 
 
 
30885 }
30886 WRITE_UTF8(z, c);
30887 }
30888 }
30889 pMem->n = (int)(z - zOut);
@@ -34971,20 +35014,21 @@
34971 static int osSetPosixAdvisoryLock(
34972 int h, /* The file descriptor on which to take the lock */
34973 struct flock *pLock, /* The description of the lock */
34974 unixFile *pFile /* Structure holding timeout value */
34975 ){
 
34976 int rc = osFcntl(h,F_SETLK,pLock);
34977 while( rc<0 && pFile->iBusyTimeout>0 ){
34978 /* On systems that support some kind of blocking file lock with a timeout,
34979 ** make appropriate changes here to invoke that blocking file lock. On
34980 ** generic posix, however, there is no such API. So we simply try the
34981 ** lock once every millisecond until either the timeout expires, or until
34982 ** the lock is obtained. */
34983 usleep(1000);
34984 rc = osFcntl(h,F_SETLK,pLock);
34985 pFile->iBusyTimeout--;
34986 }
34987 return rc;
34988 }
34989 #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
34990
@@ -37722,17 +37766,24 @@
37722
37723 /* Locks are within range */
37724 assert( n>=1 && n<=SQLITE_SHM_NLOCK );
37725
37726 if( pShmNode->hShm>=0 ){
 
37727 /* Initialize the locking parameters */
37728 f.l_type = lockType;
37729 f.l_whence = SEEK_SET;
37730 f.l_start = ofst;
37731 f.l_len = n;
37732 rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37733 rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
 
 
 
 
 
 
37734 }
37735
37736 /* Update the global lock state and do debug tracing */
37737 #ifdef SQLITE_DEBUG
37738 { u16 mask;
@@ -38225,26 +38276,27 @@
38225 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
38226 assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
38227 assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
38228 assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
38229
38230 /* Check that, if this to be a blocking lock, that locks have been
38231 ** obtained in the following order.
38232 **
38233 ** 1. Checkpointer lock (ofst==1).
38234 ** 2. Recover lock (ofst==2).
38235 ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
38236 ** 4. Write lock (ofst==0).
38237 **
38238 ** In other words, if this is a blocking lock, none of the locks that
38239 ** occur later in the above list than the lock being obtained may be
38240 ** held. */
38241 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
38242 assert( pDbFd->iBusyTimeout==0
38243 || (flags & SQLITE_SHM_UNLOCK) || ofst==0
38244 || ((p->exclMask|p->sharedMask)&~((1<<ofst)-2))==0
38245 );
 
 
38246 #endif
38247
38248 mask = (1<<(ofst+n)) - (1<<ofst);
38249 assert( n>1 || mask==(1<<ofst) );
38250 sqlite3_mutex_enter(pShmNode->pShmMutex);
@@ -45033,10 +45085,11 @@
45033 }
45034
45035 /* Forward references to VFS helper methods used for temporary files */
45036 static int winGetTempname(sqlite3_vfs *, char **);
45037 static int winIsDir(const void *);
 
45038 static BOOL winIsDriveLetterAndColon(const char *);
45039
45040 /*
45041 ** Control and query of the open file handle.
45042 */
@@ -46802,11 +46855,13 @@
46802 pFile->pVfs = pVfs;
46803 pFile->h = h;
46804 if( isReadonly ){
46805 pFile->ctrlFlags |= WINFILE_RDONLY;
46806 }
46807 if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
 
 
46808 pFile->ctrlFlags |= WINFILE_PSOW;
46809 }
46810 pFile->lastErrno = NO_ERROR;
46811 pFile->zPath = zName;
46812 #if SQLITE_MAX_MMAP_SIZE>0
@@ -47011,10 +47066,21 @@
47011 *pResOut = rc;
47012 OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
47013 zFilename, pResOut, *pResOut));
47014 return SQLITE_OK;
47015 }
 
 
 
 
 
 
 
 
 
 
 
47016
47017 /*
47018 ** Returns non-zero if the specified path name starts with a drive letter
47019 ** followed by a colon character.
47020 */
@@ -47076,14 +47142,15 @@
47076 DWORD nByte;
47077 void *zConverted;
47078 char *zOut;
47079 #endif
47080
47081 /* If this path name begins with "/X:", where "X" is any alphabetic
47082 ** character, discard the initial "/" from the pathname.
47083 */
47084 if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
 
47085 zRelative++;
47086 }
47087
47088 #if defined(__CYGWIN__)
47089 SimulateIOError( return SQLITE_ERROR );
@@ -47835,11 +47902,11 @@
47835 if( newSz>p->szMax ){
47836 return SQLITE_FULL;
47837 }
47838 newSz *= 2;
47839 if( newSz>p->szMax ) newSz = p->szMax;
47840 pNew = sqlite3_realloc64(p->aData, newSz);
47841 if( pNew==0 ) return SQLITE_NOMEM;
47842 p->aData = pNew;
47843 p->szAlloc = newSz;
47844 return SQLITE_OK;
47845 }
@@ -48282,14 +48349,15 @@
48282 */
48283 SQLITE_PRIVATE int sqlite3MemdbInit(void){
48284 sqlite3_vfs *pLower = sqlite3_vfs_find(0);
48285 int sz = pLower->szOsFile;
48286 memdb_vfs.pAppData = pLower;
48287 /* In all known configurations of SQLite, the size of a default
48288 ** sqlite3_file is greater than the size of a memdb sqlite3_file.
48289 ** Should that ever change, remove the following NEVER() */
48290 if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
 
48291 memdb_vfs.szOsFile = sz;
48292 return sqlite3_vfs_register(&memdb_vfs, 0);
48293 }
48294 #endif /* SQLITE_ENABLE_DESERIALIZE */
48295
@@ -51548,10 +51616,15 @@
51548 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
51549 #endif
51550
51551 /* Return the sqlite3_file object for the WAL file */
51552 SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
 
 
 
 
 
51553
51554 #endif /* ifndef SQLITE_OMIT_WAL */
51555 #endif /* SQLITE_WAL_H */
51556
51557 /************** End of wal.h *************************************************/
@@ -57238,11 +57311,10 @@
57238 Pager *pPager;
57239 assert( pPg!=0 );
57240 assert( pPg->pgno==1 );
57241 assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
57242 pPager = pPg->pPager;
57243 sqlite3PagerResetLockTimeout(pPager);
57244 sqlite3PcacheRelease(pPg);
57245 pagerUnlockIfUnused(pPager);
57246 }
57247
57248 /*
@@ -58531,20 +58603,10 @@
58531 */
58532 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
58533 return pPager->fd;
58534 }
58535
58536 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
58537 /*
58538 ** Reset the lock timeout for pager.
58539 */
58540 SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager){
58541 int x = 0;
58542 sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
58543 }
58544 #endif
58545
58546 /*
58547 ** Return the file handle for the journal file (if it exists).
58548 ** This will be either the rollback journal or the WAL file.
58549 */
58550 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
@@ -58954,11 +59016,10 @@
58954 (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
58955 pPager->pBusyHandlerArg,
58956 pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
58957 pnLog, pnCkpt
58958 );
58959 sqlite3PagerResetLockTimeout(pPager);
58960 }
58961 return rc;
58962 }
58963
58964 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
@@ -59119,11 +59180,35 @@
59119 }
59120 }
59121 return rc;
59122 }
59123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59124
 
 
 
 
 
 
 
 
 
 
59125
59126 #ifdef SQLITE_ENABLE_SNAPSHOT
59127 /*
59128 ** If this is a WAL database, obtain a snapshot handle for the snapshot
59129 ** currently open. Otherwise, return an error.
@@ -59139,11 +59224,14 @@
59139 /*
59140 ** If this is a WAL database, store a pointer to pSnapshot. Next time a
59141 ** read transaction is opened, attempt to read from the snapshot it
59142 ** identifies. If this is not a WAL database, return an error.
59143 */
59144 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
 
 
 
59145 int rc = SQLITE_OK;
59146 if( pPager->pWal ){
59147 sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
59148 }else{
59149 rc = SQLITE_ERROR;
@@ -59684,10 +59772,13 @@
59684 u8 lockError; /* True if a locking error has occurred */
59685 #endif
59686 #ifdef SQLITE_ENABLE_SNAPSHOT
59687 WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
59688 #endif
 
 
 
59689 };
59690
59691 /*
59692 ** Candidate values for Wal.exclusiveMode.
59693 */
@@ -59782,11 +59873,11 @@
59782
59783 /* Enlarge the pWal->apWiData[] array if required */
59784 if( pWal->nWiData<=iPage ){
59785 sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
59786 volatile u32 **apNew;
59787 apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
59788 if( !apNew ){
59789 *ppPage = 0;
59790 return SQLITE_NOMEM_BKPT;
59791 }
59792 memset((void*)&apNew[pWal->nWiData], 0,
@@ -59903,29 +59994,47 @@
59903
59904 aOut[0] = s1;
59905 aOut[1] = s2;
59906 }
59907
 
 
 
 
59908 static void walShmBarrier(Wal *pWal){
59909 if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
59910 sqlite3OsShmBarrier(pWal->pDbFd);
59911 }
59912 }
59913
 
 
 
 
 
 
 
 
 
 
 
 
 
59914 /*
59915 ** Write the header information in pWal->hdr into the wal-index.
59916 **
59917 ** The checksum on pWal->hdr is updated before it is written.
59918 */
59919 static void walIndexWriteHdr(Wal *pWal){
59920 volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
59921 const int nCksum = offsetof(WalIndexHdr, aCksum);
59922
59923 assert( pWal->writeLock );
59924 pWal->hdr.isInit = 1;
59925 pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
59926 walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
 
59927 memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
59928 walShmBarrier(pWal);
59929 memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
59930 }
59931
@@ -60057,11 +60166,11 @@
60057 if( pWal->exclusiveMode ) return SQLITE_OK;
60058 rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
60059 SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
60060 WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
60061 walLockName(lockIdx), rc ? "failed" : "ok"));
60062 VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
60063 return rc;
60064 }
60065 static void walUnlockShared(Wal *pWal, int lockIdx){
60066 if( pWal->exclusiveMode ) return;
60067 (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
@@ -60073,11 +60182,11 @@
60073 if( pWal->exclusiveMode ) return SQLITE_OK;
60074 rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
60075 SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
60076 WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
60077 walLockName(lockIdx), n, rc ? "failed" : "ok"));
60078 VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
60079 return rc;
60080 }
60081 static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
60082 if( pWal->exclusiveMode ) return;
60083 (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
@@ -60345,15 +60454,10 @@
60345 int rc; /* Return Code */
60346 i64 nSize; /* Size of log file */
60347 u32 aFrameCksum[2] = {0, 0};
60348 int iLock; /* Lock offset to lock for checkpoint */
60349
60350 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
60351 int tmout = 0;
60352 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
60353 #endif
60354
60355 /* Obtain an exclusive lock on all byte in the locking range not already
60356 ** locked by the caller. The caller is guaranteed to have locked the
60357 ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
60358 ** If successful, the same bytes that are locked here are unlocked before
60359 ** this function returns.
@@ -60897,10 +61001,93 @@
60897 p = 0;
60898 }
60899 *pp = p;
60900 return rc;
60901 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60902
60903 /*
60904 ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
60905 ** n. If the attempt fails and parameter xBusy is not NULL, then it is a
60906 ** busy-handler function. Invoke it and retry the lock until either the
@@ -60915,10 +61102,16 @@
60915 ){
60916 int rc;
60917 do {
60918 rc = walLockExclusive(pWal, lockIdx, n);
60919 }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
 
 
 
 
 
 
60920 return rc;
60921 }
60922
60923 /*
60924 ** The cache of the wal-index header must be valid to call this function.
@@ -60952,11 +61145,11 @@
60952 pWal->nCkpt++;
60953 pWal->hdr.mxFrame = 0;
60954 sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
60955 memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
60956 walIndexWriteHdr(pWal);
60957 pInfo->nBackfill = 0;
60958 pInfo->nBackfillAttempted = 0;
60959 pInfo->aReadMark[1] = 0;
60960 for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
60961 assert( pInfo->aReadMark[0]==0 );
60962 }
@@ -61027,36 +61220,17 @@
61027 ** cannot be backfilled from the WAL.
61028 */
61029 mxSafeFrame = pWal->hdr.mxFrame;
61030 mxPage = pWal->hdr.nPage;
61031 for(i=1; i<WAL_NREADER; i++){
61032 /* Thread-sanitizer reports that the following is an unsafe read,
61033 ** as some other thread may be in the process of updating the value
61034 ** of the aReadMark[] slot. The assumption here is that if that is
61035 ** happening, the other client may only be increasing the value,
61036 ** not decreasing it. So assuming either that either the "old" or
61037 ** "new" version of the value is read, and not some arbitrary value
61038 ** that would never be written by a real client, things are still
61039 ** safe.
61040 **
61041 ** Astute readers have pointed out that the assumption stated in the
61042 ** last sentence of the previous paragraph is not guaranteed to be
61043 ** true for all conforming systems. However, the assumption is true
61044 ** for all compilers and architectures in common use today (circa
61045 ** 2019-11-27) and the alternatives are both slow and complex, and
61046 ** so we will continue to go with the current design for now. If this
61047 ** bothers you, or if you really are running on a system where aligned
61048 ** 32-bit reads and writes are not atomic, then you can simply avoid
61049 ** the use of WAL mode, or only use WAL mode together with
61050 ** PRAGMA locking_mode=EXCLUSIVE and all will be well.
61051 */
61052 u32 y = pInfo->aReadMark[i];
61053 if( mxSafeFrame>y ){
61054 assert( y<=pWal->hdr.mxFrame );
61055 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
61056 if( rc==SQLITE_OK ){
61057 pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
 
61058 walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
61059 }else if( rc==SQLITE_BUSY ){
61060 mxSafeFrame = y;
61061 xBusy = 0;
61062 }else{
@@ -61070,11 +61244,11 @@
61070 rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter);
61071 assert( rc==SQLITE_OK || pIter==0 );
61072 }
61073
61074 if( pIter
61075 && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
61076 ){
61077 u32 nBackfill = pInfo->nBackfill;
61078
61079 pInfo->nBackfillAttempted = mxSafeFrame;
61080
@@ -61126,11 +61300,11 @@
61126 if( rc==SQLITE_OK ){
61127 rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
61128 }
61129 }
61130 if( rc==SQLITE_OK ){
61131 pInfo->nBackfill = mxSafeFrame;
61132 }
61133 }
61134
61135 /* Release the reader lock held while backfilling */
61136 walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
@@ -61285,11 +61459,11 @@
61285 ** and *pChanged is set to 1.
61286 **
61287 ** If the checksum cannot be verified return non-zero. If the header
61288 ** is read successfully and the checksum verified, return zero.
61289 */
61290 static int walIndexTryHdr(Wal *pWal, int *pChanged){
61291 u32 aCksum[2]; /* Checksum on the header content */
61292 WalIndexHdr h1, h2; /* Two copies of the header content */
61293 WalIndexHdr volatile *aHdr; /* Header in shared memory */
61294
61295 /* The first page of the wal-index must be mapped at this point. */
@@ -61298,17 +61472,23 @@
61298 /* Read the header. This might happen concurrently with a write to the
61299 ** same area of shared memory on a different CPU in a SMP,
61300 ** meaning it is possible that an inconsistent snapshot is read
61301 ** from the file. If this happens, return non-zero.
61302 **
 
61303 ** There are two copies of the header at the beginning of the wal-index.
61304 ** When reading, read [0] first then [1]. Writes are in the reverse order.
61305 ** Memory barriers are used to prevent the compiler or the hardware from
61306 ** reordering the reads and writes.
 
 
 
 
 
61307 */
61308 aHdr = walIndexHdr(pWal);
61309 memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
61310 walShmBarrier(pWal);
61311 memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
61312
61313 if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
61314 return 1; /* Dirty read */
@@ -61394,32 +61574,36 @@
61394 badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
61395
61396 /* If the first attempt failed, it might have been due to a race
61397 ** with a writer. So get a WRITE lock and try again.
61398 */
61399 assert( badHdr==0 || pWal->writeLock==0 );
61400 if( badHdr ){
61401 if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
61402 if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
61403 walUnlockShared(pWal, WAL_WRITE_LOCK);
61404 rc = SQLITE_READONLY_RECOVERY;
61405 }
61406 }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
61407 pWal->writeLock = 1;
61408 if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
61409 badHdr = walIndexTryHdr(pWal, pChanged);
61410 if( badHdr ){
61411 /* If the wal-index header is still malformed even while holding
61412 ** a WRITE lock, it can only mean that the header is corrupted and
61413 ** needs to be reconstructed. So run recovery to do exactly that.
61414 */
61415 rc = walIndexRecover(pWal);
61416 *pChanged = 1;
61417 }
61418 }
61419 pWal->writeLock = 0;
61420 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
 
 
 
 
 
61421 }
61422 }
61423
61424 /* If the header is read successfully, check the version number to make
61425 ** sure the wal-index was not constructed with some future format that
@@ -61745,11 +61929,11 @@
61745 }
61746
61747 assert( pWal->nWiData>0 );
61748 assert( pWal->apWiData[0]!=0 );
61749 pInfo = walCkptInfo(pWal);
61750 if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
61751 #ifdef SQLITE_ENABLE_SNAPSHOT
61752 && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
61753 #endif
61754 ){
61755 /* The WAL has been completely backfilled (or it is empty).
@@ -61912,11 +62096,11 @@
61912 void *pBuf2 = sqlite3_malloc(szPage);
61913 if( pBuf1==0 || pBuf2==0 ){
61914 rc = SQLITE_NOMEM;
61915 }else{
61916 u32 i = pInfo->nBackfillAttempted;
61917 for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
61918 WalHashLoc sLoc; /* Hash table location */
61919 u32 pgno; /* Page number in db file */
61920 i64 iDbOff; /* Offset of db file entry */
61921 i64 iWalOff; /* Offset of wal file entry */
61922
@@ -61967,26 +62151,40 @@
61967 ** needs to be flushed.
61968 */
61969 SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
61970 int rc; /* Return code */
61971 int cnt = 0; /* Number of TryBeginRead attempts */
61972 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61973 int tmout = 0;
61974 #endif
61975
61976 #ifdef SQLITE_ENABLE_SNAPSHOT
61977 int bChanged = 0;
61978 WalIndexHdr *pSnapshot = pWal->pSnapshot;
61979 if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
61980 bChanged = 1;
61981 }
61982 #endif
61983
61984 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61985 /* Disable blocking locks. They are not useful when trying to open a
61986 ** read-transaction, and blocking may cause deadlock anyway. */
61987 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61988 #endif
61989
61990 do{
61991 rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
61992 }while( rc==WAL_RETRY );
@@ -61993,20 +62191,10 @@
61993 testcase( (rc&0xff)==SQLITE_BUSY );
61994 testcase( (rc&0xff)==SQLITE_IOERR );
61995 testcase( rc==SQLITE_PROTOCOL );
61996 testcase( rc==SQLITE_OK );
61997
61998 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61999 /* If they were disabled earlier and the read-transaction has been
62000 ** successfully opened, re-enable blocking locks. This is because the
62001 ** connection may attempt to upgrade to a write-transaction, which does
62002 ** benefit from using blocking locks. */
62003 if( rc==SQLITE_OK ){
62004 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
62005 }
62006 #endif
62007
62008 #ifdef SQLITE_ENABLE_SNAPSHOT
62009 if( rc==SQLITE_OK ){
62010 if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62011 /* At this point the client has a lock on an aReadMark[] slot holding
62012 ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
@@ -62024,52 +62212,46 @@
62024 volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
62025
62026 assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
62027 assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
62028
62029 /* It is possible that there is a checkpointer thread running
62030 ** concurrent with this code. If this is the case, it may be that the
62031 ** checkpointer has already determined that it will checkpoint
62032 ** snapshot X, where X is later in the wal file than pSnapshot, but
62033 ** has not yet set the pInfo->nBackfillAttempted variable to indicate
62034 ** its intent. To avoid the race condition this leads to, ensure that
62035 ** there is no checkpointer process by taking a shared CKPT lock
62036 ** before checking pInfo->nBackfillAttempted.
62037 **
62038 ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
62039 ** this already?
62040 */
62041 rc = walLockShared(pWal, WAL_CKPT_LOCK);
62042
62043 if( rc==SQLITE_OK ){
62044 /* Check that the wal file has not been wrapped. Assuming that it has
62045 ** not, also check that no checkpointer has attempted to checkpoint any
62046 ** frames beyond pSnapshot->mxFrame. If either of these conditions are
62047 ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
62048 ** with *pSnapshot and set *pChanged as appropriate for opening the
62049 ** snapshot. */
62050 if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
62051 && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
62052 ){
62053 assert( pWal->readLock>0 );
62054 memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
62055 *pChanged = bChanged;
62056 }else{
62057 rc = SQLITE_ERROR_SNAPSHOT;
62058 }
62059
62060 /* Release the shared CKPT lock obtained above. */
62061 walUnlockShared(pWal, WAL_CKPT_LOCK);
62062 pWal->minFrame = 1;
62063 }
62064
62065
62066 if( rc!=SQLITE_OK ){
62067 sqlite3WalEndReadTransaction(pWal);
62068 }
62069 }
62070 }
 
 
 
 
 
 
 
62071 #endif
62072 return rc;
62073 }
62074
62075 /*
@@ -62145,26 +62327,28 @@
62145 for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){
62146 WalHashLoc sLoc; /* Hash table location */
62147 int iKey; /* Hash slot index */
62148 int nCollide; /* Number of hash collisions remaining */
62149 int rc; /* Error code */
 
62150
62151 rc = walHashGet(pWal, iHash, &sLoc);
62152 if( rc!=SQLITE_OK ){
62153 return rc;
62154 }
62155 nCollide = HASHTABLE_NSLOT;
62156 for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
62157 u32 iH = sLoc.aHash[iKey];
62158 u32 iFrame = iH + sLoc.iZero;
62159 if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){
62160 assert( iFrame>iRead || CORRUPT_DB );
62161 iRead = iFrame;
62162 }
62163 if( (nCollide--)==0 ){
62164 return SQLITE_CORRUPT_BKPT;
62165 }
 
62166 }
62167 if( iRead ) break;
62168 }
62169
62170 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
@@ -62235,10 +62419,20 @@
62235 **
62236 ** There can only be a single writer active at a time.
62237 */
62238 SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
62239 int rc;
 
 
 
 
 
 
 
 
 
 
62240
62241 /* Cannot start a write transaction without first holding a read
62242 ** transaction. */
62243 assert( pWal->readLock>=0 );
62244 assert( pWal->writeLock==0 && pWal->iReCksum==0 );
@@ -62811,50 +63005,57 @@
62811 ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
62812 assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
62813
62814 if( pWal->readOnly ) return SQLITE_READONLY;
62815 WALTRACE(("WAL%p: checkpoint begins\n", pWal));
 
 
 
 
 
62816
62817 /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
62818 ** "checkpoint" lock on the database file. */
 
 
 
 
 
 
62819 rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
62820 if( rc ){
62821 /* EVIDENCE-OF: R-10421-19736 If any other process is running a
62822 ** checkpoint operation at the same time, the lock cannot be obtained and
62823 ** SQLITE_BUSY is returned.
62824 ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
62825 ** it will not be invoked in this case.
62826 */
62827 testcase( rc==SQLITE_BUSY );
62828 testcase( xBusy!=0 );
62829 return rc;
62830 }
62831 pWal->ckptLock = 1;
62832
62833 /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
62834 ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
62835 ** file.
62836 **
62837 ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
62838 ** immediately, and a busy-handler is configured, it is invoked and the
62839 ** writer lock retried until either the busy-handler returns 0 or the
62840 ** lock is successfully obtained.
62841 */
62842 if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
62843 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
62844 if( rc==SQLITE_OK ){
62845 pWal->writeLock = 1;
62846 }else if( rc==SQLITE_BUSY ){
62847 eMode2 = SQLITE_CHECKPOINT_PASSIVE;
62848 xBusy2 = 0;
62849 rc = SQLITE_OK;
62850 }
62851 }
62852
62853 /* Read the wal-index header. */
62854 if( rc==SQLITE_OK ){
 
62855 rc = walIndexReadHdr(pWal, &isChanged);
 
62856 if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
62857 sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
62858 }
62859 }
62860
@@ -62881,16 +63082,24 @@
62881 ** next time the pager opens a snapshot on this database it knows that
62882 ** the cache needs to be reset.
62883 */
62884 memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
62885 }
 
 
 
62886
62887 /* Release the locks. */
62888 sqlite3WalEndWriteTransaction(pWal);
62889 walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
62890 pWal->ckptLock = 0;
 
 
62891 WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
 
 
 
62892 return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
62893 }
62894
62895 /* Return the value to pass to a sqlite3_wal_hook callback, the
62896 ** number of frames in the WAL at the point of the last commit since
@@ -63003,11 +63212,14 @@
63003 return rc;
63004 }
63005
63006 /* Try to open on pSnapshot when the next read-transaction starts
63007 */
63008 SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
 
 
 
63009 pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
63010 }
63011
63012 /*
63013 ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
@@ -63522,11 +63734,11 @@
63522 u8 incrVacuum; /* True if incr-vacuum is enabled */
63523 u8 bDoTruncate; /* True to truncate db on commit */
63524 #endif
63525 u8 inTransaction; /* Transaction state */
63526 u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
63527 u8 nReserveWanted; /* 1 more than desired number of extra bytes per page */
63528 u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
63529 u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
63530 u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
63531 u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
63532 u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
@@ -66416,12 +66628,11 @@
66416 */
66417 static int btreeInvokeBusyHandler(void *pArg){
66418 BtShared *pBt = (BtShared*)pArg;
66419 assert( pBt->db );
66420 assert( sqlite3_mutex_held(pBt->db->mutex) );
66421 return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
66422 sqlite3PagerFile(pBt->pPager));
66423 }
66424
66425 /*
66426 ** Open a database file.
66427 **
@@ -66968,23 +67179,21 @@
66968 ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
66969 ** and autovacuum mode can no longer be changed.
66970 */
66971 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
66972 int rc = SQLITE_OK;
 
66973 BtShared *pBt = p->pBt;
66974 assert( nReserve>=-1 && nReserve<=254 );
66975 sqlite3BtreeEnter(p);
66976 if( nReserve>=0 ){
66977 pBt->nReserveWanted = nReserve + 1;
66978 }
66979 if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
66980 sqlite3BtreeLeave(p);
66981 return SQLITE_READONLY;
66982 }
66983 if( nReserve<0 ){
66984 nReserve = pBt->pageSize - pBt->usableSize;
66985 }
66986 assert( nReserve>=0 && nReserve<=255 );
66987 if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
66988 ((pageSize-1)&pageSize)==0 ){
66989 assert( (pageSize & 7)==0 );
66990 assert( !pBt->pCursor );
@@ -67031,16 +67240,16 @@
67031 ** The value returned is the larger of the current reserve size and
67032 ** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
67033 ** The amount of reserve can only grow - never shrink.
67034 */
67035 SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
67036 int n;
67037 sqlite3BtreeEnter(p);
67038 n = ((int)p->pBt->nReserveWanted) - 1;
67039 if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
67040 sqlite3BtreeLeave(p);
67041 return n;
67042 }
67043
67044
67045 /*
67046 ** Set the maximum page count for a database if mxPage is positive.
@@ -67486,10 +67695,11 @@
67486 ** when A already has a read lock, we encourage A to give up and let B
67487 ** proceed.
67488 */
67489 SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
67490 BtShared *pBt = p->pBt;
 
67491 int rc = SQLITE_OK;
67492
67493 sqlite3BtreeEnter(p);
67494 btreeIntegrity(p);
67495
@@ -67501,11 +67711,11 @@
67501 goto trans_begun;
67502 }
67503 assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
67504
67505 if( (p->db->flags & SQLITE_ResetDatabase)
67506 && sqlite3PagerIsreadonly(pBt->pPager)==0
67507 ){
67508 pBt->btsFlags &= ~BTS_READ_ONLY;
67509 }
67510
67511 /* Write transactions are not possible on a read-only database */
@@ -67549,10 +67759,22 @@
67549 if( SQLITE_OK!=rc ) goto trans_begun;
67550
67551 pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
67552 if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
67553 do {
 
 
 
 
 
 
 
 
 
 
 
 
67554 /* Call lockBtree() until either pBt->pPage1 is populated or
67555 ** lockBtree() returns something other than SQLITE_OK. lockBtree()
67556 ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
67557 ** reading page 1 it discovers that the page-size of the database
67558 ** file is not pBt->pageSize. In this case lockBtree() will update
@@ -67562,11 +67784,11 @@
67562
67563 if( rc==SQLITE_OK && wrflag ){
67564 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
67565 rc = SQLITE_READONLY;
67566 }else{
67567 rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
67568 if( rc==SQLITE_OK ){
67569 rc = newDatabase(pBt);
67570 }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
67571 /* if there was no transaction opened when this function was
67572 ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
@@ -67575,15 +67797,19 @@
67575 }
67576 }
67577 }
67578
67579 if( rc!=SQLITE_OK ){
 
67580 unlockBtreeIfUnused(pBt);
67581 }
67582 }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
67583 btreeInvokeBusyHandler(pBt) );
67584 sqlite3PagerResetLockTimeout(pBt->pPager);
 
 
 
67585
67586 if( rc==SQLITE_OK ){
67587 if( p->inTrans==TRANS_NONE ){
67588 pBt->nTransaction++;
67589 #ifndef SQLITE_OMIT_SHARED_CACHE
@@ -67631,11 +67857,11 @@
67631 if( wrflag ){
67632 /* This call makes sure that the pager has the correct number of
67633 ** open savepoints. If the second parameter is greater than 0 and
67634 ** the sub-journal is not already open, then it will be opened here.
67635 */
67636 rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
67637 }
67638 }
67639
67640 btreeIntegrity(p);
67641 sqlite3BtreeLeave(p);
@@ -71267,11 +71493,11 @@
71267
71268 /* Remove cells from the start and end of the page */
71269 assert( nCell>=0 );
71270 if( iOld<iNew ){
71271 int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
71272 if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
71273 memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
71274 nCell -= nShift;
71275 }
71276 if( iNewEnd < iOldEnd ){
71277 int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
@@ -74746,11 +74972,11 @@
74746 ** Attempt to set the page size of the destination to match the page size
74747 ** of the source.
74748 */
74749 static int setDestPgsz(sqlite3_backup *p){
74750 int rc;
74751 rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
74752 return rc;
74753 }
74754
74755 /*
74756 ** Check that there is no open read-transaction on the b-tree passed as the
@@ -79143,10 +79369,11 @@
79143 char *zP4;
79144 char *zCom;
79145 sqlite3 dummyDb;
79146 static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
79147 if( pOut==0 ) pOut = stdout;
 
79148 dummyDb.mallocFailed = 1;
79149 zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
79150 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
79151 zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
79152 #else
@@ -79161,10 +79388,11 @@
79161 zCom ? zCom : ""
79162 );
79163 fflush(pOut);
79164 sqlite3_free(zP4);
79165 sqlite3_free(zCom);
 
79166 }
79167 #endif
79168
79169 /*
79170 ** Initialize an array of N Mem element.
@@ -83902,11 +84130,11 @@
83902 p->db->errCode = SQLITE_OK;
83903
83904 /* If the bit corresponding to this variable in Vdbe.expmask is set, then
83905 ** binding a new value to this variable invalidates the current query plan.
83906 **
83907 ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
83908 ** parameter in the WHERE clause might influence the choice of query plan
83909 ** for a statement, then the statement will be automatically recompiled,
83910 ** as if there had been a schema change, on the first sqlite3_step() call
83911 ** following any change to the bindings of that parameter.
83912 */
@@ -90540,16 +90768,23 @@
90540 rc = sqlite3VdbeSorterWrite(pC, pIn2);
90541 if( rc) goto abort_due_to_error;
90542 break;
90543 }
90544
90545 /* Opcode: IdxDelete P1 P2 P3 * *
90546 ** Synopsis: key=r[P2@P3]
90547 **
90548 ** The content of P3 registers starting at register P2 form
90549 ** an unpacked index key. This opcode removes that entry from the
90550 ** index opened by cursor P1.
 
 
 
 
 
 
 
90551 */
90552 case OP_IdxDelete: {
90553 VdbeCursor *pC;
90554 BtCursor *pCrsr;
90555 int res;
@@ -90562,20 +90797,22 @@
90562 assert( pC!=0 );
90563 assert( pC->eCurType==CURTYPE_BTREE );
90564 sqlite3VdbeIncrWriteCounter(p, pC);
90565 pCrsr = pC->uc.pCursor;
90566 assert( pCrsr!=0 );
90567 assert( pOp->p5==0 );
90568 r.pKeyInfo = pC->pKeyInfo;
90569 r.nField = (u16)pOp->p3;
90570 r.default_rc = 0;
90571 r.aMem = &aMem[pOp->p2];
90572 rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
90573 if( rc ) goto abort_due_to_error;
90574 if( res==0 ){
90575 rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
90576 if( rc ) goto abort_due_to_error;
 
 
 
90577 }
90578 assert( pC->deferredMoveto==0 );
90579 pC->cacheStatus = CACHE_STALE;
90580 pC->seekResult = 0;
90581 break;
@@ -96192,12 +96429,12 @@
96192 *************************************************************************
96193 **
96194 ** This file implements virtual-tables for examining the bytecode content
96195 ** of a prepared statement.
96196 */
96197 #ifdef SQLITE_ENABLE_BYTECODE_VTAB
96198 /* #include "sqliteInt.h" */
 
96199 /* #include "vdbeInt.h" */
96200
96201 /* An instance of the bytecode() table-valued function.
96202 */
96203 typedef struct bytecodevtab bytecodevtab;
@@ -96598,10 +96835,12 @@
96598 if( rc==SQLITE_OK ){
96599 rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
96600 }
96601 return rc;
96602 }
 
 
96603 #endif /* SQLITE_ENABLE_BYTECODE_VTAB */
96604
96605 /************** End of vdbevtab.c ********************************************/
96606 /************** Begin file memjournal.c **************************************/
96607 /*
@@ -97243,10 +97482,47 @@
97243 }
97244 p = p->pPrior;
97245 }while( p!=0 );
97246 return WRC_Continue;
97247 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97248
97249 /************** End of walker.c **********************************************/
97250 /************** Begin file resolve.c *****************************************/
97251 /*
97252 ** 2008 August 18
@@ -97272,10 +97548,12 @@
97272 ** This needs to occur when copying a TK_AGG_FUNCTION node from an
97273 ** outer query into an inner subquery.
97274 **
97275 ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
97276 ** is a helper function - a callback for the tree walker.
 
 
97277 */
97278 static int incrAggDepth(Walker *pWalker, Expr *pExpr){
97279 if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
97280 return WRC_Continue;
97281 }
@@ -102902,10 +103180,17 @@
102902 }
102903 setDoNotMergeFlagOnCopy(v);
102904 sqlite3VdbeResolveLabel(v, endCoalesce);
102905 break;
102906 }
 
 
 
 
 
 
 
102907
102908 default: {
102909 /* The UNLIKELY() function is a no-op. The result is the value
102910 ** of the first argument.
102911 */
@@ -103006,11 +103291,14 @@
103006 op = pExpr->op;
103007 }
103008 switch( op ){
103009 case TK_AGG_COLUMN: {
103010 AggInfo *pAggInfo = pExpr->pAggInfo;
103011 struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
 
 
 
103012 if( !pAggInfo->directMode ){
103013 assert( pCol->iMem>0 );
103014 return pCol->iMem;
103015 }else if( pAggInfo->useSortingIdx ){
103016 Table *pTab = pCol->pTab;
@@ -103306,11 +103594,14 @@
103306 sqlite3VdbeJumpHere(v, addr);
103307 break;
103308 }
103309 case TK_AGG_FUNCTION: {
103310 AggInfo *pInfo = pExpr->pAggInfo;
103311 if( pInfo==0 ){
 
 
 
103312 assert( !ExprHasProperty(pExpr, EP_IntValue) );
103313 sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
103314 }else{
103315 return pInfo->aFunc[pExpr->iAgg].iMem;
103316 }
@@ -103684,11 +103975,11 @@
103684 assert( pExpr->affExpr==OE_Rollback
103685 || pExpr->affExpr==OE_Abort
103686 || pExpr->affExpr==OE_Fail
103687 || pExpr->affExpr==OE_Ignore
103688 );
103689 if( !pParse->pTriggerTab ){
103690 sqlite3ErrorMsg(pParse,
103691 "RAISE() may only be used within a trigger-program");
103692 return 0;
103693 }
103694 if( pExpr->affExpr==OE_Abort ){
@@ -103698,12 +103989,13 @@
103698 if( pExpr->affExpr==OE_Ignore ){
103699 sqlite3VdbeAddOp4(
103700 v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
103701 VdbeCoverage(v);
103702 }else{
103703 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
103704 pExpr->affExpr, pExpr->u.zToken, 0, 0);
 
103705 }
103706
103707 break;
103708 }
103709 #endif
@@ -105061,19 +105353,10 @@
105061 }
105062 }
105063 }
105064 return WRC_Continue;
105065 }
105066 static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
105067 UNUSED_PARAMETER(pSelect);
105068 pWalker->walkerDepth++;
105069 return WRC_Continue;
105070 }
105071 static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
105072 UNUSED_PARAMETER(pSelect);
105073 pWalker->walkerDepth--;
105074 }
105075
105076 /*
105077 ** Analyze the pExpr expression looking for aggregate functions and
105078 ** for variables that need to be added to AggInfo object that pNC->pAggInfo
105079 ** points to. Additional entries are made on the AggInfo object as
@@ -105083,12 +105366,12 @@
105083 ** analyzed by sqlite3ResolveExprNames().
105084 */
105085 SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
105086 Walker w;
105087 w.xExprCallback = analyzeAggregate;
105088 w.xSelectCallback = analyzeAggregatesInSelect;
105089 w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
105090 w.walkerDepth = 0;
105091 w.u.pNC = pNC;
105092 w.pParse = 0;
105093 assert( pNC->pSrcList!=0 );
105094 sqlite3WalkExpr(&w, pExpr);
@@ -105323,11 +105606,14 @@
105323 if( !zName ) goto exit_rename_table;
105324
105325 /* Check that a table or index named 'zName' does not already exist
105326 ** in database iDb. If so, this is an error.
105327 */
105328 if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
 
 
 
105329 sqlite3ErrorMsg(pParse,
105330 "there is already another table or index with this name: %s", zName);
105331 goto exit_rename_table;
105332 }
105333
@@ -105454,10 +105740,26 @@
105454 exit_rename_table:
105455 sqlite3SrcListDelete(db, pSrc);
105456 sqlite3DbFree(db, zName);
105457 db->mDbFlags = savedDbFlags;
105458 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105459
105460 /*
105461 ** This function is called after an "ALTER TABLE ... ADD" statement
105462 ** has been parsed. Argument pColDef contains the text of the new
105463 ** column definition.
@@ -105507,11 +105809,12 @@
105507 if( pCol->colFlags & COLFLAG_PRIMKEY ){
105508 sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
105509 return;
105510 }
105511 if( pNew->pIndex ){
105512 sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
 
105513 return;
105514 }
105515 if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
105516 /* If the default value for the new column was specified with a
105517 ** literal NULL, then set pDflt to 0. This simplifies checking
@@ -105520,19 +105823,18 @@
105520 assert( pDflt==0 || pDflt->op==TK_SPAN );
105521 if( pDflt && pDflt->pLeft->op==TK_NULL ){
105522 pDflt = 0;
105523 }
105524 if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
105525 sqlite3ErrorMsg(pParse,
105526 "Cannot add a REFERENCES column with non-NULL default value");
105527 return;
105528 }
105529 if( pCol->notNull && !pDflt ){
105530 sqlite3ErrorMsg(pParse,
105531 "Cannot add a NOT NULL column with default value NULL");
105532 return;
105533 }
 
105534
105535 /* Ensure the default expression is something that sqlite3ValueFromExpr()
105536 ** can handle (i.e. not CURRENT_TIME etc.)
105537 */
105538 if( pDflt ){
@@ -105543,18 +105845,17 @@
105543 if( rc!=SQLITE_OK ){
105544 assert( db->mallocFailed == 1 );
105545 return;
105546 }
105547 if( !pVal ){
105548 sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
105549 return;
105550 }
105551 sqlite3ValueFree(pVal);
105552 }
105553 }else if( pCol->colFlags & COLFLAG_STORED ){
105554 sqlite3ErrorMsg(pParse, "cannot add a STORED column");
105555 return;
105556 }
105557
105558
105559 /* Modify the CREATE TABLE statement. */
105560 zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
@@ -110055,26 +110356,43 @@
110055 ** exists */
110056 if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
110057 return 0;
110058 }
110059 #endif
110060 while(1){
110061 for(i=OMIT_TEMPDB; i<db->nDb; i++){
110062 int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
110063 if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
110064 assert( sqlite3SchemaMutexHeld(db, j, 0) );
110065 p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
110066 if( p ) return p;
110067 }
110068 }
110069 /* Not found. If the name we were looking for was temp.sqlite_master
110070 ** then change the name to sqlite_temp_master and try again. */
110071 if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
110072 if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
110073 zName = TEMP_MASTER_NAME;
110074 }
110075 return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110076 }
110077
110078 /*
110079 ** Locate the in-memory structure that describes a particular database
110080 ** table given the name of that table and (optionally) the name of the
@@ -111874,10 +112192,32 @@
111874 assert( pPk->nColumn==j );
111875 assert( pTab->nNVCol<=j );
111876 recomputeColumnsNotIndexed(pPk);
111877 }
111878
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111879 #ifndef SQLITE_OMIT_VIRTUALTABLE
111880 /*
111881 ** Return true if zName is a shadow table name in the current database
111882 ** connection.
111883 **
@@ -111885,26 +112225,21 @@
111885 ** restored to its original value prior to this routine returning.
111886 */
111887 SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
111888 char *zTail; /* Pointer to the last "_" in zName */
111889 Table *pTab; /* Table that zName is a shadow of */
111890 Module *pMod; /* Module for the virtual table */
111891
111892 zTail = strrchr(zName, '_');
111893 if( zTail==0 ) return 0;
111894 *zTail = 0;
111895 pTab = sqlite3FindTable(db, zName, 0);
111896 *zTail = '_';
111897 if( pTab==0 ) return 0;
111898 if( !IsVirtual(pTab) ) return 0;
111899 pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
111900 if( pMod==0 ) return 0;
111901 if( pMod->pModule->iVersion<3 ) return 0;
111902 if( pMod->pModule->xShadowName==0 ) return 0;
111903 return pMod->pModule->xShadowName(zTail+1);
111904 }
111905 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
 
111906
111907 #ifdef SQLITE_DEBUG
111908 /*
111909 ** Mark all nodes of an expression as EP_Immutable, indicating that
111910 ** they should not be changed. Expressions attached to a table or
@@ -114373,11 +114708,11 @@
114373 pParse->rc = rc;
114374 return 1;
114375 }
114376 db->aDb[1].pBt = pBt;
114377 assert( db->aDb[1].pSchema );
114378 if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
114379 sqlite3OomFault(db);
114380 return 1;
114381 }
114382 }
114383 return 0;
@@ -114484,11 +114819,11 @@
114484 char *p4, /* Error message */
114485 i8 p4type, /* P4_STATIC or P4_TRANSIENT */
114486 u8 p5Errmsg /* P5_ErrMsg type */
114487 ){
114488 Vdbe *v = sqlite3GetVdbe(pParse);
114489 assert( (errCode&0xff)==SQLITE_CONSTRAINT );
114490 if( onError==OE_Abort ){
114491 sqlite3MayAbort(pParse);
114492 }
114493 sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
114494 sqlite3VdbeChangeP5(v, p5Errmsg);
@@ -116197,10 +116532,11 @@
116197 VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
116198 r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
116199 &iPartIdxLabel, pPrior, r1);
116200 sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
116201 pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
 
116202 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
116203 pPrior = pIdx;
116204 }
116205 }
116206
@@ -117590,11 +117926,11 @@
117590 if( (cntExpand&(cntExpand-1))==0 ){
117591 /* Grow the size of the output buffer only on substitutions
117592 ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
117593 u8 *zOld;
117594 zOld = zOut;
117595 zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
117596 if( zOut==0 ){
117597 sqlite3_result_error_nomem(context);
117598 sqlite3_free(zOld);
117599 return;
117600 }
@@ -118287,11 +118623,11 @@
118287 FUNCTION(round, 2, 0, 0, roundFunc ),
118288 #endif
118289 FUNCTION(upper, 1, 0, 0, upperFunc ),
118290 FUNCTION(lower, 1, 0, 0, lowerFunc ),
118291 FUNCTION(hex, 1, 0, 0, hexFunc ),
118292 INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
118293 VFUNCTION(random, 0, 0, 0, randomFunc ),
118294 VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
118295 FUNCTION(nullif, 2, 0, 1, nullifFunc ),
118296 DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
118297 DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
@@ -118327,11 +118663,12 @@
118327 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
118328 FUNCTION(unknown, -1, 0, 0, unknownFunc ),
118329 #endif
118330 FUNCTION(coalesce, 1, 0, 0, 0 ),
118331 FUNCTION(coalesce, 0, 0, 0, 0 ),
118332 INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
 
118333 };
118334 #ifndef SQLITE_OMIT_ALTERTABLE
118335 sqlite3AlterFunctions();
118336 #endif
118337 sqlite3WindowFunctions();
@@ -121752,11 +122089,11 @@
121752 }
121753 if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
121754 sqlite3TableAffinity(v, pTab, regNewData+1);
121755 bAffinityDone = 1;
121756 }
121757 VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
121758 iThisCur = iIdxCur+ix;
121759
121760
121761 /* Skip partial indices for which the WHERE clause is not true */
121762 if( pIdx->pPartIdxWhere ){
@@ -125555,11 +125892,11 @@
125555 }else{
125556 /* Malloc may fail when setting the page-size, as there is an internal
125557 ** buffer that the pager module resizes using sqlite3_realloc().
125558 */
125559 db->nextPagesize = sqlite3Atoi(zRight);
125560 if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
125561 sqlite3OomFault(db);
125562 }
125563 }
125564 break;
125565 }
@@ -133724,33 +134061,10 @@
133724 }
133725 }
133726 return WRC_Continue;
133727 }
133728
133729 /*
133730 ** No-op routine for the parse-tree walker.
133731 **
133732 ** When this routine is the Walker.xExprCallback then expression trees
133733 ** are walked without any actions being taken at each node. Presumably,
133734 ** when this routine is used for Walker.xExprCallback then
133735 ** Walker.xSelectCallback is set to do something useful for every
133736 ** subquery in the parser tree.
133737 */
133738 SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
133739 UNUSED_PARAMETER2(NotUsed, NotUsed2);
133740 return WRC_Continue;
133741 }
133742
133743 /*
133744 ** No-op routine for the parse-tree walker for SELECT statements.
133745 ** subquery in the parser tree.
133746 */
133747 SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
133748 UNUSED_PARAMETER2(NotUsed, NotUsed2);
133749 return WRC_Continue;
133750 }
133751
133752 #if SQLITE_DEBUG
133753 /*
133754 ** Always assert. This xSelectCallback2 implementation proves that the
133755 ** xSelectCallback2 is never invoked.
133756 */
@@ -134917,11 +135231,11 @@
134917 sAggInfo.mxReg = pParse->nMem;
134918 if( db->mallocFailed ) goto select_end;
134919 #if SELECTTRACE_ENABLED
134920 if( sqlite3SelectTrace & 0x400 ){
134921 int ii;
134922 SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
134923 sqlite3TreeViewSelect(0, p, 0);
134924 for(ii=0; ii<sAggInfo.nColumn; ii++){
134925 sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
134926 ii, sAggInfo.aCol[ii].iMem);
134927 sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
@@ -135193,17 +135507,19 @@
135193 **
135194 ** In practice the KeyInfo structure will not be used. It is only
135195 ** passed to keep OP_OpenRead happy.
135196 */
135197 if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
135198 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
135199 if( pIdx->bUnordered==0
135200 && pIdx->szIdxRow<pTab->szTabRow
135201 && pIdx->pPartIdxWhere==0
135202 && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
135203 ){
135204 pBest = pIdx;
 
 
135205 }
135206 }
135207 if( pBest ){
135208 iRoot = pBest->tnum;
135209 pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
@@ -135378,11 +135694,11 @@
135378 need = nCol;
135379 }
135380 if( p->nData + need > p->nAlloc ){
135381 char **azNew;
135382 p->nAlloc = p->nAlloc*2 + need;
135383 azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
135384 if( azNew==0 ) goto malloc_failed;
135385 p->azResult = azNew;
135386 }
135387
135388 /* If this is the first row, then generate an extra row containing
@@ -135487,11 +135803,11 @@
135487 sqlite3_free_table(&res.azResult[1]);
135488 return rc;
135489 }
135490 if( res.nAlloc>res.nData ){
135491 char **azNew;
135492 azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
135493 if( azNew==0 ){
135494 sqlite3_free_table(&res.azResult[1]);
135495 db->errCode = SQLITE_NOMEM;
135496 return SQLITE_NOMEM_BKPT;
135497 }
@@ -136777,14 +137093,14 @@
136777 ** Therefore, the P4 parameter is only required if the default value for
136778 ** the column is a literal number, string or null. The sqlite3ValueFromExpr()
136779 ** function is capable of transforming these types of expressions into
136780 ** sqlite3_value objects.
136781 **
136782 ** If parameter iReg is not negative, code an OP_RealAffinity instruction
136783 ** on register iReg. This is used when an equivalent integer value is
136784 ** stored in place of an 8-byte floating point value in order to save
136785 ** space.
136786 */
136787 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
136788 assert( pTab!=0 );
136789 if( !pTab->pSelect ){
136790 sqlite3_value *pValue = 0;
@@ -136797,11 +137113,11 @@
136797 if( pValue ){
136798 sqlite3VdbeAppendP4(v, pValue, P4_MEM);
136799 }
136800 }
136801 #ifndef SQLITE_OMIT_FLOATING_POINT
136802 if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
136803 sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
136804 }
136805 #endif
136806 }
136807
@@ -138439,11 +138755,11 @@
138439 db->mDbFlags = saved_mDbFlags;
138440 db->flags = saved_flags;
138441 db->nChange = saved_nChange;
138442 db->nTotalChange = saved_nTotalChange;
138443 db->mTrace = saved_mTrace;
138444 sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
138445
138446 /* Currently there is an SQL level transaction open on the vacuum
138447 ** database. No locks are held on any other files (since the main file
138448 ** was committed at the btree level). So it safe to end the transaction
138449 ** by manually setting the autoCommit flag to true and detaching the
@@ -139646,11 +139962,11 @@
139646 assert( IsVirtual(pTab) );
139647 for(i=0; i<pToplevel->nVtabLock; i++){
139648 if( pTab==pToplevel->apVtabLock[i] ) return;
139649 }
139650 n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
139651 apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
139652 if( apVtabLock ){
139653 pToplevel->apVtabLock = apVtabLock;
139654 pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
139655 }else{
139656 sqlite3OomFault(pToplevel->db);
@@ -150938,24 +151254,47 @@
150938 ){
150939 if( pAppend ){
150940 int i;
150941 int nInit = pList ? pList->nExpr : 0;
150942 for(i=0; i<pAppend->nExpr; i++){
150943 int iDummy;
150944 Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
150945 assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
150946 if( bIntToNull && pDup && sqlite3ExprIsInteger(pDup, &iDummy) ){
150947 pDup->op = TK_NULL;
150948 pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
150949 pDup->u.zToken = 0;
 
 
 
 
 
 
 
150950 }
150951 pList = sqlite3ExprListAppend(pParse, pList, pDup);
150952 if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
150953 }
150954 }
150955 return pList;
150956 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150957
150958 /*
150959 ** If the SELECT statement passed as the second argument does not invoke
150960 ** any SQL window functions, this function is a no-op. Otherwise, it
150961 ** rewrites the SELECT statement so that window function xStep functions
@@ -151062,10 +151401,11 @@
151062 pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
151063 );
151064 p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
151065 if( p->pSrc ){
151066 Table *pTab2;
 
151067 p->pSrc->a[0].pSelect = pSub;
151068 sqlite3SrcListAssignCursors(pParse, p->pSrc);
151069 pSub->selFlags |= SF_Expanded;
151070 pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
151071 pSub->selFlags |= (selFlags & SF_Aggregate);
@@ -151077,10 +151417,15 @@
151077 }else{
151078 memcpy(pTab, pTab2, sizeof(Table));
151079 pTab->tabFlags |= TF_Ephemeral;
151080 p->pSrc->a[0].pTab = pTab;
151081 pTab = pTab2;
 
 
 
 
 
151082 }
151083 }else{
151084 sqlite3SelectDelete(db, pSub);
151085 }
151086 if( db->mallocFailed ) rc = SQLITE_NOMEM;
@@ -160130,10 +160475,11 @@
160130 }
160131 #endif
160132 if( rc==SQLITE_OK ){
160133 sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
160134 sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
 
160135 sqlite3GlobalConfig.isInit = 1;
160136 #ifdef SQLITE_EXTRA_INIT
160137 bRunExtraInit = 1;
160138 #endif
160139 }
@@ -161431,12 +161777,11 @@
161431 ** Return non-zero to retry the lock. Return zero to stop trying
161432 ** and cause SQLite to return SQLITE_BUSY.
161433 */
161434 static int sqliteDefaultBusyCallback(
161435 void *ptr, /* Database connection */
161436 int count, /* Number of times table has been busy */
161437 sqlite3_file *pFile /* The file on which the lock occurred */
161438 ){
161439 #if SQLITE_OS_WIN || HAVE_USLEEP
161440 /* This case is for systems that have support for sleeping for fractions of
161441 ** a second. Examples: All windows systems, unix systems with usleep() */
161442 static const u8 delays[] =
@@ -161446,35 +161791,10 @@
161446 # define NDELAY ArraySize(delays)
161447 sqlite3 *db = (sqlite3 *)ptr;
161448 int tmout = db->busyTimeout;
161449 int delay, prior;
161450
161451 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
161452 if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
161453 if( count ){
161454 /* If this is the second or later invocation of the busy-handler,
161455 ** but tmout==0, then code in wal.c must have disabled the blocking
161456 ** lock before the SQLITE_BUSY error was hit. In this case, no delay
161457 ** occurred while waiting for the lock, so fall through to the xSleep()
161458 ** code below to delay a while before retrying the lock.
161459 **
161460 ** Alternatively, if tmout!=0, then SQLite has already waited
161461 ** sqlite3.busyTimeout ms for a lock. In this case, return 0 to
161462 ** indicate that the lock should not be retried and the SQLITE_BUSY
161463 ** error returned to the application. */
161464 if( tmout ){
161465 tmout = 0;
161466 sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
161467 return 0;
161468 }
161469 }else{
161470 return 1;
161471 }
161472 }
161473 #else
161474 UNUSED_PARAMETER(pFile);
161475 #endif
161476 assert( count>=0 );
161477 if( count < NDELAY ){
161478 delay = delays[count];
161479 prior = totals[count];
161480 }else{
@@ -161490,11 +161810,10 @@
161490 #else
161491 /* This case for unix systems that lack usleep() support. Sleeping
161492 ** must be done in increments of whole seconds */
161493 sqlite3 *db = (sqlite3 *)ptr;
161494 int tmout = ((sqlite3 *)ptr)->busyTimeout;
161495 UNUSED_PARAMETER(pFile);
161496 if( (count+1)*1000 > tmout ){
161497 return 0;
161498 }
161499 sqlite3OsSleep(db->pVfs, 1000000);
161500 return 1;
@@ -161508,23 +161827,14 @@
161508 ** lock on VFS file pFile.
161509 **
161510 ** If this routine returns non-zero, the lock is retried. If it
161511 ** returns 0, the operation aborts with an SQLITE_BUSY error.
161512 */
161513 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
161514 int rc;
161515 if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
161516 if( p->bExtraFileArg ){
161517 /* Add an extra parameter with the pFile pointer to the end of the
161518 ** callback argument list */
161519 int (*xTra)(void*,int,sqlite3_file*);
161520 xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
161521 rc = xTra(p->pBusyArg, p->nBusy, pFile);
161522 }else{
161523 /* Legacy style busy handler callback */
161524 rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
161525 }
161526 if( rc==0 ){
161527 p->nBusy = -1;
161528 }else{
161529 p->nBusy++;
161530 }
@@ -161545,11 +161855,10 @@
161545 #endif
161546 sqlite3_mutex_enter(db->mutex);
161547 db->busyHandler.xBusyHandler = xBusy;
161548 db->busyHandler.pBusyArg = pArg;
161549 db->busyHandler.nBusy = 0;
161550 db->busyHandler.bExtraFileArg = 0;
161551 db->busyTimeout = 0;
161552 sqlite3_mutex_leave(db->mutex);
161553 return SQLITE_OK;
161554 }
161555
@@ -161596,11 +161905,10 @@
161596 #endif
161597 if( ms>0 ){
161598 sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
161599 (void*)db);
161600 db->busyTimeout = ms;
161601 db->busyHandler.bExtraFileArg = 1;
161602 }else{
161603 sqlite3_busy_handler(db, 0, 0);
161604 }
161605 return SQLITE_OK;
161606 }
@@ -163071,10 +163379,13 @@
163071 | SQLITE_EnableQPSG
163072 #endif
163073 #if defined(SQLITE_DEFAULT_DEFENSIVE)
163074 | SQLITE_Defensive
163075 #endif
 
 
 
163076 ;
163077 sqlite3HashInit(&db->aCollSeq);
163078 #ifndef SQLITE_OMIT_VIRTUALTABLE
163079 sqlite3HashInit(&db->aModule);
163080 #endif
@@ -163113,11 +163424,11 @@
163113 assert( SQLITE_OPEN_CREATE == 0x04 );
163114 testcase( (1<<(flags&7))==0x02 ); /* READONLY */
163115 testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
163116 testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
163117 if( ((1<<(flags&7)) & 0x46)==0 ){
163118 rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
163119 }else{
163120 rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
163121 }
163122 if( rc!=SQLITE_OK ){
163123 if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
@@ -163668,11 +163979,11 @@
163668 *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
163669 rc = SQLITE_OK;
163670 }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
163671 int iNew = *(int*)pArg;
163672 *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
163673 if( iNew>=0 && iNew<=254 ){
163674 sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
163675 }
163676 rc = SQLITE_OK;
163677 }else{
163678 rc = sqlite3OsFileControl(fd, op, pArg);
@@ -167905,11 +168216,13 @@
167905 static void fts3ReadNextPos(
167906 char **pp, /* IN/OUT: Pointer into position-list buffer */
167907 sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
167908 ){
167909 if( (**pp)&0xFE ){
167910 fts3GetDeltaVarint(pp, pi);
 
 
167911 *pi -= 2;
167912 }else{
167913 *pi = POSITION_LIST_END;
167914 }
167915 }
@@ -171035,10 +171348,11 @@
171035 while( *pRc==SQLITE_OK && pLeft->bEof==0 ){
171036 memset(pDl->pList, 0, pDl->nList);
171037 fts3EvalNextRow(pCsr, pLeft, pRc);
171038 }
171039 }
 
171040 }
171041 }
171042 break;
171043 }
171044
@@ -182580,11 +182894,11 @@
182580 iStart = pExpr->iPhrase * p->nCol;
182581 }else{
182582 iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
182583 }
182584
182585 while( 1 ){
182586 int nHit = fts3ColumnlistCount(&pIter);
182587 if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
182588 if( p->flag==FTS3_MATCHINFO_LHITS ){
182589 p->aMatchinfo[iStart + iCol] = (u32)nHit;
182590 }else if( nHit ){
@@ -184494,10 +184808,11 @@
184494 }
184495
184496 /* Append N bytes from zIn onto the end of the JsonString string.
184497 */
184498 static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
 
184499 if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
184500 memcpy(p->zBuf+p->nUsed, zIn, N);
184501 p->nUsed += N;
184502 }
184503
@@ -224505,11 +224820,11 @@
224505 int nArg, /* Number of args */
224506 sqlite3_value **apUnused /* Function arguments */
224507 ){
224508 assert( nArg==0 );
224509 UNUSED_PARAM2(nArg, apUnused);
224510 sqlite3_result_text(pCtx, "fts5: 2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda", -1, SQLITE_TRANSIENT);
224511 }
224512
224513 /*
224514 ** Return true if zName is the extension on one of the shadow tables used
224515 ** by this module.
@@ -229288,12 +229603,12 @@
229288 }
229289 #endif /* SQLITE_CORE */
229290 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
229291
229292 /************** End of stmt.c ************************************************/
229293 #if __LINE__!=229293
229294 #undef SQLITE_SOURCE_ID
229295 #define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb21alt2"
229296 #endif
229297 /* Return the source-id for this library */
229298 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
229299 /************************** End of sqlite3.c ******************************/
229300
--- 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.32.1. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -1160,13 +1160,13 @@
1160 **
1161 ** See also: [sqlite3_libversion()],
1162 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1163 ** [sqlite_version()] and [sqlite_source_id()].
1164 */
1165 #define SQLITE_VERSION "3.32.1"
1166 #define SQLITE_VERSION_NUMBER 3032001
1167 #define SQLITE_SOURCE_ID "2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350"
1168
1169 /*
1170 ** CAPI3REF: Run-Time Library Version Numbers
1171 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1172 **
@@ -1545,18 +1545,20 @@
1545 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
1546 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
1547 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
1548 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
1549 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
1550 #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
1551 #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
1552 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
1553 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
1554 #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
1555 #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
1556 #define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
1557 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
1558 #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
1559 #define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
1560 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
1561 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
1562 #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
1563 #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
1564 #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
@@ -6530,11 +6532,11 @@
6532 ** when first called if N is less than or equal to zero or if a memory
6533 ** allocate error occurs.
6534 **
6535 ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
6536 ** determined by the N parameter on first successful call. Changing the
6537 ** value of N in any subsequent call to sqlite3_aggregate_context() within
6538 ** the same aggregate function instance will not resize the memory
6539 ** allocation.)^ Within the xFinal callback, it is customary to set
6540 ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
6541 ** pointless memory allocations occur.
6542 **
@@ -14535,11 +14537,10 @@
14537 typedef struct BusyHandler BusyHandler;
14538 struct BusyHandler {
14539 int (*xBusyHandler)(void *,int); /* The busy callback */
14540 void *pBusyArg; /* First arg to busy callback */
14541 int nBusy; /* Incremented with each busy call */
 
14542 };
14543
14544 /*
14545 ** Name of the master database table. The master database table
14546 ** is a special table that holds the names and attributes of all
@@ -15918,17 +15919,25 @@
15919 SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
15920 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
15921 SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
15922 SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
15923 # ifdef SQLITE_ENABLE_SNAPSHOT
15924 SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
15925 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
15926 SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
15927 SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
15928 SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
15929 # endif
15930 #endif
15931
15932 #if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
15933 SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
15934 SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
15935 #else
15936 # define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
15937 # define sqlite3PagerWalDb(x,y)
15938 #endif
15939
15940 #ifdef SQLITE_DIRECT_OVERFLOW_READ
15941 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
15942 #endif
15943
@@ -15951,15 +15960,10 @@
15960 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
15961 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
15962 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
15963 SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
15964 SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
 
 
 
 
 
15965
15966 /* Functions used to truncate the database file. */
15967 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
15968
15969 SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
@@ -17115,11 +17119,11 @@
17119 #define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */
17120 #define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
17121 #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
17122 #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
17123 #define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
17124 /* 0x0200 -- available for reuse */
17125 #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
17126 #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
17127 #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
17128 #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
17129 ** single query - might change over time */
@@ -17136,10 +17140,11 @@
17140 #define INLINEFUNC_coalesce 0
17141 #define INLINEFUNC_implies_nonnull_row 1
17142 #define INLINEFUNC_expr_implies_expr 2
17143 #define INLINEFUNC_expr_compare 3
17144 #define INLINEFUNC_affinity 4
17145 #define INLINEFUNC_iif 5
17146 #define INLINEFUNC_unlikely 99 /* Default case */
17147
17148 /*
17149 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
17150 ** used to create the initializers for the FuncDef structures.
@@ -17836,11 +17841,11 @@
17841 /*
17842 ** An instance of this structure contains information needed to generate
17843 ** code for a SELECT that contains aggregate functions.
17844 **
17845 ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
17846 ** pointer to this structure. The Expr.iAgg field is the index in
17847 ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
17848 ** code for that node.
17849 **
17850 ** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the
17851 ** original Select structure that describes the SELECT statement. These
@@ -19075,10 +19080,13 @@
19080 SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
19081 SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
19082 SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
19083 SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
19084 SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
19085 SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker*,Select*);
19086 SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker*,Select*);
19087
19088 #ifdef SQLITE_DEBUG
19089 SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
19090 #endif
19091
19092 /*
@@ -19935,11 +19943,11 @@
19943 SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
19944 SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
19945 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
19946 SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
19947 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
19948 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
19949 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
19950 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
19951 SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
19952 SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
19953 SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
@@ -20060,12 +20068,14 @@
20068 # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
20069 #endif
20070 SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db);
20071 #ifndef SQLITE_OMIT_VIRTUALTABLE
20072 SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
20073 SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
20074 #else
20075 # define sqlite3ShadowTableName(A,B) 0
20076 # define sqlite3IsShadowTableOf(A,B,C) 0
20077 #endif
20078 SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
20079 SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
20080 SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
20081 SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
@@ -27730,14 +27740,16 @@
27740 if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
27741 mem0.alarmThreshold-nDiff ){
27742 sqlite3MallocAlarm(nDiff);
27743 }
27744 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27745 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
27746 if( pNew==0 && mem0.alarmThreshold>0 ){
27747 sqlite3MallocAlarm((int)nBytes);
27748 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27749 }
27750 #endif
27751 if( pNew ){
27752 nNew = sqlite3MallocSize(pNew);
27753 sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
27754 }
27755 sqlite3_mutex_leave(mem0.mutex);
@@ -27918,11 +27930,11 @@
27930 }
27931 }else{
27932 assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
27933 assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
27934 sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
27935 pNew = sqlite3Realloc(p, n);
27936 if( !pNew ){
27937 sqlite3OomFault(db);
27938 }
27939 sqlite3MemdebugSetType(pNew,
27940 (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
@@ -28265,10 +28277,17 @@
28277 #ifndef SQLITE_PRINT_BUF_SIZE
28278 # define SQLITE_PRINT_BUF_SIZE 70
28279 #endif
28280 #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
28281
28282 /*
28283 ** Hard limit on the precision of floating-point conversions.
28284 */
28285 #ifndef SQLITE_PRINTF_PRECISION_LIMIT
28286 # define SQLITE_FP_PRECISION_LIMIT 100000000
28287 #endif
28288
28289 /*
28290 ** Render a string given by "fmt" into the StrAccum object.
28291 */
28292 SQLITE_API void sqlite3_str_vappendf(
28293 sqlite3_str *pAccum, /* Accumulate results here */
@@ -28465,10 +28484,12 @@
28484 ** precision The specified precision. The default
28485 ** is -1.
28486 ** xtype The class of the conversion.
28487 ** infop Pointer to the appropriate info struct.
28488 */
28489 assert( width>=0 );
28490 assert( precision>=(-1) );
28491 switch( xtype ){
28492 case etPOINTER:
28493 flag_long = sizeof(char*)==sizeof(i64) ? 2 :
28494 sizeof(char*)==sizeof(long int) ? 1 : 0;
28495 /* Fall through into the next case */
@@ -28586,10 +28607,15 @@
28607 }
28608 #ifdef SQLITE_OMIT_FLOATING_POINT
28609 length = 0;
28610 #else
28611 if( precision<0 ) precision = 6; /* Set default precision */
28612 #ifdef SQLITE_FP_PRECISION_LIMIT
28613 if( precision>SQLITE_FP_PRECISION_LIMIT ){
28614 precision = SQLITE_FP_PRECISION_LIMIT;
28615 }
28616 #endif
28617 if( realvalue<0.0 ){
28618 realvalue = -realvalue;
28619 prefix = '-';
28620 }else{
28621 prefix = flag_prefix;
@@ -28868,11 +28894,11 @@
28894 }else{
28895 escarg = va_arg(ap,char*);
28896 }
28897 isnull = escarg==0;
28898 if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
28899 /* For %q, %Q, and %w, the precision is the number of bytes (or
28900 ** characters if the ! flags is present) to use from the input.
28901 ** Because of the extra quoting characters inserted, the number
28902 ** of output characters may be larger than the precision.
28903 */
28904 k = precision;
@@ -28995,11 +29021,11 @@
29021 p->nAlloc = (int)szNew;
29022 }
29023 if( p->db ){
29024 zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
29025 }else{
29026 zNew = sqlite3Realloc(zOld, p->nAlloc);
29027 }
29028 if( zNew ){
29029 assert( p->zText!=0 || p->nChar==0 );
29030 if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
29031 p->zText = zNew;
@@ -29337,11 +29363,11 @@
29363 ** and segfaults if you give it a long long int.
29364 */
29365 SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
29366 va_list ap;
29367 StrAccum acc;
29368 char zBuf[SQLITE_PRINT_BUF_SIZE*10];
29369 sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
29370 va_start(ap,zFormat);
29371 sqlite3_str_vappendf(&acc, zFormat, ap);
29372 va_end(ap);
29373 sqlite3StrAccumFinish(&acc);
@@ -29953,12 +29979,13 @@
29979 #else
29980 pWin = 0;
29981 #endif
29982 }
29983 if( pExpr->op==TK_AGG_FUNCTION ){
29984 sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s iAgg=%d agg=%p",
29985 pExpr->op2, pExpr->u.zToken, zFlgs,
29986 pExpr->iAgg, pExpr->pAggInfo);
29987 }else if( pExpr->op2!=0 ){
29988 const char *zOp2;
29989 char zBuf[8];
29990 sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2);
29991 zOp2 = zBuf;
@@ -30847,10 +30874,11 @@
30874 /* UTF-16 Little-endian -> UTF-8 */
30875 while( zIn<zTerm ){
30876 c = *(zIn++);
30877 c += (*(zIn++))<<8;
30878 if( c>=0xd800 && c<0xe000 ){
30879 #ifdef SQLITE_REPLACE_INVALID_UTF
30880 if( c>=0xdc00 || zIn>=zTerm ){
30881 c = 0xfffd;
30882 }else{
30883 int c2 = *(zIn++);
30884 c2 += (*(zIn++))<<8;
@@ -30859,19 +30887,27 @@
30887 c = 0xfffd;
30888 }else{
30889 c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
30890 }
30891 }
30892 #else
30893 if( zIn<zTerm ){
30894 int c2 = (*zIn++);
30895 c2 += ((*zIn++)<<8);
30896 c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
30897 }
30898 #endif
30899 }
30900 WRITE_UTF8(z, c);
30901 }
30902 }else{
30903 /* UTF-16 Big-endian -> UTF-8 */
30904 while( zIn<zTerm ){
30905 c = (*(zIn++))<<8;
30906 c += *(zIn++);
30907 if( c>=0xd800 && c<0xe000 ){
30908 #ifdef SQLITE_REPLACE_INVALID_UTF
30909 if( c>=0xdc00 || zIn>=zTerm ){
30910 c = 0xfffd;
30911 }else{
30912 int c2 = (*(zIn++))<<8;
30913 c2 += *(zIn++);
@@ -30880,10 +30916,17 @@
30916 c = 0xfffd;
30917 }else{
30918 c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
30919 }
30920 }
30921 #else
30922 if( zIn<zTerm ){
30923 int c2 = ((*zIn++)<<8);
30924 c2 += (*zIn++);
30925 c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
30926 }
30927 #endif
30928 }
30929 WRITE_UTF8(z, c);
30930 }
30931 }
30932 pMem->n = (int)(z - zOut);
@@ -34971,20 +35014,21 @@
35014 static int osSetPosixAdvisoryLock(
35015 int h, /* The file descriptor on which to take the lock */
35016 struct flock *pLock, /* The description of the lock */
35017 unixFile *pFile /* Structure holding timeout value */
35018 ){
35019 int tm = pFile->iBusyTimeout;
35020 int rc = osFcntl(h,F_SETLK,pLock);
35021 while( rc<0 && tm>0 ){
35022 /* On systems that support some kind of blocking file lock with a timeout,
35023 ** make appropriate changes here to invoke that blocking file lock. On
35024 ** generic posix, however, there is no such API. So we simply try the
35025 ** lock once every millisecond until either the timeout expires, or until
35026 ** the lock is obtained. */
35027 usleep(1000);
35028 rc = osFcntl(h,F_SETLK,pLock);
35029 tm--;
35030 }
35031 return rc;
35032 }
35033 #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
35034
@@ -37722,17 +37766,24 @@
37766
37767 /* Locks are within range */
37768 assert( n>=1 && n<=SQLITE_SHM_NLOCK );
37769
37770 if( pShmNode->hShm>=0 ){
37771 int res;
37772 /* Initialize the locking parameters */
37773 f.l_type = lockType;
37774 f.l_whence = SEEK_SET;
37775 f.l_start = ofst;
37776 f.l_len = n;
37777 res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37778 if( res==-1 ){
37779 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
37780 rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
37781 #else
37782 rc = SQLITE_BUSY;
37783 #endif
37784 }
37785 }
37786
37787 /* Update the global lock state and do debug tracing */
37788 #ifdef SQLITE_DEBUG
37789 { u16 mask;
@@ -38225,26 +38276,27 @@
38276 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
38277 assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
38278 assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
38279 assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
38280
38281 /* Check that, if this to be a blocking lock, no locks that occur later
38282 ** in the following list than the lock being obtained are already held:
38283 **
38284 ** 1. Checkpointer lock (ofst==1).
38285 ** 2. Write lock (ofst==0).
38286 ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
 
38287 **
38288 ** In other words, if this is a blocking lock, none of the locks that
38289 ** occur later in the above list than the lock being obtained may be
38290 ** held. */
38291 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
38292 assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
38293 (ofst!=2) /* not RECOVER */
38294 && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
38295 && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
38296 && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
38297 ));
38298 #endif
38299
38300 mask = (1<<(ofst+n)) - (1<<ofst);
38301 assert( n>1 || mask==(1<<ofst) );
38302 sqlite3_mutex_enter(pShmNode->pShmMutex);
@@ -45033,10 +45085,11 @@
45085 }
45086
45087 /* Forward references to VFS helper methods used for temporary files */
45088 static int winGetTempname(sqlite3_vfs *, char **);
45089 static int winIsDir(const void *);
45090 static BOOL winIsLongPathPrefix(const char *);
45091 static BOOL winIsDriveLetterAndColon(const char *);
45092
45093 /*
45094 ** Control and query of the open file handle.
45095 */
@@ -46802,11 +46855,13 @@
46855 pFile->pVfs = pVfs;
46856 pFile->h = h;
46857 if( isReadonly ){
46858 pFile->ctrlFlags |= WINFILE_RDONLY;
46859 }
46860 if( (flags & SQLITE_OPEN_MAIN_DB)
46861 && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
46862 ){
46863 pFile->ctrlFlags |= WINFILE_PSOW;
46864 }
46865 pFile->lastErrno = NO_ERROR;
46866 pFile->zPath = zName;
46867 #if SQLITE_MAX_MMAP_SIZE>0
@@ -47011,10 +47066,21 @@
47066 *pResOut = rc;
47067 OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
47068 zFilename, pResOut, *pResOut));
47069 return SQLITE_OK;
47070 }
47071
47072 /*
47073 ** Returns non-zero if the specified path name starts with the "long path"
47074 ** prefix.
47075 */
47076 static BOOL winIsLongPathPrefix(
47077 const char *zPathname
47078 ){
47079 return ( zPathname[0]=='\\' && zPathname[1]=='\\'
47080 && zPathname[2]=='?' && zPathname[3]=='\\' );
47081 }
47082
47083 /*
47084 ** Returns non-zero if the specified path name starts with a drive letter
47085 ** followed by a colon character.
47086 */
@@ -47076,14 +47142,15 @@
47142 DWORD nByte;
47143 void *zConverted;
47144 char *zOut;
47145 #endif
47146
47147 /* If this path name begins with "/X:" or "\\?\", where "X" is any
47148 ** alphabetic character, discard the initial "/" from the pathname.
47149 */
47150 if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
47151 || winIsLongPathPrefix(zRelative+1)) ){
47152 zRelative++;
47153 }
47154
47155 #if defined(__CYGWIN__)
47156 SimulateIOError( return SQLITE_ERROR );
@@ -47835,11 +47902,11 @@
47902 if( newSz>p->szMax ){
47903 return SQLITE_FULL;
47904 }
47905 newSz *= 2;
47906 if( newSz>p->szMax ) newSz = p->szMax;
47907 pNew = sqlite3Realloc(p->aData, newSz);
47908 if( pNew==0 ) return SQLITE_NOMEM;
47909 p->aData = pNew;
47910 p->szAlloc = newSz;
47911 return SQLITE_OK;
47912 }
@@ -48282,14 +48349,15 @@
48349 */
48350 SQLITE_PRIVATE int sqlite3MemdbInit(void){
48351 sqlite3_vfs *pLower = sqlite3_vfs_find(0);
48352 int sz = pLower->szOsFile;
48353 memdb_vfs.pAppData = pLower;
48354 /* The following conditional can only be true when compiled for
48355 ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
48356 ** it in, to be safe, but it is marked as NO_TEST since there
48357 ** is no way to reach it under most builds. */
48358 if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
48359 memdb_vfs.szOsFile = sz;
48360 return sqlite3_vfs_register(&memdb_vfs, 0);
48361 }
48362 #endif /* SQLITE_ENABLE_DESERIALIZE */
48363
@@ -51548,10 +51616,15 @@
51616 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
51617 #endif
51618
51619 /* Return the sqlite3_file object for the WAL file */
51620 SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
51621
51622 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
51623 SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
51624 SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
51625 #endif
51626
51627 #endif /* ifndef SQLITE_OMIT_WAL */
51628 #endif /* SQLITE_WAL_H */
51629
51630 /************** End of wal.h *************************************************/
@@ -57238,11 +57311,10 @@
57311 Pager *pPager;
57312 assert( pPg!=0 );
57313 assert( pPg->pgno==1 );
57314 assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
57315 pPager = pPg->pPager;
 
57316 sqlite3PcacheRelease(pPg);
57317 pagerUnlockIfUnused(pPager);
57318 }
57319
57320 /*
@@ -58531,20 +58603,10 @@
58603 */
58604 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
58605 return pPager->fd;
58606 }
58607
 
 
 
 
 
 
 
 
 
 
58608 /*
58609 ** Return the file handle for the journal file (if it exists).
58610 ** This will be either the rollback journal or the WAL file.
58611 */
58612 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
@@ -58954,11 +59016,10 @@
59016 (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
59017 pPager->pBusyHandlerArg,
59018 pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
59019 pnLog, pnCkpt
59020 );
 
59021 }
59022 return rc;
59023 }
59024
59025 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
@@ -59119,11 +59180,35 @@
59180 }
59181 }
59182 return rc;
59183 }
59184
59185 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59186 /*
59187 ** If pager pPager is a wal-mode database not in exclusive locking mode,
59188 ** invoke the sqlite3WalWriteLock() function on the associated Wal object
59189 ** with the same db and bLock parameters as were passed to this function.
59190 ** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
59191 */
59192 SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
59193 int rc = SQLITE_OK;
59194 if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
59195 rc = sqlite3WalWriteLock(pPager->pWal, bLock);
59196 }
59197 return rc;
59198 }
59199
59200 /*
59201 ** Set the database handle used by the wal layer to determine if
59202 ** blocking locks are required.
59203 */
59204 SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
59205 if( pagerUseWal(pPager) ){
59206 sqlite3WalDb(pPager->pWal, db);
59207 }
59208 }
59209 #endif
59210
59211 #ifdef SQLITE_ENABLE_SNAPSHOT
59212 /*
59213 ** If this is a WAL database, obtain a snapshot handle for the snapshot
59214 ** currently open. Otherwise, return an error.
@@ -59139,11 +59224,14 @@
59224 /*
59225 ** If this is a WAL database, store a pointer to pSnapshot. Next time a
59226 ** read transaction is opened, attempt to read from the snapshot it
59227 ** identifies. If this is not a WAL database, return an error.
59228 */
59229 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
59230 Pager *pPager,
59231 sqlite3_snapshot *pSnapshot
59232 ){
59233 int rc = SQLITE_OK;
59234 if( pPager->pWal ){
59235 sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
59236 }else{
59237 rc = SQLITE_ERROR;
@@ -59684,10 +59772,13 @@
59772 u8 lockError; /* True if a locking error has occurred */
59773 #endif
59774 #ifdef SQLITE_ENABLE_SNAPSHOT
59775 WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
59776 #endif
59777 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59778 sqlite3 *db;
59779 #endif
59780 };
59781
59782 /*
59783 ** Candidate values for Wal.exclusiveMode.
59784 */
@@ -59782,11 +59873,11 @@
59873
59874 /* Enlarge the pWal->apWiData[] array if required */
59875 if( pWal->nWiData<=iPage ){
59876 sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
59877 volatile u32 **apNew;
59878 apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
59879 if( !apNew ){
59880 *ppPage = 0;
59881 return SQLITE_NOMEM_BKPT;
59882 }
59883 memset((void*)&apNew[pWal->nWiData], 0,
@@ -59903,29 +59994,47 @@
59994
59995 aOut[0] = s1;
59996 aOut[1] = s2;
59997 }
59998
59999 /*
60000 ** If there is the possibility of concurrent access to the SHM file
60001 ** from multiple threads and/or processes, then do a memory barrier.
60002 */
60003 static void walShmBarrier(Wal *pWal){
60004 if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
60005 sqlite3OsShmBarrier(pWal->pDbFd);
60006 }
60007 }
60008
60009 /*
60010 ** Add the SQLITE_NO_TSAN as part of the return-type of a function
60011 ** definition as a hint that the function contains constructs that
60012 ** might give false-positive TSAN warnings.
60013 **
60014 ** See tag-20200519-1.
60015 */
60016 #if defined(__clang__) && !defined(SQLITE_NO_TSAN)
60017 # define SQLITE_NO_TSAN __attribute__((no_sanitize_thread))
60018 #else
60019 # define SQLITE_NO_TSAN
60020 #endif
60021
60022 /*
60023 ** Write the header information in pWal->hdr into the wal-index.
60024 **
60025 ** The checksum on pWal->hdr is updated before it is written.
60026 */
60027 static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){
60028 volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
60029 const int nCksum = offsetof(WalIndexHdr, aCksum);
60030
60031 assert( pWal->writeLock );
60032 pWal->hdr.isInit = 1;
60033 pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
60034 walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
60035 /* Possible TSAN false-positive. See tag-20200519-1 */
60036 memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
60037 walShmBarrier(pWal);
60038 memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
60039 }
60040
@@ -60057,11 +60166,11 @@
60166 if( pWal->exclusiveMode ) return SQLITE_OK;
60167 rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
60168 SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
60169 WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
60170 walLockName(lockIdx), rc ? "failed" : "ok"));
60171 VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
60172 return rc;
60173 }
60174 static void walUnlockShared(Wal *pWal, int lockIdx){
60175 if( pWal->exclusiveMode ) return;
60176 (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
@@ -60073,11 +60182,11 @@
60182 if( pWal->exclusiveMode ) return SQLITE_OK;
60183 rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
60184 SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
60185 WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
60186 walLockName(lockIdx), n, rc ? "failed" : "ok"));
60187 VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
60188 return rc;
60189 }
60190 static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
60191 if( pWal->exclusiveMode ) return;
60192 (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
@@ -60345,15 +60454,10 @@
60454 int rc; /* Return Code */
60455 i64 nSize; /* Size of log file */
60456 u32 aFrameCksum[2] = {0, 0};
60457 int iLock; /* Lock offset to lock for checkpoint */
60458
 
 
 
 
 
60459 /* Obtain an exclusive lock on all byte in the locking range not already
60460 ** locked by the caller. The caller is guaranteed to have locked the
60461 ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
60462 ** If successful, the same bytes that are locked here are unlocked before
60463 ** this function returns.
@@ -60897,10 +61001,93 @@
61001 p = 0;
61002 }
61003 *pp = p;
61004 return rc;
61005 }
61006
61007 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61008 /*
61009 ** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
61010 ** they are supported by the VFS, and (b) the database handle is configured
61011 ** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
61012 ** or 0 otherwise.
61013 */
61014 static int walEnableBlocking(Wal *pWal){
61015 int res = 0;
61016 if( pWal->db ){
61017 int tmout = pWal->db->busyTimeout;
61018 if( tmout ){
61019 int rc;
61020 rc = sqlite3OsFileControl(
61021 pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
61022 );
61023 res = (rc==SQLITE_OK);
61024 }
61025 }
61026 return res;
61027 }
61028
61029 /*
61030 ** Disable blocking locks.
61031 */
61032 static void walDisableBlocking(Wal *pWal){
61033 int tmout = 0;
61034 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
61035 }
61036
61037 /*
61038 ** If parameter bLock is true, attempt to enable blocking locks, take
61039 ** the WRITER lock, and then disable blocking locks. If blocking locks
61040 ** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
61041 ** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
61042 ** an error if blocking locks can not be enabled.
61043 **
61044 ** If the bLock parameter is false and the WRITER lock is held, release it.
61045 */
61046 SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){
61047 int rc = SQLITE_OK;
61048 assert( pWal->readLock<0 || bLock==0 );
61049 if( bLock ){
61050 assert( pWal->db );
61051 if( walEnableBlocking(pWal) ){
61052 rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
61053 if( rc==SQLITE_OK ){
61054 pWal->writeLock = 1;
61055 }
61056 walDisableBlocking(pWal);
61057 }
61058 }else if( pWal->writeLock ){
61059 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61060 pWal->writeLock = 0;
61061 }
61062 return rc;
61063 }
61064
61065 /*
61066 ** Set the database handle used to determine if blocking locks are required.
61067 */
61068 SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
61069 pWal->db = db;
61070 }
61071
61072 /*
61073 ** Take an exclusive WRITE lock. Blocking if so configured.
61074 */
61075 static int walLockWriter(Wal *pWal){
61076 int rc;
61077 walEnableBlocking(pWal);
61078 rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
61079 walDisableBlocking(pWal);
61080 return rc;
61081 }
61082 #else
61083 # define walEnableBlocking(x) 0
61084 # define walDisableBlocking(x)
61085 # define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
61086 # define sqlite3WalDb(pWal, db)
61087 #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
61088
61089
61090 /*
61091 ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
61092 ** n. If the attempt fails and parameter xBusy is not NULL, then it is a
61093 ** busy-handler function. Invoke it and retry the lock until either the
@@ -60915,10 +61102,16 @@
61102 ){
61103 int rc;
61104 do {
61105 rc = walLockExclusive(pWal, lockIdx, n);
61106 }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
61107 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61108 if( rc==SQLITE_BUSY_TIMEOUT ){
61109 walDisableBlocking(pWal);
61110 rc = SQLITE_BUSY;
61111 }
61112 #endif
61113 return rc;
61114 }
61115
61116 /*
61117 ** The cache of the wal-index header must be valid to call this function.
@@ -60952,11 +61145,11 @@
61145 pWal->nCkpt++;
61146 pWal->hdr.mxFrame = 0;
61147 sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
61148 memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
61149 walIndexWriteHdr(pWal);
61150 AtomicStore(&pInfo->nBackfill, 0);
61151 pInfo->nBackfillAttempted = 0;
61152 pInfo->aReadMark[1] = 0;
61153 for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
61154 assert( pInfo->aReadMark[0]==0 );
61155 }
@@ -61027,36 +61220,17 @@
61220 ** cannot be backfilled from the WAL.
61221 */
61222 mxSafeFrame = pWal->hdr.mxFrame;
61223 mxPage = pWal->hdr.nPage;
61224 for(i=1; i<WAL_NREADER; i++){
61225 u32 y = AtomicLoad(pInfo->aReadMark+i);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61226 if( mxSafeFrame>y ){
61227 assert( y<=pWal->hdr.mxFrame );
61228 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
61229 if( rc==SQLITE_OK ){
61230 u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
61231 AtomicStore(pInfo->aReadMark+i, iMark);
61232 walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
61233 }else if( rc==SQLITE_BUSY ){
61234 mxSafeFrame = y;
61235 xBusy = 0;
61236 }else{
@@ -61070,11 +61244,11 @@
61244 rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter);
61245 assert( rc==SQLITE_OK || pIter==0 );
61246 }
61247
61248 if( pIter
61249 && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
61250 ){
61251 u32 nBackfill = pInfo->nBackfill;
61252
61253 pInfo->nBackfillAttempted = mxSafeFrame;
61254
@@ -61126,11 +61300,11 @@
61300 if( rc==SQLITE_OK ){
61301 rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
61302 }
61303 }
61304 if( rc==SQLITE_OK ){
61305 AtomicStore(&pInfo->nBackfill, mxSafeFrame);
61306 }
61307 }
61308
61309 /* Release the reader lock held while backfilling */
61310 walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
@@ -61285,11 +61459,11 @@
61459 ** and *pChanged is set to 1.
61460 **
61461 ** If the checksum cannot be verified return non-zero. If the header
61462 ** is read successfully and the checksum verified, return zero.
61463 */
61464 static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
61465 u32 aCksum[2]; /* Checksum on the header content */
61466 WalIndexHdr h1, h2; /* Two copies of the header content */
61467 WalIndexHdr volatile *aHdr; /* Header in shared memory */
61468
61469 /* The first page of the wal-index must be mapped at this point. */
@@ -61298,17 +61472,23 @@
61472 /* Read the header. This might happen concurrently with a write to the
61473 ** same area of shared memory on a different CPU in a SMP,
61474 ** meaning it is possible that an inconsistent snapshot is read
61475 ** from the file. If this happens, return non-zero.
61476 **
61477 ** tag-20200519-1:
61478 ** There are two copies of the header at the beginning of the wal-index.
61479 ** When reading, read [0] first then [1]. Writes are in the reverse order.
61480 ** Memory barriers are used to prevent the compiler or the hardware from
61481 ** reordering the reads and writes. TSAN and similar tools can sometimes
61482 ** give false-positive warnings about these accesses because the tools do not
61483 ** account for the double-read and the memory barrier. The use of mutexes
61484 ** here would be problematic as the memory being accessed is potentially
61485 ** shared among multiple processes and not all mutex implementions work
61486 ** reliably in that environment.
61487 */
61488 aHdr = walIndexHdr(pWal);
61489 memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */
61490 walShmBarrier(pWal);
61491 memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
61492
61493 if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
61494 return 1; /* Dirty read */
@@ -61394,32 +61574,36 @@
61574 badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
61575
61576 /* If the first attempt failed, it might have been due to a race
61577 ** with a writer. So get a WRITE lock and try again.
61578 */
 
61579 if( badHdr ){
61580 if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
61581 if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
61582 walUnlockShared(pWal, WAL_WRITE_LOCK);
61583 rc = SQLITE_READONLY_RECOVERY;
61584 }
61585 }else{
61586 int bWriteLock = pWal->writeLock;
61587 if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
61588 pWal->writeLock = 1;
61589 if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
61590 badHdr = walIndexTryHdr(pWal, pChanged);
61591 if( badHdr ){
61592 /* If the wal-index header is still malformed even while holding
61593 ** a WRITE lock, it can only mean that the header is corrupted and
61594 ** needs to be reconstructed. So run recovery to do exactly that.
61595 */
61596 rc = walIndexRecover(pWal);
61597 *pChanged = 1;
61598 }
61599 }
61600 if( bWriteLock==0 ){
61601 pWal->writeLock = 0;
61602 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61603 }
61604 }
61605 }
61606 }
61607
61608 /* If the header is read successfully, check the version number to make
61609 ** sure the wal-index was not constructed with some future format that
@@ -61745,11 +61929,11 @@
61929 }
61930
61931 assert( pWal->nWiData>0 );
61932 assert( pWal->apWiData[0]!=0 );
61933 pInfo = walCkptInfo(pWal);
61934 if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
61935 #ifdef SQLITE_ENABLE_SNAPSHOT
61936 && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
61937 #endif
61938 ){
61939 /* The WAL has been completely backfilled (or it is empty).
@@ -61912,11 +62096,11 @@
62096 void *pBuf2 = sqlite3_malloc(szPage);
62097 if( pBuf1==0 || pBuf2==0 ){
62098 rc = SQLITE_NOMEM;
62099 }else{
62100 u32 i = pInfo->nBackfillAttempted;
62101 for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
62102 WalHashLoc sLoc; /* Hash table location */
62103 u32 pgno; /* Page number in db file */
62104 i64 iDbOff; /* Offset of db file entry */
62105 i64 iWalOff; /* Offset of wal file entry */
62106
@@ -61967,26 +62151,40 @@
62151 ** needs to be flushed.
62152 */
62153 SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
62154 int rc; /* Return code */
62155 int cnt = 0; /* Number of TryBeginRead attempts */
 
 
 
 
62156 #ifdef SQLITE_ENABLE_SNAPSHOT
62157 int bChanged = 0;
62158 WalIndexHdr *pSnapshot = pWal->pSnapshot;
 
 
 
62159 #endif
62160
62161 assert( pWal->ckptLock==0 );
62162
62163 #ifdef SQLITE_ENABLE_SNAPSHOT
62164 if( pSnapshot ){
62165 if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62166 bChanged = 1;
62167 }
62168
62169 /* It is possible that there is a checkpointer thread running
62170 ** concurrent with this code. If this is the case, it may be that the
62171 ** checkpointer has already determined that it will checkpoint
62172 ** snapshot X, where X is later in the wal file than pSnapshot, but
62173 ** has not yet set the pInfo->nBackfillAttempted variable to indicate
62174 ** its intent. To avoid the race condition this leads to, ensure that
62175 ** there is no checkpointer process by taking a shared CKPT lock
62176 ** before checking pInfo->nBackfillAttempted. */
62177 (void)walEnableBlocking(pWal);
62178 rc = walLockShared(pWal, WAL_CKPT_LOCK);
62179 walDisableBlocking(pWal);
62180
62181 if( rc!=SQLITE_OK ){
62182 return rc;
62183 }
62184 pWal->ckptLock = 1;
62185 }
62186 #endif
62187
62188 do{
62189 rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
62190 }while( rc==WAL_RETRY );
@@ -61993,20 +62191,10 @@
62191 testcase( (rc&0xff)==SQLITE_BUSY );
62192 testcase( (rc&0xff)==SQLITE_IOERR );
62193 testcase( rc==SQLITE_PROTOCOL );
62194 testcase( rc==SQLITE_OK );
62195
 
 
 
 
 
 
 
 
 
 
62196 #ifdef SQLITE_ENABLE_SNAPSHOT
62197 if( rc==SQLITE_OK ){
62198 if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62199 /* At this point the client has a lock on an aReadMark[] slot holding
62200 ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
@@ -62024,52 +62212,46 @@
62212 volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
62213
62214 assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
62215 assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
62216
62217 /* Check that the wal file has not been wrapped. Assuming that it has
62218 ** not, also check that no checkpointer has attempted to checkpoint any
62219 ** frames beyond pSnapshot->mxFrame. If either of these conditions are
62220 ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
62221 ** with *pSnapshot and set *pChanged as appropriate for opening the
62222 ** snapshot. */
62223 if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
62224 && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
62225 ){
62226 assert( pWal->readLock>0 );
62227 memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
62228 *pChanged = bChanged;
62229 }else{
62230 rc = SQLITE_ERROR_SNAPSHOT;
62231 }
62232
62233 /* A client using a non-current snapshot may not ignore any frames
62234 ** from the start of the wal file. This is because, for a system
62235 ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
62236 ** have omitted to checkpoint a frame earlier than minFrame in
62237 ** the file because there exists a frame after iSnapshot that
62238 ** is the same database page. */
62239 pWal->minFrame = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
62240
62241 if( rc!=SQLITE_OK ){
62242 sqlite3WalEndReadTransaction(pWal);
62243 }
62244 }
62245 }
62246
62247 /* Release the shared CKPT lock obtained above. */
62248 if( pWal->ckptLock ){
62249 assert( pSnapshot );
62250 walUnlockShared(pWal, WAL_CKPT_LOCK);
62251 pWal->ckptLock = 0;
62252 }
62253 #endif
62254 return rc;
62255 }
62256
62257 /*
@@ -62145,26 +62327,28 @@
62327 for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){
62328 WalHashLoc sLoc; /* Hash table location */
62329 int iKey; /* Hash slot index */
62330 int nCollide; /* Number of hash collisions remaining */
62331 int rc; /* Error code */
62332 u32 iH;
62333
62334 rc = walHashGet(pWal, iHash, &sLoc);
62335 if( rc!=SQLITE_OK ){
62336 return rc;
62337 }
62338 nCollide = HASHTABLE_NSLOT;
62339 iKey = walHash(pgno);
62340 while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
62341 u32 iFrame = iH + sLoc.iZero;
62342 if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){
62343 assert( iFrame>iRead || CORRUPT_DB );
62344 iRead = iFrame;
62345 }
62346 if( (nCollide--)==0 ){
62347 return SQLITE_CORRUPT_BKPT;
62348 }
62349 iKey = walNextHash(iKey);
62350 }
62351 if( iRead ) break;
62352 }
62353
62354 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
@@ -62235,10 +62419,20 @@
62419 **
62420 ** There can only be a single writer active at a time.
62421 */
62422 SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
62423 int rc;
62424
62425 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
62426 /* If the write-lock is already held, then it was obtained before the
62427 ** read-transaction was even opened, making this call a no-op.
62428 ** Return early. */
62429 if( pWal->writeLock ){
62430 assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
62431 return SQLITE_OK;
62432 }
62433 #endif
62434
62435 /* Cannot start a write transaction without first holding a read
62436 ** transaction. */
62437 assert( pWal->readLock>=0 );
62438 assert( pWal->writeLock==0 && pWal->iReCksum==0 );
@@ -62811,50 +63005,57 @@
63005 ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
63006 assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
63007
63008 if( pWal->readOnly ) return SQLITE_READONLY;
63009 WALTRACE(("WAL%p: checkpoint begins\n", pWal));
63010
63011 /* Enable blocking locks, if possible. If blocking locks are successfully
63012 ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
63013 sqlite3WalDb(pWal, db);
63014 (void)walEnableBlocking(pWal);
63015
63016 /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
63017 ** "checkpoint" lock on the database file.
63018 ** EVIDENCE-OF: R-10421-19736 If any other process is running a
63019 ** checkpoint operation at the same time, the lock cannot be obtained and
63020 ** SQLITE_BUSY is returned.
63021 ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
63022 ** it will not be invoked in this case.
63023 */
63024 rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
63025 testcase( rc==SQLITE_BUSY );
63026 testcase( rc!=SQLITE_OK && xBusy2!=0 );
63027 if( rc==SQLITE_OK ){
63028 pWal->ckptLock = 1;
63029
63030 /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
63031 ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
63032 ** file.
63033 **
63034 ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
63035 ** immediately, and a busy-handler is configured, it is invoked and the
63036 ** writer lock retried until either the busy-handler returns 0 or the
63037 ** lock is successfully obtained.
63038 */
63039 if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
63040 rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
63041 if( rc==SQLITE_OK ){
63042 pWal->writeLock = 1;
63043 }else if( rc==SQLITE_BUSY ){
63044 eMode2 = SQLITE_CHECKPOINT_PASSIVE;
63045 xBusy2 = 0;
63046 rc = SQLITE_OK;
63047 }
63048 }
63049 }
63050
 
 
 
 
 
 
63051
63052 /* Read the wal-index header. */
63053 if( rc==SQLITE_OK ){
63054 walDisableBlocking(pWal);
63055 rc = walIndexReadHdr(pWal, &isChanged);
63056 (void)walEnableBlocking(pWal);
63057 if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
63058 sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
63059 }
63060 }
63061
@@ -62881,16 +63082,24 @@
63082 ** next time the pager opens a snapshot on this database it knows that
63083 ** the cache needs to be reset.
63084 */
63085 memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
63086 }
63087
63088 walDisableBlocking(pWal);
63089 sqlite3WalDb(pWal, 0);
63090
63091 /* Release the locks. */
63092 sqlite3WalEndWriteTransaction(pWal);
63093 if( pWal->ckptLock ){
63094 walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
63095 pWal->ckptLock = 0;
63096 }
63097 WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
63098 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
63099 if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
63100 #endif
63101 return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
63102 }
63103
63104 /* Return the value to pass to a sqlite3_wal_hook callback, the
63105 ** number of frames in the WAL at the point of the last commit since
@@ -63003,11 +63212,14 @@
63212 return rc;
63213 }
63214
63215 /* Try to open on pSnapshot when the next read-transaction starts
63216 */
63217 SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
63218 Wal *pWal,
63219 sqlite3_snapshot *pSnapshot
63220 ){
63221 pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
63222 }
63223
63224 /*
63225 ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
@@ -63522,11 +63734,11 @@
63734 u8 incrVacuum; /* True if incr-vacuum is enabled */
63735 u8 bDoTruncate; /* True to truncate db on commit */
63736 #endif
63737 u8 inTransaction; /* Transaction state */
63738 u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
63739 u8 nReserveWanted; /* Desired number of extra bytes per page */
63740 u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
63741 u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
63742 u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
63743 u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
63744 u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
@@ -66416,12 +66628,11 @@
66628 */
66629 static int btreeInvokeBusyHandler(void *pArg){
66630 BtShared *pBt = (BtShared*)pArg;
66631 assert( pBt->db );
66632 assert( sqlite3_mutex_held(pBt->db->mutex) );
66633 return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
 
66634 }
66635
66636 /*
66637 ** Open a database file.
66638 **
@@ -66968,23 +67179,21 @@
67179 ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
67180 ** and autovacuum mode can no longer be changed.
67181 */
67182 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
67183 int rc = SQLITE_OK;
67184 int x;
67185 BtShared *pBt = p->pBt;
67186 assert( nReserve>=0 && nReserve<=255 );
67187 sqlite3BtreeEnter(p);
67188 pBt->nReserveWanted = nReserve;
67189 x = pBt->pageSize - pBt->usableSize;
67190 if( nReserve<x ) nReserve = x;
67191 if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
67192 sqlite3BtreeLeave(p);
67193 return SQLITE_READONLY;
67194 }
 
 
 
67195 assert( nReserve>=0 && nReserve<=255 );
67196 if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
67197 ((pageSize-1)&pageSize)==0 ){
67198 assert( (pageSize & 7)==0 );
67199 assert( !pBt->pCursor );
@@ -67031,16 +67240,16 @@
67240 ** The value returned is the larger of the current reserve size and
67241 ** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
67242 ** The amount of reserve can only grow - never shrink.
67243 */
67244 SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
67245 int n1, n2;
67246 sqlite3BtreeEnter(p);
67247 n1 = (int)p->pBt->nReserveWanted;
67248 n2 = sqlite3BtreeGetReserveNoMutex(p);
67249 sqlite3BtreeLeave(p);
67250 return n1>n2 ? n1 : n2;
67251 }
67252
67253
67254 /*
67255 ** Set the maximum page count for a database if mxPage is positive.
@@ -67486,10 +67695,11 @@
67695 ** when A already has a read lock, we encourage A to give up and let B
67696 ** proceed.
67697 */
67698 SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
67699 BtShared *pBt = p->pBt;
67700 Pager *pPager = pBt->pPager;
67701 int rc = SQLITE_OK;
67702
67703 sqlite3BtreeEnter(p);
67704 btreeIntegrity(p);
67705
@@ -67501,11 +67711,11 @@
67711 goto trans_begun;
67712 }
67713 assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
67714
67715 if( (p->db->flags & SQLITE_ResetDatabase)
67716 && sqlite3PagerIsreadonly(pPager)==0
67717 ){
67718 pBt->btsFlags &= ~BTS_READ_ONLY;
67719 }
67720
67721 /* Write transactions are not possible on a read-only database */
@@ -67549,10 +67759,22 @@
67759 if( SQLITE_OK!=rc ) goto trans_begun;
67760
67761 pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
67762 if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
67763 do {
67764 sqlite3PagerWalDb(pPager, p->db);
67765
67766 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67767 /* If transitioning from no transaction directly to a write transaction,
67768 ** block for the WRITER lock first if possible. */
67769 if( pBt->pPage1==0 && wrflag ){
67770 assert( pBt->inTransaction==TRANS_NONE );
67771 rc = sqlite3PagerWalWriteLock(pPager, 1);
67772 if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
67773 }
67774 #endif
67775
67776 /* Call lockBtree() until either pBt->pPage1 is populated or
67777 ** lockBtree() returns something other than SQLITE_OK. lockBtree()
67778 ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
67779 ** reading page 1 it discovers that the page-size of the database
67780 ** file is not pBt->pageSize. In this case lockBtree() will update
@@ -67562,11 +67784,11 @@
67784
67785 if( rc==SQLITE_OK && wrflag ){
67786 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
67787 rc = SQLITE_READONLY;
67788 }else{
67789 rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
67790 if( rc==SQLITE_OK ){
67791 rc = newDatabase(pBt);
67792 }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
67793 /* if there was no transaction opened when this function was
67794 ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
@@ -67575,15 +67797,19 @@
67797 }
67798 }
67799 }
67800
67801 if( rc!=SQLITE_OK ){
67802 (void)sqlite3PagerWalWriteLock(pPager, 0);
67803 unlockBtreeIfUnused(pBt);
67804 }
67805 }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
67806 btreeInvokeBusyHandler(pBt) );
67807 sqlite3PagerWalDb(pPager, 0);
67808 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67809 if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
67810 #endif
67811
67812 if( rc==SQLITE_OK ){
67813 if( p->inTrans==TRANS_NONE ){
67814 pBt->nTransaction++;
67815 #ifndef SQLITE_OMIT_SHARED_CACHE
@@ -67631,11 +67857,11 @@
67857 if( wrflag ){
67858 /* This call makes sure that the pager has the correct number of
67859 ** open savepoints. If the second parameter is greater than 0 and
67860 ** the sub-journal is not already open, then it will be opened here.
67861 */
67862 rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
67863 }
67864 }
67865
67866 btreeIntegrity(p);
67867 sqlite3BtreeLeave(p);
@@ -71267,11 +71493,11 @@
71493
71494 /* Remove cells from the start and end of the page */
71495 assert( nCell>=0 );
71496 if( iOld<iNew ){
71497 int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
71498 if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
71499 memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
71500 nCell -= nShift;
71501 }
71502 if( iNewEnd < iOldEnd ){
71503 int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
@@ -74746,11 +74972,11 @@
74972 ** Attempt to set the page size of the destination to match the page size
74973 ** of the source.
74974 */
74975 static int setDestPgsz(sqlite3_backup *p){
74976 int rc;
74977 rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
74978 return rc;
74979 }
74980
74981 /*
74982 ** Check that there is no open read-transaction on the b-tree passed as the
@@ -79143,10 +79369,11 @@
79369 char *zP4;
79370 char *zCom;
79371 sqlite3 dummyDb;
79372 static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
79373 if( pOut==0 ) pOut = stdout;
79374 sqlite3BeginBenignMalloc();
79375 dummyDb.mallocFailed = 1;
79376 zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
79377 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
79378 zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
79379 #else
@@ -79161,10 +79388,11 @@
79388 zCom ? zCom : ""
79389 );
79390 fflush(pOut);
79391 sqlite3_free(zP4);
79392 sqlite3_free(zCom);
79393 sqlite3EndBenignMalloc();
79394 }
79395 #endif
79396
79397 /*
79398 ** Initialize an array of N Mem element.
@@ -83902,11 +84130,11 @@
84130 p->db->errCode = SQLITE_OK;
84131
84132 /* If the bit corresponding to this variable in Vdbe.expmask is set, then
84133 ** binding a new value to this variable invalidates the current query plan.
84134 **
84135 ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host
84136 ** parameter in the WHERE clause might influence the choice of query plan
84137 ** for a statement, then the statement will be automatically recompiled,
84138 ** as if there had been a schema change, on the first sqlite3_step() call
84139 ** following any change to the bindings of that parameter.
84140 */
@@ -90540,16 +90768,23 @@
90768 rc = sqlite3VdbeSorterWrite(pC, pIn2);
90769 if( rc) goto abort_due_to_error;
90770 break;
90771 }
90772
90773 /* Opcode: IdxDelete P1 P2 P3 * P5
90774 ** Synopsis: key=r[P2@P3]
90775 **
90776 ** The content of P3 registers starting at register P2 form
90777 ** an unpacked index key. This opcode removes that entry from the
90778 ** index opened by cursor P1.
90779 **
90780 ** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
90781 ** if no matching index entry is found. This happens when running
90782 ** an UPDATE or DELETE statement and the index entry to be updated
90783 ** or deleted is not found. For some uses of IdxDelete
90784 ** (example: the EXCEPT operator) it does not matter that no matching
90785 ** entry is found. For those cases, P5 is zero.
90786 */
90787 case OP_IdxDelete: {
90788 VdbeCursor *pC;
90789 BtCursor *pCrsr;
90790 int res;
@@ -90562,20 +90797,22 @@
90797 assert( pC!=0 );
90798 assert( pC->eCurType==CURTYPE_BTREE );
90799 sqlite3VdbeIncrWriteCounter(p, pC);
90800 pCrsr = pC->uc.pCursor;
90801 assert( pCrsr!=0 );
 
90802 r.pKeyInfo = pC->pKeyInfo;
90803 r.nField = (u16)pOp->p3;
90804 r.default_rc = 0;
90805 r.aMem = &aMem[pOp->p2];
90806 rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
90807 if( rc ) goto abort_due_to_error;
90808 if( res==0 ){
90809 rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
90810 if( rc ) goto abort_due_to_error;
90811 }else if( pOp->p5 ){
90812 rc = SQLITE_CORRUPT_INDEX;
90813 goto abort_due_to_error;
90814 }
90815 assert( pC->deferredMoveto==0 );
90816 pC->cacheStatus = CACHE_STALE;
90817 pC->seekResult = 0;
90818 break;
@@ -96192,12 +96429,12 @@
96429 *************************************************************************
96430 **
96431 ** This file implements virtual-tables for examining the bytecode content
96432 ** of a prepared statement.
96433 */
 
96434 /* #include "sqliteInt.h" */
96435 #if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
96436 /* #include "vdbeInt.h" */
96437
96438 /* An instance of the bytecode() table-valued function.
96439 */
96440 typedef struct bytecodevtab bytecodevtab;
@@ -96598,10 +96835,12 @@
96835 if( rc==SQLITE_OK ){
96836 rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
96837 }
96838 return rc;
96839 }
96840 #elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
96841 SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
96842 #endif /* SQLITE_ENABLE_BYTECODE_VTAB */
96843
96844 /************** End of vdbevtab.c ********************************************/
96845 /************** Begin file memjournal.c **************************************/
96846 /*
@@ -97243,10 +97482,47 @@
97482 }
97483 p = p->pPrior;
97484 }while( p!=0 );
97485 return WRC_Continue;
97486 }
97487
97488 /* Increase the walkerDepth when entering a subquery, and
97489 ** descrease when leaving the subquery.
97490 */
97491 SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
97492 UNUSED_PARAMETER(pSelect);
97493 pWalker->walkerDepth++;
97494 return WRC_Continue;
97495 }
97496 SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){
97497 UNUSED_PARAMETER(pSelect);
97498 pWalker->walkerDepth--;
97499 }
97500
97501
97502 /*
97503 ** No-op routine for the parse-tree walker.
97504 **
97505 ** When this routine is the Walker.xExprCallback then expression trees
97506 ** are walked without any actions being taken at each node. Presumably,
97507 ** when this routine is used for Walker.xExprCallback then
97508 ** Walker.xSelectCallback is set to do something useful for every
97509 ** subquery in the parser tree.
97510 */
97511 SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
97512 UNUSED_PARAMETER2(NotUsed, NotUsed2);
97513 return WRC_Continue;
97514 }
97515
97516 /*
97517 ** No-op routine for the parse-tree walker for SELECT statements.
97518 ** subquery in the parser tree.
97519 */
97520 SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
97521 UNUSED_PARAMETER2(NotUsed, NotUsed2);
97522 return WRC_Continue;
97523 }
97524
97525 /************** End of walker.c **********************************************/
97526 /************** Begin file resolve.c *****************************************/
97527 /*
97528 ** 2008 August 18
@@ -97272,10 +97548,12 @@
97548 ** This needs to occur when copying a TK_AGG_FUNCTION node from an
97549 ** outer query into an inner subquery.
97550 **
97551 ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
97552 ** is a helper function - a callback for the tree walker.
97553 **
97554 ** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
97555 */
97556 static int incrAggDepth(Walker *pWalker, Expr *pExpr){
97557 if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
97558 return WRC_Continue;
97559 }
@@ -102902,10 +103180,17 @@
103180 }
103181 setDoNotMergeFlagOnCopy(v);
103182 sqlite3VdbeResolveLabel(v, endCoalesce);
103183 break;
103184 }
103185 case INLINEFUNC_iif: {
103186 Expr caseExpr;
103187 memset(&caseExpr, 0, sizeof(caseExpr));
103188 caseExpr.op = TK_CASE;
103189 caseExpr.x.pList = pFarg;
103190 return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
103191 }
103192
103193 default: {
103194 /* The UNLIKELY() function is a no-op. The result is the value
103195 ** of the first argument.
103196 */
@@ -103006,11 +103291,14 @@
103291 op = pExpr->op;
103292 }
103293 switch( op ){
103294 case TK_AGG_COLUMN: {
103295 AggInfo *pAggInfo = pExpr->pAggInfo;
103296 struct AggInfo_col *pCol;
103297 assert( pAggInfo!=0 );
103298 assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
103299 pCol = &pAggInfo->aCol[pExpr->iAgg];
103300 if( !pAggInfo->directMode ){
103301 assert( pCol->iMem>0 );
103302 return pCol->iMem;
103303 }else if( pAggInfo->useSortingIdx ){
103304 Table *pTab = pCol->pTab;
@@ -103306,11 +103594,14 @@
103594 sqlite3VdbeJumpHere(v, addr);
103595 break;
103596 }
103597 case TK_AGG_FUNCTION: {
103598 AggInfo *pInfo = pExpr->pAggInfo;
103599 if( pInfo==0
103600 || NEVER(pExpr->iAgg<0)
103601 || NEVER(pExpr->iAgg>=pInfo->nFunc)
103602 ){
103603 assert( !ExprHasProperty(pExpr, EP_IntValue) );
103604 sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
103605 }else{
103606 return pInfo->aFunc[pExpr->iAgg].iMem;
103607 }
@@ -103684,11 +103975,11 @@
103975 assert( pExpr->affExpr==OE_Rollback
103976 || pExpr->affExpr==OE_Abort
103977 || pExpr->affExpr==OE_Fail
103978 || pExpr->affExpr==OE_Ignore
103979 );
103980 if( !pParse->pTriggerTab && !pParse->nested ){
103981 sqlite3ErrorMsg(pParse,
103982 "RAISE() may only be used within a trigger-program");
103983 return 0;
103984 }
103985 if( pExpr->affExpr==OE_Abort ){
@@ -103698,12 +103989,13 @@
103989 if( pExpr->affExpr==OE_Ignore ){
103990 sqlite3VdbeAddOp4(
103991 v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
103992 VdbeCoverage(v);
103993 }else{
103994 sqlite3HaltConstraint(pParse,
103995 pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
103996 pExpr->affExpr, pExpr->u.zToken, 0, 0);
103997 }
103998
103999 break;
104000 }
104001 #endif
@@ -105061,19 +105353,10 @@
105353 }
105354 }
105355 }
105356 return WRC_Continue;
105357 }
 
 
 
 
 
 
 
 
 
105358
105359 /*
105360 ** Analyze the pExpr expression looking for aggregate functions and
105361 ** for variables that need to be added to AggInfo object that pNC->pAggInfo
105362 ** points to. Additional entries are made on the AggInfo object as
@@ -105083,12 +105366,12 @@
105366 ** analyzed by sqlite3ResolveExprNames().
105367 */
105368 SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
105369 Walker w;
105370 w.xExprCallback = analyzeAggregate;
105371 w.xSelectCallback = sqlite3WalkerDepthIncrease;
105372 w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
105373 w.walkerDepth = 0;
105374 w.u.pNC = pNC;
105375 w.pParse = 0;
105376 assert( pNC->pSrcList!=0 );
105377 sqlite3WalkExpr(&w, pExpr);
@@ -105323,11 +105606,14 @@
105606 if( !zName ) goto exit_rename_table;
105607
105608 /* Check that a table or index named 'zName' does not already exist
105609 ** in database iDb. If so, this is an error.
105610 */
105611 if( sqlite3FindTable(db, zName, zDb)
105612 || sqlite3FindIndex(db, zName, zDb)
105613 || sqlite3IsShadowTableOf(db, pTab, zName)
105614 ){
105615 sqlite3ErrorMsg(pParse,
105616 "there is already another table or index with this name: %s", zName);
105617 goto exit_rename_table;
105618 }
105619
@@ -105454,10 +105740,26 @@
105740 exit_rename_table:
105741 sqlite3SrcListDelete(db, pSrc);
105742 sqlite3DbFree(db, zName);
105743 db->mDbFlags = savedDbFlags;
105744 }
105745
105746 /*
105747 ** Write code that will raise an error if the table described by
105748 ** zDb and zTab is not empty.
105749 */
105750 static void sqlite3ErrorIfNotEmpty(
105751 Parse *pParse, /* Parsing context */
105752 const char *zDb, /* Schema holding the table */
105753 const char *zTab, /* Table to check for empty */
105754 const char *zErr /* Error message text */
105755 ){
105756 sqlite3NestedParse(pParse,
105757 "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
105758 zErr, zDb, zTab
105759 );
105760 }
105761
105762 /*
105763 ** This function is called after an "ALTER TABLE ... ADD" statement
105764 ** has been parsed. Argument pColDef contains the text of the new
105765 ** column definition.
@@ -105507,11 +105809,12 @@
105809 if( pCol->colFlags & COLFLAG_PRIMKEY ){
105810 sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
105811 return;
105812 }
105813 if( pNew->pIndex ){
105814 sqlite3ErrorMsg(pParse,
105815 "Cannot add a UNIQUE column");
105816 return;
105817 }
105818 if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
105819 /* If the default value for the new column was specified with a
105820 ** literal NULL, then set pDflt to 0. This simplifies checking
@@ -105520,19 +105823,18 @@
105823 assert( pDflt==0 || pDflt->op==TK_SPAN );
105824 if( pDflt && pDflt->pLeft->op==TK_NULL ){
105825 pDflt = 0;
105826 }
105827 if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
105828 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105829 "Cannot add a REFERENCES column with non-NULL default value");
 
105830 }
105831 if( pCol->notNull && !pDflt ){
105832 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105833 "Cannot add a NOT NULL column with default value NULL");
 
105834 }
105835
105836
105837 /* Ensure the default expression is something that sqlite3ValueFromExpr()
105838 ** can handle (i.e. not CURRENT_TIME etc.)
105839 */
105840 if( pDflt ){
@@ -105543,18 +105845,17 @@
105845 if( rc!=SQLITE_OK ){
105846 assert( db->mallocFailed == 1 );
105847 return;
105848 }
105849 if( !pVal ){
105850 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105851 "Cannot add a column with non-constant default");
105852 }
105853 sqlite3ValueFree(pVal);
105854 }
105855 }else if( pCol->colFlags & COLFLAG_STORED ){
105856 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
 
105857 }
105858
105859
105860 /* Modify the CREATE TABLE statement. */
105861 zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
@@ -110055,26 +110356,43 @@
110356 ** exists */
110357 if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
110358 return 0;
110359 }
110360 #endif
110361 if( zDatabase ){
110362 for(i=0; i<db->nDb; i++){
110363 if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
110364 }
110365 if( i>=db->nDb ){
110366 /* No match against the official names. But always match "main"
110367 ** to schema 0 as a legacy fallback. */
110368 if( sqlite3StrICmp(zDatabase,"main")==0 ){
110369 i = 0;
110370 }else{
110371 return 0;
110372 }
110373 }
110374 p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
110375 if( p==0 && i==1 && sqlite3StrICmp(zName, MASTER_NAME)==0 ){
110376 /* All temp.sqlite_master to be an alias for sqlite_temp_master */
110377 p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, TEMP_MASTER_NAME);
110378 }
110379 }else{
110380 /* Match against TEMP first */
110381 p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
110382 if( p ) return p;
110383 /* The main database is second */
110384 p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
110385 if( p ) return p;
110386 /* Attached databases are in order of attachment */
110387 for(i=2; i<db->nDb; i++){
110388 assert( sqlite3SchemaMutexHeld(db, i, 0) );
110389 p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
110390 if( p ) break;
110391 }
110392 }
110393 return p;
110394 }
110395
110396 /*
110397 ** Locate the in-memory structure that describes a particular database
110398 ** table given the name of that table and (optionally) the name of the
@@ -111874,10 +112192,32 @@
112192 assert( pPk->nColumn==j );
112193 assert( pTab->nNVCol<=j );
112194 recomputeColumnsNotIndexed(pPk);
112195 }
112196
112197
112198 #ifndef SQLITE_OMIT_VIRTUALTABLE
112199 /*
112200 ** Return true if pTab is a virtual table and zName is a shadow table name
112201 ** for that virtual table.
112202 */
112203 SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
112204 int nName; /* Length of zName */
112205 Module *pMod; /* Module for the virtual table */
112206
112207 if( !IsVirtual(pTab) ) return 0;
112208 nName = sqlite3Strlen30(pTab->zName);
112209 if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
112210 if( zName[nName]!='_' ) return 0;
112211 pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
112212 if( pMod==0 ) return 0;
112213 if( pMod->pModule->iVersion<3 ) return 0;
112214 if( pMod->pModule->xShadowName==0 ) return 0;
112215 return pMod->pModule->xShadowName(zName+nName+1);
112216 }
112217 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
112218
112219 #ifndef SQLITE_OMIT_VIRTUALTABLE
112220 /*
112221 ** Return true if zName is a shadow table name in the current database
112222 ** connection.
112223 **
@@ -111885,26 +112225,21 @@
112225 ** restored to its original value prior to this routine returning.
112226 */
112227 SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
112228 char *zTail; /* Pointer to the last "_" in zName */
112229 Table *pTab; /* Table that zName is a shadow of */
 
 
112230 zTail = strrchr(zName, '_');
112231 if( zTail==0 ) return 0;
112232 *zTail = 0;
112233 pTab = sqlite3FindTable(db, zName, 0);
112234 *zTail = '_';
112235 if( pTab==0 ) return 0;
112236 if( !IsVirtual(pTab) ) return 0;
112237 return sqlite3IsShadowTableOf(db, pTab, zName);
 
 
 
 
112238 }
112239 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
112240
112241
112242 #ifdef SQLITE_DEBUG
112243 /*
112244 ** Mark all nodes of an expression as EP_Immutable, indicating that
112245 ** they should not be changed. Expressions attached to a table or
@@ -114373,11 +114708,11 @@
114708 pParse->rc = rc;
114709 return 1;
114710 }
114711 db->aDb[1].pBt = pBt;
114712 assert( db->aDb[1].pSchema );
114713 if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
114714 sqlite3OomFault(db);
114715 return 1;
114716 }
114717 }
114718 return 0;
@@ -114484,11 +114819,11 @@
114819 char *p4, /* Error message */
114820 i8 p4type, /* P4_STATIC or P4_TRANSIENT */
114821 u8 p5Errmsg /* P5_ErrMsg type */
114822 ){
114823 Vdbe *v = sqlite3GetVdbe(pParse);
114824 assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
114825 if( onError==OE_Abort ){
114826 sqlite3MayAbort(pParse);
114827 }
114828 sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
114829 sqlite3VdbeChangeP5(v, p5Errmsg);
@@ -116197,10 +116532,11 @@
116532 VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
116533 r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
116534 &iPartIdxLabel, pPrior, r1);
116535 sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
116536 pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
116537 sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
116538 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
116539 pPrior = pIdx;
116540 }
116541 }
116542
@@ -117590,11 +117926,11 @@
117926 if( (cntExpand&(cntExpand-1))==0 ){
117927 /* Grow the size of the output buffer only on substitutions
117928 ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
117929 u8 *zOld;
117930 zOld = zOut;
117931 zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
117932 if( zOut==0 ){
117933 sqlite3_result_error_nomem(context);
117934 sqlite3_free(zOld);
117935 return;
117936 }
@@ -118287,11 +118623,11 @@
118623 FUNCTION(round, 2, 0, 0, roundFunc ),
118624 #endif
118625 FUNCTION(upper, 1, 0, 0, upperFunc ),
118626 FUNCTION(lower, 1, 0, 0, lowerFunc ),
118627 FUNCTION(hex, 1, 0, 0, hexFunc ),
118628 INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
118629 VFUNCTION(random, 0, 0, 0, randomFunc ),
118630 VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
118631 FUNCTION(nullif, 2, 0, 1, nullifFunc ),
118632 DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
118633 DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
@@ -118327,11 +118663,12 @@
118663 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
118664 FUNCTION(unknown, -1, 0, 0, unknownFunc ),
118665 #endif
118666 FUNCTION(coalesce, 1, 0, 0, 0 ),
118667 FUNCTION(coalesce, 0, 0, 0, 0 ),
118668 INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
118669 INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
118670 };
118671 #ifndef SQLITE_OMIT_ALTERTABLE
118672 sqlite3AlterFunctions();
118673 #endif
118674 sqlite3WindowFunctions();
@@ -121752,11 +122089,11 @@
122089 }
122090 if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
122091 sqlite3TableAffinity(v, pTab, regNewData+1);
122092 bAffinityDone = 1;
122093 }
122094 VdbeNoopComment((v, "prep index %s", pIdx->zName));
122095 iThisCur = iIdxCur+ix;
122096
122097
122098 /* Skip partial indices for which the WHERE clause is not true */
122099 if( pIdx->pPartIdxWhere ){
@@ -125555,11 +125892,11 @@
125892 }else{
125893 /* Malloc may fail when setting the page-size, as there is an internal
125894 ** buffer that the pager module resizes using sqlite3_realloc().
125895 */
125896 db->nextPagesize = sqlite3Atoi(zRight);
125897 if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
125898 sqlite3OomFault(db);
125899 }
125900 }
125901 break;
125902 }
@@ -133724,33 +134061,10 @@
134061 }
134062 }
134063 return WRC_Continue;
134064 }
134065
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134066 #if SQLITE_DEBUG
134067 /*
134068 ** Always assert. This xSelectCallback2 implementation proves that the
134069 ** xSelectCallback2 is never invoked.
134070 */
@@ -134917,11 +135231,11 @@
135231 sAggInfo.mxReg = pParse->nMem;
135232 if( db->mallocFailed ) goto select_end;
135233 #if SELECTTRACE_ENABLED
135234 if( sqlite3SelectTrace & 0x400 ){
135235 int ii;
135236 SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", &sAggInfo));
135237 sqlite3TreeViewSelect(0, p, 0);
135238 for(ii=0; ii<sAggInfo.nColumn; ii++){
135239 sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
135240 ii, sAggInfo.aCol[ii].iMem);
135241 sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
@@ -135193,17 +135507,19 @@
135507 **
135508 ** In practice the KeyInfo structure will not be used. It is only
135509 ** passed to keep OP_OpenRead happy.
135510 */
135511 if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
135512 if( !p->pSrc->a[0].fg.notIndexed ){
135513 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
135514 if( pIdx->bUnordered==0
135515 && pIdx->szIdxRow<pTab->szTabRow
135516 && pIdx->pPartIdxWhere==0
135517 && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
135518 ){
135519 pBest = pIdx;
135520 }
135521 }
135522 }
135523 if( pBest ){
135524 iRoot = pBest->tnum;
135525 pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
@@ -135378,11 +135694,11 @@
135694 need = nCol;
135695 }
135696 if( p->nData + need > p->nAlloc ){
135697 char **azNew;
135698 p->nAlloc = p->nAlloc*2 + need;
135699 azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
135700 if( azNew==0 ) goto malloc_failed;
135701 p->azResult = azNew;
135702 }
135703
135704 /* If this is the first row, then generate an extra row containing
@@ -135487,11 +135803,11 @@
135803 sqlite3_free_table(&res.azResult[1]);
135804 return rc;
135805 }
135806 if( res.nAlloc>res.nData ){
135807 char **azNew;
135808 azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
135809 if( azNew==0 ){
135810 sqlite3_free_table(&res.azResult[1]);
135811 db->errCode = SQLITE_NOMEM;
135812 return SQLITE_NOMEM_BKPT;
135813 }
@@ -136777,14 +137093,14 @@
137093 ** Therefore, the P4 parameter is only required if the default value for
137094 ** the column is a literal number, string or null. The sqlite3ValueFromExpr()
137095 ** function is capable of transforming these types of expressions into
137096 ** sqlite3_value objects.
137097 **
137098 ** If column as REAL affinity and the table is an ordinary b-tree table
137099 ** (not a virtual table) then the value might have been stored as an
137100 ** integer. In that case, add an OP_RealAffinity opcode to make sure
137101 ** it has been converted into REAL.
137102 */
137103 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
137104 assert( pTab!=0 );
137105 if( !pTab->pSelect ){
137106 sqlite3_value *pValue = 0;
@@ -136797,11 +137113,11 @@
137113 if( pValue ){
137114 sqlite3VdbeAppendP4(v, pValue, P4_MEM);
137115 }
137116 }
137117 #ifndef SQLITE_OMIT_FLOATING_POINT
137118 if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
137119 sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
137120 }
137121 #endif
137122 }
137123
@@ -138439,11 +138755,11 @@
138755 db->mDbFlags = saved_mDbFlags;
138756 db->flags = saved_flags;
138757 db->nChange = saved_nChange;
138758 db->nTotalChange = saved_nTotalChange;
138759 db->mTrace = saved_mTrace;
138760 sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
138761
138762 /* Currently there is an SQL level transaction open on the vacuum
138763 ** database. No locks are held on any other files (since the main file
138764 ** was committed at the btree level). So it safe to end the transaction
138765 ** by manually setting the autoCommit flag to true and detaching the
@@ -139646,11 +139962,11 @@
139962 assert( IsVirtual(pTab) );
139963 for(i=0; i<pToplevel->nVtabLock; i++){
139964 if( pTab==pToplevel->apVtabLock[i] ) return;
139965 }
139966 n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
139967 apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n);
139968 if( apVtabLock ){
139969 pToplevel->apVtabLock = apVtabLock;
139970 pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
139971 }else{
139972 sqlite3OomFault(pToplevel->db);
@@ -150938,24 +151254,47 @@
151254 ){
151255 if( pAppend ){
151256 int i;
151257 int nInit = pList ? pList->nExpr : 0;
151258 for(i=0; i<pAppend->nExpr; i++){
 
151259 Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
151260 assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
151261 if( bIntToNull && pDup ){
151262 int iDummy;
151263 Expr *pSub;
151264 for(pSub=pDup; ExprHasProperty(pSub, EP_Skip); pSub=pSub->pLeft){
151265 assert( pSub );
151266 }
151267 if( sqlite3ExprIsInteger(pSub, &iDummy) ){
151268 pSub->op = TK_NULL;
151269 pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
151270 pSub->u.zToken = 0;
151271 }
151272 }
151273 pList = sqlite3ExprListAppend(pParse, pList, pDup);
151274 if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
151275 }
151276 }
151277 return pList;
151278 }
151279
151280 /*
151281 ** When rewriting a query, if the new subquery in the FROM clause
151282 ** contains TK_AGG_FUNCTION nodes that refer to an outer query,
151283 ** then we have to increase the Expr->op2 values of those nodes
151284 ** due to the extra subquery layer that was added.
151285 **
151286 ** See also the incrAggDepth() routine in resolve.c
151287 */
151288 static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){
151289 if( pExpr->op==TK_AGG_FUNCTION
151290 && pExpr->op2>=pWalker->walkerDepth
151291 ){
151292 pExpr->op2++;
151293 }
151294 return WRC_Continue;
151295 }
151296
151297 /*
151298 ** If the SELECT statement passed as the second argument does not invoke
151299 ** any SQL window functions, this function is a no-op. Otherwise, it
151300 ** rewrites the SELECT statement so that window function xStep functions
@@ -151062,10 +151401,11 @@
151401 pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
151402 );
151403 p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
151404 if( p->pSrc ){
151405 Table *pTab2;
151406 Walker w;
151407 p->pSrc->a[0].pSelect = pSub;
151408 sqlite3SrcListAssignCursors(pParse, p->pSrc);
151409 pSub->selFlags |= SF_Expanded;
151410 pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
151411 pSub->selFlags |= (selFlags & SF_Aggregate);
@@ -151077,10 +151417,15 @@
151417 }else{
151418 memcpy(pTab, pTab2, sizeof(Table));
151419 pTab->tabFlags |= TF_Ephemeral;
151420 p->pSrc->a[0].pTab = pTab;
151421 pTab = pTab2;
151422 memset(&w, 0, sizeof(w));
151423 w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
151424 w.xSelectCallback = sqlite3WalkerDepthIncrease;
151425 w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
151426 sqlite3WalkSelect(&w, pSub);
151427 }
151428 }else{
151429 sqlite3SelectDelete(db, pSub);
151430 }
151431 if( db->mallocFailed ) rc = SQLITE_NOMEM;
@@ -160130,10 +160475,11 @@
160475 }
160476 #endif
160477 if( rc==SQLITE_OK ){
160478 sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
160479 sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
160480 sqlite3MemoryBarrier();
160481 sqlite3GlobalConfig.isInit = 1;
160482 #ifdef SQLITE_EXTRA_INIT
160483 bRunExtraInit = 1;
160484 #endif
160485 }
@@ -161431,12 +161777,11 @@
161777 ** Return non-zero to retry the lock. Return zero to stop trying
161778 ** and cause SQLite to return SQLITE_BUSY.
161779 */
161780 static int sqliteDefaultBusyCallback(
161781 void *ptr, /* Database connection */
161782 int count /* Number of times table has been busy */
 
161783 ){
161784 #if SQLITE_OS_WIN || HAVE_USLEEP
161785 /* This case is for systems that have support for sleeping for fractions of
161786 ** a second. Examples: All windows systems, unix systems with usleep() */
161787 static const u8 delays[] =
@@ -161446,35 +161791,10 @@
161791 # define NDELAY ArraySize(delays)
161792 sqlite3 *db = (sqlite3 *)ptr;
161793 int tmout = db->busyTimeout;
161794 int delay, prior;
161795
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161796 assert( count>=0 );
161797 if( count < NDELAY ){
161798 delay = delays[count];
161799 prior = totals[count];
161800 }else{
@@ -161490,11 +161810,10 @@
161810 #else
161811 /* This case for unix systems that lack usleep() support. Sleeping
161812 ** must be done in increments of whole seconds */
161813 sqlite3 *db = (sqlite3 *)ptr;
161814 int tmout = ((sqlite3 *)ptr)->busyTimeout;
 
161815 if( (count+1)*1000 > tmout ){
161816 return 0;
161817 }
161818 sqlite3OsSleep(db->pVfs, 1000000);
161819 return 1;
@@ -161508,23 +161827,14 @@
161827 ** lock on VFS file pFile.
161828 **
161829 ** If this routine returns non-zero, the lock is retried. If it
161830 ** returns 0, the operation aborts with an SQLITE_BUSY error.
161831 */
161832 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
161833 int rc;
161834 if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
161835 rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
 
 
 
 
 
 
 
 
 
161836 if( rc==0 ){
161837 p->nBusy = -1;
161838 }else{
161839 p->nBusy++;
161840 }
@@ -161545,11 +161855,10 @@
161855 #endif
161856 sqlite3_mutex_enter(db->mutex);
161857 db->busyHandler.xBusyHandler = xBusy;
161858 db->busyHandler.pBusyArg = pArg;
161859 db->busyHandler.nBusy = 0;
 
161860 db->busyTimeout = 0;
161861 sqlite3_mutex_leave(db->mutex);
161862 return SQLITE_OK;
161863 }
161864
@@ -161596,11 +161905,10 @@
161905 #endif
161906 if( ms>0 ){
161907 sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
161908 (void*)db);
161909 db->busyTimeout = ms;
 
161910 }else{
161911 sqlite3_busy_handler(db, 0, 0);
161912 }
161913 return SQLITE_OK;
161914 }
@@ -163071,10 +163379,13 @@
163379 | SQLITE_EnableQPSG
163380 #endif
163381 #if defined(SQLITE_DEFAULT_DEFENSIVE)
163382 | SQLITE_Defensive
163383 #endif
163384 #if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
163385 | SQLITE_LegacyAlter
163386 #endif
163387 ;
163388 sqlite3HashInit(&db->aCollSeq);
163389 #ifndef SQLITE_OMIT_VIRTUALTABLE
163390 sqlite3HashInit(&db->aModule);
163391 #endif
@@ -163113,11 +163424,11 @@
163424 assert( SQLITE_OPEN_CREATE == 0x04 );
163425 testcase( (1<<(flags&7))==0x02 ); /* READONLY */
163426 testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
163427 testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
163428 if( ((1<<(flags&7)) & 0x46)==0 ){
163429 rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
163430 }else{
163431 rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
163432 }
163433 if( rc!=SQLITE_OK ){
163434 if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
@@ -163668,11 +163979,11 @@
163979 *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
163980 rc = SQLITE_OK;
163981 }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
163982 int iNew = *(int*)pArg;
163983 *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
163984 if( iNew>=0 && iNew<=255 ){
163985 sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
163986 }
163987 rc = SQLITE_OK;
163988 }else{
163989 rc = sqlite3OsFileControl(fd, op, pArg);
@@ -167905,11 +168216,13 @@
168216 static void fts3ReadNextPos(
168217 char **pp, /* IN/OUT: Pointer into position-list buffer */
168218 sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
168219 ){
168220 if( (**pp)&0xFE ){
168221 int iVal;
168222 *pp += fts3GetVarint32((*pp), &iVal);
168223 *pi += iVal;
168224 *pi -= 2;
168225 }else{
168226 *pi = POSITION_LIST_END;
168227 }
168228 }
@@ -171035,10 +171348,11 @@
171348 while( *pRc==SQLITE_OK && pLeft->bEof==0 ){
171349 memset(pDl->pList, 0, pDl->nList);
171350 fts3EvalNextRow(pCsr, pLeft, pRc);
171351 }
171352 }
171353 pRight->bEof = pLeft->bEof = 1;
171354 }
171355 }
171356 break;
171357 }
171358
@@ -182580,11 +182894,11 @@
182894 iStart = pExpr->iPhrase * p->nCol;
182895 }else{
182896 iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
182897 }
182898
182899 if( pIter ) while( 1 ){
182900 int nHit = fts3ColumnlistCount(&pIter);
182901 if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
182902 if( p->flag==FTS3_MATCHINFO_LHITS ){
182903 p->aMatchinfo[iStart + iCol] = (u32)nHit;
182904 }else if( nHit ){
@@ -184494,10 +184808,11 @@
184808 }
184809
184810 /* Append N bytes from zIn onto the end of the JsonString string.
184811 */
184812 static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
184813 if( N==0 ) return;
184814 if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
184815 memcpy(p->zBuf+p->nUsed, zIn, N);
184816 p->nUsed += N;
184817 }
184818
@@ -224505,11 +224820,11 @@
224820 int nArg, /* Number of args */
224821 sqlite3_value **apUnused /* Function arguments */
224822 ){
224823 assert( nArg==0 );
224824 UNUSED_PARAM2(nArg, apUnused);
224825 sqlite3_result_text(pCtx, "fts5: 2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350", -1, SQLITE_TRANSIENT);
224826 }
224827
224828 /*
224829 ** Return true if zName is the extension on one of the shadow tables used
224830 ** by this module.
@@ -229288,12 +229603,12 @@
229603 }
229604 #endif /* SQLITE_CORE */
229605 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
229606
229607 /************** End of stmt.c ************************************************/
229608 #if __LINE__!=229608
229609 #undef SQLITE_SOURCE_ID
229610 #define SQLITE_SOURCE_ID "2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba8alt2"
229611 #endif
229612 /* Return the source-id for this library */
229613 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
229614 /************************** End of sqlite3.c ******************************/
229615
+6 -4
--- 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.32.0"
127
-#define SQLITE_VERSION_NUMBER 3032000
128
-#define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda"
126
+#define SQLITE_VERSION "3.32.1"
127
+#define SQLITE_VERSION_NUMBER 3032001
128
+#define SQLITE_SOURCE_ID "2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350"
129129
130130
/*
131131
** CAPI3REF: Run-Time Library Version Numbers
132132
** KEYWORDS: sqlite3_version sqlite3_sourceid
133133
**
@@ -506,18 +506,20 @@
506506
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
507507
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
508508
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
509509
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
510510
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
511
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
511512
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
512513
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
513514
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
514515
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
515516
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
516517
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
517518
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
518519
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
520
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
519521
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
520522
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
521523
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
522524
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
523525
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
@@ -5491,11 +5493,11 @@
54915493
** when first called if N is less than or equal to zero or if a memory
54925494
** allocate error occurs.
54935495
**
54945496
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
54955497
** determined by the N parameter on first successful call. Changing the
5496
-** value of N in any subsequents call to sqlite3_aggregate_context() within
5498
+** value of N in any subsequent call to sqlite3_aggregate_context() within
54975499
** the same aggregate function instance will not resize the memory
54985500
** allocation.)^ Within the xFinal callback, it is customary to set
54995501
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
55005502
** pointless memory allocations occur.
55015503
**
55025504
--- 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.32.0"
127 #define SQLITE_VERSION_NUMBER 3032000
128 #define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
@@ -506,18 +506,20 @@
506 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
507 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
508 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
509 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
510 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
 
511 #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
512 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
513 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
514 #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
515 #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
516 #define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
517 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
518 #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
 
519 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
520 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
521 #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
522 #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
523 #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
@@ -5491,11 +5493,11 @@
5491 ** when first called if N is less than or equal to zero or if a memory
5492 ** allocate error occurs.
5493 **
5494 ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
5495 ** determined by the N parameter on first successful call. Changing the
5496 ** value of N in any subsequents call to sqlite3_aggregate_context() within
5497 ** the same aggregate function instance will not resize the memory
5498 ** allocation.)^ Within the xFinal callback, it is customary to set
5499 ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
5500 ** pointless memory allocations occur.
5501 **
5502
--- 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.32.1"
127 #define SQLITE_VERSION_NUMBER 3032001
128 #define SQLITE_SOURCE_ID "2020-05-25 16:19:56 0c1fcf4711a2e66c813aed38cf41cd3e2123ee8eb6db98118086764c4ba83350"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
@@ -506,18 +506,20 @@
506 #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
507 #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
508 #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
509 #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
510 #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
511 #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
512 #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
513 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
514 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
515 #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
516 #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
517 #define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
518 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
519 #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
520 #define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
521 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
522 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
523 #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
524 #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
525 #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
@@ -5491,11 +5493,11 @@
5493 ** when first called if N is less than or equal to zero or if a memory
5494 ** allocate error occurs.
5495 **
5496 ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
5497 ** determined by the N parameter on first successful call. Changing the
5498 ** value of N in any subsequent call to sqlite3_aggregate_context() within
5499 ** the same aggregate function instance will not resize the memory
5500 ** allocation.)^ Within the xFinal callback, it is customary to set
5501 ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
5502 ** pointless memory allocations occur.
5503 **
5504
+2 -1
--- src/style.c
+++ src/style.c
@@ -707,11 +707,11 @@
707707
708708
/*
709709
** Generate code to load a single javascript file
710710
*/
711711
void style_load_one_js_file(const char *zFile){
712
- @ <script src='%R/builtin/%s(zFile)?id=%S(MANIFEST_UUID)'></script>
712
+ @ <script src='%R/builtin/%s(zFile)?id=%S(fossil_exe_id())'></script>
713713
}
714714
715715
/*
716716
** All extra JS files to load.
717717
*/
@@ -1259,10 +1259,11 @@
12591259
@ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
12601260
}
12611261
@ g.zRepositoryName = %h(g.zRepositoryName)<br />
12621262
@ load_average() = %f(load_average())<br />
12631263
@ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
1264
+ @ fossil_exe_id() = %h(fossil_exe_id())<br />
12641265
@ <hr />
12651266
P("HTTP_USER_AGENT");
12661267
cgi_print_all(showAll, 0);
12671268
if( showAll && blob_size(&g.httpHeader)>0 ){
12681269
@ <hr />
12691270
--- src/style.c
+++ src/style.c
@@ -707,11 +707,11 @@
707
708 /*
709 ** Generate code to load a single javascript file
710 */
711 void style_load_one_js_file(const char *zFile){
712 @ <script src='%R/builtin/%s(zFile)?id=%S(MANIFEST_UUID)'></script>
713 }
714
715 /*
716 ** All extra JS files to load.
717 */
@@ -1259,10 +1259,11 @@
1259 @ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
1260 }
1261 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
1262 @ load_average() = %f(load_average())<br />
1263 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
 
1264 @ <hr />
1265 P("HTTP_USER_AGENT");
1266 cgi_print_all(showAll, 0);
1267 if( showAll && blob_size(&g.httpHeader)>0 ){
1268 @ <hr />
1269
--- src/style.c
+++ src/style.c
@@ -707,11 +707,11 @@
707
708 /*
709 ** Generate code to load a single javascript file
710 */
711 void style_load_one_js_file(const char *zFile){
712 @ <script src='%R/builtin/%s(zFile)?id=%S(fossil_exe_id())'></script>
713 }
714
715 /*
716 ** All extra JS files to load.
717 */
@@ -1259,10 +1259,11 @@
1259 @ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
1260 }
1261 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
1262 @ load_average() = %f(load_average())<br />
1263 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
1264 @ fossil_exe_id() = %h(fossil_exe_id())<br />
1265 @ <hr />
1266 P("HTTP_USER_AGENT");
1267 cgi_print_all(showAll, 0);
1268 if( showAll && blob_size(&g.httpHeader)>0 ){
1269 @ <hr />
1270
+19 -8
--- src/terminal.c
+++ src/terminal.c
@@ -51,12 +51,11 @@
5151
** Under Linux/bash the size info is also available from env $LINES, $COLUMNS.
5252
** Or it can be queried using tput `echo -e "lines\ncols"|tput -S`.
5353
** Technically, this info could be cached, but then we'd need to handle
5454
** SIGWINCH signal to requery the terminal on resize event.
5555
*/
56
-int terminal_get_size(struct TerminalSize *t)
57
-{
56
+int terminal_get_size(TerminalSize *t){
5857
memset(t, 0, sizeof(*t));
5958
6059
#if defined(TIOCGSIZE)
6160
{
6261
struct ttysize ts;
@@ -94,13 +93,12 @@
9493
9594
/*
9695
** Return the terminal's current width in columns when available, otherwise
9796
** return the specified default value.
9897
*/
99
-unsigned int terminal_get_width(unsigned int nDefault)
100
-{
101
- struct TerminalSize ts;
98
+unsigned int terminal_get_width(unsigned int nDefault){
99
+ TerminalSize ts;
102100
if( terminal_get_size(&ts) ){
103101
return ts.nColumns;
104102
}
105103
return nDefault;
106104
}
@@ -107,13 +105,26 @@
107105
108106
/*
109107
** Return the terminal's current height in lines when available, otherwise
110108
** return the specified default value.
111109
*/
112
-unsigned int terminal_get_height(unsigned int nDefault)
113
-{
114
- struct TerminalSize ts;
110
+unsigned int terminal_get_height(unsigned int nDefault){
111
+ TerminalSize ts;
115112
if( terminal_get_size(&ts) ){
116113
return ts.nLines;
117114
}
118115
return nDefault;
119116
}
117
+
118
+/*
119
+** COMMAND: test-terminal-size
120
+**
121
+** Show the size of the terminal window from which the command is launched
122
+** as two integers, the width in charaters and the height in lines.
123
+**
124
+** If the size cannot be determined, two zeros are shown.
125
+*/
126
+void test_terminal_size_cmd(void){
127
+ TerminalSize ts;
128
+ terminal_get_size(&ts);
129
+ fossil_print("%d %d\n", ts.nColumns, ts.nLines);
130
+}
120131
--- src/terminal.c
+++ src/terminal.c
@@ -51,12 +51,11 @@
51 ** Under Linux/bash the size info is also available from env $LINES, $COLUMNS.
52 ** Or it can be queried using tput `echo -e "lines\ncols"|tput -S`.
53 ** Technically, this info could be cached, but then we'd need to handle
54 ** SIGWINCH signal to requery the terminal on resize event.
55 */
56 int terminal_get_size(struct TerminalSize *t)
57 {
58 memset(t, 0, sizeof(*t));
59
60 #if defined(TIOCGSIZE)
61 {
62 struct ttysize ts;
@@ -94,13 +93,12 @@
94
95 /*
96 ** Return the terminal's current width in columns when available, otherwise
97 ** return the specified default value.
98 */
99 unsigned int terminal_get_width(unsigned int nDefault)
100 {
101 struct TerminalSize ts;
102 if( terminal_get_size(&ts) ){
103 return ts.nColumns;
104 }
105 return nDefault;
106 }
@@ -107,13 +105,26 @@
107
108 /*
109 ** Return the terminal's current height in lines when available, otherwise
110 ** return the specified default value.
111 */
112 unsigned int terminal_get_height(unsigned int nDefault)
113 {
114 struct TerminalSize ts;
115 if( terminal_get_size(&ts) ){
116 return ts.nLines;
117 }
118 return nDefault;
119 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
--- src/terminal.c
+++ src/terminal.c
@@ -51,12 +51,11 @@
51 ** Under Linux/bash the size info is also available from env $LINES, $COLUMNS.
52 ** Or it can be queried using tput `echo -e "lines\ncols"|tput -S`.
53 ** Technically, this info could be cached, but then we'd need to handle
54 ** SIGWINCH signal to requery the terminal on resize event.
55 */
56 int terminal_get_size(TerminalSize *t){
 
57 memset(t, 0, sizeof(*t));
58
59 #if defined(TIOCGSIZE)
60 {
61 struct ttysize ts;
@@ -94,13 +93,12 @@
93
94 /*
95 ** Return the terminal's current width in columns when available, otherwise
96 ** return the specified default value.
97 */
98 unsigned int terminal_get_width(unsigned int nDefault){
99 TerminalSize ts;
 
100 if( terminal_get_size(&ts) ){
101 return ts.nColumns;
102 }
103 return nDefault;
104 }
@@ -107,13 +105,26 @@
105
106 /*
107 ** Return the terminal's current height in lines when available, otherwise
108 ** return the specified default value.
109 */
110 unsigned int terminal_get_height(unsigned int nDefault){
111 TerminalSize ts;
 
112 if( terminal_get_size(&ts) ){
113 return ts.nLines;
114 }
115 return nDefault;
116 }
117
118 /*
119 ** COMMAND: test-terminal-size
120 **
121 ** Show the size of the terminal window from which the command is launched
122 ** as two integers, the width in charaters and the height in lines.
123 **
124 ** If the size cannot be determined, two zeros are shown.
125 */
126 void test_terminal_size_cmd(void){
127 TerminalSize ts;
128 terminal_get_size(&ts);
129 fossil_print("%d %d\n", ts.nColumns, ts.nLines);
130 }
131
+1 -1
--- src/th_main.c
+++ src/th_main.c
@@ -1500,11 +1500,11 @@
15001500
if( argc!=3 ){
15011501
return Th_WrongNumArgs(interp, "unversioned content FILENAME");
15021502
}
15031503
if( Th_IsRepositoryOpen() ){
15041504
Blob content;
1505
- if( unversioned_content(argv[2], &content)==0 ){
1505
+ if( unversioned_content(argv[2], &content)!=0 ){
15061506
Th_SetResult(interp, blob_str(&content), blob_size(&content));
15071507
blob_reset(&content);
15081508
return TH_OK;
15091509
}else{
15101510
return TH_ERROR;
15111511
--- src/th_main.c
+++ src/th_main.c
@@ -1500,11 +1500,11 @@
1500 if( argc!=3 ){
1501 return Th_WrongNumArgs(interp, "unversioned content FILENAME");
1502 }
1503 if( Th_IsRepositoryOpen() ){
1504 Blob content;
1505 if( unversioned_content(argv[2], &content)==0 ){
1506 Th_SetResult(interp, blob_str(&content), blob_size(&content));
1507 blob_reset(&content);
1508 return TH_OK;
1509 }else{
1510 return TH_ERROR;
1511
--- src/th_main.c
+++ src/th_main.c
@@ -1500,11 +1500,11 @@
1500 if( argc!=3 ){
1501 return Th_WrongNumArgs(interp, "unversioned content FILENAME");
1502 }
1503 if( Th_IsRepositoryOpen() ){
1504 Blob content;
1505 if( unversioned_content(argv[2], &content)!=0 ){
1506 Th_SetResult(interp, blob_str(&content), blob_size(&content));
1507 blob_reset(&content);
1508 return TH_OK;
1509 }else{
1510 return TH_ERROR;
1511
+13 -1
--- src/timeline.c
+++ src/timeline.c
@@ -1312,11 +1312,11 @@
13121312
){
13131313
if( zChng==0 || zChng[0]==0 ) return;
13141314
blob_append_sql(pSql," AND event.objid IN ("
13151315
"SELECT mlink.mid FROM mlink, filename"
13161316
" WHERE mlink.fnid=filename.fnid AND %s)",
1317
- glob_expr("filename.name", zChng));
1317
+ glob_expr("filename.name", mprintf("\"%s\"", zChng)));
13181318
}
13191319
static void addFileGlobDescription(
13201320
const char *zChng, /* The filename GLOB list */
13211321
Blob *pDescription /* Result description */
13221322
){
@@ -1742,10 +1742,11 @@
17421742
|| (bisectLocal && !g.perm.Setup)
17431743
){
17441744
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
17451745
return;
17461746
}
1747
+ etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA, 0);
17471748
cookie_read_parameter("y","y");
17481749
zType = P("y");
17491750
if( zType==0 ){
17501751
zType = g.perm.Read ? "ci" : "all";
17511752
cgi_set_parameter("y", zType);
@@ -1795,10 +1796,11 @@
17951796
}else if( fossil_stricmp(zMatchStyle, "regexp")==0 ){
17961797
matchStyle = MS_REGEXP;
17971798
}else{
17981799
/* For exact maching, inhibit links to the selected tag. */
17991800
zThisTag = zTagName;
1801
+ Th_Store("current_checkin", zTagName);
18001802
}
18011803
18021804
/* Display a checkbox to enable/disable display of related check-ins. */
18031805
if( advancedMenu ){
18041806
style_submenu_checkbox("rel", "Related", 0, 0);
@@ -2200,10 +2202,17 @@
22002202
"CREATE TEMP TABLE selected_nodes(rid INTEGER PRIMARY KEY);"
22012203
"INSERT OR IGNORE INTO selected_nodes"
22022204
" SELECT tagxref.rid FROM tagxref NATURAL JOIN tag"
22032205
" WHERE %s AND tagtype>0", zTagSql/*safe-for-%s*/
22042206
);
2207
+ if( zMark ){
2208
+ /* If the t=release option is used with m=UUID, then also
2209
+ ** include the UUID check-in in the display list */
2210
+ int ridMark = name_to_rid(zMark);
2211
+ db_multi_exec(
2212
+ "INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridMark);
2213
+ }
22052214
if( !related ){
22062215
blob_append_sql(&cond, " AND blob.rid IN selected_nodes");
22072216
}else{
22082217
db_multi_exec(
22092218
"CREATE TEMP TABLE related_nodes(rid INTEGER PRIMARY KEY);"
@@ -2426,10 +2435,13 @@
24262435
blob_appendf(&desc, " related to tags matching %h", zMatchDesc);
24272436
}else{
24282437
blob_appendf(&desc, " with tags matching %h", zMatchDesc);
24292438
}
24302439
}
2440
+ if( zMark ){
2441
+ blob_appendf(&desc," plus check-in \"%h\"", zMark);
2442
+ }
24312443
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
24322444
}
24332445
addFileGlobDescription(zChng, &desc);
24342446
if( rAfter>0.0 ){
24352447
if( rBefore>0.0 ){
24362448
--- src/timeline.c
+++ src/timeline.c
@@ -1312,11 +1312,11 @@
1312 ){
1313 if( zChng==0 || zChng[0]==0 ) return;
1314 blob_append_sql(pSql," AND event.objid IN ("
1315 "SELECT mlink.mid FROM mlink, filename"
1316 " WHERE mlink.fnid=filename.fnid AND %s)",
1317 glob_expr("filename.name", zChng));
1318 }
1319 static void addFileGlobDescription(
1320 const char *zChng, /* The filename GLOB list */
1321 Blob *pDescription /* Result description */
1322 ){
@@ -1742,10 +1742,11 @@
1742 || (bisectLocal && !g.perm.Setup)
1743 ){
1744 login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
1745 return;
1746 }
 
1747 cookie_read_parameter("y","y");
1748 zType = P("y");
1749 if( zType==0 ){
1750 zType = g.perm.Read ? "ci" : "all";
1751 cgi_set_parameter("y", zType);
@@ -1795,10 +1796,11 @@
1795 }else if( fossil_stricmp(zMatchStyle, "regexp")==0 ){
1796 matchStyle = MS_REGEXP;
1797 }else{
1798 /* For exact maching, inhibit links to the selected tag. */
1799 zThisTag = zTagName;
 
1800 }
1801
1802 /* Display a checkbox to enable/disable display of related check-ins. */
1803 if( advancedMenu ){
1804 style_submenu_checkbox("rel", "Related", 0, 0);
@@ -2200,10 +2202,17 @@
2200 "CREATE TEMP TABLE selected_nodes(rid INTEGER PRIMARY KEY);"
2201 "INSERT OR IGNORE INTO selected_nodes"
2202 " SELECT tagxref.rid FROM tagxref NATURAL JOIN tag"
2203 " WHERE %s AND tagtype>0", zTagSql/*safe-for-%s*/
2204 );
 
 
 
 
 
 
 
2205 if( !related ){
2206 blob_append_sql(&cond, " AND blob.rid IN selected_nodes");
2207 }else{
2208 db_multi_exec(
2209 "CREATE TEMP TABLE related_nodes(rid INTEGER PRIMARY KEY);"
@@ -2426,10 +2435,13 @@
2426 blob_appendf(&desc, " related to tags matching %h", zMatchDesc);
2427 }else{
2428 blob_appendf(&desc, " with tags matching %h", zMatchDesc);
2429 }
2430 }
 
 
 
2431 tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
2432 }
2433 addFileGlobDescription(zChng, &desc);
2434 if( rAfter>0.0 ){
2435 if( rBefore>0.0 ){
2436
--- src/timeline.c
+++ src/timeline.c
@@ -1312,11 +1312,11 @@
1312 ){
1313 if( zChng==0 || zChng[0]==0 ) return;
1314 blob_append_sql(pSql," AND event.objid IN ("
1315 "SELECT mlink.mid FROM mlink, filename"
1316 " WHERE mlink.fnid=filename.fnid AND %s)",
1317 glob_expr("filename.name", mprintf("\"%s\"", zChng)));
1318 }
1319 static void addFileGlobDescription(
1320 const char *zChng, /* The filename GLOB list */
1321 Blob *pDescription /* Result description */
1322 ){
@@ -1742,10 +1742,11 @@
1742 || (bisectLocal && !g.perm.Setup)
1743 ){
1744 login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
1745 return;
1746 }
1747 etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA, 0);
1748 cookie_read_parameter("y","y");
1749 zType = P("y");
1750 if( zType==0 ){
1751 zType = g.perm.Read ? "ci" : "all";
1752 cgi_set_parameter("y", zType);
@@ -1795,10 +1796,11 @@
1796 }else if( fossil_stricmp(zMatchStyle, "regexp")==0 ){
1797 matchStyle = MS_REGEXP;
1798 }else{
1799 /* For exact maching, inhibit links to the selected tag. */
1800 zThisTag = zTagName;
1801 Th_Store("current_checkin", zTagName);
1802 }
1803
1804 /* Display a checkbox to enable/disable display of related check-ins. */
1805 if( advancedMenu ){
1806 style_submenu_checkbox("rel", "Related", 0, 0);
@@ -2200,10 +2202,17 @@
2202 "CREATE TEMP TABLE selected_nodes(rid INTEGER PRIMARY KEY);"
2203 "INSERT OR IGNORE INTO selected_nodes"
2204 " SELECT tagxref.rid FROM tagxref NATURAL JOIN tag"
2205 " WHERE %s AND tagtype>0", zTagSql/*safe-for-%s*/
2206 );
2207 if( zMark ){
2208 /* If the t=release option is used with m=UUID, then also
2209 ** include the UUID check-in in the display list */
2210 int ridMark = name_to_rid(zMark);
2211 db_multi_exec(
2212 "INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridMark);
2213 }
2214 if( !related ){
2215 blob_append_sql(&cond, " AND blob.rid IN selected_nodes");
2216 }else{
2217 db_multi_exec(
2218 "CREATE TEMP TABLE related_nodes(rid INTEGER PRIMARY KEY);"
@@ -2426,10 +2435,13 @@
2435 blob_appendf(&desc, " related to tags matching %h", zMatchDesc);
2436 }else{
2437 blob_appendf(&desc, " with tags matching %h", zMatchDesc);
2438 }
2439 }
2440 if( zMark ){
2441 blob_appendf(&desc," plus check-in \"%h\"", zMark);
2442 }
2443 tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
2444 }
2445 addFileGlobDescription(zChng, &desc);
2446 if( rAfter>0.0 ){
2447 if( rBefore>0.0 ){
2448
--- src/unversioned.c
+++ src/unversioned.c
@@ -85,25 +85,40 @@
8585
}
8686
8787
/*
8888
** Initialize pContent to be the content of an unversioned file zName.
8989
**
90
-** Return 0 on success. Return 1 if zName is not found.
90
+** Return 0 on failures.
91
+** Return 1 if the file is found by name.
92
+** Return 2 if the file is found by hash.
9193
*/
9294
int unversioned_content(const char *zName, Blob *pContent){
9395
Stmt q;
94
- int rc = 1;
96
+ int rc = 0;
9597
blob_init(pContent, 0, 0);
96
- db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE name=%Q", zName);
98
+ db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE name=%Q",
99
+ zName);
97100
if( db_step(&q)==SQLITE_ROW ){
98101
db_column_blob(&q, 1, pContent);
99102
if( db_column_int(&q, 0)==1 ){
100103
blob_uncompress(pContent, pContent);
101104
}
102
- rc = 0;
105
+ rc = 1;
103106
}
104107
db_finalize(&q);
108
+ if( rc==0 && validate16(zName,-1) ){
109
+ db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE hash=%Q",
110
+ zName);
111
+ if( db_step(&q)==SQLITE_ROW ){
112
+ db_column_blob(&q, 1, pContent);
113
+ if( db_column_int(&q, 0)==1 ){
114
+ blob_uncompress(pContent, pContent);
115
+ }
116
+ rc = 2;
117
+ }
118
+ db_finalize(&q);
119
+ }
105120
return rc;
106121
}
107122
108123
/*
109124
** Write unversioned content into the database.
@@ -328,11 +343,11 @@
328343
int i;
329344
verify_all_options();
330345
db_begin_transaction();
331346
for(i=3; i<g.argc; i++){
332347
Blob content;
333
- if( unversioned_content(g.argv[i], &content)==0 ){
348
+ if( unversioned_content(g.argv[i], &content)!=0 ){
334349
blob_write_to_file(&content, "-");
335350
}
336351
blob_reset(&content);
337352
}
338353
db_end_transaction(0);
@@ -352,11 +367,11 @@
352367
}
353368
zTFile = fossil_temp_filename();
354369
if( zTFile==0 ) fossil_fatal("cannot find a temporary filename");
355370
db_begin_transaction();
356371
content_rcvid_init("#!fossil unversioned edit");
357
- if( unversioned_content(zUVFile, &content) ){
372
+ if( unversioned_content(zUVFile, &content)==0 ){
358373
fossil_fatal("no such uv-file: %Q", zUVFile);
359374
}
360375
if( looks_like_binary(&content) ){
361376
fossil_fatal("cannot edit binary content");
362377
}
@@ -381,11 +396,11 @@
381396
blob_reset(&content);
382397
}else if( memcmp(zCmd, "export", nCmd)==0 ){
383398
Blob content;
384399
verify_all_options();
385400
if( g.argc!=5 ) usage("export UVFILE OUTPUT");
386
- if( unversioned_content(g.argv[3], &content) ){
401
+ if( unversioned_content(g.argv[3], &content)==0 ){
387402
fossil_fatal("no such uv-file: %Q", g.argv[3]);
388403
}
389404
blob_write_to_file(&content, g.argv[4]);
390405
blob_reset(&content);
391406
}else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */
@@ -524,10 +539,11 @@
524539
int showDel = 0;
525540
char zSzName[100];
526541
527542
login_check_credentials();
528543
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
544
+ etag_check(ETAG_DATA,0);
529545
style_header("Unversioned Files");
530546
if( !db_table_exists("repository","unversioned") ){
531547
@ No unversioned files on this server
532548
style_footer();
533549
return;
@@ -636,10 +652,11 @@
636652
Blob json;
637653
638654
login_check_credentials();
639655
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
640656
cgi_set_content_type("text/json");
657
+ etag_check(ETAG_DATA,0);
641658
if( !db_table_exists("repository","unversioned") ){
642659
blob_init(&json, "[]", -1);
643660
cgi_set_content(&json);
644661
return;
645662
}
646663
647664
ADDED test/subdir with spaces/filename with spaces.txt
--- src/unversioned.c
+++ src/unversioned.c
@@ -85,25 +85,40 @@
85 }
86
87 /*
88 ** Initialize pContent to be the content of an unversioned file zName.
89 **
90 ** Return 0 on success. Return 1 if zName is not found.
 
 
91 */
92 int unversioned_content(const char *zName, Blob *pContent){
93 Stmt q;
94 int rc = 1;
95 blob_init(pContent, 0, 0);
96 db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE name=%Q", zName);
 
97 if( db_step(&q)==SQLITE_ROW ){
98 db_column_blob(&q, 1, pContent);
99 if( db_column_int(&q, 0)==1 ){
100 blob_uncompress(pContent, pContent);
101 }
102 rc = 0;
103 }
104 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
105 return rc;
106 }
107
108 /*
109 ** Write unversioned content into the database.
@@ -328,11 +343,11 @@
328 int i;
329 verify_all_options();
330 db_begin_transaction();
331 for(i=3; i<g.argc; i++){
332 Blob content;
333 if( unversioned_content(g.argv[i], &content)==0 ){
334 blob_write_to_file(&content, "-");
335 }
336 blob_reset(&content);
337 }
338 db_end_transaction(0);
@@ -352,11 +367,11 @@
352 }
353 zTFile = fossil_temp_filename();
354 if( zTFile==0 ) fossil_fatal("cannot find a temporary filename");
355 db_begin_transaction();
356 content_rcvid_init("#!fossil unversioned edit");
357 if( unversioned_content(zUVFile, &content) ){
358 fossil_fatal("no such uv-file: %Q", zUVFile);
359 }
360 if( looks_like_binary(&content) ){
361 fossil_fatal("cannot edit binary content");
362 }
@@ -381,11 +396,11 @@
381 blob_reset(&content);
382 }else if( memcmp(zCmd, "export", nCmd)==0 ){
383 Blob content;
384 verify_all_options();
385 if( g.argc!=5 ) usage("export UVFILE OUTPUT");
386 if( unversioned_content(g.argv[3], &content) ){
387 fossil_fatal("no such uv-file: %Q", g.argv[3]);
388 }
389 blob_write_to_file(&content, g.argv[4]);
390 blob_reset(&content);
391 }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */
@@ -524,10 +539,11 @@
524 int showDel = 0;
525 char zSzName[100];
526
527 login_check_credentials();
528 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
 
529 style_header("Unversioned Files");
530 if( !db_table_exists("repository","unversioned") ){
531 @ No unversioned files on this server
532 style_footer();
533 return;
@@ -636,10 +652,11 @@
636 Blob json;
637
638 login_check_credentials();
639 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
640 cgi_set_content_type("text/json");
 
641 if( !db_table_exists("repository","unversioned") ){
642 blob_init(&json, "[]", -1);
643 cgi_set_content(&json);
644 return;
645 }
646
647 DDED test/subdir with spaces/filename with spaces.txt
--- src/unversioned.c
+++ src/unversioned.c
@@ -85,25 +85,40 @@
85 }
86
87 /*
88 ** Initialize pContent to be the content of an unversioned file zName.
89 **
90 ** Return 0 on failures.
91 ** Return 1 if the file is found by name.
92 ** Return 2 if the file is found by hash.
93 */
94 int unversioned_content(const char *zName, Blob *pContent){
95 Stmt q;
96 int rc = 0;
97 blob_init(pContent, 0, 0);
98 db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE name=%Q",
99 zName);
100 if( db_step(&q)==SQLITE_ROW ){
101 db_column_blob(&q, 1, pContent);
102 if( db_column_int(&q, 0)==1 ){
103 blob_uncompress(pContent, pContent);
104 }
105 rc = 1;
106 }
107 db_finalize(&q);
108 if( rc==0 && validate16(zName,-1) ){
109 db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE hash=%Q",
110 zName);
111 if( db_step(&q)==SQLITE_ROW ){
112 db_column_blob(&q, 1, pContent);
113 if( db_column_int(&q, 0)==1 ){
114 blob_uncompress(pContent, pContent);
115 }
116 rc = 2;
117 }
118 db_finalize(&q);
119 }
120 return rc;
121 }
122
123 /*
124 ** Write unversioned content into the database.
@@ -328,11 +343,11 @@
343 int i;
344 verify_all_options();
345 db_begin_transaction();
346 for(i=3; i<g.argc; i++){
347 Blob content;
348 if( unversioned_content(g.argv[i], &content)!=0 ){
349 blob_write_to_file(&content, "-");
350 }
351 blob_reset(&content);
352 }
353 db_end_transaction(0);
@@ -352,11 +367,11 @@
367 }
368 zTFile = fossil_temp_filename();
369 if( zTFile==0 ) fossil_fatal("cannot find a temporary filename");
370 db_begin_transaction();
371 content_rcvid_init("#!fossil unversioned edit");
372 if( unversioned_content(zUVFile, &content)==0 ){
373 fossil_fatal("no such uv-file: %Q", zUVFile);
374 }
375 if( looks_like_binary(&content) ){
376 fossil_fatal("cannot edit binary content");
377 }
@@ -381,11 +396,11 @@
396 blob_reset(&content);
397 }else if( memcmp(zCmd, "export", nCmd)==0 ){
398 Blob content;
399 verify_all_options();
400 if( g.argc!=5 ) usage("export UVFILE OUTPUT");
401 if( unversioned_content(g.argv[3], &content)==0 ){
402 fossil_fatal("no such uv-file: %Q", g.argv[3]);
403 }
404 blob_write_to_file(&content, g.argv[4]);
405 blob_reset(&content);
406 }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */
@@ -524,10 +539,11 @@
539 int showDel = 0;
540 char zSzName[100];
541
542 login_check_credentials();
543 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
544 etag_check(ETAG_DATA,0);
545 style_header("Unversioned Files");
546 if( !db_table_exists("repository","unversioned") ){
547 @ No unversioned files on this server
548 style_footer();
549 return;
@@ -636,10 +652,11 @@
652 Blob json;
653
654 login_check_credentials();
655 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
656 cgi_set_content_type("text/json");
657 etag_check(ETAG_DATA,0);
658 if( !db_table_exists("repository","unversioned") ){
659 blob_init(&json, "[]", -1);
660 cgi_set_content(&json);
661 return;
662 }
663
664 DDED test/subdir with spaces/filename with spaces.txt
--- a/test/subdir with spaces/filename with spaces.txt
+++ b/test/subdir with spaces/filename with spaces.txt
@@ -0,0 +1,2 @@
1
+This file has a name that contains spaces. It is used to help verify
2
+that fossil can handle filenames that contain spaces.
--- a/test/subdir with spaces/filename with spaces.txt
+++ b/test/subdir with spaces/filename with spaces.txt
@@ -0,0 +1,2 @@
 
 
--- a/test/subdir with spaces/filename with spaces.txt
+++ b/test/subdir with spaces/filename with spaces.txt
@@ -0,0 +1,2 @@
1 This file has a name that contains spaces. It is used to help verify
2 that fossil can handle filenames that contain spaces.
+2 -2
--- www/cgi.wiki
+++ www/cgi.wiki
@@ -14,12 +14,12 @@
1414
script]. CGI is the technique that the three
1515
[./selfhost.wiki|self-hosting Fossil repositories] all use.
1616
1717
Setting up a Fossil server using CGI is mostly about writing a short
1818
script (usually just 2 lines line) in the cgi-bin folder of an ordinary
19
-web-browser. But there are a lot of extra options that can be added
20
-to this script, to customize the configuration. This article descripts
19
+web-server. But there are a lot of extra options that can be added
20
+to this script, to customize the configuration. This article describes
2121
those options.
2222
2323
<h1>CGI Script Options</h1>
2424
2525
The CGI script used to launch a Fossil server will usually look something
2626
--- www/cgi.wiki
+++ www/cgi.wiki
@@ -14,12 +14,12 @@
14 script]. CGI is the technique that the three
15 [./selfhost.wiki|self-hosting Fossil repositories] all use.
16
17 Setting up a Fossil server using CGI is mostly about writing a short
18 script (usually just 2 lines line) in the cgi-bin folder of an ordinary
19 web-browser. But there are a lot of extra options that can be added
20 to this script, to customize the configuration. This article descripts
21 those options.
22
23 <h1>CGI Script Options</h1>
24
25 The CGI script used to launch a Fossil server will usually look something
26
--- www/cgi.wiki
+++ www/cgi.wiki
@@ -14,12 +14,12 @@
14 script]. CGI is the technique that the three
15 [./selfhost.wiki|self-hosting Fossil repositories] all use.
16
17 Setting up a Fossil server using CGI is mostly about writing a short
18 script (usually just 2 lines line) in the cgi-bin folder of an ordinary
19 web-server. But there are a lot of extra options that can be added
20 to this script, to customize the configuration. This article describes
21 those options.
22
23 <h1>CGI Script Options</h1>
24
25 The CGI script used to launch a Fossil server will usually look something
26
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,14 @@
11
<title>Change Log</title>
22
3
+<a name='v2_12'></a>
4
+<h2>Changes for Version 2.12 (pending)</h2>
5
+
6
+ * <i>(no changes yet...)</i>
7
+
38
<a name='v2_11'></a>
4
-<h2>Changes for Version 2.11 (pending)</h2>
9
+<h2>Changes for Version 2.11 (2020-05-25)</h2>
510
611
* Support [/md_rules|Markdown] in the default ticket configuration.
712
* Timestamp strings in [./checkin_names.wiki|object names]
813
can now omit punctation. So, for example, "202004181942" and
914
"2020-04-18 19:42" mean the same thing.
@@ -55,10 +60,12 @@
5560
* Security: Fossil now puts the Content-Security-Policy in the
5661
HTTP reply header, in addition to also leaving it in the
5762
HTML &lt;head&gt; section, so that it is always available, even
5863
if a custom skin overrides the HTML &lt;head&gt; and omits
5964
the CSP in the process.
65
+ * Output of the [/help?cmd=diff|fossil diff -y] command automatically
66
+ adjusts according to the terminal width.
6067
* The Content-Security-Policy is now set using the
6168
[/help?cmd=default-csp|default-csp setting].
6269
* Merge conflicts caused via the [/help?cmd=merge|merge] and
6370
[/help?cmd=update|update] commands no longer leave temporary
6471
files behind unless the new <tt>--keep-merge-files</tt> flag
6572
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,14 @@
1 <title>Change Log</title>
2
 
 
 
 
 
3 <a name='v2_11'></a>
4 <h2>Changes for Version 2.11 (pending)</h2>
5
6 * Support [/md_rules|Markdown] in the default ticket configuration.
7 * Timestamp strings in [./checkin_names.wiki|object names]
8 can now omit punctation. So, for example, "202004181942" and
9 "2020-04-18 19:42" mean the same thing.
@@ -55,10 +60,12 @@
55 * Security: Fossil now puts the Content-Security-Policy in the
56 HTTP reply header, in addition to also leaving it in the
57 HTML &lt;head&gt; section, so that it is always available, even
58 if a custom skin overrides the HTML &lt;head&gt; and omits
59 the CSP in the process.
 
 
60 * The Content-Security-Policy is now set using the
61 [/help?cmd=default-csp|default-csp setting].
62 * Merge conflicts caused via the [/help?cmd=merge|merge] and
63 [/help?cmd=update|update] commands no longer leave temporary
64 files behind unless the new <tt>--keep-merge-files</tt> flag
65
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,9 +1,14 @@
1 <title>Change Log</title>
2
3 <a name='v2_12'></a>
4 <h2>Changes for Version 2.12 (pending)</h2>
5
6 * <i>(no changes yet...)</i>
7
8 <a name='v2_11'></a>
9 <h2>Changes for Version 2.11 (2020-05-25)</h2>
10
11 * Support [/md_rules|Markdown] in the default ticket configuration.
12 * Timestamp strings in [./checkin_names.wiki|object names]
13 can now omit punctation. So, for example, "202004181942" and
14 "2020-04-18 19:42" mean the same thing.
@@ -55,10 +60,12 @@
60 * Security: Fossil now puts the Content-Security-Policy in the
61 HTTP reply header, in addition to also leaving it in the
62 HTML &lt;head&gt; section, so that it is always available, even
63 if a custom skin overrides the HTML &lt;head&gt; and omits
64 the CSP in the process.
65 * Output of the [/help?cmd=diff|fossil diff -y] command automatically
66 adjusts according to the terminal width.
67 * The Content-Security-Policy is now set using the
68 [/help?cmd=default-csp|default-csp setting].
69 * Merge conflicts caused via the [/help?cmd=merge|merge] and
70 [/help?cmd=update|update] commands no longer leave temporary
71 files behind unless the new <tt>--keep-merge-files</tt> flag
72
+1 -1
--- www/index.wiki
+++ www/index.wiki
@@ -9,11 +9,11 @@
99
<li> [./build.wiki | Install]
1010
<li> [https://fossil-scm.org/forum | Support/Forum ]
1111
<li> [./hints.wiki | Tips &amp; Hints]
1212
<li> [./changes.wiki | Change Log]
1313
<li> [../COPYRIGHT-BSD2.txt | License]
14
-<li> [./userlinks.wiki | User inks]
14
+<li> [./userlinks.wiki | User Links]
1515
<li> [./hacker-howto.wiki | Hacker How-To]
1616
<li> [./fossil-v-git.wiki | Fossil vs. Git]
1717
<li> [./permutedindex.html | Documentation Index]
1818
</ul>
1919
<img src="fossil3.gif" align="center">
2020
--- www/index.wiki
+++ www/index.wiki
@@ -9,11 +9,11 @@
9 <li> [./build.wiki | Install]
10 <li> [https://fossil-scm.org/forum | Support/Forum ]
11 <li> [./hints.wiki | Tips &amp; Hints]
12 <li> [./changes.wiki | Change Log]
13 <li> [../COPYRIGHT-BSD2.txt | License]
14 <li> [./userlinks.wiki | User inks]
15 <li> [./hacker-howto.wiki | Hacker How-To]
16 <li> [./fossil-v-git.wiki | Fossil vs. Git]
17 <li> [./permutedindex.html | Documentation Index]
18 </ul>
19 <img src="fossil3.gif" align="center">
20
--- www/index.wiki
+++ www/index.wiki
@@ -9,11 +9,11 @@
9 <li> [./build.wiki | Install]
10 <li> [https://fossil-scm.org/forum | Support/Forum ]
11 <li> [./hints.wiki | Tips &amp; Hints]
12 <li> [./changes.wiki | Change Log]
13 <li> [../COPYRIGHT-BSD2.txt | License]
14 <li> [./userlinks.wiki | User Links]
15 <li> [./hacker-howto.wiki | Hacker How-To]
16 <li> [./fossil-v-git.wiki | Fossil vs. Git]
17 <li> [./permutedindex.html | Documentation Index]
18 </ul>
19 <img src="fossil3.gif" align="center">
20

Keyboard Shortcuts

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